Skip to content

Commit

Permalink
feat: add error messages to new mutations
Browse files Browse the repository at this point in the history
  • Loading branch information
matthieu-foucault committed Mar 30, 2022
1 parent d5569b4 commit 916260b
Show file tree
Hide file tree
Showing 11 changed files with 161 additions and 524 deletions.
3 changes: 0 additions & 3 deletions app/components/Form/ProjectManagerFormGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@ const ProjectManagerFormGroup: React.FC<Props> = (props) => {
id: formChangeId,
projectRevision: projectRevision.id,
},
onError: (error) => {
console.log(error);
},
});
};

Expand Down
2 changes: 1 addition & 1 deletion app/mutations/FormChange/updateFormChange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const mutation = graphql`
`;

const useUpdateFormChange = () => {
return useDebouncedMutation<updateFormChangeMutationType>(
return useDebouncedMutation<updateFormChangeMutation>(
mutation,
() => "An error occurred when updating the form."
);
Expand Down
5 changes: 4 additions & 1 deletion app/mutations/FormChange/updateProjectFormChange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@ export const mutation = graphql`
`;

export const useUpdateProjectFormChange = () => {
return useDebouncedMutation<updateProjectFormChangeMutation>(mutation);
return useDebouncedMutation<updateProjectFormChangeMutation>(
mutation,
() => "An error occurred when updating the project overview."
);
};
8 changes: 6 additions & 2 deletions app/mutations/ProjectContact/addContactToRevision.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { graphql, useMutation } from "react-relay";
import useMutationWithErrorMessage from "mutations/useMutationWithErrorMessage";
import { graphql } from "react-relay";
import { addContactToRevisionMutation } from "__generated__/addContactToRevisionMutation.graphql";

const mutation = graphql`
Expand All @@ -19,7 +20,10 @@ const mutation = graphql`
`;

const useAddContactToRevision = () => {
return useMutation<addContactToRevisionMutation>(mutation);
return useMutationWithErrorMessage<addContactToRevisionMutation>(
mutation,
() => "An error occurred while adding the contact to the revision."
);
};

export { mutation, useAddContactToRevision };
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ const mutation = graphql`
`;

const useUpdateProjectContactFormChange = () => {
return useDebouncedMutation<updateProjectContactFormChangeMutation>(mutation);
return useDebouncedMutation<updateProjectContactFormChangeMutation>(
mutation,
() => "An error occurred when updating the project contact form."
);
};

export { mutation, useUpdateProjectContactFormChange };
9 changes: 7 additions & 2 deletions app/mutations/ProjectManager/addManagerToRevision.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useMutation, graphql, Disposable, Environment } from "react-relay";
import useMutationWithErrorMessage from "mutations/useMutationWithErrorMessage";
import { graphql, Disposable, Environment } from "react-relay";
import { MutationConfig } from "relay-runtime";
import { addManagerToRevisionMutation } from "__generated__/addManagerToRevisionMutation.graphql";

Expand Down Expand Up @@ -33,7 +34,11 @@ export const useAddManagerToRevisionMutation = (
config: MutationConfig<addManagerToRevisionMutation>
) => Disposable
) => {
return useMutation<addManagerToRevisionMutation>(mutation, commitMutationFn);
return useMutationWithErrorMessage<addManagerToRevisionMutation>(
mutation,
() => "An error occurred while adding a manager to the project.",
commitMutationFn
);
};

export default useAddManagerToRevisionMutation;
19 changes: 14 additions & 5 deletions app/mutations/ProjectManager/deleteManagerFromRevision.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useMutation, graphql, Disposable, Environment } from "react-relay";
import useMutationWithErrorMessage from "mutations/useMutationWithErrorMessage";
import { graphql, Disposable, Environment } from "react-relay";
import { MutationConfig, PayloadError } from "relay-runtime";
import {
deleteManagerFromRevisionMutation,
Expand Down Expand Up @@ -68,10 +69,14 @@ const useDeleteMutation = (
>
) => Disposable
) => {
return useMutation<
return useMutationWithErrorMessage<
| deleteManagerFromRevisionMutation
| deleteManagerFromRevisionWithArchiveMutation
>(deleteMutation, commitMutationFn);
>(
deleteMutation,
() => "An error occurred while removing the manager from the project.",
commitMutationFn
);
};

const useArchiveMutation = (
Expand All @@ -83,10 +88,14 @@ const useArchiveMutation = (
>
) => Disposable
) => {
return useMutation<
return useMutationWithErrorMessage<
| deleteManagerFromRevisionMutation
| deleteManagerFromRevisionWithArchiveMutation
>(archiveMutation, commitMutationFn);
>(
archiveMutation,
() => "An error occurred while removing the manager from the project.",
commitMutationFn
);
};

export const useDeleteManagerFromRevisionMutation = (): [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ const mutation = graphql`
`;

const useUpdateProjectManagerFormChange = () => {
return useDebouncedMutation<updateProjectManagerFormChangeMutation>(mutation);
return useDebouncedMutation<updateProjectManagerFormChangeMutation>(
mutation,
() => "An error occurred when updating the project manager form."
);
};

export { mutation, useUpdateProjectManagerFormChange };
114 changes: 38 additions & 76 deletions app/tests/unit/components/Form/ProjectContactForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { render, screen, act, within, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { ValidatingFormProps } from "components/Form/Interfaces/FormValidationTypes";
import ProjectContactForm from "components/Form/ProjectContactForm";
import { ErrorContext } from "contexts/ErrorContext";
import {
graphql,
RelayEnvironmentProvider,
Expand All @@ -12,7 +13,6 @@ import compiledProjectContactFormQuery, {
ProjectContactFormQuery,
} from "__generated__/ProjectContactFormQuery.graphql";
import { ProjectContactForm_projectRevision } from "__generated__/ProjectContactForm_projectRevision.graphql";
import userEvent from "@testing-library/user-event";

const loadedQuery = graphql`
query ProjectContactFormQuery @relay_test_operation {
Expand All @@ -30,6 +30,15 @@ const props: ValidatingFormProps = {
setValidatingForm: jest.fn(),
};

const errorContext = {
error: null,
setError: jest.fn().mockImplementation((error) =>
act(() => {
errorContext.error = error;
})
),
};

let environment;
const TestRenderer = () => {
const data = useLazyLoadQuery<ProjectContactFormQuery>(loadedQuery, {
Expand All @@ -46,9 +55,11 @@ const TestRenderer = () => {
};
const renderProjectForm = () => {
return render(
<RelayEnvironmentProvider environment={environment}>
<TestRenderer />
</RelayEnvironmentProvider>
<ErrorContext.Provider value={errorContext}>
<RelayEnvironmentProvider environment={environment}>
<TestRenderer />
</RelayEnvironmentProvider>
</ErrorContext.Provider>
);
};

Expand Down Expand Up @@ -143,8 +154,6 @@ const loadTestQuery = (mockResolver = getMockQueryPayload()) => {

describe("The ProjectContactForm", () => {
beforeEach(() => {
jest.restoreAllMocks();

environment = createMockEnvironment();
});

Expand All @@ -159,16 +168,13 @@ describe("The ProjectContactForm", () => {
});

it("Calls the addContactToRevision mutation when the Add button is clicked", () => {
const mutationSpy = jest.fn();
jest
.spyOn(require("app/mutations/useMutationWithErrorMessage"), "default")
.mockImplementation(() => [mutationSpy, false]);
loadTestQuery();
renderProjectForm();

const addButton = screen.getByText("Add");
addButton.click();

expect(mutationSpy).toHaveBeenCalledWith({
expect(environment.mock.getMostRecentOperation().request).toMatchObject({
variables: {
connections: expect.any(Array),
input: {
Expand All @@ -180,79 +186,59 @@ describe("The ProjectContactForm", () => {
});

it("calls useMutationWithErrorMessage and returns expected message when the user clicks the Add button and there's a mutation error", () => {
loadTestQuery();
renderProjectForm();
const spy = jest.spyOn(
require("app/mutations/useMutationWithErrorMessage"),
"default"
);

userEvent.click(screen.getByText(/Add/i));
act(() => {
environment.mock.rejectMostRecentOperation(new Error());
});
const getErrorMessage = spy.mock.calls[0][1] as Function;

expect(getErrorMessage()).toBe(
"An error occurred while attempting to add a contact."
expect(errorContext.setError).toBeCalledWith(
"An error occurred while adding the contact to the revision."
);
});

it("Calls the updateFormChange mutation when the remove button is clicked", () => {
const mutationSpy = jest.fn();
jest
.mockImplementation(() => [mutationSpy, jest.fn()]);
.mockImplementation(() => [mutationSpy, false]);
loadTestQuery();
renderProjectForm();

const removeButton = screen.getAllByText("Remove")[0];
removeButton.click();

expect(mutationSpy).toHaveBeenCalledWith({
expect(environment.mock.getMostRecentOperation().request).toMatchObject({
variables: {
input: {
id: "Form ID 2",
},
connections: expect.any(Array),
},
onCompleted: expect.any(Function),
});
});

it("calls useMutationWithErrorMessage and returns expected message when the remove button is clicked", () => {
loadTestQuery();
renderProjectForm();
const spy = jest.spyOn(
require("app/mutations/useMutationWithErrorMessage"),
"default"
);

const removeButton = screen.getAllByText("Remove")[0];
removeButton.click();
act(() => {
environment.mock.rejectMostRecentOperation(new Error());
});
const getErrorMessage = spy.mock.calls[0][1] as Function;

expect(getErrorMessage()).toBe(
"An error occurred while attempting to add a contact."
expect(errorContext.setError).toBeCalledWith(
"An error occurred when deleting."
);
});

it("Clears the primary contact field when the Clear button is pressed", () => {
const mutationSpy = jest.fn();
jest
.spyOn(require("mutations/useDebouncedMutation"), "default")
.mockImplementation(() => [mutationSpy, false]);

jest
.spyOn(require("app/mutations/useMutationWithErrorMessage"), "default")
.mockImplementation(() => [jest.fn(), false]);
loadTestQuery();

renderProjectForm();

const clearButton = screen.getAllByText("Clear")[0];
clearButton.click();

expect(mutationSpy).toHaveBeenCalledWith({
expect(environment.mock.getMostRecentOperation().request).toMatchObject({
variables: {
input: {
id: "Form ID 1",
Expand All @@ -265,61 +251,37 @@ describe("The ProjectContactForm", () => {
},
},
},
optimisticResponse: {
updateFormChange: {
formChange: {
__typename: "FormChange",
id: "Form ID 1",
changeStatus: "pending",
updatedAt: "2020-01-01T00:00:00.000Z",
newFormData: {
contactIndex: 1,
projectId: 10,
},
operation: "CREATE",
},
},
},
debounceKey: "Form ID 1",
});
});

it("calls useMutationWithErrorMessage and returns expected message when the Clear button is pressed", () => {
//Warning: Expected `optimisticResponse` to match structure of server response for mutation `updateFormChangeMutation`
loadTestQuery();
renderProjectForm();
const spy = jest.spyOn(
require("app/mutations/useMutationWithErrorMessage"),
"default"
);

const clearButton = screen.getAllByText("Clear")[0];
clearButton.click();
act(() => {
environment.mock.rejectMostRecentOperation(new Error());
});
const getErrorMessage = spy.mock.calls[0][1] as Function;

expect(getErrorMessage()).toBe(
"An error occurred while attempting to add a contact."
expect(errorContext.setError).toBeCalledWith(
"An error occurred when updating the project contact form."
);
});

it("Validates all contact forms when validator is called", () => {
mocked(validateFormWithErrors).mockImplementation(() => []);
jest
.spyOn(require("app/mutations/useMutationWithErrorMessage"), "default")
.mockImplementation(() => [jest.fn(), jest.fn()]);

it("Validates all contact forms when the submit button is clicked", () => {
loadTestQuery();
renderProjectForm();

expect(props.setValidatingForm).toHaveBeenCalledWith({
selfValidate: expect.any(Function),
});

mocked(props.setValidatingForm).mock.calls[0][0].selfValidate();
const validateFormWithErrors = jest.spyOn(
require("lib/helpers/validateFormWithErrors"),
"default"
);

screen.getByText(/Submit/i).click();
// Once per form
expect(mocked(validateFormWithErrors)).toHaveBeenCalledTimes(3);
expect(validateFormWithErrors).toHaveBeenCalledTimes(3);
});

it("stages the form changes when the `submit` button is clicked", () => {
Expand Down
Loading

0 comments on commit 916260b

Please sign in to comment.