Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1222 vitest widgets #1605

Merged
merged 14 commits into from
May 17, 2024
Merged

1222 vitest widgets #1605

merged 14 commits into from
May 17, 2024

Conversation

marcellmueller
Copy link
Contributor

@marcellmueller marcellmueller commented May 3, 2024

Implements #1222

Added Vitest coverage report which can be run using yarn coverage. We haven't discussed testing coverage but could be a good topic for dev team agreements. Most of these tests have good coverage but there are a few that could be improved especially the FileWidget.
Screenshot 2024-05-03 at 10 54 28 AM

Comment on lines 11 to 6
"react/react-in-jsx-scope": "off",
"react/jsx-uses-react": "off",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was added to remove a warning from the nx merge airbnb rules. Basically it gives an error if you use jsx in a file without importing React at the top of each file 🤮

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I actually removed this since I rebased on Josh's PR which fixed these eslint rules!

@@ -10,6 +10,7 @@ const ReadOnlyComboBoxWidget: React.FC<WidgetProps> = ({
];
const selectedValue =
fieldSchema &&
value &&
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found this bug while testing the empty state of the read only widget. Without this added it would show a selected value even if there was no value 😱

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😱 nice find!

Comment on lines +8 to +12
"reg:coverage": "nx run registration:test --coverage",
"reg:test": "nx run registration:test"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hot reloading is currently not working. To enable it I believe we will have to update nx, so I decided to make it's own issue:

#1610

@marcellmueller marcellmueller marked this pull request as ready for review May 6, 2024 16:14
expect(screen.queryByText(urlErrorMessage)).toBeNull();
});

// Todo: Fix bug preventing required field validation
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix I did ages ago for the URL widget empty string error prevents it from being set to a required field. There is more context in this bug ticket though it's something we should handle properly in the future.

#1612

},
};

describe("RJSF FileWidget", () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels like this could be more thoroughly tested. What are we missing here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • should allow user to select a file for upload, then remove it?
  • should display an error when trying to upload files greater than ? (iirc, when Brianna implemented file upload, she added a file size limit)
  • (if we have restrictions on file type in place?) should display an error message when an "undesired" file (e.g., .exe) is uploaded
  • if we want to be really on the ball, should allow file types of .kml and .kmz to be uploaded

Copy link
Contributor Author

@marcellmueller marcellmueller May 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I've done what I can here but some things to note as our FileWidget is super basic at the moment:

  • There is no feature to remove the file. I added a test to verify that we can replace the current file though.
  • The accept functionality for file types just blocks them from being selected in the document browser and we don't currently have any built in validation messages. I added a test that verifies that the input won't accept a non-pdf.
  • I added a test to confirm that the accept option would accept .kml/.kmz. I wasn't sure if you meant you actually wanted that enabled for the file upload field on the operations form. It would be easy to do but I only added a test.
  • Added a couple tests for the 20mb maximum, one to verify it won't accept that input and one that uses spyOn for the window alert and makes sure it gets called.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the test cases for FileWidget are very comprehensive now - great work @BCerki and @marcellmueller !

Copy link
Contributor

@andrea-williams andrea-williams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fantastic work Marcel!

@@ -10,6 +10,7 @@ const ReadOnlyComboBoxWidget: React.FC<WidgetProps> = ({
];
const selectedValue =
fieldSchema &&
value &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😱 nice find!


export const comboBoxFieldSchema = {
type: "object",
required: ["comboBoxTestField"],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

likely just me being an idiot, but why is the value of required an array of strings? I would have expected a bool

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take a look at any of our actual form schemas. In JSONSchema format this is an array of all required fields in an object. If it is a nested object then it requires it's own array for those fields.

expect(comboBoxInput.value).toBe("Option 3");
});

it("should allow clearing a combo box value", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feels like we should have an additional test here to assert that multiple values can be selected simultaneously in the comboBox?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-review: not seeing a test case for multiple simultaneous values...?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we can select more than one option in the comboBox. We can in the MultiSelectWidget

"data:application/pdf;name=dummy.pdf;base64,ZHVtbXk=";
const mockFile = new File(["test"], "test.pdf", { type: "application/pdf" });

vi.resetAllMocks();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: is this needed here when it's also called in beforeEach()?

},
};

