@openmrs/esm-react-utils 5.8.2-pre.2533 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/jest.config.js +1 -0
- package/package.json +11 -12
- package/src/ConfigurableLink.test.tsx +7 -5
- package/src/extensions.test.tsx +45 -24
- package/src/openmrsComponentDecorator.test.tsx +21 -24
- package/src/useAbortController.test.tsx +1 -3
- package/src/useConfig.test.tsx +22 -16
- package/src/useOnClickOutside.test.tsx +4 -5
- package/src/useOpenmrsFetchAll.test.tsx +1 -3
- package/src/useOpenmrsInfinite.test.tsx +1 -3
- package/src/useOpenmrsPagination.test.tsx +1 -3
package/.turbo/turbo-build.log
CHANGED
|
@@ -11,4 +11,4 @@ built modules 295 KiB [built]
|
|
|
11
11
|
./src/index.ts + 138 modules 284 KiB [built] [code generated]
|
|
12
12
|
../esm-state/dist/openmrs-esm-state.js 8.12 KiB [built] [code generated]
|
|
13
13
|
+ 5 modules
|
|
14
|
-
webpack 5.88.0 compiled successfully in
|
|
14
|
+
webpack 5.88.0 compiled successfully in 8039 ms
|
package/jest.config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmrs/esm-react-utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"description": "React utilities for OpenMRS.",
|
|
6
6
|
"browser": "dist/openmrs-esm-react-utils.js",
|
|
@@ -61,15 +61,15 @@
|
|
|
61
61
|
"swr": "2.x"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@openmrs/esm-api": "
|
|
65
|
-
"@openmrs/esm-config": "
|
|
66
|
-
"@openmrs/esm-context": "
|
|
67
|
-
"@openmrs/esm-error-handling": "
|
|
68
|
-
"@openmrs/esm-extensions": "
|
|
69
|
-
"@openmrs/esm-feature-flags": "
|
|
70
|
-
"@openmrs/esm-globals": "
|
|
71
|
-
"@openmrs/esm-navigation": "
|
|
72
|
-
"@openmrs/esm-utils": "
|
|
64
|
+
"@openmrs/esm-api": "6.0.0",
|
|
65
|
+
"@openmrs/esm-config": "6.0.0",
|
|
66
|
+
"@openmrs/esm-context": "6.0.0",
|
|
67
|
+
"@openmrs/esm-error-handling": "6.0.0",
|
|
68
|
+
"@openmrs/esm-extensions": "6.0.0",
|
|
69
|
+
"@openmrs/esm-feature-flags": "6.0.0",
|
|
70
|
+
"@openmrs/esm-globals": "6.0.0",
|
|
71
|
+
"@openmrs/esm-navigation": "6.0.0",
|
|
72
|
+
"@openmrs/esm-utils": "6.0.0",
|
|
73
73
|
"dayjs": "^1.10.8",
|
|
74
74
|
"i18next": "^21.10.0",
|
|
75
75
|
"react": "^18.1.0",
|
|
@@ -78,6 +78,5 @@
|
|
|
78
78
|
"rxjs": "^6.5.3",
|
|
79
79
|
"swr": "^2.2.5",
|
|
80
80
|
"webpack": "^5.88.0"
|
|
81
|
-
}
|
|
82
|
-
"stableVersion": "5.8.1"
|
|
81
|
+
}
|
|
83
82
|
}
|
|
@@ -7,7 +7,7 @@ import { ConfigurableLink } from './ConfigurableLink';
|
|
|
7
7
|
|
|
8
8
|
jest.mock('single-spa');
|
|
9
9
|
|
|
10
|
-
const mockNavigate =
|
|
10
|
+
const mockNavigate = jest.mocked(navigate);
|
|
11
11
|
|
|
12
12
|
describe(`ConfigurableLink`, () => {
|
|
13
13
|
const path = '${openmrsSpaBase}/home';
|
|
@@ -15,19 +15,21 @@ describe(`ConfigurableLink`, () => {
|
|
|
15
15
|
mockNavigate.mockClear();
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
it(
|
|
18
|
+
it('interpolates the link', async () => {
|
|
19
19
|
render(
|
|
20
20
|
<ConfigurableLink to={path} className="fancy-link">
|
|
21
21
|
SPA Home
|
|
22
22
|
</ConfigurableLink>,
|
|
23
23
|
);
|
|
24
24
|
const link = screen.getByRole('link', { name: /spa home/i });
|
|
25
|
-
expect(link).
|
|
25
|
+
expect(link).toBeInTheDocument();
|
|
26
|
+
// eslint-disable-next-line testing-library/no-node-access
|
|
26
27
|
expect(link.closest('a')).toHaveClass('fancy-link');
|
|
28
|
+
// eslint-disable-next-line testing-library/no-node-access
|
|
27
29
|
expect(link.closest('a')).toHaveAttribute('href', '/openmrs/spa/home');
|
|
28
30
|
});
|
|
29
31
|
|
|
30
|
-
it(
|
|
32
|
+
it('calls navigate on normal click but not special clicks', async () => {
|
|
31
33
|
render(
|
|
32
34
|
<ConfigurableLink to={path} className="fancy-link">
|
|
33
35
|
SPA Home
|
|
@@ -42,7 +44,7 @@ describe(`ConfigurableLink`, () => {
|
|
|
42
44
|
expect(navigate).toHaveBeenCalledWith({ to: path });
|
|
43
45
|
});
|
|
44
46
|
|
|
45
|
-
it(
|
|
47
|
+
it('calls navigate on enter', async () => {
|
|
46
48
|
render(
|
|
47
49
|
<ConfigurableLink to={path} className="fancy-link">
|
|
48
50
|
SPA Home
|
package/src/extensions.test.tsx
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import React, { useReducer } from 'react';
|
|
2
3
|
import '@testing-library/jest-dom';
|
|
4
|
+
import userEvent from '@testing-library/user-event';
|
|
3
5
|
import { act, render, screen, waitFor, within } from '@testing-library/react';
|
|
6
|
+
import { registerFeatureFlag, setFeatureFlag } from '@openmrs/esm-feature-flags';
|
|
4
7
|
import {
|
|
5
8
|
attach,
|
|
6
|
-
type ConnectedExtension,
|
|
7
9
|
getExtensionNameFromId,
|
|
8
10
|
registerExtension,
|
|
9
11
|
updateInternalExtensionStore,
|
|
@@ -14,32 +16,29 @@ import {
|
|
|
14
16
|
ExtensionSlot,
|
|
15
17
|
openmrsComponentDecorator,
|
|
16
18
|
useExtensionSlotMeta,
|
|
17
|
-
type ExtensionData,
|
|
18
19
|
useRenderableExtensions,
|
|
19
20
|
} from '.';
|
|
20
|
-
import userEvent from '@testing-library/user-event';
|
|
21
|
-
import { registerFeatureFlag, setFeatureFlag } from '@openmrs/esm-feature-flags';
|
|
22
21
|
|
|
23
22
|
// For some reason in the test context `isEqual` always returns true
|
|
24
23
|
// when using the import substitution in jest.config.js. Here's a custom
|
|
25
24
|
// mock.
|
|
26
|
-
jest.mock('lodash-es/isEqual', () => (a, b) => JSON.stringify(a)
|
|
25
|
+
jest.mock('lodash-es/isEqual', () => (a, b) => JSON.stringify(a) === JSON.stringify(b));
|
|
27
26
|
|
|
28
27
|
describe('ExtensionSlot, Extension, and useExtensionSlotMeta', () => {
|
|
29
28
|
beforeEach(() => {
|
|
30
29
|
updateInternalExtensionStore(() => ({ slots: {}, extensions: {} }));
|
|
31
30
|
});
|
|
32
31
|
|
|
33
|
-
afterEach(() => {
|
|
34
|
-
jest.clearAllMocks();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
32
|
test('Extension receives state changes passed through (not using <Extension>)', async () => {
|
|
33
|
+
const user = userEvent.setup();
|
|
34
|
+
|
|
38
35
|
function EnglishExtension({ suffix }) {
|
|
39
36
|
return <div>English{suffix}</div>;
|
|
40
37
|
}
|
|
38
|
+
|
|
41
39
|
registerSimpleExtension('English', 'esm-languages-app', EnglishExtension);
|
|
42
40
|
attach('Box', 'English');
|
|
41
|
+
|
|
43
42
|
const App = openmrsComponentDecorator({
|
|
44
43
|
moduleName: 'esm-languages-app',
|
|
45
44
|
featureName: 'Languages',
|
|
@@ -53,20 +52,25 @@ describe('ExtensionSlot, Extension, and useExtensionSlotMeta', () => {
|
|
|
53
52
|
</div>
|
|
54
53
|
);
|
|
55
54
|
});
|
|
55
|
+
|
|
56
56
|
render(<App />);
|
|
57
57
|
|
|
58
|
-
await
|
|
58
|
+
expect(await screen.findByText(/English/)).toBeInTheDocument();
|
|
59
59
|
expect(screen.getByText(/English/)).toHaveTextContent('English!');
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
await user.click(screen.getByText('Toggle suffix'));
|
|
61
|
+
expect(screen.getByText(/English/)).toHaveTextContent('English?');
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
test('Extension receives state changes (using <Extension>)', async () => {
|
|
65
|
+
const user = userEvent.setup();
|
|
66
|
+
|
|
65
67
|
function HaitianCreoleExtension({ suffix }) {
|
|
66
68
|
return <div>Haitian Creole{suffix}</div>;
|
|
67
69
|
}
|
|
70
|
+
|
|
68
71
|
registerSimpleExtension('Haitian', 'esm-languages-app', HaitianCreoleExtension);
|
|
69
72
|
attach('Box', 'Haitian');
|
|
73
|
+
|
|
70
74
|
const App = openmrsComponentDecorator({
|
|
71
75
|
moduleName: 'esm-languages-app',
|
|
72
76
|
featureName: 'Languages',
|
|
@@ -84,21 +88,24 @@ describe('ExtensionSlot, Extension, and useExtensionSlotMeta', () => {
|
|
|
84
88
|
</div>
|
|
85
89
|
);
|
|
86
90
|
});
|
|
91
|
+
|
|
87
92
|
render(<App />);
|
|
88
93
|
|
|
89
|
-
await
|
|
94
|
+
expect(await screen.findByText(/Haitian/)).toBeInTheDocument();
|
|
90
95
|
expect(screen.getByText(/Haitian/)).toHaveTextContent('Haitian Creole!');
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
await user.click(screen.getByText('Toggle suffix'));
|
|
97
|
+
expect(screen.getByText(/Haitian/)).toHaveTextContent('Haitian Creole?');
|
|
93
98
|
});
|
|
94
99
|
|
|
95
100
|
test('ExtensionSlot throws error if both state and children provided', () => {
|
|
96
101
|
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
102
|
+
|
|
97
103
|
const App = () => (
|
|
98
104
|
<ExtensionSlot name="Box" state={{ color: 'red' }}>
|
|
99
105
|
<Extension />
|
|
100
106
|
</ExtensionSlot>
|
|
101
107
|
);
|
|
108
|
+
|
|
102
109
|
expect(() => render(<App />)).toThrow();
|
|
103
110
|
expect(consoleError).toHaveBeenNthCalledWith(
|
|
104
111
|
1,
|
|
@@ -116,6 +123,7 @@ describe('ExtensionSlot, Extension, and useExtensionSlotMeta', () => {
|
|
|
116
123
|
code: 'es',
|
|
117
124
|
});
|
|
118
125
|
attach('Box', 'Spanish');
|
|
126
|
+
|
|
119
127
|
const App = openmrsComponentDecorator({
|
|
120
128
|
moduleName: 'esm-languages-app',
|
|
121
129
|
featureName: 'Languages',
|
|
@@ -135,21 +143,26 @@ describe('ExtensionSlot, Extension, and useExtensionSlotMeta', () => {
|
|
|
135
143
|
</div>
|
|
136
144
|
);
|
|
137
145
|
});
|
|
146
|
+
|
|
138
147
|
render(<App />);
|
|
139
148
|
|
|
140
|
-
await
|
|
149
|
+
expect(await screen.findByRole('heading')).toBeInTheDocument();
|
|
141
150
|
expect(screen.getByRole('heading')).toHaveTextContent('es');
|
|
142
|
-
|
|
151
|
+
expect(screen.getByText('Spanish')).toBeInTheDocument();
|
|
143
152
|
});
|
|
144
153
|
|
|
145
154
|
test('Both meta and state can be used at the same time', async () => {
|
|
155
|
+
const user = userEvent.setup();
|
|
146
156
|
function SwahiliExtension({ suffix }) {
|
|
147
157
|
return <div>Swahili{suffix}</div>;
|
|
148
158
|
}
|
|
159
|
+
|
|
149
160
|
registerSimpleExtension('Swahili', 'esm-languages-app', SwahiliExtension, {
|
|
150
161
|
code: 'sw',
|
|
151
162
|
});
|
|
163
|
+
|
|
152
164
|
attach('Box', 'Swahili');
|
|
165
|
+
|
|
153
166
|
const App = openmrsComponentDecorator({
|
|
154
167
|
moduleName: 'esm-languages-app',
|
|
155
168
|
featureName: 'Languages',
|
|
@@ -171,12 +184,13 @@ describe('ExtensionSlot, Extension, and useExtensionSlotMeta', () => {
|
|
|
171
184
|
</div>
|
|
172
185
|
);
|
|
173
186
|
});
|
|
187
|
+
|
|
174
188
|
render(<App />);
|
|
175
189
|
|
|
176
|
-
await
|
|
190
|
+
expect(await screen.findByRole('heading')).toBeInTheDocument();
|
|
177
191
|
expect(screen.getByRole('heading')).toHaveTextContent('sw');
|
|
178
192
|
await waitFor(() => expect(screen.getByText(/Swahili/)).toHaveTextContent('Swahili!'));
|
|
179
|
-
|
|
193
|
+
await user.click(screen.getByText('Toggle suffix'));
|
|
180
194
|
await waitFor(() => expect(screen.getByText(/Swahili/)).toHaveTextContent('Swahili?'));
|
|
181
195
|
});
|
|
182
196
|
|
|
@@ -187,8 +201,10 @@ describe('ExtensionSlot, Extension, and useExtensionSlotMeta', () => {
|
|
|
187
201
|
registerSimpleExtension('Hindi', 'esm-languages-app', undefined, {
|
|
188
202
|
code: 'hi',
|
|
189
203
|
});
|
|
204
|
+
|
|
190
205
|
attach('Box', 'Urdu');
|
|
191
206
|
attach('Box', 'Hindi');
|
|
207
|
+
|
|
192
208
|
const App = openmrsComponentDecorator({
|
|
193
209
|
moduleName: 'esm-languages-app',
|
|
194
210
|
featureName: 'Languages',
|
|
@@ -207,9 +223,10 @@ describe('ExtensionSlot, Extension, and useExtensionSlotMeta', () => {
|
|
|
207
223
|
</div>
|
|
208
224
|
);
|
|
209
225
|
});
|
|
226
|
+
|
|
210
227
|
render(<App />);
|
|
211
228
|
|
|
212
|
-
await
|
|
229
|
+
expect(await screen.findByTestId('Urdu')).toBeInTheDocument();
|
|
213
230
|
expect(within(screen.getByTestId('Urdu')).getByRole('heading')).toHaveTextContent('urd');
|
|
214
231
|
expect(within(screen.getByTestId('Hindi')).getByRole('heading')).toHaveTextContent('hi');
|
|
215
232
|
});
|
|
@@ -219,18 +236,22 @@ describe('ExtensionSlot, Extension, and useExtensionSlotMeta', () => {
|
|
|
219
236
|
registerSimpleExtension('Turkish', 'esm-languages-app', undefined, undefined, 'turkic');
|
|
220
237
|
registerSimpleExtension('Turkmeni', 'esm-languages-app', undefined, undefined, 'turkic');
|
|
221
238
|
registerSimpleExtension('Kurmanji', 'esm-languages-app', undefined, undefined, 'kurdish');
|
|
239
|
+
|
|
222
240
|
attach('Box', 'Arabic');
|
|
223
241
|
attach('Box', 'Turkish');
|
|
224
242
|
attach('Box', 'Turkmeni');
|
|
225
243
|
attach('Box', 'Kurmanji');
|
|
244
|
+
|
|
226
245
|
registerFeatureFlag('turkic', '', '');
|
|
227
246
|
registerFeatureFlag('kurdish', '', '');
|
|
228
247
|
setFeatureFlag('turkic', true);
|
|
248
|
+
|
|
229
249
|
const App = openmrsComponentDecorator({
|
|
230
250
|
moduleName: 'esm-languages-app',
|
|
231
251
|
featureName: 'Languages',
|
|
232
252
|
disableTranslations: true,
|
|
233
253
|
})(() => <ExtensionSlot name="Box" />);
|
|
254
|
+
|
|
234
255
|
render(<App />);
|
|
235
256
|
|
|
236
257
|
await waitFor(() => expect(screen.getByText(/Turkmeni/)).toBeInTheDocument());
|
|
@@ -255,13 +276,13 @@ describe('ExtensionSlot, Extension, and useExtensionSlotMeta', () => {
|
|
|
255
276
|
featureName: 'Languages',
|
|
256
277
|
disableTranslations: true,
|
|
257
278
|
})(() => {
|
|
258
|
-
const
|
|
259
|
-
const Ext =
|
|
279
|
+
const utils = useRenderableExtensions('Box');
|
|
280
|
+
const Ext = utils[0];
|
|
260
281
|
return <Ext state={{ suffix: ' hola' }} />;
|
|
261
282
|
});
|
|
262
283
|
render(<App />);
|
|
263
284
|
|
|
264
|
-
await
|
|
285
|
+
expect(await screen.findByText('Spanish hola')).toBeInTheDocument();
|
|
265
286
|
});
|
|
266
287
|
});
|
|
267
288
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { Component } from 'react';
|
|
2
|
-
import { render, screen
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
3
|
import { openmrsComponentDecorator } from './openmrsComponentDecorator';
|
|
4
4
|
import { ComponentContext } from './ComponentContext';
|
|
5
5
|
|
|
@@ -10,11 +10,11 @@ describe('openmrs-component-decorator', () => {
|
|
|
10
10
|
moduleName: 'test',
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
it('renders a component', () => {
|
|
13
|
+
it('renders a component', async () => {
|
|
14
14
|
const DecoratedComp = openmrsComponentDecorator(opts)(CompThatWorks);
|
|
15
15
|
render(<DecoratedComp />);
|
|
16
16
|
|
|
17
|
-
screen.findByText('The button');
|
|
17
|
+
expect(await screen.findByText('The button')).toBeInTheDocument();
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
it('catches any errors in the component tree and renders a ui explaining something bad happened', () => {
|
|
@@ -36,21 +36,21 @@ describe('openmrs-component-decorator', () => {
|
|
|
36
36
|
render(<DecoratedComp />);
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
it(
|
|
39
|
+
it('rendering a unsafe component in strict mode should log error in console', () => {
|
|
40
40
|
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
})
|
|
41
|
+
const UnsafeDecoratedCompnent = openmrsComponentDecorator(opts)(UnsafeComponent);
|
|
42
|
+
render(<UnsafeDecoratedCompnent />);
|
|
43
|
+
expect(consoleError.mock.calls[0][0]).toContain('Warning: Using UNSAFE_componentWillMount');
|
|
44
|
+
consoleError.mockRestore();
|
|
45
|
+
});
|
|
46
46
|
|
|
47
|
-
it(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
})
|
|
47
|
+
it('rendering an unsafe component without strict mode should not log an error in console', () => {
|
|
48
|
+
const spy = jest.spyOn(console, 'error');
|
|
49
|
+
const unsafeComponentOptions = Object.assign(opts, { strictMode: false });
|
|
50
|
+
const UnsafeDecoratedCompnent = openmrsComponentDecorator(unsafeComponentOptions)(UnsafeComponent);
|
|
51
|
+
render(<UnsafeDecoratedCompnent />);
|
|
52
|
+
expect(spy).not.toHaveBeenCalled();
|
|
53
|
+
});
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
function CompThatWorks() {
|
|
@@ -66,13 +66,10 @@ function CompWithConfig() {
|
|
|
66
66
|
return <div>{moduleName}</div>;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
class UnsafeComponent extends Component<any, any> {
|
|
70
|
+
UNSAFE_componentWillMount() {}
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
render() {
|
|
76
|
-
return <h1>This is Unsafe Component</h1>;
|
|
77
|
-
}
|
|
72
|
+
render() {
|
|
73
|
+
return <h1>This is Unsafe Component</h1>;
|
|
74
|
+
}
|
|
78
75
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { renderHook
|
|
1
|
+
import { renderHook } from '@testing-library/react';
|
|
2
2
|
import '@testing-library/jest-dom';
|
|
3
3
|
import useAbortController from './useAbortController';
|
|
4
4
|
|
|
5
5
|
describe('useAbortController', () => {
|
|
6
|
-
afterEach(cleanup);
|
|
7
|
-
|
|
8
6
|
it('returns an AbortController', () => {
|
|
9
7
|
const { result } = renderHook(() => useAbortController());
|
|
10
8
|
expect(result.current).not.toBeNull();
|
package/src/useConfig.test.tsx
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
/* eslint-disable -- Test file uses React Testing Library patterns that conflict
|
|
2
|
+
with current ESLint rules. TODO: Investigate updating test patterns or ESLint config */
|
|
1
3
|
import React from 'react';
|
|
2
|
-
import {
|
|
4
|
+
import { act, render, screen, waitFor } from '@testing-library/react';
|
|
3
5
|
import {
|
|
6
|
+
configInternalStore,
|
|
4
7
|
defineConfigSchema,
|
|
5
|
-
temporaryConfigStore,
|
|
6
8
|
provide,
|
|
7
|
-
|
|
9
|
+
temporaryConfigStore,
|
|
8
10
|
type ConfigInternalStore,
|
|
9
11
|
} from '@openmrs/esm-config';
|
|
10
|
-
import type
|
|
12
|
+
import { type MockedStore } from '@openmrs/esm-state/mock';
|
|
11
13
|
import { useConfig } from './useConfig';
|
|
12
14
|
import { ComponentContext } from './ComponentContext';
|
|
13
15
|
|
|
@@ -32,7 +34,7 @@ function clearConfig() {
|
|
|
32
34
|
describe(`useConfig in root context`, () => {
|
|
33
35
|
afterEach(clearConfig);
|
|
34
36
|
|
|
35
|
-
it(
|
|
37
|
+
it('can return config as a react hook', async () => {
|
|
36
38
|
defineConfigSchema('foo-module', {
|
|
37
39
|
thing: {
|
|
38
40
|
_default: 'The first thing',
|
|
@@ -41,7 +43,7 @@ describe(`useConfig in root context`, () => {
|
|
|
41
43
|
|
|
42
44
|
render(
|
|
43
45
|
<React.Suspense fallback={<div>Suspense!</div>}>
|
|
44
|
-
<ComponentContext.Provider value={{ moduleName: 'foo-module' }}>
|
|
46
|
+
<ComponentContext.Provider value={{ moduleName: 'foo-module', featureName: 'foo-feature' }}>
|
|
45
47
|
<RenderConfig configKey="thing" />
|
|
46
48
|
</ComponentContext.Provider>
|
|
47
49
|
</React.Suspense>,
|
|
@@ -50,7 +52,7 @@ describe(`useConfig in root context`, () => {
|
|
|
50
52
|
await waitFor(() => expect(screen.findByText('The first thing')).toBeTruthy());
|
|
51
53
|
});
|
|
52
54
|
|
|
53
|
-
it(
|
|
55
|
+
it('can handle multiple calls to useConfig from different modules', async () => {
|
|
54
56
|
defineConfigSchema('foo-module', {
|
|
55
57
|
thing: {
|
|
56
58
|
_default: 'foo thing',
|
|
@@ -65,7 +67,7 @@ describe(`useConfig in root context`, () => {
|
|
|
65
67
|
|
|
66
68
|
render(
|
|
67
69
|
<React.Suspense fallback={<div>Suspense!</div>}>
|
|
68
|
-
<ComponentContext.Provider value={{ moduleName: 'foo-module' }}>
|
|
70
|
+
<ComponentContext.Provider value={{ moduleName: 'foo-module', featureName: 'foo-feature' }}>
|
|
69
71
|
<RenderConfig configKey="thing" />
|
|
70
72
|
</ComponentContext.Provider>
|
|
71
73
|
</React.Suspense>,
|
|
@@ -73,11 +75,9 @@ describe(`useConfig in root context`, () => {
|
|
|
73
75
|
|
|
74
76
|
await waitFor(() => expect(screen.findByText('foo thing')).toBeTruthy());
|
|
75
77
|
|
|
76
|
-
await cleanup();
|
|
77
|
-
|
|
78
78
|
render(
|
|
79
79
|
<React.Suspense fallback={<div>Suspense!</div>}>
|
|
80
|
-
<ComponentContext.Provider value={{ moduleName: 'bar-module' }}>
|
|
80
|
+
<ComponentContext.Provider value={{ moduleName: 'bar-module', featureName: 'bar-feature' }}>
|
|
81
81
|
<RenderConfig configKey="thing" />
|
|
82
82
|
</ComponentContext.Provider>
|
|
83
83
|
</React.Suspense>,
|
|
@@ -95,7 +95,7 @@ describe(`useConfig in root context`, () => {
|
|
|
95
95
|
|
|
96
96
|
render(
|
|
97
97
|
<React.Suspense fallback={<div>Suspense!</div>}>
|
|
98
|
-
<ComponentContext.Provider value={{ moduleName: 'foo-module' }}>
|
|
98
|
+
<ComponentContext.Provider value={{ moduleName: 'foo-module', featureName: 'foo-feature' }}>
|
|
99
99
|
<RenderConfig configKey="thing" />
|
|
100
100
|
</ComponentContext.Provider>
|
|
101
101
|
</React.Suspense>,
|
|
@@ -109,15 +109,14 @@ describe(`useConfig in root context`, () => {
|
|
|
109
109
|
}),
|
|
110
110
|
);
|
|
111
111
|
|
|
112
|
-
await
|
|
112
|
+
await screen.findByText('A new thing');
|
|
113
113
|
});
|
|
114
114
|
});
|
|
115
115
|
|
|
116
116
|
describe(`useConfig in an extension`, () => {
|
|
117
117
|
afterEach(clearConfig);
|
|
118
|
-
afterEach(cleanup);
|
|
119
118
|
|
|
120
|
-
it(
|
|
119
|
+
it('can return extension config as a react hook', async () => {
|
|
121
120
|
defineConfigSchema('ext-module', {
|
|
122
121
|
thing: {
|
|
123
122
|
_default: 'The basics',
|
|
@@ -129,6 +128,7 @@ describe(`useConfig in an extension`, () => {
|
|
|
129
128
|
<ComponentContext.Provider
|
|
130
129
|
value={{
|
|
131
130
|
moduleName: 'ext-module',
|
|
131
|
+
featureName: 'ext-feature',
|
|
132
132
|
extension: {
|
|
133
133
|
extensionSlotName: 'fooSlot',
|
|
134
134
|
extensionSlotModuleName: 'slot-mod',
|
|
@@ -144,7 +144,7 @@ describe(`useConfig in an extension`, () => {
|
|
|
144
144
|
await waitFor(() => expect(screen.findByText('The basics')).toBeTruthy());
|
|
145
145
|
});
|
|
146
146
|
|
|
147
|
-
it(
|
|
147
|
+
it('can handle multiple extensions', async () => {
|
|
148
148
|
defineConfigSchema('first-module', {
|
|
149
149
|
thing: {
|
|
150
150
|
_default: 'first thing',
|
|
@@ -162,6 +162,7 @@ describe(`useConfig in an extension`, () => {
|
|
|
162
162
|
<ComponentContext.Provider
|
|
163
163
|
value={{
|
|
164
164
|
moduleName: 'first-module',
|
|
165
|
+
featureName: 'first-feature',
|
|
165
166
|
extension: {
|
|
166
167
|
extensionSlotName: 'fooSlot',
|
|
167
168
|
extensionSlotModuleName: 'slot-mod',
|
|
@@ -174,6 +175,7 @@ describe(`useConfig in an extension`, () => {
|
|
|
174
175
|
<ComponentContext.Provider
|
|
175
176
|
value={{
|
|
176
177
|
moduleName: 'second-module',
|
|
178
|
+
featureName: 'second-feature',
|
|
177
179
|
extension: {
|
|
178
180
|
extensionSlotName: 'fooSlot',
|
|
179
181
|
extensionSlotModuleName: 'slot-mod',
|
|
@@ -214,6 +216,7 @@ describe(`useConfig in an extension`, () => {
|
|
|
214
216
|
<ComponentContext.Provider
|
|
215
217
|
value={{
|
|
216
218
|
moduleName: 'extension-module',
|
|
219
|
+
featureName: 'extension-feature',
|
|
217
220
|
extension: {
|
|
218
221
|
extensionSlotName: 'slot1',
|
|
219
222
|
extensionSlotModuleName: 'slot-1-module',
|
|
@@ -226,6 +229,7 @@ describe(`useConfig in an extension`, () => {
|
|
|
226
229
|
<ComponentContext.Provider
|
|
227
230
|
value={{
|
|
228
231
|
moduleName: 'extension-module',
|
|
232
|
+
featureName: 'extension-feature',
|
|
229
233
|
extension: {
|
|
230
234
|
extensionSlotName: 'slot2',
|
|
231
235
|
extensionSlotModuleName: 'slot-2-module',
|
|
@@ -254,6 +258,7 @@ describe(`useConfig in an extension`, () => {
|
|
|
254
258
|
<ComponentContext.Provider
|
|
255
259
|
value={{
|
|
256
260
|
moduleName: 'ext-module',
|
|
261
|
+
featureName: 'ext-feature',
|
|
257
262
|
extension: {
|
|
258
263
|
extensionSlotName: 'fooSlot',
|
|
259
264
|
extensionSlotModuleName: 'slot-module',
|
|
@@ -309,6 +314,7 @@ describe(`useConfig in an extension`, () => {
|
|
|
309
314
|
<ComponentContext.Provider
|
|
310
315
|
value={{
|
|
311
316
|
moduleName: 'first-module',
|
|
317
|
+
featureName: 'first-feature',
|
|
312
318
|
extension: {
|
|
313
319
|
extensionSlotName: 'fooSlot',
|
|
314
320
|
extensionSlotModuleName: 'slot-mod',
|
|
@@ -5,7 +5,6 @@ import { useOnClickOutside } from './useOnClickOutside';
|
|
|
5
5
|
|
|
6
6
|
describe('useOnClickOutside', () => {
|
|
7
7
|
const handler: (e: Event) => void = jest.fn();
|
|
8
|
-
afterEach(() => (handler as jest.Mock).mockClear());
|
|
9
8
|
|
|
10
9
|
it('should call the handler when clicking outside', async () => {
|
|
11
10
|
const user = userEvent.setup();
|
|
@@ -14,10 +13,10 @@ describe('useOnClickOutside', () => {
|
|
|
14
13
|
const ref = useOnClickOutside<HTMLDivElement>(handler);
|
|
15
14
|
return <div ref={ref}>{children}</div>;
|
|
16
15
|
};
|
|
17
|
-
const
|
|
16
|
+
const view = render(<Component />);
|
|
18
17
|
|
|
19
18
|
// act
|
|
20
|
-
await user.click(
|
|
19
|
+
await user.click(view.container);
|
|
21
20
|
|
|
22
21
|
// verify
|
|
23
22
|
expect(handler).toHaveBeenCalledTimes(1);
|
|
@@ -52,11 +51,11 @@ describe('useOnClickOutside', () => {
|
|
|
52
51
|
const ref = useOnClickOutside<HTMLDivElement>(handler);
|
|
53
52
|
return <div ref={ref}>{children}</div>;
|
|
54
53
|
};
|
|
55
|
-
const
|
|
54
|
+
const view = render(<Component />);
|
|
56
55
|
const spy = jest.spyOn(window, 'removeEventListener');
|
|
57
56
|
|
|
58
57
|
// act
|
|
59
|
-
|
|
58
|
+
view.unmount();
|
|
60
59
|
|
|
61
60
|
// verify
|
|
62
61
|
expect(spy).toHaveBeenCalledWith('mousedown', expect.any(Function));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { renderHook,
|
|
1
|
+
import { renderHook, waitFor } from '@testing-library/react';
|
|
2
2
|
import '@testing-library/jest-dom';
|
|
3
3
|
import { useOpenmrsFetchAll } from './useOpenmrsFetchAll';
|
|
4
4
|
import { type OpenMRSPaginatedResponse } from './useOpenmrsPagination';
|
|
@@ -27,8 +27,6 @@ export async function getTestData(url: string, totalCount: number): Promise<Open
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
describe('useOpenmrsFetchAll', () => {
|
|
30
|
-
afterEach(cleanup);
|
|
31
|
-
|
|
32
30
|
it('should render all rows on if number of rows < pageSize', async () => {
|
|
33
31
|
const expectedRowCount = 17;
|
|
34
32
|
const { result } = renderHook(() =>
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import '@testing-library/jest-dom';
|
|
2
|
-
import { act,
|
|
2
|
+
import { act, renderHook, waitFor } from '@testing-library/react';
|
|
3
3
|
import { useOpenmrsInfinite } from './useOpenmrsInfinite';
|
|
4
4
|
import { getIntArray, getTestData } from './useOpenmrsPagination.test';
|
|
5
5
|
|
|
6
6
|
describe('useOpenmrsInfinite', () => {
|
|
7
|
-
afterEach(cleanup);
|
|
8
|
-
|
|
9
7
|
it('should load all rows with 1 fetch if number of rows < pageSize', async () => {
|
|
10
8
|
const pageSize = 20;
|
|
11
9
|
const expectedRowCount = 17;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { renderHook,
|
|
1
|
+
import { renderHook, waitFor, act } from '@testing-library/react';
|
|
2
2
|
import '@testing-library/jest-dom';
|
|
3
3
|
import { useOpenmrsPagination, type OpenMRSPaginatedResponse } from './useOpenmrsPagination';
|
|
4
4
|
|
|
@@ -26,8 +26,6 @@ export async function getTestData(url: string, totalCount: number): Promise<Open
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
describe('useOpenmrsPagination', () => {
|
|
29
|
-
afterEach(cleanup);
|
|
30
|
-
|
|
31
29
|
it('should not fetch anything if url is null', async () => {
|
|
32
30
|
const { result } = renderHook(() =>
|
|
33
31
|
useOpenmrsPagination(null as any, 50, {
|