1- import { describe , expect , it , vi } from 'vitest'
2- import { withJsdomEnvironment } from '@test/unit/helpers/litRuntime'
1+ import { afterEach , beforeEach , describe , expect , it , vi } from 'vitest'
2+ import { experimental_AstroContainer as AstroContainer } from 'astro/container'
3+ import type { WebComponentModule } from '@components/scripts/@types/webComponentModule'
4+ import { executeRender , withJsdomEnvironment } from '@test/unit/helpers/litRuntime'
5+ import CodeTabsFixture from '@components/Code/CodeTabs/client/__fixtures__/codeTabs.fixture.astro'
6+ import type { CodeTabsElement } from '../index'
7+
8+ type CodeTabsModule = WebComponentModule < CodeTabsElement >
39
410describe ( 'CodeTabs web component' , ( ) => {
11+ let container : AstroContainer
12+
13+ beforeEach ( async ( ) => {
14+ container = await AstroContainer . create ( )
15+ } )
16+
17+ afterEach ( ( ) => {
18+ vi . restoreAllMocks ( )
19+ } )
20+
21+ const renderCodeTabs = async (
22+ props : { variant ?: 'single' | 'multi' | 'excluded' } ,
23+ assertion : ( _context : { element : CodeTabsElement ; window : Window } ) => Promise < void > | void
24+ ) : Promise < void > => {
25+ await executeRender < CodeTabsModule > ( {
26+ container,
27+ component : CodeTabsFixture ,
28+ moduleSpecifier : '@components/Code/CodeTabs/client/index' ,
29+ args : { props } ,
30+ selector : 'code-tabs' ,
31+ waitForReady : async ( element : CodeTabsElement ) => {
32+ await element . updateComplete
33+ } ,
34+ assert : async ( { element, window } ) => {
35+ await assertion ( { element, window : window ?? globalThis . window } )
36+ } ,
37+ } )
38+ }
39+
540 it ( 'skips registration when customElements is unavailable' , async ( ) => {
641 await withJsdomEnvironment ( async ( ) => {
742 const globalRef = globalThis as unknown as { customElements ?: CustomElementRegistry }
@@ -28,7 +63,7 @@ describe('CodeTabs web component', () => {
2863 } )
2964
3065 it ( 'copies the active code block when clipboard is available' , async ( ) => {
31- await withJsdomEnvironment ( async ( { window } ) => {
66+ await renderCodeTabs ( { variant : 'single' } , async ( { element , window } ) => {
3267 const globalRef = globalThis as unknown as { navigator ?: Navigator }
3368 const originalNavigator = globalRef . navigator
3469
@@ -45,18 +80,6 @@ describe('CodeTabs web component', () => {
4580 } )
4681
4782 try {
48- const { registerCodeTabsWebComponent } =
49- await import ( '@components/Code/CodeTabs/client/index' )
50- registerCodeTabsWebComponent ( )
51-
52- const element = window . document . createElement ( 'code-tabs' )
53- const pre = window . document . createElement ( 'pre' )
54- const code = window . document . createElement ( 'code' )
55- code . textContent = 'console.log("hello")'
56- pre . appendChild ( code )
57- element . appendChild ( pre )
58- window . document . body . appendChild ( element )
59-
6083 const copyButton = element . querySelector (
6184 'button[aria-label="Copy"]'
6285 ) as HTMLButtonElement | null
@@ -65,7 +88,7 @@ describe('CodeTabs web component', () => {
6588 copyButton ?. click ( )
6689
6790 await vi . waitFor ( ( ) => {
68- expect ( writeText ) . toHaveBeenCalledWith ( 'console.log("hello") ' )
91+ expect ( writeText ) . toHaveBeenCalledWith ( 'const x: number = 1 ' )
6992 } )
7093 } finally {
7194 Object . defineProperty ( globalThis , 'navigator' , {
@@ -78,48 +101,40 @@ describe('CodeTabs web component', () => {
78101 } )
79102
80103 it ( 'does not throw when clipboard is unavailable' , async ( ) => {
81- await withJsdomEnvironment ( async ( { window } ) => {
104+ await renderCodeTabs ( { variant : 'single' } , ( { element, window } ) => {
105+ const globalRef = globalThis as unknown as { navigator ?: Navigator }
106+ const originalNavigator = globalRef . navigator
107+
108+ Object . defineProperty ( globalThis , 'navigator' , {
109+ configurable : true ,
110+ writable : true ,
111+ value : window . navigator ,
112+ } )
113+
82114 Object . defineProperty ( window . navigator , 'clipboard' , {
83115 configurable : true ,
84116 value : undefined ,
85117 } )
86118
87- const { registerCodeTabsWebComponent } =
88- await import ( '@components/Code/CodeTabs/client/index' )
89- registerCodeTabsWebComponent ( )
90-
91- const element = window . document . createElement ( 'code-tabs' )
92- const pre = window . document . createElement ( 'pre' )
93- pre . textContent = 'no clipboard'
94- element . appendChild ( pre )
95- window . document . body . appendChild ( element )
96-
97- const copyButton = element . querySelector (
98- 'button[aria-label="Copy"]'
99- ) as HTMLButtonElement | null
100- expect ( copyButton , 'CodeTabs should render a copy button' ) . toBeTruthy ( )
119+ try {
120+ const copyButton = element . querySelector (
121+ 'button[aria-label="Copy"]'
122+ ) as HTMLButtonElement | null
123+ expect ( copyButton , 'CodeTabs should render a copy button' ) . toBeTruthy ( )
101124
102- expect ( ( ) => copyButton ?. click ( ) ) . not . toThrow ( )
125+ expect ( ( ) => copyButton ?. click ( ) ) . not . toThrow ( )
126+ } finally {
127+ Object . defineProperty ( globalThis , 'navigator' , {
128+ configurable : true ,
129+ writable : true ,
130+ value : originalNavigator ,
131+ } )
132+ }
103133 } )
104134 } )
105135
106136 it ( 'renders a single tab label for a single named code block' , async ( ) => {
107- await withJsdomEnvironment ( async ( { window } ) => {
108- const { registerCodeTabsWebComponent } =
109- await import ( '@components/Code/CodeTabs/client/index' )
110- registerCodeTabsWebComponent ( )
111-
112- const element = window . document . createElement ( 'code-tabs' )
113- const pre = window . document . createElement ( 'pre' )
114- pre . setAttribute ( 'data-language' , 'typescript' )
115-
116- const code = window . document . createElement ( 'code' )
117- code . textContent = 'const x: number = 1'
118- pre . appendChild ( code )
119-
120- element . appendChild ( pre )
121- window . document . body . appendChild ( element )
122-
137+ await renderCodeTabs ( { variant : 'single' } , ( { element } ) => {
123138 const tabButton = element . querySelector ( 'button[data-code-tabs-button="0"]' )
124139 expect ( tabButton , 'CodeTabs should render a tab button for a single named code block' ) . toBeTruthy ( )
125140 expect ( tabButton ?. textContent ) . toBe ( 'TypeScript' )
@@ -131,27 +146,7 @@ describe('CodeTabs web component', () => {
131146 } )
132147
133148 it ( 'does not apply hover color change to the active tab when multiple tabs exist' , async ( ) => {
134- await withJsdomEnvironment ( async ( { window } ) => {
135- const { registerCodeTabsWebComponent } =
136- await import ( '@components/Code/CodeTabs/client/index' )
137- registerCodeTabsWebComponent ( )
138-
139- const element = window . document . createElement ( 'code-tabs' )
140-
141- const preA = window . document . createElement ( 'pre' )
142- preA . setAttribute ( 'data-code-tabs-tab' , 'A' )
143- preA . setAttribute ( 'data-language' , 'javascript' )
144- preA . appendChild ( window . document . createElement ( 'code' ) )
145-
146- const preB = window . document . createElement ( 'pre' )
147- preB . setAttribute ( 'data-code-tabs-tab' , 'B' )
148- preB . setAttribute ( 'data-language' , 'typescript' )
149- preB . appendChild ( window . document . createElement ( 'code' ) )
150-
151- element . appendChild ( preA )
152- element . appendChild ( preB )
153- window . document . body . appendChild ( element )
154-
149+ await renderCodeTabs ( { variant : 'multi' } , ( { element } ) => {
155150 const activeButton = element . querySelector ( 'button[data-code-tabs-button="0"]' )
156151 const inactiveButton = element . querySelector ( 'button[data-code-tabs-button="1"]' )
157152
@@ -171,18 +166,7 @@ describe('CodeTabs web component', () => {
171166 } )
172167
173168 it ( 'does not render tabs for excluded single-language blocks' , async ( ) => {
174- await withJsdomEnvironment ( async ( { window } ) => {
175- const { registerCodeTabsWebComponent } =
176- await import ( '@components/Code/CodeTabs/client/index' )
177- registerCodeTabsWebComponent ( )
178-
179- const element = window . document . createElement ( 'code-tabs' )
180- const pre = window . document . createElement ( 'pre' )
181- pre . setAttribute ( 'data-language' , 'text' )
182- pre . textContent = 'plain text'
183- element . appendChild ( pre )
184- window . document . body . appendChild ( element )
185-
169+ await renderCodeTabs ( { variant : 'excluded' } , ( { element } ) => {
186170 const anyTabButton = element . querySelector ( 'button[data-code-tabs-button]' )
187171 expect ( anyTabButton , 'CodeTabs should not render tab buttons for excluded languages' ) . toBeFalsy ( )
188172 } )
0 commit comments