describe("RJSF FileWidget", () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • should allow user to select a file for upload, then remove it?
  • should display an error when trying to upload files greater than ? (iirc, when Brianna implemented file upload, she added a file size limit)
  • (if we have restrictions on file type in place?) should display an error message when an "undesired" file (e.g., .exe) is uploaded
  • if we want to be really on the ball, should allow file types of .kml and .kmz to be uploaded

expect(input).toHaveValue("test");
});

it("should only allow entering numbers in a number field", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the other use case we might need in the future is decimal values (e.g., 23.5)
and in the case of reporting in particular, I'd expect there will be users typing in large values like "1,320,000" so maybe a test with commas in the input value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good add a should not allow entering commas in a number field test.

it("should trigger validation error for invalid URL", async () => {
render(<FormBase schema={urlFieldSchema} uiSchema={urlFieldUiSchema} />);
const input = screen.getByLabelText(urlLabelRequired);
await userEvent.type(input, "example.com");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how hard/easy is it to change this behaviour? IMO, "example.com" should be considered a valid URL. As a naive user, I wouldn't expect to have to specify "https://www.example.com" - I don't consider that to be the norm anymore.
I would call "example" or ".com" invalid URLs.

{end rant}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha I pushed to create our own custom validation for this because I thought forcing users to add http:// or https:// before a url was silly. Though I got overridden pre-mvp. There is a ticket for it, it's out of scope for this PR.

@marcellmueller marcellmueller force-pushed the 1222-vitest-widgets branch from 809b074 to 0d6d99c Compare May 9, 2024 15:14
Copy link
Contributor

@BCerki BCerki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests are super comprehensive, great work! I've reviewed everything except the file widget, which I'm going to spend a little more time with today. Re my comments about adding test coverage--I've mentioned things I noticed aren't covered, but I'm not sure they do need to be covered (e.g. custom onBlur). Just wanted to points out gaps in case you hadn't already considered them.

expect(checkbox).toBeChecked();
});

it("should allow unchecking the checkbox", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing tests for:

  • when field is required

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A boolean field can't be required. It's either true or it's false.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if it's optional users can just not select anything and the form will still submit. I added a test for when it's required and I did get an error message

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good call @BCerki - we will need the option to make checkboxes required when external users are accepting terms & conditions (or the equivalent for BCIERS - more likely to be something like "I confirm that the information I've submitted is accurate")

"data:application/pdf;name=dummy.pdf;base64,ZHVtbXk=";
const mockFile = new File(["test"], "test.pdf", { type: "application/pdf" });

vi.resetAllMocks();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is needed here; it's in already in beforeEach

Comment on lines 110 to 135
const selectedOption1 = screen.getByRole("button", { name: "Option 2" });
const selectedOption2 = screen.getByRole("button", { name: "Option 3" });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest naming the variables the same number as the option to avoid confusion

Comment on lines 112 to 138
const optionCancelIcon = screen.getByTestId("CloseIcon");

await userEvent.click(optionCancelIcon);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have expected this to fail because if there are two chips, then getByTestId would choke because there are two close icons. But it seems to have worked?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TestId is CancelIcon

} from "@/tests/components/form/widgets/ComboBox.test";

describe("RJSF ReadOnlyComboBoxWidget", () => {
it("should render a combo box field", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This additionally checks that the form data comes through correctly, so suggest adding something about that to the test name

} from "@/tests/components/form/widgets/MultiSelectWidget.test";

describe("RJSF ReadOnlyMultiSelectWidget", () => {
it("should render a multi select field", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same, the formData part isn't captured in the test name

@BCerki BCerki force-pushed the 1222-vitest-widgets branch from 48d615c to a0e9971 Compare May 13, 2024 22:48
Copy link
Contributor

@BCerki BCerki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anything marked with the rocket ship emoji I've implemented


const fileFieldLabel = "FileWidget test field";
const fileLabelRequired = `${fileFieldLabel}*`;
export const dummyDataUri =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we please use something other than "dummy"? "Mock," "sample," whatever

const input = screen.getByLabelText(fileLabelRequired);
await userEvent.upload(input, mockFile);

actionHandler.mockResolvedValueOnce({});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to mock the actionHandler here? If I remember right, the file doesn't get uploaded until the user clicks submit, so I wouldn't expect the actionHandler to fire at this point

screen.queryByRole("button", { name: "Upload attachment" }),
).not.toBeInTheDocument();
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible tests to add coverage:

  • something for this: We need to store the value in state to prevent loosing the value when user switches between tabs
  • file input is correctly hidden
  • required
  • replacing an uploaded file when there was one in the formData (I already see a test for replacing one before it got submitted)
  • it looks sort of like the file widget is set up to upload more than one file (processFiles function) but we only allow uploading one

Copy link
Contributor

@BCerki BCerki May 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find a way to test tab-switching-- Document.visibilityState was the closest and that's not really it. Did the rest

expect(checkbox).toBeChecked();
});

it("should allow unchecking the checkbox", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if it's optional users can just not select anything and the form will still submit. I added a test for when it's required and I did get an error message

Comment on lines 112 to 138
const optionCancelIcon = screen.getByTestId("CloseIcon");

await userEvent.click(optionCancelIcon);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TestId is CancelIcon

"12345678",
);
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error for this case is about formatting, which isn't accurate, so created this ticket: https://github.com/orgs/bcgov/projects/122/views/2?filterQuery=&pane=issue&itemId=62787538

expect(optionYes).not.toBeChecked();
expect(optionNo).toBeChecked();
expect(optionMaybe).not.toBeChecked();
});
Copy link
Contributor

@BCerki BCerki May 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did the required errors part, not sure if the custom functions need tests; they look like they're coming from node_modules

@BCerki BCerki force-pushed the 1222-vitest-widgets branch from fc0c845 to b08b4f6 Compare May 14, 2024 16:24
expect(inputBorderElement).toHaveStyle(errorStyle);
};

