xunit.ts 1.0.1 → 1.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/.editorconfig +2 -0
- package/.eslintrc.json +37 -0
- package/README.md +6 -2
- package/cli.ts +5 -5
- package/dist/cli.js.map +1 -1
- package/dist/src/Assertions/Contains.js +1 -1
- package/dist/src/Assertions/Contains.js.map +1 -1
- package/dist/src/Assertions/Count.js.map +1 -1
- package/dist/src/Assertions/Defined.js +2 -2
- package/dist/src/Assertions/Defined.js.map +1 -1
- package/dist/src/Assertions/DoesNotContain.js +1 -1
- package/dist/src/Assertions/DoesNotContain.js.map +1 -1
- package/dist/src/Assertions/DoesNotThrow.js +2 -2
- package/dist/src/Assertions/DoesNotThrow.js.map +1 -1
- package/dist/src/Assertions/Empty.js +1 -1
- package/dist/src/Assertions/Empty.js.map +1 -1
- package/dist/src/Assertions/Equal.js +1 -1
- package/dist/src/Assertions/Equal.js.map +1 -1
- package/dist/src/Assertions/False.js +1 -1
- package/dist/src/Assertions/False.js.map +1 -1
- package/dist/src/Assertions/InstanceOf.d.ts +1 -1
- package/dist/src/Assertions/InstanceOf.d.ts.map +1 -1
- package/dist/src/Assertions/InstanceOf.js +1 -1
- package/dist/src/Assertions/InstanceOf.js.map +1 -1
- package/dist/src/Assertions/NotEmpty.js +2 -2
- package/dist/src/Assertions/NotEmpty.js.map +1 -1
- package/dist/src/Assertions/NotEqual.js +1 -1
- package/dist/src/Assertions/NotEqual.js.map +1 -1
- package/dist/src/Assertions/NotNull.js +2 -2
- package/dist/src/Assertions/NotNull.js.map +1 -1
- package/dist/src/Assertions/Null.js +1 -1
- package/dist/src/Assertions/Null.js.map +1 -1
- package/dist/src/Assertions/StringContains.js +1 -1
- package/dist/src/Assertions/StringContains.js.map +1 -1
- package/dist/src/Assertions/StringDoesNotContain.d.ts.map +1 -1
- package/dist/src/Assertions/StringDoesNotContain.js +1 -1
- package/dist/src/Assertions/StringDoesNotContain.js.map +1 -1
- package/dist/src/Assertions/StringDoesNotEndWith.js +1 -1
- package/dist/src/Assertions/StringDoesNotEndWith.js.map +1 -1
- package/dist/src/Assertions/StringDoesNotStartWith.d.ts.map +1 -1
- package/dist/src/Assertions/StringDoesNotStartWith.js +1 -1
- package/dist/src/Assertions/StringDoesNotStartWith.js.map +1 -1
- package/dist/src/Assertions/StringEndsWith.js +1 -1
- package/dist/src/Assertions/StringEndsWith.js.map +1 -1
- package/dist/src/Assertions/StringStartsWith.d.ts.map +1 -1
- package/dist/src/Assertions/StringStartsWith.js +1 -1
- package/dist/src/Assertions/StringStartsWith.js.map +1 -1
- package/dist/src/Assertions/Throws.js +1 -1
- package/dist/src/Assertions/Throws.js.map +1 -1
- package/dist/src/Assertions/True.js +1 -1
- package/dist/src/Assertions/True.js.map +1 -1
- package/dist/src/Assertions/Undefined.js +1 -1
- package/dist/src/Assertions/Undefined.js.map +1 -1
- package/dist/src/Assertions/index.d.ts +22 -22
- package/dist/src/Assertions/index.d.ts.map +1 -1
- package/dist/src/Assertions/index.js.map +1 -1
- package/dist/src/CLI.d.ts.map +1 -1
- package/dist/src/CLI.js +19 -8
- package/dist/src/CLI.js.map +1 -1
- package/dist/src/Factory.d.ts +4 -4
- package/dist/src/Factory.d.ts.map +1 -1
- package/dist/src/Factory.js.map +1 -1
- package/dist/src/Framework/ResultType.d.ts.map +1 -1
- package/dist/src/Framework/ResultType.js.map +1 -1
- package/dist/src/Framework/Test.d.ts.map +1 -1
- package/dist/src/Framework/Test.js.map +1 -1
- package/dist/src/Framework/TestName.d.ts.map +1 -1
- package/dist/src/Framework/TestName.js.map +1 -1
- package/dist/src/Framework/TestResult.d.ts.map +1 -1
- package/dist/src/Framework/TestResult.js.map +1 -1
- package/dist/src/Framework/TestSuite.d.ts +3 -2
- package/dist/src/Framework/TestSuite.d.ts.map +1 -1
- package/dist/src/Framework/TestSuite.js +12 -2
- package/dist/src/Framework/TestSuite.js.map +1 -1
- package/dist/src/Framework/TestSuiteResults.d.ts +1 -1
- package/dist/src/Framework/TestSuiteResults.d.ts.map +1 -1
- package/dist/src/Framework/TestSuiteResults.js.map +1 -1
- package/dist/src/IO/FileSystem.d.ts +2 -2
- package/dist/src/IO/FileSystem.d.ts.map +1 -1
- package/dist/src/IO/FileSystem.js +6 -6
- package/dist/src/IO/FileSystem.js.map +1 -1
- package/dist/src/IO/Output.d.ts.map +1 -1
- package/dist/src/IO/Output.js.map +1 -1
- package/dist/src/Reporters/ConsoleReporter.d.ts.map +1 -1
- package/dist/src/Reporters/ConsoleReporter.js +8 -7
- package/dist/src/Reporters/ConsoleReporter.js.map +1 -1
- package/dist/src/Reporters/FileReporter.d.ts.map +1 -1
- package/dist/src/Reporters/FileReporter.js +1 -0
- package/dist/src/Reporters/FileReporter.js.map +1 -1
- package/dist/src/Reporters/JUnitReporter.d.ts +2 -2
- package/dist/src/Reporters/JUnitReporter.d.ts.map +1 -1
- package/dist/src/Reporters/JUnitReporter.js +7 -7
- package/dist/src/Reporters/JUnitReporter.js.map +1 -1
- package/dist/src/Reporters/ResultReporter.d.ts +3 -3
- package/dist/src/Reporters/ResultReporter.d.ts.map +1 -1
- package/dist/src/Reporters/SonarReporter.d.ts +2 -2
- package/dist/src/Reporters/SonarReporter.d.ts.map +1 -1
- package/dist/src/Reporters/SonarReporter.js +16 -16
- package/dist/src/Reporters/SonarReporter.js.map +1 -1
- package/dist/src/Reporters/XMLReporter.d.ts.map +1 -1
- package/dist/src/Reporters/XMLReporter.js.map +1 -1
- package/dist/src/Runners/Runner.d.ts +3 -3
- package/dist/src/Runners/Runner.d.ts.map +1 -1
- package/dist/src/Runners/Runner.js +8 -8
- package/dist/src/Runners/Runner.js.map +1 -1
- package/dist/src/Runners/TestRunner.d.ts +4 -4
- package/dist/src/Runners/TestRunner.d.ts.map +1 -1
- package/dist/src/Runners/TestRunner.js +4 -4
- package/dist/src/Runners/TestRunner.js.map +1 -1
- package/dist/src/Runners/TestSuiteLoader.d.ts +4 -4
- package/dist/src/Runners/TestSuiteLoader.d.ts.map +1 -1
- package/dist/src/Runners/TestSuiteLoader.js +21 -18
- package/dist/src/Runners/TestSuiteLoader.js.map +1 -1
- package/dist/src/Runners/TestSuiteRunner.d.ts +6 -6
- package/dist/src/Runners/TestSuiteRunner.d.ts.map +1 -1
- package/dist/src/Runners/TestSuiteRunner.js +3 -3
- package/dist/src/Runners/TestSuiteRunner.js.map +1 -1
- package/dist/xunit.d.ts +3 -3
- package/dist/xunit.d.ts.map +1 -1
- package/dist/xunit.js.map +1 -1
- package/icon.svg +74 -75
- package/logo.svg +130 -130
- package/package.json +44 -37
- package/src/Assertions/Contains.ts +10 -10
- package/src/Assertions/Count.ts +11 -11
- package/src/Assertions/Defined.ts +11 -11
- package/src/Assertions/DoesNotContain.ts +11 -11
- package/src/Assertions/DoesNotThrow.ts +13 -13
- package/src/Assertions/Empty.ts +11 -11
- package/src/Assertions/Equal.ts +12 -12
- package/src/Assertions/False.ts +11 -11
- package/src/Assertions/InstanceOf.ts +13 -13
- package/src/Assertions/NotEmpty.ts +11 -11
- package/src/Assertions/NotEqual.ts +12 -12
- package/src/Assertions/NotNull.ts +11 -11
- package/src/Assertions/Null.ts +11 -11
- package/src/Assertions/StringContains.ts +11 -11
- package/src/Assertions/StringDoesNotContain.ts +12 -12
- package/src/Assertions/StringDoesNotEndWith.ts +13 -13
- package/src/Assertions/StringDoesNotStartWith.ts +12 -12
- package/src/Assertions/StringEndsWith.ts +13 -13
- package/src/Assertions/StringStartsWith.ts +12 -12
- package/src/Assertions/Throws.ts +11 -11
- package/src/Assertions/True.ts +11 -11
- package/src/Assertions/Undefined.ts +12 -12
- package/src/Assertions/index.ts +45 -45
- package/src/CLI.ts +96 -85
- package/src/Factory.ts +25 -25
- package/src/Framework/ResultType.ts +4 -4
- package/src/Framework/Test.ts +6 -6
- package/src/Framework/TestName.ts +7 -7
- package/src/Framework/TestResult.ts +3 -2
- package/src/Framework/TestSuite.ts +29 -18
- package/src/Framework/TestSuiteResults.ts +17 -16
- package/src/IO/FileSystem.ts +28 -29
- package/src/IO/Output.ts +21 -20
- package/src/Reporters/ConsoleReporter.ts +88 -87
- package/src/Reporters/FileReporter.ts +29 -29
- package/src/Reporters/JUnitReporter.ts +80 -80
- package/src/Reporters/ResultReporter.ts +20 -12
- package/src/Reporters/SonarReporter.ts +86 -86
- package/src/Reporters/XMLReporter.ts +6 -6
- package/src/Runners/Runner.ts +21 -21
- package/src/Runners/TestRunner.ts +34 -33
- package/src/Runners/TestSuiteLoader.ts +52 -45
- package/src/Runners/TestSuiteRunner.ts +27 -26
- package/tsconfig.json +26 -26
- package/xunit.ts +6 -6
package/src/Assertions/index.ts
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
import is_true from
|
|
2
|
-
import is_false from
|
|
1
|
+
import is_true from "./True";
|
|
2
|
+
import is_false from "./False";
|
|
3
3
|
|
|
4
|
-
import is_undefined from
|
|
5
|
-
import is_defined from
|
|
4
|
+
import is_undefined from "./Undefined";
|
|
5
|
+
import is_defined from "./Defined";
|
|
6
6
|
|
|
7
|
-
import is_null from
|
|
8
|
-
import not_null from
|
|
7
|
+
import is_null from "./Null";
|
|
8
|
+
import not_null from "./NotNull";
|
|
9
9
|
|
|
10
|
-
import equal from
|
|
11
|
-
import not_equal from
|
|
10
|
+
import equal from "./Equal";
|
|
11
|
+
import not_equal from "./NotEqual";
|
|
12
12
|
|
|
13
|
-
import empty from
|
|
14
|
-
import not_empty from
|
|
13
|
+
import empty from "./Empty";
|
|
14
|
+
import not_empty from "./NotEmpty";
|
|
15
15
|
|
|
16
|
-
import count from
|
|
16
|
+
import count from "./Count";
|
|
17
17
|
|
|
18
|
-
import contains from
|
|
19
|
-
import not_contains from
|
|
18
|
+
import contains from "./Contains";
|
|
19
|
+
import not_contains from "./DoesNotContain";
|
|
20
20
|
|
|
21
|
-
import string_contains from
|
|
22
|
-
import string_not_contains from
|
|
21
|
+
import string_contains from "./StringContains";
|
|
22
|
+
import string_not_contains from "./StringDoesNotContain";
|
|
23
23
|
|
|
24
|
-
import string_starts from
|
|
25
|
-
import string_not_starts from
|
|
24
|
+
import string_starts from "./StringStartsWith";
|
|
25
|
+
import string_not_starts from "./StringDoesNotStartWith";
|
|
26
26
|
|
|
27
|
-
import string_ends from
|
|
28
|
-
import string_not_ends from
|
|
27
|
+
import string_ends from "./StringEndsWith";
|
|
28
|
+
import string_not_ends from "./StringDoesNotEndWith";
|
|
29
29
|
|
|
30
|
-
import instance_of from
|
|
30
|
+
import instance_of from "./InstanceOf";
|
|
31
31
|
|
|
32
|
-
import throws from
|
|
33
|
-
import does_not_throw from
|
|
32
|
+
import throws from "./Throws";
|
|
33
|
+
import does_not_throw from "./DoesNotThrow";
|
|
34
34
|
|
|
35
35
|
export default new class AssertionLibrary {
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
true = is_true;
|
|
37
|
+
false = is_false;
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
undefined = is_undefined;
|
|
40
|
+
defined = is_defined;
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
null = is_null;
|
|
43
|
+
notNull = not_null;
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
equal = equal;
|
|
46
|
+
notEqual = not_equal;
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
empty = empty;
|
|
49
|
+
notEmpty = not_empty;
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
count = count;
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
contains = contains;
|
|
54
|
+
doesNotContain = not_contains;
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
stringContains = string_contains;
|
|
57
|
+
stringDoesNotContain = string_not_contains;
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
stringStartsWith = string_starts;
|
|
60
|
+
stringDoesNotStartWIth = string_not_starts;
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
stringEndsWith = string_ends;
|
|
63
|
+
stringDoesNotEndWith = string_not_ends;
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
instanceOf = instance_of;
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
67
|
+
throws = throws;
|
|
68
|
+
doesNotThrow = does_not_throw;
|
|
69
|
+
};
|
package/src/CLI.ts
CHANGED
|
@@ -1,99 +1,110 @@
|
|
|
1
|
-
import Usage from
|
|
2
|
-
import JUnitReporter from
|
|
1
|
+
import Usage from "command-line-usage";
|
|
2
|
+
import JUnitReporter from "./Reporters/JUnitReporter";
|
|
3
3
|
import Process from "process";
|
|
4
4
|
import Args from "command-line-args";
|
|
5
5
|
import Runner from "./Runners/Runner";
|
|
6
6
|
import SonarReporter from "./Reporters/SonarReporter";
|
|
7
7
|
|
|
8
8
|
export default class CLI {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
9
|
+
private static readonly options: Usage.OptionDefinition[] = [
|
|
10
|
+
{
|
|
11
|
+
name: "dir",
|
|
12
|
+
alias: "d",
|
|
13
|
+
type: String,
|
|
14
|
+
defaultOption: true,
|
|
15
|
+
typeLabel: "<directory>",
|
|
16
|
+
description: "The path where tests to run are located (-d/--dir flag optional)"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: "filter",
|
|
20
|
+
alias: "f",
|
|
21
|
+
type: String,
|
|
22
|
+
multiple: true,
|
|
23
|
+
typeLabel: "<regex>",
|
|
24
|
+
description: "A regular expression to filter against TestSuiteName.TestMethodName()"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: "junit",
|
|
28
|
+
alias: "j",
|
|
29
|
+
type: String,
|
|
30
|
+
typeLabel: `[filename] (${JUnitReporter.defaultFileName})`,
|
|
31
|
+
description: "Save results as JUnit-formatted XML"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "sonar",
|
|
35
|
+
alias: "s",
|
|
36
|
+
type: String,
|
|
37
|
+
typeLabel: `[filename] (${SonarReporter.defaultFileName})`,
|
|
38
|
+
description: "Save results as SonarQube/SonarCloud-formatted XML"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "quiet",
|
|
42
|
+
alias: "q",
|
|
43
|
+
type: Boolean,
|
|
44
|
+
description: "Do not print individual test results to stdout"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "help",
|
|
48
|
+
alias: "h",
|
|
49
|
+
type: Boolean,
|
|
50
|
+
description: "Display this help page (and ignore all other options)"
|
|
51
|
+
}
|
|
52
|
+
];
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
54
|
+
private static readonly sections: Usage.Section[] = [
|
|
55
|
+
{
|
|
56
|
+
header: "xunit.ts",
|
|
57
|
+
content: "A TypeScript unit testing framework, following standard xUnit patterns"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
header: "Usage",
|
|
61
|
+
content: [
|
|
62
|
+
"<npm run | yarn> xunit [-d|--dir] <directory>",
|
|
63
|
+
"[-q|--quiet] [-j|--junit [filename]] [-s|--sonar [filename]] [-f|--filter regex]"
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
header: "Examples",
|
|
68
|
+
content: [
|
|
69
|
+
"npm run xunit dist/tests",
|
|
70
|
+
"yarn xunit --junit results.xml --dir dist/tests --quiet",
|
|
71
|
+
"yarn xunit -q -s -d dist/tests",
|
|
72
|
+
"yarn xunit dist/tests --filter MyTestSuite",
|
|
73
|
+
"yarn xunit dist/tests -f MyTestSuite.JustOneTest",
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
header: "Options",
|
|
78
|
+
optionList: CLI.options
|
|
79
|
+
}
|
|
80
|
+
];
|
|
71
81
|
|
|
72
|
-
|
|
82
|
+
private static readonly usage = Usage(CLI.sections);
|
|
73
83
|
|
|
74
|
-
|
|
75
|
-
|
|
84
|
+
constructor(private readonly runnerFactory: (args: Args.CommandLineOptions) => Runner, private readonly process: typeof Process) {
|
|
85
|
+
}
|
|
76
86
|
|
|
77
|
-
|
|
78
|
-
|
|
87
|
+
async run(): Promise<boolean> {
|
|
88
|
+
const args = Args(CLI.options, {argv: this.process.argv});
|
|
79
89
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
if (args.help) {
|
|
91
|
+
this.process.stdout.write(CLI.usage);
|
|
92
|
+
this.process.stdout.write("\n");
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
85
95
|
|
|
86
|
-
|
|
96
|
+
const runner = this.runnerFactory(args);
|
|
87
97
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
try {
|
|
99
|
+
const filters = args.filter ?? [];
|
|
100
|
+
const results = await runner.runAll(args.dir, filters.map((f: string) => new RegExp(f)));
|
|
101
|
+
return Runner.allTestsPassed(results);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
if (error instanceof Error) {
|
|
104
|
+
this.process.stderr.write(`An unhandled ${error.name} occurred: ${error.message}\n`);
|
|
105
|
+
this.process.stderr.write(error.stack?.toString() || "(no call stack)\n");
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
99
110
|
}
|
package/src/Factory.ts
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import Args from
|
|
2
|
-
import ConsoleReporter from
|
|
3
|
-
import FileSystem from
|
|
4
|
-
import JUnitReporter from
|
|
5
|
-
import Output from
|
|
6
|
-
import ResultReporter from
|
|
7
|
-
import Runner from
|
|
8
|
-
import TestRunner from
|
|
9
|
-
import TestSuiteLoader from
|
|
10
|
-
import TestSuiteRunner from
|
|
1
|
+
import Args from "command-line-args";
|
|
2
|
+
import ConsoleReporter from "./Reporters/ConsoleReporter";
|
|
3
|
+
import FileSystem from "./IO/FileSystem";
|
|
4
|
+
import JUnitReporter from "./Reporters/JUnitReporter";
|
|
5
|
+
import Output from "./IO/Output";
|
|
6
|
+
import ResultReporter from "./Reporters/ResultReporter";
|
|
7
|
+
import Runner from "./Runners/Runner";
|
|
8
|
+
import TestRunner from "./Runners/TestRunner";
|
|
9
|
+
import TestSuiteLoader from "./Runners/TestSuiteLoader";
|
|
10
|
+
import TestSuiteRunner from "./Runners/TestSuiteRunner";
|
|
11
11
|
import fs from "fs/promises";
|
|
12
12
|
import SonarReporter from "./Reporters/SonarReporter";
|
|
13
13
|
|
|
14
14
|
export default class Factory {
|
|
15
|
-
|
|
15
|
+
static readonly file_system = new FileSystem(fs);
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
static Runner(args: Args.CommandLineOptions) {
|
|
18
|
+
const loader = new TestSuiteLoader(Factory.file_system);
|
|
19
|
+
const reporters = Factory.Reporters(args);
|
|
20
|
+
const test_runner = new TestRunner(reporters);
|
|
21
|
+
const test_suite_runner = new TestSuiteRunner(test_runner, reporters);
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
return new Runner(loader, test_suite_runner, reporters);
|
|
24
|
+
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
static Reporters(args: Args.CommandLineOptions): ReadonlyArray<ResultReporter> {
|
|
27
|
+
return [
|
|
28
|
+
!args.quiet ? new ConsoleReporter(new Output(process.stdout)) : null,
|
|
29
|
+
args.junit !== undefined ? new JUnitReporter(Factory.file_system, args.junit ?? JUnitReporter.defaultFileName) : null,
|
|
30
|
+
args.sonar !== undefined ? new SonarReporter(Factory.file_system, args.sonar ?? SonarReporter.defaultFileName) : null
|
|
31
|
+
].filter(r => r !== null) as ResultReporter[];
|
|
32
|
+
}
|
|
33
33
|
}
|
package/src/Framework/Test.ts
CHANGED
|
@@ -4,12 +4,12 @@ import TestName from "./TestName";
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Annotates a test method within a {@link TestSuite}
|
|
7
|
-
*
|
|
7
|
+
*
|
|
8
8
|
* @remarks
|
|
9
9
|
* This instructs `xunit.ts` to run this method as part of its {@link TestSuite}
|
|
10
|
-
*
|
|
10
|
+
*
|
|
11
11
|
* @param test_name (optional) the test's display name; if not set, a sentence case version of the method name will be used
|
|
12
|
-
*
|
|
12
|
+
*
|
|
13
13
|
* @example
|
|
14
14
|
* ```
|
|
15
15
|
* @Test()
|
|
@@ -17,7 +17,7 @@ import TestName from "./TestName";
|
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
19
|
export default function Test(test_name?: string) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
return function (suite: TestSuite, method_name: string, info: TestInfo) {
|
|
21
|
+
suite.addTest(test_name || TestName.toSentenceCase(method_name), info);
|
|
22
|
+
};
|
|
23
23
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export default class TestName {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
static toSentenceCase(test_name: string) {
|
|
3
|
+
const result = test_name
|
|
4
|
+
.replace(/_([A-Z])/gi, (substring: string, match: string) => match.toUpperCase())
|
|
5
|
+
.replace(/([A-Z])/g, " $1")
|
|
6
|
+
.trim();
|
|
7
|
+
return result.charAt(0).toUpperCase() + result.slice(1);
|
|
8
|
+
}
|
|
9
9
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {ResultType} from "./ResultType";
|
|
1
|
+
import { ResultType } from "./ResultType";
|
|
2
2
|
|
|
3
3
|
export default class TestResult {
|
|
4
|
-
|
|
4
|
+
constructor(readonly type: ResultType, readonly duration: number, readonly error: Error | null = null) {
|
|
5
|
+
}
|
|
5
6
|
}
|
|
@@ -1,32 +1,43 @@
|
|
|
1
|
-
import TestInfo from
|
|
2
|
-
import AssertionLibrary from
|
|
1
|
+
import TestInfo from "./TestInfo";
|
|
2
|
+
import AssertionLibrary from "../Assertions";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Defines a container of tests
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* @remarks
|
|
8
8
|
* Extend this class for `xunit.ts` load its tests
|
|
9
|
-
*
|
|
9
|
+
*
|
|
10
10
|
* @example
|
|
11
11
|
* export default class CustomClassTests extends TestSuite { ... }
|
|
12
12
|
*/
|
|
13
13
|
export default abstract class TestSuite {
|
|
14
|
-
|
|
14
|
+
assert = AssertionLibrary;
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
private tests: Record<string, TestInfo> = {};
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
addTest(name: string, info: TestInfo) {
|
|
19
|
+
if (this.tests === undefined || this.tests === null) {
|
|
20
|
+
this.tests = {};
|
|
21
|
+
}
|
|
22
|
+
this.tests[name] = info;
|
|
23
|
+
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
setTests(tests: Record<string, TestInfo>) {
|
|
26
|
+
this.tests = tests;
|
|
27
|
+
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
getTests(filters: RegExp[]) {
|
|
30
|
+
return filters.length > 0
|
|
31
|
+
? this.filteredTests(filters)
|
|
32
|
+
: this.tests;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
filteredTests(filters: RegExp[]) {
|
|
36
|
+
const filtered: Record<string, TestInfo> = {};
|
|
37
|
+
const keys = Object.keys(this.tests).filter(k => filters.map(f => f.test(`${this.constructor.name}.${this.tests[k].value?.name}`)).filter(m => m).length > 0);
|
|
38
|
+
keys.forEach(k => {
|
|
39
|
+
return filtered[k] = this.tests[k];
|
|
40
|
+
});
|
|
41
|
+
return filtered;
|
|
42
|
+
}
|
|
32
43
|
}
|
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
import { ResultType } from
|
|
1
|
+
import { ResultType } from "./ResultType";
|
|
2
2
|
import TestResult from "./TestResult";
|
|
3
3
|
import TestSuite from "./TestSuite";
|
|
4
4
|
|
|
5
5
|
export default class TestSuiteResults {
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
constructor(readonly suite: TestSuite) { }
|
|
7
|
+
readonly results: Record<string, TestResult> = {};
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
9
|
+
constructor(readonly suite: TestSuite) {
|
|
10
|
+
}
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
addResult(name: string, result: TestResult) {
|
|
13
|
+
this.results[name] = result;
|
|
14
|
+
}
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
total() {
|
|
17
|
+
return Object.values(this.results).length;
|
|
18
|
+
}
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
count(result_type: ResultType) {
|
|
21
|
+
return Object.values(this.results).filter(result => result.type === result_type).length;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
time() {
|
|
25
|
+
return Object.values(this.results).reduce((sum, result) => sum + result.duration, 0);
|
|
26
|
+
}
|
|
26
27
|
}
|
package/src/IO/FileSystem.ts
CHANGED
|
@@ -1,37 +1,36 @@
|
|
|
1
|
-
import fs_promises from
|
|
1
|
+
import fs_promises from "fs/promises";
|
|
2
2
|
import path from "path";
|
|
3
3
|
|
|
4
4
|
export default class FileSystem {
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
constructor(private readonly fs: typeof fs_promises) {
|
|
7
|
+
}
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const stats = await this.fs.stat(item_path);
|
|
16
|
-
files.push(...stats.isDirectory()
|
|
17
|
-
? await this.getFiles(item_path)
|
|
18
|
-
: [item_path]);
|
|
19
|
-
}
|
|
20
|
-
return files;
|
|
21
|
-
} catch (e) {
|
|
22
|
-
return [];
|
|
23
|
-
}
|
|
24
|
-
}
|
|
9
|
+
static extension(file: string) {
|
|
10
|
+
const match = file.match(/\.(\w+)$/);
|
|
11
|
+
return match !== undefined && match !== null && match.length > 1
|
|
12
|
+
? match[1]
|
|
13
|
+
: "";
|
|
14
|
+
}
|
|
25
15
|
|
|
16
|
+
async getFiles(dir: string): Promise<string[]> {
|
|
17
|
+
try {
|
|
18
|
+
const files = [];
|
|
19
|
+
const contents = await this.fs.readdir(dir);
|
|
20
|
+
for (const item of contents) {
|
|
21
|
+
const item_path = `${dir}${path.sep}${item}`;
|
|
22
|
+
const stats = await this.fs.stat(item_path);
|
|
23
|
+
files.push(...stats.isDirectory()
|
|
24
|
+
? await this.getFiles(item_path)
|
|
25
|
+
: [ item_path ]);
|
|
26
|
+
}
|
|
27
|
+
return files;
|
|
28
|
+
} catch (e) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
? match[1]
|
|
31
|
-
: '';
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async save(data: string, file_path: string) {
|
|
35
|
-
await this.fs.writeFile(file_path, data);
|
|
36
|
-
}
|
|
33
|
+
async save(data: string, file_path: string) {
|
|
34
|
+
await this.fs.writeFile(file_path, data);
|
|
35
|
+
}
|
|
37
36
|
}
|