Skip to content

Commit

Permalink
add touched prop to collection for sync validations (#20)
Browse files Browse the repository at this point in the history
Co-authored-by: Antonio <[email protected]>
  • Loading branch information
iusehooks and Antonio committed Dec 16, 2020
1 parent 48f3c02 commit 9291181
Show file tree
Hide file tree
Showing 30 changed files with 772 additions and 101 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ npm install --save usetheform
import React from "react";
import Form, { Input, useValidation } from "usetheform";

const preventNegativeNumber = (next, prev) => (next <= 0 ? 0 : next);
const required = (value) =>
value && value.trim() !== "" ? undefined : "Required";

export default function App() {
const onChange = (formState) => console.log("ON_CHANGE : ", formState);
const onSubmit = (formState) => console.log("ON_SUBMIT : ", formState);

const preventNegativeNumber = (next, prev) => (next <= 0 ? 0 : next);
const required = (value) =>
value && value.trim() !== "" ? undefined : "Required";

const [status, validation] = useValidation([required]);

return (
Expand Down
99 changes: 97 additions & 2 deletions __tests__/Collection.spec.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import React from "react";
import { act } from "react-dom/test-utils";

import {
render,
fireEvent,
waitForElement,
cleanup
} from "@testing-library/react";

import Form, { Input, Collection } from "./../src";
import { Form, Input, Collection } from "./../src";

import { CollectionDynamicCart } from "./helpers/components/CollectionDynamicField";
import CollectionValidation from "./helpers/components/CollectionValidation";
import CollectionDynamicAdded from "./helpers/components/CollectionDynamicAdded";
import CollectionValidation, {
CollectionValidationTouched
} from "./helpers/components/CollectionValidation";
import CollectionAsyncValidation from "./helpers/components/CollectionAsyncValidation";
import CollectionArrayNested, {
initialValue as initialValueNested,
Expand Down Expand Up @@ -133,6 +138,96 @@ describe("Component => Collection", () => {
);
});

it("should add/remove collection dynamically and reset the errors message validation to the proper value", async () => {
const children = [<CollectionDynamicAdded key="1" />, <Reset key="2" />];
const { getByTestId, getAllByTestId } = mountForm({ children });

const addCollection = getByTestId("addCollection");
const removeCollection = getByTestId("removeCollection");

// no error initially
expect(() => getByTestId("errorLabel")).toThrow();
expect(() => getByTestId("errorLabelCollection")).toThrow();

fireEvent.click(addCollection);

let input_1 = getByTestId("input1");
fireEvent.change(input_1, { target: { value: "ab" } });

let errorLabel = getByTestId("errorLabel");
expect(errorLabel).toBeDefined();

// Collection has touched = true
act(() => {
input_1.focus();
input_1.blur();
});
let errorLabelCollection = getByTestId("errorLabelCollection");
expect(errorLabelCollection).toBeDefined();

fireEvent.click(removeCollection);
expect(() => getAllByTestId("errorLabel")).toThrow();
expect(() => getByTestId("errorLabelCollection")).toThrow();

fireEvent.click(addCollection);
let input_2 = getByTestId("input2");
fireEvent.change(input_2, { target: { value: "3" } });
expect(() => getByTestId("errorLabel")).toThrow();

// Collection has touched = true
act(() => {
input_2.focus();
input_2.blur();
});

expect(() => getByTestId("errorLabelCollection")).toThrow();
});

it("should trigger validation when touched prop is true and only if any of its children is touched at any nested level", async () => {
const children = [
<CollectionValidationTouched key="1" />,
<Reset key="2" />
];
const { getByTestId, getAllByTestId } = mountForm({ children });

const addMember = getByTestId("addMember");
fireEvent.click(addMember);

let member = getByTestId("member_name");

expect(() => getAllByTestId("errorLabel")).toThrow();
fireEvent.change(member, { target: { value: "Foo" } });
expect(() => getAllByTestId("errorLabel")).toThrow();

// Collection has touched = true
act(() => {
member.focus();
member.blur();
});

let errorLabel = getByTestId("errorLabel");
expect(errorLabel).toBeDefined();

fireEvent.click(addMember);

const reset = getByTestId("reset");
fireEvent.click(reset);
expect(() => getAllByTestId("member")).toThrow();
expect(() => getAllByTestId("errorLabel")).toThrow();

fireEvent.click(addMember);
member = getByTestId("member_name");

// Collection has touched = true
act(() => {
member.focus();
member.blur();
});

errorLabel = getByTestId("errorLabel");
expect(errorLabel).toBeDefined();
});

it("should show an error label if Collection is not valid due to sync validator", () => {
const children = [
<CollectionValidation key="1" />,
Expand Down
91 changes: 91 additions & 0 deletions __tests__/Input.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from "react";
import { act } from "react-dom/test-utils";
import {
render,
fireEvent,
Expand All @@ -9,6 +10,7 @@ import {
import Form, { Input } from "./../src";

import InputAsync from "./helpers/components/InputAsync";
import InputSyncValidation from "./helpers/components/InputSyncValidation";
import Submit from "./helpers/components/Submit";
import Reset from "./helpers/components/Reset";
import { SimpleFormDynamicField } from "./helpers/components/SimpleForm";
Expand Down Expand Up @@ -271,6 +273,95 @@ describe("Component => Input", () => {
expect(onReset).toHaveBeenCalledWith({ [name]: value }, false);
});

it("should use sync validator functions to validate the Input with touched prop true", () => {
const name = "test";
const props = { onReset, onChange };
const children = [
<InputSyncValidation name={name} touched={true} key="1" />,
<Reset key="2" />
];

const { getByTestId } = mountForm({ children, props });

const input = getByTestId("input");
fireEvent.change(input, { target: { value: "1234" } });
expect(onChange).toHaveBeenCalledWith({ [name]: "1234" }, true);

expect(() => getByTestId("errorLabel")).toThrow();

fireEvent.change(input, { target: { value: "" } });
act(() => {
input.focus();
input.blur();
});

const errorLabel = getByTestId("errorLabel");
expect(errorLabel).toBeDefined();

const reset = getByTestId("reset");
fireEvent.click(reset);
expect(onReset).toHaveBeenCalledWith({}, false);
expect(() => getByTestId("errorLabel")).toThrow();
});

it("should use sync validator functions to validate the Input with touched prop false", () => {
const name = "test";
const props = { onReset, onChange };
const children = [
<InputSyncValidation name={name} touched={false} key="1" />,
<Reset key="2" />
];

const { getByTestId } = mountForm({ children, props });
const input = getByTestId("input");

// touched false errorLabel must be present
let errorLabel = getByTestId("errorLabel");
expect(errorLabel).toBeDefined();

fireEvent.change(input, { target: { value: "1234" } });
expect(onChange).toHaveBeenCalledWith({ [name]: "1234" }, true);

expect(() => getByTestId("errorLabel")).toThrow();

fireEvent.change(input, { target: { value: "" } });

errorLabel = getByTestId("errorLabel");
expect(errorLabel).toBeDefined();

const reset = getByTestId("reset");
fireEvent.click(reset);
expect(onReset).toHaveBeenCalledWith({}, false);

errorLabel = getByTestId("errorLabel");
expect(errorLabel).toBeDefined();
});

it("should use sync validator functions to validate the Input with touched prop false and initial value", () => {
const name = "test";
const value = "123";
const props = { onReset, onChange };
const children = [
<InputSyncValidation name={name} touched={false} key="1" value={value} />,
<Reset key="2" />
];

const { getByTestId } = mountForm({ children, props });
const input = getByTestId("input");

expect(() => getByTestId("errorLabel")).toThrow();

fireEvent.change(input, { target: { value: "" } });
let errorLabel = getByTestId("errorLabel");
expect(errorLabel).toBeDefined();

const reset = getByTestId("reset");
fireEvent.click(reset);
expect(onReset).toHaveBeenCalledWith({ [name]: value }, true);

expect(() => getByTestId("errorLabel")).toThrow();
});

it("should use an async validator function to validate the Input", async () => {
const value = "33";
const name = "test";
Expand Down
Loading

0 comments on commit 9291181

Please sign in to comment.