@w-lfpup/jackrabbit 0.3.0 → 0.3.1

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.
@@ -3,8 +3,8 @@
3
3
  "runAsynchronusly": false,
4
4
  "webdrivers": [
5
5
  {
6
- "command": "$GECKOWEBDRIVER/geckodriver -p 4001",
7
6
  "title": "Firefox",
7
+ "command": "$GECKOWEBDRIVER/geckodriver -p 4001",
8
8
  "timeout_ms": 30000,
9
9
  "url": "http://localhost:4001",
10
10
  "capabilities": {
@@ -16,27 +16,37 @@
16
16
  }
17
17
  },
18
18
  {
19
- "command": "$CHROMEWEBDRIVER/chromedriver --port=4005",
20
19
  "title": "Chrome",
20
+ "command": "$CHROMEWEBDRIVER/chromedriver --port=4005",
21
21
  "timeout_ms": 30000,
22
22
  "url": "http://localhost:4005",
23
23
  "capabilities": {
24
24
  "alwaysMatch": {
25
25
  "goog:chromeOptions": {
26
- "args": ["--headless"]
26
+ "args": [
27
+ "--headless",
28
+ "--disbale-gpu",
29
+ "--disable-dev-shm-usage",
30
+ "--start-maximized"
31
+ ]
27
32
  }
28
33
  }
29
34
  }
30
35
  },
31
36
  {
32
- "command": "$EDGEWEBDRIVER/msedgedriver --port=4010",
33
37
  "title": "Edge",
38
+ "command": "$EDGEWEBDRIVER/msedgedriver --port=4010",
34
39
  "timeout_ms": 30000,
35
40
  "url": "http://localhost:4010",
36
41
  "capabilities": {
37
42
  "alwaysMatch": {
38
43
  "ms:edgeOptions": {
39
- "args": ["--headless", "--disable-dev-shm-usage"]
44
+ "args": [
45
+ "--headless",
46
+ "--disbale-gpu",
47
+ "--disable-dev-shm-usage",
48
+ "--start-maximized"
49
+ ]
40
50
  }
41
51
  }
42
52
  }
@@ -29,14 +29,3 @@ jobs:
29
29
  run: npm run test
30
30
  - name: Test browsers
31
31
  run: npx jackrabbit_webdriver .github/workflows/browsers.macos.json ./tests/dist/mod.js
32
- # build_and_test_windows:
33
- # runs-on: windows-latest
34
- # steps:
35
- # - uses: actions/checkout@v6
36
- # - uses: actions/setup-node@v6
37
- # - name: Install
38
- # run: npm ci
39
- # - name: Test
40
- # run: npm run test
41
- # - name: Test browsers
42
- # run: npx jackrabbit_webdriver .github/workflows/browsers.windows.json ./tests/dist/mod.js
@@ -5,7 +5,6 @@ try {
5
5
  let jackrabbitMap = document.querySelector("script[type=jackrabbit_config]");
6
6
  if (null === jackrabbitMap)
7
7
  throw new Error("Failed to query jackrabbit_config script");
8
- // should be it's own verification and then throw
9
8
  let config = JSON.parse(jackrabbitMap.textContent);
10
9
  logger.log({
11
10
  type: "start_run",
@@ -1,4 +1,4 @@
1
- import { getResultsAsString } from "./results_str.js";
1
+ import { getResultsAsString } from "./results.js";
2
2
  export class Logger {
3
3
  #results = {
4
4
  startTime: 0,
@@ -21,6 +21,10 @@ export class Logger {
21
21
  get errored() {
22
22
  return this.#results.errors !== 0;
23
23
  }
24
+ get completed() {
25
+ return (0 < this.#results.expectedTests &&
26
+ this.#results.expectedTests === this.#results.completedTests);
27
+ }
24
28
  get results() {
25
29
  return getResultsAsString(this.#results);
26
30
  }
@@ -150,7 +154,6 @@ function endTest(runResults, loggerAction) {
150
154
  module.completedTests += 1;
151
155
  let { assertions } = loggerAction;
152
156
  const isAssertionArray = Array.isArray(assertions) && assertions.length;
153
- // might be worth just sticking with language standard "none" like "" or 0 or false
154
157
  const isAssertion = !Array.isArray(assertions) && undefined !== assertions;
155
158
  if (isAssertion || isAssertionArray) {
156
159
  runResults.fails += 1;
@@ -28,4 +28,6 @@ logger.log({
28
28
  time: performance.now(),
29
29
  });
30
30
  console.log(logger.results);
31
- logger.failed || logger.errored ? process.exit(1) : process.exit(0);
31
+ logger.failed || logger.errored || !logger.completed
32
+ ? process.exit(1)
33
+ : process.exit(0);
@@ -39,6 +39,8 @@ ${result.completedCollections} collections`);
39
39
  continue;
40
40
  output.push(`[run_error] ${errorAction.error}`);
41
41
  }
42
+ if (result.errorLogs.length)
43
+ output.push("");
42
44
  return false;
43
45
  }
44
46
  function logCollectionResult(output, collection) {
@@ -47,20 +49,22 @@ function logCollectionResult(output, collection) {
47
49
  let { loggerAction } = collection;
48
50
  if ("start_collection" !== loggerAction.type)
49
51
  return true;
50
- output.push(`${SPACE}${loggerAction.collection_url}`);
52
+ output.push(`${loggerAction.collection_url}`);
51
53
  if (!collection.fails &&
52
54
  !collection.errors &&
53
55
  collection.expectedTests === collection.completedTests &&
54
56
  collection.expectedModules === collection.completedModules) {
55
- output.push(`${collection.expectedTests} tests
56
- ${loggerAction.expected_module_count} modules`);
57
+ output.push(`${SPACE}${collection.expectedTests} tests
58
+ ${SPACE}${loggerAction.expected_module_count} modules`);
57
59
  return true;
58
60
  }
59
61
  for (let errorAction of collection.errorLogs) {
60
62
  if ("collection_error" !== errorAction.type)
61
63
  continue;
62
- output.push(`[collection_error] ${errorAction.error}`);
64
+ output.push(`${SPACE}[collection_error] ${errorAction.error}`);
63
65
  }
66
+ if (collection.errorLogs.length)
67
+ output.push("");
64
68
  return false;
65
69
  }
66
70
  function logModuleResult(output, module) {
@@ -79,8 +83,10 @@ function logModuleResult(output, module) {
79
83
  for (let errorAction of module.errorLogs) {
80
84
  if ("collection_error" !== errorAction.type)
81
85
  continue;
82
- output.push(`${SPACE}[module_error] ${errorAction.error}`);
86
+ output.push(`${SPACE.repeat(2)}[module_error] ${errorAction.error}`);
83
87
  }
88
+ if (module.errorLogs.length)
89
+ output.push("");
84
90
  return false;
85
91
  }
86
92
  function logTest(output, test) {
@@ -51,20 +51,20 @@ function logCollectionResult(output, collection) {
51
51
  let { loggerAction } = collection;
52
52
  if ("start_collection" !== loggerAction.type)
53
53
  return true;
54
- output.push(`${SPACE}${loggerAction.collection_url}`);
54
+ output.push(`${loggerAction.collection_url}`);
55
55
  // when everything in the collection goes right
56
56
  if (!collection.fails &&
57
57
  !collection.errors &&
58
58
  collection.expectedTests === collection.completedTests &&
59
59
  collection.expectedModules === collection.completedModules) {
60
- output.push(`${collection.expectedTests} tests
61
- ${loggerAction.expected_module_count} modules`);
60
+ output.push(`${SPACE}${collection.expectedTests} tests
61
+ ${SPACE}${loggerAction.expected_module_count} modules`);
62
62
  return true;
63
63
  }
64
64
  for (let errorAction of collection.errorLogs) {
65
65
  if ("collection_error" !== errorAction.type)
66
66
  continue;
67
- output.push(`[collection_error] ${errorAction.error}`);
67
+ output.push(`${SPACE}[collection_error] ${errorAction.error}`);
68
68
  }
69
69
  return false;
70
70
  }
@@ -85,7 +85,7 @@ function logModuleResult(output, module) {
85
85
  for (let errorAction of module.errorLogs) {
86
86
  if ("collection_error" !== errorAction.type)
87
87
  continue;
88
- output.push(`${SPACE}[module_error] ${errorAction.error}`);
88
+ output.push(`${SPACE.repeat(2)}[module_error] ${errorAction.error}`);
89
89
  }
90
90
  return false;
91
91
  }
@@ -3,9 +3,9 @@ import type {
3
3
  LoggerInterface,
4
4
  EndTest,
5
5
  } from "../../core/dist/mod.js";
6
- import type { RunResults } from "./results_str.js";
6
+ import type { RunResults } from "./results.js";
7
7
 
8
- import { getResultsAsString } from "./results_str.js";
8
+ import { getResultsAsString } from "./results.js";
9
9
 
10
10
  export class Logger implements LoggerInterface {
11
11
  #results: RunResults = {
@@ -24,14 +24,21 @@ export class Logger implements LoggerInterface {
24
24
  collections: [],
25
25
  };
26
26
 
27
- get failed() {
27
+ get failed(): boolean {
28
28
  return this.#results.fails !== 0;
29
29
  }
30
30
 
31
- get errored() {
31
+ get errored(): boolean {
32
32
  return this.#results.errors !== 0;
33
33
  }
34
34
 
35
+ get completed(): boolean {
36
+ return (
37
+ 0 < this.#results.expectedTests &&
38
+ this.#results.expectedTests === this.#results.completedTests
39
+ );
40
+ }
41
+
35
42
  get results(): string {
36
43
  return getResultsAsString(this.#results);
37
44
  }
package/nodejs/src/mod.ts CHANGED
@@ -34,4 +34,6 @@ logger.log({
34
34
  });
35
35
 
36
36
  console.log(logger.results);
37
- logger.failed || logger.errored ? process.exit(1) : process.exit(0);
37
+ logger.failed || logger.errored || !logger.completed
38
+ ? process.exit(1)
39
+ : process.exit(0);
@@ -97,6 +97,8 @@ ${result.completedCollections} collections`);
97
97
  output.push(`[run_error] ${errorAction.error}`);
98
98
  }
99
99
 
100
+ if (result.errorLogs.length) output.push("");
101
+
100
102
  return false;
101
103
  }
102
104
 
@@ -109,7 +111,7 @@ function logCollectionResult(
109
111
  let { loggerAction } = collection;
110
112
  if ("start_collection" !== loggerAction.type) return true;
111
113
 
112
- output.push(`${SPACE}${loggerAction.collection_url}`);
114
+ output.push(`${loggerAction.collection_url}`);
113
115
 
114
116
  // when everything in the collection goes right
115
117
  if (
@@ -119,8 +121,8 @@ function logCollectionResult(
119
121
  collection.expectedModules === collection.completedModules
120
122
  ) {
121
123
  output.push(
122
- `${collection.expectedTests} tests
123
- ${loggerAction.expected_module_count} modules`,
124
+ `${SPACE}${collection.expectedTests} tests
125
+ ${SPACE}${loggerAction.expected_module_count} modules`,
124
126
  );
125
127
 
126
128
  return true;
@@ -128,8 +130,9 @@ ${loggerAction.expected_module_count} modules`,
128
130
 
129
131
  for (let errorAction of collection.errorLogs) {
130
132
  if ("collection_error" !== errorAction.type) continue;
131
- output.push(`[collection_error] ${errorAction.error}`);
133
+ output.push(`${SPACE}[collection_error] ${errorAction.error}`);
132
134
  }
135
+ if (collection.errorLogs.length) output.push("");
133
136
 
134
137
  return false;
135
138
  }
@@ -157,9 +160,11 @@ function logModuleResult(
157
160
 
158
161
  for (let errorAction of module.errorLogs) {
159
162
  if ("collection_error" !== errorAction.type) continue;
160
- output.push(`${SPACE}[module_error] ${errorAction.error}`);
163
+ output.push(`${SPACE.repeat(2)}[module_error] ${errorAction.error}`);
161
164
  }
162
165
 
166
+ if (module.errorLogs.length) output.push("");
167
+
163
168
  return false;
164
169
  }
165
170
 
@@ -1 +1 @@
1
- {"root":["./src/logger.ts","./src/mod.ts","./src/results_str.ts"],"version":"5.9.3"}
1
+ {"root":["./src/logger.ts","./src/mod.ts","./src/results.ts"],"version":"5.9.3"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@w-lfpup/jackrabbit",
3
3
  "description": "A test runner without dependencies",
4
- "version": "0.3.0",
4
+ "version": "0.3.1",
5
5
  "license": "BSD-3-Clause",
6
6
  "workspaces": [
7
7
  "core",
package/tests/dist/mod.js CHANGED
@@ -3,7 +3,6 @@ import * as PassTests from "./test_pass.test.js";
3
3
  import * as ErrorTests from "./test_error.test.js";
4
4
  import { runCollection } from "../../core/dist/mod.js";
5
5
  import { TestLogger } from "./test_logger.js";
6
- // jackrabbit test run won't pass failing tests
7
6
  async function testsFail() {
8
7
  let logger = new TestLogger();
9
8
  await runCollection(logger, [FailTests], 0, "test_pass.tests.js");
@@ -12,7 +11,6 @@ async function testsFail() {
12
11
  if (!logger.failed)
13
12
  return "fail tests failed to fail";
14
13
  }
15
- // jackrabbit test run won't fail passing tests
16
14
  async function testsPass() {
17
15
  let logger = new TestLogger();
18
16
  await runCollection(logger, [PassTests], 1, "test_fail.tests.js");
@@ -14,14 +14,12 @@ async function testMoreStuffAndErrorAsync() {
14
14
  throw Error("good");
15
15
  return ["good"];
16
16
  }
17
- // export tests
18
17
  export const tests = [
19
18
  testStuffAndError,
20
19
  testMoreStuffAndError,
21
20
  testStuffAndErrorAsync,
22
21
  testMoreStuffAndErrorAsync,
23
22
  ];
24
- // export optional test details
25
23
  export const options = {
26
24
  title: import.meta.url,
27
25
  };
@@ -10,14 +10,12 @@ async function testStuffAndFailAsync() {
10
10
  async function testMoreStuffAndFailAsync() {
11
11
  return ["this test also failed!"];
12
12
  }
13
- // export tests
14
13
  export const tests = [
15
14
  testStuffAndFail,
16
15
  testMoreStuffAndFail,
17
16
  testStuffAndFailAsync,
18
17
  testMoreStuffAndFailAsync,
19
18
  ];
20
- // export optional test details
21
19
  export const options = {
22
20
  title: import.meta.url,
23
21
  };
@@ -10,14 +10,12 @@ async function testStuffAndPassAsync() {
10
10
  async function testMoreStuffAndPassAsync() {
11
11
  return [];
12
12
  }
13
- // export tests
14
13
  export const tests = [
15
14
  testStuffAndPass,
16
15
  testMoreStuffAndPass,
17
16
  testStuffAndPassAsync,
18
17
  testMoreStuffAndPassAsync,
19
18
  ];
20
- // export optional test details
21
19
  export const options = {
22
20
  title: import.meta.url,
23
21
  };
package/tsconfig.json CHANGED
@@ -4,6 +4,7 @@
4
4
  "module": "nodenext",
5
5
  "target": "esnext",
6
6
  "strict": true,
7
- "declaration": true
7
+ "declaration": true,
8
+ "removeComments": true
8
9
  }
9
10
  }
@@ -3,7 +3,6 @@ export async function createConfig(args) {
3
3
  let configFilepath = args[0];
4
4
  let relPath = path.resolve(process.cwd(), configFilepath);
5
5
  try {
6
- // windows might need a "file://<relPath>" situation
7
6
  let { default: json } = await import(`file://${relPath}`, {
8
7
  with: { type: "json" },
9
8
  });
@@ -1,4 +1,4 @@
1
- import { getResultsAsString } from "./results_str.js";
1
+ import { getResultsAsString, isComplete } from "./results.js";
2
2
  export class Logger {
3
3
  #eventbus;
4
4
  #sessionResults = {
@@ -35,14 +35,12 @@ export class Logger {
35
35
  get errored() {
36
36
  return this.#sessionResults.errors !== 0;
37
37
  }
38
- get compeleted() {
39
- return false;
38
+ get completed() {
39
+ return isComplete(this.#sessionResults);
40
40
  }
41
41
  get results() {
42
42
  return getResultsAsString(this.#sessionResults);
43
43
  }
44
- // get output
45
- // output being a array of a string
46
44
  #boundError = this.#onError.bind(this);
47
45
  #onError(action) {
48
46
  let runResults = this.#sessionResults.runs.get(action.id);
@@ -191,7 +189,6 @@ function endTest(sessionResults, runResults, loggerAction) {
191
189
  module.completedTests += 1;
192
190
  let { assertions } = loggerAction;
193
191
  const isAssertionArray = Array.isArray(assertions) && assertions.length;
194
- // might be worth just sticking with language standard "none" like "" or 0 or false
195
192
  const isAssertion = !Array.isArray(assertions) && undefined !== assertions;
196
193
  if (isAssertion || isAssertionArray) {
197
194
  sessionResults.fails += 1;
@@ -15,22 +15,21 @@ let eventbus = new EventBus();
15
15
  let logger = new Logger(config, eventbus);
16
16
  let router = new Router(config, eventbus);
17
17
  let webdrivers = new WebDrivers(config, eventbus);
18
- // setup server
19
18
  let server = http.createServer();
20
19
  server.addListener("request", router.route);
21
20
  server.addListener("close", function () {
22
21
  console.log(logger.results);
23
- logger.errored || logger.failed ? process.exit(1) : process.exit(0);
22
+ logger.errored || logger.failed || !logger.completed
23
+ ? process.exit(1)
24
+ : process.exit(0);
24
25
  });
25
26
  eventbus.addListener("end", function () {
26
27
  server.closeAllConnections();
27
28
  server.close();
28
29
  });
29
- // run server
30
30
  let { port, hostname } = config.hostAndPort;
31
31
  server.listen({
32
32
  port,
33
33
  hostname,
34
34
  });
35
- // start test run
36
35
  config.runAsynchronously ? webdrivers.runAll() : webdrivers.run();
@@ -1 +1,190 @@
1
- export {};
1
+ const SPACE = " ";
2
+ export function getResultsAsString(sessionResults) {
3
+ const output = [];
4
+ logSessionErrors(output, sessionResults);
5
+ for (let [, result] of sessionResults.runs) {
6
+ if (logRunResults(output, result))
7
+ continue;
8
+ for (const collection of result.collections) {
9
+ if (logCollectionResult(output, collection))
10
+ continue;
11
+ if (collection)
12
+ for (const moduleResult of collection.modules) {
13
+ if (logModuleResult(output, moduleResult))
14
+ continue;
15
+ if (moduleResult)
16
+ for (const testResult of moduleResult.testResults) {
17
+ logTest(output, testResult);
18
+ }
19
+ }
20
+ }
21
+ }
22
+ logSummary(output, sessionResults);
23
+ return output.join("\n");
24
+ }
25
+ function logSessionErrors(output, sessionResults) {
26
+ if (!sessionResults.runs.size)
27
+ output.push("\nNo webdrivers were run.");
28
+ for (let [, result] of sessionResults.runs) {
29
+ if (result.errorLogs.length)
30
+ output.push(`\n${result.webdriverParams.title}`);
31
+ for (let errorAction of result.errorLogs) {
32
+ if ("session_error" === errorAction.type) {
33
+ output.push(`${SPACE}[session_error] ${errorAction.error}`);
34
+ }
35
+ }
36
+ }
37
+ }
38
+ function logRunResults(output, result) {
39
+ output.push(`\n${result.webdriverParams.title}`);
40
+ for (let errorAction of result.errorLogs) {
41
+ if ("log" !== errorAction.type)
42
+ continue;
43
+ if ("run_error" !== errorAction.loggerAction.type)
44
+ continue;
45
+ output.push(`${SPACE.repeat(2)}[run_error] ${errorAction.loggerAction.error}`);
46
+ }
47
+ if (result.errorLogs.length)
48
+ output.push("");
49
+ if (!result.collections && !result.expectedTests) {
50
+ output.push(`${SPACE}No tests were run.`);
51
+ return true;
52
+ }
53
+ if (!result.fails &&
54
+ !result.errors &&
55
+ result.expectedTests === result.completedTests &&
56
+ result.expectedModules === result.completedModules &&
57
+ result.expectedCollections === result.completedCollections) {
58
+ output.push(`${SPACE}${result.completedTests} tests
59
+ ${SPACE}${result.completedModules} modules
60
+ ${SPACE}${result.completedCollections} collections`);
61
+ return true;
62
+ }
63
+ return false;
64
+ }
65
+ function logCollectionResult(output, collection) {
66
+ if (!collection)
67
+ return true;
68
+ let { loggerAction } = collection;
69
+ if ("start_collection" !== loggerAction.type)
70
+ return true;
71
+ output.push(`${SPACE}${loggerAction.collection_url}`);
72
+ if (!collection.fails &&
73
+ !collection.errors &&
74
+ collection.expectedTests === collection.completedTests &&
75
+ collection.expectedModules === collection.completedModules) {
76
+ output.push(`${SPACE.repeat(2)}${collection.expectedTests} tests
77
+ ${SPACE.repeat(2)}${loggerAction.expected_module_count} modules`);
78
+ return true;
79
+ }
80
+ for (let errorAction of collection.errorLogs) {
81
+ if ("collection_error" !== errorAction.type)
82
+ continue;
83
+ output.push(`${SPACE.repeat(2)}[collection_error] ${errorAction.error}`);
84
+ }
85
+ if (collection.errorLogs.length)
86
+ output.push("");
87
+ return false;
88
+ }
89
+ function logModuleResult(output, module) {
90
+ if (!module)
91
+ return true;
92
+ let { loggerAction } = module;
93
+ if ("start_module" !== loggerAction.type)
94
+ return true;
95
+ output.push(`${SPACE.repeat(2)}${loggerAction.module_name}`);
96
+ if (!module.fails &&
97
+ !module.errors &&
98
+ module.expectedTests === module.completedTests) {
99
+ output.push(`${SPACE.repeat(3)}${module.expectedTests} tests`);
100
+ return true;
101
+ }
102
+ output.push(`${SPACE.repeat(3)}${module.completedTests - module.fails}/${module.expectedTests} tests`);
103
+ output.push("");
104
+ for (let errorAction of module.errorLogs) {
105
+ if ("module_error" !== errorAction.type)
106
+ continue;
107
+ output.push(`${SPACE.repeat(3)}[module_error] ${errorAction.error}`);
108
+ }
109
+ if (module.errorLogs.length)
110
+ output.push("");
111
+ return false;
112
+ }
113
+ function logTest(output, test) {
114
+ if (!test)
115
+ return;
116
+ let { loggerStartAction, loggerEndAction } = test;
117
+ if ("start_test" !== loggerStartAction.type)
118
+ return;
119
+ if ("test_error" === loggerEndAction?.type) {
120
+ let { test_name } = loggerStartAction;
121
+ output.push(`${SPACE.repeat(3)}${test_name}
122
+ ${SPACE.repeat(4)}[error] ${loggerEndAction.error}`);
123
+ }
124
+ if ("end_test" === loggerEndAction?.type) {
125
+ let { assertions } = loggerEndAction;
126
+ const isAssertionArray = Array.isArray(assertions) && assertions.length;
127
+ const isAssertion = !Array.isArray(assertions) &&
128
+ undefined !== assertions &&
129
+ null !== assertions;
130
+ if (isAssertion || isAssertionArray) {
131
+ let { test_name } = loggerStartAction;
132
+ output.push(`${SPACE.repeat(3)}${test_name}`);
133
+ }
134
+ if (isAssertion) {
135
+ output.push(`${SPACE.repeat(4)}- ${assertions}`);
136
+ }
137
+ if (isAssertionArray) {
138
+ for (const assertion of assertions) {
139
+ output.push(`${SPACE.repeat(4)}- ${assertion}`);
140
+ }
141
+ }
142
+ }
143
+ if (undefined === loggerEndAction) {
144
+ let { test_name } = loggerStartAction;
145
+ output.push(`${SPACE.repeat(3)}${test_name}
146
+ ${SPACE.repeat(4)}[incomplete]`);
147
+ }
148
+ }
149
+ function logSummary(output, sessionResults) {
150
+ let status_with_color = blue("\u{2714} passed");
151
+ if (!isComplete(sessionResults))
152
+ status_with_color = gray("\u{2717} incomplete");
153
+ if (sessionResults.fails)
154
+ status_with_color = yellow("\u{2717} failed");
155
+ if (sessionResults.errors)
156
+ status_with_color = gray("\u{2717} errored");
157
+ let totalTime = 0;
158
+ let testTime = 0;
159
+ for (let [, run] of sessionResults.runs) {
160
+ totalTime += run.endTime - run.startTime;
161
+ testTime += run.testTime;
162
+ }
163
+ output.push(`
164
+ ${status_with_color}
165
+ duration: ${testTime.toFixed(4)} mS
166
+ total: ${totalTime.toFixed(4)} mS
167
+ `);
168
+ }
169
+ export function isComplete(sessionResults) {
170
+ for (const [, result] of sessionResults.runs) {
171
+ if (!result.expectedTests ||
172
+ !result.expectedModules ||
173
+ !result.expectedCollections)
174
+ return false;
175
+ if (result.expectedTests !== result.completedTests ||
176
+ result.expectedModules !== result.completedModules ||
177
+ result.expectedCollections !== result.completedCollections)
178
+ return false;
179
+ }
180
+ return true;
181
+ }
182
+ function blue(text) {
183
+ return `\x1b[44m\x1b[97m${text}\x1b[0m`;
184
+ }
185
+ function yellow(text) {
186
+ return `\x1b[43m\x1b[97m${text}\x1b[0m`;
187
+ }
188
+ function gray(text) {
189
+ return `\x1b[100m\x1b[97m${text}\x1b[0m`;
190
+ }