瀏覽代碼

test(web): RelativeModal

Paul Armstrong 4 年之前
父節點
當前提交
f87813805a

+ 9 - 0
web/package-lock.json

@@ -3786,6 +3786,15 @@
         "@testing-library/dom": "^7.16.2"
       }
     },
+    "@testing-library/user-event": {
+      "version": "12.7.1",
+      "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.7.1.tgz",
+      "integrity": "sha512-COfCkYgcxc+P9+pEAIGlmBuIDjO91Chf9GOBHI8AhIiMyaoOrKVPQny1uf0HIAYNoHKL5slhkqOPP2ZyNaVQGw==",
+      "dev": true,
+      "requires": {
+        "@babel/runtime": "^7.12.5"
+      }
+    },
     "@ts-morph/common": {
       "version": "0.7.3",
       "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.7.3.tgz",

+ 1 - 0
web/package.json

@@ -24,6 +24,7 @@
     "@snowpack/plugin-postcss": "^1.1.0",
     "@testing-library/jest-dom": "^5.11.9",
     "@testing-library/preact": "^2.0.1",
+    "@testing-library/user-event": "^12.7.1",
     "autoprefixer": "^10.2.1",
     "cross-env": "^7.0.3",
     "eslint": "^7.19.0",

+ 3 - 2
web/src/components/RelativeModal.jsx

@@ -41,10 +41,11 @@ export default function RelativeModal({
 
       if (event.key === 'Escape') {
         setShow(false);
+        handleDismiss();
         return;
       }
     },
-    [ref]
+    [ref, handleDismiss]
   );
 
   useLayoutEffect(() => {
@@ -96,7 +97,7 @@ export default function RelativeModal({
 
   const menu = (
     <Fragment>
-      <div key="scrim" className="absolute inset-0 z-10" onClick={handleDismiss} />
+      <div data-testid="scrim" key="scrim" className="absolute inset-0 z-10" onClick={handleDismiss} />
       <div
         key="menu"
         className={`z-10 bg-white dark:bg-gray-700 dark:text-white absolute shadow-lg rounded w-auto h-auto transition-all duration-75 transform scale-90 opacity-0 overflow-scroll ${

+ 63 - 0
web/src/components/__tests__/RelativeModal.test.jsx

@@ -0,0 +1,63 @@
+import { h, createRef } from 'preact';
+import RelativeModal from '../RelativeModal';
+import userEvent from '@testing-library/user-event';
+import { fireEvent, render, screen } from '@testing-library/preact';
+
+describe('RelativeModal', () => {
+  test('keeps tab focus', async () => {
+    const ref = createRef();
+    render(
+      <div>
+        <label for="outside-input">outside</label>
+        <input id="outside-input" tabindex="0" />
+        <div ref={ref} />
+        <RelativeModal relativeTo={ref}>
+          <input data-testid="modal-input-0" tabindex="0" />
+          <input data-testid="modal-input-1" tabindex="0" />
+        </RelativeModal>
+      </div>
+    );
+
+    const inputs = screen.queryAllByTestId(/modal-input/);
+    expect(document.activeElement).toBe(inputs[0]);
+    userEvent.tab();
+    expect(document.activeElement).toBe(inputs[1]);
+    userEvent.tab();
+    expect(document.activeElement).toBe(inputs[0]);
+  });
+
+  test('pressing ESC dismisses', async () => {
+    const handleDismiss = jest.fn();
+    const ref = createRef();
+    render(
+      <div>
+        <div ref={ref} />
+        <RelativeModal onDismiss={handleDismiss} relativeTo={ref}>
+          <input data-testid="modal-input-0" tabindex="0" />
+        </RelativeModal>
+      </div>
+    );
+
+    const dialog = screen.queryByRole('dialog');
+    expect(dialog).toBeInTheDocument();
+
+    fireEvent.keyDown(document.activeElement, { key: 'Escape', code: 'Escape' });
+    expect(handleDismiss).toHaveBeenCalled();
+  });
+
+  test('clicking a scrim dismisses', async () => {
+    const handleDismiss = jest.fn();
+    const ref = createRef();
+    render(
+      <div>
+        <div ref={ref} />
+        <RelativeModal onDismiss={handleDismiss} relativeTo={ref}>
+          <input data-testid="modal-input-0" tabindex="0" />
+        </RelativeModal>
+      </div>
+    );
+
+    fireEvent.click(screen.queryByTestId('scrim'));
+    expect(handleDismiss).toHaveBeenCalled();
+  });
+});