export const checkNoValidationErrorIsTriggered = async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes this causes test errors, so not using it everywhere yet

@BCerki BCerki force-pushed the 1222-vitest-widgets branch 3 times, most recently from 4a3a31c to 666a911 Compare May 15, 2024 16:59
Copy link
Contributor

@andrea-williams andrea-williams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my brain is kaput - will continue reviewing this tomorrow

expect(checkbox).toBeChecked();
});

it("should allow unchecking the checkbox", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good call @BCerki - we will need the option to make checkboxes required when external users are accepting terms & conditions (or the equivalent for BCIERS - more likely to be something like "I confirm that the information I've submitted is accurate")

expect(comboBoxInput.value).toBe("Option 3");
});

it("should allow clearing a combo box value", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-review: not seeing a test case for multiple simultaneous values...?

@BCerki BCerki force-pushed the 1222-vitest-widgets branch from 666a911 to f75bbd4 Compare May 16, 2024 15:56
<FormBase schema={emailFieldSchema} uiSchema={emailFieldUiSchema} />,
);
const input = screen.getByLabelText(emailLabelRequired);
await userEvent.type(input, "test.email@test.com");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This input doesn't match the test description of a "subdomain" - I propose changing the input to test@email.test.com

},
};

describe("RJSF FileWidget", () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the test cases for FileWidget are very comprehensive now - great work @BCerki and @marcellmueller !


await userEvent.click(submitButton);

expect(screen.getByText("Format should be A1A 1A1")).toBeVisible();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Horrible thought: if we're accepting American phone numbers, should we also be accepting American zip codes...? (This thought makes me sad.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😱 I'll ask the designers

screen.getByPlaceholderText("Select regulated products..."),
).toBeVisible();
});
it("should use the enum values as the names if no enumNames are provided, use the enum values as the names", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test name seems a little repetitive, a little bit

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point point

@BCerki BCerki force-pushed the 1222-vitest-widgets branch from f75bbd4 to 7916473 Compare May 16, 2024 23:28
Copy link
Contributor

@andrea-williams andrea-williams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not able to run the tests locally because something wacky is going on with my local git. (Grrrr).

But code LGTM and it's the end of day before a long weekend so I'm feeling especially reckless.

@BCerki
Copy link
Contributor

BCerki commented May 17, 2024

Not able to run the tests locally because something wacky is going on with my local git. (Grrrr).

But code LGTM and it's the end of day before a long weekend so I'm feeling especially reckless.

I too like to live dangerously

@BCerki BCerki merged commit f0f5345 into develop May 17, 2024
23 of 24 checks passed
@BCerki BCerki deleted the 1222-vitest-widgets branch May 17, 2024 15:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants