Skip to content

Commit

Permalink
Merge pull request #1685 from boxwise/intra-org-shipments
Browse files Browse the repository at this point in the history
Intra-org shipments between bases of the same org
  • Loading branch information
fhenrich33 authored Nov 15, 2024
2 parents 3016451 + 1583acd commit 08f4d0f
Show file tree
Hide file tree
Showing 6 changed files with 316 additions and 126 deletions.
2 changes: 1 addition & 1 deletion front/src/types/generated/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2351,7 +2351,7 @@ export type AllAcceptedTransferAgreementsQuery = { __typename?: 'Query', base?:
export type CreateShipmentMutationVariables = Exact<{
sourceBaseId: Scalars['Int']['input'];
targetBaseId: Scalars['Int']['input'];
transferAgreementId: Scalars['Int']['input'];
transferAgreementId?: InputMaybe<Scalars['Int']['input']>;
}>;


Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { vi, it, describe, expect } from "vitest";
import { screen, render, waitFor } from "tests/test-utils";
import { organisation1 } from "mocks/organisations";
import { organisation1, organisation2 } from "mocks/organisations";
import { acceptedTransferAgreement } from "mocks/transferAgreements";
import { userEvent } from "@testing-library/user-event";
import { assertOptionsInSelectField, selectOptionInSelectField } from "tests/helpers";
import { base1 } from "mocks/bases";
import { base1, base2 } from "mocks/bases";
import { ShipmentState } from "types/generated/graphql";
import { generateMockShipment } from "mocks/shipments";
import { cache } from "queries/cache";
Expand Down Expand Up @@ -156,10 +156,11 @@ it("4.3.1 - Initial load of Page", async () => {

expect(screen.getByTestId("loading-indicator")).toBeInTheDocument();

const title = await screen.findByRole("heading", { name: "Start New Shipment" });
const title = await screen.findByRole("heading", { name: "New Shipment" });
expect(title).toBeInTheDocument();
// Test case 4.3.1.1 - Content: Displays Source Base Label
expect(screen.getByText(/boxaid - lesvos/i)).toBeInTheDocument();
expect(await screen.findByText(/boxaid/i)).toBeInTheDocument();
expect(await screen.findByText(/lesvos/i)).toBeInTheDocument();
// Test case 4.3.1.2 - Content: Displays Partner Orgs Select Options
await assertOptionsInSelectField(user, /organisation/i, [/boxcare/i], title);
await selectOptionInSelectField(user, /organisation/i, "BoxCare");
Expand Down Expand Up @@ -190,15 +191,15 @@ it("4.3.2 - Input Validations", async () => {
},
});

const submitButton = await screen.findByRole("button", { name: /start/i });
const submitButton = await screen.findByRole("button", { name: /start new shipment/i });
expect(submitButton).toBeInTheDocument();
user.click(submitButton);
// Test case 4.3.2.1 - Partner Organisation SELECT field cannot be empty
expect((screen.getByLabelText(/organisation/i) as HTMLInputElement).value).toEqual("");
expect(screen.getByText(/please select an organisation/i)).toBeInTheDocument();
// Test case 4.3.2.2 - Partner Organisation Base SELECT field cannot be empty
expect((screen.getByLabelText(/base/i) as HTMLInputElement).value).toEqual("");
expect(screen.getByText(/please select a base/i)).toBeInTheDocument();
expect(screen.getAllByText(/please select a base/i)[0]).toBeInTheDocument();

expect((await screen.findAllByText(/required/i)).length).toEqual(2);
});
Expand Down Expand Up @@ -241,11 +242,11 @@ it("4.3.3 (4.3.3.1 and 4.3.3.2) - Click on Submit Button", async () => {
},
});

const title = await screen.findByRole("heading", { name: "Start New Shipment" });
const title = await screen.findByRole("heading", { name: "New Shipment" });
expect(title).toBeInTheDocument();

// Test case 4.3.3.1 - Form data was valid and mutation was successful
const submitButton = await screen.findByRole("button", { name: /start/i });
const submitButton = await screen.findByRole("button", { name: /start new shipment/i });
expect(submitButton).toBeInTheDocument();

await assertOptionsInSelectField(user, /organisation/i, [/boxcare/i], title);
Expand Down Expand Up @@ -289,10 +290,10 @@ it("4.3.3.3 - Form data was valid, but the mutation failed", async () => {
});

