@testspectra/cli 1.0.28 → 1.0.30
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/dist/commands/add.js +4 -6
- package/dist/commands/init.js +84 -43
- package/dist/types/generator.js +73 -71
- package/package.json +1 -1
- package/templates/default/tsconfig.json +1 -15
- package/templates/{nx/modules/auth/e2e/tsconfig.json → default/tsconfig.spectra.json} +7 -8
- package/templates/nx/modules/auth/e2e/project.json +3 -4
- package/templates/nx/modules/catalog/e2e/project.json +3 -4
- package/templates/nx/package.json +1 -1
- package/templates/nx/shared/testing/page-objects/NavigationBar/common.ts +2 -2
- package/templates/nx/tsconfig.json +1 -3
- package/templates/nx/tsconfig.spectra.android.json +36 -0
- package/templates/nx/tsconfig.spectra.ios.json +36 -0
- package/templates/nx/{modules/catalog/e2e/tsconfig.json → tsconfig.spectra.json} +7 -8
- package/templates/nx/tsconfig.spectra.web.json +42 -0
- package/templates/nx/modules/auth/e2e/.testspectra/types/android.d.ts +0 -82
- package/templates/nx/modules/auth/e2e/.testspectra/types/common.d.ts +0 -80
- package/templates/nx/modules/auth/e2e/.testspectra/types/fixtures.d.ts +0 -10
- package/templates/nx/modules/auth/e2e/.testspectra/types/index.d.ts +0 -1
- package/templates/nx/modules/auth/e2e/.testspectra/types/ios.d.ts +0 -82
- package/templates/nx/modules/auth/e2e/.testspectra/types/mobile.d.ts +0 -82
- package/templates/nx/modules/auth/e2e/.testspectra/types/web.d.ts +0 -82
- package/templates/nx/modules/auth/e2e/tsconfig.android.json +0 -39
- package/templates/nx/modules/auth/e2e/tsconfig.android.tsbuildinfo +0 -1
- package/templates/nx/modules/auth/e2e/tsconfig.ios.json +0 -39
- package/templates/nx/modules/auth/e2e/tsconfig.ios.tsbuildinfo +0 -1
- package/templates/nx/modules/auth/e2e/tsconfig.web.json +0 -45
- package/templates/nx/modules/auth/e2e/tsconfig.web.tsbuildinfo +0 -1
- package/templates/nx/modules/catalog/e2e/.testspectra/types/android.d.ts +0 -82
- package/templates/nx/modules/catalog/e2e/.testspectra/types/common.d.ts +0 -80
- package/templates/nx/modules/catalog/e2e/.testspectra/types/fixtures.d.ts +0 -10
- package/templates/nx/modules/catalog/e2e/.testspectra/types/index.d.ts +0 -1
- package/templates/nx/modules/catalog/e2e/.testspectra/types/ios.d.ts +0 -82
- package/templates/nx/modules/catalog/e2e/.testspectra/types/mobile.d.ts +0 -82
- package/templates/nx/modules/catalog/e2e/.testspectra/types/web.d.ts +0 -82
- package/templates/nx/modules/catalog/e2e/tsconfig.android.json +0 -39
- package/templates/nx/modules/catalog/e2e/tsconfig.android.tsbuildinfo +0 -1
- package/templates/nx/modules/catalog/e2e/tsconfig.ios.json +0 -39
- package/templates/nx/modules/catalog/e2e/tsconfig.ios.tsbuildinfo +0 -1
- package/templates/nx/modules/catalog/e2e/tsconfig.web.json +0 -45
- package/templates/nx/modules/catalog/e2e/tsconfig.web.tsbuildinfo +0 -1
- package/templates/nx/shared/testing/tsconfig.json +0 -18
- package/templates/nx/shared/testing/tsconfig.tsbuildinfo +0 -1
- /package/templates/default/{tsconfig.android.json → tsconfig.spectra.android.json} +0 -0
- /package/templates/default/{tsconfig.ios.json → tsconfig.spectra.ios.json} +0 -0
- /package/templates/default/{tsconfig.web.json → tsconfig.spectra.web.json} +0 -0
package/dist/commands/add.js
CHANGED
|
@@ -311,24 +311,22 @@ export async function addCommand(moduleNameArg, options = {}) {
|
|
|
311
311
|
const localConfig = path.join(targetE2eDir, "spectra.config.ts");
|
|
312
312
|
if (fs.existsSync(localConfig))
|
|
313
313
|
fs.unlinkSync(localConfig);
|
|
314
|
-
//
|
|
314
|
+
// Ensure Root Solution tsconfig.json references tsconfig.spectra.json
|
|
315
315
|
const rootTsConfigPath = path.join(rootDir, "tsconfig.json");
|
|
316
316
|
if (fs.existsSync(rootTsConfigPath)) {
|
|
317
317
|
try {
|
|
318
318
|
const rootTsConfig = JSON.parse(fs.readFileSync(rootTsConfigPath, "utf-8"));
|
|
319
319
|
if (!rootTsConfig.references)
|
|
320
320
|
rootTsConfig.references = [];
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
rootTsConfig.references.push({ path: relRef });
|
|
321
|
+
if (!rootTsConfig.references.some((r) => r.path === "./tsconfig.spectra.json")) {
|
|
322
|
+
rootTsConfig.references.push({ path: "./tsconfig.spectra.json" });
|
|
324
323
|
fs.writeFileSync(rootTsConfigPath, JSON.stringify(rootTsConfig, null, 2), "utf-8");
|
|
325
324
|
}
|
|
326
325
|
}
|
|
327
326
|
catch { }
|
|
328
327
|
}
|
|
329
|
-
// Generate Ambient Types for root
|
|
328
|
+
// Generate Ambient Types for root workspace
|
|
330
329
|
TypeGenerator.writeDeclarationFiles(rootDir);
|
|
331
|
-
TypeGenerator.writeDeclarationFiles(targetE2eDir);
|
|
332
330
|
s.stop(`Module ${e2eProjectName} added successfully!`);
|
|
333
331
|
p.log.success(chalk.green(`Directory: ./${path.relative(rootDir, targetE2eDir)}`));
|
|
334
332
|
p.log.success(chalk.green(`Nx Target: ${e2eProjectName}:e2e`));
|
package/dist/commands/init.js
CHANGED
|
@@ -293,7 +293,10 @@ export async function initCommand(options = {}) {
|
|
|
293
293
|
// --- MONOREPO INTERACTIVE FLOW ---
|
|
294
294
|
if (templateName === "nx" && (detectedProjects.length > 0 || isMonorepo)) {
|
|
295
295
|
let chosenProjects = [];
|
|
296
|
-
if (
|
|
296
|
+
if (options.force) {
|
|
297
|
+
chosenProjects = detectedProjects.map((p) => p.relPath);
|
|
298
|
+
}
|
|
299
|
+
else if (detectedProjects.length > 0) {
|
|
297
300
|
p.log.step(chalk.cyan(`Monorepo Auto-Discovery: Found ${detectedProjects.length} workspace feature package(s)`));
|
|
298
301
|
const projectChoices = await p.multiselect({
|
|
299
302
|
message: "Select workspace features to initialize with TestSpectra:",
|
|
@@ -311,34 +314,77 @@ export async function initCommand(options = {}) {
|
|
|
311
314
|
}
|
|
312
315
|
chosenProjects = projectChoices;
|
|
313
316
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
317
|
+
let e2eFolderName = "e2e";
|
|
318
|
+
let sharedTestingRelPath = "shared/testing";
|
|
319
|
+
if (!options.force) {
|
|
320
|
+
const e2eFolderNameInput = await p.text({
|
|
321
|
+
message: "Enter E2E test folder name for each selected feature:",
|
|
322
|
+
placeholder: "e2e",
|
|
323
|
+
defaultValue: "e2e",
|
|
324
|
+
});
|
|
325
|
+
if (p.isCancel(e2eFolderNameInput)) {
|
|
326
|
+
p.cancel("Setup cancelled.");
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const sharedTestingPathInput = await p.text({
|
|
330
|
+
message: "Enter path for Shared Testing library (POMs, Steps, Actions, Fixtures):",
|
|
331
|
+
placeholder: "shared/testing",
|
|
332
|
+
defaultValue: "shared/testing",
|
|
333
|
+
});
|
|
334
|
+
if (p.isCancel(sharedTestingPathInput)) {
|
|
335
|
+
p.cancel("Setup cancelled.");
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
e2eFolderName = e2eFolderNameInput.trim() || "e2e";
|
|
339
|
+
sharedTestingRelPath = sharedTestingPathInput.trim() || "shared/testing";
|
|
331
340
|
}
|
|
332
|
-
const e2eFolderName = e2eFolderNameInput.trim() || "e2e";
|
|
333
|
-
const sharedTestingRelPath = sharedTestingPathInput.trim() || "shared/testing";
|
|
334
341
|
const sharedTestingAbsPath = path.join(cwd, sharedTestingRelPath);
|
|
335
342
|
const s = p.spinner();
|
|
336
343
|
s.start("Scaffolding distributed monorepo structure and ambient types...");
|
|
337
|
-
// 1. Centralized Root
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
344
|
+
// 1. Centralized Root Configs & Orchestration
|
|
345
|
+
const rootConfigFiles = [
|
|
346
|
+
"spectra.config.ts",
|
|
347
|
+
"tsconfig.spectra.json",
|
|
348
|
+
"tsconfig.spectra.web.json",
|
|
349
|
+
"tsconfig.spectra.android.json",
|
|
350
|
+
"tsconfig.spectra.ios.json",
|
|
351
|
+
"nx.json",
|
|
352
|
+
];
|
|
353
|
+
for (const cf of rootConfigFiles) {
|
|
354
|
+
const src = path.join(templateDir, cf);
|
|
355
|
+
const dest = path.join(cwd, cf);
|
|
356
|
+
if (fs.existsSync(src) && (!fs.existsSync(dest) || options.force)) {
|
|
357
|
+
fs.copyFileSync(src, dest);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
// Ensure root package.json has TestSpectra devDependencies
|
|
361
|
+
const rootPkgPath = path.join(cwd, "package.json");
|
|
362
|
+
if (!fs.existsSync(rootPkgPath)) {
|
|
363
|
+
const templatePkgSrc = path.join(templateDir, "package.json");
|
|
364
|
+
if (fs.existsSync(templatePkgSrc)) {
|
|
365
|
+
copyRecursive(templatePkgSrc, rootPkgPath);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
try {
|
|
370
|
+
const rootPkg = JSON.parse(fs.readFileSync(rootPkgPath, "utf-8"));
|
|
371
|
+
if (!rootPkg.devDependencies)
|
|
372
|
+
rootPkg.devDependencies = {};
|
|
373
|
+
if (!rootPkg.devDependencies["@testspectra/cli"])
|
|
374
|
+
rootPkg.devDependencies["@testspectra/cli"] = cliDepVersion;
|
|
375
|
+
if (!rootPkg.devDependencies["typescript"])
|
|
376
|
+
rootPkg.devDependencies["typescript"] = "^5.4.5";
|
|
377
|
+
if (!rootPkg.devDependencies["@wdio/globals"])
|
|
378
|
+
rootPkg.devDependencies["@wdio/globals"] = "^9.2.8";
|
|
379
|
+
if (!rootPkg.devDependencies["@wdio/mocha-framework"])
|
|
380
|
+
rootPkg.devDependencies["@wdio/mocha-framework"] = "^9.2.8";
|
|
381
|
+
if (!rootPkg.devDependencies["@types/node"])
|
|
382
|
+
rootPkg.devDependencies["@types/node"] = "^20.14.0";
|
|
383
|
+
if (!rootPkg.devDependencies["webdriverio"])
|
|
384
|
+
rootPkg.devDependencies["webdriverio"] = "^9.2.8";
|
|
385
|
+
fs.writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2), "utf-8");
|
|
386
|
+
}
|
|
387
|
+
catch { }
|
|
342
388
|
}
|
|
343
389
|
// 2. Centralized Root .testspectra folder for cache/logs
|
|
344
390
|
const rootTestDataDir = path.join(cwd, ".testspectra");
|
|
@@ -385,36 +431,28 @@ export async function initCommand(options = {}) {
|
|
|
385
431
|
// 5. Ensure pnpm-workspace.yaml includes shared library (feature modules are already part of existing workspace globs)
|
|
386
432
|
const pnpmWorkspaceFilePath = path.join(cwd, "pnpm-workspace.yaml");
|
|
387
433
|
ensurePnpmWorkspaceIncludes(pnpmWorkspaceFilePath, sharedTestingRelPath);
|
|
388
|
-
// 6. Update Root Solution tsconfig.json
|
|
434
|
+
// 6. Update Root Solution tsconfig.json to reference tsconfig.spectra.json
|
|
389
435
|
const rootTsConfigPath = path.join(cwd, "tsconfig.json");
|
|
390
|
-
const references = [];
|
|
391
|
-
for (const e2eDir of featureE2eDirs) {
|
|
392
|
-
references.push({ path: `./${path.relative(cwd, e2eDir).replace(/\\/g, "/")}` });
|
|
393
|
-
}
|
|
394
|
-
references.push({ path: `./${sharedTestingRelPath.replace(/\\/g, "/")}` });
|
|
395
436
|
let rootTsConfig = { files: [], references: [] };
|
|
396
437
|
if (fs.existsSync(rootTsConfigPath)) {
|
|
397
438
|
try {
|
|
398
439
|
rootTsConfig = JSON.parse(fs.readFileSync(rootTsConfigPath, "utf-8"));
|
|
399
440
|
if (!rootTsConfig.references)
|
|
400
441
|
rootTsConfig.references = [];
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
rootTsConfig.references.push(ref);
|
|
404
|
-
}
|
|
442
|
+
if (!rootTsConfig.references.some((r) => r.path === "./tsconfig.spectra.json")) {
|
|
443
|
+
rootTsConfig.references.push({ path: "./tsconfig.spectra.json" });
|
|
405
444
|
}
|
|
406
445
|
}
|
|
407
|
-
catch {
|
|
446
|
+
catch {
|
|
447
|
+
rootTsConfig = { files: [], references: [{ path: "./tsconfig.spectra.json" }] };
|
|
448
|
+
}
|
|
408
449
|
}
|
|
409
450
|
else {
|
|
410
|
-
rootTsConfig = { files: [], references };
|
|
451
|
+
rootTsConfig = { files: [], references: [{ path: "./tsconfig.spectra.json" }] };
|
|
411
452
|
}
|
|
412
453
|
fs.writeFileSync(rootTsConfigPath, JSON.stringify(rootTsConfig, null, 2), "utf-8");
|
|
413
|
-
// 7. Generate Ambient Types
|
|
454
|
+
// 7. Generate Ambient Types in ROOT only
|
|
414
455
|
TypeGenerator.writeDeclarationFiles(cwd);
|
|
415
|
-
for (const e2eDir of featureE2eDirs) {
|
|
416
|
-
TypeGenerator.writeDeclarationFiles(e2eDir);
|
|
417
|
-
}
|
|
418
456
|
const sharedPoLine = `${sharedTestingRelPath}/page-objects`.padEnd(28, " ");
|
|
419
457
|
const sharedStepsLine = `${sharedTestingRelPath}/steps`.padEnd(28, " ");
|
|
420
458
|
const sharedActLine = `${sharedTestingRelPath}/actions`.padEnd(28, " ");
|
|
@@ -430,6 +468,10 @@ This workspace uses TestSpectra's **"Centralized Configuration, Distributed Impl
|
|
|
430
468
|
### Centralized Root Elements
|
|
431
469
|
- \`./spectra.config.ts\`: Single source of truth for runtime configurations (Base URL, Appium devices, browser targets, timeouts).
|
|
432
470
|
- \`./.testspectra/\`: Centralized app data folder containing driver caches (ChromeDriver, GeckoDriver, Appium), execution logs, and universal ambient types (\`.testspectra/types/\`).
|
|
471
|
+
- \`./tsconfig.spectra.json\`: Solution TypeScript entry point equipped with TestSpectra language service plugin.
|
|
472
|
+
- \`./tsconfig.spectra.web.json\`: Strongly-typed composite configuration for Web platform tests.
|
|
473
|
+
- \`./tsconfig.spectra.android.json\`: Strongly-typed composite configuration for Android platform tests.
|
|
474
|
+
- \`./tsconfig.spectra.ios.json\`: Strongly-typed composite configuration for iOS platform tests.
|
|
433
475
|
- \`./nx.json\`: Nx target defaults with execution caching and inputs.
|
|
434
476
|
- \`./pnpm-workspace.yaml\`: Monorepo package glob definitions.
|
|
435
477
|
- \`./tsconfig.json\`: Solution-style TypeScript orchestrator linking all distributed E2E projects and shared libraries.
|
|
@@ -449,8 +491,7 @@ ${featureE2eDirs.map((d) => {
|
|
|
449
491
|
return `- \`./${rel}\` (**${name}**, Nx Project: \`${e2eName}\`):
|
|
450
492
|
- \`specs/\`: Feature test cases (\`specs/<SuiteName>/<CaseId>/\` with \`web.test.ts\`, \`android.test.ts\`, \`ios.test.ts\`).
|
|
451
493
|
- \`page-objects/\`: Feature-specific Page Objects (e.g. \`LoginPage\`, \`ProductPage\`).
|
|
452
|
-
- \`project.json\`: Nx targets (\`e2e\`, \`type-check\`) supporting configurations (\`--configuration=android\`, \`--configuration=ios\`, \`--configuration=headless\`)
|
|
453
|
-
- \`tsconfig.json\`: Solution TypeScript config reference.`;
|
|
494
|
+
- \`project.json\`: Nx targets (\`e2e\`, \`type-check\`) supporting configurations (\`--configuration=android\`, \`--configuration=ios\`, \`--configuration=headless\`).`;
|
|
454
495
|
}).join("\n")}
|
|
455
496
|
|
|
456
497
|
---
|
package/dist/types/generator.js
CHANGED
|
@@ -10,91 +10,72 @@ const PLATFORM_HIERARCHY = {
|
|
|
10
10
|
export class TypeGenerator {
|
|
11
11
|
static getPageObjectsDirs(cwd) {
|
|
12
12
|
const dirs = [];
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
path.join(cur, "shared/testing/page-objects"),
|
|
24
|
-
path.join(cur, "shared/page-objects"),
|
|
25
|
-
path.join(cur, "packages/core/testing/page-objects"),
|
|
26
|
-
path.join(cur, "packages/shared/testing/page-objects"),
|
|
27
|
-
path.join(cur, "packages/testing/page-objects"),
|
|
28
|
-
path.join(cur, "core/testing/page-objects"),
|
|
29
|
-
];
|
|
30
|
-
for (const cand of candidates) {
|
|
31
|
-
if (fs.existsSync(cand) && !dirs.includes(cand))
|
|
32
|
-
dirs.push(cand);
|
|
13
|
+
function scanDir(dir, maxDepth) {
|
|
14
|
+
if (maxDepth <= 0 || !fs.existsSync(dir))
|
|
15
|
+
return;
|
|
16
|
+
const base = path.basename(dir);
|
|
17
|
+
if (base === "node_modules" || base === "dist" || base === ".git" || base === ".testspectra")
|
|
18
|
+
return;
|
|
19
|
+
if (base === "page-objects" || base === "pageobjects") {
|
|
20
|
+
if (!dirs.includes(dir))
|
|
21
|
+
dirs.push(dir);
|
|
22
|
+
return;
|
|
33
23
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (Array.isArray(parsed.references)) {
|
|
40
|
-
for (const ref of parsed.references) {
|
|
41
|
-
if (ref.path) {
|
|
42
|
-
const poPath1 = path.resolve(cur, ref.path, "page-objects");
|
|
43
|
-
const poPath2 = path.resolve(cur, ref.path, "pageobjects");
|
|
44
|
-
if (fs.existsSync(poPath1) && !dirs.includes(poPath1))
|
|
45
|
-
dirs.push(poPath1);
|
|
46
|
-
if (fs.existsSync(poPath2) && !dirs.includes(poPath2))
|
|
47
|
-
dirs.push(poPath2);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
24
|
+
try {
|
|
25
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
26
|
+
for (const entry of entries) {
|
|
27
|
+
if (entry.isDirectory()) {
|
|
28
|
+
scanDir(path.join(dir, entry.name), maxDepth - 1);
|
|
50
29
|
}
|
|
51
30
|
}
|
|
52
|
-
catch { }
|
|
53
31
|
}
|
|
54
|
-
|
|
32
|
+
catch { }
|
|
33
|
+
}
|
|
34
|
+
// 1. Scan from cwd downwards (finds all feature page-objects and shared page-objects)
|
|
35
|
+
scanDir(cwd, 6);
|
|
36
|
+
// 2. Also look upwards to monorepo root if called from a subfolder
|
|
37
|
+
let cur = cwd;
|
|
38
|
+
while (cur !== path.dirname(cur)) {
|
|
39
|
+
if (fs.existsSync(path.join(cur, "pnpm-workspace.yaml")) || fs.existsSync(path.join(cur, "nx.json")) || fs.existsSync(path.join(cur, "spectra.config.ts"))) {
|
|
40
|
+
scanDir(cur, 6);
|
|
55
41
|
break;
|
|
42
|
+
}
|
|
56
43
|
cur = path.dirname(cur);
|
|
57
44
|
}
|
|
58
45
|
return dirs;
|
|
59
46
|
}
|
|
60
47
|
static getEntityDirs(cwd, entityType) {
|
|
61
48
|
const dirs = [];
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
path.join(cur, "packages/testing", entityType),
|
|
73
|
-
path.join(cur, "core/testing", entityType),
|
|
74
|
-
];
|
|
75
|
-
for (const cand of candidates) {
|
|
76
|
-
if (fs.existsSync(cand) && !dirs.includes(cand))
|
|
77
|
-
dirs.push(cand);
|
|
49
|
+
function scanDir(dir, maxDepth) {
|
|
50
|
+
if (maxDepth <= 0 || !fs.existsSync(dir))
|
|
51
|
+
return;
|
|
52
|
+
const base = path.basename(dir);
|
|
53
|
+
if (base === "node_modules" || base === "dist" || base === ".git" || base === ".testspectra")
|
|
54
|
+
return;
|
|
55
|
+
if (base === entityType) {
|
|
56
|
+
if (!dirs.includes(dir))
|
|
57
|
+
dirs.push(dir);
|
|
58
|
+
return;
|
|
78
59
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (Array.isArray(parsed.references)) {
|
|
85
|
-
for (const ref of parsed.references) {
|
|
86
|
-
if (ref.path) {
|
|
87
|
-
const entPath = path.resolve(cur, ref.path, entityType);
|
|
88
|
-
if (fs.existsSync(entPath) && !dirs.includes(entPath))
|
|
89
|
-
dirs.push(entPath);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
60
|
+
try {
|
|
61
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
62
|
+
for (const entry of entries) {
|
|
63
|
+
if (entry.isDirectory()) {
|
|
64
|
+
scanDir(path.join(dir, entry.name), maxDepth - 1);
|
|
92
65
|
}
|
|
93
66
|
}
|
|
94
|
-
catch { }
|
|
95
67
|
}
|
|
96
|
-
|
|
68
|
+
catch { }
|
|
69
|
+
}
|
|
70
|
+
// 1. Scan from cwd downwards
|
|
71
|
+
scanDir(cwd, 6);
|
|
72
|
+
// 2. Look upwards to monorepo root if called from a subfolder
|
|
73
|
+
let cur = cwd;
|
|
74
|
+
while (cur !== path.dirname(cur)) {
|
|
75
|
+
if (fs.existsSync(path.join(cur, "pnpm-workspace.yaml")) || fs.existsSync(path.join(cur, "nx.json")) || fs.existsSync(path.join(cur, "spectra.config.ts"))) {
|
|
76
|
+
scanDir(cur, 6);
|
|
97
77
|
break;
|
|
78
|
+
}
|
|
98
79
|
cur = path.dirname(cur);
|
|
99
80
|
}
|
|
100
81
|
return dirs;
|
|
@@ -207,8 +188,28 @@ export class TypeGenerator {
|
|
|
207
188
|
}
|
|
208
189
|
}
|
|
209
190
|
}
|
|
210
|
-
// 2.
|
|
211
|
-
content += `\ninterface
|
|
191
|
+
// 2. Built-in Spectra Static Methods & Custom Actions
|
|
192
|
+
content += `\ninterface SpectraStaticInstance {\n`;
|
|
193
|
+
content += ` get(target: any): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
194
|
+
content += ` getAll(selector: string): import('@testspectra/matchers').MultiElementRunner;\n`;
|
|
195
|
+
content += ` navigate(url: string): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
196
|
+
content += ` back(): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
197
|
+
content += ` refresh(): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
198
|
+
content += ` click(target: any, textOrOptions?: string | import('@testspectra/matchers').ClickOptions): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
199
|
+
content += ` doubleClick(target: any, textOrOptions?: string | import('@testspectra/matchers').ClickOptions): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
200
|
+
content += ` longPress(target: any, options?: import('@testspectra/matchers').LongPressOptions | number): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
201
|
+
content += ` type(target: any, value: string, options?: import('@testspectra/matchers').TypeOptions): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
202
|
+
content += ` clear(target: any): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
203
|
+
content += ` select(target: any, value: string): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
204
|
+
content += ` hover(target: any): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
205
|
+
content += ` pressKey(key: import('@testspectra/matchers').KeyOption | string): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
206
|
+
content += ` dragDrop(sourceTarget: any, destTarget: any): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
207
|
+
content += ` scroll(options?: import('@testspectra/matchers').ScrollOptions): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
208
|
+
content += ` swipe(options: import('@testspectra/matchers').SwipeOptions): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
209
|
+
content += ` wait(durationMs: number): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
210
|
+
content += ` waitForElement(target: any, timeoutMs?: number): import('@testspectra/matchers').SingleElementRunner;\n`;
|
|
211
|
+
content += `}\n\n`;
|
|
212
|
+
content += `interface TestSpectraCustomActions {\n`;
|
|
212
213
|
const declaredActions = new Set();
|
|
213
214
|
for (const actionsDir of actionsDirs) {
|
|
214
215
|
if (!fs.existsSync(actionsDir))
|
|
@@ -259,6 +260,7 @@ export class TypeGenerator {
|
|
|
259
260
|
}
|
|
260
261
|
}
|
|
261
262
|
content += `}\n`;
|
|
263
|
+
content += `type TestSpectraActions = SpectraStaticInstance & TestSpectraCustomActions;\n`;
|
|
262
264
|
content += `declare const Spectra: TestSpectraActions;\n\n`;
|
|
263
265
|
// 3. Shared Steps Global Interface (Local + Shared)
|
|
264
266
|
content += `interface TestSpectraSteps {\n`;
|
package/package.json
CHANGED
|
@@ -1,20 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"types": ["node", "@wdio/globals/types", "@wdio/mocha-framework"],
|
|
7
|
-
"plugins": [
|
|
8
|
-
{ "name": "@testspectra/cli" }
|
|
9
|
-
],
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"strict": true,
|
|
12
|
-
"noEmit": true
|
|
13
|
-
},
|
|
14
2
|
"files": [],
|
|
15
3
|
"references": [
|
|
16
|
-
{ "path": "./tsconfig.
|
|
17
|
-
{ "path": "./tsconfig.android.json" },
|
|
18
|
-
{ "path": "./tsconfig.ios.json" }
|
|
4
|
+
{ "path": "./tsconfig.spectra.json" }
|
|
19
5
|
]
|
|
20
6
|
}
|
|
@@ -3,18 +3,17 @@
|
|
|
3
3
|
"target": "ES2022",
|
|
4
4
|
"module": "NodeNext",
|
|
5
5
|
"moduleResolution": "NodeNext",
|
|
6
|
-
"types": ["node", "@wdio/globals/types", "@wdio/mocha-framework"],
|
|
7
|
-
"plugins": [
|
|
8
|
-
{ "name": "@testspectra/cli" }
|
|
9
|
-
],
|
|
10
6
|
"skipLibCheck": true,
|
|
11
7
|
"strict": true,
|
|
12
|
-
"noEmit": true
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"plugins": [
|
|
10
|
+
{ "name": "@testspectra/cli" }
|
|
11
|
+
]
|
|
13
12
|
},
|
|
14
13
|
"files": [],
|
|
15
14
|
"references": [
|
|
16
|
-
{ "path": "./tsconfig.web.json" },
|
|
17
|
-
{ "path": "./tsconfig.android.json" },
|
|
18
|
-
{ "path": "./tsconfig.ios.json" }
|
|
15
|
+
{ "path": "./tsconfig.spectra.web.json" },
|
|
16
|
+
{ "path": "./tsconfig.spectra.android.json" },
|
|
17
|
+
{ "path": "./tsconfig.spectra.ios.json" }
|
|
19
18
|
]
|
|
20
19
|
}
|
|
@@ -25,11 +25,10 @@
|
|
|
25
25
|
"type-check": {
|
|
26
26
|
"executor": "nx:run-commands",
|
|
27
27
|
"options": {
|
|
28
|
-
"command": "tsc -b",
|
|
29
|
-
"cwd": "
|
|
28
|
+
"command": "tsc -b tsconfig.spectra.json",
|
|
29
|
+
"cwd": "."
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
|
-
"tags": ["scope:auth", "type:e2e"]
|
|
34
|
-
"implicitDependencies": ["@testspectra/feature-auth"]
|
|
33
|
+
"tags": ["scope:auth", "type:e2e"]
|
|
35
34
|
}
|
|
@@ -25,11 +25,10 @@
|
|
|
25
25
|
"type-check": {
|
|
26
26
|
"executor": "nx:run-commands",
|
|
27
27
|
"options": {
|
|
28
|
-
"command": "tsc -b",
|
|
29
|
-
"cwd": "
|
|
28
|
+
"command": "tsc -b tsconfig.spectra.json",
|
|
29
|
+
"cwd": "."
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
|
-
"tags": ["scope:catalog", "type:e2e"]
|
|
34
|
-
"implicitDependencies": ["@testspectra/feature-catalog"]
|
|
33
|
+
"tags": ["scope:catalog", "type:e2e"]
|
|
35
34
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export default class NavigationBar {
|
|
2
|
-
static get logo() {
|
|
2
|
+
static get logo(): ChainablePromiseElement {
|
|
3
3
|
return $('header .logo');
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
static get profileMenu() {
|
|
6
|
+
static get profileMenu(): ChainablePromiseElement {
|
|
7
7
|
return $('header .user-profile');
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"composite": true,
|
|
7
|
+
"noEmit": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"types": ["node", "@wdio/globals/types", "@wdio/mocha-framework"]
|
|
11
|
+
},
|
|
12
|
+
"include": [
|
|
13
|
+
".testspectra/types/android.d.ts",
|
|
14
|
+
".testspectra/types/fixtures.d.ts",
|
|
15
|
+
"spectra.config.ts",
|
|
16
|
+
"modules/**/e2e/**/*.ts",
|
|
17
|
+
"packages/**/e2e/**/*.ts",
|
|
18
|
+
"shared/testing/**/*.ts"
|
|
19
|
+
],
|
|
20
|
+
"exclude": [
|
|
21
|
+
"node_modules",
|
|
22
|
+
"dist",
|
|
23
|
+
"**/page-objects/**/web.ts",
|
|
24
|
+
"**/page-objects/**/ios.ts",
|
|
25
|
+
"**/steps/**/web.step.ts",
|
|
26
|
+
"**/steps/**/ios.step.ts",
|
|
27
|
+
"**/actions/**/web.action.ts",
|
|
28
|
+
"**/actions/**/ios.action.ts",
|
|
29
|
+
"**/global-hooks/**/web.hook.ts",
|
|
30
|
+
"**/global-hooks/**/ios.hook.ts",
|
|
31
|
+
"**/specs/**/hooks/**/web.hook.ts",
|
|
32
|
+
"**/specs/**/hooks/**/ios.hook.ts",
|
|
33
|
+
"**/specs/**/web.test.ts",
|
|
34
|
+
"**/specs/**/ios.test.ts"
|
|
35
|
+
]
|
|
36
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"composite": true,
|
|
7
|
+
"noEmit": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"types": ["node", "@wdio/globals/types", "@wdio/mocha-framework"]
|
|
11
|
+
},
|
|
12
|
+
"include": [
|
|
13
|
+
".testspectra/types/ios.d.ts",
|
|
14
|
+
".testspectra/types/fixtures.d.ts",
|
|
15
|
+
"spectra.config.ts",
|
|
16
|
+
"modules/**/e2e/**/*.ts",
|
|
17
|
+
"packages/**/e2e/**/*.ts",
|
|
18
|
+
"shared/testing/**/*.ts"
|
|
19
|
+
],
|
|
20
|
+
"exclude": [
|
|
21
|
+
"node_modules",
|
|
22
|
+
"dist",
|
|
23
|
+
"**/page-objects/**/web.ts",
|
|
24
|
+
"**/page-objects/**/android.ts",
|
|
25
|
+
"**/steps/**/web.step.ts",
|
|
26
|
+
"**/steps/**/android.step.ts",
|
|
27
|
+
"**/actions/**/web.action.ts",
|
|
28
|
+
"**/actions/**/android.action.ts",
|
|
29
|
+
"**/global-hooks/**/web.hook.ts",
|
|
30
|
+
"**/global-hooks/**/android.hook.ts",
|
|
31
|
+
"**/specs/**/hooks/**/web.hook.ts",
|
|
32
|
+
"**/specs/**/hooks/**/android.hook.ts",
|
|
33
|
+
"**/specs/**/web.test.ts",
|
|
34
|
+
"**/specs/**/android.test.ts"
|
|
35
|
+
]
|
|
36
|
+
}
|
|
@@ -3,18 +3,17 @@
|
|
|
3
3
|
"target": "ES2022",
|
|
4
4
|
"module": "NodeNext",
|
|
5
5
|
"moduleResolution": "NodeNext",
|
|
6
|
-
"types": ["node", "@wdio/globals/types", "@wdio/mocha-framework"],
|
|
7
|
-
"plugins": [
|
|
8
|
-
{ "name": "@testspectra/cli" }
|
|
9
|
-
],
|
|
10
6
|
"skipLibCheck": true,
|
|
11
7
|
"strict": true,
|
|
12
|
-
"noEmit": true
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"plugins": [
|
|
10
|
+
{ "name": "@testspectra/cli" }
|
|
11
|
+
]
|
|
13
12
|
},
|
|
14
13
|
"files": [],
|
|
15
14
|
"references": [
|
|
16
|
-
{ "path": "./tsconfig.web.json" },
|
|
17
|
-
{ "path": "./tsconfig.android.json" },
|
|
18
|
-
{ "path": "./tsconfig.ios.json" }
|
|
15
|
+
{ "path": "./tsconfig.spectra.web.json" },
|
|
16
|
+
{ "path": "./tsconfig.spectra.android.json" },
|
|
17
|
+
{ "path": "./tsconfig.spectra.ios.json" }
|
|
19
18
|
]
|
|
20
19
|
}
|