@travetto/test 8.0.0-alpha.0 → 8.0.0-alpha.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/test",
3
- "version": "8.0.0-alpha.0",
3
+ "version": "8.0.0-alpha.2",
4
4
  "type": "module",
5
5
  "description": "Declarative test framework",
6
6
  "keywords": [
@@ -28,15 +28,15 @@
28
28
  "directory": "module/test"
29
29
  },
30
30
  "dependencies": {
31
- "@travetto/registry": "^8.0.0-alpha.0",
32
- "@travetto/runtime": "^8.0.0-alpha.0",
33
- "@travetto/terminal": "^8.0.0-alpha.0",
34
- "@travetto/worker": "^8.0.0-alpha.0",
31
+ "@travetto/registry": "^8.0.0-alpha.2",
32
+ "@travetto/runtime": "^8.0.0-alpha.2",
33
+ "@travetto/terminal": "^8.0.0-alpha.2",
34
+ "@travetto/worker": "^8.0.0-alpha.2",
35
35
  "yaml": "^2.8.2"
36
36
  },
37
37
  "peerDependencies": {
38
- "@travetto/cli": "^8.0.0-alpha.0",
39
- "@travetto/transformer": "^8.0.0-alpha.0"
38
+ "@travetto/cli": "^8.0.0-alpha.3",
39
+ "@travetto/transformer": "^8.0.0-alpha.2"
40
40
  },
41
41
  "peerDependenciesMeta": {
42
42
  "@travetto/transformer": {
@@ -40,15 +40,13 @@ export class AssertUtil {
40
40
  * Determine file location for a given error and the stack trace
41
41
  */
42
42
  static getPositionOfError(error: Error): { import: string, line: number } | undefined {
43
- const stack = error.stack ?? new Error().stack!;
44
- const frames = Util.stackTraceToParts(stack)
43
+ const frames = Util.stackTraceToParts(error.stack ?? new Error().stack!)
45
44
  .map(frame => {
46
- const imp = (RuntimeIndex.getFromSource(frame.filename) ?? RuntimeIndex.getEntry(frame.filename))?.import;
47
- return { ...frame, import: imp! };
48
- })
49
- .filter(frame => !!frame.import);
45
+ const entry = RuntimeIndex.getEntry(frame.filename);
46
+ return { ...frame, import: entry?.import!, line: entry?.type === 'ts' ? frame.line : 1 };
47
+ });
50
48
 
51
- return frames[0];
49
+ return frames.find(frame => frame.import);
52
50
  }
53
51
 
54
52
  /**
@@ -99,7 +99,7 @@ export class TapSummaryEmitter implements TestConsumerShape {
99
99
  total[value.status] += 1;
100
100
  total.count += 1;
101
101
  const statusLine = `${total.failed} failed, ${total.errored} errored, ${total.skipped} skipped`;
102
- return { value: `Tests %idx/%total [${statusLine}] -- ${value.classId}`, total: state.testCount, idx: total.count };
102
+ return { value: `Tests %idx/%total [${statusLine}] -- ${value.classId}`, total: state.testCount, idx: total.passed };
103
103
 
104
104
  },
105
105
  TerminalUtil.progressBarUpdater(this.#terminal, { style: () => ({ complete: (total.failed || total.errored) ? fail : success }) })
@@ -1,4 +1,4 @@
1
- import { castTo, type Class, type ClassInstance, describeFunction, getClass } from '@travetto/runtime';
1
+ import { castTo, type Class, type ClassInstance, getClass } from '@travetto/runtime';
2
2
 
3
3
  import type { SuiteConfig } from '../model/suite.ts';
4
4
  import { SuiteRegistryIndex } from '../registry/registry-index.ts';
@@ -15,11 +15,9 @@ export function Suite(...rest: Partial<SuiteConfig>[]): ClassDecorator;
15
15
  export function Suite(description: string, ...rest: Partial<SuiteConfig>[]): ClassDecorator;
16
16
  export function Suite(description?: string | Partial<SuiteConfig>, ...rest: Partial<SuiteConfig>[]): ClassDecorator {
17
17
  const decorator = (cls: Class): typeof cls => {
18
- const isAbstract = describeFunction(cls).abstract;
19
18
  SuiteRegistryIndex.getForRegister(cls).register(
20
19
  ...(typeof description !== 'string' && description ? [description] : []),
21
20
  ...rest,
22
- ...isAbstract ? [{ skip: true }] : [],
23
21
  ...(typeof description === 'string' ? [{ description }] : []),
24
22
  );
25
23
  return cls;
@@ -92,7 +92,7 @@ export class TestExecutor {
92
92
  /**
93
93
  * An empty suite result based on a suite config
94
94
  */
95
- createSuiteResult(suite: SuiteConfig): SuiteResult {
95
+ createSuiteResult(suite: SuiteConfig, override?: Partial<SuiteResult>): SuiteResult {
96
96
  return {
97
97
  passed: 0,
98
98
  failed: 0,
@@ -107,7 +107,8 @@ export class TestExecutor {
107
107
  classId: suite.classId,
108
108
  sourceHash: suite.sourceHash,
109
109
  duration: 0,
110
- tests: {}
110
+ tests: {},
111
+ ...override
111
112
  };
112
113
  }
113
114
 
@@ -176,7 +177,20 @@ export class TestExecutor {
176
177
 
177
178
  suite.instance = classConstruct(suite.class);
178
179
 
179
- if (!tests.length || await this.#shouldSkip(suite, suite.instance)) {
180
+ const shouldSkip = await this.#shouldSkip(suite, suite.instance);
181
+
182
+ if (shouldSkip) {
183
+ this.#consumer.onEvent({
184
+ phase: 'after', type: 'suite',
185
+ suite: this.createSuiteResult(suite, {
186
+ status: 'skipped',
187
+ skipped: tests.length,
188
+ total: tests.length
189
+ })
190
+ });
191
+ }
192
+
193
+ if (shouldSkip || !tests.length) {
180
194
  return;
181
195
  }
182
196
 
@@ -8,7 +8,7 @@ import type { TestConfig } from '../model/test.ts';
8
8
  function combineClasses(baseConfig: SuiteConfig, ...subConfig: Partial<SuiteConfig>[]): SuiteConfig {
9
9
  for (const config of subConfig) {
10
10
  if (config.tags) {
11
- baseConfig.tags = [...baseConfig.tags ?? [], ...config.tags];
11
+ baseConfig.tags = [...new Set([...baseConfig.tags ?? [], ...config.tags])];
12
12
  }
13
13
  baseConfig.skip = config.skip ?? baseConfig.skip;
14
14
 
@@ -30,6 +30,21 @@ function combineClasses(baseConfig: SuiteConfig, ...subConfig: Partial<SuiteConf
30
30
  return baseConfig;
31
31
  }
32
32
 
33
+ function combineWithParent(baseConfig: SuiteConfig, parentConfig: SuiteConfig): SuiteConfig {
34
+ baseConfig.tags = [...parentConfig.tags ?? [], ...baseConfig.tags ?? []];
35
+ baseConfig.skip = baseConfig.skip ?? parentConfig.skip;
36
+ baseConfig.phaseHandlers = [...(parentConfig.phaseHandlers ?? []), ...(baseConfig.phaseHandlers ?? [])];
37
+ for (const [key, test] of Object.entries(parentConfig.tests ?? {})) {
38
+ baseConfig.tests[key] = {
39
+ ...test,
40
+ class: baseConfig.class,
41
+ classId: baseConfig.classId,
42
+ import: baseConfig.import,
43
+ };
44
+ }
45
+ return baseConfig;
46
+ }
47
+
33
48
  function combineMethods(suite: SuiteConfig, baseConfig: TestConfig, ...subConfig: Partial<TestConfig>[]): TestConfig {
34
49
  baseConfig.classId = suite.classId;
35
50
  baseConfig.import = suite.import;
@@ -54,12 +69,12 @@ export class SuiteRegistryAdapter implements RegistryAdapter<SuiteConfig> {
54
69
 
55
70
  register(...data: Partial<SuiteConfig>[]): SuiteConfig {
56
71
  if (!this.#config) {
57
- const { lines, hash } = describeFunction(this.#cls) ?? {};
72
+ const { lines, hash, abstract: isAbstract } = describeFunction(this.#cls) ?? {};
58
73
  this.#config = asFull<SuiteConfig>({
59
74
  class: this.#cls,
60
75
  classId: this.#cls.Ⲑid,
61
76
  tags: [],
62
- skip: false,
77
+ skip: isAbstract,
63
78
  import: Runtime.getImport(this.#cls),
64
79
  lineStart: lines?.[0],
65
80
  lineEnd: lines?.[1],
@@ -99,11 +114,11 @@ export class SuiteRegistryAdapter implements RegistryAdapter<SuiteConfig> {
99
114
 
100
115
  finalize(parent?: SuiteConfig): void {
101
116
  if (parent) {
102
- combineClasses(this.#config, parent);
117
+ combineWithParent(this.#config, parent);
103
118
  }
104
119
 
105
120
  for (const test of Object.values(this.#config.tests)) {
106
- test.tags = [...test.tags ?? [], ...this.#config.tags ?? []];
121
+ test.tags = [...new Set([...test.tags ?? [], ...this.#config.tags ?? []])];
107
122
  test.description ||= SchemaRegistryIndex.get(this.#cls).getMethod(test.methodName).description;
108
123
  }
109
124
  }
@@ -1,7 +1,3 @@
1
- import { getClass, Runtime } from '@travetto/runtime';
2
- import { SchemaRegistryIndex } from '@travetto/schema';
3
-
4
- import { TestConsumerRegistryIndex } from '../../src/consumer/registry-index.ts';
5
1
  import type { TestConsumerConfig } from '../../src/execute/types.ts';
6
2
  import type { TestRunInput } from '../../src/model/test.ts';
7
3
 
@@ -21,17 +17,4 @@ export async function runTests(state: TestConsumerConfig, input: TestRunInput):
21
17
  }
22
18
  }
23
19
 
24
- export async function selectConsumer(instance: { format?: string }) {
25
- if (instance.format?.includes('/')) {
26
- await Runtime.importFrom(instance.format);
27
- }
28
-
29
- const types = await TestConsumerRegistryIndex.getTypes();
30
-
31
- SchemaRegistryIndex.getForRegister(getClass(instance), true).registerField('format', {
32
- enum: {
33
- message: `{path} is only allowed to be "${types.join('" or "')}"`,
34
- values: types
35
- }
36
- });
37
- }
20
+ export type TestConsumerType = 'tap' | 'tap-summary' | 'json' | 'exec' | 'event' | 'xunit' | 'custom';
@@ -5,6 +5,8 @@ import { type CliCommandShape, CliCommand, CliUtil } from '@travetto/cli';
5
5
  import { WorkPool } from '@travetto/worker';
6
6
  import { Max, Min } from '@travetto/schema';
7
7
 
8
+ import type { TestConsumerType } from './bin/run.ts';
9
+
8
10
  /**
9
11
  * Launch test framework and execute tests
10
12
  */
@@ -12,7 +14,7 @@ import { Max, Min } from '@travetto/schema';
12
14
  export class TestCommand implements CliCommandShape {
13
15
 
14
16
  /** Output format for test results */
15
- format: string = 'tap';
17
+ format: TestConsumerType = 'tap';
16
18
 
17
19
  /** Number of tests to run concurrently */
18
20
  @Min(1) @Max(WorkPool.MAX_SIZE)
@@ -30,7 +32,7 @@ export class TestCommand implements CliCommandShape {
30
32
  */
31
33
  formatOptions?: string[];
32
34
 
33
- preMain(): void {
35
+ finalize(): void {
34
36
  EventEmitter.defaultMaxListeners = 1000;
35
37
  Env.TRV_ROLE.set('test');
36
38
  Env.DEBUG.set(false);
@@ -38,11 +40,6 @@ export class TestCommand implements CliCommandShape {
38
40
  Env.TRV_LOG_TIME.clear();
39
41
  }
40
42
 
41
- async preValidate(): Promise<void> {
42
- const { selectConsumer } = await import('./bin/run.ts');
43
- await selectConsumer(this);
44
- }
45
-
46
43
  async main(first: string = '**/*', globs: string[] = []): Promise<void> {
47
44
  const { runTests } = await import('./bin/run.ts');
48
45
 
@@ -4,7 +4,7 @@ import { Env, JSONUtil, RuntimeIndex } from '@travetto/runtime';
4
4
  import { CliCommand, CliUtil } from '@travetto/cli';
5
5
  import { IsPrivate } from '@travetto/schema';
6
6
 
7
- import { runTests, selectConsumer } from './bin/run.ts';
7
+ import { runTests, type TestConsumerType } from './bin/run.ts';
8
8
  import type { TestDiffSource } from '../src/model/test.ts';
9
9
 
10
10
  /** Direct test invocation */
@@ -12,7 +12,8 @@ import type { TestDiffSource } from '../src/model/test.ts';
12
12
  @IsPrivate()
13
13
  export class TestDiffCommand {
14
14
 
15
- format: string = 'tap';
15
+ /** Output format for test results */
16
+ format: TestConsumerType = 'tap';
16
17
 
17
18
  /**
18
19
  * Format options
@@ -20,10 +21,6 @@ export class TestDiffCommand {
20
21
  */
21
22
  formatOptions?: string[];
22
23
 
23
- async preValidate(): Promise<void> {
24
- await selectConsumer(this);
25
- }
26
-
27
24
  preMain(): void {
28
25
  Env.TRV_ROLE.set('test');
29
26
  Env.TRV_LOG_PLAIN.set(true);
@@ -2,14 +2,15 @@ import { Env, RuntimeIndex } from '@travetto/runtime';
2
2
  import { CliCommand, CliUtil } from '@travetto/cli';
3
3
  import { IsPrivate } from '@travetto/schema';
4
4
 
5
- import { runTests, selectConsumer } from './bin/run.ts';
5
+ import { runTests, type TestConsumerType } from './bin/run.ts';
6
6
 
7
7
  /** Direct test invocation */
8
8
  @CliCommand()
9
9
  @IsPrivate()
10
10
  export class TestDirectCommand {
11
11
 
12
- format: string = 'tap';
12
+ /** Output format for test results */
13
+ format: TestConsumerType = 'tap';
13
14
 
14
15
  /**
15
16
  * Format options
@@ -17,10 +18,6 @@ export class TestDirectCommand {
17
18
  */
18
19
  formatOptions?: string[];
19
20
 
20
- async preValidate(): Promise<void> {
21
- await selectConsumer(this);
22
- }
23
-
24
21
  preMain(): void {
25
22
  Env.TRV_ROLE.set('test');
26
23
  Env.TRV_LOG_PLAIN.set(true);
@@ -1,7 +1,7 @@
1
1
  import { Env } from '@travetto/runtime';
2
2
  import { CliCommand } from '@travetto/cli';
3
3
 
4
- import { selectConsumer } from './bin/run.ts';
4
+ import type { TestConsumerType } from './bin/run.ts';
5
5
 
6
6
  /**
7
7
  * Invoke the test watcher
@@ -9,12 +9,10 @@ import { selectConsumer } from './bin/run.ts';
9
9
  @CliCommand()
10
10
  export class TestWatcherCommand {
11
11
 
12
- format: string = 'tap';
13
- mode: 'all' | 'change' = 'all';
12
+ /** Output format for test results */
13
+ format: TestConsumerType = 'tap';
14
14
 
15
- async preValidate(): Promise<void> {
16
- await selectConsumer(this);
17
- }
15
+ mode: 'all' | 'change' = 'all';
18
16
 
19
17
  preMain(): void {
20
18
  Env.TRV_ROLE.set('test');