// Test case 4.3.3.3 - Form data was valid, but the mutation failed
const pageTitle = await screen.findByRole("heading", { name: "Start New Shipment" });
const pageTitle = await screen.findByRole("heading", { name: "New Shipment" });
expect(pageTitle).toBeInTheDocument();

const submitStartButton = await screen.findByRole("button", { name: /start/i });
const submitStartButton = await screen.findByRole("button", { name: /start new shipment/i });
expect(submitStartButton).toBeInTheDocument();

await assertOptionsInSelectField(user, /organisation/i, [/boxcare/i], pageTitle);
Expand Down Expand Up @@ -329,10 +330,12 @@ it("4.3.3.4 - Form data was valid, but the mutation response has errors", async
});

// Test case 4.3.3.4 - Form data was valid, but the mutation response has errors
const shipmentPageTitle = await screen.findByRole("heading", { name: "Start New Shipment" });
const shipmentPageTitle = await screen.findByRole("heading", { name: "New Shipment" });
expect(shipmentPageTitle).toBeInTheDocument();

const submitShipmentStartButton = await screen.findByRole("button", { name: /start/i });
const submitShipmentStartButton = await screen.findByRole("button", {
name: /Start New Shipment/i,
});
expect(submitShipmentStartButton).toBeInTheDocument();

await assertOptionsInSelectField(user, /organisation/i, [/boxcare/i], shipmentPageTitle);
Expand All @@ -350,6 +353,75 @@ it("4.3.3.4 - Form data was valid, but the mutation response has errors", async
);
});

// TODO: can't make this to work inside the test environment.
it.skip("4.3.3.5 - Click on Submit Button - Intra-org Shipment", async () => {
const user = userEvent.setup();

// modify the cache
cache.modify({
fields: {
shipments(existingShipments = []) {
const newShipmentRef = cache.writeFragment({
data: successfulMutation.result.data,
fragment: gql`
fragment NewShipment on Shipment {
id
}
`,
});
return existingShipments.concat(newShipmentRef);
},
},
});

render(<CreateShipmentView />, {
routePath: "/bases/:baseId/transfers/shipments/create",
// Maybe there's a route and org, base mismatch?
initialUrl: "/bases/2/transfers/shipments/create",
additionalRoute: "/bases/2/transfers/shipments/1",
mocks: [initialQuery, successfulMutation, initialWithoutBoxQuery],
addTypename: true,
cache,
globalPreferences: {
dispatch: vi.fn(),
globalPreferences: {
organisation: { id: organisation2.id, name: organisation2.name },
availableBases: organisation2.bases,
selectedBase: { id: base2.id, name: base2.name },
},
},
});

const title = await screen.findByRole("heading", { name: "New Shipment" });
expect(title).toBeInTheDocument();

const intraOrgTab = await screen.findByRole("tab", { name: /BoxAid - Lesvos/i });
expect(intraOrgTab).toBeInTheDocument();
await user.click(intraOrgTab);

// Since this base is the only other base for this test org, it will be already selected.
expect(await screen.findByText("Samos")).toBeInTheDocument();

// Test case 4.3.3.1 - Form data was valid and mutation was successful
const submitButton = await screen.findByRole("button", { name: /start new shipment/i });
expect(submitButton).toBeInTheDocument();

await user.click(submitButton);

await waitFor(() =>
expect(mockedCreateToast).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringMatching(/successfully created a new shipment/i),
}),
),
);

// Test case 4.3.3.2 - Redirect to Transfers Shipments Page
expect(
await screen.findByRole("heading", { name: "/bases/1/transfers/shipments/1" }),
).toBeInTheDocument();
});

