Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Resolved failure to find arbitrarily-named snapshot files when using expect(...).toMatchFileSnapshot() matcher. #4839

Merged
merged 26 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3ce5f62
Fixed script file patterns; browser tests now run as expected
Jan 1, 2024
c3aef1d
Fixed script file patterns; benchmark tests now run as expected
Jan 1, 2024
6756cf8
fix: resolved failure to find arbitrarily-named snapshot files by rem…
Jan 1, 2024
d932ede
Remove extra semicolon
Jan 1, 2024
fdf2feb
Merge remote-tracking branch 'upstream/main'
Jan 2, 2024
eeb9b73
fix: Resolve deserialization issue for Errors through from Node-side …
zmullett Jan 4, 2024
dac6f72
feature: Support a special equality for snapshots where both the expe…
zmullett Jan 4, 2024
380a11e
fix: Use Vite server isFileServingAllowed() util to determine accessi…
zmullett Jan 4, 2024
e5f64b7
chore: lint fixes
zmullett Jan 4, 2024
d91c4d9
chore(deps): update dependency vitepress to ^1.0.0-rc.34 (#4835)
renovate[bot] Jan 2, 2024
78924d8
chore(deps): update playwright monorepo to ^1.40.1 (#4836)
renovate[bot] Jan 2, 2024
c49ec7c
fix(deps): update dependency acorn-walk to ^8.3.1 (#4837)
renovate[bot] Jan 2, 2024
c83f05a
fix(deps): update dependency sirv to ^2.0.4 (#4838)
renovate[bot] Jan 2, 2024
d92ad9c
docs: use Badge to display versions (#4823)
sheremet-va Jan 2, 2024
5686388
ci: fix failing ci (#4846)
sheremet-va Jan 2, 2024
3a750b0
refactor(vitest): reimplement hoistMocks to fix incorrect dynamic imp…
Dunqing Jan 3, 2024
54dc582
docs: fix rendering of note (#4822)
pascalberger Jan 3, 2024
96bf8fc
fix(runner): fix fixture cleanup for concurrent tests (#4827)
hi-ogawa Jan 3, 2024
1bacc8b
fix(spy): don't allow Promise in mockImplementation (#4859)
sheremet-va Jan 3, 2024
e2957da
fix: remove internal flag from UI option in the config
sheremet-va Jan 3, 2024
1a2e7ef
chore(runner): update better error message for nested test (#4652)
Dunqing Jan 3, 2024
45988cc
Merge branch 'main' into main
zmullett Jan 4, 2024
40e7ced
chore: Resolve code review issues
zmullett Jan 4, 2024
b25c572
chore: Revert packages/snapshot/src/port/state.ts changes that altere…
zmullett Jan 4, 2024
613dc05
Merge branch 'main' into main
zmullett Jan 4, 2024
255bdb1
chore: cleanup
sheremet-va Jan 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 0 additions & 2 deletions packages/snapshot/src/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { SnapshotResult, SnapshotStateOptions, SnapshotSummary } from './ty

export class SnapshotManager {
summary: SnapshotSummary = undefined!
resolvedPaths = new Set<string>()
extension = '.snap'

constructor(public options: Omit<SnapshotStateOptions, 'snapshotEnvironment'>) {
Expand All @@ -30,7 +29,6 @@ export class SnapshotManager {
})

const path = resolver(testPath, this.extension)
this.resolvedPaths.add(path)
return path
}

Expand Down
25 changes: 17 additions & 8 deletions packages/vitest/src/api/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,27 @@ import { createBirpc } from 'birpc'
import { parse, stringify } from 'flatted'
import type { WebSocket } from 'ws'
import { WebSocketServer } from 'ws'
import { isFileServingAllowed } from 'vite'
import type { ViteDevServer } from 'vite'
import type { StackTraceParserOptions } from '@vitest/utils/source-map'
import { API_PATH } from '../constants'
import type { Vitest } from '../node'
import type { File, ModuleGraphData, Reporter, TaskResultPack, UserConsoleLog } from '../types'
import { getModuleGraph, isPrimitive } from '../utils'
import { getModuleGraph, isPrimitive, stringifyReplace } from '../utils'
import type { WorkspaceProject } from '../node/workspace'
import { parseErrorStacktrace } from '../utils/source-map'
import type { TransformResultWithSource, WebSocketEvents, WebSocketHandlers } from './types'

export function setup(vitestOrWorkspace: Vitest | WorkspaceProject, server?: ViteDevServer) {
export function setup(vitestOrWorkspace: Vitest | WorkspaceProject, _server?: ViteDevServer) {
const ctx = 'ctx' in vitestOrWorkspace ? vitestOrWorkspace.ctx : vitestOrWorkspace

const wss = new WebSocketServer({ noServer: true })

const clients = new Map<WebSocket, BirpcReturn<WebSocketEvents, WebSocketHandlers>>()

;(server || ctx.server).httpServer?.on('upgrade', (request, socket, head) => {
const server = _server || ctx.server

server.httpServer?.on('upgrade', (request, socket, head) => {
if (!request.url)
return

Expand All @@ -37,6 +40,11 @@ export function setup(vitestOrWorkspace: Vitest | WorkspaceProject, server?: Vit
})
})

function checkFileAccess(path: string) {
if (!isFileServingAllowed(path, server))
throw new Error(`Access denied to "${path}". See Vite config documentation for "server.fs": https://vitejs.dev/config/server-options.html#server-fs-strict.`)
}

function setupClient(ws: WebSocket) {
const rpc = createBirpc<WebSocketEvents, WebSocketHandlers>(
{
Expand Down Expand Up @@ -73,7 +81,8 @@ export function setup(vitestOrWorkspace: Vitest | WorkspaceProject, server?: Vit
return ctx.snapshot.resolveRawPath(testPath, rawPath)
},
async readSnapshotFile(snapshotPath) {
if (!ctx.snapshot.resolvedPaths.has(snapshotPath) || !existsSync(snapshotPath))
checkFileAccess(snapshotPath)
if (!existsSync(snapshotPath))
return null
return fs.readFile(snapshotPath, 'utf-8')
},
Expand All @@ -88,13 +97,13 @@ export function setup(vitestOrWorkspace: Vitest | WorkspaceProject, server?: Vit
return fs.writeFile(id, content, 'utf-8')
},
async saveSnapshotFile(id, content) {
if (!ctx.snapshot.resolvedPaths.has(id))
throw new Error(`Snapshot file "${id}" does not exist.`)
checkFileAccess(id)
await fs.mkdir(dirname(id), { recursive: true })
zmullett marked this conversation as resolved.
Show resolved Hide resolved
return fs.writeFile(id, content, 'utf-8')
},
async removeSnapshotFile(id) {
if (!ctx.snapshot.resolvedPaths.has(id) || !existsSync(id))
checkFileAccess(id)
if (!existsSync(id))
zmullett marked this conversation as resolved.
Show resolved Hide resolved
throw new Error(`Snapshot file "${id}" does not exist.`)
return fs.unlink(id)
},
Expand Down Expand Up @@ -140,7 +149,7 @@ export function setup(vitestOrWorkspace: Vitest | WorkspaceProject, server?: Vit
post: msg => ws.send(msg),
on: fn => ws.on('message', fn),
eventNames: ['onUserConsoleLog', 'onFinished', 'onCollected', 'onCancel'],
serialize: stringify,
serialize: (data: any) => stringify(data, stringifyReplace),
deserialize: parse,
},
)
Expand Down
1 change: 1 addition & 0 deletions packages/vitest/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export * from './global'
export * from './timers'
export * from './env'
export * from './modules'
export * from './serialization'

export const isWindows = isNode && process.platform === 'win32'
export function getRunMode() {
Expand Down
22 changes: 22 additions & 0 deletions packages/vitest/src/utils/serialization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Serialization support utils.

function cloneByOwnProperties(value: any) {
// Clones the value's properties into a new Object. The simpler approach of
// Object.assign() won't work in the case that properties are not enumerable.
return Object.getOwnPropertyNames(value)
.reduce((clone, prop) => ({
...clone,
[prop]: value[prop],
}), {})
}

/**
* Replacer function for serialization methods such as JS.stringify() or
* flatted.stringify().
*/
export function stringifyReplace(key: string, value: any) {
if (value instanceof Error)
return cloneByOwnProperties(value)
else
return value
}
2 changes: 1 addition & 1 deletion test/benchmark/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"type": "module",
"private": true,
"scripts": {
"test": "node --test specs/ && echo '1'",
"test": "node --test specs/* && echo '1'",
"bench:json": "vitest bench --reporter=json",
"bench": "vitest bench"
},
Expand Down
8 changes: 6 additions & 2 deletions test/browser/specs/runner.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ const passedTests = getPassed(browserResultJson.testResults)
const failedTests = getFailed(browserResultJson.testResults)

await test('tests are actually running', async () => {
assert.ok(browserResultJson.testResults.length === 9, 'Not all the tests have been run')
assert.ok(browserResultJson.testResults.length === 10, 'Not all the tests have been run')
assert.ok(passedTests.length === 8, 'Some tests failed')
assert.ok(failedTests.length === 1, 'Some tests have passed but should fail')
assert.ok(failedTests.length === 2, 'Some tests have passed but should fail')

assert.doesNotMatch(stderr, /Unhandled Error/, 'doesn\'t have any unhandled errors')
})
Expand Down Expand Up @@ -80,3 +80,7 @@ await test('popup apis should log a warning', () => {
assert.ok(stderr.includes('Vitest encountered a \`confirm\("test"\)\`'), 'prints warning for confirm')
assert.ok(stderr.includes('Vitest encountered a \`prompt\("test"\)\`'), 'prints warning for prompt')
})

await test('snapshot inaccessible file debuggability', () => {
assert.ok(stdout.includes('Access denied to "/inaccesible/path".'), 'file security enforcement explained')
})
1 change: 1 addition & 0 deletions test/browser/test/__snapshots__/custom/my_snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
my snapshot content
2 changes: 1 addition & 1 deletion test/browser/test/__snapshots__/snapshot.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`file snapshot 1`] = `1`;
exports[`snapshot 1`] = `1`;
6 changes: 6 additions & 0 deletions test/browser/test/failing.snaphot.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { expect, test } from 'vitest'

test('file snapshot', async () => {
await expect('inaccessible snapshot content')
.toMatchFileSnapshot('/inaccesible/path')
})
7 changes: 6 additions & 1 deletion test/browser/test/snapshot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ test('inline snapshot', () => {
expect(1).toMatchInlineSnapshot('1')
})

test('file snapshot', () => {
test('snapshot', () => {
expect(1).toMatchSnapshot()
})

test('file snapshot', async () => {
await expect('my snapshot content')
.toMatchFileSnapshot('./__snapshots__/custom/my_snapshot')
})