From edaf401dd4ec56ffdeb925232306c1f6faf81457 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Wed, 6 Feb 2019 06:48:53 +0100 Subject: [PATCH] feat(mutators): Remove side effects from mutator plugins (#1352) Use the new plugin system to load the `Mutator` plugins. Remove side effects from importing the existing mutator plugins: * `TypescriptMutator` * `JavascriptMutator` * `VueMutator` --- .../stryker-javascript-mutator/package.json | 11 +- .../src/JavaScriptMutator.ts | 20 ++- .../src/NodeMutatorFactory.ts | 23 --- .../src/helpers/NodeGenerator.ts | 2 +- .../stryker-javascript-mutator/src/index.ts | 18 ++- .../src/mutators/ArrayLiteralMutator.ts | 2 +- .../src/mutators/ArrayNewExpressionMutator.ts | 2 +- .../src/mutators/BinaryExpressionMutator.ts | 2 +- .../src/mutators/BlockMutator.ts | 2 +- .../mutators/BooleanSubstitutionMutator.ts | 2 +- .../mutators/ConditionalExpressionMutator.ts | 4 +- .../src/mutators/DoStatementMutator.ts | 4 +- .../src/mutators/ForStatementMutator.ts | 4 +- .../src/mutators/IfStatementMutator.ts | 4 +- .../src/mutators/NodeMutator.ts | 4 +- .../src/mutators/ObjectLiteralMutator.ts | 2 +- .../mutators/PostfixUnaryExpressionMutator.ts | 2 +- .../mutators/PrefixUnaryExpressionMutator.ts | 2 +- .../src/mutators/StringLiteralMutator.ts | 2 +- .../src/mutators/SwitchCaseMutator.ts | 2 +- .../src/mutators/WhileStatementMutator.ts | 4 +- .../src/mutators/index.ts | 34 ++-- .../test/helpers/mutatorAssertions.ts | 8 +- .../test/unit/JavaScriptMutatorSpec.ts | 31 ++-- .../test/unit/helpers/initSinon.ts | 11 ++ .../tsconfig.src.json | 3 - .../tsconfig.test.json | 6 + .../test/unit/JestConfigEditor.spec.ts | 2 +- packages/stryker-typescript/package.json | 3 +- .../src/TypescriptMutator.ts | 51 ++---- packages/stryker-typescript/src/index.ts | 9 +- .../stryker-typescript/src/mutator/index.ts | 34 ++++ .../test/helpers/globals.ts | 6 - .../test/helpers/producers.ts | 27 ---- .../test/integration/sampleSpec.ts | 7 +- .../test/unit/TypescriptMutatorSpec.ts | 28 ++-- .../test/unit/TypescriptTranspilerSpec.ts | 7 +- packages/stryker-vue-mutator/package.json | 6 +- .../stryker-vue-mutator/src/VueMutator.ts | 9 +- .../src/helpers/MutatorHelpers.ts | 32 ++-- packages/stryker-vue-mutator/src/index.ts | 14 +- .../test/helpers/globals.ts | 6 - .../test/helpers/initSinon.ts | 7 +- .../test/integration/VueMutator.it.ts | 30 ++-- .../test/unit/VueMutatorSpec.ts | 86 ++++++----- .../stryker-vue-mutator/tsconfig.test.json | 3 + packages/stryker/src/MutatorFacade.ts | 26 ---- packages/stryker/src/Stryker.ts | 77 ++++----- packages/stryker/src/di/buildMainInjector.ts | 5 +- packages/stryker/src/di/coreTokens.ts | 2 + .../src/{ => mutants}/MutantTestMatcher.ts | 76 ++++----- packages/stryker/src/mutants/MutatorFacade.ts | 54 +++++++ packages/stryker/src/mutators/ES5Mutator.ts | 32 ++-- packages/stryker/src/mutators/index.ts | 6 + .../src/process/MutationTestExecutor.ts | 2 +- .../src/transpiler/MutantTranspiler.ts | 2 +- .../stryker/test/unit/MutatorFacadeSpec.ts | 43 ------ packages/stryker/test/unit/StrykerSpec.ts | 64 +------- .../test/unit/di/buildMainInjector.spec.ts | 4 +- .../{ => mutants}/MutantTestMatcherSpec.ts | 146 ++++++++++-------- .../test/unit/mutants/MutatorFacadeSpec.ts | 93 +++++++++++ .../unit/mutators/ES5MutantGeneratorSpec.ts | 5 +- 62 files changed, 637 insertions(+), 578 deletions(-) delete mode 100644 packages/stryker-javascript-mutator/src/NodeMutatorFactory.ts create mode 100644 packages/stryker-javascript-mutator/test/unit/helpers/initSinon.ts create mode 100644 packages/stryker-typescript/src/mutator/index.ts delete mode 100644 packages/stryker-typescript/test/helpers/globals.ts delete mode 100644 packages/stryker-typescript/test/helpers/producers.ts delete mode 100644 packages/stryker-vue-mutator/test/helpers/globals.ts delete mode 100644 packages/stryker/src/MutatorFacade.ts rename packages/stryker/src/{ => mutants}/MutantTestMatcher.ts (69%) create mode 100644 packages/stryker/src/mutants/MutatorFacade.ts create mode 100644 packages/stryker/src/mutators/index.ts delete mode 100644 packages/stryker/test/unit/MutatorFacadeSpec.ts rename packages/stryker/test/unit/{ => mutants}/MutantTestMatcherSpec.ts (77%) create mode 100644 packages/stryker/test/unit/mutants/MutatorFacadeSpec.ts diff --git a/packages/stryker-javascript-mutator/package.json b/packages/stryker-javascript-mutator/package.json index afeb38feeb..ca7938479a 100644 --- a/packages/stryker-javascript-mutator/package.json +++ b/packages/stryker-javascript-mutator/package.json @@ -39,21 +39,14 @@ "@babel/parser": "~7.3.1", "@babel/traverse": "~7.2.2", "lodash": "~4.17.4", + "stryker-api": "^0.23.0", "tslib": "~1.9.3" }, "devDependencies": { "@babel/types": "~7.3.0", + "@stryker-mutator/test-helpers": "^0.0.0", "@types/babel__generator": "^7.0.0", "@types/babel__traverse": "^7.0.0", - "stryker-api": "^0.23.0", "stryker-mutator-specification": "^0.7.0" - }, - "peerDependencies": { - "stryker-api": ">=0.18.0 <0.24.0" - }, - "initStrykerConfig": { - "mutate": [ - "src/**/*.js" - ] } } diff --git a/packages/stryker-javascript-mutator/src/JavaScriptMutator.ts b/packages/stryker-javascript-mutator/src/JavaScriptMutator.ts index 33463cae65..1e78852b61 100644 --- a/packages/stryker-javascript-mutator/src/JavaScriptMutator.ts +++ b/packages/stryker-javascript-mutator/src/JavaScriptMutator.ts @@ -1,21 +1,19 @@ import * as types from '@babel/types'; -import { getLogger } from 'stryker-api/logging'; +import { Logger } from 'stryker-api/logging'; import { Mutator, Mutant } from 'stryker-api/mutant'; import { File } from 'stryker-api/core'; -import { Config } from 'stryker-api/config'; import copy from './helpers/copy'; -import NodeMutatorFactory from './NodeMutatorFactory'; -import NodeMutator from './mutators/NodeMutator'; +import { NodeMutator, NODE_MUTATORS_TOKEN } from './mutators/NodeMutator'; import BabelHelper from './helpers/BabelHelper'; +import { tokens, commonTokens } from 'stryker-api/plugin'; -function defaultMutators(): NodeMutator[] { - return NodeMutatorFactory.instance().knownNames().map(name => NodeMutatorFactory.instance().create(name, undefined)); -} - -export default class JavaScriptMutator implements Mutator { - private readonly log = getLogger(JavaScriptMutator.name); +export class JavaScriptMutator implements Mutator { - constructor(_: Config, private readonly mutators: NodeMutator[] = defaultMutators()) { } + public static inject = tokens(commonTokens.logger, NODE_MUTATORS_TOKEN) ; + constructor( + private readonly log: Logger, + private readonly mutators: ReadonlyArray + ) { } public mutate(inputFiles: File[]): Mutant[] { const mutants: Mutant[] = []; diff --git a/packages/stryker-javascript-mutator/src/NodeMutatorFactory.ts b/packages/stryker-javascript-mutator/src/NodeMutatorFactory.ts deleted file mode 100644 index 110ddfa7f6..0000000000 --- a/packages/stryker-javascript-mutator/src/NodeMutatorFactory.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Factory } from 'stryker-api/core'; -import NodeMutator from './mutators/NodeMutator'; - -namespace NodeMutatorFactory { - /** - * Represents a Factory for TestFrameworks. - */ - class NodeMutatorFactory extends Factory { - constructor() { - super('nodeMutator'); - } - } - const nodeMutatorFactoryInstance = new NodeMutatorFactory(); - - /** - * Returns the current instance of the MutatorFactory. - */ - export function instance() { - return nodeMutatorFactoryInstance as Factory; - } -} - -export default NodeMutatorFactory; diff --git a/packages/stryker-javascript-mutator/src/helpers/NodeGenerator.ts b/packages/stryker-javascript-mutator/src/helpers/NodeGenerator.ts index b13834f36f..6d2f7d79fb 100644 --- a/packages/stryker-javascript-mutator/src/helpers/NodeGenerator.ts +++ b/packages/stryker-javascript-mutator/src/helpers/NodeGenerator.ts @@ -1,6 +1,6 @@ import * as types from '@babel/types'; -export default class NodeGenerator { +export class NodeGenerator { public static createBooleanLiteralNode(originalNode: types.Node, value: boolean): types.BooleanLiteral { return { end: originalNode.end, diff --git a/packages/stryker-javascript-mutator/src/index.ts b/packages/stryker-javascript-mutator/src/index.ts index a846aa9868..1793c60ce2 100644 --- a/packages/stryker-javascript-mutator/src/index.ts +++ b/packages/stryker-javascript-mutator/src/index.ts @@ -1,5 +1,15 @@ -import { MutatorFactory } from 'stryker-api/mutant'; -import JavaScriptMutator from './JavaScriptMutator'; -require('./mutators'); +import { JavaScriptMutator } from './JavaScriptMutator'; +import { PluginKind, declareFactoryPlugin, commonTokens, tokens, Injector, OptionsContext } from 'stryker-api/plugin'; +import { NODE_MUTATORS_TOKEN } from './mutators/NodeMutator'; +import { nodeMutators } from './mutators'; -MutatorFactory.instance().register('javascript', JavaScriptMutator); +export const strykerPlugins = [ + declareFactoryPlugin(PluginKind.Mutator, 'javascript', javaScriptMutatorFactory) +]; + +function javaScriptMutatorFactory(injector: Injector): JavaScriptMutator { + return injector + .provideValue(NODE_MUTATORS_TOKEN, nodeMutators) + .injectClass(JavaScriptMutator); +} +javaScriptMutatorFactory.inject = tokens(commonTokens.injector); diff --git a/packages/stryker-javascript-mutator/src/mutators/ArrayLiteralMutator.ts b/packages/stryker-javascript-mutator/src/mutators/ArrayLiteralMutator.ts index 0f6aa48702..6ade8b4b93 100644 --- a/packages/stryker-javascript-mutator/src/mutators/ArrayLiteralMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/ArrayLiteralMutator.ts @@ -1,5 +1,5 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; +import { NodeMutator } from './NodeMutator'; /** * Represents a mutator which can remove the content of an array's elements. diff --git a/packages/stryker-javascript-mutator/src/mutators/ArrayNewExpressionMutator.ts b/packages/stryker-javascript-mutator/src/mutators/ArrayNewExpressionMutator.ts index a990dd5151..5122f14be0 100644 --- a/packages/stryker-javascript-mutator/src/mutators/ArrayNewExpressionMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/ArrayNewExpressionMutator.ts @@ -1,5 +1,5 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; +import { NodeMutator } from './NodeMutator'; /** * Represents a mutator which can remove the content of an array's elements. diff --git a/packages/stryker-javascript-mutator/src/mutators/BinaryExpressionMutator.ts b/packages/stryker-javascript-mutator/src/mutators/BinaryExpressionMutator.ts index d8a7f6a7be..0a910d682e 100644 --- a/packages/stryker-javascript-mutator/src/mutators/BinaryExpressionMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/BinaryExpressionMutator.ts @@ -1,5 +1,5 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; +import { NodeMutator } from './NodeMutator'; export default class BinaryExpressionMutator implements NodeMutator { private readonly operators: { [targetedOperator: string]: string | string[] } = { diff --git a/packages/stryker-javascript-mutator/src/mutators/BlockMutator.ts b/packages/stryker-javascript-mutator/src/mutators/BlockMutator.ts index 45816c7b35..78e6ed99eb 100644 --- a/packages/stryker-javascript-mutator/src/mutators/BlockMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/BlockMutator.ts @@ -1,5 +1,5 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; +import { NodeMutator } from './NodeMutator'; /** * Represents a mutator which can remove the content of a Block. diff --git a/packages/stryker-javascript-mutator/src/mutators/BooleanSubstitutionMutator.ts b/packages/stryker-javascript-mutator/src/mutators/BooleanSubstitutionMutator.ts index fe4892d07c..190105c276 100644 --- a/packages/stryker-javascript-mutator/src/mutators/BooleanSubstitutionMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/BooleanSubstitutionMutator.ts @@ -1,5 +1,5 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; +import { NodeMutator } from './NodeMutator'; export default class BooleanSubstitutionMutator implements NodeMutator { public name = 'BooleanSubstitution'; diff --git a/packages/stryker-javascript-mutator/src/mutators/ConditionalExpressionMutator.ts b/packages/stryker-javascript-mutator/src/mutators/ConditionalExpressionMutator.ts index 03c84efecf..a8093466bc 100644 --- a/packages/stryker-javascript-mutator/src/mutators/ConditionalExpressionMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/ConditionalExpressionMutator.ts @@ -1,6 +1,6 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; -import NodeGenerator from '../helpers/NodeGenerator'; +import { NodeMutator } from './NodeMutator'; +import { NodeGenerator } from '../helpers/NodeGenerator'; import { NodeWithParent } from '../helpers/ParentNode'; /** diff --git a/packages/stryker-javascript-mutator/src/mutators/DoStatementMutator.ts b/packages/stryker-javascript-mutator/src/mutators/DoStatementMutator.ts index 6008edb1c6..1689c4fd50 100644 --- a/packages/stryker-javascript-mutator/src/mutators/DoStatementMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/DoStatementMutator.ts @@ -1,6 +1,6 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; -import NodeGenerator from '../helpers/NodeGenerator'; +import { NodeMutator } from './NodeMutator'; +import { NodeGenerator } from '../helpers/NodeGenerator'; /** * Represents a mutator which can remove the conditional clause from statements. diff --git a/packages/stryker-javascript-mutator/src/mutators/ForStatementMutator.ts b/packages/stryker-javascript-mutator/src/mutators/ForStatementMutator.ts index 59ffe81f12..367e1bcd13 100644 --- a/packages/stryker-javascript-mutator/src/mutators/ForStatementMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/ForStatementMutator.ts @@ -1,6 +1,6 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; -import NodeGenerator from '../helpers/NodeGenerator'; +import { NodeMutator } from './NodeMutator'; +import { NodeGenerator } from '../helpers/NodeGenerator'; /** * Represents a mutator which can remove the conditional clause from statements. diff --git a/packages/stryker-javascript-mutator/src/mutators/IfStatementMutator.ts b/packages/stryker-javascript-mutator/src/mutators/IfStatementMutator.ts index 5d65362c35..3ca5e7cb4c 100644 --- a/packages/stryker-javascript-mutator/src/mutators/IfStatementMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/IfStatementMutator.ts @@ -1,6 +1,6 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; -import NodeGenerator from '../helpers/NodeGenerator'; +import { NodeMutator } from './NodeMutator'; +import { NodeGenerator } from '../helpers/NodeGenerator'; /** * Represents a mutator which can remove the conditional clause from statements. diff --git a/packages/stryker-javascript-mutator/src/mutators/NodeMutator.ts b/packages/stryker-javascript-mutator/src/mutators/NodeMutator.ts index 9e79c66805..4ca795f9a7 100644 --- a/packages/stryker-javascript-mutator/src/mutators/NodeMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/NodeMutator.ts @@ -1,10 +1,12 @@ import * as types from '@babel/types'; import { NodeWithParent } from '../helpers/ParentNode'; +export const NODE_MUTATORS_TOKEN = 'NodeMutators'; + /** * Represents a class which can mutate parts of an Abstract Syntax Tree. */ -export default interface NodeMutator { +export interface NodeMutator { /** * The name of the Mutator which may be used by reporters. */ diff --git a/packages/stryker-javascript-mutator/src/mutators/ObjectLiteralMutator.ts b/packages/stryker-javascript-mutator/src/mutators/ObjectLiteralMutator.ts index 2668734047..46a976f5ee 100644 --- a/packages/stryker-javascript-mutator/src/mutators/ObjectLiteralMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/ObjectLiteralMutator.ts @@ -1,5 +1,5 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; +import { NodeMutator } from './NodeMutator'; /** * Represents a mutator which can remove the content of a Object. diff --git a/packages/stryker-javascript-mutator/src/mutators/PostfixUnaryExpressionMutator.ts b/packages/stryker-javascript-mutator/src/mutators/PostfixUnaryExpressionMutator.ts index 5313fd3759..33343fd9e1 100644 --- a/packages/stryker-javascript-mutator/src/mutators/PostfixUnaryExpressionMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/PostfixUnaryExpressionMutator.ts @@ -1,5 +1,5 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; +import { NodeMutator } from './NodeMutator'; export default class PostfixUnaryExpressionMutator implements NodeMutator { public name = 'PostfixUnaryExpression'; diff --git a/packages/stryker-javascript-mutator/src/mutators/PrefixUnaryExpressionMutator.ts b/packages/stryker-javascript-mutator/src/mutators/PrefixUnaryExpressionMutator.ts index 25bc7491b6..88c411f060 100644 --- a/packages/stryker-javascript-mutator/src/mutators/PrefixUnaryExpressionMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/PrefixUnaryExpressionMutator.ts @@ -1,5 +1,5 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; +import { NodeMutator } from './NodeMutator'; export default class PrefixUnaryExpressionMutator implements NodeMutator { public name = 'PrefixUnaryExpression'; diff --git a/packages/stryker-javascript-mutator/src/mutators/StringLiteralMutator.ts b/packages/stryker-javascript-mutator/src/mutators/StringLiteralMutator.ts index 5665164b77..45023b853a 100644 --- a/packages/stryker-javascript-mutator/src/mutators/StringLiteralMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/StringLiteralMutator.ts @@ -1,5 +1,5 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; +import { NodeMutator } from './NodeMutator'; import { NodeWithParent } from '../helpers/ParentNode'; export default class StringLiteralMutator implements NodeMutator { diff --git a/packages/stryker-javascript-mutator/src/mutators/SwitchCaseMutator.ts b/packages/stryker-javascript-mutator/src/mutators/SwitchCaseMutator.ts index 37d5e1c9f6..c7a96d9bf9 100644 --- a/packages/stryker-javascript-mutator/src/mutators/SwitchCaseMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/SwitchCaseMutator.ts @@ -1,5 +1,5 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; +import { NodeMutator } from './NodeMutator'; import { NodeWithParent } from '../helpers/ParentNode'; /** diff --git a/packages/stryker-javascript-mutator/src/mutators/WhileStatementMutator.ts b/packages/stryker-javascript-mutator/src/mutators/WhileStatementMutator.ts index 106b3d27ad..48c8a8b1ac 100644 --- a/packages/stryker-javascript-mutator/src/mutators/WhileStatementMutator.ts +++ b/packages/stryker-javascript-mutator/src/mutators/WhileStatementMutator.ts @@ -1,6 +1,6 @@ import * as types from '@babel/types'; -import NodeMutator from './NodeMutator'; -import NodeGenerator from '../helpers/NodeGenerator'; +import { NodeMutator } from './NodeMutator'; +import { NodeGenerator } from '../helpers/NodeGenerator'; /** * Represents a mutator which can remove the conditional clause from statements. diff --git a/packages/stryker-javascript-mutator/src/mutators/index.ts b/packages/stryker-javascript-mutator/src/mutators/index.ts index db41b00334..4f62c8c346 100644 --- a/packages/stryker-javascript-mutator/src/mutators/index.ts +++ b/packages/stryker-javascript-mutator/src/mutators/index.ts @@ -1,4 +1,3 @@ -import NodeMutatorFactory from '../NodeMutatorFactory'; import ArrayLiteralMutator from './ArrayLiteralMutator'; import ArrayNewExpressionMutator from './ArrayNewExpressionMutator'; import BinaryExpressionMutator from './BinaryExpressionMutator'; @@ -15,19 +14,20 @@ import StringLiteralMutator from './StringLiteralMutator'; import SwitchCaseMutator from './SwitchCaseMutator'; import WhileStatementMutator from './WhileStatementMutator'; -const factory = NodeMutatorFactory.instance(); -factory.register(ArrayLiteralMutator.name, ArrayLiteralMutator); -factory.register(ArrayNewExpressionMutator.name, ArrayNewExpressionMutator); -factory.register(BinaryExpressionMutator.name, BinaryExpressionMutator); -factory.register(BlockMutator.name, BlockMutator); -factory.register(BooleanSubstitutionMutator.name, BooleanSubstitutionMutator); -factory.register(ConditionalExpressionMutator.name, ConditionalExpressionMutator); -factory.register(DoStatementMutator.name, DoStatementMutator); -factory.register(ForStatementMutator.name, ForStatementMutator); -factory.register(IfStatementMutator.name, IfStatementMutator); -factory.register(ObjectLiteralMutator.name, ObjectLiteralMutator); -factory.register(PostfixUnaryExpressionMutator.name, PostfixUnaryExpressionMutator); -factory.register(PrefixUnaryExpressionMutator.name, PrefixUnaryExpressionMutator); -factory.register(StringLiteralMutator.name, StringLiteralMutator); -factory.register(SwitchCaseMutator.name, SwitchCaseMutator); -factory.register(WhileStatementMutator.name, WhileStatementMutator); +export const nodeMutators = Object.freeze([ + new ArrayLiteralMutator(), + new ArrayNewExpressionMutator(), + new BinaryExpressionMutator(), + new BlockMutator(), + new BooleanSubstitutionMutator(), + new ConditionalExpressionMutator(), + new DoStatementMutator(), + new ForStatementMutator(), + new IfStatementMutator(), + new ObjectLiteralMutator(), + new PostfixUnaryExpressionMutator(), + new PrefixUnaryExpressionMutator(), + new StringLiteralMutator(), + new SwitchCaseMutator(), + new WhileStatementMutator() +]); diff --git a/packages/stryker-javascript-mutator/test/helpers/mutatorAssertions.ts b/packages/stryker-javascript-mutator/test/helpers/mutatorAssertions.ts index 5a63d9ab24..5123a92447 100644 --- a/packages/stryker-javascript-mutator/test/helpers/mutatorAssertions.ts +++ b/packages/stryker-javascript-mutator/test/helpers/mutatorAssertions.ts @@ -1,10 +1,10 @@ import { expect } from 'chai'; import { File } from 'stryker-api/core'; import { Mutant } from 'stryker-api/mutant'; -import { Config } from 'stryker-api/config'; -import JavaScriptMutator from '../../src/JavaScriptMutator'; -import NodeMutator from '../../src/mutators/NodeMutator'; +import { JavaScriptMutator } from '../../src/JavaScriptMutator'; +import { NodeMutator } from '../../src/mutators/NodeMutator'; import ExpectMutation from 'stryker-mutator-specification/src/ExpectMutation'; +import { testInjector } from '@stryker-mutator/test-helpers'; type MutatorConstructor = new() => NodeMutator; @@ -13,7 +13,7 @@ export function verifySpecification(specification: (name: string, expectMutation } export function expectMutation(mutator: NodeMutator, sourceText: string, ...expectedTexts: string[]) { - const javaScriptMutator = new JavaScriptMutator(new Config(), [mutator]); + const javaScriptMutator = new JavaScriptMutator(testInjector.logger, [mutator]); const sourceFile = new File('file.js', sourceText); const mutants = javaScriptMutator.mutate([sourceFile]); expect(mutants).lengthOf(expectedTexts.length); diff --git a/packages/stryker-javascript-mutator/test/unit/JavaScriptMutatorSpec.ts b/packages/stryker-javascript-mutator/test/unit/JavaScriptMutatorSpec.ts index 611bfa4f4f..d5ca5497af 100644 --- a/packages/stryker-javascript-mutator/test/unit/JavaScriptMutatorSpec.ts +++ b/packages/stryker-javascript-mutator/test/unit/JavaScriptMutatorSpec.ts @@ -1,13 +1,26 @@ import { expect } from 'chai'; import { File } from 'stryker-api/core'; -import JavaScriptMutator from '../../src/JavaScriptMutator'; -import '../../src/index'; -import { Config } from 'stryker-api/config'; +import { JavaScriptMutator } from '../../src/JavaScriptMutator'; +import { testInjector } from '@stryker-mutator/test-helpers'; +import { NodeMutator, NODE_MUTATORS_TOKEN } from '../../src/mutators/NodeMutator'; +import { nodeMutators } from '../../src/mutators'; describe('JavaScriptMutator', () => { + let selectedMutators: ReadonlyArray; + + beforeEach(() => { + selectedMutators = nodeMutators; + }); + + function createSut() { + return testInjector.injector + .provideValue(NODE_MUTATORS_TOKEN, selectedMutators) + .injectClass(JavaScriptMutator); + } + it('should generate a correct mutant', () => { - const mutator = new JavaScriptMutator(new Config()); + const mutator = createSut(); const files: File[] = [new File('testFile.js', '"use strict"; var a = 1 + 2;')]; const mutants = mutator.mutate(files); @@ -22,7 +35,7 @@ describe('JavaScriptMutator', () => { }); it('should generate mutant a correct mutant for jsx code', () => { - const mutator = new JavaScriptMutator(new Config()); + const mutator = createSut(); const files: File[] = [new File('testFile.jsx', ` "use strict"; import React from 'react' @@ -52,7 +65,7 @@ describe('JavaScriptMutator', () => { }); it('should not mutate unknown extensions', () => { - const mutator = new JavaScriptMutator(new Config()); + const mutator = createSut(); const files: File[] = [new File('testFile.html', ` @@ -69,7 +82,7 @@ describe('JavaScriptMutator', () => { }); it('should generate mutants for flow code', () => { - const mutator = new JavaScriptMutator(new Config()); + const mutator = createSut(); const files: File[] = [new File('testFile.js', ` // @flow import React from 'react' @@ -105,7 +118,7 @@ describe('JavaScriptMutator', () => { }); it('should generate mutants for js vnext code', () => { - const sut = new JavaScriptMutator(new Config()); + const sut = createSut(); const files: File[] = [new File('testFile.js', ` function objectRestSpread(input) { return { @@ -131,7 +144,7 @@ describe('JavaScriptMutator', () => { }); it('should generate mutants for multiple files', () => { - const mutator = new JavaScriptMutator(new Config()); + const mutator = createSut(); const file: File = new File('testFile.js', '"use strict"; var a = 1 + 2;'); const file2: File = new File('testFile2.js', '"use strict"; var a = 1 + 2;'); const mutants = mutator.mutate([file, file2]); diff --git a/packages/stryker-javascript-mutator/test/unit/helpers/initSinon.ts b/packages/stryker-javascript-mutator/test/unit/helpers/initSinon.ts new file mode 100644 index 0000000000..770a409879 --- /dev/null +++ b/packages/stryker-javascript-mutator/test/unit/helpers/initSinon.ts @@ -0,0 +1,11 @@ +import * as chai from 'chai'; +import * as chaiAsPromised from 'chai-as-promised'; +import * as sinon from 'sinon'; +import * as sinonChai from 'sinon-chai'; +import { testInjector } from '@stryker-mutator/test-helpers'; +chai.use(chaiAsPromised); +chai.use(sinonChai); +afterEach(() => { + sinon.restore(); + testInjector.reset(); +}); diff --git a/packages/stryker-javascript-mutator/tsconfig.src.json b/packages/stryker-javascript-mutator/tsconfig.src.json index 603d400a61..a0614147a9 100644 --- a/packages/stryker-javascript-mutator/tsconfig.src.json +++ b/packages/stryker-javascript-mutator/tsconfig.src.json @@ -9,9 +9,6 @@ "references": [ { "path": "../stryker-api/tsconfig.src.json", - }, - { - "path": "../stryker-mutator-specification/tsconfig.src.json" } ] } \ No newline at end of file diff --git a/packages/stryker-javascript-mutator/tsconfig.test.json b/packages/stryker-javascript-mutator/tsconfig.test.json index 6931176018..3a0ae29648 100644 --- a/packages/stryker-javascript-mutator/tsconfig.test.json +++ b/packages/stryker-javascript-mutator/tsconfig.test.json @@ -13,6 +13,12 @@ "references": [ { "path": "./tsconfig.src.json" + }, + { + "path": "../stryker-mutator-specification/tsconfig.src.json" + }, + { + "path": "../stryker-test-helpers/tsconfig.src.json" } ] } \ No newline at end of file diff --git a/packages/stryker-jest-runner/test/unit/JestConfigEditor.spec.ts b/packages/stryker-jest-runner/test/unit/JestConfigEditor.spec.ts index e07f2fc7a5..0f11c989c9 100644 --- a/packages/stryker-jest-runner/test/unit/JestConfigEditor.spec.ts +++ b/packages/stryker-jest-runner/test/unit/JestConfigEditor.spec.ts @@ -8,7 +8,7 @@ import ReactScriptsTSJestConfigLoader, * as reactScriptsTSJestConfigLoader from import { Configuration } from 'jest'; import { testInjector } from '@stryker-mutator/test-helpers'; -describe.only('JestConfigEditor', () => { +describe('JestConfigEditor', () => { let sut: JestConfigEditor; let customConfigLoaderStub: ConfigLoaderStub; let reactScriptsJestConfigLoaderStub: ConfigLoaderStub; diff --git a/packages/stryker-typescript/package.json b/packages/stryker-typescript/package.json index 75b2237e2a..37a070dd4b 100644 --- a/packages/stryker-typescript/package.json +++ b/packages/stryker-typescript/package.json @@ -38,18 +38,17 @@ "@stryker-mutator/util": "~0.0.3", "lodash.flatmap": "~4.5.0", "semver": "~5.6.0", + "stryker-api": "^0.23.0", "tslib": "~1.9.3" }, "devDependencies": { "@stryker-mutator/test-helpers": "0.0.0", "@types/lodash.flatmap": "~4.5.3", "@types/semver": "~5.5.0", - "stryker-api": "^0.23.0", "stryker-mutator-specification": "^0.7.0", "surrial": "~0.1.3" }, "peerDependencies": { - "stryker-api": ">=0.18.0 <0.24.0", "typescript": "^3.0.3" }, "initStrykerConfig": { diff --git a/packages/stryker-typescript/src/TypescriptMutator.ts b/packages/stryker-typescript/src/TypescriptMutator.ts index 7a29b1fbc6..211deb2c0e 100644 --- a/packages/stryker-typescript/src/TypescriptMutator.ts +++ b/packages/stryker-typescript/src/TypescriptMutator.ts @@ -1,48 +1,27 @@ import * as ts from 'typescript'; import flatMap = require('lodash.flatmap'); -import { File } from 'stryker-api/core'; +import { File, StrykerOptions } from 'stryker-api/core'; import { Mutant } from 'stryker-api/mutant'; -import { Config } from 'stryker-api/config'; import { parseFile, getTSConfig } from './helpers/tsHelpers'; import NodeMutator from './mutator/NodeMutator'; -import BinaryExpressionMutator from './mutator/BinaryExpressionMutator'; -import BooleanSubstitutionMutator from './mutator/BooleanSubstitutionMutator'; -import ArrayLiteralMutator from './mutator/ArrayLiteralMutator'; -import ArrayNewExpressionMutator from './mutator/ArrayNewExpressionMutator'; -import BlockMutator from './mutator/BlockMutator'; -import IfStatementMutator from './mutator/IfStatementMutator'; -import ObjectLiteralMutator from './mutator/ObjectLiteralMutator'; -import WhileStatementMutator from './mutator/WhileStatementMutator'; -import ForStatementMutator from './mutator/ForStatementMutator'; -import DoStatementMutator from './mutator/DoStatementMutator'; -import ConditionalExpressionMutator from './mutator/ConditionalExpressionMutator'; -import PrefixUnaryExpressionMutator from './mutator/PrefixUnaryExpressionMutator'; -import ArrowFunctionMutator from './mutator/ArrowFunctionMutator'; -import StringLiteralMutator from './mutator/StringLiteralMutator'; -import SwitchCaseMutator from './mutator/SwitchCaseMutator'; +import { commonTokens, tokens, Injector, OptionsContext } from 'stryker-api/plugin'; +import { nodeMutators } from './mutator'; -export default class TypescriptMutator { +export function typescriptMutatorFactory(injector: Injector): TypescriptMutator { + return injector + .provideValue(MUTATORS_TOKEN, nodeMutators) + .injectClass(TypescriptMutator); +} +typescriptMutatorFactory.inject = tokens(commonTokens.injector); + +export const MUTATORS_TOKEN = 'mutators'; +export class TypescriptMutator { - constructor(private readonly config: Config, public mutators: NodeMutator[] = [ - new BinaryExpressionMutator(), - new BooleanSubstitutionMutator(), - new ArrayLiteralMutator(), - new ArrayNewExpressionMutator(), - new BlockMutator(), - new ArrowFunctionMutator(), - new IfStatementMutator(), - new ObjectLiteralMutator(), - new WhileStatementMutator(), - new ForStatementMutator(), - new DoStatementMutator(), - new ConditionalExpressionMutator(), - new PrefixUnaryExpressionMutator(), - new StringLiteralMutator(), - new SwitchCaseMutator(), - ]) { } + public static inject = tokens(commonTokens.options, MUTATORS_TOKEN); + constructor(private readonly options: StrykerOptions, public mutators: ReadonlyArray) { } public mutate(inputFiles: File[]): Mutant[] { - const tsConfig = getTSConfig(this.config); + const tsConfig = getTSConfig(this.options); const mutants = flatMap(inputFiles, inputFile => { const sourceFile = parseFile(inputFile, tsConfig && tsConfig.options && tsConfig.options.target); return this.mutateForNode(sourceFile, sourceFile); diff --git a/packages/stryker-typescript/src/index.ts b/packages/stryker-typescript/src/index.ts index 32cd36cae6..54f14b079e 100644 --- a/packages/stryker-typescript/src/index.ts +++ b/packages/stryker-typescript/src/index.ts @@ -1,11 +1,10 @@ -import { MutatorFactory } from 'stryker-api/mutant'; -import { declareClassPlugin, PluginKind } from 'stryker-api/plugin'; +import { declareClassPlugin, PluginKind, declareFactoryPlugin } from 'stryker-api/plugin'; import TypescriptConfigEditor from './TypescriptConfigEditor'; -import TypescriptMutator from './TypescriptMutator'; +import { typescriptMutatorFactory } from './TypescriptMutator'; import TypescriptTranspiler from './TypescriptTranspiler'; export const strykerPlugins = [ declareClassPlugin(PluginKind.ConfigEditor, 'typescript', TypescriptConfigEditor), - declareClassPlugin(PluginKind.Transpiler, 'typescript', TypescriptTranspiler) + declareClassPlugin(PluginKind.Transpiler, 'typescript', TypescriptTranspiler), + declareFactoryPlugin(PluginKind.Mutator, 'typescript', typescriptMutatorFactory) ]; -MutatorFactory.instance().register('typescript', TypescriptMutator); diff --git a/packages/stryker-typescript/src/mutator/index.ts b/packages/stryker-typescript/src/mutator/index.ts new file mode 100644 index 0000000000..821d69fd40 --- /dev/null +++ b/packages/stryker-typescript/src/mutator/index.ts @@ -0,0 +1,34 @@ +import NodeMutator from './NodeMutator'; +import SwitchCaseMutator from './SwitchCaseMutator'; +import StringLiteralMutator from './StringLiteralMutator'; +import BinaryExpressionMutator from './BinaryExpressionMutator'; +import BooleanSubstitutionMutator from './BooleanSubstitutionMutator'; +import ArrayLiteralMutator from './ArrayLiteralMutator'; +import ArrayNewExpressionMutator from './ArrayNewExpressionMutator'; +import BlockMutator from './BlockMutator'; +import ArrowFunctionMutator from './ArrowFunctionMutator'; +import IfStatementMutator from './IfStatementMutator'; +import ObjectLiteralMutator from './ObjectLiteralMutator'; +import WhileStatementMutator from './WhileStatementMutator'; +import ForStatementMutator from './ForStatementMutator'; +import DoStatementMutator from './DoStatementMutator'; +import ConditionalExpressionMutator from './ConditionalExpressionMutator'; +import PrefixUnaryExpressionMutator from './PrefixUnaryExpressionMutator'; + +export const nodeMutators: ReadonlyArray = [ + new BinaryExpressionMutator(), + new BooleanSubstitutionMutator(), + new ArrayLiteralMutator(), + new ArrayNewExpressionMutator(), + new BlockMutator(), + new ArrowFunctionMutator(), + new IfStatementMutator(), + new ObjectLiteralMutator(), + new WhileStatementMutator(), + new ForStatementMutator(), + new DoStatementMutator(), + new ConditionalExpressionMutator(), + new PrefixUnaryExpressionMutator(), + new StringLiteralMutator(), + new SwitchCaseMutator(), +]; diff --git a/packages/stryker-typescript/test/helpers/globals.ts b/packages/stryker-typescript/test/helpers/globals.ts deleted file mode 100644 index 8d26910fe6..0000000000 --- a/packages/stryker-typescript/test/helpers/globals.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare const sandbox: sinon.SinonSandbox; -namespace NodeJS { - export interface Global { - sandbox: sinon.SinonSandbox; - } -} diff --git a/packages/stryker-typescript/test/helpers/producers.ts b/packages/stryker-typescript/test/helpers/producers.ts deleted file mode 100644 index f8b045f967..0000000000 --- a/packages/stryker-typescript/test/helpers/producers.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as sinon from 'sinon'; -import { Logger } from 'stryker-api/logging'; - -export type Mock = { [P in keyof T]: sinon.SinonStub; }; - -export type Constructor = new (...args: any[]) => T; - -export function mock(constructorFn: Constructor): sinon.SinonStubbedInstance { - return sinon.createStubInstance(constructorFn); -} - -export const logger = (): Mock => { - return { - debug: sinon.stub(), - error: sinon.stub(), - fatal: sinon.stub(), - info: sinon.stub(), - isDebugEnabled: sinon.stub(), - isErrorEnabled: sinon.stub(), - isFatalEnabled: sinon.stub(), - isInfoEnabled: sinon.stub(), - isTraceEnabled: sinon.stub(), - isWarnEnabled: sinon.stub(), - trace: sinon.stub(), - warn: sinon.stub() - }; -}; diff --git a/packages/stryker-typescript/test/integration/sampleSpec.ts b/packages/stryker-typescript/test/integration/sampleSpec.ts index d7d6e8aa0f..a599b935f6 100644 --- a/packages/stryker-typescript/test/integration/sampleSpec.ts +++ b/packages/stryker-typescript/test/integration/sampleSpec.ts @@ -5,7 +5,7 @@ import { expect } from 'chai'; import { Config } from 'stryker-api/config'; import { File } from 'stryker-api/core'; import TypescriptConfigEditor from '../../src/TypescriptConfigEditor'; -import TypescriptMutator from '../../src/TypescriptMutator'; +import { typescriptMutatorFactory } from '../../src/TypescriptMutator'; import TypescriptTranspiler from '../../src/TypescriptTranspiler'; import { CONFIG_KEY } from '../../src/helpers/keys'; import { testInjector } from '@stryker-mutator/test-helpers'; @@ -23,11 +23,12 @@ describe('Sample integration', () => { }); configEditor.edit(config); inputFiles = config[CONFIG_KEY].fileNames.map((fileName: string) => new File(fileName, fs.readFileSync(fileName, 'utf8'))); + testInjector.options = config; }); it('should be able to generate mutants', () => { // Generate mutants - const mutator = new TypescriptMutator(config); + const mutator = testInjector.injector.injectFunction(typescriptMutatorFactory); const mutants = mutator.mutate(inputFiles); expect(mutants.length).to.eq(5); }); @@ -52,7 +53,7 @@ describe('Sample integration', () => { it('should be able to transpile mutated code', async () => { // Transpile mutants - const mutator = new TypescriptMutator(config); + const mutator = testInjector.injector.injectFunction(typescriptMutatorFactory); const mutants = mutator.mutate(inputFiles); const transpiler = new TypescriptTranspiler(config, /*produceSourceMaps: */ false); transpiler.transpile(inputFiles); diff --git a/packages/stryker-typescript/test/unit/TypescriptMutatorSpec.ts b/packages/stryker-typescript/test/unit/TypescriptMutatorSpec.ts index 4a391a9e8b..56837666e1 100644 --- a/packages/stryker-typescript/test/unit/TypescriptMutatorSpec.ts +++ b/packages/stryker-typescript/test/unit/TypescriptMutatorSpec.ts @@ -2,10 +2,10 @@ import * as path from 'path'; import * as fs from 'fs'; import { expect } from 'chai'; import * as ts from 'typescript'; -import { Config } from 'stryker-api/config'; import { File } from 'stryker-api/core'; -import TypescriptMutator from '../../src/TypescriptMutator'; +import { TypescriptMutator, MUTATORS_TOKEN, typescriptMutatorFactory } from '../../src/TypescriptMutator'; import NodeMutator, { NodeReplacement } from '../../src/mutator/NodeMutator'; +import { testInjector } from '@stryker-mutator/test-helpers'; class FunctionDeclarationMutator extends NodeMutator { public name = 'FunctionDeclarationForTest'; @@ -30,13 +30,17 @@ class SourceFileMutator extends NodeMutator { } } +function createSut() { + return testInjector.injector + .provideValue(MUTATORS_TOKEN, [ + new SourceFileMutator(), + new FunctionDeclarationMutator() + ]) + .injectClass(TypescriptMutator); +} + describe('TypescriptMutator', () => { let sut: TypescriptMutator; - let config: Config; - - beforeEach(() => { - config = new Config(); - }); it('should register all mutators by default', () => { // Arrange @@ -44,11 +48,12 @@ describe('TypescriptMutator', () => { .readdirSync(path.resolve(__dirname, '..', '..', 'src', 'mutator')) .filter(mutatorFile => path.extname(mutatorFile) === '.ts' && !mutatorFile.endsWith('.d.ts') - && mutatorFile !== 'NodeMutator.ts') + && mutatorFile !== 'NodeMutator.ts' + && mutatorFile !== 'index.ts') .map(fileName => fileName.substr(0, fileName.length - 'Mutator.ts'.length)); // Act - const actualMutators = new TypescriptMutator(config).mutators.map(m => m.name); + const actualMutators = testInjector.injector.injectFunction(typescriptMutatorFactory).mutators.map(m => m.name); // Assert expect(expectedMutatorNames).length.greaterThan(2); // sanity check @@ -61,10 +66,7 @@ describe('TypescriptMutator', () => { let file2: File; beforeEach(() => { - sut = new TypescriptMutator(config, [ - new FunctionDeclarationMutator(), - new SourceFileMutator() - ]); + sut = createSut(); file1 = new File( 'file1.ts', `function add(n...: number[]) { diff --git a/packages/stryker-typescript/test/unit/TypescriptTranspilerSpec.ts b/packages/stryker-typescript/test/unit/TypescriptTranspilerSpec.ts index 3f75e16dab..02d2f0866b 100644 --- a/packages/stryker-typescript/test/unit/TypescriptTranspilerSpec.ts +++ b/packages/stryker-typescript/test/unit/TypescriptTranspilerSpec.ts @@ -1,6 +1,5 @@ import TranspilingLanguageService, * as transpilingLanguageService from '../../src/transpiler/TranspilingLanguageService'; import { expect } from 'chai'; -import { Mock, mock } from '../helpers/producers'; import TypescriptTranspiler from '../../src/TypescriptTranspiler'; import { File } from 'stryker-api/core'; import { EmitOutput } from '../../src/transpiler/TranspilingLanguageService'; @@ -12,12 +11,12 @@ import { commonTokens } from 'stryker-api/plugin'; describe('TypescriptTranspiler', () => { - let languageService: Mock; + let languageService: sinon.SinonStubbedInstance; let sut: TypescriptTranspiler; - let transpileFilterMock: Mock; + let transpileFilterMock: sinon.SinonStubbedInstance; beforeEach(() => { - languageService = mock(TranspilingLanguageService); + languageService = sinon.createStubInstance(TranspilingLanguageService); transpileFilterMock = { // Cannot use `mock` as it is an abstract class isIncluded: sinon.stub() diff --git a/packages/stryker-vue-mutator/package.json b/packages/stryker-vue-mutator/package.json index bbb2e466d7..3b84b4e7a0 100644 --- a/packages/stryker-vue-mutator/package.json +++ b/packages/stryker-vue-mutator/package.json @@ -31,13 +31,15 @@ "homepage": "https://github.com/stryker-mutator/stryker/tree/master/packages/stryker-vue-mutator#readme", "license": "Apache-2.0", "devDependencies": { - "stryker-api": "^0.23.0", + "@stryker-mutator/test-helpers": "^0.0.0", "stryker-javascript-mutator": "^0.13.0", "stryker-typescript": "^0.17.0", "vue-template-compiler": "^2.0.0" }, + "dependencies": { + "stryker-api": "^0.23.0" + }, "peerDependencies": { - "stryker-api": ">=0.18.0 <0.24.0", "vue-template-compiler": "^2.0.0" } } diff --git a/packages/stryker-vue-mutator/src/VueMutator.ts b/packages/stryker-vue-mutator/src/VueMutator.ts index 678f4660e6..67b945e55f 100644 --- a/packages/stryker-vue-mutator/src/VueMutator.ts +++ b/packages/stryker-vue-mutator/src/VueMutator.ts @@ -1,17 +1,16 @@ -import { Config } from 'stryker-api/config'; import { File } from 'stryker-api/core'; import { Mutant, Mutator } from 'stryker-api/mutant'; -import { discoverMutators } from './helpers/MutatorHelpers'; +import { MUTATORS_TOKEN } from './helpers/MutatorHelpers'; +import { tokens } from 'stryker-api/plugin'; const compiler = require('vue-template-compiler'); export default class VueMutator implements Mutator { - private readonly mutators: { [name: string]: Mutator; }; private readonly javascriptMutatorName = 'javascript'; private readonly typescriptMutatorName = 'typescript'; - constructor(config: Config) { - this.mutators = discoverMutators(config); + constructor(private readonly mutators: { [name: string]: Mutator; }) { } + public static inject = tokens(MUTATORS_TOKEN); public mutate(inputFiles: File[]): Mutant[] { const mutants: Mutant[] = []; diff --git a/packages/stryker-vue-mutator/src/helpers/MutatorHelpers.ts b/packages/stryker-vue-mutator/src/helpers/MutatorHelpers.ts index 9edf3da9b6..ba0c664959 100644 --- a/packages/stryker-vue-mutator/src/helpers/MutatorHelpers.ts +++ b/packages/stryker-vue-mutator/src/helpers/MutatorHelpers.ts @@ -1,15 +1,29 @@ -import { Mutator, MutatorFactory } from 'stryker-api/mutant'; -import { Config } from 'stryker-api/config'; +import { Mutator } from 'stryker-api/mutant'; +import { PluginResolver, Injector, OptionsContext, PluginKind, InjectionToken, Plugin, FactoryPlugin, tokens, commonTokens } from 'stryker-api/plugin'; -const discoverMutators = (config: Config): { [name: string]: Mutator; } => { +export const MUTATORS_TOKEN = 'mutators'; + +mutatorsFactory.inject = tokens(commonTokens.pluginResolver, commonTokens.injector); +export function mutatorsFactory(pluginResolver: PluginResolver, injector: Injector) { const mutators: { [name: string]: Mutator; } = {}; - const factory = MutatorFactory.instance(); - factory.knownNames().forEach(name => { - if (name !== 'es5' && name !== 'vue') { - mutators[name] = factory.create(name, config); + const mutatorPlugins = pluginResolver.resolveAll(PluginKind.Mutator); + mutatorPlugins.forEach(plugin => { + if (plugin.name !== 'es5' && plugin.name !== 'vue') { + mutators[plugin.name] = createPlugin(injector, plugin); } }); return mutators; -}; +} + +function createPlugin(injector: Injector, plugin: Plugin[]>): Mutator { + if (isFactoryPlugin(plugin)) { + return injector.injectFunction(plugin.factory); + } else { + return injector.injectClass(plugin.injectableClass); + } +} -export { discoverMutators }; +function isFactoryPlugin(plugin: Plugin[]>): + plugin is FactoryPlugin[]> { + return !!(plugin as FactoryPlugin[]>).factory; +} diff --git a/packages/stryker-vue-mutator/src/index.ts b/packages/stryker-vue-mutator/src/index.ts index 74ecf84502..6dfaafcf1b 100644 --- a/packages/stryker-vue-mutator/src/index.ts +++ b/packages/stryker-vue-mutator/src/index.ts @@ -1,4 +1,14 @@ -import { MutatorFactory } from 'stryker-api/mutant'; import VueMutator from './VueMutator'; +import { declareFactoryPlugin, PluginKind, Injector, OptionsContext, tokens, commonTokens } from 'stryker-api/plugin'; +import { mutatorsFactory, MUTATORS_TOKEN } from './helpers/MutatorHelpers'; -MutatorFactory.instance().register('vue', VueMutator); +export const strykerPlugins = [ + declareFactoryPlugin(PluginKind.Mutator, 'vue', vueMutatorFactory) +]; + +function vueMutatorFactory(injector: Injector) { + return injector + .provideFactory(MUTATORS_TOKEN, mutatorsFactory) + .injectClass(VueMutator); +} +vueMutatorFactory.inject = tokens(commonTokens.injector); diff --git a/packages/stryker-vue-mutator/test/helpers/globals.ts b/packages/stryker-vue-mutator/test/helpers/globals.ts deleted file mode 100644 index 8d26910fe6..0000000000 --- a/packages/stryker-vue-mutator/test/helpers/globals.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare const sandbox: sinon.SinonSandbox; -namespace NodeJS { - export interface Global { - sandbox: sinon.SinonSandbox; - } -} diff --git a/packages/stryker-vue-mutator/test/helpers/initSinon.ts b/packages/stryker-vue-mutator/test/helpers/initSinon.ts index de71b2d71a..770a409879 100644 --- a/packages/stryker-vue-mutator/test/helpers/initSinon.ts +++ b/packages/stryker-vue-mutator/test/helpers/initSinon.ts @@ -2,11 +2,10 @@ import * as chai from 'chai'; import * as chaiAsPromised from 'chai-as-promised'; import * as sinon from 'sinon'; import * as sinonChai from 'sinon-chai'; +import { testInjector } from '@stryker-mutator/test-helpers'; chai.use(chaiAsPromised); chai.use(sinonChai); -beforeEach(() => { - global.sandbox = sinon.createSandbox(); -}); afterEach(() => { - global.sandbox.restore(); + sinon.restore(); + testInjector.reset(); }); diff --git a/packages/stryker-vue-mutator/test/integration/VueMutator.it.ts b/packages/stryker-vue-mutator/test/integration/VueMutator.it.ts index 26d3af6a9a..67d9ef98a3 100644 --- a/packages/stryker-vue-mutator/test/integration/VueMutator.it.ts +++ b/packages/stryker-vue-mutator/test/integration/VueMutator.it.ts @@ -1,16 +1,26 @@ import { expect } from 'chai'; -import { Config } from 'stryker-api/config'; import { File } from 'stryker-api/core'; -import { MutatorFactory } from 'stryker-api/mutant'; -import VueMutator from '../../src/VueMutator'; -import '../../src/index'; -import 'stryker-javascript-mutator'; -import 'stryker-typescript'; +import { strykerPlugins } from '../../src/index'; +import { testInjector } from '@stryker-mutator/test-helpers'; +import { PluginKind } from 'stryker-api/plugin'; +import { Mutator } from 'stryker-api/mutant'; +import { strykerPlugins as javascriptMutatorStrykerPlugins } from 'stryker-javascript-mutator'; +import { strykerPlugins as typescriptMutatorStrykerPlugins } from 'stryker-typescript'; + +const javascriptMutatorPlugin = javascriptMutatorStrykerPlugins.find(plugin => plugin.kind === PluginKind.Mutator); +const typescriptMutatorPlugin = typescriptMutatorStrykerPlugins.find(plugin => plugin.kind === PluginKind.Mutator); describe('VueMutator', () => { + + function createSut(): Mutator { + return testInjector.injector + .injectFunction(strykerPlugins[0].factory); + } + describe('JavaScript project', () => { it('should generate mutants', () => { - sandbox.stub(MutatorFactory.instance(), 'knownNames').returns(['javascript']); + testInjector.pluginResolver.resolveAll.returns([javascriptMutatorPlugin]); + const vueCode = ` @@ -39,7 +49,7 @@ describe('VueMutator', () => { return user.age >= 18; }`; const files = [new File('AppComponent.vue', vueCode), new File('age.js', jsCode)]; - const sut = new VueMutator(new Config()); + const sut = createSut(); const mutants = sut.mutate(files); @@ -51,7 +61,7 @@ describe('VueMutator', () => { describe('TypeScript project', () => { it('should generate mutants', () => { - sandbox.stub(MutatorFactory.instance(), 'knownNames').returns(['typescript']); + testInjector.pluginResolver.resolveAll.returns([typescriptMutatorPlugin]); const vueCode = ` @@ -79,7 +89,7 @@ describe('VueMutator', () => { return user.age >= 18; }`; const files = [new File('AppComponent.vue', vueCode), new File('age.ts', jsCode)]; - const sut = new VueMutator(new Config()); + const sut = createSut(); const mutants = sut.mutate(files); diff --git a/packages/stryker-vue-mutator/test/unit/VueMutatorSpec.ts b/packages/stryker-vue-mutator/test/unit/VueMutatorSpec.ts index 6cc1dee510..c420204c96 100644 --- a/packages/stryker-vue-mutator/test/unit/VueMutatorSpec.ts +++ b/packages/stryker-vue-mutator/test/unit/VueMutatorSpec.ts @@ -1,33 +1,34 @@ import { expect } from 'chai'; -import { Config } from 'stryker-api/config'; import { File } from 'stryker-api/core'; import { Mutant, Mutator } from 'stryker-api/mutant'; import * as MutatorHelpers from '../../src/helpers/MutatorHelpers'; import VueMutator from '../../src/VueMutator'; import { SinonStubbedInstance } from 'sinon'; +import * as sinon from 'sinon'; +import { testInjector } from '@stryker-mutator/test-helpers'; describe('VueMutator', () => { - let config: Config; let stubJavaScriptMutator: SinonStubbedInstance; let stubTypeScriptMutator: SinonStubbedInstance; + let mutators: { [name: string]: Mutator }; beforeEach(() => { - config = new Config(); - stubJavaScriptMutator = sandbox.createStubInstance(VueMutator); + mutators = {}; + stubJavaScriptMutator = sinon.createStubInstance(VueMutator); stubJavaScriptMutator.mutate.returns([]); - stubTypeScriptMutator = sandbox.createStubInstance(VueMutator); + stubTypeScriptMutator = sinon.createStubInstance(VueMutator); stubTypeScriptMutator.mutate.returns([]); }); - const setMutators = (mutators: { [name: string]: Mutator }) => sandbox.stub(MutatorHelpers, 'discoverMutators').returns(mutators); - const activateNoMutators = () => setMutators({}); - const activateJavaScriptMutator = () => setMutators({ javascript: stubJavaScriptMutator }); - const activateTypeScriptMutator = () => setMutators({ typescript: stubTypeScriptMutator }); - const activateJavaScriptAndTypeScriptMutators = () => setMutators({ javascript: stubJavaScriptMutator, typescript: stubTypeScriptMutator }); + function createSut() { + return testInjector.injector + .provideValue(MutatorHelpers.MUTATORS_TOKEN, mutators) + .injectClass(VueMutator); + } describe('with JavaScript', () => { it('should throw an error if no JavaScript mutator is installed', () => { - activateNoMutators(); + mutators = {}; const vueFile = new File('Component.vue', ` `); const files = [vueFile]; - const sut = new VueMutator(config); + const sut = createSut(); sut.mutate(files); @@ -116,7 +117,7 @@ describe('VueMutator', () => { }); it('should pass Vue script blocks with lang="javascript" to the JavaScript mutator', () => { - activateJavaScriptMutator(); + mutators = { javascript: stubJavaScriptMutator }; const script = `export default { data () { return { @@ -130,7 +131,7 @@ describe('VueMutator', () => { `); const files = [vueFile]; - const sut = new VueMutator(config); + const sut = createSut(); sut.mutate(files); @@ -138,10 +139,10 @@ describe('VueMutator', () => { }); it('should pass regular files to the TypeScript mutator, even if the JavaScript mutator is installed', () => { - activateJavaScriptAndTypeScriptMutators(); + mutators = { javascript: stubJavaScriptMutator, typescript: stubTypeScriptMutator }; const jsFile = new File('index.js', 'var name = "MyApp";'); const files = [jsFile]; - const sut = new VueMutator(config); + const sut = createSut(); sut.mutate(files); @@ -150,10 +151,10 @@ describe('VueMutator', () => { }); it('should pass regular files to the JavaScript mutator', () => { - activateJavaScriptMutator(); + mutators = { javascript: stubJavaScriptMutator }; const jsFile = new File('index.js', 'var name = "MyApp";'); const files = [jsFile]; - const sut = new VueMutator(config); + const sut = createSut(); sut.mutate(files); @@ -163,7 +164,7 @@ describe('VueMutator', () => { describe('with TypeScript', () => { it('should throw an error if no TypeScript mutator is installed', () => { - activateNoMutators(); + mutators = {}; const vueFile = new File('Component.vue', ` `); const files = [vueFile]; - const sut = new VueMutator(config); + const sut = createSut(); sut.mutate(files); @@ -252,10 +253,10 @@ describe('VueMutator', () => { }); it('should pass regular files to the TypeScript mutator', () => { - activateTypeScriptMutator(); + mutators = { typescript: stubTypeScriptMutator }; const jsFile = new File('index.js', 'var name = "MyApp";'); const files = [jsFile]; - const sut = new VueMutator(config); + const sut = createSut(); sut.mutate(files); @@ -264,27 +265,28 @@ describe('VueMutator', () => { }); it('should throw an error when a Vue script block has an unknown lang attribute', () => { - activateNoMutators(); - const script = `export default { + mutators = {}; + const script = `export default { data () { return { message: 'hello!' } } }`; - const vueFile = new File('Component.vue', + const vueFile = new File('Component.vue', ` `); - const files = [vueFile]; - const sut = new VueMutator(config); + const files = [vueFile]; + const sut = createSut(); - expect(() => sut.mutate(files)).throws(`Found unsupported language attribute 'lang="coffeescript"' on a