// Test case 4.3.4
describe("4.3.4 - Failed to Fetch Initial Data", () => {
it("4.3.4.1 - No Partner Organisations and Bases Data", async () => {
Expand Down
41 changes: 23 additions & 18 deletions front/src/views/Transfers/CreateShipment/CreateShipmentView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const ALL_ACCEPTED_TRANSFER_AGREEMENTS_QUERY = gql`

export const CREATE_SHIPMENT_MUTATION = gql`
${SHIPMENT_FIELDS_FRAGMENT}
mutation CreateShipment($sourceBaseId: Int!, $targetBaseId: Int!, $transferAgreementId: Int!) {
mutation CreateShipment($sourceBaseId: Int!, $targetBaseId: Int!, $transferAgreementId: Int) {
createShipment(
creationInput: {
sourceBaseId: $sourceBaseId
Expand Down Expand Up @@ -107,8 +107,10 @@ function CreateShipmentView() {

// Prep data for Form
const currentBase = allAcceptedTransferAgreements?.data?.base;
const currentOrganisationLabel = `${currentBase?.organisation?.name} - ${currentBase?.name}`;
const currentOrganisationName = currentBase?.organisation?.name;
const currentOrganisationBase = currentBase?.name;
const currentOrganisationId = globalPreferences.organisation?.id;
const currentOrganisationBases = globalPreferences.availableBases;
const acceptedTransferAgreementsPartnerData =
allAcceptedTransferAgreements.data?.transferAgreements
?.filter(
Expand All @@ -129,13 +131,15 @@ function CreateShipmentView() {
name: agreement.sourceOrganisation.name,
bases: agreement.sourceBases,
agreementId: agreement.id,
agreementComment: agreement.comment,
} as IAcceptedTransferAgreementsPartnerData;
}
return {
id: agreement.targetOrganisation.id,
name: agreement.targetOrganisation.name,
bases: agreement.targetBases,
agreementId: agreement.id,
agreementComment: agreement.comment,
} as IAcceptedTransferAgreementsPartnerData;
});

Expand All @@ -147,6 +151,7 @@ function CreateShipmentView() {
id: agreement.id,
name: agreement.name,
bases: agreement.bases,
agreement: agreement.comment,
}) as IOrganisationBaseData,
)
.reduce((accumulator, currentOrg) => {
Expand All @@ -168,14 +173,17 @@ function CreateShipmentView() {
const onSubmitCreateShipmentForm = useCallback(
(createShipmentFormData: ICreateShipmentFormData) => {
// Find the possible agreement Ids for the partner base
// Or ignore this and return an empty array if this is an intra-org shipment between bases of the same organization.
const agreementIds: Array<string> =
acceptedTransferAgreementsPartnerData
?.filter((org) =>
org.bases.some((base) => base.id === createShipmentFormData.receivingBase.value),
)
.map((org) => org.agreementId) || [];
createShipmentFormData.shipmentTarget === "currentOrg"
? []
: acceptedTransferAgreementsPartnerData
?.filter((org) =>
org.bases.some((base) => base.id === createShipmentFormData.receivingBase.value),
)
.map((org) => org.agreementId) || [];

if (agreementIds.length === 0) {
if (agreementIds.length === 0 && createShipmentFormData.shipmentTarget === "partners") {
triggerError({
message: "Error while trying to create a new shipment",
});
Expand Down Expand Up @@ -223,9 +231,7 @@ function CreateShipmentView() {
);

// Handle Loading State
if (allAcceptedTransferAgreements.loading || isGlobalStateLoading) {
return <APILoadingIndicator />;
}
if (allAcceptedTransferAgreements.loading || isGlobalStateLoading) return <APILoadingIndicator />;

const renderNoAcceptedAgreementsAlert = (
<Alert status="warning">
Expand All @@ -248,21 +254,20 @@ function CreateShipmentView() {
const noPartnerOrgBaseData =
!partnerOrganisationBaseData || partnerOrganisationBaseData.length === 0;

if (noAcceptedAgreements) {
return renderNoAcceptedAgreementsAlert;
}
if (noAcceptedAgreements) return renderNoAcceptedAgreementsAlert;

if (noPartnerOrgBaseData || allAcceptedTransferAgreements.error) {
return renderErrorAlert;
}
if (noPartnerOrgBaseData || allAcceptedTransferAgreements.error) return renderErrorAlert;

return (
<>
<MobileBreadcrumbButton label="Back to Manage Shipments" linkPath=".." />
<Center>
<CreateShipment
isLoading={createShipmentMutationState.loading}
currentOrganisationLabel={currentOrganisationLabel}
currentOrganisationId={currentOrganisationId || ""}
currentOrganisationName={currentOrganisationName || ""}
currentOrganisationBase={currentOrganisationBase || ""}
currentOrganisationBases={currentOrganisationBases || []}
organisationBaseData={partnerOrganisationBaseData}
onSubmit={onSubmitCreateShipmentForm}
/>
Expand Down
Loading

0 comments on commit 08f4d0f

Please sign in to comment.