UNPKG

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