Skip to content

Commit f6200bc

Browse files
authored
fix: ci failure (#103)
1 parent 1a01bc4 commit f6200bc

File tree

7 files changed

+245
-160
lines changed

7 files changed

+245
-160
lines changed

.github/workflows/cross-platform-tests.yml

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,21 @@ on:
77

88
jobs:
99
test:
10+
timeout-minutes: 90
1011
strategy:
1112
matrix:
1213
os: [ubuntu-latest, windows-latest, macos-latest]
1314
node-version: ['20.x', '22.x']
14-
fail-fast: false
15+
fail-fast: true
1516

1617
runs-on: ${{ matrix.os }}
1718
name: Test on ${{ matrix.os }} (Node ${{ matrix.node-version }})
19+
env:
20+
CI: true
21+
CRF_NPM_INSTALL_TIMEOUT_MS: '600000'
22+
CRF_NPM_BUILD_TIMEOUT_MS: '600000'
23+
CRF_TEST_HOOK_TIMEOUT_MS: '300000'
24+
CRF_CLI_TEST_TIMEOUT_MS: '30000'
1825

1926
steps:
2027
- name: Checkout code
@@ -33,28 +40,36 @@ jobs:
3340
run: npm run build
3441

3542
- name: Run unit tests
36-
run: npm test
43+
timeout-minutes: 20
44+
run: npm test -- --bail=1 src/__tests__/ --exclude "src/__tests__/integration/**"
3745

3846
- name: Run integration tests
39-
run: npm test -- src/__tests__/integration/
47+
timeout-minutes: 45
48+
run: npm test -- --bail=1 src/__tests__/integration/
4049

4150
- name: Run cross-platform tests
42-
run: npm test -- src/__tests__/integration/cross-platform-cli.test.ts
51+
timeout-minutes: 15
52+
run: npm test -- --bail=1 src/__tests__/integration/cross-platform-cli.test.ts
4353

4454
- name: Run E2E CLI tests
45-
run: npm test -- src/__tests__/integration/e2e-cli.test.ts
55+
timeout-minutes: 15
56+
run: npm test -- --bail=1 src/__tests__/integration/e2e-cli.test.ts
4657

4758
- name: Run E2E scenario tests
48-
run: npm test -- src/__tests__/integration/e2e-scenarios.test.ts
59+
timeout-minutes: 20
60+
run: npm test -- --bail=1 src/__tests__/integration/e2e-scenarios.test.ts
4961

5062
- name: Run config builder comprehensive tests
51-
run: npm test -- src/__tests__/config-builder.test.ts
63+
timeout-minutes: 15
64+
run: npm test -- --bail=1 src/__tests__/config-builder.test.ts
5265

5366
- name: Run template system comprehensive tests
54-
run: npm test -- src/__tests__/integration/template-loading.test.ts
67+
timeout-minutes: 15
68+
run: npm test -- --bail=1 src/__tests__/integration/template-loading.test.ts
5569

5670
- name: Run generator comprehensive tests
57-
run: npm test -- src/__tests__/integration/generator.test.ts
71+
timeout-minutes: 15
72+
run: npm test -- --bail=1 src/__tests__/integration/generator.test.ts
5873

5974
- name: Test CLI command (Unix)
6075
if: runner.os != 'Windows'
@@ -68,8 +83,8 @@ jobs:
6883
shell: powershell
6984
run: |
7085
# Test that the CLI can be invoked
71-
node dist/index.js --version -or $true
72-
node dist/index.js --help -or $true
86+
try { node dist/index.js --version } catch { $true | Out-Null }
87+
try { node dist/index.js --help } catch { $true | Out-Null }
7388
7489
- name: Upload coverage
7590
if: matrix.os == 'ubuntu-latest'
@@ -80,6 +95,7 @@ jobs:
8095
name: codecov-umbrella
8196

8297
e2e-scaffold-test:
98+
timeout-minutes: 30
8399
strategy:
84100
matrix:
85101
os: [ubuntu-latest, windows-latest, macos-latest]
@@ -129,6 +145,7 @@ jobs:
129145
130146
lint:
131147
runs-on: ubuntu-latest
148+
timeout-minutes: 15
132149
name: Lint and Format Check
133150

134151
steps:
@@ -150,6 +167,7 @@ jobs:
150167
build-artifacts:
151168
needs: [test, e2e-scaffold-test, lint]
152169
runs-on: ubuntu-latest
170+
timeout-minutes: 15
153171
name: Verify Build Artifacts
154172

155173
steps:

src/__tests__/cli-index.test.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { basename } from 'path';
23
import type { PromptAnswers } from '../cli/prompts';
34

45
const { promptForProjectDetailsMock, generateProjectMock } = vi.hoisted(() => ({
@@ -55,7 +56,7 @@ describe('CLI Index', () => {
5556
);
5657

5758
expect(config.name).toBe('test-app');
58-
expect(config.path).toContain('/test-app');
59+
expect(basename(config.path)).toBe('test-app');
5960
expect(config.runtime).toBe('nextjs');
6061
expect(config.language).toBe('javascript');
6162
expect(config.styling.solution).toBe('styled-components');
@@ -120,11 +121,9 @@ describe('CLI Index', () => {
120121
it('should exit with code 1 when generation fails', async () => {
121122
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => undefined);
122123
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => undefined);
123-
const exitSpy = vi
124-
.spyOn(process, 'exit')
125-
.mockImplementation(((code?: number) => {
126-
throw new Error(`exit ${code}`);
127-
}) as never);
124+
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(((code?: number) => {
125+
throw new Error(`exit ${code}`);
126+
}) as never);
128127

129128
promptForProjectDetailsMock.mockResolvedValue(createAnswers());
130129
generateProjectMock.mockResolvedValue({
@@ -145,11 +144,9 @@ describe('CLI Index', () => {
145144

146145
it('should exit with code 0 when user cancels prompt', async () => {
147146
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => undefined);
148-
const exitSpy = vi
149-
.spyOn(process, 'exit')
150-
.mockImplementation(((code?: number) => {
151-
throw new Error(`exit ${code}`);
152-
}) as never);
147+
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(((code?: number) => {
148+
throw new Error(`exit ${code}`);
149+
}) as never);
153150

154151
promptForProjectDetailsMock.mockRejectedValue(new Error('User force closed the prompt'));
155152

src/__tests__/integration/build-verification.test.ts

Lines changed: 54 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { existsSync, rmSync } from 'fs';
2-
import { tmpdir } from 'os';
1+
import { existsSync, mkdirSync, realpathSync, rmSync } from 'fs';
32
import { join } from 'path';
43
import { afterEach, describe, expect, it } from 'vitest';
54
import { execa } from 'execa';
@@ -13,7 +12,14 @@ import { ProjectGenerator } from '../../generator/index.js';
1312
*/
1413

1514
function getTempProjectPath(name: string): string {
16-
return join(tmpdir(), `react-setup-build-${name}-${Date.now()}`);
15+
const baseDir = join(process.cwd(), '.tmp-test-projects');
16+
if (!existsSync(baseDir)) {
17+
mkdirSync(baseDir, { recursive: true });
18+
}
19+
return join(
20+
baseDir,
21+
`react-setup-build-${name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
22+
);
1723
}
1824

1925
function cleanupProject(path: string): void {
@@ -46,13 +52,39 @@ function createConfig(name: string, overrides: Partial<ProjectConfig>): ProjectC
4652
};
4753
}
4854

55+
const NPM_INSTALL_TIMEOUT_MS = Number(process.env.CRF_NPM_INSTALL_TIMEOUT_MS ?? 600000);
56+
const NPM_BUILD_TIMEOUT_MS = Number(process.env.CRF_NPM_BUILD_TIMEOUT_MS ?? 600000);
57+
const TEST_HOOK_TIMEOUT_MS = Number(process.env.CRF_TEST_HOOK_TIMEOUT_MS ?? 300000);
58+
59+
async function installDependencies(projectPath: string) {
60+
return execa('npm', ['install', '--no-audit', '--no-fund'], {
61+
cwd: getCommandCwd(projectPath),
62+
timeout: NPM_INSTALL_TIMEOUT_MS,
63+
});
64+
}
65+
66+
async function buildProject(projectPath: string) {
67+
return execa('npm', ['run', 'build'], {
68+
cwd: getCommandCwd(projectPath),
69+
timeout: NPM_BUILD_TIMEOUT_MS,
70+
});
71+
}
72+
73+
function getCommandCwd(projectPath: string): string {
74+
try {
75+
return realpathSync(projectPath);
76+
} catch {
77+
return projectPath;
78+
}
79+
}
80+
4981
describe('Build Verification Tests', () => {
5082
const projectPaths: string[] = [];
5183

5284
afterEach(() => {
5385
projectPaths.forEach(cleanupProject);
5486
projectPaths.length = 0;
55-
});
87+
}, TEST_HOOK_TIMEOUT_MS);
5688

5789
describe('Next.js Projects', () => {
5890
it('should generate and build a minimal Next.js project', async () => {
@@ -70,23 +102,17 @@ describe('Build Verification Tests', () => {
70102

71103
// Install dependencies
72104
console.log('Installing dependencies for Next.js project...');
73-
const installResult = await execa('npm', ['install'], {
74-
cwd: config.path,
75-
timeout: 120000, // 2 minutes
76-
});
105+
const installResult = await installDependencies(config.path);
77106
expect(installResult.exitCode).toBe(0);
78107

79108
// Build the project
80109
console.log('Building Next.js project...');
81-
const buildResult = await execa('npm', ['run', 'build'], {
82-
cwd: config.path,
83-
timeout: 180000, // 3 minutes
84-
});
110+
const buildResult = await buildProject(config.path);
85111
expect(buildResult.exitCode).toBe(0);
86112

87113
// Verify build output exists
88114
expect(existsSync(join(config.path, '.next'))).toBe(true);
89-
}, 360000); // 6 minute timeout for entire test
115+
}, 720000); // 12 minute timeout for entire test
90116

91117
it('should generate and build Next.js with Tailwind', async () => {
92118
const config = createConfig('nextjs-build-tailwind', {
@@ -102,22 +128,16 @@ describe('Build Verification Tests', () => {
102128

103129
// Install dependencies
104130
console.log('Installing dependencies for Next.js + Tailwind project...');
105-
const installResult = await execa('npm', ['install'], {
106-
cwd: config.path,
107-
timeout: 120000,
108-
});
131+
const installResult = await installDependencies(config.path);
109132
expect(installResult.exitCode).toBe(0);
110133

111134
// Build the project
112135
console.log('Building Next.js + Tailwind project...');
113-
const buildResult = await execa('npm', ['run', 'build'], {
114-
cwd: config.path,
115-
timeout: 180000,
116-
});
136+
const buildResult = await buildProject(config.path);
117137
expect(buildResult.exitCode).toBe(0);
118138

119139
expect(existsSync(join(config.path, '.next'))).toBe(true);
120-
}, 360000);
140+
}, 720000);
121141

122142
it('should generate and build Next.js with state management', async () => {
123143
const config = createConfig('nextjs-build-zustand', {
@@ -134,22 +154,16 @@ describe('Build Verification Tests', () => {
134154

135155
// Install dependencies
136156
console.log('Installing dependencies for Next.js + Zustand project...');
137-
const installResult = await execa('npm', ['install'], {
138-
cwd: config.path,
139-
timeout: 120000,
140-
});
157+
const installResult = await installDependencies(config.path);
141158
expect(installResult.exitCode).toBe(0);
142159

143160
// Build the project
144161
console.log('Building Next.js + Zustand project...');
145-
const buildResult = await execa('npm', ['run', 'build'], {
146-
cwd: config.path,
147-
timeout: 180000,
148-
});
162+
const buildResult = await buildProject(config.path);
149163
expect(buildResult.exitCode).toBe(0);
150164

151165
expect(existsSync(join(config.path, '.next'))).toBe(true);
152-
}, 360000);
166+
}, 720000);
153167
});
154168

155169
describe('Vite Projects', () => {
@@ -168,23 +182,17 @@ describe('Build Verification Tests', () => {
168182

169183
// Install dependencies
170184
console.log('Installing dependencies for Vite project...');
171-
const installResult = await execa('npm', ['install'], {
172-
cwd: config.path,
173-
timeout: 120000,
174-
});
185+
const installResult = await installDependencies(config.path);
175186
expect(installResult.exitCode).toBe(0);
176187

177188
// Build the project
178189
console.log('Building Vite project...');
179-
const buildResult = await execa('npm', ['run', 'build'], {
180-
cwd: config.path,
181-
timeout: 120000,
182-
});
190+
const buildResult = await buildProject(config.path);
183191
expect(buildResult.exitCode).toBe(0);
184192

185193
// Verify build output exists
186194
expect(existsSync(join(config.path, 'dist'))).toBe(true);
187-
}, 300000); // 5 minute timeout
195+
}, 600000); // 10 minute timeout
188196

189197
it('should generate and build Vite with Tailwind', async () => {
190198
const config = createConfig('vite-build-tailwind', {
@@ -200,22 +208,16 @@ describe('Build Verification Tests', () => {
200208

201209
// Install dependencies
202210
console.log('Installing dependencies for Vite + Tailwind project...');
203-
const installResult = await execa('npm', ['install'], {
204-
cwd: config.path,
205-
timeout: 120000,
206-
});
211+
const installResult = await installDependencies(config.path);
207212
expect(installResult.exitCode).toBe(0);
208213

209214
// Build the project
210215
console.log('Building Vite + Tailwind project...');
211-
const buildResult = await execa('npm', ['run', 'build'], {
212-
cwd: config.path,
213-
timeout: 120000,
214-
});
216+
const buildResult = await buildProject(config.path);
215217
expect(buildResult.exitCode).toBe(0);
216218

217219
expect(existsSync(join(config.path, 'dist'))).toBe(true);
218-
}, 300000);
220+
}, 600000);
219221

220222
it('should generate and build Vite with full stack (Tailwind + Zustand + TanStack Query)', async () => {
221223
const config = createConfig('vite-build-full', {
@@ -233,22 +235,15 @@ describe('Build Verification Tests', () => {
233235

234236
// Install dependencies
235237
console.log('Installing dependencies for Vite full stack project...');
236-
const installResult = await execa('npm', ['install'], {
237-
cwd: config.path,
238-
timeout: 120000,
239-
});
238+
const installResult = await installDependencies(config.path);
240239
expect(installResult.exitCode).toBe(0);
241240

242241
// Build the project
243242
console.log('Building Vite full stack project...');
244-
const buildResult = await execa('npm', ['run', 'build'], {
245-
cwd: config.path,
246-
timeout: 120000,
247-
});
243+
const buildResult = await buildProject(config.path);
248244
expect(buildResult.exitCode).toBe(0);
249245

250246
expect(existsSync(join(config.path, 'dist'))).toBe(true);
251-
}, 300000);
247+
}, 600000);
252248
});
253249
});
254-

0 commit comments

Comments
 (0)