|
1 |
| -# jest-when |
| 1 | +# react-context-reverse |
2 | 2 |
|
3 | 3 | ```
|
4 |
| -npm i --save-dev jest-when |
| 4 | +npm i --save-dev react-context-reverse |
5 | 5 | ```
|
6 | 6 |
|
7 |
| -A sugary way to mock return values for specific arguments only. |
| 7 | +Similar to React.createContext() but instead of the ancestor passing data to it's descendant, the descendant passes data to a single ancestor. |
8 | 8 |
|
9 |
| -#### Basic usage: |
| 9 | +#### Usage: |
10 | 10 |
|
11 |
| -```javascript |
12 |
| -import { when } from "jest-when"; |
| 11 | +Use the `createReverseContext` function just like you would use the `React.createContext` function. |
13 | 12 |
|
14 |
| -const fn = jest.fn(); |
15 |
| -when(fn) |
16 |
| - .calledWith(1) |
17 |
| - .mockReturnValue("yay!"); |
| 13 | +The difference is it returns a Context object with a: |
18 | 14 |
|
19 |
| -const result = fn(1); |
20 |
| -expect(result).toEqual("yay!"); |
21 |
| -``` |
22 |
| - |
23 |
| -#### Supports multiple args: |
24 |
| - |
25 |
| -```javascript |
26 |
| -import { when } from "jest-when"; |
27 |
| - |
28 |
| -const fn = jest.fn(); |
29 |
| -when(fn) |
30 |
| - .calledWith(1, true, "foo") |
31 |
| - .mockReturnValue("yay!"); |
32 |
| - |
33 |
| -const result = fn(1, true, "foo"); |
34 |
| -expect(result).toEqual("yay!"); |
35 |
| -``` |
36 |
| - |
37 |
| -#### Supports training for single calls |
38 |
| - |
39 |
| -```javascript |
40 |
| -import { when } from "jest-when"; |
41 |
| - |
42 |
| -const fn = jest.fn(); |
43 |
| -when(fn) |
44 |
| - .calledWith(1, true, "foo") |
45 |
| - .mockReturnValueOnce("yay!"); |
46 |
| -when(fn) |
47 |
| - .calledWith(1, true, "foo") |
48 |
| - .mockReturnValueOnce("nay!"); |
| 15 | +- `<Context.ReverseProvider>`: Component used in a child/descendant component to provide a value to the context. |
| 16 | +- `<Context.ReverseConsumer>`: Component used in the parent/ancestor component to consume the provided value from the context. |
49 | 17 |
|
50 |
| -expect(fn(1, true, "foo")).toEqual("yay!"); |
51 |
| -expect(fn(1, true, "foo")).toEqual("nay!"); |
52 |
| -expect(fn(1, true, "foo")).toBeUndefined(); |
53 |
| -``` |
54 |
| - |
55 |
| -#### Supports Promises |
56 |
| - |
57 |
| -```javascript |
58 |
| -import { when } from "jest-when"; |
| 18 | +**Note:** I made the names `ReverseProvider` and `ReverseConsumer` to avoid confusion with a regular `Provider` and `Consumer`. |
59 | 19 |
|
60 |
| -const fn = jest.fn(); |
61 |
| -when(fn) |
62 |
| - .calledWith(1, true, "foo") |
63 |
| - .mockResolvedValue("yay!"); |
64 |
| -when(fn) |
65 |
| - .calledWith(2, false, "bar") |
66 |
| - .mockResolvedValueOnce("nay!"); |
| 20 | +#### Example: |
67 | 21 |
|
68 |
| -expect(await fn(1, true, "foo")).toEqual("yay!"); |
69 |
| -expect(await fn(1, true, "foo")).toEqual("yay!"); |
70 |
| - |
71 |
| -expect(await fn(2, false, "bar")).toEqual("nay!"); |
72 |
| -expect(await fn(2, false, "bar")).toBeUndefined(); |
73 |
| -``` |
| 22 | +In this example, we are going to add a disabled class to a `<label>` if it's nested `<input>` is disabled. |
74 | 23 |
|
75 |
| -#### Supports jest matchers: |
| 24 | +```jsx |
| 25 | +//////////////// |
| 26 | +/* Example.js */ |
| 27 | +//////////////// |
76 | 28 |
|
77 |
| -```javascript |
78 |
| -import { when } from "jest-when"; |
| 29 | +import { Label } from "./Label"; |
| 30 | +import { Checkbox } from "./Checkbox"; |
79 | 31 |
|
80 |
| -const fn = jest.fn(); |
81 |
| -when(fn) |
82 |
| - .calledWith( |
83 |
| - expect.anything(), |
84 |
| - expect.any(Number), |
85 |
| - expect.arrayContaining(false) |
86 |
| - ) |
87 |
| - .mockReturnValue("yay!"); |
88 |
| - |
89 |
| -const result = fn("whatever", 100, [true, false]); |
90 |
| -expect(result).toEqual("yay!"); |
91 |
| -``` |
92 |
| - |
93 |
| -#### Supports compound declarations: |
94 |
| - |
95 |
| -```javascript |
96 |
| -import { when } from "jest-when"; |
97 |
| - |
98 |
| -const fn = jest.fn(); |
99 |
| -when(fn) |
100 |
| - .calledWith(1) |
101 |
| - .mockReturnValue("no"); |
102 |
| -when(fn) |
103 |
| - .calledWith(2) |
104 |
| - .mockReturnValue("way?"); |
105 |
| -when(fn) |
106 |
| - .calledWith(3) |
107 |
| - .mockReturnValue("yes"); |
108 |
| -when(fn) |
109 |
| - .calledWith(4) |
110 |
| - .mockReturnValue("way!"); |
111 |
| - |
112 |
| -expect(fn(1)).toEqual("no"); |
113 |
| -expect(fn(2)).toEqual("way?"); |
114 |
| -expect(fn(3)).toEqual("yes"); |
115 |
| -expect(fn(4)).toEqual("way!"); |
116 |
| -expect(fn(5)).toEqual(undefined); |
117 |
| -``` |
| 32 | +export const Example = () => ( |
| 33 | + <Label> |
| 34 | + <Checkbox disabled /> // Note: the child has some disabled state to share |
| 35 | + Check Me |
| 36 | + </Label> |
| 37 | +); |
118 | 38 |
|
119 |
| -#### Assert the args: |
| 39 | +////////////// |
| 40 | +/* Label.js */ |
| 41 | +////////////// |
120 | 42 |
|
121 |
| -Use `expectCalledWith` instead to run an assertion that the `fn` was called with the provided args. Your test will fail if the jest mock function is ever called without those exact `expectCalledWith` params. |
| 43 | +import { createReverseContext } from 'react-context-reverse' |
122 | 44 |
|
123 |
| -Disclaimer: This won't really work very well with compound declarations, because one of them will always fail, and throw an assertion error. |
| 45 | +// We start by creating a reverse context to consume |
| 46 | +// the disabled context of the child checkbox |
| 47 | +export const DisabledContext = createReverseContext(false); |
124 | 48 |
|
125 |
| -```javascript |
126 |
| -import { when } from "jest-when"; |
| 49 | +// In the parent we use the ReverseConsumer, it provides |
| 50 | +// the value of the context via a child function |
| 51 | +export const Label = props => ( |
| 52 | + <DisabledContext.ReverseConsumer> |
| 53 | + {disabled => ( |
| 54 | + <label {...props} className={cx("Label", disabled && "is-disabled")} /> |
| 55 | + )} |
| 56 | + </DisabledContext.ReverseConsumer> |
| 57 | +); |
127 | 58 |
|
128 |
| -const fn = jest.fn(); |
129 |
| -when(fn) |
130 |
| - .expectCalledWith(1) |
131 |
| - .mockReturnValue("x"); |
| 59 | +////////////// |
| 60 | +/* Input.js */ |
| 61 | +////////////// |
| 62 | +import { DisabledContext } from "./Label"; |
132 | 63 |
|
133 |
| -fn(2); // Will throw a helpful jest assertion error with args diff |
| 64 | +// In the child we use the ReverseProvider, we provide |
| 65 | +// the value to the context |
| 66 | +export const Checkbox = props => ( |
| 67 | + <DisabledContext.ReverseProvider value={props.disabled}> |
| 68 | + <input {...props} type="checkbox" className="Checkbox" /> |
| 69 | + </DisabledContext.ReverseProvider> |
| 70 | +); |
134 | 71 | ```
|
0 commit comments