@khanacademy/wonder-blocks-modal 3.0.2 → 3.0.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @khanacademy/wonder-blocks-modal
2
2
 
3
+ ## 3.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [b561425a]
8
+ - Updated dependencies [a566e232]
9
+ - Updated dependencies [d2b21a6e]
10
+ - @khanacademy/wonder-blocks-core@4.6.0
11
+ - @khanacademy/wonder-blocks-breadcrumbs@1.0.35
12
+ - @khanacademy/wonder-blocks-icon@1.2.33
13
+ - @khanacademy/wonder-blocks-icon-button@3.4.17
14
+ - @khanacademy/wonder-blocks-layout@1.4.13
15
+ - @khanacademy/wonder-blocks-typography@1.1.35
16
+
3
17
  ## 3.0.2
4
18
 
5
19
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-modal",
3
- "version": "3.0.2",
3
+ "version": "3.0.3",
4
4
  "design": "v2",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -16,14 +16,14 @@
16
16
  "license": "MIT",
17
17
  "dependencies": {
18
18
  "@babel/runtime": "^7.18.6",
19
- "@khanacademy/wonder-blocks-breadcrumbs": "^1.0.34",
19
+ "@khanacademy/wonder-blocks-breadcrumbs": "^1.0.35",
20
20
  "@khanacademy/wonder-blocks-color": "^1.2.0",
21
- "@khanacademy/wonder-blocks-core": "^4.5.0",
22
- "@khanacademy/wonder-blocks-icon": "^1.2.32",
23
- "@khanacademy/wonder-blocks-icon-button": "^3.4.16",
24
- "@khanacademy/wonder-blocks-layout": "^1.4.12",
21
+ "@khanacademy/wonder-blocks-core": "^4.6.0",
22
+ "@khanacademy/wonder-blocks-icon": "^1.2.33",
23
+ "@khanacademy/wonder-blocks-icon-button": "^3.4.17",
24
+ "@khanacademy/wonder-blocks-layout": "^1.4.13",
25
25
  "@khanacademy/wonder-blocks-spacing": "^3.0.5",
26
- "@khanacademy/wonder-blocks-typography": "^1.1.34"
26
+ "@khanacademy/wonder-blocks-typography": "^1.1.35"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "aphrodite": "^1.2.5",
@@ -31,6 +31,6 @@
31
31
  "react-dom": "16.14.0"
32
32
  },
33
33
  "devDependencies": {
34
- "wb-dev-build-settings": "^0.4.0"
34
+ "wb-dev-build-settings": "^0.5.0"
35
35
  }
36
36
  }
@@ -1,7 +1,6 @@
1
1
  // @flow
2
2
  import * as React from "react";
3
- import {mount} from "enzyme";
4
- import "jest-enzyme";
3
+ import {render, screen} from "@testing-library/react";
5
4
 
6
5
  import expectRenderError from "../../../../../utils/testing/expect-render-error.js";
7
6
  import CloseButton from "../close-button.js";
