1+ /**
2+ * @vitest -environment jsdom
3+ */
4+
5+ import { vi } from "vitest" ;
6+ import { EventManager } from "@contentstack/advanced-post-message" ;
7+ import { LIVE_PREVIEW_CHANNEL_ID } from "../livePreviewEventManager.constant" ;
8+
9+ // Mock dependencies
10+ vi . mock ( "@contentstack/advanced-post-message" , ( ) => ( {
11+ EventManager : vi . fn ( ) ,
12+ } ) ) ;
13+
14+ vi . mock ( "../../../common/inIframe" , ( ) => ( {
15+ isOpeningInNewTab : vi . fn ( ) ,
16+ } ) ) ;
17+
18+ // Import after mocking
19+ import { isOpeningInNewTab } from "../../../common/inIframe" ;
20+
21+ describe ( "livePreviewEventManager" , ( ) => {
22+ let mockEventManager : any ;
23+ let originalWindow : any ;
24+
25+ beforeEach ( ( ) => {
26+ // Reset all mocks
27+ vi . clearAllMocks ( ) ;
28+
29+ // Create mock EventManager
30+ mockEventManager = {
31+ on : vi . fn ( ) ,
32+ send : vi . fn ( ) ,
33+ } ;
34+ ( EventManager as any ) . mockImplementation ( ( ) => mockEventManager ) ;
35+
36+ // Store original window
37+ originalWindow = global . window ;
38+
39+ // Reset isOpeningInNewTab mock
40+ ( isOpeningInNewTab as any ) . mockReturnValue ( false ) ;
41+ } ) ;
42+
43+ afterEach ( ( ) => {
44+ // Restore original window
45+ global . window = originalWindow ;
46+
47+ // Clear module cache to reset the module state
48+ vi . resetModules ( ) ;
49+ } ) ;
50+
51+ describe ( "when window is undefined" , ( ) => {
52+ beforeEach ( ( ) => {
53+ // Mock window as undefined
54+ Object . defineProperty ( global , "window" , {
55+ value : undefined ,
56+ writable : true ,
57+ } ) ;
58+ } ) ;
59+
60+ it ( "should not initialize EventManager when window is undefined" , async ( ) => {
61+ // Re-import the module to trigger initialization
62+ const module = await import ( "../livePreviewEventManager" ) ;
63+
64+ expect ( EventManager ) . not . toHaveBeenCalled ( ) ;
65+ expect ( module . default ) . toBeUndefined ( ) ;
66+ } ) ;
67+ } ) ;
68+
69+ describe ( "when window is defined" , ( ) => {
70+ let mockWindow : any ;
71+
72+ beforeEach ( ( ) => {
73+ // Create mock window object
74+ mockWindow = {
75+ parent : { postMessage : vi . fn ( ) } ,
76+ opener : { postMessage : vi . fn ( ) } ,
77+ } ;
78+
79+ Object . defineProperty ( global , "window" , {
80+ value : mockWindow ,
81+ writable : true ,
82+ } ) ;
83+ } ) ;
84+
85+ it ( "should initialize EventManager with window.parent as target when not in new tab" , async ( ) => {
86+ ( isOpeningInNewTab as any ) . mockReturnValue ( false ) ;
87+
88+ // Re-import the module to trigger initialization
89+ const module = await import ( "../livePreviewEventManager" ) ;
90+
91+ expect ( EventManager ) . toHaveBeenCalledWith ( LIVE_PREVIEW_CHANNEL_ID , {
92+ target : mockWindow . parent ,
93+ debug : false ,
94+ suppressErrors : true ,
95+ } ) ;
96+ expect ( module . default ) . toBe ( mockEventManager ) ;
97+ } ) ;
98+
99+ it ( "should initialize EventManager with window.opener as target when in new tab" , async ( ) => {
100+ ( isOpeningInNewTab as any ) . mockReturnValue ( true ) ;
101+
102+ // Re-import the module to trigger initialization
103+ const module = await import ( "../livePreviewEventManager" ) ;
104+
105+ expect ( EventManager ) . toHaveBeenCalledWith ( LIVE_PREVIEW_CHANNEL_ID , {
106+ target : mockWindow . opener ,
107+ debug : false ,
108+ suppressErrors : true ,
109+ } ) ;
110+ expect ( module . default ) . toBe ( mockEventManager ) ;
111+ } ) ;
112+
113+ it ( "should call isOpeningInNewTab to determine the target" , async ( ) => {
114+ // Re-import the module to trigger initialization
115+ await import ( "../livePreviewEventManager" ) ;
116+
117+ expect ( isOpeningInNewTab ) . toHaveBeenCalled ( ) ;
118+ } ) ;
119+
120+ it ( "should use correct channel ID" , async ( ) => {
121+ // Re-import the module to trigger initialization
122+ await import ( "../livePreviewEventManager" ) ;
123+
124+ expect ( EventManager ) . toHaveBeenCalledWith (
125+ LIVE_PREVIEW_CHANNEL_ID ,
126+ expect . any ( Object )
127+ ) ;
128+ } ) ;
129+
130+ it ( "should set correct default event options" , async ( ) => {
131+ ( isOpeningInNewTab as any ) . mockReturnValue ( false ) ;
132+
133+ // Re-import the module to trigger initialization
134+ await import ( "../livePreviewEventManager" ) ;
135+
136+ expect ( EventManager ) . toHaveBeenCalledWith (
137+ expect . any ( String ) ,
138+ expect . objectContaining ( {
139+ debug : false ,
140+ suppressErrors : true ,
141+ } )
142+ ) ;
143+ } ) ;
144+
145+ describe ( "target selection logic" , ( ) => {
146+ it ( "should prioritize window.opener when isOpeningInNewTab returns true" , async ( ) => {
147+ ( isOpeningInNewTab as any ) . mockReturnValue ( true ) ;
148+
149+ // Re-import the module to trigger initialization
150+ await import ( "../livePreviewEventManager" ) ;
151+
152+ const callArgs = ( EventManager as any ) . mock . calls [ 0 ] ;
153+ expect ( callArgs [ 1 ] . target ) . toBe ( mockWindow . opener ) ;
154+ expect ( callArgs [ 1 ] . target ) . not . toBe ( mockWindow . parent ) ;
155+ } ) ;
156+
157+ it ( "should use window.parent when isOpeningInNewTab returns false" , async ( ) => {
158+ ( isOpeningInNewTab as any ) . mockReturnValue ( false ) ;
159+
160+ // Re-import the module to trigger initialization
161+ await import ( "../livePreviewEventManager" ) ;
162+
163+ const callArgs = ( EventManager as any ) . mock . calls [ 0 ] ;
164+ expect ( callArgs [ 1 ] . target ) . toBe ( mockWindow . parent ) ;
165+ expect ( callArgs [ 1 ] . target ) . not . toBe ( mockWindow . opener ) ;
166+ } ) ;
167+
168+ it ( "should throw error when isOpeningInNewTab throws an error" , async ( ) => {
169+ ( isOpeningInNewTab as any ) . mockImplementation ( ( ) => {
170+ throw new Error ( "isOpeningInNewTab error" ) ;
171+ } ) ;
172+
173+ // Should throw because isOpeningInNewTab error is not caught in the implementation
174+ await expect ( async ( ) => {
175+ await import ( "../livePreviewEventManager" ) ;
176+ } ) . rejects . toThrow ( "isOpeningInNewTab error" ) ;
177+ } ) ;
178+ } ) ;
179+
180+ describe ( "edge cases" , ( ) => {
181+ it ( "should handle missing window.parent gracefully" , async ( ) => {
182+ mockWindow . parent = undefined ;
183+ ( isOpeningInNewTab as any ) . mockReturnValue ( false ) ;
184+
185+ // Re-import the module to trigger initialization
186+ const module = await import ( "../livePreviewEventManager" ) ;
187+
188+ expect ( EventManager ) . toHaveBeenCalledWith ( LIVE_PREVIEW_CHANNEL_ID , {
189+ target : undefined ,
190+ debug : false ,
191+ suppressErrors : true ,
192+ } ) ;
193+ expect ( module . default ) . toBe ( mockEventManager ) ;
194+ } ) ;
195+
196+ it ( "should handle missing window.opener gracefully" , async ( ) => {
197+ mockWindow . opener = undefined ;
198+ ( isOpeningInNewTab as any ) . mockReturnValue ( true ) ;
199+
200+ // Re-import the module to trigger initialization
201+ const module = await import ( "../livePreviewEventManager" ) ;
202+
203+ expect ( EventManager ) . toHaveBeenCalledWith ( LIVE_PREVIEW_CHANNEL_ID , {
204+ target : undefined ,
205+ debug : false ,
206+ suppressErrors : true ,
207+ } ) ;
208+ expect ( module . default ) . toBe ( mockEventManager ) ;
209+ } ) ;
210+
211+ it ( "should handle when EventManager constructor throws" , async ( ) => {
212+ ( EventManager as any ) . mockImplementation ( ( ) => {
213+ throw new Error ( "EventManager constructor error" ) ;
214+ } ) ;
215+
216+ // Should not crash the module initialization
217+ expect ( async ( ) => {
218+ await import ( "../livePreviewEventManager" ) ;
219+ } ) . not . toThrow ( ) ;
220+ } ) ;
221+ } ) ;
222+ } ) ;
223+
224+ describe ( "module export" , ( ) => {
225+ it ( "should export the EventManager instance when window is available" , async ( ) => {
226+ const mockWindow = {
227+ parent : { postMessage : vi . fn ( ) } ,
228+ opener : { postMessage : vi . fn ( ) } ,
229+ } ;
230+
231+ Object . defineProperty ( global , "window" , {
232+ value : mockWindow ,
233+ writable : true ,
234+ } ) ;
235+
236+ const module = await import ( "../livePreviewEventManager" ) ;
237+
238+ expect ( module . default ) . toBe ( mockEventManager ) ;
239+ } ) ;
240+
241+ it ( "should export undefined when window is not available" , async ( ) => {
242+ Object . defineProperty ( global , "window" , {
243+ value : undefined ,
244+ writable : true ,
245+ } ) ;
246+
247+ const module = await import ( "../livePreviewEventManager" ) ;
248+
249+ expect ( module . default ) . toBeUndefined ( ) ;
250+ } ) ;
251+ } ) ;
252+ } ) ;
0 commit comments