@openmrs/esm-framework 8.0.1-pre.3439 → 8.0.1-pre.3457

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.
Files changed (42) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/openmrs-esm-framework.js +2 -2
  3. package/dist/openmrs-esm-framework.js.map +1 -1
  4. package/docs/functions/attach.md +1 -1
  5. package/docs/functions/compile.md +1 -1
  6. package/docs/functions/defineConfigSchema.md +1 -1
  7. package/docs/functions/defineExtensionConfigSchema.md +1 -1
  8. package/docs/functions/detach.md +1 -1
  9. package/docs/functions/detachAll.md +1 -1
  10. package/docs/functions/evaluateAsTypeAsync.md +1 -1
  11. package/docs/functions/getAssignedExtensions.md +1 -1
  12. package/docs/functions/getConfig.md +1 -1
  13. package/docs/functions/getExtensionNameFromId.md +1 -1
  14. package/docs/functions/getExtensionStore.md +1 -1
  15. package/docs/functions/provide.md +1 -1
  16. package/docs/functions/setLeftNav.md +1 -1
  17. package/docs/functions/unsetLeftNav.md +1 -1
  18. package/docs/interfaces/AssignedExtension.md +9 -9
  19. package/docs/interfaces/ConnectedExtension.md +6 -6
  20. package/docs/interfaces/ExtensionRegistration.md +8 -0
  21. package/docs/interfaces/ExtensionSlotProps.md +264 -264
  22. package/docs/interfaces/ExtensionSlotState.md +11 -3
  23. package/docs/interfaces/ExtensionStore.md +2 -2
  24. package/docs/interfaces/FeatureFlagDefinition.md +4 -4
  25. package/docs/interfaces/LeftNavStore.md +13 -5
  26. package/docs/interfaces/OpenmrsAppRoutes.md +13 -13
  27. package/docs/interfaces/ResourceLoader.md +2 -2
  28. package/docs/interfaces/SetLeftNavParams.md +13 -5
  29. package/docs/interfaces/WorkspaceDefinition2.md +4 -4
  30. package/docs/interfaces/WorkspaceGroupDefinition.md +3 -3
  31. package/docs/interfaces/WorkspaceGroupDefinition2.md +4 -4
  32. package/docs/interfaces/WorkspaceWindowDefinition2.md +9 -9
  33. package/docs/type-aliases/ExtensionDefinition.md +13 -3
  34. package/docs/type-aliases/ModalDefinition.md +3 -3
  35. package/docs/type-aliases/NameUse.md +1 -1
  36. package/docs/type-aliases/OpenmrsRoutes.md +1 -1
  37. package/docs/type-aliases/WorkspaceDefinition.md +10 -10
  38. package/docs/type-aliases/WorkspaceWindowState.md +1 -1
  39. package/package.json +20 -20
  40. package/setup-tests.ts +23 -2
  41. package/src/integration-tests/extension-config-expressions.test.tsx +316 -0
  42. package/src/integration-tests/extension-config.test.tsx +48 -36
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-framework",
3
- "version": "8.0.1-pre.3439",
3
+ "version": "8.0.1-pre.3457",
4
4
  "license": "MPL-2.0",
5
5
  "type": "module",
6
6
  "module": "dist/openmrs-esm-framework.js",
@@ -59,24 +59,24 @@
59
59
  "access": "public"
60
60
  },
