[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

fix(vitest): correctly resolve mocked node:* imports in __mocks__ folder (#6204)

authored by

Vladimir and committed by
GitHub
(Jul 23, 2024, 9:12 PM +0200) a48be6ff 3aab8a1e

+109 -16
+21 -2
pnpm-lock.yaml
··· 1173 1173 immutable: 1174 1174 specifier: 5.0.0-beta.5 1175 1175 version: 5.0.0-beta.5 1176 + memfs: 1177 + specifier: ^4.8.2 1178 + version: 4.8.2 1176 1179 strip-ansi: 1177 1180 specifier: ^7.1.0 1178 1181 version: 7.1.0 ··· 1434 1437 peerDependencies: 1435 1438 '@algolia/client-search': '>= 4.9.1 < 6' 1436 1439 algoliasearch: '>= 4.9.1 < 6' 1440 + peerDependenciesMeta: 1441 + '@algolia/client-search': 1442 + optional: true 1437 1443 1438 1444 '@algolia/autocomplete-shared@1.9.3': 1439 1445 resolution: {integrity: sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==} 1440 1446 peerDependencies: 1441 1447 '@algolia/client-search': '>= 4.9.1 < 6' 1442 1448 algoliasearch: '>= 4.9.1 < 6' 1449 + peerDependenciesMeta: 1450 + '@algolia/client-search': 1451 + optional: true 1443 1452 1444 1453 '@algolia/cache-browser-local-storage@4.20.0': 1445 1454 resolution: {integrity: sha512-uujahcBt4DxduBTvYdwO3sBfHuJvJokiC3BP1+O70fglmE1ShkH8lpXqZBac1rrU3FnNYSUs4pL9lBdTKeRPOQ==} ··· 6785 6794 resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} 6786 6795 engines: {node: '>= 0.6'} 6787 6796 6797 + memfs@4.8.2: 6798 + resolution: {integrity: sha512-j4WKth315edViMBGkHW6NTF0QBjsTrcRDmYNcGsPq+ozMEyCCCIlX2d2mJ5wuh6iHvJ3FevUrr48v58YRqVdYg==} 6799 + engines: {node: '>= 4.0.0'} 6800 + 6788 6801 merge-anything@5.1.7: 6789 6802 resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==} 6790 6803 engines: {node: '>=12.13'} ··· 9240 9253 '@algolia/autocomplete-preset-algolia@1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0)': 9241 9254 dependencies: 9242 9255 '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0) 9243 - '@algolia/client-search': 4.20.0 9244 9256 algoliasearch: 4.20.0 9257 + optionalDependencies: 9258 + '@algolia/client-search': 4.20.0 9245 9259 9246 9260 '@algolia/autocomplete-shared@1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0)': 9247 9261 dependencies: 9248 - '@algolia/client-search': 4.20.0 9249 9262 algoliasearch: 4.20.0 9263 + optionalDependencies: 9264 + '@algolia/client-search': 4.20.0 9250 9265 9251 9266 '@algolia/cache-browser-local-storage@4.20.0': 9252 9267 dependencies: ··· 15601 15616 mdn-data@2.0.30: {} 15602 15617 15603 15618 media-typer@0.3.0: {} 15619 + 15620 + memfs@4.8.2: 15621 + dependencies: 15622 + tslib: 2.6.2 15604 15623 15605 15624 merge-anything@5.1.7: 15606 15625 dependencies:
+5 -5
docs/guide/mocking.md
··· 383 383 ::: 384 384 385 385 ```ts 386 - // hello-world.js 386 + // read-hello-world.js 387 387 import { readFileSync } from 'node:fs' 388 388 389 389 export function readHelloWorld(path) { 390 - return readFileSync('./hello-world.txt') 390 + return readFileSync(path) 391 391 } 392 392 ``` 393 393 ··· 395 395 // hello-world.test.js 396 396 import { beforeEach, expect, it, vi } from 'vitest' 397 397 import { fs, vol } from 'memfs' 398 - import { readHelloWorld } from './hello-world.js' 398 + import { readHelloWorld } from './read-hello-world.js' 399 399 400 400 // tell vitest to use fs mock from __mocks__ folder 401 401 // this can be done in a setup file if fs should always be mocked ··· 408 408 }) 409 409 410 410 it('should return correct text', () => { 411 - const path = './hello-world.txt' 411 + const path = '/hello-world.txt' 412 412 fs.writeFileSync(path, 'hello world') 413 413 414 414 const text = readHelloWorld(path) ··· 423 423 './dir2/hw.txt': 'hello dir2', 424 424 }, 425 425 // default cwd 426 - '/tmp' 426 + '/tmp', 427 427 ) 428 428 429 429 expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1')
+1
test/core/package.json
··· 23 23 "axios": "^0.26.1", 24 24 "debug": "^4.3.4", 25 25 "immutable": "5.0.0-beta.5", 26 + "memfs": "^4.8.2", 26 27 "strip-ansi": "^7.1.0", 27 28 "sweetalert2": "^11.6.16", 28 29 "tinyrainbow": "^1.2.0",
+6
test/core/__mocks__/fs.cjs
··· 1 + // we can also use `import`, but then 2 + // every export should be explicitly defined 3 + 4 + const { fs } = require('memfs') 5 + 6 + module.exports = fs
+6
test/core/src/read-hello-world.ts
··· 1 + // hello-world.js 2 + import { readFileSync } from 'node:fs' 3 + 4 + export function readHelloWorld(path: string) { 5 + return readFileSync(path, 'utf-8') 6 + }
+5 -1
test/core/test/file-path.test.ts
··· 2 2 import { describe, expect, it, vi } from 'vitest' 3 3 import { isWindows, slash, toFilePath } from '../../../packages/vite-node/src/utils' 4 4 5 - vi.mock('fs') 5 + vi.mock('fs', () => { 6 + return { 7 + existsSync: vi.fn(), 8 + } 9 + }) 6 10 7 11 describe('current url', () => { 8 12 it('__filename is equal to import.meta.url', () => {
+37
test/core/test/mock-fs.test.ts
··· 1 + // hello-world.test.js 2 + import { beforeEach, expect, it, vi } from 'vitest' 3 + import { fs, vol } from 'memfs' 4 + import { readHelloWorld } from '../src/read-hello-world' 5 + 6 + // tell vitest to use fs mock from __mocks__ folder 7 + // this can be done in a setup file if fs should always be mocked 8 + vi.mock('node:fs') 9 + vi.mock('node:fs/promises') 10 + 11 + beforeEach(() => { 12 + // reset the state of in-memory fs 13 + vol.reset() 14 + }) 15 + 16 + it('should return correct text', () => { 17 + const path = '/hello-world.txt' 18 + fs.writeFileSync(path, 'hello world') 19 + 20 + const text = readHelloWorld(path) 21 + expect(text).toBe('hello world') 22 + }) 23 + 24 + it('can return a value multiple times', () => { 25 + // you can use vol.fromJSON to define several files 26 + vol.fromJSON( 27 + { 28 + './dir1/hw.txt': 'hello dir1', 29 + './dir2/hw.txt': 'hello dir2', 30 + }, 31 + // default cwd 32 + '/tmp', 33 + ) 34 + 35 + expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1') 36 + expect(readHelloWorld('/tmp/dir2/hw.txt')).toBe('hello dir2') 37 + })
+22 -8
packages/vitest/src/runtime/mocker.ts
··· 188 188 return { 189 189 id, 190 190 fsPath, 191 - external, 191 + external: external ? this.normalizePath(external) : external, 192 192 } 193 193 } 194 194 ··· 315 315 const files = readdirSync(mockFolder) 316 316 const baseOriginal = basename(path) 317 317 318 - for (const file of files) { 319 - const baseFile = basename(file, extname(file)) 320 - if (baseFile === baseOriginal) { 321 - return resolve(mockFolder, file) 318 + function findFile(files: string[], baseOriginal: string): string | null { 319 + for (const file of files) { 320 + const baseFile = basename(file, extname(file)) 321 + if (baseFile === baseOriginal) { 322 + const path = resolve(mockFolder, file) 323 + // if the same name, return the file 324 + if (fs.statSync(path).isFile()) { 325 + return path 326 + } 327 + else { 328 + // find folder/index.{js,ts} 329 + const indexFile = findFile(readdirSync(path), 'index') 330 + if (indexFile) { 331 + return indexFile 332 + } 333 + } 334 + } 322 335 } 336 + return null 323 337 } 324 338 325 - return null 339 + return findFile(files, baseOriginal) 326 340 } 327 341 328 342 const dir = dirname(path) ··· 517 531 const mocks = this.mockMap.get(suitefile) || {} 518 532 const resolves = this.resolveCache.get(suitefile) || {} 519 533 520 - mocks[id] = factory || this.resolveMockPath(path, external) 534 + mocks[id] = factory || this.resolveMockPath(id, external) 521 535 resolves[id] = originalId 522 536 523 537 this.mockMap.set(suitefile, mocks) ··· 546 560 let mock = this.getDependencyMock(normalizedId) 547 561 548 562 if (mock === undefined) { 549 - mock = this.resolveMockPath(fsPath, external) 563 + mock = this.resolveMockPath(normalizedId, external) 550 564 } 551 565 552 566 if (mock === null) {
+6
test/core/__mocks__/fs/promises.cjs
··· 1 + // we can also use `import`, but then 2 + // every export should be explicitly defined 3 + 4 + const { fs } = require('memfs') 5 + 6 + module.exports = fs.promises