@ranger1/dx 0.1.95 → 0.1.96
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cli/commands/core.js +76 -25
- package/lib/cli/flags.js +5 -1
- package/lib/cli/help.js +5 -4
- package/package.json +1 -1
package/lib/cli/commands/core.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs'
|
|
2
|
-
import { join, relative } from 'node:path'
|
|
2
|
+
import { dirname, join, relative } from 'node:path'
|
|
3
3
|
import { logger } from '../../logger.js'
|
|
4
4
|
import { confirmManager } from '../../confirm.js'
|
|
5
5
|
import { execManager } from '../../exec.js'
|
|
@@ -83,11 +83,7 @@ export async function handleTest(cli, args) {
|
|
|
83
83
|
|
|
84
84
|
// 解析 -t 参数用于指定特定测试用例(使用原始参数列表)
|
|
85
85
|
const allArgs = cli.args // 使用原始参数列表包含所有标志
|
|
86
|
-
const
|
|
87
|
-
let testNamePattern = null
|
|
88
|
-
if (testNamePatternIndex !== -1 && testNamePatternIndex + 1 < allArgs.length) {
|
|
89
|
-
testNamePattern = allArgs[testNamePatternIndex + 1]
|
|
90
|
-
}
|
|
86
|
+
const testNamePattern = resolveTestNamePattern(allArgs)
|
|
91
87
|
|
|
92
88
|
// 根据测试类型自动设置环境标志
|
|
93
89
|
if (type === 'e2e' && !cli.flags.e2e) {
|
|
@@ -120,7 +116,8 @@ export async function handleTest(cli, args) {
|
|
|
120
116
|
process.exit(1)
|
|
121
117
|
}
|
|
122
118
|
|
|
123
|
-
|
|
119
|
+
const normalizedTestPath = normalizeE2eTestPathForCommand(cli, fileCommand, testPath)
|
|
120
|
+
let command = fileCommand.replace('{TEST_PATH}', shellEscape(normalizedTestPath))
|
|
124
121
|
|
|
125
122
|
if (testNamePattern) {
|
|
126
123
|
command += ` -t ${shellEscape(testNamePattern)}`
|
|
@@ -179,6 +176,15 @@ function shellEscape(value) {
|
|
|
179
176
|
return `'${String(value).replace(/'/g, `'\\''`)}'`
|
|
180
177
|
}
|
|
181
178
|
|
|
179
|
+
function resolveTestNamePattern(args = []) {
|
|
180
|
+
const aliases = ['-t', '--name', '--test-name-pattern']
|
|
181
|
+
for (let i = 0; i < args.length; i++) {
|
|
182
|
+
if (!aliases.includes(args[i])) continue
|
|
183
|
+
if (i + 1 < args.length) return args[i + 1]
|
|
184
|
+
}
|
|
185
|
+
return null
|
|
186
|
+
}
|
|
187
|
+
|
|
182
188
|
function shouldUseDirectPathArg(command) {
|
|
183
189
|
const text = String(command || '')
|
|
184
190
|
return (
|
|
@@ -196,11 +202,11 @@ function normalizeUnitTestPathForCommand(cli, command, testPath) {
|
|
|
196
202
|
return rawPath
|
|
197
203
|
}
|
|
198
204
|
|
|
199
|
-
const
|
|
200
|
-
if (!
|
|
205
|
+
const projectCwd = resolveNxTargetProjectCwd(cli, command, ['test'])
|
|
206
|
+
if (!projectCwd) return rawPath
|
|
201
207
|
|
|
202
208
|
const projectRoot = cli?.projectRoot || process.cwd()
|
|
203
|
-
const absoluteProjectCwd = join(projectRoot,
|
|
209
|
+
const absoluteProjectCwd = join(projectRoot, projectCwd)
|
|
204
210
|
const absoluteTestPath = join(projectRoot, rawPath)
|
|
205
211
|
const relativePath = relative(absoluteProjectCwd, absoluteTestPath)
|
|
206
212
|
|
|
@@ -211,33 +217,78 @@ function normalizeUnitTestPathForCommand(cli, command, testPath) {
|
|
|
211
217
|
return relativePath
|
|
212
218
|
}
|
|
213
219
|
|
|
214
|
-
function
|
|
220
|
+
function normalizeE2eTestPathForCommand(cli, command, testPath) {
|
|
221
|
+
const rawPath = String(testPath || '')
|
|
222
|
+
if (!rawPath) return rawPath
|
|
223
|
+
|
|
224
|
+
const projectCwd = resolveNxTargetProjectCwd(cli, command, ['test:e2e'])
|
|
225
|
+
if (!projectCwd) return rawPath
|
|
226
|
+
|
|
215
227
|
const projectRoot = cli?.projectRoot || process.cwd()
|
|
216
|
-
const
|
|
217
|
-
|
|
228
|
+
const absoluteProjectCwd = join(projectRoot, projectCwd)
|
|
229
|
+
const absoluteTestPath = join(projectRoot, rawPath)
|
|
230
|
+
const relativePath = relative(absoluteProjectCwd, absoluteTestPath)
|
|
231
|
+
|
|
232
|
+
if (!relativePath || relativePath.startsWith('..')) {
|
|
233
|
+
return rawPath
|
|
234
|
+
}
|
|
218
235
|
|
|
219
|
-
|
|
236
|
+
return relativePath
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function resolveNxTargetProjectCwd(cli, command, targetNames = []) {
|
|
240
|
+
const projectRoot = cli?.projectRoot || process.cwd()
|
|
241
|
+
const nxResolution = extractNxTarget(command, targetNames)
|
|
242
|
+
if (!nxResolution) return null
|
|
243
|
+
|
|
244
|
+
const projectDir = join(projectRoot, 'apps', nxResolution.project)
|
|
245
|
+
const projectConfigPath = join(projectDir, 'project.json')
|
|
220
246
|
if (!existsSync(projectConfigPath)) return null
|
|
221
247
|
|
|
222
248
|
try {
|
|
223
249
|
const projectConfig = JSON.parse(readFileSync(projectConfigPath, 'utf8'))
|
|
224
|
-
const
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
250
|
+
const resolvedTarget = projectConfig?.targets?.[nxResolution.target]
|
|
251
|
+
const cwd = resolvedTarget?.options?.cwd
|
|
252
|
+
if (typeof cwd === 'string' && cwd.trim().length > 0) {
|
|
253
|
+
return cwd
|
|
254
|
+
}
|
|
255
|
+
if (nxResolution.target === 'test:e2e') {
|
|
256
|
+
const e2eDir = join(projectDir, 'e2e')
|
|
257
|
+
if (existsSync(e2eDir)) {
|
|
258
|
+
return relative(projectRoot, e2eDir)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return relative(projectRoot, dirname(projectConfigPath))
|
|
230
262
|
} catch {
|
|
231
263
|
return null
|
|
232
264
|
}
|
|
233
265
|
}
|
|
234
266
|
|
|
235
|
-
function
|
|
267
|
+
function extractNxTarget(command, targetNames = []) {
|
|
236
268
|
const text = String(command || '').trim()
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
269
|
+
const names = Array.isArray(targetNames) && targetNames.length > 0 ? targetNames : ['test']
|
|
270
|
+
|
|
271
|
+
for (const targetName of names) {
|
|
272
|
+
if (targetName === 'test') {
|
|
273
|
+
const directMatch = text.match(/\bnx(?:\.js)?\s+test\s+([^\s]+)/)
|
|
274
|
+
if (directMatch?.[1]) {
|
|
275
|
+
return { project: directMatch[1], target: 'test' }
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const escapedTarget = targetName.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
280
|
+
const runMatch = text.match(new RegExp(`\\bnx(?:\\.js)?\\s+run\\s+([^:\\s]+):${escapedTarget}\\b`))
|
|
281
|
+
if (runMatch?.[1]) {
|
|
282
|
+
return { project: runMatch[1], target: targetName }
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const directColonMatch = text.match(new RegExp(`\\bnx(?:\\.js)?\\s+${escapedTarget}\\s+([^\\s]+)`))
|
|
286
|
+
if (directColonMatch?.[1]) {
|
|
287
|
+
return { project: directColonMatch[1], target: targetName }
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return null
|
|
241
292
|
}
|
|
242
293
|
|
|
243
294
|
export async function handleLint(cli, args) {
|
package/lib/cli/flags.js
CHANGED
|
@@ -24,7 +24,11 @@ export const FLAG_DEFINITIONS = {
|
|
|
24
24
|
{ flag: '--name', expectsValue: true },
|
|
25
25
|
{ flag: '-n', expectsValue: true },
|
|
26
26
|
],
|
|
27
|
-
test: [
|
|
27
|
+
test: [
|
|
28
|
+
{ flag: '-t', expectsValue: true },
|
|
29
|
+
{ flag: '--name', expectsValue: true },
|
|
30
|
+
{ flag: '--test-name-pattern', expectsValue: true },
|
|
31
|
+
],
|
|
28
32
|
package: [
|
|
29
33
|
{ flag: '--skip-build' },
|
|
30
34
|
{ flag: '--keep-workdir' },
|
package/lib/cli/help.js
CHANGED
|
@@ -41,11 +41,11 @@ export function showHelp() {
|
|
|
41
41
|
' dx db script fix-pending-transfer-status --prod # 运行数据库脚本(生产环境,需确认)',
|
|
42
42
|
' dx db script my-script --dev -- --arg1 --arg2 # 向脚本传递额外参数(-- 后面的部分)',
|
|
43
43
|
'',
|
|
44
|
-
' test [type] [target] [path] [-t pattern] 运行测试',
|
|
44
|
+
' test [type] [target] [path] [-t pattern|--name pattern] 运行测试',
|
|
45
45
|
' type: e2e, unit (默认: e2e)',
|
|
46
46
|
' target: 由 commands.json 的 test.<type>.<target> 决定(e2e 默认会拒绝隐式 all)',
|
|
47
47
|
' path: 测试文件或目录路径 (guarded e2e target 必填,例如 backend/quantify)',
|
|
48
|
-
' -t pattern: 指定测试用例名称模式 (可选,需要和 path 一起使用)',
|
|
48
|
+
' -t pattern / --name pattern: 指定测试用例名称模式 (可选,需要和 path 一起使用)',
|
|
49
49
|
' 说明: guarded E2E target 禁止无路径或 all 全量执行,dx test e2e all 也不受支持',
|
|
50
50
|
'',
|
|
51
51
|
' worktree [action] [num...] Git Worktree管理',
|
|
@@ -94,6 +94,7 @@ export function showHelp() {
|
|
|
94
94
|
' dx test e2e backend apps/backend/e2e/auth # 按目录运行后端 E2E',
|
|
95
95
|
' dx test e2e backend apps/backend/e2e/activity/activity.admin.e2e-spec.ts # 运行单个E2E测试文件',
|
|
96
96
|
' dx test e2e backend apps/backend/e2e/activity/activity.admin.e2e-spec.ts -t "should list all activity definitions" # 运行特定测试用例',
|
|
97
|
+
' dx test unit backend apps/backend/src/modules/chat/chat.service.spec.ts --name "should create chat" # 运行单测中的特定用例',
|
|
97
98
|
' dx test e2e quantify apps/quantify/e2e/health/health.e2e-spec.ts # 运行 Quantify E2E 文件',
|
|
98
99
|
' dx test unit backend apps/backend/src/modules/chat/chat.service.spec.ts # 运行单个后端单测文件',
|
|
99
100
|
' dx test e2e all # 不受支持,必须指定 target 和 path',
|
|
@@ -254,13 +255,13 @@ start 命令用法:
|
|
|
254
255
|
case 'test':
|
|
255
256
|
console.log(`
|
|
256
257
|
test 命令用法:
|
|
257
|
-
dx test [type] [target] [path] [-t pattern]
|
|
258
|
+
dx test [type] [target] [path] [-t pattern|--name pattern]
|
|
258
259
|
|
|
259
260
|
参数说明:
|
|
260
261
|
type: e2e, unit (默认: e2e)
|
|
261
262
|
target: 由 commands.json 的 test.<type>.<target> 决定
|
|
262
263
|
path: guarded e2e target 必须提供文件或目录路径
|
|
263
|
-
-t pattern: 指定测试用例名称模式,需要和 path 一起使用
|
|
264
|
+
-t pattern / --name pattern: 指定测试用例名称模式,需要和 path 一起使用
|
|
264
265
|
|
|
265
266
|
限制说明:
|
|
266
267
|
guarded E2E target 禁止无路径全量执行。
|