From 688d82754bc494777d59f0e8ff6145d7360e8443 Mon Sep 17 00:00:00 2001 From: neverland Date: Fri, 31 Jul 2026 17:11:01 +0800 Subject: [PATCH 1/3] test(staged): cover rs fmt integration --- packages/rstack/tests/cli/staged/fmt.test.ts | 108 +++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 packages/rstack/tests/cli/staged/fmt.test.ts diff --git a/packages/rstack/tests/cli/staged/fmt.test.ts b/packages/rstack/tests/cli/staged/fmt.test.ts new file mode 100644 index 0000000..8dc61ee --- /dev/null +++ b/packages/rstack/tests/cli/staged/fmt.test.ts @@ -0,0 +1,108 @@ +import { spawnSync } from 'node:child_process'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { afterEach, beforeEach, expect, test } from 'rstack/test'; +import { RSTACK_BIN_PATH } from '#test-helpers'; + +let projectPath: string; +let env: NodeJS.ProcessEnv; + +const writeProjectFile = (filePath: string, content: string): void => { + const absolutePath = path.join(projectPath, filePath); + mkdirSync(path.dirname(absolutePath), { recursive: true }); + writeFileSync(absolutePath, content); +}; + +const readProjectFile = (filePath: string): string => + readFileSync(path.join(projectPath, filePath), 'utf8'); + +const git = (args: string[]): string => { + const result = spawnSync('git', args, { + cwd: projectPath, + encoding: 'utf8', + env, + }); + + if (result.status !== 0) { + throw new Error(result.stderr || `Git exited with status ${result.status}.`); + } + + return result.stdout; +}; + +const runStaged = () => + spawnSync(process.execPath, [RSTACK_BIN_PATH, 'staged', '--no-stash'], { + cwd: projectPath, + encoding: 'utf8', + env, + }); + +beforeEach(() => { + projectPath = mkdtempSync(path.join(import.meta.dirname, 'staged-fmt-project-')); + env = { + ...process.env, + GIT_CONFIG_GLOBAL: path.join(projectPath, 'global.gitconfig'), + GIT_CONFIG_NOSYSTEM: '1', + NO_COLOR: '1', + }; + delete env.FORCE_COLOR; + + git(['init', '--quiet']); +}); + +afterEach(() => { + rmSync(projectPath, { force: true, recursive: true }); +}); + +test('formats staged files with rs fmt and applies ignore rules', () => { + writeProjectFile( + 'rstack.config.ts', + `import { define } from 'rstack'; + +define.fmt({ + ignorePatterns: ['ignored-by-fmt.ts'], +}); + +define.staged({ + '*': 'rs fmt', +}); +`, + ); + writeProjectFile('.gitignore', 'ignored-by-git.ts\n'); + writeProjectFile('file with spaces.ts', 'const spaced="spaced"'); + writeProjectFile('ignored-by-git.ts', 'const gitIgnored="git ignored"'); + writeProjectFile('ignored-by-fmt.ts', 'const fmtIgnored="fmt ignored"'); + + git(['add', '--', 'file with spaces.ts', 'ignored-by-fmt.ts']); + git(['add', '--force', '--', 'ignored-by-git.ts']); + + const result = runStaged(); + + expect(result.status).toBe(0); + expect(readProjectFile('file with spaces.ts')).toBe('const spaced = "spaced";\n'); + expect(readProjectFile('ignored-by-git.ts')).toBe('const gitIgnored = "git ignored";\n'); + expect(readProjectFile('ignored-by-fmt.ts')).toBe('const fmtIgnored="fmt ignored"'); + expect(git(['show', ':file with spaces.ts'])).toBe('const spaced = "spaced";\n'); + expect(git(['show', ':ignored-by-git.ts'])).toBe('const gitIgnored = "git ignored";\n'); + expect(git(['show', ':ignored-by-fmt.ts'])).toBe('const fmtIgnored="fmt ignored"'); +}); + +test('propagates rs fmt failures', () => { + writeProjectFile( + 'rstack.config.ts', + `import { define } from 'rstack'; + +define.staged({ + '*': 'rs fmt', +}); +`, + ); + writeProjectFile('invalid.ts', 'const value = ;'); + git(['add', '--', 'invalid.ts']); + + const result = runStaged(); + + expect(result.status).toBe(1); + expect(`${result.stdout}\n${result.stderr}`).toContain('SyntaxError'); + expect(readProjectFile('invalid.ts')).toBe('const value = ;'); +}); From de264ebd71be458960343b29f9faafdf8060ae61 Mon Sep 17 00:00:00 2001 From: neverland Date: Fri, 31 Jul 2026 17:15:43 +0800 Subject: [PATCH 2/3] test(staged): remove redundant color cleanup --- packages/rstack/tests/cli/staged/fmt.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/rstack/tests/cli/staged/fmt.test.ts b/packages/rstack/tests/cli/staged/fmt.test.ts index 8dc61ee..5410ea1 100644 --- a/packages/rstack/tests/cli/staged/fmt.test.ts +++ b/packages/rstack/tests/cli/staged/fmt.test.ts @@ -45,7 +45,6 @@ beforeEach(() => { GIT_CONFIG_NOSYSTEM: '1', NO_COLOR: '1', }; - delete env.FORCE_COLOR; git(['init', '--quiet']); }); From 48ef6e290c46dbf08b44287e3a640cdc3117965c Mon Sep 17 00:00:00 2001 From: neverland Date: Fri, 31 Jul 2026 17:17:42 +0800 Subject: [PATCH 3/3] test(staged): simplify fmt fixture setup --- packages/rstack/tests/cli/staged/fmt.test.ts | 34 ++++++-------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/packages/rstack/tests/cli/staged/fmt.test.ts b/packages/rstack/tests/cli/staged/fmt.test.ts index 5410ea1..1ce8fa1 100644 --- a/packages/rstack/tests/cli/staged/fmt.test.ts +++ b/packages/rstack/tests/cli/staged/fmt.test.ts @@ -1,5 +1,5 @@ import { spawnSync } from 'node:child_process'; -import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import { afterEach, beforeEach, expect, test } from 'rstack/test'; import { RSTACK_BIN_PATH } from '#test-helpers'; @@ -7,11 +7,8 @@ import { RSTACK_BIN_PATH } from '#test-helpers'; let projectPath: string; let env: NodeJS.ProcessEnv; -const writeProjectFile = (filePath: string, content: string): void => { - const absolutePath = path.join(projectPath, filePath); - mkdirSync(path.dirname(absolutePath), { recursive: true }); - writeFileSync(absolutePath, content); -}; +const writeProjectFile = (filePath: string, content: string): void => + writeFileSync(path.join(projectPath, filePath), content); const readProjectFile = (filePath: string): string => readFileSync(path.join(projectPath, filePath), 'utf8'); @@ -43,17 +40,9 @@ beforeEach(() => { ...process.env, GIT_CONFIG_GLOBAL: path.join(projectPath, 'global.gitconfig'), GIT_CONFIG_NOSYSTEM: '1', - NO_COLOR: '1', }; git(['init', '--quiet']); -}); - -afterEach(() => { - rmSync(projectPath, { force: true, recursive: true }); -}); - -test('formats staged files with rs fmt and applies ignore rules', () => { writeProjectFile( 'rstack.config.ts', `import { define } from 'rstack'; @@ -67,6 +56,13 @@ define.staged({ }); `, ); +}); + +afterEach(() => { + rmSync(projectPath, { force: true, recursive: true }); +}); + +test('formats staged files with rs fmt and applies ignore rules', () => { writeProjectFile('.gitignore', 'ignored-by-git.ts\n'); writeProjectFile('file with spaces.ts', 'const spaced="spaced"'); writeProjectFile('ignored-by-git.ts', 'const gitIgnored="git ignored"'); @@ -83,19 +79,9 @@ define.staged({ expect(readProjectFile('ignored-by-fmt.ts')).toBe('const fmtIgnored="fmt ignored"'); expect(git(['show', ':file with spaces.ts'])).toBe('const spaced = "spaced";\n'); expect(git(['show', ':ignored-by-git.ts'])).toBe('const gitIgnored = "git ignored";\n'); - expect(git(['show', ':ignored-by-fmt.ts'])).toBe('const fmtIgnored="fmt ignored"'); }); test('propagates rs fmt failures', () => { - writeProjectFile( - 'rstack.config.ts', - `import { define } from 'rstack'; - -define.staged({ - '*': 'rs fmt', -}); -`, - ); writeProjectFile('invalid.ts', 'const value = ;'); git(['add', '--', 'invalid.ts']);