Skip to content

Commit

Permalink
Form action attribute async validation (#17)
Browse files Browse the repository at this point in the history
* Add action attribute fo form and async validation

* add npm dev script to start a test browser in dev mode

* React Strict Mode fixed for array context

* 3.0.0-alpha.0

* clean code comments

* Docz styles (#16)

* 3.0.0-alpha.0

* DOCZ_STYLES docz styles changes

* clean code comments

Co-authored-by: Antonio <[email protected]>
Co-authored-by: Antonio Pangallo <[email protected]>

* fix typo in docz

* unit test improved

* improve doc

* improve doc

* improve doc

* cover usetheform

* remove cover usetheform

* update doc

* Improve array collection autoIndex

* 3.0.0-alpha.1

* improve examples

* improve examples

* withIndex - auto indexing fields

* 3.0.0-alpha.2

* withIndex - auto indexing fields

* removing comments

* fix index - uniqueid - array collection

* 3.0.0-alpha.3

* add ON_RUN_ASYNC status

* reducers applied on fields removal from collections

* 3.0.0-alpha.4

* adding codesandbox example

* optimize Form using useMemo and React.memo

* 3.0.0-alpha.5

* fix radios reset feature

* 3.0.0-alpha.6

* added unit tests for radio buttons into nested object collection

* 3.0.0-alpha.7

* improve FormContext performances

* 3.0.0-alpha.8

* fix useNameProp

* 3.0.0-alpha.9

* unit test Form dynamic

* fix example

* refactoring useField

* added submitted and submittingAttempts counters

* refactoring useForm and useCollection

* 3.0.0-alpha.10

* fix number input type

* 3.0.0-beta.0

* add validators flag argument to onInit, onChange, onReset funcs

* 3.0.0-beta.1

* 3.0.0

* add unit test for some inputs type

* removing unused code

* fix audit

Co-authored-by: Antonio <[email protected]>
Co-authored-by: Antonio Pangallo <[email protected]>
  • Loading branch information
3 people committed Oct 7, 2020
1 parent f7c833b commit 44b8389
Show file tree
Hide file tree
Showing 83 changed files with 23,843 additions and 17,407 deletions.
4 changes: 4 additions & 0 deletions .babelrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ if (process.env.NODE_ENV === "test") {
plugins.push("@babel/transform-modules-commonjs");
}

if (process.env.NODE_ENV === "development") {
presets = ["@babel/preset-react"];
}

module.exports = {
presets,
plugins
Expand Down
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
**/build/**
**/build/**
**/dev/**
**/node_modules/**
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ node_modules
.DS_Store
dist
build
dev
coverage
_config.yml
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# <img src='https://iusehooks.github.io/usetheform/docs/gatsby-theme-docz/assets/logo.png' width="233" height='51' alt='Usetheform Logo' />

Usetheform is a React library for composing declarative forms and managing their state. It uses the Context API and React Hooks. I does not depend on any libray like redux or others.
Usetheform is a React library for composing declarative forms and managing their state. It uses the Context API and React Hooks. I does not depend on any library like redux or others.

- [Documentation](https://iusehooks.github.io/usetheform/)
- [Installation](#Installation)
Expand All @@ -21,6 +21,7 @@ npm install --save usetheform

# CodeSandbox Examples

- Shopping Cart: [Sandbox](https://codesandbox.io/s/shopping-cart-97y5k)
- Examples: Slider, Select, Collections etc..: [Sandbox](https://codesandbox.io/s/formexample2-mmcjs)
- Various Implementation: [Sandbox](https://codesandbox.io/s/035l4l75ln)
- Wizard: [Sandbox](https://codesandbox.io/s/v680xok7k7)
Expand Down
188 changes: 188 additions & 0 deletions __tests__/AsyncValidationFormStrictMode.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import React from "react";
import {
render,
cleanup,
fireEvent,
waitForElement,
act
} from "@testing-library/react";

import {
SimpleFormWithAsyncStrictMode,
expectedInitialState
} from "./helpers/components/SimpleFormWithAsync";

const mountForm = ({ props = {} } = {}) =>
render(
<React.StrictMode>
<SimpleFormWithAsyncStrictMode {...props} />
</React.StrictMode>
);

const onInit = jest.fn(state => state);
const onChange = jest.fn(state => state);
const onReset = jest.fn(state => state);
const onSubmit = jest.fn(state => state);

afterEach(cleanup);

describe("Async Validation Form StrictMode => Async Validation", () => {
beforeEach(() => {
onInit.mockClear();
onChange.mockClear();
onReset.mockClear();
onSubmit.mockClear();
});

it("should run Async validators at Form initialization time", async () => {
const props = { onInit, onSubmit, onChange, onReset };

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

const submit = getByTestId("submit");

const asyncStartUsername = await waitForElement(() =>
getByTestId("asyncStartUsername")
);
expect(asyncStartUsername).toBeDefined();

const asyncStartCity = await waitForElement(() =>
getByTestId("asyncStartCity")
);
expect(asyncStartCity).toBeDefined();

const asyncErrorDetails = await waitForElement(() =>
getByTestId("asyncErrorDetails")
);
expect(asyncErrorDetails).toBeDefined();

expect(onInit).toHaveReturnedWith(expectedInitialState);
expect(submit.disabled).toBe(true);
});

it("should run Async validators on fields or Collections changes", async () => {
const props = { onInit, onSubmit, onChange, onReset };

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

const submit = getByTestId("submit");
const reset = getByTestId("reset");

const addInputs = getByTestId("addInput");
const removeInputs = getByTestId("removeInput");

const asyncErrorDetails = await waitForElement(() =>
getByTestId("asyncErrorDetails")
);
expect(asyncErrorDetails).toBeDefined();

const details = getByTestId("details");

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

expect(details.value).toBe("3331234567");

const asyncSuccessDetails = await waitForElement(() =>
getByTestId("asyncSuccessDetails")
);

expect(asyncSuccessDetails).toBeDefined();

const email = getByTestId("email");

act(() => {
email.focus();
fireEvent.change(email, { target: { value: "[email protected]" } });
email.blur();
});

expect(email.value).toBe("[email protected]");
expect(submit.disabled).toBe(false);

fireEvent.click(submit);

let asyncErrorCollection = await waitForElement(() =>
getByTestId("asyncError")
);

expect(asyncErrorCollection).toBeDefined();

const submittedCounter = getByTestId("submittedCounter");
expect(submittedCounter.textContent).toBe("0");

fireEvent.click(addInputs);
fireEvent.click(addInputs);
fireEvent.click(submit);

const asyncSuccessCollection = await waitForElement(() =>
getByTestId("asyncSuccess")
);

expect(asyncSuccessCollection).toBeDefined();
expect(submittedCounter.textContent).toBe("1");

fireEvent.click(removeInputs);
fireEvent.click(submit);

asyncErrorCollection = await waitForElement(() =>
getByTestId("asyncError")
);

expect(asyncErrorCollection).toBeDefined();

fireEvent.click(removeInputs);
fireEvent.click(reset);
expect(onReset).toHaveReturnedWith(expectedInitialState);

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

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

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

act(() => {
details.focus();
details.blur();
});

const asyncStartDetailsAfterReset = await waitForElement(() =>
getByTestId("asyncStartDetails")
);
expect(asyncStartDetailsAfterReset).toBeDefined();

const asyncErrorDetailsAfterReset = await waitForElement(() =>
getByTestId("asyncErrorDetails")
);
expect(asyncErrorDetailsAfterReset).toBeDefined();

const username = getByTestId("username");
const city = getByTestId("city");
act(() => {
username.focus();
username.blur();
city.focus();
city.blur();
});

const [
asyncStartUsernameAfterReset,
asyncStartCityAfterReset
] = await waitForElement(() =>
Promise.all([
getByTestId("asyncStartUsername"),
getByTestId("asyncStartCity")
])
);
expect(asyncStartUsernameAfterReset).toBeDefined();
expect(asyncStartCityAfterReset).toBeDefined();
});
});
Loading

0 comments on commit 44b8389

Please sign in to comment.