Skip to content

Commit 64a70fd

Browse files
committed
chore: fixed afterScreenshot
- updated tests
1 parent 788379b commit 64a70fd

7 files changed

Lines changed: 170 additions & 49 deletions

File tree

packages/image-comparison-core/src/commands/saveAppElement.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export default async function saveAppElement(
2626
formatImageName,
2727
savePerInstance,
2828
} = saveElementOptions.wic
29-
const { executor, getElementRect, screenShot } = methods
29+
const { getElementRect, screenShot } = methods
3030
const resizeDimensions: ResizeDimensions = saveElementOptions.method.resizeDimensions || DEFAULT_RESIZE_DIMENSIONS
3131
const {
3232
browserName,
@@ -85,5 +85,5 @@ export default async function saveAppElement(
8585
}
8686

8787
// 4. Return the data
88-
return afterScreenshot(executor, afterOptions)
88+
return afterScreenshot(afterOptions)
8989
}

packages/image-comparison-core/src/commands/saveAppScreen.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import type { InternalSaveScreenMethodOptions } from './save.interfaces.js'
99
*/
1010
export default async function saveAppScreen(
1111
{
12-
methods,
1312
instanceData,
1413
folders,
1514
tag,
@@ -91,5 +90,5 @@ export default async function saveAppScreen(
9190
}
9291

9392
// 5. Return the data
94-
return afterScreenshot(methods.executor, afterOptions)
93+
return afterScreenshot(afterOptions)
9594
}

packages/image-comparison-core/src/commands/saveFullPageScreen.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export default async function saveFullPageScreen(
9090
} = enrichedInstanceData
9191
let fullPageBase64Image: string
9292

93-
if (canUseBidiScreenshot(methods) && !isEmulated && (!userBasedFullPageScreenshot || !enableLegacyScreenshotMethod)) {
93+
if (canUseBidiScreenshot() && !isEmulated && (!userBasedFullPageScreenshot || !enableLegacyScreenshotMethod)) {
9494
// 3a. Fullpage screenshots are taken in one go with the Bidi protocol
9595
fullPageBase64Image = await takeBase64BiDiScreenshot({
9696
bidiScreenshot: methods.bidiScreenshot!,
@@ -116,7 +116,6 @@ export default async function saveFullPageScreen(
116116
toolBarShadowPadding: toolBarShadowPadding,
117117
}
118118
const screenshotsData: FullPageScreenshotsData = await getBase64FullPageScreenshotsData(
119-
methods.screenShot,
120119
methods.executor,
121120
fullPageScreenshotOptions,
122121
)
@@ -168,6 +167,6 @@ export default async function saveFullPageScreen(
168167
}
169168

170169
// 6. Return the data
171-
return afterScreenshot(methods.executor, afterOptions!)
170+
return afterScreenshot(afterOptions!)
172171
}
173172

packages/image-comparison-core/src/commands/saveWebElement.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export default async function saveWebElement(
8484

8585
let base64Image: string
8686

87-
if (canUseBidiScreenshot(methods) && !isMobile && !enableLegacyScreenshotMethod) {
87+
if (canUseBidiScreenshot() && !isMobile && !enableLegacyScreenshotMethod) {
8888
// 3a. Take the screenshot with the BiDi method
8989
// We also need to clip the image to the element size, taking into account the DPR
9090
// and also clipt if from the document, not the viewport
@@ -213,5 +213,5 @@ export default async function saveWebElement(
213213
}
214214

215215
// 7. Return the data
216-
return afterScreenshot(executor, afterOptions)
216+
return afterScreenshot(afterOptions)
217217
}

packages/image-comparison-core/src/commands/saveWebScreen.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,5 +158,5 @@ export default async function saveWebScreen(
158158
}
159159

160160
// 6. Return the data
161-
return afterScreenshot(methods.executor, afterOptions)
161+
return afterScreenshot(afterOptions)
162162
}

packages/image-comparison-core/src/helpers/afterScreenshot.test.ts

Lines changed: 156 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,60 +2,183 @@ import { join } from 'node:path'
22
import { describe, it, expect, afterEach, vi } from 'vitest'
33
import afterScreenshot from './afterScreenshot.js'
44
import { 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

611
vi.mock('../methods/images.js', () => ({
712
saveBase64Image: vi.fn()
813
}))
914

15+
vi.mock('@wdio/globals', () => ({
16+
browser: {
17+
execute: () => Promise.resolve('')
18+
}
19+
}))
20+
1021
describe('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
})

packages/image-comparison-core/src/helpers/afterScreenshot.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ import removeElementFromDom from '../clientSideScripts/removeElementFromDom.js'
55
import { CUSTOM_CSS_ID } from './constants.js'
66
import { checkIsMobile, formatFileName, getAndCreatePath } from './utils.js'
77
import { saveBase64Image } from '../methods/images.js'
8-
import type { Executor } from '../methods/methods.interfaces.js'
98
import type { AfterScreenshotOptions, ScreenshotOutput } from './afterScreenshot.interfaces.js'
109
import hideRemoveElements from '../clientSideScripts/hideRemoveElements.js'
1110
import toggleTextTransparency from '../clientSideScripts/toggleTextTransparency.js'
11+
import { browser } from '@wdio/globals'
1212

1313
const log = logger('@wdio/visual-service:webdriver-image-comparison')
1414

1515
/**
1616
* Methods that need to be executed after a screenshot has been taken
1717
* to set all back to the original state
1818
*/
19-
export default async function afterScreenshot(executor: Executor, options: AfterScreenshotOptions): Promise<ScreenshotOutput> {
19+
export default async function afterScreenshot(options: AfterScreenshotOptions): Promise<ScreenshotOutput> {
2020
const {
2121
actualFolder,
2222
base64Image,
@@ -45,13 +45,13 @@ export default async function afterScreenshot(executor: Executor, options: After
4545
if (!isNativeContext){
4646
// Show the scrollbars again
4747
if (noScrollBars) {
48-
await executor(hideScrollBars, !noScrollBars)
48+
await browser.execute(hideScrollBars, !noScrollBars)
4949
}
5050

5151
// Show elements again
5252
if ((hideElements && hideElements.length > 0) || (removeElements && removeElements.length > 0)) {
5353
try {
54-
await executor(hideRemoveElements, { hide: hideElements, remove: removeElements }, false)
54+
await browser.execute(hideRemoveElements, { hide: hideElements, remove: removeElements }, false)
5555
} catch (e) {
5656
log.warn(
5757
'\x1b[33m%s\x1b[0m',
@@ -70,12 +70,12 @@ export default async function afterScreenshot(executor: Executor, options: After
7070

7171
// Remove the custom set css
7272
if (disableCSSAnimation || disableBlinkingCursor || checkIsMobile(platformName)) {
73-
await executor(removeElementFromDom, CUSTOM_CSS_ID)
73+
await browser.execute(removeElementFromDom, CUSTOM_CSS_ID)
7474
}
7575

7676
// Show the text again
7777
if (enableLayoutTesting){
78-
await executor(toggleTextTransparency, !enableLayoutTesting)
78+
await browser.execute(toggleTextTransparency, !enableLayoutTesting)
7979
}
8080

8181
}

0 commit comments

Comments
 (0)