mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-25 17:54:34 +08:00
test: add default test runner
This commit is contained in:
1 parent
33353be9e2
commit
2d88215d63
8 files changed
+135
-9
No files matched your search
@@ -40,7 +40,7 @@
|
||||
- 类型检查:Node/CLI/Electron 主进程相关改动运行 `pnpm run type-check:node`;前端/Vue 相关改动运行 `pnpm run type-check:web`;跨端或发布前改动运行 `pnpm run type-check:all`
|
||||
- Lint:优先对修改文件运行 `pnpm exec eslint <files...>`;需要全量修复时再运行 `pnpm lint`
|
||||
- Format:优先对修改文件运行 `pnpm exec prettier --write <files...>`;大范围格式化才运行 `pnpm format`
|
||||
- 单元/集成测试:当前没有统一全量 `test` 脚本,优先运行相关测试文件,例如 `pnpm exec tsx --test path/to/file.test.ts`
|
||||
- 单元/集成测试:日常默认运行 `pnpm test` 或 `pnpm run test:unit`;优先运行相关测试文件时用 `pnpm test -- path/to/file.test.ts`
|
||||
- 文档:修改公开文档或 VitePress 配置后运行 `pnpm docs:build`;只改 `.docs/` 私有任务文档时不需要构建公开文档站
|
||||
- E2E/Smoke:`pnpm run test:e2e:launcher`、`pnpm run test:e2e:smoke` 和真实 LLM/真实 Electron 测试只在相关功能需要时运行,默认不作为每次改动的必跑项
|
||||
- 最后检查:提交前运行 `git diff --check`,确认没有空白错误
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
isSubPath,
|
||||
writeMigrationLog,
|
||||
} from './utils/pathUtils'
|
||||
import { shouldMarkUnifiedDirMigrationDone } from './utils/unifiedDirMigration'
|
||||
import {
|
||||
createPendingDataDirMigration,
|
||||
isDirectoryEmptyOrMissing,
|
||||
@@ -568,10 +569,6 @@ export function removeLegacyDir(): boolean {
|
||||
|
||||
const SYSTEM_SUBDIRS = ['ai', 'settings', 'cache', 'logs', 'temp', 'nlp']
|
||||
|
||||
export function shouldMarkUnifiedDirMigrationDone(failedDirs: string[]): boolean {
|
||||
return failedDirs.length === 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测是否需要从 Electron 旧目录结构迁移到新的双根目录结构
|
||||
*
|
||||
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
import { describe, it } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { shouldMarkUnifiedDirMigrationDone } from './paths'
|
||||
import { shouldMarkUnifiedDirMigrationDone } from './unifiedDirMigration'
|
||||
|
||||
describe('desktop path migration', () => {
|
||||
it('marks unified directory migration done only when no directory failed', () => {
|
||||
describe('desktop unified directory migration', () => {
|
||||
it('marks migration done only when no directory failed', () => {
|
||||
assert.equal(shouldMarkUnifiedDirMigrationDone([]), true)
|
||||
assert.equal(shouldMarkUnifiedDirMigrationDone(['settings']), false)
|
||||
})
|
||||
@@ -0,0 +1,3 @@
|
||||
export function shouldMarkUnifiedDirMigrationDone(failedDirs: string[]): boolean {
|
||||
return failedDirs.length === 0
|
||||
}
|
||||
@@ -39,6 +39,8 @@
|
||||
"type-check:node": "tsc --noEmit -p tsconfig.node.json && tsc --noEmit -p apps/desktop/tsconfig.node.json",
|
||||
"type-check:all": "pnpm run type-check:web && pnpm run type-check:node",
|
||||
"type-check": "vue-tsc --noEmit -p tsconfig.web.json",
|
||||
"test": "node scripts/run-tests.mjs",
|
||||
"test:unit": "node scripts/run-tests.mjs",
|
||||
"test:auth": "tsx --test apps/cli/src/http/auth.test.ts src/services/utils/http.test.ts",
|
||||
"test:agent-context": "node --experimental-strip-types --test apps/desktop/main/ai/context/sessionLog.test.mjs",
|
||||
"test:e2e:launcher": "node --test tests/e2e/helpers/app-launcher.test.js",
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { readdirSync, statSync } from 'node:fs'
|
||||
import { join, relative, sep } from 'node:path'
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const SKIP_DIRS = new Set([
|
||||
'.git',
|
||||
'.docs',
|
||||
'node_modules',
|
||||
'dist',
|
||||
'dist-web',
|
||||
'out',
|
||||
'build',
|
||||
'coverage',
|
||||
'.vitepress',
|
||||
])
|
||||
|
||||
const TEST_FILE_RE = /\.(?:test|spec)\.(?:ts|tsx|js|jsx|mjs|mts|cjs|cts)$/
|
||||
|
||||
function normalizePath(filePath) {
|
||||
return filePath.split(sep).join('/')
|
||||
}
|
||||
|
||||
export function filterDefaultTestFiles(files) {
|
||||
return files
|
||||
.map(normalizePath)
|
||||
.filter((file) => TEST_FILE_RE.test(file))
|
||||
.filter((file) => !file.startsWith('tests/e2e/'))
|
||||
.filter((file) => !file.includes('/smoke/'))
|
||||
.filter((file) => !file.includes('.smoke.test.'))
|
||||
.filter((file) => !file.includes('.e2e.test.'))
|
||||
}
|
||||
|
||||
function collectFiles(rootDir, dir = rootDir) {
|
||||
const entries = readdirSync(dir, { withFileTypes: true })
|
||||
const files = []
|
||||
|
||||
for (const entry of entries) {
|
||||
if (entry.isDirectory()) {
|
||||
if (SKIP_DIRS.has(entry.name)) continue
|
||||
files.push(...collectFiles(rootDir, join(dir, entry.name)))
|
||||
continue
|
||||
}
|
||||
|
||||
if (!entry.isFile()) continue
|
||||
|
||||
const filePath = join(dir, entry.name)
|
||||
files.push(normalizePath(relative(rootDir, filePath)))
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
export function collectDefaultTestFiles(rootDir = process.cwd()) {
|
||||
if (!statSync(rootDir).isDirectory()) {
|
||||
throw new Error(`Test root is not a directory: ${rootDir}`)
|
||||
}
|
||||
return filterDefaultTestFiles(collectFiles(rootDir)).sort()
|
||||
}
|
||||
|
||||
export function buildNodeTestArgs(testArgs) {
|
||||
return ['--import', 'tsx', '--test', ...testArgs]
|
||||
}
|
||||
|
||||
function run() {
|
||||
const explicitArgs = process.argv.slice(2)
|
||||
const testArgs = explicitArgs.length > 0 ? explicitArgs : collectDefaultTestFiles()
|
||||
|
||||
if (testArgs.length === 0) {
|
||||
console.error('No test files found.')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (explicitArgs.length === 0) {
|
||||
console.log(`Running ${testArgs.length} default test files.`)
|
||||
}
|
||||
|
||||
const result = spawnSync(process.execPath, buildNodeTestArgs(testArgs), {
|
||||
stdio: 'inherit',
|
||||
})
|
||||
|
||||
if (result.error) {
|
||||
throw result.error
|
||||
}
|
||||
|
||||
process.exit(result.status ?? 1)
|
||||
}
|
||||
|
||||
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
||||
run()
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import test from 'node:test'
|
||||
|
||||
import { buildNodeTestArgs, filterDefaultTestFiles } from './run-tests.mjs'
|
||||
|
||||
test('default test collection excludes e2e, smoke, and real external tests', () => {
|
||||
const files = [
|
||||
'apps/cli/src/ai/chat-command.test.ts',
|
||||
'tests/chart-runtime/agent-chart-flow.test.mts',
|
||||
'tests/chart-runtime/render-chart.integration.test.ts',
|
||||
'tests/e2e/helpers/app-launcher.test.js',
|
||||
'tests/e2e/smoke/chart-runtime.smoke.test.js',
|
||||
'tests/chart-runtime/real-llm-chart-flow.e2e.test.ts',
|
||||
'tests/e2e/helpers/app-launcher.js',
|
||||
]
|
||||
|
||||
assert.deepEqual(filterDefaultTestFiles(files), [
|
||||
'apps/cli/src/ai/chat-command.test.ts',
|
||||
'tests/chart-runtime/agent-chart-flow.test.mts',
|
||||
'tests/chart-runtime/render-chart.integration.test.ts',
|
||||
])
|
||||
})
|
||||
|
||||
test('explicit test arguments are passed through without default exclusions', () => {
|
||||
assert.deepEqual(buildNodeTestArgs(['tests/e2e/helpers/app-launcher.test.js']), [
|
||||
'--import',
|
||||
'tsx',
|
||||
'--test',
|
||||
'tests/e2e/helpers/app-launcher.test.js',
|
||||
])
|
||||
})
|
||||
@@ -1,7 +1,7 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import test from 'node:test'
|
||||
|
||||
import { resolveLanguageBootstrap } from './onboardingFlow.ts'
|
||||
import { resolveLanguageBootstrap } from './onboardingFlow'
|
||||
|
||||
test('新用户没有保存语言时应先打开语言选择,不继续后续弹窗流程', () => {
|
||||
assert.deepEqual(resolveLanguageBootstrap(''), {
|
||||
Reference in new issue
Block a user