61
61
  "dependencies": {
62
- "@openmrs/esm-api": "8.0.1-pre.3439",
63
- "@openmrs/esm-config": "8.0.1-pre.3439",
64
- "@openmrs/esm-context": "8.0.1-pre.3439",
65
- "@openmrs/esm-dynamic-loading": "8.0.1-pre.3439",
66
- "@openmrs/esm-emr-api": "8.0.1-pre.3439",
67
- "@openmrs/esm-error-handling": "8.0.1-pre.3439",
68
- "@openmrs/esm-expression-evaluator": "8.0.1-pre.3439",
69
- "@openmrs/esm-extensions": "8.0.1-pre.3439",
70
- "@openmrs/esm-feature-flags": "8.0.1-pre.3439",
71
- "@openmrs/esm-globals": "8.0.1-pre.3439",
72
- "@openmrs/esm-navigation": "8.0.1-pre.3439",
73
- "@openmrs/esm-offline": "8.0.1-pre.3439",
74
- "@openmrs/esm-react-utils": "8.0.1-pre.3439",
75
- "@openmrs/esm-routes": "8.0.1-pre.3439",
76
- "@openmrs/esm-state": "8.0.1-pre.3439",
77
- "@openmrs/esm-styleguide": "8.0.1-pre.3439",
78
- "@openmrs/esm-translations": "8.0.1-pre.3439",
79
- "@openmrs/esm-utils": "8.0.1-pre.3439"
62
+ "@openmrs/esm-api": "8.0.1-pre.3457",
63
+ "@openmrs/esm-config": "8.0.1-pre.3457",
64
+ "@openmrs/esm-context": "8.0.1-pre.3457",
65
+ "@openmrs/esm-dynamic-loading": "8.0.1-pre.3457",
66
+ "@openmrs/esm-emr-api": "8.0.1-pre.3457",
67
+ "@openmrs/esm-error-handling": "8.0.1-pre.3457",
68
+ "@openmrs/esm-expression-evaluator": "8.0.1-pre.3457",
69
+ "@openmrs/esm-extensions": "8.0.1-pre.3457",
70
+ "@openmrs/esm-feature-flags": "8.0.1-pre.3457",
71
+ "@openmrs/esm-globals": "8.0.1-pre.3457",
72
+ "@openmrs/esm-navigation": "8.0.1-pre.3457",
73
+ "@openmrs/esm-offline": "8.0.1-pre.3457",
74
+ "@openmrs/esm-react-utils": "8.0.1-pre.3457",
75
+ "@openmrs/esm-routes": "8.0.1-pre.3457",
76
+ "@openmrs/esm-state": "8.0.1-pre.3457",
77
+ "@openmrs/esm-styleguide": "8.0.1-pre.3457",
78
+ "@openmrs/esm-translations": "8.0.1-pre.3457",
79
+ "@openmrs/esm-utils": "8.0.1-pre.3457"
80
80
  },
81
81
  "peerDependencies": {
82
82
  "dayjs": "1.x",
@@ -89,7 +89,7 @@
89
89
  "swr": "2.x"
90
90
  },
