Skip to content

Commit 8970a22

Browse files
iusehooksAntonio
andauthored
useSelector implementation (#25)
Co-authored-by: Antonio <[email protected]>
1 parent e281bb8 commit 8970a22

34 files changed

+820
-147
lines changed

.babelrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ if (process.env.NODE_ENV === "test") {
1919
}
2020

2121
if (process.env.NODE_ENV === "development") {
22-
presets = ["@babel/preset-react"];
22+
presets = ["@babel/preset-env", "@babel/preset-react"];
2323
}
2424

2525
module.exports = {

.eslintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
}
2020
},
2121
"rules": {
22+
"no-unused-vars": ["error", { "varsIgnorePattern": "omit" }],
2223
"prettier/prettier": ["error", {
2324
"endOfLine":"auto",
2425
"trailingComma": "none",

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,13 @@ export default function App() {
6464
}
6565
```
6666

67+
## Author
68+
69+
- Antonio Pangallo [@antonio_pangall](https://twitter.com/antonio_pangall)
70+
6771
## Code Sandboxes
6872

73+
- Twitter What's Happening Form Bar: [Sandbox](https://codesandbox.io/s/twitter-bar-form-czx3o)
6974
- Shopping Cart: [Sandbox](https://codesandbox.io/s/shopping-cart-97y5k)
7075
- Examples: Slider, Select, Collections etc..: [Sandbox](https://codesandbox.io/s/formexample2-mmcjs)
7176
- Various Implementation: [Sandbox](https://codesandbox.io/s/035l4l75ln)

__tests__/Collection.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ describe("Component => Collection", () => {
303303
it("should reduce a Collection of type object value with the given reducer function", () => {
304304
const initalValue = { name: "test" };
305305
const props = { onInit };
306-
const reducer = jest.fn((state, prevState) => {
306+
const reducer = jest.fn(state => {
307307
const newState = { ...state };
308308
if (newState.name !== "mickey") newState.name = "foo";
309309
return newState;

__tests__/Form.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ describe("Component => Form", () => {
419419
it("should reduce the Form state with the given reducer function", () => {
420420
const initialState = { name: "test" };
421421

422-
const reducer = jest.fn((state, prevState) => {
422+
const reducer = jest.fn(state => {
423423
const newState = { ...state };
424424
if (newState.name !== "mickey") newState.name = "foo";
425425
return newState;
@@ -709,7 +709,7 @@ describe("Component => Form", () => {
709709
});
710710

711711
it("should submitted, submitAttempts be equal for async func which does not explicitly resolve or reject", async () => {
712-
async function test(mIndex) {
712+
async function test() {
713713
return 1;
714714
}
715715
async function onSubmit() {

__tests__/Input.spec.js

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import React from "react";
2-
import { act } from "react-dom/test-utils";
3-
import { render, fireEvent, waitFor, cleanup } from "@testing-library/react";
2+
import {
3+
render,
4+
fireEvent,
5+
waitFor,
6+
cleanup,
7+
act
8+
} from "@testing-library/react";
9+
import userEvent from "@testing-library/user-event";
410

5-
import Form, { Input } from "./../src";
11+
import { Form, Input } from "./../src";
612

713
import InputAsync from "./helpers/components/InputAsync";
814
import InputSyncValidation from "./helpers/components/InputSyncValidation";
@@ -126,6 +132,58 @@ describe("Component => Input", () => {
126132
expect(onSubmit).toHaveBeenCalledWith({ text: "text" }, true);
127133
});
128134

135+
it("should render Input of type file single/multiple and upload files", () => {
136+
const singeFile = "singeFile";
137+
const multipleFile = "multipleFile";
138+
const props = { onChange };
139+
const fileValue = new File(["(⌐□_□)"], "file.xml", {
140+
type: "application/xml"
141+
});
142+
const files = [
143+
new File(["hello"], "hello.png", { type: "image/png" }),
144+
new File(["there"], "there.png", { type: "image/png" })
145+
];
146+
147+
const children = [
148+
<Input key="1" data-testid={singeFile} type="file" name={singeFile} />,
149+
<Input
150+
key="2"
151+
multiple
152+
data-testid={multipleFile}
153+
type="file"
154+
name={multipleFile}
155+
/>
156+
];
157+
const { getByTestId } = mountForm({ children, props });
158+
const fileInput = getByTestId(singeFile);
159+
const fileInputMultiple = getByTestId(multipleFile);
160+
161+
act(() => {
162+
userEvent.upload(fileInput, fileValue);
163+
});
164+
expect(onChange).toHaveBeenCalledWith({ [singeFile]: fileValue }, true);
165+
166+
act(() => {
167+
userEvent.upload(fileInputMultiple, files);
168+
});
169+
170+
expect(onChange).toHaveBeenCalledWith(
171+
{ [singeFile]: fileValue, [multipleFile]: files },
172+
true
173+
);
174+
175+
expect(fileInput.type).toBe("file");
176+
expect(fileInput.files[0]).toStrictEqual(fileValue);
177+
expect(fileInput.files.item(0)).toStrictEqual(fileValue);
178+
expect(fileInput.files).toHaveLength(1);
179+
180+
expect(fileInputMultiple.type).toBe("file");
181+
expect(fileInputMultiple.multiple).toBe(true);
182+
expect(fileInputMultiple.files).toHaveLength(2);
183+
expect(fileInputMultiple.files[0]).toStrictEqual(files[0]);
184+
expect(fileInputMultiple.files[1]).toStrictEqual(files[1]);
185+
});
186+
129187
it("should trigger onChange event when the Input value changes", () => {
130188
const onChangeInput = jest.fn(value => value);
131189
const children = [

__tests__/helpers/components/AgeRange.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from "react";
22
import { Input, Collection } from "./../../../src";
33

4-
const preventAge = (state, prevState, formState) => {
4+
const preventAge = (state, prevState) => {
55
let newState = { ...state };
66
if (newState.end < prevState.start) newState.end = prevState.start;
77

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React, { useState } from "react";
2+
import { useSelector } from "./../../../src";
3+
4+
export const CmpWithSelectorToggle = ({ id = "", ...props }) => {
5+
const [visible, toggle] = useState(() => true);
6+
7+
return (
8+
<>
9+
{visible && <CmpWithSelector id={id} {...props} />}
10+
<button
11+
type="button"
12+
data-testid={`toggle${id}`}
13+
onClick={() => toggle(prev => !prev)}
14+
/>
15+
</>
16+
);
17+
};
18+
19+
export const CmpWithSelector = ({ selector, setNewValue, id = "" }) => {
20+
const [value = "", setValue] = useSelector(selector);
21+
22+
const valueToShow = typeof value === "object" ? JSON.stringify(value) : value;
23+
return (
24+
<>
25+
<pre>
26+
<code data-testid={`selector${id}`}>{valueToShow}</code>
27+
</pre>
28+
<button
29+
type="button"
30+
data-testid={`selectorBtn${id}`}
31+
onClick={() => setValue(setNewValue)}
32+
/>
33+
</>
34+
);
35+
};

__tests__/hooks/useField.spec.js

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
import React from "react";
2-
import { render, fireEvent, cleanup } from "@testing-library/react";
3-
import Form, { Collection, useField, withIndex } from "./../../src";
2+
import { render, fireEvent, cleanup, act } from "@testing-library/react";
3+
import { Form, Collection, useField, withIndex } from "./../../src";
44

55
const InputCustom = withIndex(({ type, name, value, index, ...restAttr }) => {
66
const props = useField({ type, name, value, index });
77
return <input {...restAttr} {...props}></input>;
88
});
99

10+
const CustomField = withIndex(({ name, value, ...restAttr }) => {
11+
const props = useField({ type: "custom", name, value });
12+
const onChange = () => props.onChange({ target: { value: "5" } });
13+
return (
14+
<button type="button" onClick={onChange} {...restAttr}>
15+
Change Value
16+
</button>
17+
);
18+
});
19+
1020
const InputCustomNoAutoIndex = ({ type, name, value, index, ...restAttr }) => {
1121
const props = useField({ type, name, value, index });
1222
return <input {...restAttr} {...props}></input>;
@@ -59,6 +69,25 @@ describe("Hooks => useField", () => {
5969
expect(onChange).toHaveBeenCalledWith({ number: "50", number2: "5" }, true);
6070
});
6171

72+
it("should render a Field of type custom with an initial value", () => {
73+
const name = "custom";
74+
const props = { onInit, onChange };
75+
const initial = { a: "test" };
76+
77+
const children = [
78+
<CustomField key="1" data-testid={name} name={name} value={initial} />
79+
];
80+
const { getByTestId } = mountForm({ children, props });
81+
expect(onInit).toHaveBeenCalledWith({ [name]: initial }, true);
82+
83+
const custom = getByTestId("custom");
84+
act(() => {
85+
fireEvent.click(custom);
86+
});
87+
88+
expect(onChange).toHaveBeenCalledWith({ [name]: "5" }, true);
89+
});
90+
6291
it("should change a Field value due to an action", () => {
6392
const props = { onChange };
6493
const children = [

0 commit comments

Comments
 (0)