From b042b3965f7ba1fb26a32db844dc8ecef6d0e303 Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Wed, 11 Feb 2026 08:58:54 +0800 Subject: [PATCH 1/5] refactor: re-export from VSCodeMock # Conflicts: # tests/__mocks__/vscode.ts # tests/utils/resolve.test.ts --- tests/__mocks__/vscode.ts | 38 ++++++++++++++++++---------- tests/{ => utils}/filesystem.test.ts | 2 +- tests/{ => utils}/memoize.test.ts | 2 +- tests/{ => utils}/package.test.ts | 2 +- tests/{ => utils}/resolve.test.ts | 4 +-- tests/{ => utils}/version.test.ts | 2 +- 6 files changed, 30 insertions(+), 20 deletions(-) rename tests/{ => utils}/filesystem.test.ts (95%) rename tests/{ => utils}/memoize.test.ts (98%) rename tests/{ => utils}/package.test.ts (84%) rename tests/{ => utils}/resolve.test.ts (94%) rename tests/{ => utils}/version.test.ts (97%) diff --git a/tests/__mocks__/vscode.ts b/tests/__mocks__/vscode.ts index da24b46..5c746b6 100644 --- a/tests/__mocks__/vscode.ts +++ b/tests/__mocks__/vscode.ts @@ -3,18 +3,28 @@ import { vi } from 'vitest' const vscode = createVSCodeMock(vi) -export const Uri = vscode.Uri -export const workspace = vscode.workspace -export const Range = vscode.Range -export const Position = vscode.Position -export const Location = vscode.Location -export const Selection = vscode.Selection -export const CodeAction = vscode.CodeAction -export const CodeActionKind = vscode.CodeActionKind -export const WorkspaceEdit = vscode.WorkspaceEdit -export const ThemeColor = vscode.ThemeColor -export const ThemeIcon = vscode.ThemeIcon -export const TreeItem = vscode.TreeItem -export const TreeItemCollapsibleState = vscode.TreeItemCollapsibleState -export const Disposable = vscode.Disposable +export const { + Uri, + workspace, + Range, + Position, + Location, + Selection, + ThemeColor, + ThemeIcon, + TreeItem, + TreeItemCollapsibleState, + Disposable, + MarkdownString, + CompletionItem, + CompletionItemKind, + CodeAction, + CodeActionKind, + WorkspaceEdit, + DiagnosticSeverity, + DiagnosticTag, + window, + languages, +} = vscode + export default vscode diff --git a/tests/filesystem.test.ts b/tests/utils/filesystem.test.ts similarity index 95% rename from tests/filesystem.test.ts rename to tests/utils/filesystem.test.ts index 323fb77..ce5c58f 100644 --- a/tests/filesystem.test.ts +++ b/tests/utils/filesystem.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { Uri, workspace } from 'vscode' -import { mockFileSystem } from './__mocks__/filesystem' +import { mockFileSystem } from '../__mocks__/filesystem' describe('mockFileSystem', () => { beforeEach(() => { diff --git a/tests/memoize.test.ts b/tests/utils/memoize.test.ts similarity index 98% rename from tests/memoize.test.ts rename to tests/utils/memoize.test.ts index e4ebc2f..a6cc89d 100644 --- a/tests/memoize.test.ts +++ b/tests/utils/memoize.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi } from 'vitest' -import { memoize } from '../src/utils/memoize' +import { memoize } from '../../src/utils/memoize' describe('memoize', () => { it('should cache sync function result', () => { diff --git a/tests/package.test.ts b/tests/utils/package.test.ts similarity index 84% rename from tests/package.test.ts rename to tests/utils/package.test.ts index e3ab59d..31fc969 100644 --- a/tests/package.test.ts +++ b/tests/utils/package.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { encodePackageName } from '../src/utils/package' +import { encodePackageName } from '../../src/utils/package' describe('encodePackageName', () => { it('should encode regular package name', () => { diff --git a/tests/resolve.test.ts b/tests/utils/resolve.test.ts similarity index 94% rename from tests/resolve.test.ts rename to tests/utils/resolve.test.ts index b73f8fc..f73a68f 100644 --- a/tests/resolve.test.ts +++ b/tests/utils/resolve.test.ts @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { Uri } from 'vscode' -import { findNearestFile, walkAncestors } from '../src/utils/resolve' -import { mockFileSystem } from './__mocks__/filesystem' +import { resolvePackageRelativePath } from '../../src/utils/resolve' +import { mockFileSystem } from '../__mocks__/filesystem' describe('walkAncestors', () => { it('should yield all ancestor directories', () => { diff --git a/tests/version.test.ts b/tests/utils/version.test.ts similarity index 97% rename from tests/version.test.ts rename to tests/utils/version.test.ts index 4f26a5c..0522063 100644 --- a/tests/version.test.ts +++ b/tests/utils/version.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { getPrereleaseId, lt, parseVersion } from '../src/utils/version' +import { getPrereleaseId, lt, parseVersion } from '../../src/utils/version' describe('parseVersion', () => { it('should parse plain version', () => { From aee5dc061ad7c8920d9213053f19890f72ebf8bc Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Wed, 18 Feb 2026 13:58:24 +0800 Subject: [PATCH 2/5] chore: update --- tests/utils/resolve.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/utils/resolve.test.ts b/tests/utils/resolve.test.ts index f73a68f..1971233 100644 --- a/tests/utils/resolve.test.ts +++ b/tests/utils/resolve.test.ts @@ -1,6 +1,6 @@ +import { findNearestFile, walkAncestors } from '#utils/resolve' import { beforeEach, describe, expect, it, vi } from 'vitest' import { Uri } from 'vscode' -import { resolvePackageRelativePath } from '../../src/utils/resolve' import { mockFileSystem } from '../__mocks__/filesystem' describe('walkAncestors', () => { From f89f2b6b86677f04c8fd10e0afac17c0f759d9e7 Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Wed, 18 Feb 2026 14:16:00 +0800 Subject: [PATCH 3/5] test: use real filesystem instead of custom mock --- tests/__mocks__/filesystem.ts | 35 ---------------------------- tests/utils/filesystem.test.ts | 42 ---------------------------------- tests/utils/resolve.test.ts | 37 ++++++++---------------------- 3 files changed, 10 insertions(+), 104 deletions(-) delete mode 100644 tests/__mocks__/filesystem.ts delete mode 100644 tests/utils/filesystem.test.ts diff --git a/tests/__mocks__/filesystem.ts b/tests/__mocks__/filesystem.ts deleted file mode 100644 index c8f6b63..0000000 --- a/tests/__mocks__/filesystem.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { expect, vi } from 'vitest' -import { workspace } from 'vscode' - -/** - * Mocks the VS Code filesystem by intercepting {@link workspace.fs}. - * - * @param files A record mapping file paths to their string content. - */ -export function mockFileSystem(files: Record) { - // Make all functions throw by default. - for (const [name, fn] of Object.entries(workspace.fs)) { - if (typeof fn === 'function') { - vi.mocked(fn).mockImplementation(() => { - expect.fail(`\`workspace.fs.${name}\` is not supported as a fake.`) - }) - } - } - - vi.mocked(workspace.fs.stat).mockImplementation(async (uri) => { - const path = uri.path - if (files[path] === undefined) { - throw new Error(`File not found: ${uri.toString()}`) - } - return {} as any - }) - - vi.mocked(workspace.fs.readFile).mockImplementation(async (uri) => { - const path = uri.path - const content = files[path] - if (content === undefined) { - throw new Error(`File not found: ${uri.toString()}`) - } - return new TextEncoder().encode(content) - }) -} diff --git a/tests/utils/filesystem.test.ts b/tests/utils/filesystem.test.ts deleted file mode 100644 index ce5c58f..0000000 --- a/tests/utils/filesystem.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest' -import { Uri, workspace } from 'vscode' -import { mockFileSystem } from '../__mocks__/filesystem' - -describe('mockFileSystem', () => { - beforeEach(() => { - vi.resetAllMocks() - }) - - describe('`readFile`', () => { - it('should mock matched paths', async () => { - mockFileSystem({ - '/test/file.txt': 'hello world', - }) - - const uri = Uri.file('/test/file.txt') - const content = await workspace.fs.readFile(uri) - - expect(new TextDecoder().decode(content)).toBe('hello world') - }) - - it('should throw error for unmatched paths', async () => { - mockFileSystem({}) - - const uri = Uri.file('/does-not-exist.txt') - await expect(workspace.fs.readFile(uri)).rejects.toThrow('File not found') - }) - - it('should handle multiple files', async () => { - mockFileSystem({ - '/a.js': 'content a', - '/b.js': 'content b', - }) - - const contentA = await workspace.fs.readFile(Uri.file('/a.js')) - const contentB = await workspace.fs.readFile(Uri.file('/b.js')) - - expect(new TextDecoder().decode(contentA)).toBe('content a') - expect(new TextDecoder().decode(contentB)).toBe('content b') - }) - }) -}) diff --git a/tests/utils/resolve.test.ts b/tests/utils/resolve.test.ts index 1971233..f789ab9 100644 --- a/tests/utils/resolve.test.ts +++ b/tests/utils/resolve.test.ts @@ -1,7 +1,9 @@ +import path from 'node:path' import { findNearestFile, walkAncestors } from '#utils/resolve' -import { beforeEach, describe, expect, it, vi } from 'vitest' +import { describe, expect, it } from 'vitest' import { Uri } from 'vscode' -import { mockFileSystem } from '../__mocks__/filesystem' + +const root = process.cwd() describe('walkAncestors', () => { it('should yield all ancestor directories', () => { @@ -34,44 +36,25 @@ describe('walkAncestors', () => { }) describe('findNearestFile', () => { - beforeEach(() => { - vi.resetAllMocks() - }) - it('should find a file in a parent directory', async () => { - mockFileSystem({ - '/a/b/target.txt': '', - }) - - const result = await findNearestFile('target.txt', Uri.file('/a/b/c/d')) + const result = await findNearestFile('package.json', Uri.file(path.join(root, 'src/utils'))) expect(result).toBeDefined() - expect(result!.path).toBe('/a/b/target.txt') + expect(result!.fsPath).toBe(path.join(root, 'package.json')) }) it('should return the closest match', async () => { - mockFileSystem({ - '/a/target.txt': '', - '/a/b/c/target.txt': '', - }) - - const result = await findNearestFile('target.txt', Uri.file('/a/b/c/d')) + const result = await findNearestFile('package.json', Uri.file(path.join(root, 'playground'))) expect(result).toBeDefined() - expect(result!.path).toBe('/a/b/c/target.txt') + expect(result!.fsPath).toBe(path.join(root, 'playground/package.json')) }) it('should return undefined when file is not found', async () => { - mockFileSystem({}) - - const result = await findNearestFile('target.txt', Uri.file('/a/b/c')) + const result = await findNearestFile('__nonexistent_file__', Uri.file(path.join(root, 'src'))) expect(result).toBeUndefined() }) it('should respect shouldStop', async () => { - mockFileSystem({ - '/a/target.txt': '', - }) - - const result = await findNearestFile('target.txt', Uri.file('/a/b/c'), (u) => u.path === '/a/b') + const result = await findNearestFile('package.json', Uri.file(path.join(root, 'src/utils')), (u) => u.fsPath === path.join(root, 'src')) expect(result).toBeUndefined() }) }) From 5a76adc26d534b494181900e5243f2c93cb0faa5 Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Wed, 18 Feb 2026 14:27:48 +0800 Subject: [PATCH 4/5] ci: try fix test in windows --- tests/utils/resolve.test.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/utils/resolve.test.ts b/tests/utils/resolve.test.ts index f789ab9..8d27ede 100644 --- a/tests/utils/resolve.test.ts +++ b/tests/utils/resolve.test.ts @@ -1,9 +1,8 @@ -import path from 'node:path' import { findNearestFile, walkAncestors } from '#utils/resolve' import { describe, expect, it } from 'vitest' import { Uri } from 'vscode' -const root = process.cwd() +const root = Uri.file(process.cwd()) describe('walkAncestors', () => { it('should yield all ancestor directories', () => { @@ -37,24 +36,25 @@ describe('walkAncestors', () => { describe('findNearestFile', () => { it('should find a file in a parent directory', async () => { - const result = await findNearestFile('package.json', Uri.file(path.join(root, 'src/utils'))) + const result = await findNearestFile('package.json', Uri.joinPath(root, 'src/utils')) expect(result).toBeDefined() - expect(result!.fsPath).toBe(path.join(root, 'package.json')) + expect(result!.fsPath).toBe(Uri.joinPath(root, 'package.json').fsPath) }) it('should return the closest match', async () => { - const result = await findNearestFile('package.json', Uri.file(path.join(root, 'playground'))) + const result = await findNearestFile('package.json', Uri.joinPath(root, 'playground')) expect(result).toBeDefined() - expect(result!.fsPath).toBe(path.join(root, 'playground/package.json')) + expect(result!.fsPath).toBe(Uri.joinPath(root, 'playground/package.json').fsPath) }) it('should return undefined when file is not found', async () => { - const result = await findNearestFile('__nonexistent_file__', Uri.file(path.join(root, 'src'))) + const result = await findNearestFile('__nonexistent_file__', Uri.joinPath(root, 'src')) expect(result).toBeUndefined() }) it('should respect shouldStop', async () => { - const result = await findNearestFile('package.json', Uri.file(path.join(root, 'src/utils')), (u) => u.fsPath === path.join(root, 'src')) + const stop = Uri.joinPath(root, 'src') + const result = await findNearestFile('package.json', Uri.joinPath(root, 'src/utils'), (u) => u.fsPath === stop.fsPath) expect(result).toBeUndefined() }) }) From 38fa767eb984d8d0bb9e6c68e55fdc09becf728c Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Wed, 18 Feb 2026 14:47:18 +0800 Subject: [PATCH 5/5] chore: update --- tests/utils/resolve.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/utils/resolve.test.ts b/tests/utils/resolve.test.ts index 8d27ede..203582e 100644 --- a/tests/utils/resolve.test.ts +++ b/tests/utils/resolve.test.ts @@ -1,6 +1,6 @@ -import { findNearestFile, walkAncestors } from '#utils/resolve' import { describe, expect, it } from 'vitest' import { Uri } from 'vscode' +import { findNearestFile, walkAncestors } from '../../src/utils/resolve' const root = Uri.file(process.cwd())