Skip to content

Commit

Permalink
feat: expose validate, validateAttribute and setErrors to the context
Browse files Browse the repository at this point in the history
This is to make the context and state management more flexible. This
comes in handy when you have larger forms when nested context. You can
now validate sections of the form independently.
  • Loading branch information
AdeAttwood committed Apr 1, 2023
1 parent 06ff464 commit 18f0610
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 7 deletions.
21 changes: 16 additions & 5 deletions src/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ export class Form<T extends Record<string, any>> extends React.Component<FormPro
submit = async (event: React.SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
this.setState({ status: "validating" });
const errors = await this.props.validator?.validate(this.state.formState);
const status = this.getErrorStatus(errors || {});
if (errors && status === "error") {
const errors = await this.validate(this.state.formState);
const status = this.getErrorStatus(errors);
if (status === "error") {
return this.setState({ errors, status });
}

Expand Down Expand Up @@ -266,6 +266,14 @@ export class Form<T extends Record<string, any>> extends React.Component<FormPro
return await fun(attribute, formState);
};

validate = async (formState: T): Promise<ErrorBag> => {
if (!this.props.validator?.validate) {
return {};
}

return await this.props.validator.validate(formState);
};

/**
* Get if the error bag has errors or is valid. In this case it will return
* "clean" to indicate the form is valid.
Expand All @@ -279,13 +287,16 @@ export class Form<T extends Record<string, any>> extends React.Component<FormPro
*/
private getContextValue = () => {
return {
status: this.state.status,
formState: this.state.formState,
errors: this.state.errors,
firstError: this.firstError,
formState: this.state.formState,
getAttribute: this.getAttribute,
setAttribute: this.setAttribute,
setErrors: this.setErrors,
status: this.state.status,
submit: this.submit,
validate: this.validate,
validateAttribute: this.validateAttribute,
};
};

Expand Down
28 changes: 28 additions & 0 deletions tests/form-context.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from "react";
import { renderHook, act } from "@testing-library/react";

import { Form, useFormContext, createValidator } from "../src";

it("will allow you to validate the form from the context", async () => {
const onSubmit = jest.fn();

const validator = createValidator({ test: [() => "I will always fail"] });

const { result } = renderHook(() => useFormContext(), {
wrapper: ({ children }) => (
<Form onSubmit={onSubmit} validator={validator}>
{children}
</Form>
),
});

const errors = await result.current.validate(result.current.formState);
expect(errors).toStrictEqual({ test: ["I will always fail"] });

const attributeErrors = await result.current.validateAttribute("test-1", result.current.formState);
expect(attributeErrors).toHaveLength(0);

expect(result.current.status).toBe("clean");
await act(async () => result.current.setErrors(errors));
expect(result.current.status).toBe("error");
});
2 changes: 1 addition & 1 deletion tests/form-status.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ it("validate and submit", async () => {
});

await waitFor(() => expect(formContext.current?.status).toBe("validating"), { timeout: 5000 });
validateResolve();
validateResolve({});

await waitFor(() => expect(formContext.current?.status).toBe("submitting"), { timeout: 5000 });
onSubmitResolve();
Expand Down
2 changes: 1 addition & 1 deletion tests/validation.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ it("will validate the data with a raw function", async () => {
});

it("will validate after input delay", async () => {
const validate = jest.fn();
const validate = jest.fn(async () => ({}));
const validateAttribute = jest.fn(async () => []);

render(
Expand Down

0 comments on commit 18f0610

Please sign in to comment.