From 338d9893f54ccc237c35cb74951f68207de721f6 Mon Sep 17 00:00:00 2001 From: neverland Date: Thu, 8 Oct 2026 18:41:50 +0800 Subject: [PATCH 1/5] test(config): cover shared config session isolation and check reuse --- packages/rstack/tests/cli/check.test.ts | 21 +++++++++++++++---- .../tests/config/load-config/index.test.ts | 3 +++ .../load-config/parallel-failing.config.ts | 2 ++ .../load-config/parallel-first.config.ts | 2 ++ .../load-config/parallel-second.config.ts | 2 ++ 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/rstack/tests/cli/check.test.ts b/packages/rstack/tests/cli/check.test.ts index a23019f0..6463f68c 100644 --- a/packages/rstack/tests/cli/check.test.ts +++ b/packages/rstack/tests/cli/check.test.ts @@ -10,10 +10,23 @@ const writeLintConfig = (): void => { 'rstack.config.ts', `import { define } from "rstack"; -define.lint([ +if (process.env.RSTACK_CHECK_CONFIG_LOADED) { + throw new Error("Config was loaded twice"); +} +process.env.RSTACK_CHECK_CONFIG_LOADED = "1"; + +define.extends([ { - files: ["**/*.{js,ts}"], - rules: { "no-debugger": "error" }, + app: () => { + throw new Error("App config must not run during check"); + }, + lint: [ + { + files: ["**/*.{js,ts}"], + rules: { "no-debugger": "error" }, + }, + ], + fmt: { singleQuote: false }, }, ]); `, @@ -28,7 +41,7 @@ test('displays check help without loading config', () => { expect(normalizeHelpOutput(result.stdout)).toMatchSnapshot(); }); -test('runs lint followed by a formatting check', () => { +test('loads shared config once for lint and formatting without resolving app', () => { writeLintConfig(); writeProjectFile('src/index.ts', 'const value=true'); diff --git a/packages/rstack/tests/config/load-config/index.test.ts b/packages/rstack/tests/config/load-config/index.test.ts index b6ec8f01..d54fd601 100644 --- a/packages/rstack/tests/config/load-config/index.test.ts +++ b/packages/rstack/tests/config/load-config/index.test.ts @@ -88,10 +88,12 @@ test('should isolate parallel config sessions across top-level await', async () expect(firstResult.configs).toEqual({ app: { root: 'first' }, + fmt: { semi: false }, test: {}, }); expect(secondResult.configs).toEqual({ app: { root: 'second' }, + fmt: { semi: true }, lib: {}, }); }); @@ -108,6 +110,7 @@ test('should keep a running session intact when another config fails', async () expect((await successfulLoad).configs).toEqual({ app: { root: 'first' }, + fmt: { semi: false }, test: {}, }); }); diff --git a/packages/rstack/tests/config/load-config/parallel-failing.config.ts b/packages/rstack/tests/config/load-config/parallel-failing.config.ts index 75b06414..d847b0fe 100644 --- a/packages/rstack/tests/config/load-config/parallel-failing.config.ts +++ b/packages/rstack/tests/config/load-config/parallel-failing.config.ts @@ -1,4 +1,6 @@ import { define } from 'rstack'; +define.extends([{ fmt: { semi: true } }]); + define.app({ root: 'failing' }); throw new Error('parallel config error'); diff --git a/packages/rstack/tests/config/load-config/parallel-first.config.ts b/packages/rstack/tests/config/load-config/parallel-first.config.ts index 4d68eed0..bc25363d 100644 --- a/packages/rstack/tests/config/load-config/parallel-first.config.ts +++ b/packages/rstack/tests/config/load-config/parallel-first.config.ts @@ -1,5 +1,7 @@ import { define } from 'rstack'; +define.extends([{ fmt: { semi: false } }]); + const hooks = globalThis.__rstackConfigTestHooks!; define.app({ root: 'first' }); diff --git a/packages/rstack/tests/config/load-config/parallel-second.config.ts b/packages/rstack/tests/config/load-config/parallel-second.config.ts index f5d6bcb7..2b8bd79d 100644 --- a/packages/rstack/tests/config/load-config/parallel-second.config.ts +++ b/packages/rstack/tests/config/load-config/parallel-second.config.ts @@ -1,4 +1,6 @@ import { define } from 'rstack'; +define.extends([{ fmt: { semi: true } }]); + define.app({ root: 'second' }); define.lib({}); From a7696463e56353acdf99618b06fb6072e9cee1fa Mon Sep 17 00:00:00 2001 From: neverland Date: Thu, 8 Oct 2026 20:57:29 +0800 Subject: [PATCH 2/5] test(config): expand nested config objects for readability --- .../tests/config/load-config/parallel-failing.config.ts | 6 +++++- .../tests/config/load-config/parallel-first.config.ts | 6 +++++- .../tests/config/load-config/parallel-second.config.ts | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/rstack/tests/config/load-config/parallel-failing.config.ts b/packages/rstack/tests/config/load-config/parallel-failing.config.ts index d847b0fe..4f4df7b5 100644 --- a/packages/rstack/tests/config/load-config/parallel-failing.config.ts +++ b/packages/rstack/tests/config/load-config/parallel-failing.config.ts @@ -1,6 +1,10 @@ import { define } from 'rstack'; -define.extends([{ fmt: { semi: true } }]); +define.extends([ + { + fmt: { semi: true }, + }, +]); define.app({ root: 'failing' }); throw new Error('parallel config error'); diff --git a/packages/rstack/tests/config/load-config/parallel-first.config.ts b/packages/rstack/tests/config/load-config/parallel-first.config.ts index bc25363d..bf466967 100644 --- a/packages/rstack/tests/config/load-config/parallel-first.config.ts +++ b/packages/rstack/tests/config/load-config/parallel-first.config.ts @@ -1,6 +1,10 @@ import { define } from 'rstack'; -define.extends([{ fmt: { semi: false } }]); +define.extends([ + { + fmt: { semi: false }, + }, +]); const hooks = globalThis.__rstackConfigTestHooks!; diff --git a/packages/rstack/tests/config/load-config/parallel-second.config.ts b/packages/rstack/tests/config/load-config/parallel-second.config.ts index 2b8bd79d..4ba6bc3a 100644 --- a/packages/rstack/tests/config/load-config/parallel-second.config.ts +++ b/packages/rstack/tests/config/load-config/parallel-second.config.ts @@ -1,6 +1,10 @@ import { define } from 'rstack'; -define.extends([{ fmt: { semi: true } }]); +define.extends([ + { + fmt: { semi: true }, + }, +]); define.app({ root: 'second' }); define.lib({}); From ba393dddc26975d009ea1e9e633fb0be2b1a8240 Mon Sep 17 00:00:00 2001 From: neverland Date: Fri, 9 Oct 2026 10:28:01 +0800 Subject: [PATCH 3/5] test(config): verify inherited formatting changes string quotes --- packages/rstack/tests/cli/check.test.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/rstack/tests/cli/check.test.ts b/packages/rstack/tests/cli/check.test.ts index 6463f68c..d3717fac 100644 --- a/packages/rstack/tests/cli/check.test.ts +++ b/packages/rstack/tests/cli/check.test.ts @@ -8,25 +8,25 @@ const runCheck = (args: string[] = []) => runCLI(['check', ...args]); const writeLintConfig = (): void => { writeProjectFile( 'rstack.config.ts', - `import { define } from "rstack"; + `import { define } from 'rstack'; if (process.env.RSTACK_CHECK_CONFIG_LOADED) { - throw new Error("Config was loaded twice"); + throw new Error('Config was loaded twice'); } -process.env.RSTACK_CHECK_CONFIG_LOADED = "1"; +process.env.RSTACK_CHECK_CONFIG_LOADED = '1'; define.extends([ { app: () => { - throw new Error("App config must not run during check"); + throw new Error('App config must not run during check'); }, lint: [ { - files: ["**/*.{js,ts}"], - rules: { "no-debugger": "error" }, + files: ['**/*.{js,ts}'], + rules: { 'no-debugger': 'error' }, }, ], - fmt: { singleQuote: false }, + fmt: { singleQuote: true }, }, ]); `, @@ -43,7 +43,7 @@ test('displays check help without loading config', () => { test('loads shared config once for lint and formatting without resolving app', () => { writeLintConfig(); - writeProjectFile('src/index.ts', 'const value=true'); + writeProjectFile('src/index.ts', 'const value = "hello";\n'); const unformatted = runCheck(); @@ -52,9 +52,9 @@ test('loads shared config once for lint and formatting without resolving app', ( expect(unformatted.stderr).toContain( 'Formatting issues found in 1 file. Rerun this command with --fix to fix.', ); - expect(readProjectFile('src/index.ts')).toBe('const value=true'); + expect(readProjectFile('src/index.ts')).toBe('const value = "hello";\n'); - writeProjectFile('src/index.ts', 'const value = true;\n'); + writeProjectFile('src/index.ts', "const value = 'hello';\n"); const formatted = runCheck(); expect(formatted.status).toBe(0); From 9c5b87334247c17939e730cf131fdb730b48690b Mon Sep 17 00:00:00 2001 From: neverland Date: Fri, 9 Oct 2026 10:35:06 +0800 Subject: [PATCH 4/5] test(config): isolate shared config check coverage --- packages/rstack/tests/cli/check.test.ts | 69 +++++++++++++++++-------- 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/packages/rstack/tests/cli/check.test.ts b/packages/rstack/tests/cli/check.test.ts index d3717fac..bfc544e3 100644 --- a/packages/rstack/tests/cli/check.test.ts +++ b/packages/rstack/tests/cli/check.test.ts @@ -8,25 +8,12 @@ const runCheck = (args: string[] = []) => runCLI(['check', ...args]); const writeLintConfig = (): void => { writeProjectFile( 'rstack.config.ts', - `import { define } from 'rstack'; - -if (process.env.RSTACK_CHECK_CONFIG_LOADED) { - throw new Error('Config was loaded twice'); -} -process.env.RSTACK_CHECK_CONFIG_LOADED = '1'; + `import { define } from "rstack"; -define.extends([ +define.lint([ { - app: () => { - throw new Error('App config must not run during check'); - }, - lint: [ - { - files: ['**/*.{js,ts}'], - rules: { 'no-debugger': 'error' }, - }, - ], - fmt: { singleQuote: true }, + files: ["**/*.{js,ts}"], + rules: { "no-debugger": "error" }, }, ]); `, @@ -41,9 +28,9 @@ test('displays check help without loading config', () => { expect(normalizeHelpOutput(result.stdout)).toMatchSnapshot(); }); -test('loads shared config once for lint and formatting without resolving app', () => { +test('runs lint followed by a formatting check', () => { writeLintConfig(); - writeProjectFile('src/index.ts', 'const value = "hello";\n'); + writeProjectFile('src/index.ts', 'const value=true'); const unformatted = runCheck(); @@ -52,9 +39,9 @@ test('loads shared config once for lint and formatting without resolving app', ( expect(unformatted.stderr).toContain( 'Formatting issues found in 1 file. Rerun this command with --fix to fix.', ); - expect(readProjectFile('src/index.ts')).toBe('const value = "hello";\n'); + expect(readProjectFile('src/index.ts')).toBe('const value=true'); - writeProjectFile('src/index.ts', "const value = 'hello';\n"); + writeProjectFile('src/index.ts', 'const value = true;\n'); const formatted = runCheck(); expect(formatted.status).toBe(0); @@ -62,6 +49,46 @@ test('loads shared config once for lint and formatting without resolving app', ( expect(formatted.stderr).toBe(''); }); +test('applies shared lint and format config without reloading or resolving app', () => { + writeProjectFile( + 'rstack.config.ts', + `import { define } from 'rstack'; + +if (process.env.RSTACK_CHECK_CONFIG_LOADED) { + throw new Error('Config was loaded twice'); +} +process.env.RSTACK_CHECK_CONFIG_LOADED = '1'; + +define.extends([ + { + app: () => { + throw new Error('App config must not run during check'); + }, + lint: [ + { + files: ['**/*.ts'], + rules: { curly: 'error' }, + }, + ], + fmt: { singleQuote: true }, + }, +]); +`, + ); + writeProjectFile( + 'src/index.ts', + 'const value = "hello";\nif (value) console.log(value);\n', + ); + + const result = runCheck(['--fix', 'src/index.ts']); + + expect(result.status).toBe(0); + expect(result.stderr).toBe(''); + expect(readProjectFile('src/index.ts')).toBe( + "const value = 'hello';\nif (value) {\n console.log(value);\n}\n", + ); +}); + test('passes file arguments to lint and the formatting check', () => { writeLintConfig(); writeProjectFile('src/selected-a.ts', 'const selectedA = true;\n'); From 4fb06369fb0e6293e9a0b72a9a9ea6473b203c19 Mon Sep 17 00:00:00 2001 From: neverland Date: Fri, 9 Oct 2026 11:21:13 +0800 Subject: [PATCH 5/5] test(config): keep existing concurrency tests unchanged --- packages/rstack/tests/config/load-config/index.test.ts | 3 --- .../tests/config/load-config/parallel-failing.config.ts | 6 ------ .../tests/config/load-config/parallel-first.config.ts | 6 ------ .../tests/config/load-config/parallel-second.config.ts | 6 ------ 4 files changed, 21 deletions(-) diff --git a/packages/rstack/tests/config/load-config/index.test.ts b/packages/rstack/tests/config/load-config/index.test.ts index d54fd601..b6ec8f01 100644 --- a/packages/rstack/tests/config/load-config/index.test.ts +++ b/packages/rstack/tests/config/load-config/index.test.ts @@ -88,12 +88,10 @@ test('should isolate parallel config sessions across top-level await', async () expect(firstResult.configs).toEqual({ app: { root: 'first' }, - fmt: { semi: false }, test: {}, }); expect(secondResult.configs).toEqual({ app: { root: 'second' }, - fmt: { semi: true }, lib: {}, }); }); @@ -110,7 +108,6 @@ test('should keep a running session intact when another config fails', async () expect((await successfulLoad).configs).toEqual({ app: { root: 'first' }, - fmt: { semi: false }, test: {}, }); }); diff --git a/packages/rstack/tests/config/load-config/parallel-failing.config.ts b/packages/rstack/tests/config/load-config/parallel-failing.config.ts index 4f4df7b5..75b06414 100644 --- a/packages/rstack/tests/config/load-config/parallel-failing.config.ts +++ b/packages/rstack/tests/config/load-config/parallel-failing.config.ts @@ -1,10 +1,4 @@ import { define } from 'rstack'; -define.extends([ - { - fmt: { semi: true }, - }, -]); - define.app({ root: 'failing' }); throw new Error('parallel config error'); diff --git a/packages/rstack/tests/config/load-config/parallel-first.config.ts b/packages/rstack/tests/config/load-config/parallel-first.config.ts index bf466967..4d68eed0 100644 --- a/packages/rstack/tests/config/load-config/parallel-first.config.ts +++ b/packages/rstack/tests/config/load-config/parallel-first.config.ts @@ -1,11 +1,5 @@ import { define } from 'rstack'; -define.extends([ - { - fmt: { semi: false }, - }, -]); - const hooks = globalThis.__rstackConfigTestHooks!; define.app({ root: 'first' }); diff --git a/packages/rstack/tests/config/load-config/parallel-second.config.ts b/packages/rstack/tests/config/load-config/parallel-second.config.ts index 4ba6bc3a..f5d6bcb7 100644 --- a/packages/rstack/tests/config/load-config/parallel-second.config.ts +++ b/packages/rstack/tests/config/load-config/parallel-second.config.ts @@ -1,10 +1,4 @@ import { define } from 'rstack'; -define.extends([ - { - fmt: { semi: true }, - }, -]); - define.app({ root: 'second' }); define.lib({});