UNPKG

3.49 kBPlain TextView Raw
1import { MutantResult, PartialStrykerOptions } from '@stryker-mutator/api/core';
2import { createInjector } from 'typed-inject';
3import { commonTokens } from '@stryker-mutator/api/plugin';
4
5import { PrepareExecutor, MutantInstrumenterExecutor, DryRunExecutor, MutationTestExecutor } from './process/index.js';
6import { coreTokens } from './di/index.js';
7import { retrieveCause, ConfigError } from './errors.js';
8import { provideLogging, provideLoggingBackend } from './logging/index.js';
9
10/**
11 * The main Stryker class.
12 * It provides a single `runMutationTest()` function which runs mutation testing:
13 */
14export class Stryker {
15 /**
16 * @constructor
17 * @param cliOptions The cli options.
18 * @param injectorFactory The injector factory, for testing purposes only
19 */
20 constructor(
21 private readonly cliOptions: PartialStrykerOptions,
22 private readonly injectorFactory = createInjector,
23 ) {}
24
25 public async runMutationTest(): Promise<MutantResult[]> {
26 const rootInjector = this.injectorFactory();
27 const loggerProvider = provideLogging(await provideLoggingBackend(rootInjector));
28
29 try {
30 // 1. Prepare. Load Stryker configuration, load the input files and starts the logging server
31 const prepareExecutor = loggerProvider.injectClass(PrepareExecutor);
32 const mutantInstrumenterInjector = await prepareExecutor.execute(this.cliOptions);
33
34 try {
35 // 2. Mutate and instrument the files and write to the sandbox.
36 const mutantInstrumenter = mutantInstrumenterInjector.injectClass(MutantInstrumenterExecutor);
37 const dryRunExecutorInjector = await mutantInstrumenter.execute();
38
39 // 3. Perform a 'dry run' (initial test run). Runs the tests without active mutants and collects coverage.
40 const dryRunExecutor = dryRunExecutorInjector.injectClass(DryRunExecutor);
41 const mutationRunExecutorInjector = await dryRunExecutor.execute();
42
43 // 4. Actual mutation testing. Will check every mutant and if valid run it in an available test runner.
44 const mutationRunExecutor = mutationRunExecutorInjector.injectClass(MutationTestExecutor);
45 const mutantResults = await mutationRunExecutor.execute();
46
47 return mutantResults;
48 } catch (error) {
49 if (mutantInstrumenterInjector.resolve(commonTokens.options).cleanTempDir !== 'always') {
50 const log = loggerProvider.resolve(commonTokens.getLogger)(Stryker.name);
51 log.debug('Not removing the temp dir because an error occurred');
52 mutantInstrumenterInjector.resolve(coreTokens.temporaryDirectory).removeDuringDisposal = false;
53 }
54 throw error;
55 }
56 } catch (error) {
57 const log = loggerProvider.resolve(commonTokens.getLogger)(Stryker.name);
58 const cause = retrieveCause(error);
59 if (cause instanceof ConfigError) {
60 log.error(cause.message);
61 } else {
62 log.error('Unexpected error occurred while running Stryker', error);
63 log.info('This might be a known problem with a solution documented in our troubleshooting guide.');
64 log.info('You can find it at https://stryker-mutator.io/docs/stryker-js/troubleshooting/');
65 if (!log.isTraceEnabled()) {
66 log.info(
67 'Still having trouble figuring out what went wrong? Try `npx stryker run --fileLogLevel trace --logLevel debug` to get some more info.',
68 );
69 }
70 }
71 throw cause;
72 } finally {
73 await rootInjector.dispose();
74 }
75 }
76}