Skip to content

Commit ed0bea6

Browse files
fix: use dirname() for resolveSnapshotPath to avoid EISDIR conflict (#984) (#1124)
The visual-service was using the resolveSnapshotPath return value directly as a baseline directory, but this path is also read as a file by expect-webdriverio's SnapshotService. Wrapping with dirname() extracts the parent directory so the two consumers no longer collide. Co-authored-by: Cursor <[email protected]>
1 parent ce74703 commit ed0bea6

4 files changed

Lines changed: 51 additions & 2 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
"@wdio/visual-service": patch
3+
---
4+
5+
Fix `EISDIR` error when using `resolveSnapshotPath` with the visual service. The service now uses `dirname()` of the resolved path as the baseline folder, preventing it from creating a directory at a path that `expect-webdriverio`'s snapshot service expects to be a file. Fixes #984.
6+
7+
# Committers: 1
8+
9+
- Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
10+

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,6 @@ dist
3636

3737
*.tgz
3838
bugreport*.zip
39+
40+
# IDE
41+
.cursor/

packages/visual-service/src/service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ export default class WdioImageComparisonService extends BaseClass {
130130
* We also check `this.#config` because for standalone usage of the service, the config is not available
131131
*/
132132
if (this.#config && typeof this.#config.resolveSnapshotPath === 'function' && this.#currentFile && isDefaultBaselineFolder) {
133-
return this.#config.resolveSnapshotPath(this.#currentFile, '.png')
133+
return dirname(this.#config.resolveSnapshotPath(this.#currentFile, '.png'))
134134
}
135135

136136
return baselineFolder

packages/visual-service/tests/service.test.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { join } from 'node:path'
1+
import { dirname, join, normalize } from 'node:path'
22
import logger from '@wdio/logger'
33
import { expect as wdioExpect } from '@wdio/globals'
44
import { beforeEach, describe, expect, it, vi } from 'vitest'
@@ -199,5 +199,41 @@ describe('@wdio/visual-service', () => {
199199
const [saveScreenOptions] = vi.mocked(saveScreen).mock.calls[0]
200200
expect((saveScreenOptions as any).saveScreenOptions?.wic?.alwaysSaveActualImage).toBe(true)
201201
})
202+
203+
it('should use dirname() of resolveSnapshotPath result as baselineFolder to avoid EISDIR conflicts', async () => {
204+
vi.mocked(saveScreen).mockResolvedValue({} as any)
205+
const resolveSnapshotPath = vi.fn().mockReturnValue('/custom/snapshots/specs/test.e2e.png')
206+
const config = {
207+
framework: 'mocha',
208+
resolveSnapshotPath,
209+
} as unknown as WebdriverIO.Config
210+
const service = new VisualService({}, {}, config)
211+
;(service as any).defaultOptions = {}
212+
;(service as any).folders = { baselineFolder: normalize('./__snapshots__/') }
213+
const browser = {
214+
isMultiremote: false,
215+
addCommand: vi.fn((name, fn) => {
216+
(browser as any)[name] = fn
217+
}),
218+
capabilities: {},
219+
requestedCapabilities: {},
220+
on: vi.fn(),
221+
execute: vi.fn().mockResolvedValue(1),
222+
} as any as WebdriverIO.Browser
223+
224+
await service.before({}, [], browser)
225+
service.beforeTest({
226+
file: '/project/specs/test.e2e.ts',
227+
parent: 'suite',
228+
title: 'test',
229+
} as any)
230+
await (browser as any).saveScreen('tag')
231+
232+
expect(resolveSnapshotPath).toHaveBeenCalledWith('/project/specs/test.e2e.ts', '.png')
233+
const [saveScreenOptions] = vi.mocked(saveScreen).mock.calls[0]
234+
expect((saveScreenOptions as any).folders.baselineFolder).toBe(
235+
dirname('/custom/snapshots/specs/test.e2e.png')
236+
)
237+
})
202238
})
203239
})

0 commit comments

Comments
 (0)