A calm place to write long-form, and publish it to the open social web. skypress.blog/
0

Configure Feed

Select the types of activity you want to include in your feed.

at trunk 2.6 kB View raw
1import { describe, it, expect, afterEach } from 'vitest'; 2import { act, createElement } from 'react'; 3import { createRoot, type Root } from 'react-dom/client'; 4import RecordJsonViewer from './RecordJsonViewer'; 5 6// react-dom/client + act need this flag so React treats vitest's jsdom as a test env. 7( globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean } ).IS_REACT_ACT_ENVIRONMENT = true; 8 9const HTML = 10 '<code class="hljs language-json"><span class="hljs-attr">"title"</span>: <span class="hljs-string">"Hi"</span></code>'; 11 12let container: HTMLDivElement; 13let root: Root; 14 15async function mount() { 16 container = document.createElement( 'div' ); 17 document.body.appendChild( container ); 18 root = createRoot( container ); 19 await act( async () => { 20 root.render( createElement( RecordJsonViewer, { highlightedHtml: HTML } ) ); 21 } ); 22} 23 24afterEach( () => { 25 act( () => root.unmount() ); 26 container.remove(); 27} ); 28 29const trigger = () => container.querySelector( '.record-json__trigger' ) as HTMLButtonElement; 30const dialog = () => document.querySelector( '[role="dialog"]' ); 31 32describe( 'RecordJsonViewer interaction', () => { 33 it( 'renders a labelled trigger and no dialog initially', async () => { 34 await mount(); 35 expect( trigger() ).not.toBeNull(); 36 expect( trigger().getAttribute( 'aria-label' ) ).toBe( 'View record JSON' ); 37 expect( dialog() ).toBeNull(); 38 } ); 39 40 it( 'opens the dialog with the highlighted JSON on click', async () => { 41 await mount(); 42 await act( async () => { 43 trigger().click(); 44 } ); 45 expect( dialog() ).not.toBeNull(); 46 expect( dialog()!.innerHTML ).toContain( 'hljs-string' ); 47 } ); 48 49 it( 'closes via the close button and restores focus to the trigger', async () => { 50 await mount(); 51 await act( async () => { 52 trigger().click(); 53 } ); 54 const closeBtn = document.querySelector( '.record-json__close' ) as HTMLButtonElement; 55 await act( async () => { 56 closeBtn.click(); 57 } ); 58 expect( dialog() ).toBeNull(); 59 expect( document.activeElement ).toBe( trigger() ); 60 } ); 61 62 it( 'closes when the backdrop is clicked', async () => { 63 await mount(); 64 await act( async () => { 65 trigger().click(); 66 } ); 67 const backdrop = document.querySelector( '.record-json__backdrop' ) as HTMLElement; 68 await act( async () => { 69 backdrop.click(); 70 } ); 71 expect( dialog() ).toBeNull(); 72 } ); 73 74 it( 'closes on Escape', async () => { 75 await mount(); 76 await act( async () => { 77 trigger().click(); 78 } ); 79 await act( async () => { 80 document.dispatchEvent( new KeyboardEvent( 'keydown', { key: 'Escape' } ) ); 81 } ); 82 expect( dialog() ).toBeNull(); 83 } ); 84} );