1- // @vitest -environment happy-dom
1+ // @vitest -environment jsdom
22/**
33 * Unit tests for AppBootstrap
44 * Tests initialization of state management on page load
55 */
6- import { describe , it , expect , beforeEach , vi } from 'vitest'
6+ import { afterAll , beforeEach , describe , expect , it , vi } from 'vitest'
77import { AppBootstrap } from '@components/scripts/bootstrap'
88import { addScriptBreadcrumb , ClientScriptError } from '@components/scripts/errors'
99import { TestError } from '@test/errors'
1010
11+ vi . mock ( '@components/scripts/errors' , async ( ) => {
12+ const actual = await vi . importActual < typeof import ( '@components/scripts/errors' ) > (
13+ '@components/scripts/errors'
14+ )
15+
16+ return {
17+ ...actual ,
18+ addScriptBreadcrumb : vi . fn ( ) ,
19+ handleScriptError : vi . fn ( ) ,
20+ }
21+ } )
22+
1123// Mock the store initialization functions
1224vi . mock ( '@components/scripts/store' , ( ) => ( {
1325 initConsentFromCookies : vi . fn ( ) ,
@@ -18,30 +30,76 @@ vi.mock('@components/scripts/store', () => ({
1830 } ,
1931} ) )
2032
21- // Mock Sentry breadcrumb function
22- vi . mock ( '@components/scripts/errors' , ( ) => ( {
23- addScriptBreadcrumb : vi . fn ( ) ,
24- handleScriptError : vi . fn ( ) ,
33+ vi . mock ( '@components/scripts/sentry/client' , ( ) => ( {
34+ SentryBootstrap : {
35+ init : vi . fn ( ) ,
36+ } ,
37+ } ) )
38+
39+ const mockEnvironmentClient = vi . hoisted ( ( ) => ( {
40+ getPackageRelease : vi . fn ( ) . mockReturnValue ( 'test-release' ) ,
41+ getPrivacyPolicyVersion : vi . fn ( ) . mockReturnValue ( '1.0.0' ) ,
42+ isProd : vi . fn ( ) . mockReturnValue ( false ) ,
43+ isDev : vi . fn ( ) . mockReturnValue ( true ) ,
44+ isE2eTest : vi . fn ( ) . mockReturnValue ( false ) ,
45+ isTest : vi . fn ( ) . mockReturnValue ( false ) ,
46+ isUnitTest : vi . fn ( ) . mockReturnValue ( true ) ,
2547} ) )
2648
49+ vi . mock ( '@components/scripts/utils/environmentClient' , ( ) => mockEnvironmentClient )
50+
2751// Import the mocked functions after setting up mocks
2852import {
2953 initConsentFromCookies ,
3054 initConsentSideEffects ,
3155 addViewTransitionThemeInitListener ,
3256} from '@components/scripts/store'
57+ import { SentryBootstrap } from '@components/scripts/sentry/client'
58+
59+ type TestWindow = Window & {
60+ isPlaywrightControlled ?: boolean
61+ environmentClientSnapshot ?: {
62+ isUnitTest : boolean
63+ isTest : boolean
64+ isE2eTest : boolean
65+ isDev : boolean
66+ isProd : boolean
67+ packageRelease : string
68+ privacyPolicyVersion : string
69+ }
70+ }
71+
72+ const testWindow = window as TestWindow
73+ const consoleInfoSpy = vi . spyOn ( console , 'info' ) . mockImplementation ( ( ) => { } )
74+
75+ const mockSuccessfulInit = ( ) => {
76+ vi . mocked ( addViewTransitionThemeInitListener ) . mockReturnValue ( undefined )
77+ vi . mocked ( initConsentFromCookies ) . mockReturnValue ( undefined )
78+ vi . mocked ( initConsentSideEffects ) . mockReturnValue ( undefined )
79+ }
3380
3481describe ( 'AppBootstrap' , ( ) => {
3582 beforeEach ( ( ) => {
3683 vi . clearAllMocks ( )
84+ mockSuccessfulInit ( )
85+ delete testWindow . isPlaywrightControlled
86+ delete testWindow . environmentClientSnapshot
87+ mockEnvironmentClient . isProd . mockReturnValue ( false )
88+ mockEnvironmentClient . isDev . mockReturnValue ( true )
89+ mockEnvironmentClient . isE2eTest . mockReturnValue ( false )
90+ mockEnvironmentClient . isTest . mockReturnValue ( false )
91+ mockEnvironmentClient . isUnitTest . mockReturnValue ( true )
92+ mockEnvironmentClient . getPackageRelease . mockReturnValue ( 'test-release' )
93+ mockEnvironmentClient . getPrivacyPolicyVersion . mockReturnValue ( '1.0.0' )
94+ consoleInfoSpy . mockClear ( )
95+ } )
96+
97+ afterAll ( ( ) => {
98+ consoleInfoSpy . mockRestore ( )
3799 } )
38100
39101 describe ( 'Successful initialization' , ( ) => {
40102 it ( 'should call addViewTransitionThemeInitListener, initConsentFromCookies and initialize side effects' , ( ) => {
41- vi . mocked ( addViewTransitionThemeInitListener ) . mockReturnValue ( undefined )
42- vi . mocked ( initConsentFromCookies ) . mockReturnValue ( undefined )
43- vi . mocked ( initConsentSideEffects ) . mockReturnValue ( undefined )
44-
45103 AppBootstrap . init ( )
46104
47105 expect ( addViewTransitionThemeInitListener ) . toHaveBeenCalledTimes ( 1 )
@@ -50,10 +108,6 @@ describe('AppBootstrap', () => {
50108 } )
51109
52110 it ( 'should add breadcrumbs for successful initialization' , ( ) => {
53- vi . mocked ( addViewTransitionThemeInitListener ) . mockReturnValue ( undefined )
54- vi . mocked ( initConsentFromCookies ) . mockReturnValue ( undefined )
55- vi . mocked ( initConsentSideEffects ) . mockReturnValue ( undefined )
56-
57111 AppBootstrap . init ( )
58112
59113 expect ( addScriptBreadcrumb ) . toHaveBeenCalledWith ( {
@@ -75,10 +129,6 @@ describe('AppBootstrap', () => {
75129 } )
76130
77131 it ( 'should not throw error when initialization succeeds' , ( ) => {
78- vi . mocked ( addViewTransitionThemeInitListener ) . mockReturnValue ( undefined )
79- vi . mocked ( initConsentFromCookies ) . mockReturnValue ( undefined )
80- vi . mocked ( initConsentSideEffects ) . mockReturnValue ( undefined )
81-
82132 expect ( ( ) => AppBootstrap . init ( ) ) . not . toThrow ( )
83133 } )
84134 } )
@@ -122,11 +172,9 @@ describe('AppBootstrap', () => {
122172 } )
123173
124174 it ( 'should not call side effects when initConsentFromCookies fails' , ( ) => {
125- vi . mocked ( addViewTransitionThemeInitListener ) . mockReturnValue ( undefined )
126175 vi . mocked ( initConsentFromCookies ) . mockImplementation ( ( ) => {
127176 throw new TestError ( 'Cookie initialization failed' )
128177 } )
129- vi . mocked ( initConsentSideEffects ) . mockReturnValue ( undefined )
130178
131179 try {
132180 AppBootstrap . init ( )
@@ -138,7 +186,6 @@ describe('AppBootstrap', () => {
138186 } )
139187
140188 it ( 'should wrap non-Error objects in ClientScriptError' , ( ) => {
141- vi . mocked ( addViewTransitionThemeInitListener ) . mockReturnValue ( undefined )
142189 vi . mocked ( initConsentFromCookies ) . mockImplementation ( ( ) => {
143190 throw 'String error'
144191 } )
@@ -155,10 +202,6 @@ describe('AppBootstrap', () => {
155202
156203 describe ( 'Integration scenarios' , ( ) => {
157204 it ( 'should successfully initialize on repeated calls' , ( ) => {
158- vi . mocked ( addViewTransitionThemeInitListener ) . mockReturnValue ( undefined )
159- vi . mocked ( initConsentFromCookies ) . mockReturnValue ( undefined )
160- vi . mocked ( initConsentSideEffects ) . mockReturnValue ( undefined )
161-
162205 AppBootstrap . init ( )
163206 AppBootstrap . init ( )
164207
@@ -167,4 +210,47 @@ describe('AppBootstrap', () => {
167210 expect ( initConsentSideEffects ) . toHaveBeenCalledTimes ( 2 )
168211 } )
169212 } )
213+
214+ describe ( 'Runtime integrations' , ( ) => {
215+ it ( 'should write the environment snapshot when Playwright controls the window' , ( ) => {
216+ testWindow . isPlaywrightControlled = true
217+ mockEnvironmentClient . isUnitTest . mockReturnValue ( false )
218+ mockEnvironmentClient . isTest . mockReturnValue ( true )
219+ mockEnvironmentClient . isE2eTest . mockReturnValue ( true )
220+ mockEnvironmentClient . isDev . mockReturnValue ( false )
221+ mockEnvironmentClient . isProd . mockReturnValue ( true )
222+ mockEnvironmentClient . getPackageRelease . mockReturnValue ( '2024.10.0' )
223+ mockEnvironmentClient . getPrivacyPolicyVersion . mockReturnValue ( '3.1.4' )
224+
225+ AppBootstrap . init ( )
226+
227+ expect ( testWindow . environmentClientSnapshot ) . toEqual ( {
228+ isUnitTest : false ,
229+ isTest : true ,
230+ isE2eTest : true ,
231+ isDev : false ,
232+ isProd : true ,
233+ packageRelease : '2024.10.0' ,
234+ privacyPolicyVersion : '3.1.4' ,
235+ } )
236+ } )
237+
238+ it ( 'should initialize Sentry in production builds' , ( ) => {
239+ mockEnvironmentClient . isProd . mockReturnValue ( true )
240+
241+ AppBootstrap . init ( )
242+
243+ expect ( SentryBootstrap . init ) . toHaveBeenCalledTimes ( 1 )
244+ expect ( consoleInfoSpy ) . not . toHaveBeenCalled ( )
245+ } )
246+
247+ it ( 'should log when Sentry stays disabled outside production' , ( ) => {
248+ mockEnvironmentClient . isProd . mockReturnValue ( false )
249+
250+ AppBootstrap . init ( )
251+
252+ expect ( SentryBootstrap . init ) . not . toHaveBeenCalled ( )
253+ expect ( consoleInfoSpy ) . toHaveBeenCalledWith ( '🔧 Sentry disabled in development mode' )
254+ } )
255+ } )
170256} )
0 commit comments