@@ -2,60 +2,183 @@ import { join } from 'node:path'
22import { describe , it , expect , afterEach , vi } from 'vitest'
33import afterScreenshot from './afterScreenshot.js'
44import { rmSync } from 'node:fs'
5+ import hideScrollBars from '../clientSideScripts/hideScrollbars.js'
6+ import hideRemoveElements from '../clientSideScripts/hideRemoveElements.js'
7+ import removeElementFromDom from '../clientSideScripts/removeElementFromDom.js'
8+ import toggleTextTransparency from '../clientSideScripts/toggleTextTransparency.js'
9+ import { CUSTOM_CSS_ID } from './constants.js'
510
611vi . mock ( '../methods/images.js' , ( ) => ( {
712 saveBase64Image : vi . fn ( )
813} ) )
914
15+ vi . mock ( '@wdio/globals' , ( ) => ( {
16+ browser : {
17+ execute : ( ) => Promise . resolve ( '' )
18+ }
19+ } ) )
20+
1021describe ( 'afterScreenshot' , ( ) => {
1122 const folder = join ( process . cwd ( ) , '/.tmp/afterScreenshot' )
1223
1324 afterEach ( ( ) => rmSync ( folder , { recursive : true , force : true } ) )
1425
26+ // Helper function to create mock browser with execute function
27+ const createMockBrowser = async ( mockExecuteFn = vi . fn ( ) . mockResolvedValue ( '' ) ) => {
28+ const mockBrowser = await vi . importMock ( '@wdio/globals' ) as any
29+ mockBrowser . browser . execute = mockExecuteFn
30+ return mockExecuteFn
31+ }
32+
33+ // Base options that are common across tests
34+ const baseFilePath = {
35+ browserName : 'browserName' ,
36+ deviceName : 'deviceName' ,
37+ isMobile : false ,
38+ savePerInstance : true ,
39+ }
40+
41+ const baseFileName = {
42+ browserName : 'browserName' ,
43+ browserVersion : 'browserVersion' ,
44+ deviceName : 'deviceName' ,
45+ devicePixelRatio : 2 ,
46+ formatImageName : '{tag}-{browserName}-{width}x{height}-dpr-{dpr}' ,
47+ isMobile : false ,
48+ isTestInBrowser : true ,
49+ logName : 'logName' ,
50+ name : 'name' ,
51+ outerHeight : 850 ,
52+ outerWidth : 1400 ,
53+ platformName : 'platformName' ,
54+ platformVersion : 'platformVersion' ,
55+ screenHeight : 900 ,
56+ screenWidth : 1440 ,
57+ tag : 'tag' ,
58+ }
59+
60+ const createBaseOptions = ( overrides = { } ) => ( {
61+ actualFolder : folder ,
62+ base64Image : 'string' ,
63+ filePath : baseFilePath ,
64+ fileName : baseFileName ,
65+ hideScrollBars : false ,
66+ isLandscape : false ,
67+ isNativeContext : false ,
68+ platformName : '' ,
69+ ...overrides ,
70+ } )
71+
1572 it ( 'should be able to return the ScreenshotOutput with default options' , async ( ) => {
16- const MOCKED_EXECUTOR = vi . fn ( ) . mockReturnValue ( '' )
17- const options = {
18- actualFolder : folder ,
19- base64Image : 'string' ,
73+ const options = createBaseOptions ( {
2074 disableBlinkingCursor : false ,
2175 disableCSSAnimation : false ,
22- filePath : {
23- browserName : 'browserName' ,
24- deviceName : 'deviceName' ,
25- isMobile : false ,
26- savePerInstance : true ,
27- } ,
28- fileName : {
29- browserName : 'browserName' ,
30- browserVersion : 'browserVersion' ,
31- deviceName : 'deviceName' ,
32- devicePixelRatio : 2 ,
33- formatImageName : '{tag}-{browserName}-{width}x{height}-dpr-{dpr}' ,
34- isMobile : false ,
35- isTestInBrowser : true ,
36- logName : 'logName' ,
37- name : 'name' ,
38- outerHeight : 850 ,
39- outerWidth : 1400 ,
40- platformName : 'platformName' ,
41- platformVersion : 'platformVersion' ,
42- screenHeight : 900 ,
43- screenWidth : 1440 ,
44- tag : 'tag' ,
45- } ,
4676 hideScrollBars : true ,
47- isLandscape : false ,
48- isNativeContext : false ,
4977 hideElements : [ < HTMLElement > ( < any > '<div></div>' ) ] ,
50- platformName : '' ,
5178 removeElements : [ < HTMLElement > ( < any > '<div></div>' ) ] ,
52- }
79+ } )
5380
54- expect ( await afterScreenshot ( MOCKED_EXECUTOR , options ) ) . toEqual ( {
81+ expect ( await afterScreenshot ( options ) ) . toEqual ( {
5582 devicePixelRatio : 2 ,
5683 fileName : 'tag-browserName-1400x850-dpr-2.png' ,
5784 isLandscape : false ,
5885 path : `${ process . cwd ( ) } /.tmp/afterScreenshot/desktop_browserName` ,
5986 } )
6087 } )
88+
89+ it ( 'should handle native context and skip browser operations' , async ( ) => {
90+ const options = createBaseOptions ( {
91+ disableBlinkingCursor : true ,
92+ disableCSSAnimation : true ,
93+ enableLayoutTesting : true ,
94+ fileName : {
95+ ...baseFileName ,
96+ devicePixelRatio : 1.5 ,
97+ outerHeight : 600 ,
98+ outerWidth : 800 ,
99+ screenHeight : 700 ,
100+ screenWidth : 900 ,
101+ } ,
102+ hideScrollBars : true ,
103+ isLandscape : true ,
104+ isNativeContext : true , // This should skip all browser operations
105+ hideElements : [ < HTMLElement > ( < any > '<div></div>' ) ] ,
106+ platformName : 'iOS' ,
107+ removeElements : [ < HTMLElement > ( < any > '<div></div>' ) ] ,
108+ } )
109+
110+ expect ( await afterScreenshot ( options ) ) . toEqual ( {
111+ devicePixelRatio : 1.5 ,
112+ fileName : 'tag-browserName-800x600-dpr-1.5.png' ,
113+ isLandscape : true ,
114+ path : `${ process . cwd ( ) } /.tmp/afterScreenshot/desktop_browserName` ,
115+ } )
116+ } )
117+
118+ it ( 'should handle layout testing with enableLayoutTesting' , async ( ) => {
119+ const mockExecute = await createMockBrowser ( )
120+ const options = createBaseOptions ( {
121+ enableLayoutTesting : true ,
122+ } )
123+
124+ await afterScreenshot ( options )
125+
126+ // Should call toggleTextTransparency to show text again (enableLayoutTesting = true, so !enableLayoutTesting = false)
127+ expect ( mockExecute ) . toHaveBeenCalledWith ( toggleTextTransparency , false )
128+ } )
129+
130+ it ( 'should handle mobile platform and remove custom CSS' , async ( ) => {
131+ const mockExecute = await createMockBrowser ( )
132+ const options = createBaseOptions ( {
133+ disableBlinkingCursor : false ,
134+ disableCSSAnimation : false ,
135+ filePath : {
136+ ...baseFilePath ,
137+ isMobile : true ,
138+ } ,
139+ fileName : {
140+ ...baseFileName ,
141+ isMobile : true ,
142+ platformName : 'Android' ,
143+ } ,
144+ platformName : 'Android' , // This should trigger CSS removal for mobile
145+ } )
146+
147+ await afterScreenshot ( options )
148+
149+ // Should call removeElementFromDom with CUSTOM_CSS_ID for mobile platform
150+ expect ( mockExecute ) . toHaveBeenCalledWith ( removeElementFromDom , CUSTOM_CSS_ID )
151+ } )
152+
153+ it ( 'should handle hide/remove elements with error handling' , async ( ) => {
154+ const mockExecute = await createMockBrowser ( vi . fn ( ) . mockRejectedValueOnce ( new Error ( 'Element not found' ) ) )
155+ const consoleSpy = vi . spyOn ( console , 'warn' ) . mockImplementation ( ( ) => { } )
156+
157+ const hideElements = [ < HTMLElement > ( < any > '<div></div>' ) ]
158+ const removeElements = [ < HTMLElement > ( < any > '<div></div>' ) ]
159+
160+ const options = createBaseOptions ( {
161+ hideElements,
162+ removeElements,
163+ } )
164+
165+ await afterScreenshot ( options )
166+
167+ // Should call hideRemoveElements with proper parameters and handle error gracefully
168+ expect ( mockExecute ) . toHaveBeenCalledWith ( hideRemoveElements , { hide : hideElements , remove : removeElements } , false )
169+
170+ consoleSpy . mockRestore ( )
171+ } )
172+
173+ it ( 'should handle hideScrollBars when hideScrollBars is true' , async ( ) => {
174+ const mockExecute = await createMockBrowser ( )
175+ const options = createBaseOptions ( {
176+ hideScrollBars : true , // This should trigger hideScrollBars call
177+ } )
178+
179+ await afterScreenshot ( options )
180+
181+ // Should call hideScrollBars with false to show scrollbars again (hideScrollBars = true, so !hideScrollBars = false)
182+ expect ( mockExecute ) . toHaveBeenCalledWith ( hideScrollBars , false )
183+ } )
61184} )
0 commit comments