Skip to content

Commit

Permalink
Add flag for coordinates metadata, add test for composerActions
Browse files Browse the repository at this point in the history
  • Loading branch information
matborowczyk committed Nov 28, 2024
1 parent 726c0a0 commit 8ab9ac3
Show file tree
Hide file tree
Showing 12 changed files with 310 additions and 25 deletions.
4 changes: 4 additions & 0 deletions changelogs/unreleased/5989-actions-composer-flag-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
description: Add v2 flag for coordinates metadata saved in Instance and tests for composer Actions
issue-nr: 5989
change-type: patch
destination-branches: [master]
14 changes: 7 additions & 7 deletions src/UI/Components/Diagram/Context/EventWrapper.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ describe("addInterServiceRelationToTracker - eventHandler that adds to the Map i
detail: {
id: "1",
name: "test",
relations: [{ current: 0, min: 1, name: "test2" }],
relations: [{ currentAmount: 0, min: 1, name: "test2" }],
},
}),
);
Expand All @@ -446,7 +446,7 @@ describe("addInterServiceRelationToTracker - eventHandler that adds to the Map i
expect(result.current).toStrictEqual(
new Map().set("1", {
name: "test",
relations: [{ current: 0, min: 1, name: "test2" }],
relations: [{ currentAmount: 0, min: 1, name: "test2" }],
}),
);
});
Expand All @@ -465,7 +465,7 @@ describe("removeInterServiceRelationFromTracker - event handler that removes int
setInterServiceRelationsOnCanvas(
new Map().set("1", {
name: "test",
relations: [{ current: 0, min: 1, name: "test2" }],
relations: [{ currentAmount: 0, min: 1, name: "test2" }],
}),
);
}, [setInterServiceRelationsOnCanvas]);
Expand All @@ -484,7 +484,7 @@ describe("removeInterServiceRelationFromTracker - event handler that removes int
expect(result.current).toStrictEqual(
new Map().set("1", {
name: "test",
relations: [{ current: 0, min: 1, name: "test2" }],
relations: [{ currentAmount: 0, min: 1, name: "test2" }],
}),
);

Expand Down Expand Up @@ -514,7 +514,7 @@ describe("updateInterServiceRelations", () => {
setInterServiceRelationsOnCanvas(
new Map().set("1", {
name: "test",
relations: [{ current: 0, min: 1, name: "test2" }],
relations: [{ currentAmount: 0, min: 1, name: "test2" }],
}),
);
}, [setInterServiceRelationsOnCanvas]);
Expand Down Expand Up @@ -545,7 +545,7 @@ describe("updateInterServiceRelations", () => {
expect(result.current).toStrictEqual(
new Map().set("1", {
name: "test",
relations: [{ current: 1, min: 1, name: "test2" }],
relations: [{ currentAmount: 1, min: 1, name: "test2" }],
}),
);

Expand All @@ -564,7 +564,7 @@ describe("updateInterServiceRelations", () => {
expect(result.current).toStrictEqual(
new Map().set("1", {
name: "test",
relations: [{ current: 0, min: 1, name: "test2" }],
relations: [{ currentAmount: 0, min: 1, name: "test2" }],
}),
);
});
Expand Down
4 changes: 2 additions & 2 deletions src/UI/Components/Diagram/Context/EventWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,9 @@ export const EventWrapper: React.FC<React.PropsWithChildren> = ({
const relationToUpdate =
cellsRelations.relations[indexOfRelationToUpdate];

let current = relationToUpdate.current;
let current = relationToUpdate.currentAmount;

relationToUpdate.current =
relationToUpdate.currentAmount =
action === EventActionEnum.ADD ? ++current : --current;

cellsRelations.relations.splice(
Expand Down
4 changes: 2 additions & 2 deletions src/UI/Components/Diagram/actions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ describe("addDefaultEntities", () => {
).toMatchObject({
name: "child_container",
id: expect.any(String),
relations: [{ current: 0, min: 1, name: "parent-service" }],
relations: [{ currentAmount: 0, min: 1, name: "parent-service" }],
}); //add relations to Tracker

//assert the arguments of the second call - calls is array of the arguments of each call
Expand Down Expand Up @@ -521,7 +521,7 @@ describe("appendEmbeddedEntity", () => {
).toMatchObject({
name: "child_container",
id: expect.any(String),
relations: [{ current: 0, min: 1, name: "parent-service" }],
relations: [{ currentAmount: 0, min: 1, name: "parent-service" }],
}); //add relations to Tracker

//assert the arguments of the second call - calls is array of the arguments of each call
Expand Down
2 changes: 1 addition & 1 deletion src/UI/Components/Diagram/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export function createComposerEntity({
relations.push({
name: relation.entity_type,
min: relation.lower_limit,
current: 0,
currentAmount: 0,
});
}
});
Expand Down
267 changes: 267 additions & 0 deletions src/UI/Components/Diagram/components/ComposerActions.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
import React, { act } from "react";
import { MemoryRouter, useLocation } from "react-router-dom";
import {
QueryClient,
QueryClientProvider,
UseQueryResult,
} from "@tanstack/react-query";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { StoreProvider } from "easy-peasy";
import { delay, http, HttpResponse } from "msw";
import { setupServer } from "msw/node";
import { RemoteData } from "@/Core";
import { getStoreInstance } from "@/Data";
import { InstanceWithRelations } from "@/Data/Managers/V2/GETTERS/GetInstanceWithRelations";
import { Inventories } from "@/Data/Managers/V2/GETTERS/GetInventoryList";
import { dependencies } from "@/Test";
import { DependencyProvider, EnvironmentHandlerImpl } from "@/UI/Dependency";
import { PrimaryRouteManager } from "@/UI/Routing";
import {
CanvasContext,
defaultCanvasContext,
InstanceComposerContext,
} from "../Context";
import { childModel } from "../Mocks";
import { RelationCounterForCell } from "../interfaces";
import { ComposerActions } from "./ComposerActions";
const mockedNavigate = jest.fn();

jest.mock("react-router-dom", () => ({
...jest.requireActual("react-router-dom"),
useNavigate: () => mockedNavigate,
}));

describe("ComposerActions.", () => {
const setup = (
instanceWithRelations: InstanceWithRelations | null,
canvasContext: typeof defaultCanvasContext,
editable: boolean = true,
) => {
const client = new QueryClient();
const environmentHandler = EnvironmentHandlerImpl(
useLocation,
PrimaryRouteManager(""),
);
const store = getStoreInstance();

store.dispatch.environment.setEnvironments(
RemoteData.success([
{
id: "aaa",
name: "env-a",
project_id: "ppp",
repo_branch: "branch",
repo_url: "repo",
projectName: "project",
},
]),
);

return (
<QueryClientProvider client={client}>
<MemoryRouter initialEntries={[{ search: "?env=aaa" }]}>
<StoreProvider store={store}>
<DependencyProvider
dependencies={{ ...dependencies, environmentHandler }}
>
<InstanceComposerContext.Provider
value={{
serviceModels: [childModel],
instance: instanceWithRelations,
mainService: childModel,
relatedInventoriesQuery: {} as UseQueryResult<
Inventories,
Error
>,
}}
>
<CanvasContext.Provider value={canvasContext}>
<ComposerActions
serviceName="child-service"
editable={editable}
/>
</CanvasContext.Provider>
</InstanceComposerContext.Provider>
</DependencyProvider>
</StoreProvider>
</MemoryRouter>
</QueryClientProvider>
);
};

const validContextForEnabledDeploy = {
...defaultCanvasContext,
serviceOrderItems: new Map().set("13920268-cce0-4491-93b5-11316aa2fc37", {
instance_id: "13920268-cce0-4491-93b5-11316aa2fc37",
service_entity: "child-service",
config: {},
action: "create",
attributes: {
name: "test123456789",
service_id: "123test",
should_deploy_fail: false,
parent_entity: "6af44f75-ba4b-4fba-9186-cc61c3c9463c",
},
}),
diagramHandlers: {
getCoordinates: jest.fn(),
saveAndClearCanvas: jest.fn(),
loadState: jest.fn(),
addInstance: jest.fn(),
editEntity: jest.fn(),
} as typeof defaultCanvasContext.diagramHandlers,
isDirty: true,
looseElement: new Set<string>(),
interServiceRelationsOnCanvas: new Map<string, RelationCounterForCell>(),
};

const server = setupServer(
http.post(
"/lsm/v1/service_inventory/child-service}/*/metadata/coordinates",
async () => {
return HttpResponse.json({
data: [],
});
},
),
http.post("/lsm/v2/order", async () => {
return HttpResponse.json({
data: [],
});
}),
);

beforeAll(() => {
server.listen();
});
afterEach(() => {
server.resetHandlers();
});

afterAll(() => {
server.close();
});

it("should render the ComposerActions component", () => {
render(setup(null, defaultCanvasContext));

expect(screen.getByText("Cancel")).toBeVisible();
expect(screen.getByText("Cancel")).toBeEnabled();

expect(screen.getByText("Deploy")).toBeVisible();
expect(screen.getByText("Deploy")).toBeDisabled(); //for default canvas context deploy should be disabled by default
});

it.each`
serviceOrderItems | isDirty | looseElement | editable | interServiceRelationsOnCanvas
${new Map()} | ${true} | ${null} | ${true} | ${null}
${null} | ${false} | ${null} | ${true} | ${null}
${null} | ${true} | ${new Set().add("test")} | ${true} | ${null}
${null} | ${true} | ${null} | ${false} | ${null}
${null} | ${true} | ${null} | ${true} | ${new Map().set("test_id", {
name: "test",
relations: [{ name: "relation-test", currentAmount: 0, min: 1 }],
})}
`(
"should have deploy button disabled when at least one of conditions are not met",
({
serviceOrderItems,
isDirty,
looseElement,
editable,
interServiceRelationsOnCanvas,
}) => {
const canvasContext = {
...defaultCanvasContext,
serviceOrderItems: serviceOrderItems || new Map().set("test", "test"),
isDirty: isDirty,
looseElement: looseElement || new Set<string>(),
interServiceRelationsOnCanvas:
interServiceRelationsOnCanvas ||
new Map<string, RelationCounterForCell>(),
};

render(setup(null, canvasContext, editable));
expect(screen.getByText("Deploy")).toBeDisabled();
},
);

it("should have deploy button enabled when all conditions are met", () => {
render(setup(null, validContextForEnabledDeploy));
expect(screen.getByText("Deploy")).toBeEnabled();
});

it("shows success message and redirects when deploy button is clicked", async () => {
server.use(
http.post("/lsm/v2/order", async () => {
return HttpResponse.json();
}),
);

render(setup(null, validContextForEnabledDeploy));
expect(screen.getByText("Deploy")).toBeEnabled();
await act(async () => {
await userEvent.click(screen.getByText("Deploy"));
});

expect(
await screen.findByText("The request got sent successfully"),
).toBeVisible();

await waitFor(
() =>
expect(mockedNavigate).toHaveBeenCalledWith(
"/lsm/catalog/child-service/inventory?env=aaa",
),
{ timeout: 1500 },
);
});

it("shows error message about coordinates when there is no diagramHandlers", async () => {
server.use(
http.post("/lsm/v2/order", async () => {
await delay();

return HttpResponse.json();
}),
);
const canvasContext = {
...validContextForEnabledDeploy,
diagramHandlers: null,
};

render(setup(null, canvasContext));
expect(screen.getByText("Deploy")).toBeEnabled();
await act(async () => {
await userEvent.click(screen.getByText("Deploy"));
});

expect(
screen.getByText("Failed to save instance coordinates on deploy."),
).toBeVisible();
});

it("shows error message when deploy button is clicked and request fails", async () => {
server.use(
http.post("/lsm/v2/order", async () => {
return HttpResponse.json(
{
message: "Failed to deploy instance.",
},
{
status: 401,
},
);
}),
);

render(setup(null, validContextForEnabledDeploy));
expect(screen.getByText("Deploy")).toBeEnabled();
await act(async () => {
await userEvent.click(screen.getByText("Deploy"));
});

expect(await screen.findByText("Failed to deploy instance.")).toBeVisible();
});
});
Loading

0 comments on commit 8ab9ac3

Please sign in to comment.