Skip to content

Add user friendly validation errors for required and pattern fields on integration modal #5212

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

Merged
merged 15 commits into from
Feb 23, 2023

Conversation

mnholtz
Copy link
Collaborator

@mnholtz mnholtz commented Feb 18, 2023

What does this PR do?

Reviewer Tips

  • buildYup has an errMessages options you can pass to config to define custom error messages per field. The approach I've taken here is to walk the schema & add generic validation messages for properties with required and pattern fields

Discussion

  • Alternative implementation is to add an errMessages field to the schema itself which get collected via getValidationErrMessages (which would allow for more specific validation messages). I originally shied away from doing this, because it wouldn't match the JSONSchema7 type. However, it looks like we're mutating the schema anyways by adding config?

Demo/Discussion

https://www.loom.com/share/2affe022ae9848cebdbf336a2276f997

Checklist

  • Add tests
  • Designate a primary reviewer @BLoe

};
}

if (schema.properties[key].pattern) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm getting a type error for pattern on this type which is apparently JSONSchema7Definition. Does anyone happen to know what type this object actually is?

Copy link
Contributor

Choose a reason for hiding this comment

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

JSONSchema has some types where boolean is an allowed variant. So you likely need to handle that case

name: "controlRoomUrl",
});
await userEvent.type(controlRoomUrlInput, "https://invalid.control.room/");
expect(controlRoomUrlInput).toHaveValue("https://invalid.control.room/");
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This test is failing here - no value is actually getting modified. Any ideas what's going on?

Copy link
Contributor

Choose a reason for hiding this comment

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

I suspect you need to add an await tick() or await waitForEffect(). For controlled components, I think there's some React involved in changing the value of the input in the DOM

@twschiller
Copy link
Contributor

twschiller commented Feb 19, 2023

However, it looks like we're mutating the schema anyways by adding config?

Could you add a code reference? Where/what is mutating the schema?

Alternative implementation is to add an errMessages field to the schema itself which get collected via

There's some prior art for how people declaratively define custom error messages. You're correct though that the official JSON Schema spec doesn't have them

The AJV project, for example supports an errorMessage prop with handling for the different kinds of errors (pattern, required, etc.): https://github.com/ajv-validator/ajv-errors

We use a different JSON Schema validator that doesn't rely on Function constructor: @cfworker/json-schema

Discussion on the JSON Schema project here: json-schema-org/json-schema-spec#1075

I'm find with the JS approach you're taking for now to solve the immediate UI/UX pain. We'll likely want to move to supporting custom messages in the JSON Schema in the future, but that will require additional work to determine approach

@twschiller twschiller added this to the 1.7.20 milestone Feb 19, 2023
@codecov
Copy link

codecov bot commented Feb 21, 2023

Codecov Report

Merging #5212 (f84355a) into main (cb4cfc6) will increase coverage by 0.01%.
The diff coverage is 84.21%.

❗ Current head f84355a differs from pull request most recent head e937bf8. Consider uploading reports for the commit e937bf8 to get more accurate results

@@            Coverage Diff             @@
##             main    #5212      +/-   ##
==========================================
+ Coverage   61.27%   61.28%   +0.01%     
==========================================
  Files         989      989              
  Lines       30746    30764      +18     
  Branches     5922     5928       +6     
==========================================
+ Hits        18840    18855      +15     
- Misses      11906    11909       +3     
Impacted Files Coverage Δ
src/components/fields/fieldUtils.ts 80.70% <82.35%> (+0.70%) ⬆️
src/options/pages/services/ServiceEditorModal.tsx 81.13% <100.00%> (+0.36%) ⬆️

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@@ -54,4 +56,32 @@ describe("ServiceEditorModal", () => {
const dialogRoot = screen.getByRole("dialog");
expect(dialogRoot).toMatchSnapshot();
});

// eslint-disable-next-line jest/no-disabled-tests -- FIXME: for some reason, userEvent.type (the alternative approach of using fireEvent) is not modifying the value of the textarea
test.skip("displays user-friendly pattern validation message", async () => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ticket for this here: #5237

Spent several hours trying to debug this 🤷‍♀️

@mnholtz mnholtz marked this pull request as ready for review February 21, 2023 23:55
Copy link
Contributor

@BLoe BLoe left a comment

Choose a reason for hiding this comment

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

Had some questions and code style suggestions. Depends on the answer to the questions as to whether they are blockers or not. Overall makes sense though! Sorry the test never worked out properly.

): Record<string, Record<string, string>> => {
const errMessages: Record<string, Record<string, string>> = {};

if (schema) {
Copy link
Contributor

@BLoe BLoe Feb 22, 2023

Choose a reason for hiding this comment

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

You could do an early-return here instead for code readability, to avoid nesting the entire function one level:

if (!schema) {
  return errMessages;
}

Comment on lines 121 to 125
errMessages[key] = {
// eslint-disable-next-line security/detect-object-injection
...(errMessages[key] ? {} : errMessages[key]),
required: `${key} is required`,
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a big deal if you like this syntax, but spreading props like this with a ternary inside is hard to parse at a glance for me. Maybe something like this would be more clear?

const messages = errMessages[key] ? {};

if (...) {
  messages.required = ...
}

if (...) {
  messages.pattern = ...
}

// Lodash _.isEmpty()
if (!isEmpty(messages)) {
 errMessages[key] = messages;
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Wow, this suggestion made the function look miles better. Thanks!

@github-actions
Copy link

When the PR is merged, the first loom link found on this PR will be posted to #sprint-demo on Slack. Do not edit this comment manually.

@mnholtz mnholtz enabled auto-merge (squash) February 23, 2023 19:31
@mnholtz mnholtz merged commit 3cb5b5b into main Feb 23, 2023
@mnholtz mnholtz deleted the bugfix/aa_user_friendly_error branch February 23, 2023 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Automation Anywhere Control Room Integration User Friendly Alerts
3 participants