@wp-tester/cli 0.0.5 → 0.1.0
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/cli/cli.js +16 -2
- package/dist/cli/cli.js.map +1 -1
- package/dist/commands/config/index.d.ts +1 -1
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +11 -3
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/config/validate.d.ts +45 -1
- package/dist/commands/config/validate.d.ts.map +1 -1
- package/dist/commands/config/validate.js +187 -18
- package/dist/commands/config/validate.js.map +1 -1
- package/dist/commands/config/validate.spec.d.ts +2 -0
- package/dist/commands/config/validate.spec.d.ts.map +1 -0
- package/dist/commands/config/validate.spec.js +89 -0
- package/dist/commands/config/validate.spec.js.map +1 -0
- package/dist/commands/test/index.d.ts +4 -1
- package/dist/commands/test/index.d.ts.map +1 -1
- package/dist/commands/test/index.js +34 -4
- package/dist/commands/test/index.js.map +1 -1
- package/dist/commands/test/runner.d.ts +23 -1
- package/dist/commands/test/runner.d.ts.map +1 -1
- package/dist/commands/test/runner.js +101 -52
- package/dist/commands/test/runner.js.map +1 -1
- package/dist/commands/test/watcher.d.ts +6 -0
- package/dist/commands/test/watcher.d.ts.map +1 -0
- package/dist/commands/test/watcher.js +173 -0
- package/dist/commands/test/watcher.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -5
package/dist/cli/cli.js
CHANGED
|
@@ -28,7 +28,6 @@ void yargs(hideBin(process.argv))
|
|
|
28
28
|
alias: "c",
|
|
29
29
|
describe: "Path to wp-tester.json config file",
|
|
30
30
|
type: "string",
|
|
31
|
-
default: "./wp-tester.json",
|
|
32
31
|
});
|
|
33
32
|
}, async (argv) => {
|
|
34
33
|
console.log(logo());
|
|
@@ -40,13 +39,28 @@ void yargs(hideBin(process.argv))
|
|
|
40
39
|
alias: "c",
|
|
41
40
|
describe: "Path to wp-tester.json config file",
|
|
42
41
|
type: "string",
|
|
43
|
-
default: "./wp-tester.json",
|
|
44
42
|
})
|
|
45
43
|
.option("test", {
|
|
46
44
|
alias: "t",
|
|
47
45
|
describe: "Type of test to run (wp, plugin, theme, or phpunit)",
|
|
48
46
|
type: "string",
|
|
49
47
|
choices: ["wp", "plugin", "theme", "phpunit"],
|
|
48
|
+
})
|
|
49
|
+
.option("watch", {
|
|
50
|
+
alias: "w",
|
|
51
|
+
describe: "Watch for file changes and re-run tests automatically",
|
|
52
|
+
type: "boolean",
|
|
53
|
+
default: false,
|
|
54
|
+
})
|
|
55
|
+
.option("passWithNoTests", {
|
|
56
|
+
describe: "Allow the test suite to pass when no tests are executed",
|
|
57
|
+
type: "boolean",
|
|
58
|
+
default: false,
|
|
59
|
+
})
|
|
60
|
+
.option("failed-only", {
|
|
61
|
+
describe: "Only display failed tests in output",
|
|
62
|
+
type: "boolean",
|
|
63
|
+
default: false,
|
|
50
64
|
});
|
|
51
65
|
}, async (argv) => {
|
|
52
66
|
console.log(logo());
|
package/dist/cli/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli/cli.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,KAAK,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;KAC9B,mBAAmB,CAAC;IACnB,YAAY,EAAE,IAAI;CACnB,CAAC;KACD,UAAU,CAAC,WAAW,CAAC;KACvB,KAAK,CAAC,wBAAwB,CAAC;KAC/B,OAAO,CACN,OAAO,EACP,+BAA+B,EAC/B,GAAG,EAAE,GAAE,CAAC,EACR,KAAK,IAAI,EAAE;IACT,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACpB,MAAM,YAAY,EAAE,CAAC;AACvB,CAAC,CACF;KACA,OAAO,CACN,iBAAiB,EACjB,gCAAgC,EAChC,CAAC,KAAK,EAAE,EAAE;IACR,OAAO,KAAK;SACT,UAAU,CAAC,QAAQ,EAAE;QACpB,QAAQ,EAAE,mBAAmB;QAC7B,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli/cli.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,KAAK,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;KAC9B,mBAAmB,CAAC;IACnB,YAAY,EAAE,IAAI;CACnB,CAAC;KACD,UAAU,CAAC,WAAW,CAAC;KACvB,KAAK,CAAC,wBAAwB,CAAC;KAC/B,OAAO,CACN,OAAO,EACP,+BAA+B,EAC/B,GAAG,EAAE,GAAE,CAAC,EACR,KAAK,IAAI,EAAE;IACT,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACpB,MAAM,YAAY,EAAE,CAAC;AACvB,CAAC,CACF;KACA,OAAO,CACN,iBAAiB,EACjB,gCAAgC,EAChC,CAAC,KAAK,EAAE,EAAE;IACR,OAAO,KAAK;SACT,UAAU,CAAC,QAAQ,EAAE;QACpB,QAAQ,EAAE,mBAAmB;QAC7B,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,CAAC,UAAU,EAAE,GAAG,WAAW,CAAU;QAC9C,YAAY,EAAE,IAAI;KACnB,CAAC;SACD,MAAM,CAAC,QAAQ,EAAE;QAChB,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,oCAAoC;QAC9C,IAAI,EAAE,QAAQ;KACf,CAAC,CAAC;AACP,CAAC,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;IACb,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACpB,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC,CACF;KACA,OAAO,CACN,MAAM,EACN,WAAW,EACX,CAAC,KAAK,EAAE,EAAE;IACR,OAAO,KAAK;SACT,MAAM,CAAC,QAAQ,EAAE;QAChB,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,oCAAoC;QAC9C,IAAI,EAAE,QAAQ;KACf,CAAC;SACD,MAAM,CAAC,MAAM,EAAE;QACd,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,qDAAqD;QAC/D,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAU;KACvD,CAAC;SACD,MAAM,CAAC,OAAO,EAAE;QACf,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,uDAAuD;QACjE,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,KAAK;KACf,CAAC;SACD,MAAM,CAAC,iBAAiB,EAAE;QACzB,QAAQ,EAAE,yDAAyD;QACnE,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,KAAK;KACf,CAAC;SACD,MAAM,CAAC,aAAa,EAAE;QACrB,QAAQ,EAAE,qCAAqC;QAC/C,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;AACP,CAAC,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;IACb,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACpB,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC,CACF;KACA,aAAa,CAAC,CAAC,EAAE,mEAAmE,CAAC;KACrF,IAAI,EAAE;KACN,OAAO,EAAE;KACT,KAAK,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"AAMA,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,aAAa,GAAU,MAAM,UAAU,KAAG,OAAO,CAAC,IAAI,CAmBlE,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { optionNames } from '@wp-tester/config';
|
|
2
|
-
import { validateConfig } from './validate.js';
|
|
3
2
|
import { updateConfigOption } from './option.js';
|
|
4
3
|
import * as clack from '../../cli/theme.js';
|
|
4
|
+
import { validateConfig, generateConfigSummary, printConfigSummary } from './validate.js';
|
|
5
|
+
import pc from 'picocolors';
|
|
5
6
|
export const configHandler = async (argv) => {
|
|
6
|
-
const { action, config } = argv;
|
|
7
|
+
const { action, config = './wp-tester.json' } = argv;
|
|
7
8
|
if (action === "validate") {
|
|
8
|
-
await validateConfig(config);
|
|
9
|
+
const validatedConfig = await validateConfig(config);
|
|
10
|
+
if (!validatedConfig) {
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
console.log(pc.green(pc.bold("✓ Configuration is valid")));
|
|
14
|
+
// Display configuration summary
|
|
15
|
+
const summary = generateConfigSummary(validatedConfig);
|
|
16
|
+
printConfigSummary(summary);
|
|
9
17
|
}
|
|
10
18
|
else if (action && optionNames.includes(action)) {
|
|
11
19
|
await updateConfigOption(action);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAmB,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAmB,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,KAAK,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,MAAM,YAAY,CAAC;AAO5B,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,IAAgB,EAAiB,EAAE;IACrE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,kBAAkB,EAAE,GAAG,IAAI,CAAC;IAErD,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;QAC1B,MAAM,eAAe,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;QACrD,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC;QAE3D,gCAAgC;QAChC,MAAM,OAAO,GAAG,qBAAqB,CAAC,eAAe,CAAC,CAAC;QACvD,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;SAAM,IAAI,MAAM,IAAI,WAAW,CAAC,QAAQ,CAAC,MAAoB,CAAC,EAAE,CAAC;QAChE,MAAM,kBAAkB,CAAC,MAAoB,CAAC,CAAC;IACjD,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,KAAK,CAAC,0BAA0B,MAAM,IAAI,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -1,2 +1,46 @@
|
|
|
1
|
-
|
|
1
|
+
import { type ErrorObject } from "ajv";
|
|
2
|
+
import { type WPTesterConfig, type Tests } from "@wp-tester/config";
|
|
3
|
+
/**
|
|
4
|
+
* Summary of enabled test suites
|
|
5
|
+
*/
|
|
6
|
+
export interface TestSuiteSummary {
|
|
7
|
+
name: string;
|
|
8
|
+
label: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Configuration summary for display
|
|
12
|
+
*/
|
|
13
|
+
export interface ConfigSummary {
|
|
14
|
+
activeEnvironments: number;
|
|
15
|
+
skippedEnvironments: number;
|
|
16
|
+
testSuites: TestSuiteSummary[];
|
|
17
|
+
matrixCombinations: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get a list of enabled test suites from the tests configuration
|
|
21
|
+
*/
|
|
22
|
+
export declare function getEnabledTestSuites(tests: Tests): TestSuiteSummary[];
|
|
23
|
+
/**
|
|
24
|
+
* Generate a configuration summary from a valid config
|
|
25
|
+
*/
|
|
26
|
+
export declare function generateConfigSummary(config: WPTesterConfig): ConfigSummary;
|
|
27
|
+
/**
|
|
28
|
+
* Print the configuration summary
|
|
29
|
+
*/
|
|
30
|
+
export declare function printConfigSummary(summary: ConfigSummary): void;
|
|
31
|
+
interface ValidationErrorDisplay {
|
|
32
|
+
message: string;
|
|
33
|
+
hint: string;
|
|
34
|
+
docsUrl: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Format a validation error into a user-friendly message with documentation link
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatValidationError(error: ErrorObject): ValidationErrorDisplay;
|
|
40
|
+
/**
|
|
41
|
+
* Validates config and prints errors if invalid.
|
|
42
|
+
* Returns the validated config if valid, null otherwise.
|
|
43
|
+
*/
|
|
44
|
+
export declare function validateConfig(configPath: string): Promise<WPTesterConfig | null>;
|
|
45
|
+
export {};
|
|
2
46
|
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/commands/config/validate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/commands/config/validate.ts"],"names":[],"mappings":"AACA,OAAY,EAAE,KAAK,WAAW,EAAE,MAAM,KAAK,CAAC;AAE5C,OAAO,EAAsC,KAAK,cAAc,EAAE,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAGxG;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,KAAK,GAAG,gBAAgB,EAAE,CAqBrE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,GAAG,aAAa,CAY3E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAsB/D;AAED,UAAU,sBAAsB;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AA+BD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,WAAW,GAAG,sBAAsB,CA+DhF;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAkEvF"}
|
|
@@ -1,12 +1,160 @@
|
|
|
1
1
|
import { readFile } from 'fs/promises';
|
|
2
|
-
import path from 'path';
|
|
3
2
|
import Ajv from "ajv";
|
|
4
3
|
import pc from "picocolors";
|
|
5
|
-
import { getSchemaPath } from "@wp-tester/config";
|
|
4
|
+
import { getSchemaPath, normalizeConfigPath } from "@wp-tester/config";
|
|
5
|
+
import * as clack from "../../cli/theme.js";
|
|
6
|
+
/**
|
|
7
|
+
* Get a list of enabled test suites from the tests configuration
|
|
8
|
+
*/
|
|
9
|
+
export function getEnabledTestSuites(tests) {
|
|
10
|
+
const suites = [];
|
|
11
|
+
if (tests.wp) {
|
|
12
|
+
suites.push({ name: 'wp', label: 'WordPress' });
|
|
13
|
+
}
|
|
14
|
+
if (tests.plugin) {
|
|
15
|
+
suites.push({ name: 'plugin', label: `Plugin (${tests.plugin})` });
|
|
16
|
+
}
|
|
17
|
+
if (tests.theme) {
|
|
18
|
+
suites.push({ name: 'theme', label: `Theme (${tests.theme})` });
|
|
19
|
+
}
|
|
20
|
+
if (tests.phpunit) {
|
|
21
|
+
const modeLabel = tests.phpunit.testMode === 'integration' ? 'integration' : 'unit';
|
|
22
|
+
suites.push({ name: 'phpunit', label: `PHPUnit (${modeLabel})` });
|
|
23
|
+
}
|
|
24
|
+
return suites;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Generate a configuration summary from a valid config
|
|
28
|
+
*/
|
|
29
|
+
export function generateConfigSummary(config) {
|
|
30
|
+
const activeEnvironments = config.environments.filter(env => !env.skip).length;
|
|
31
|
+
const skippedEnvironments = config.environments.filter(env => env.skip).length;
|
|
32
|
+
const testSuites = getEnabledTestSuites(config.tests);
|
|
33
|
+
const matrixCombinations = activeEnvironments * testSuites.length;
|
|
34
|
+
return {
|
|
35
|
+
activeEnvironments,
|
|
36
|
+
skippedEnvironments,
|
|
37
|
+
testSuites,
|
|
38
|
+
matrixCombinations,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Print the configuration summary
|
|
43
|
+
*/
|
|
44
|
+
export function printConfigSummary(summary) {
|
|
45
|
+
const lines = [];
|
|
46
|
+
// Environment count
|
|
47
|
+
if (summary.skippedEnvironments > 0) {
|
|
48
|
+
lines.push(`Environments: ${pc.cyan(String(summary.activeEnvironments))} active, ${pc.yellow(String(summary.skippedEnvironments))} skipped`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
lines.push(`Environments: ${pc.cyan(String(summary.activeEnvironments))}`);
|
|
52
|
+
}
|
|
53
|
+
// Test suites
|
|
54
|
+
if (summary.testSuites.length > 0) {
|
|
55
|
+
const suiteLabels = summary.testSuites.map(s => s.label).join(', ');
|
|
56
|
+
lines.push(`Test suites: ${pc.cyan(suiteLabels)}`);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
lines.push(`Test suites: ${pc.dim('None configured')}`);
|
|
60
|
+
}
|
|
61
|
+
// Matrix combinations
|
|
62
|
+
lines.push(`Total runs: ${pc.cyan(String(summary.matrixCombinations))}`);
|
|
63
|
+
clack.note(lines.join('\n'), 'Configuration Summary');
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Known top-level configuration properties that have their own documentation sections.
|
|
67
|
+
* These correspond to the main headings in the configuration.md file.
|
|
68
|
+
*/
|
|
69
|
+
const DOCUMENTED_PROPERTIES = new Set(['environments', 'tests', 'reporters']);
|
|
70
|
+
/**
|
|
71
|
+
* Get the documentation URL for a configuration property.
|
|
72
|
+
* Returns a full URL pointing to the relevant documentation section.
|
|
73
|
+
*
|
|
74
|
+
* For nested properties (e.g., 'tests.wp'), we link to the parent section.
|
|
75
|
+
* For unknown/unrecognized properties, pass 'unknown' to link to configuration options.
|
|
76
|
+
*/
|
|
77
|
+
function getDocumentationUrl(propertyName) {
|
|
78
|
+
const baseUrl = 'https://bgrgicak.github.io/wp-tester/#/configuration';
|
|
79
|
+
if (!propertyName) {
|
|
80
|
+
return baseUrl; // Link to top of page
|
|
81
|
+
}
|
|
82
|
+
// Check if this is a known top-level property with its own section
|
|
83
|
+
if (DOCUMENTED_PROPERTIES.has(propertyName)) {
|
|
84
|
+
return `${baseUrl}?id=${propertyName.toLowerCase()}`;
|
|
85
|
+
}
|
|
86
|
+
// For all other properties, link to the configuration options section
|
|
87
|
+
return `${baseUrl}?id=configuration-options`;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Format a validation error into a user-friendly message with documentation link
|
|
91
|
+
*/
|
|
92
|
+
export function formatValidationError(error) {
|
|
93
|
+
const instancePath = error.instancePath || "/";
|
|
94
|
+
switch (error.keyword) {
|
|
95
|
+
case 'additionalProperties': {
|
|
96
|
+
const unknownProp = error.params?.additionalProperty;
|
|
97
|
+
return {
|
|
98
|
+
message: `Unknown property: ${pc.bold(unknownProp)}`,
|
|
99
|
+
hint: 'This property is not recognized. Check for typos in your property names.',
|
|
100
|
+
docsUrl: getDocumentationUrl('unknown')
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
case 'required': {
|
|
104
|
+
const missingProp = error.params?.missingProperty;
|
|
105
|
+
return {
|
|
106
|
+
message: `Missing required property: ${pc.bold(missingProp)}`,
|
|
107
|
+
hint: `The "${missingProp}" property is required in your configuration.`,
|
|
108
|
+
docsUrl: getDocumentationUrl(missingProp)
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
case 'enum': {
|
|
112
|
+
const allowedValues = error.params?.allowedValues || [];
|
|
113
|
+
// Extract the root property from the path
|
|
114
|
+
const rootProperty = instancePath.split('/')[1] || '';
|
|
115
|
+
return {
|
|
116
|
+
message: `Invalid value at ${pc.bold(instancePath)}`,
|
|
117
|
+
hint: `Allowed values: ${allowedValues.map(v => pc.cyan(v)).join(', ')}`,
|
|
118
|
+
docsUrl: getDocumentationUrl(rootProperty)
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
case 'type': {
|
|
122
|
+
const expectedType = error.params?.type;
|
|
123
|
+
// Extract the root property from the path (e.g., /tests/wp -> tests)
|
|
124
|
+
const rootProperty = instancePath.split('/')[1] || '';
|
|
125
|
+
return {
|
|
126
|
+
message: `Type error at ${pc.bold(instancePath)}`,
|
|
127
|
+
hint: `Expected type: ${pc.cyan(expectedType)}`,
|
|
128
|
+
docsUrl: getDocumentationUrl(rootProperty)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
case 'minItems': {
|
|
132
|
+
const limit = error.params?.limit;
|
|
133
|
+
// Extract the root property from the path
|
|
134
|
+
const rootProperty = instancePath.split('/')[1] || '';
|
|
135
|
+
return {
|
|
136
|
+
message: `Array at ${pc.bold(instancePath)} is too short`,
|
|
137
|
+
hint: `Minimum items required: ${pc.cyan(String(limit))}`,
|
|
138
|
+
docsUrl: getDocumentationUrl(rootProperty)
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
default: {
|
|
142
|
+
return {
|
|
143
|
+
message: `${instancePath}: ${error.message || 'validation error'}`,
|
|
144
|
+
hint: error.params ? JSON.stringify(error.params) : '',
|
|
145
|
+
docsUrl: getDocumentationUrl('')
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Validates config and prints errors if invalid.
|
|
152
|
+
* Returns the validated config if valid, null otherwise.
|
|
153
|
+
*/
|
|
6
154
|
export async function validateConfig(configPath) {
|
|
7
155
|
try {
|
|
8
|
-
// Resolve config path relative to cwd
|
|
9
|
-
const resolvedConfigPath =
|
|
156
|
+
// Resolve config path relative to cwd and normalize (handles directory paths)
|
|
157
|
+
const resolvedConfigPath = normalizeConfigPath(configPath);
|
|
10
158
|
const config = JSON.parse(await readFile(resolvedConfigPath, "utf-8"));
|
|
11
159
|
// Get schema path from config package
|
|
12
160
|
const schemaPath = getSchemaPath();
|
|
@@ -16,29 +164,50 @@ export async function validateConfig(configPath) {
|
|
|
16
164
|
const validate = ajv.compile(schema);
|
|
17
165
|
const valid = validate(config);
|
|
18
166
|
if (!valid) {
|
|
19
|
-
console.error(pc.red(pc.bold("Configuration validation failed:")));
|
|
20
|
-
console.error("");
|
|
21
167
|
if (validate.errors) {
|
|
168
|
+
// Group errors by documentation URL to show one link per error type
|
|
169
|
+
const errorsByUrl = new Map();
|
|
22
170
|
for (const error of validate.errors) {
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
171
|
+
const formatted = formatValidationError(error);
|
|
172
|
+
const existing = errorsByUrl.get(formatted.docsUrl) || [];
|
|
173
|
+
existing.push(formatted);
|
|
174
|
+
errorsByUrl.set(formatted.docsUrl, existing);
|
|
175
|
+
}
|
|
176
|
+
// Display all errors with their hints
|
|
177
|
+
for (const [_, errors] of errorsByUrl) {
|
|
178
|
+
for (const error of errors) {
|
|
179
|
+
clack.log.error(`Configuration validation failed: ${error.message}`);
|
|
180
|
+
if (error.hint) {
|
|
181
|
+
clack.log.info(pc.dim(error.hint));
|
|
182
|
+
}
|
|
28
183
|
}
|
|
29
184
|
}
|
|
185
|
+
// Show documentation links (unique URLs only)
|
|
186
|
+
if (errorsByUrl.size > 0) {
|
|
187
|
+
const urls = Array.from(errorsByUrl.keys());
|
|
188
|
+
clack.log.info(pc.dim(`Learn more: ${urls.join(', ')}`));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
// Check for skipped environments and display info
|
|
194
|
+
const typedConfig = config;
|
|
195
|
+
if (typedConfig.environments) {
|
|
196
|
+
const skippedEnvs = typedConfig.environments.filter(env => env.skip === true);
|
|
197
|
+
if (skippedEnvs.length > 0) {
|
|
198
|
+
for (const env of skippedEnvs) {
|
|
199
|
+
const envName = env.name || 'Unnamed environment';
|
|
200
|
+
clack.log.warn(pc.yellow(` ${envName} (Skipped)`));
|
|
201
|
+
}
|
|
30
202
|
}
|
|
31
|
-
console.error("");
|
|
32
|
-
process.exit(1);
|
|
33
203
|
}
|
|
34
|
-
|
|
204
|
+
return typedConfig;
|
|
35
205
|
}
|
|
36
206
|
catch (error) {
|
|
37
207
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
process.exit(1);
|
|
208
|
+
clack.log.error("Validation error:");
|
|
209
|
+
clack.log.error(message);
|
|
210
|
+
return null;
|
|
42
211
|
}
|
|
43
212
|
}
|
|
44
213
|
//# sourceMappingURL=validate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/commands/config/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/commands/config/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.spec.d.ts","sourceRoot":"","sources":["../../../src/commands/config/validate.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { formatValidationError } from './validate.js';
|
|
3
|
+
describe('formatValidationError', () => {
|
|
4
|
+
it('should format additionalProperties error', () => {
|
|
5
|
+
const error = {
|
|
6
|
+
keyword: 'additionalProperties',
|
|
7
|
+
instancePath: '',
|
|
8
|
+
schemaPath: '#/additionalProperties',
|
|
9
|
+
params: { additionalProperty: 'reportering' },
|
|
10
|
+
message: 'must NOT have additional properties'
|
|
11
|
+
};
|
|
12
|
+
const result = formatValidationError(error);
|
|
13
|
+
expect(result.message).toContain('Unknown property');
|
|
14
|
+
expect(result.message).toContain('reportering');
|
|
15
|
+
expect(result.hint).toContain('not recognized');
|
|
16
|
+
expect(result.docsUrl).toBe('https://bgrgicak.github.io/wp-tester/#/configuration?id=configuration-options');
|
|
17
|
+
});
|
|
18
|
+
it('should format required property error', () => {
|
|
19
|
+
const error = {
|
|
20
|
+
keyword: 'required',
|
|
21
|
+
instancePath: '',
|
|
22
|
+
schemaPath: '#/required',
|
|
23
|
+
params: { missingProperty: 'tests' },
|
|
24
|
+
message: 'must have required property \'tests\''
|
|
25
|
+
};
|
|
26
|
+
const result = formatValidationError(error);
|
|
27
|
+
expect(result.message).toContain('Missing required property');
|
|
28
|
+
expect(result.message).toContain('tests');
|
|
29
|
+
expect(result.hint).toContain('required');
|
|
30
|
+
expect(result.docsUrl).toBe('https://bgrgicak.github.io/wp-tester/#/configuration?id=tests');
|
|
31
|
+
});
|
|
32
|
+
it('should format enum error', () => {
|
|
33
|
+
const error = {
|
|
34
|
+
keyword: 'enum',
|
|
35
|
+
instancePath: '/projectType',
|
|
36
|
+
schemaPath: '#/properties/projectType/enum',
|
|
37
|
+
params: { allowedValues: ['plugin', 'theme', 'wordpress', 'wp-content', 'other'] },
|
|
38
|
+
message: 'must be equal to one of the allowed values'
|
|
39
|
+
};
|
|
40
|
+
const result = formatValidationError(error);
|
|
41
|
+
expect(result.message).toContain('Invalid value');
|
|
42
|
+
expect(result.message).toContain('/projectType');
|
|
43
|
+
expect(result.hint).toContain('Allowed values');
|
|
44
|
+
expect(result.hint).toContain('plugin');
|
|
45
|
+
expect(result.docsUrl).toBe('https://bgrgicak.github.io/wp-tester/#/configuration?id=configuration-options');
|
|
46
|
+
});
|
|
47
|
+
it('should format type error', () => {
|
|
48
|
+
const error = {
|
|
49
|
+
keyword: 'type',
|
|
50
|
+
instancePath: '/environments',
|
|
51
|
+
schemaPath: '#/properties/environments/type',
|
|
52
|
+
params: { type: 'array' },
|
|
53
|
+
message: 'must be array'
|
|
54
|
+
};
|
|
55
|
+
const result = formatValidationError(error);
|
|
56
|
+
expect(result.message).toContain('Type error');
|
|
57
|
+
expect(result.message).toContain('/environments');
|
|
58
|
+
expect(result.hint).toContain('array');
|
|
59
|
+
expect(result.docsUrl).toBe('https://bgrgicak.github.io/wp-tester/#/configuration?id=configuration-options');
|
|
60
|
+
});
|
|
61
|
+
it('should format minItems error', () => {
|
|
62
|
+
const error = {
|
|
63
|
+
keyword: 'minItems',
|
|
64
|
+
instancePath: '/environments',
|
|
65
|
+
schemaPath: '#/properties/environments/minItems',
|
|
66
|
+
params: { limit: 1 },
|
|
67
|
+
message: 'must NOT have fewer than 1 items'
|
|
68
|
+
};
|
|
69
|
+
const result = formatValidationError(error);
|
|
70
|
+
expect(result.message).toContain('too short');
|
|
71
|
+
expect(result.message).toContain('/environments');
|
|
72
|
+
expect(result.hint).toContain('Minimum items required: 1');
|
|
73
|
+
expect(result.docsUrl).toBe('https://bgrgicak.github.io/wp-tester/#/configuration?id=configuration-options');
|
|
74
|
+
});
|
|
75
|
+
it('should format unknown error types with default handler', () => {
|
|
76
|
+
const error = {
|
|
77
|
+
keyword: 'pattern',
|
|
78
|
+
instancePath: '/someField',
|
|
79
|
+
schemaPath: '#/properties/someField/pattern',
|
|
80
|
+
params: { pattern: '^[a-z]+$' },
|
|
81
|
+
message: 'must match pattern'
|
|
82
|
+
};
|
|
83
|
+
const result = formatValidationError(error);
|
|
84
|
+
expect(result.message).toContain('/someField');
|
|
85
|
+
expect(result.message).toContain('must match pattern');
|
|
86
|
+
expect(result.docsUrl).toBe('https://bgrgicak.github.io/wp-tester/#/configuration');
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
//# sourceMappingURL=validate.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.spec.js","sourceRoot":"","sources":["../../../src/commands/config/validate.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEnD,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,KAAK,GAAgB;YACzB,OAAO,EAAE,sBAAsB;YAC/B,YAAY,EAAE,EAAE;YAChB,UAAU,EAAE,wBAAwB;YACpC,MAAM,EAAE,EAAE,kBAAkB,EAAE,aAAa,EAAE;YAC7C,OAAO,EAAE,qCAAqC;SAC/C,CAAC;QAEF,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAE5C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;QACrD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,+EAA+E,CAAC,CAAC;IAC/G,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,KAAK,GAAgB;YACzB,OAAO,EAAE,UAAU;YACnB,YAAY,EAAE,EAAE;YAChB,UAAU,EAAE,YAAY;YACxB,MAAM,EAAE,EAAE,eAAe,EAAE,OAAO,EAAE;YACpC,OAAO,EAAE,uCAAuC;SACjD,CAAC;QAEF,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAE5C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAC;IAC/F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,KAAK,GAAgB;YACzB,OAAO,EAAE,MAAM;YACf,YAAY,EAAE,cAAc;YAC5B,UAAU,EAAE,+BAA+B;YAC3C,MAAM,EAAE,EAAE,aAAa,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE;YAClF,OAAO,EAAE,4CAA4C;SACtD,CAAC;QAEF,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAE5C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QAClD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,+EAA+E,CAAC,CAAC;IAC/G,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,KAAK,GAAgB;YACzB,OAAO,EAAE,MAAM;YACf,YAAY,EAAE,eAAe;YAC7B,UAAU,EAAE,gCAAgC;YAC5C,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;YACzB,OAAO,EAAE,eAAe;SACzB,CAAC;QAEF,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAE5C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QAClD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,+EAA+E,CAAC,CAAC;IAC/G,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,KAAK,GAAgB;YACzB,OAAO,EAAE,UAAU;YACnB,YAAY,EAAE,eAAe;YAC7B,UAAU,EAAE,oCAAoC;YAChD,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE;YACpB,OAAO,EAAE,kCAAkC;SAC5C,CAAC;QAEF,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAE5C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QAClD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAC;QAC3D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,+EAA+E,CAAC,CAAC;IAC/G,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,KAAK,GAAgB;YACzB,OAAO,EAAE,SAAS;YAClB,YAAY,EAAE,YAAY;YAC1B,UAAU,EAAE,gCAAgC;YAC5C,MAAM,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE;YAC/B,OAAO,EAAE,oBAAoB;SAC9B,CAAC;QAEF,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAE5C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;QACvD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { TestType } from '@wp-tester/config';
|
|
2
2
|
interface TestArgs {
|
|
3
|
-
config
|
|
3
|
+
config?: string;
|
|
4
4
|
test?: TestType;
|
|
5
|
+
watch?: boolean;
|
|
6
|
+
passWithNoTests?: boolean;
|
|
7
|
+
'failed-only'?: boolean;
|
|
5
8
|
'--'?: string[];
|
|
6
9
|
}
|
|
7
10
|
export declare const testHandler: (argv: TestArgs) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/test/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/test/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAIlD,UAAU,QAAQ;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,eAAO,MAAM,WAAW,GAAU,MAAM,QAAQ,KAAG,OAAO,CAAC,IAAI,CAkC9D,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1,8 +1,38 @@
|
|
|
1
|
-
import { runTests } from './runner.js';
|
|
1
|
+
import { runTests, executeTests } from './runner.js';
|
|
2
|
+
import { runWatchMode } from './watcher.js';
|
|
3
|
+
import { getConfigPath } from '@wp-tester/config';
|
|
4
|
+
import * as clack from "@clack/prompts";
|
|
2
5
|
export const testHandler = async (argv) => {
|
|
3
|
-
const { config, test } = argv;
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
+
const { config = './wp-tester.json', test, watch, passWithNoTests } = argv;
|
|
7
|
+
const failedOnly = argv['failed-only'];
|
|
8
|
+
const extraArgs = argv["--"] || [];
|
|
9
|
+
if (extraArgs.length > 0 && test === undefined) {
|
|
10
|
+
clack.log.error("You provided extra arguments but didn't specify which tests to run.\n\nExtra arguments are passed to the test runner, so we need to know whether to pass them to PHPUnit or Smoke tests.\n\nPlease use --test to specify the test type.");
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
if (watch) {
|
|
14
|
+
const absoluteConfigPath = getConfigPath(config);
|
|
15
|
+
await runWatchMode({
|
|
16
|
+
configPath: absoluteConfigPath,
|
|
17
|
+
onRunTests: async () => {
|
|
18
|
+
await executeTests(absoluteConfigPath, {
|
|
19
|
+
testType: test,
|
|
20
|
+
extraArgs,
|
|
21
|
+
passWithNoTests,
|
|
22
|
+
failedOnly,
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
clack.log.info(" Test Run\n");
|
|
29
|
+
await runTests(config, {
|
|
30
|
+
testType: test,
|
|
31
|
+
extraArgs,
|
|
32
|
+
passWithNoTests,
|
|
33
|
+
failedOnly,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
6
36
|
};
|
|
7
37
|
export default testHandler;
|
|
8
38
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/test/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/test/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAC;AAWxC,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAAE,IAAc,EAAiB,EAAE;IACjE,MAAM,EAAE,MAAM,GAAG,kBAAkB,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IAC3E,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IAEnC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/C,KAAK,CAAC,GAAG,CAAC,KAAK,CACb,yOAAyO,CAC1O,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,kBAAkB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;QACjD,MAAM,YAAY,CAAC;YACjB,UAAU,EAAE,kBAAkB;YAC9B,UAAU,EAAE,KAAK,IAAI,EAAE;gBACrB,MAAM,YAAY,CAAC,kBAAkB,EAAE;oBACrC,QAAQ,EAAE,IAAI;oBACd,SAAS;oBACT,eAAe;oBACf,UAAU;iBACX,CAAC,CAAC;YACL,CAAC;SACF,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC9B,MAAM,QAAQ,CAAC,MAAM,EAAE;YACrB,QAAQ,EAAE,IAAI;YACd,SAAS;YACT,eAAe;YACf,UAAU;SACX,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1,3 +1,25 @@
|
|
|
1
1
|
import type { TestType } from "@wp-tester/config";
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Options for the test runner
|
|
4
|
+
*/
|
|
5
|
+
export interface RunTestsOptions {
|
|
6
|
+
/** Type of test to run (phpunit, wp, plugin, theme) */
|
|
7
|
+
testType?: TestType;
|
|
8
|
+
/** Additional arguments to pass to test runners */
|
|
9
|
+
extraArgs?: string[];
|
|
10
|
+
/** Allow the test suite to pass when no tests are executed (CLI override) */
|
|
11
|
+
passWithNoTests?: boolean;
|
|
12
|
+
/** Only display failed tests in output (CLI override) */
|
|
13
|
+
failedOnly?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface TestResult {
|
|
16
|
+
success: boolean;
|
|
17
|
+
hasTests: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Execute tests and return results without exiting the process.
|
|
21
|
+
* Used internally and by watch mode.
|
|
22
|
+
*/
|
|
23
|
+
export declare const executeTests: (configPath: string, options?: RunTestsOptions) => Promise<TestResult>;
|
|
24
|
+
export declare const runTests: (configPath: string, options?: RunTestsOptions) => Promise<void>;
|
|
3
25
|
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/commands/test/runner.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/commands/test/runner.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAA0B,MAAM,mBAAmB,CAAC;AAK1E;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,yDAAyD;IACzD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAwED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,GACvB,YAAY,MAAM,EAClB,UAAU,eAAe,KACxB,OAAO,CAAC,UAAU,CAwEpB,CAAC;AAEF,eAAO,MAAM,QAAQ,GACnB,YAAY,MAAM,EAClB,UAAU,eAAe,KACxB,OAAO,CAAC,IAAI,CA0Cd,CAAC"}
|