@@ -19,7 +18,7 @@ describe("CloseButton", () => {
19
18
 
20
19
  test("testId should be set in the Icon element", () => {
21
20
  // Arrange
22
- const wrapper = mount(
21
+ render(
23
22
  <div>
24
23
  <ModalContext.Provider value={{closeModal: () => {}}}>
25
24
  <CloseButton testId="modal-example-close" />,
@@ -28,9 +27,12 @@ describe("CloseButton", () => {
28
27
  );
29
28
 
30
29
  // Act
31
- const closeButton = wrapper.find(CloseButton);
30
+ const closeButton = screen.getByRole("button");
32
31
 
33
32
  // Assert
34
- expect(closeButton.prop("testId")).toBe("modal-example-close");
33
+ expect(closeButton).toHaveAttribute(
34
+ "data-test-id",
35
+ "modal-example-close",
36
+ );
35
37
  });
36
38
  });
@@ -1,24 +1,16 @@
1
1
  // @flow
2
2
  import * as React from "react";
3
- import {mount} from "enzyme";
4
- import "jest-enzyme";
5
- import {render, screen, fireEvent} from "@testing-library/react";
3
+ import {render, screen, fireEvent, waitFor} from "@testing-library/react";
6
4
  import userEvent from "@testing-library/user-event";
7
5
 
8
6
  import ModalBackdrop from "../modal-backdrop.js";
9
7
  import OnePaneDialog from "../one-pane-dialog.js";
10
8
 
11
- import {unmountAll} from "../../../../../utils/testing/enzyme-shim.js";
12
- import {getElementAttachedToDocument} from "../../../../../utils/testing/get-element-attached-to-document.js";
13
-
14
- const wait = (duration: number = 0) =>
15
- new Promise((resolve, reject) => setTimeout(resolve, duration));
16
-
17
9
  const exampleModal = (
18
10
  <OnePaneDialog
19
- content={<div data-modal-content />}
11
+ content={<div data-test-id="example-modal-content" />}
20
12
  title="Title"
21
- footer={<div data-modal-footer />}
13
+ footer={<div data-test-id="example-modal-footer" />}
22
14
  testId="example-modal-test-id"
23
15
  />
24
16
  );
@@ -27,9 +19,9 @@ const exampleModalWithButtons = (
27
19
  <OnePaneDialog
28
20
  content={
29
21
  <div>
30
- <button data-button-id="1" data-first-button />
31
- <button data-button-id="2" />
32
- <button data-button-id="3" />
22
+ <button>first focusable button</button>
23
+ <button />
24
+ <button />
33
25
  </div>
34
26
  }
35
27
  title="Title"
@@ -38,13 +30,6 @@ const exampleModalWithButtons = (
38
30
  );
39
31
 
40
32
  describe("ModalBackdrop", () => {
41
- afterEach(() => {
42
- unmountAll();
43
- if (document.body) {
44
- document.body.innerHTML = "";
45
- }
46
- });
47
-
48
33
  test("Clicking the backdrop triggers `onCloseModal`", () => {
49
34
  // Arrange
50
35
  const onCloseModal = jest.fn();
@@ -68,17 +53,19 @@ describe("ModalBackdrop", () => {
68
53
  });
69
54
 
70
55
  test("Clicking the modal content does not trigger `onCloseModal`", () => {
56
+ // Arrange
71
57
  const onCloseModal = jest.fn();
72
58
 
73
- // We use `mount` instead of `shallow` here, because the component's
74
- // click handler expects actual DOM events.
75
- const wrapper = mount(
59
+ render(
76
60
  <ModalBackdrop onCloseModal={onCloseModal}>
77
61
  {exampleModal}
78
62
  </ModalBackdrop>,
79
63
  );
80
64
 
81
- wrapper.find("[data-modal-content]").simulate("click");
65
+ // Act
66
+ userEvent.click(screen.getByTestId("example-modal-content"));
67
+
68
+ // Assert
82
69
  expect(onCloseModal).not.toHaveBeenCalled();
83
70
  });
84
71
 
@@ -139,29 +126,27 @@ describe("ModalBackdrop", () => {
139
126
  });
140
127
 
141
128
  test("Clicking the modal footer does not trigger `onCloseModal`", () => {
129
+ // Arrange
142
130
  const onCloseModal = jest.fn();
143
131
 
144
- // We use `mount` instead of `shallow` here, because the component's
145
- // click handler expects actual DOM events.
146
- const wrapper = mount(
132
+ render(
147
133
  <ModalBackdrop onCloseModal={onCloseModal}>
148
134
  {exampleModal}
149
135
  </ModalBackdrop>,
150
136
  );
151
137
 
152
- wrapper.find("[data-modal-footer]").simulate("click");
138
+ // Act
139
+ userEvent.click(screen.getByTestId("example-modal-footer"));
140
+
141
+ // Assert
153
142
  expect(onCloseModal).not.toHaveBeenCalled();
154
143
  });
155
144
 
156
145
  test("If initialFocusId is set and element is found, we focus that element inside the modal", async () => {
157
146
  // Arrange
158
- // We need the elements in the DOM document, it seems, for this test
159
- // to work. Changing to testing-library will likely fix this.
160
- // Then we can remove the lint suppression.
161
- const attachElement = getElementAttachedToDocument("container");
162
147
  const initialFocusId = "initial-focus";
163
148
 
164
- const wrapper = mount(
149
+ render(
165
150
  <ModalBackdrop
166
151
  initialFocusId={initialFocusId}
167
152
  onCloseModal={() => {}}
@@ -170,107 +155,84 @@ describe("ModalBackdrop", () => {
170
155
  content={
171
156
  <div data-modal-content>
172
157
  <input type="text" />
173
- <button id="initial-focus" />
158
+ <button id="initial-focus">Initial focus</button>
174
159
  </div>
175
160
  }
176
161
  title="Title"
177
162
  footer={<div data-modal-footer />}
178
163
  />
179
164
  </ModalBackdrop>,
180
- {attachTo: attachElement},
181
165
  );
182
166
 
183
167
  // Act
184
- await wait(); // wait for styles to be applied
185
- const initialFocusElement = wrapper.find(`#${initialFocusId}`);
168
+ const initialFocusElement = screen.getByRole("button", {
169
+ name: "Initial focus",
170
+ });
186
171
 
187
172
  // Assert
188
- // first we verify the element exists in the DOM
189
- expect(initialFocusElement).toHaveLength(1);
190
-
191
- // verify the focus is set on the correct element
192
- // eslint-disable-next-line testing-library/no-node-access
193
- expect(document.activeElement).toBe(initialFocusElement.getDOMNode());
173
+ await waitFor(() => expect(initialFocusElement).toHaveFocus());
194
174
  });
195
175
 
196
176
  test("If initialFocusId is set but element is NOT found, we focus on the first focusable element instead", async () => {
197
177
  // Arrange
198
- // We need the elements in the DOM document, it seems, for this test
199
- // to work. Changing to testing-library will likely fix this.
200
- // Then we can remove the lint suppression.
201
- const attachElement = getElementAttachedToDocument("container");
202
- const initialFocusId = "initial-focus";
203
- const firstFocusableElement = "[data-first-button]";
178
+ // This element does not exist in the DOM
179
+ const initialFocusId = "unknown-node";
204
180
 
205
- const wrapper = mount(
181
+ const {container} = render(
206
182
  <ModalBackdrop
207
183
  initialFocusId={initialFocusId}
208
184
  onCloseModal={() => {}}
209
185
  >
210
186
  {exampleModalWithButtons}
211
187
  </ModalBackdrop>,
212
- {attachTo: attachElement},
213
188
  );
214
189
 
215
190
  // Act
216
- await wait(); // wait for styles to be applied
217
- const initialFocusElement = wrapper.find(`#${initialFocusId}`);
191
+ // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
192
+ const initialFocusElement = container.querySelector(
193
+ `#${initialFocusId}`,
194
+ );
195
+
196
+ const firstFocusableElement = screen.getByRole("button", {
197
+ name: "first focusable button",
198
+ });
218
199
 
219
200
  // Assert
220
201
  // first we verify the element doesn't exist in the DOM
221
- expect(initialFocusElement).toHaveLength(0);
202
+ expect(initialFocusElement).not.toBeInTheDocument();
222
203
  // verify the focus is set on the first focusable element instead
223
- // eslint-disable-next-line testing-library/no-node-access
224
- expect(document.activeElement).toBe(
225
- wrapper.find(firstFocusableElement).getDOMNode(),
226
- );
204
+ await waitFor(() => expect(firstFocusableElement).toHaveFocus());
227
205
  });
228
206
 
229
207
  test("If no initialFocusId is set, we focus the first button in the modal", async () => {
230
208
  // Arrange
231
- // We need the elements in the DOM document, it seems, for this test
232
- // to work. Changing to testing-library will likely fix this.
233
- // Then we can remove the lint suppression.
234
- const attachElement = getElementAttachedToDocument("container");
235
- const wrapper = mount(
209
+ render(
236
210
  <ModalBackdrop onCloseModal={() => {}}>
237
211
  {exampleModalWithButtons}
238
212
  </ModalBackdrop>,
239
- {attachTo: attachElement},
240
213
  );
241
214
 
242
215
  // Act
243
- await wait(); // wait for styles to be applied
244
- const focusableElement = wrapper
245
- .find("[data-first-button]")
246
- .getDOMNode();
216
+ const firstFocusableElement = screen.getByRole("button", {
217
+ name: "first focusable button",
218
+ });
247
219
 
248
220
  // Assert
249
- // eslint-disable-next-line testing-library/no-node-access
250
- expect(document.activeElement).toBe(focusableElement);
221
+ await waitFor(() => expect(firstFocusableElement).toHaveFocus());
251
222
  });
252
223
 
253
224
  test("If there are no focusable elements, we focus the Dialog instead", async () => {
254
225
  // Arrange
255
- // We need the elements in the DOM document, it seems, for this test
256
- // to work. Changing to testing-library will likely fix this.
257
- // Then we can remove the lint suppression.
258
- const attachElement = getElementAttachedToDocument("container");
259
- const wrapper = mount(
226
+ render(
260
227
  <ModalBackdrop onCloseModal={() => {}}>
261
228
  {exampleModal}
262
229
  </ModalBackdrop>,
263
- {attachTo: attachElement},
264
230
  );
265
231
 
266
232
  // Act
267
- await wait(); // wait for styles to be applied
268
- const focusableElement = wrapper
269
- .find('div[role="dialog"]')
270
- .getDOMNode();
233
+ const firstFocusableElement = screen.getByRole("dialog");
271
234
 
272
235
  // Assert
273
- // eslint-disable-next-line testing-library/no-node-access
274
- expect(document.activeElement).toBe(focusableElement);
236
+ await waitFor(() => expect(firstFocusableElement).toHaveFocus());
275
237
  });
276
238
  });
@@ -1,7 +1,6 @@
1
1
  // @flow
2
2
  import * as React from "react";
3
- import {mount, shallow} from "enzyme";
4
- import "jest-enzyme";
3
+ import {render, screen} from "@testing-library/react";
5
4
 
6
5
  import {
7
6
  Breadcrumbs,
@@ -12,24 +11,22 @@ import ModalHeader from "../modal-header.js";
12
11
 
13
12
  const exampleBreadcrumbs: React.Element<typeof Breadcrumbs> = (
14
13
  <Breadcrumbs>
15
- <BreadcrumbsItem>test</BreadcrumbsItem>
14
+ <BreadcrumbsItem>breadcrumb item</BreadcrumbsItem>
16
15
  </Breadcrumbs>
17
16
  );
18
17
 
19
18
  describe("ModalHeader", () => {
20
19
  test("renders the title by default", () => {
21
20
  // Arrange, Act
22
- const wrapper = shallow(
23
- <ModalHeader title="Title" titleId="modal-title" />,
24
- );
21
+ render(<ModalHeader title="Title" titleId="modal-title" />);
25
22
 
26
23
  // Assert
27
- expect(wrapper.exists()).toBe(true);
24
+ expect(screen.getByText("Title")).toBeInTheDocument();
28
25
  });
29
26
 
30
27
  test("using only `breadcrumbs` should render the header", () => {
31
28
  // Arrange, Act
32
- const wrapper = shallow(
29
+ render(
33
30
  <ModalHeader
34
31
  title="Title"
35
32
  breadcrumbs={exampleBreadcrumbs}
@@ -38,12 +35,12 @@ describe("ModalHeader", () => {
38
35
  );
39
36
 
40
37
  // Assert
41
- expect(wrapper.exists()).toBe(true);
38
+ expect(screen.getByText("breadcrumb item")).toBeInTheDocument();
42
39
  });
43
40
 
44
41
  test("using only `subtitle` should render the header", () => {
45
42
  // Arrange, Act
46
- const wrapper = shallow(
43
+ render(
47
44
  <ModalHeader
48
45
  title="Title"
49
46
  subtitle="Subtitle"
@@ -52,12 +49,12 @@ describe("ModalHeader", () => {
52
49
  );
53
50
 
54
51
  // Assert
55
- expect(wrapper.exists()).toBe(true);
52
+ expect(screen.getByText("Subtitle")).toBeInTheDocument();
56
53
  });
57
54
 
58
55
  test("testId should be added to the title", () => {
59
56
  // Arrange
60
- const wrapper = mount(
57
+ render(
61
58
  <ModalHeader
62
59
  title="Title"
63
60
  subtitle="Subtitle"
@@ -67,17 +64,18 @@ describe("ModalHeader", () => {
67
64
  );
68
65
 
69
66
  // Act
70
- const title = wrapper.find(
71
- `[data-test-id="test-example-header-title"]`,
72
- );
67
+ const title = screen.getByText("Title");
73
68
 
74
69
  // Assert
75
- expect(title).toHaveLength(1);
70
+ expect(title).toHaveAttribute(
71
+ "data-test-id",
72
+ "test-example-header-title",
73
+ );
76
74
  });
77
75
 
78
76
  test("testId should be added to the subtitle", () => {
79
77
  // Arrange
80
- const wrapper = mount(
78
+ render(
81
79
  <ModalHeader
82
80
  title="Title"
83
81
  subtitle="Subtitle"
@@ -87,11 +85,12 @@ describe("ModalHeader", () => {
87
85
  );
88
86
 
89
87
  // Act
90
- const subtitle = wrapper.find(
91
- `[data-test-id="test-example-header-subtitle"]`,
92
- );
88
+ const subtitle = screen.getByText("Subtitle");
93
89
 
94
90
  // Assert
95
- expect(subtitle).toHaveLength(1);
91
+ expect(subtitle).toHaveAttribute(
92
+ "data-test-id",
93
+ "test-example-header-subtitle",
94
+ );
96
95
  });
97
96
  });