91
91
  "devDependencies": {
92
- "@openmrs/typedoc-plugin-file-categories": "8.0.1-pre.3439",
92
+ "@openmrs/typedoc-plugin-file-categories": "8.0.1-pre.3457",
93
93
  "@rspack/cli": "^1.3.11",
94
94
  "@rspack/core": "^1.3.11",
95
95
  "concurrently": "^9.1.2",
package/setup-tests.ts CHANGED
@@ -1,12 +1,33 @@
1
- import { afterEach, vi } from 'vitest';
1
+ import { afterEach } from 'vitest';
2
2
  import type {} from '@openmrs/esm-globals';
3
3
  import '@testing-library/jest-dom/vitest';
4
4
  import { cleanup } from '@testing-library/react';
5
5
 
6
+ // Configure React's act() environment for Vitest
7
+ // See: https://github.com/testing-library/react-testing-library/issues/1061
8
+ // Store the actual value in a variable to avoid infinite recursion
9
+ let actEnvironment = true;
10
+
11
+ Object.defineProperty(globalThis, 'IS_REACT_ACT_ENVIRONMENT', {
12
+ get() {
13
+ return actEnvironment;
14
+ },
15
+ set(value) {
16
+ actEnvironment = value;
17
+ if (typeof window !== 'undefined' && globalThis !== window) {
18
+ window.IS_REACT_ACT_ENVIRONMENT = value;
19
+ }
20
+ },
21
+ });
22
+
23
+ globalThis.IS_REACT_ACT_ENVIRONMENT = true;
24
+
6
25
  window.openmrsBase = '/openmrs';
7
26
  window.spaBase = '/spa';
8
27
  window.getOpenmrsSpaBase = () => '/openmrs/spa/';
9
28
  const { getComputedStyle } = window;
10
29
  window.getComputedStyle = (elt) => getComputedStyle(elt);
11
30
 
12
- afterEach(cleanup);
31
+ afterEach(() => {
32
+ cleanup();
33
+ });
@@ -0,0 +1,316 @@
1
+ /* eslint-disable */
2
+ import React from 'react';
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
+ import '@testing-library/jest-dom/vitest';
5
+ import { act, cleanup, render, screen, waitFor } from '@testing-library/react';
6
+ import { type Person } from '@openmrs/esm-api';
7
+ import { mockSessionStore } from '@openmrs/esm-api/mock';
8
+ import { attach, registerExtension, updateInternalExtensionStore } from '../../../esm-extensions';
9
+ import { ExtensionSlot, getSyncLifecycle, openmrsComponentDecorator, useConfig } from '../../../esm-react-utils/src';
10
+ import {
11
+ configInternalStore,
12
+ defineConfigSchema,
13
+ getExtensionSlotsConfigStore,
14
+ getExtensionsConfigStore,
15
+ provide,
16
+ registerModuleLoad,
17
+ resetConfigSystem,
18
+ temporaryConfigStore,
19
+ } from '../../../esm-config/src';
20
+
21
+ vi.mock('@openmrs/esm-api', async () => {
22
+ const original = await import('@openmrs/esm-api');
23
+ return {
24
+ ...original,
25
+ sessionStore: mockSessionStore,
26
+ refetchCurrentUser: vi.fn(),
27
+ };
28
+ });
29
+
30
+ /**
31
+ * Expression evaluation tests
32
+ *
33
+ * These tests are in a separate file due to test isolation issues. When run with other
34
+ * extension/config tests, there is accumulation of state/subscriptions that causes infinite
35
+ * update loops. The tests pass when run individually or in this isolated file.
36
+ *
37
+ * Root cause: Even with subscription cleanup (resetConfigSystem) and deep equality checks,
38
+ * running these tests alongside other tests that manipulate the config system creates
39
+ * conditions where store updates don't settle. This is a test environment issue, not a
40
+ * production code bug - the functionality works correctly in isolation and in production.
41
+ */
42
+ describe('Expression evaluation in extension display conditions', () => {
43
+ beforeEach(() => {
44
+ temporaryConfigStore.setState({ config: {} });
45
+ configInternalStore.setState({ providedConfigs: [], schemas: {}, moduleLoaded: {} });
46
+ mockSessionStore.setState({});
47
+ getExtensionSlotsConfigStore().setState({ slots: {} });
48
+ getExtensionsConfigStore().setState({ configs: {} });
49
+ updateInternalExtensionStore(() => ({ slots: {}, extensions: {} }));
50
+ resetConfigSystem();
51
+ });
52
+
53
+ afterEach(() => {
54
+ cleanup();
55
+ });
56
+
57
+ it('should show extension when the expression evalutes to true', async () => {
58
+ const promise = Promise.resolve();
59
+
60
+ registerSimpleExtension('Schmoo', 'esm-bedrock', true);
61
+ attach('A slot', 'Schmoo');
62
+ defineConfigSchema('esm-bedrock', {});
63
+ registerModuleLoad('esm-bedrock');
64
+ provide({
65
+ 'esm-bedrock': {
66
+ 'Display conditions': {
67
+ expression: 'true',
68
+ },
69
+ },
70
+ });
71
+
72
+ function RootComponent() {
73
+ return (
74
+ <div>
75
+ <ExtensionSlot data-testid="slot" name="A slot" />
76
+ </div>
77
+ );
78
+ }
79
+
80
+ const App = openmrsComponentDecorator({
81
+ moduleName: 'esm-bedrock',
82
+ featureName: 'Bedrock',
83
+ disableTranslations: true,
84
+ })(RootComponent);
85
+
86
+ await act(async () => await promise);
87
+
88
+ render(<App />);
89
+
90
+ await screen.findByTestId(/slot/);
91
+ expect(screen.getByTestId('slot').firstChild).toHaveAttribute('data-extension-id', 'Schmoo');
92
+ });
93
+
94
+ it('should hide extension when the expression evaluates to false', async () => {
95
+ const promise = Promise.resolve();
96
+
97
+ registerSimpleExtension('Schmoo', 'esm-bedrock', true);
98
+ attach('A slot', 'Schmoo');
99
+ defineConfigSchema('esm-bedrock', {});
100
+ registerModuleLoad('esm-bedrock');
101
+ provide({
102
+ 'esm-bedrock': {
103
+ 'Display conditions': {
104
+ expression: 'false',
105
+ },
106
+ },
107
+ });
108
+
109
+ function RootComponent() {
110
+ return (
111
+ <div>
112
+ <ExtensionSlot data-testid="slot" name="A slot" />
113
+ </div>
114
+ );
115
+ }
116
+
117
+ const App = openmrsComponentDecorator({
118
+ moduleName: 'esm-bedrock',
119
+ featureName: 'Bedrock',
120
+ disableTranslations: true,
121
+ })(RootComponent);
122
+
123
+ await act(async () => await promise);
124
+
125
+ render(<App />);
126
+
127
+ await screen.findByTestId(/slot/);
128
+ expect(screen.getByTestId('slot').firstChild).toBeNull();
129
+ });
130
+
131
+ it('should show extension using a complex expression', async () => {
132
+ registerSimpleExtension('Schmoo', 'esm-bedrock', true);
133
+ attach('A slot', 'Schmoo');
134
+ defineConfigSchema('esm-bedrock', {});
135
+ registerModuleLoad('esm-bedrock');
136
+ provide({
137
+ 'esm-bedrock': {
138
+ 'Display conditions': {
139
+ expression: 'session.user.privileges.some(p => p.display === "YOWTCH!")',
140
+ },
141
+ },
142
+ });
143
+
144
+ function RootComponent() {
145
+ return (
146
+ <div>
147
+ <ExtensionSlot data-testid="slot" name="A slot" />
148
+ </div>
149
+ );
150
+ }
151
+
152
+ const App = openmrsComponentDecorator({
153
+ moduleName: 'esm-bedrock',
154
+ featureName: 'Bedrock',
155
+ disableTranslations: true,
156
+ })(RootComponent);
157
+
158
+ render(<App />);
159
+
160
+ // Update session state after rendering so the component can react to the change
161
+ await act(async () => {
162
+ mockSessionStore.setState({
163
+ loaded: true,
164
+ session: {
165
+ authenticated: true,
166
+ sessionId: '1',
167
+ user: {
168
+ uuid: '1',
169
+ display: 'Non-Admin',
170
+ username: 'nonadmin',
171
+ systemId: 'nonadmin',
172
+ userProperties: {},
173
+ person: {} as Person,
174
+ privileges: [{ uuid: '1', display: 'YOWTCH!' }],
175
+ roles: [],
176
+ retired: false,
177
+ locale: 'en',
178
+ allowedLocales: ['en'],
179
+ },
180
+ },
181
+ });
182
+ });
183
+
184
+ await waitFor(() => {
185
+ const slot = screen.getByTestId('slot');
186
+ expect(slot.firstChild).toHaveAttribute('data-extension-id', 'Schmoo');
187
+ });
188
+ });
189
+
190
+ it('should hide extension using a complex expression', async () => {
191
+ registerSimpleExtension('Schmoo', 'esm-bedrock', true);
192
+ attach('A slot', 'Schmoo');
193
+ defineConfigSchema('esm-bedrock', {});
194
+ registerModuleLoad('esm-bedrock');
195
+ provide({
196
+ 'esm-bedrock': {
197
+ 'Display conditions': {
198
+ expression: 'session.user.privileges.every(p => p.display !== "YOWTCH!")',
199
+ },
200
+ },
201
+ });
202
+
203
+ function RootComponent() {
204
+ return (
205
+ <div>
206
+ <ExtensionSlot data-testid="slot" name="A slot" />
207
+ </div>
208
+ );
209
+ }
210
+
211
+ const App = openmrsComponentDecorator({
212
+ moduleName: 'esm-bedrock',
213
+ featureName: 'Bedrock',
214
+ disableTranslations: true,
215
+ })(RootComponent);
216
+
217
+ render(<App />);
218
+
219
+ // Update session state after rendering so the component can react to the change
220
+ await act(async () => {
221
+ mockSessionStore.setState({
222
+ loaded: true,
223
+ session: {
224
+ authenticated: true,
225
+ sessionId: '1',
226
+ user: {
227
+ uuid: '1',
228
+ display: 'Non-Admin',
229
+ username: 'nonadmin',
230
+ systemId: 'nonadmin',
231
+ userProperties: {},
232
+ person: {} as Person,
233
+ privileges: [{ uuid: '1', display: 'YOWTCH!' }],
234
+ roles: [],
235
+ retired: false,
236
+ locale: 'en',
237
+ allowedLocales: ['en'],
238
+ },
239
+ },
240
+ });
241
+ });
242
+
243
+ await waitFor(() => {
244
+ const slot = screen.getByTestId('slot');
245
+ expect(slot.firstChild).toBeNull();
246
+ });
247
+ });
248
+
249
+ it('should hide extension if expression contains an error', async () => {
250
+ registerSimpleExtension('Schmoo', 'esm-bedrock', true);
251
+ attach('A slot', 'Schmoo');
252
+ defineConfigSchema('esm-bedrock', {});
253
+ registerModuleLoad('esm-bedrock');
254
+
255
+ function RootComponent() {
256
+ return (
257
+ <div>
258
+ <ExtensionSlot data-testid="slot" name="A slot" />
259
+ </div>
260
+ );
261
+ }
262
+
263
+ const App = openmrsComponentDecorator({
264
+ moduleName: 'esm-bedrock',
265
+ featureName: 'Bedrock',
266
+ disableTranslations: true,
267
+ })(RootComponent);
268
+
269
+ render(<App />);
270
+
271
+ // Provide config with error expression after rendering so the component can react to the change
272
+ await act(async () => {
273
+ provide({
274
+ 'esm-bedrock': {
275
+ 'Display conditions': {
276
+ expression: 'NotDefined === true',
277
+ },
278
+ },
279
+ });
280
+ });
281
+
282
+ await waitFor(() => {
283
+ const slot = screen.getByTestId('slot');
284
+ expect(slot.firstChild).toBeNull();
285
+ });
286
+ }, 10000);
287
+ });
288
+
289
+ async function registerSimpleExtension(
290
+ name: string,
291
+ moduleName: string,
292
+ takesConfig: boolean = false,
293
+ privileges?: string | string[],
294
+ ) {
295
+ const SimpleComponent = () => <div>{name}</div>;
296
+ const ConfigurableComponent = () => {
297
+ const config = useConfig();
298
+ return (
299
+ <div>
300
+ {name}: {JSON.stringify(config)}
301
+ </div>
302
+ );
303
+ };
304
+
305
+ registerExtension({
306
+ name,
307
+ moduleName,
308
+ load: getSyncLifecycle(takesConfig ? ConfigurableComponent : SimpleComponent, {
309
+ moduleName,
310
+ featureName: moduleName,
311
+ disableTranslations: true,
312
+ }),
313
+ meta: {},
314
+ privileges,
315
+ });
316
+ }
@@ -1,8 +1,8 @@
1
1
  /* eslint-disable */
2
2
  import React from 'react';
3
- import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
4
  import '@testing-library/jest-dom/vitest';
5
- import { act, render, screen, waitFor } from '@testing-library/react';
5
+ import { act, cleanup, render, screen, waitFor } from '@testing-library/react';
6
6
  import { type Person } from '@openmrs/esm-api';
7
7
  import { mockSessionStore } from '@openmrs/esm-api/mock';
8
8
  import { attach, registerExtension, updateInternalExtensionStore } from '../../../esm-extensions';
@@ -14,13 +14,15 @@ import {
14
14
  useExtensionStore,
15
15
  } from '../../../esm-react-utils/src';
16
16
  import {
17
+ configInternalStore,
17
18
  defineConfigSchema,
19
+ getExtensionSlotsConfigStore,
20
+ getExtensionsConfigStore,
18
21
  provide,
19
- Type,
20
22
  registerModuleLoad,
23
+ resetConfigSystem,
21
24
  temporaryConfigStore,
22
- configInternalStore,
23
- getExtensionSlotsConfigStore,
25
+ Type,
24
26
  } from '../../../esm-config/src';
25
27
 
26
28
  vi.mock('@openmrs/esm-api', async () => {
@@ -35,9 +37,16 @@ vi.mock('@openmrs/esm-api', async () => {
35
37
  describe('Interaction between configuration and extension systems', () => {
36
38
  beforeEach(() => {
37
39
  temporaryConfigStore.setState({ config: {} });
38
- configInternalStore.setState({ providedConfigs: [], schemas: {} });
40
+ configInternalStore.setState({ providedConfigs: [], schemas: {}, moduleLoaded: {} });
41
+ mockSessionStore.setState({});
39
42
  getExtensionSlotsConfigStore().setState({ slots: {} });
43
+ getExtensionsConfigStore().setState({ configs: {} });
40
44
  updateInternalExtensionStore(() => ({ slots: {}, extensions: {} }));
45
+ resetConfigSystem();
46
+ });
47
+
48
+ afterEach(() => {
49
+ cleanup();
41
50
  });
42
51
 
43
52
  it('Config should add, order, and remove extensions within slots', async () => {
@@ -292,7 +301,7 @@ describe('Interaction between configuration and extension systems', () => {
292
301
 
293
302
  render(<App />);
294
303
 
295
- screen.findByTestId(/slot/);
304
+ await screen.findByTestId(/slot/);
296
305
  expect(screen.getByText(/clothes/)).toHaveTextContent(/leopard/);
297
306
 
298
307
  act(() => {
@@ -374,9 +383,11 @@ describe('Interaction between configuration and extension systems', () => {
374
383
 
375
384
  render(<App />);
376
385
 
377
- screen.findByTestId(/slot/);
378
- expect(screen.getByTestId('slot').firstChild).toHaveAttribute('data-extension-id', 'Wilma');
379
- expect(screen.queryAllByText(/\bSchmoo\b/)).toHaveLength(0);
386
+ await waitFor(() => {
387
+ const slot = screen.getByTestId('slot');
388
+ expect(slot.firstChild).toHaveAttribute('data-extension-id', 'Wilma');
389
+ expect(screen.queryAllByText(/\bSchmoo\b/)).toHaveLength(0);
390
+ });
380
391
  });
381
392
 
382
393
  it('should show extension when user has configured privilege', async () => {
@@ -436,28 +447,29 @@ describe('Interaction between configuration and extension systems', () => {
436
447
  expect(screen.getByTestId('slot').firstChild).toHaveAttribute('data-extension-id', 'Schmoo');
437
448
  });
438
449
 
439
- // TODO This test fails on CI but not locally
440
- it.skip('should only show extensions users have default privilege for', async () => {
441
- const promise = Promise.resolve();
442
- mockSessionStore.setState({
443
- loaded: true,
444
- session: {
445
- authenticated: true,
446
- sessionId: '1',
447
- user: {
448
- uuid: '1',
449
- display: 'Non-Admin',
450
- username: 'nonadmin',
451
- systemId: 'nonadmin',
452
- userProperties: {},
453
- person: {} as Person,
454
- privileges: [{ uuid: '1', display: 'YOWTCH!' }],
455
- roles: [],
456
- retired: false,
457
- locale: 'en',
458
- allowedLocales: ['en'],
450
+ it('should only show extensions users have default privilege for', async () => {
451
+ // Set up initial session state before registering extensions
452
+ await act(async () => {
453
+ mockSessionStore.setState({
454
+ loaded: true,
455
+ session: {
456
+ authenticated: true,
457
+ sessionId: '1',
458
+ user: {
459
+ uuid: '1',
460
+ display: 'Non-Admin',
461
+ username: 'nonadmin',
462
+ systemId: 'nonadmin',
463
+ userProperties: {},
464
+ person: {} as Person,
465
+ privileges: [{ uuid: '1', display: 'YOWTCH!' }],
466
+ roles: [],
467
+ retired: false,
468
+ locale: 'en',
469
+ allowedLocales: ['en'],
470
+ },
459
471
  },
460
- },
472
+ });
461
473
  });
462
474
 
463
475
  registerSimpleExtension('Schmoo', 'esm-bedrock', true, 'Yabadabadoo!');
@@ -485,13 +497,13 @@ describe('Interaction between configuration and extension systems', () => {
485
497
  disableTranslations: true,
486
498
  })(RootComponent);
487
499
 
488
- await act(async () => await promise);
489
-
490
500
  render(<App />);
491
501
 
492
- screen.findByTestId(/slot/);
493
- expect(screen.getByTestId('slot').firstChild).toHaveAttribute('data-extension-id', 'Wilma');
494
- expect(screen.queryAllByText(/\bSchmoo\b/)).toHaveLength(0);
502
+ await waitFor(() => {
503
+ const slot = screen.getByTestId('slot');
504
+ expect(slot.firstChild).toHaveAttribute('data-extension-id', 'Wilma');
505
+ expect(screen.queryAllByText(/\bSchmoo\b/)).toHaveLength(0);
506
+ });
495
507
  });
496
508
  });
497
509