Best JavaScript code snippet using stryker-parent
incremental-differ.spec.ts
Source:incremental-differ.spec.ts
1import path from 'path';2import { Mutant, MutantStatus, schema } from '@stryker-mutator/api/core';3import { factory, testInjector } from '@stryker-mutator/test-helpers';4import { deepFreeze } from '@stryker-mutator/util';5import { expect } from 'chai';6import chalk from 'chalk';7import sinon from 'sinon';8import { IncrementalDiffer } from '../../../src/mutants/index.js';9import { createMutant, loc, pos } from '../../helpers/producers.js';10import { TestCoverageTestDouble } from '../../helpers/test-coverage-test-double.js';11// Keep this files here for the indenting12const srcAddContent = `export function add(a, b) {13 return a + b;14} 15`;16const testAddContent = `import { expect } from 'chai';17import { add } from '../src/add.js';18describe('add' () => {19 it('should result in 42 for 2 and 40', () => {20 expect(add(40, 2)).eq(42);21 });22});23`;24const testAddContentTwoTests = `import { expect } from 'chai';25import { add } from '../src/add.js';26describe('add' () => {27 it('should result in 42 for 2 and 40', () => {28 expect(add(40, 2)).eq(42);29 });30 it('should result in 42 for 45 and -3', () => {31 expect(add(45, -3)).eq(42);32 });33});34`;35const testAddContentWithTestGeneration = `import { expect } from 'chai';36import { add } from '../src/add.js';37describe('add' () => {38 for(const [a, b, answer] of [[40, 2, 42], [45, -3, 42]]) {39 it(\`should result in \${answer} for \${a} and \${b}\`, () => {40 expect(add(a, b)).eq(answer);41 });42 }43 it('should have name "add"', () => {44 expect(add.name).eq('add');45 });46});47`;48const testAddContentWithTestGenerationUpdated = `import { expect } from 'chai';49import { add } from '../src/add.js';50describe('add' () => {51 for(const [a, b, answer] of [[40, 2, 42], [45, -3, 42]]) {52 it(\`should result in \${answer} for \${a} and \${b}\`, () => {53 expect(add(a, b)).eq(answer);54 });55 }56 it('should have name "add"', () => {57 // Add a comment as change58 expect(add.name).eq('add');59 });60});61`;62const srcMultiplyContent = `export function multiply(a, b) {63 return a * b;64}`;65const testMultiplyContent = `import { expect } from 'chai';66import { multiply } from '../src/multiply.js';67describe('multiply' () => {68 it('should result in 42 for 2 and 21', () => {69 expect(multiply(2, 21)).eq(42);70 });71});72`;73const srcAdd = 'src/add.js';74const srcMultiply = 'src/multiply.js';75const testAdd = 'test/add.spec.js';76const testMultiply = 'test/multiply.spec.js';77class ScenarioBuilder {78 public readonly oldSpecId = 'spec-1';79 public readonly newTestId = 'new-spec-2';80 public readonly mutantId = '2';81 public incrementalFiles: schema.FileResultDictionary = {};82 public incrementalTestFiles: schema.TestFileDefinitionDictionary = {};83 public currentFiles = new Map<string, string>();84 public mutants: Mutant[] = [];85 public testCoverage = new TestCoverageTestDouble();86 public sut?: IncrementalDiffer;87 public withMathProjectExample({ mutantState: mutantStatus = MutantStatus.Killed, isStatic = false } = {}): this {88 this.mutants.push(89 createMutant({ id: this.mutantId, fileName: srcAdd, replacement: '-', mutatorName: 'min-replacement', location: loc(1, 11, 1, 12) })90 );91 this.incrementalFiles[srcAdd] = factory.mutationTestReportSchemaFileResult({92 mutants: [93 factory.mutationTestReportSchemaMutantResult({94 id: 'mut-1',95 coveredBy: isStatic ? undefined : [this.oldSpecId],96 killedBy: [this.oldSpecId],97 replacement: '-',98 mutatorName: 'min-replacement',99 statusReason: 'Killed by first test',100 testsCompleted: 1,101 status: mutantStatus,102 location: loc(1, 11, 1, 12),103 }),104 ],105 source: srcAddContent,106 });107 this.incrementalTestFiles[testAdd] = factory.mutationTestReportSchemaTestFile({108 tests: [{ id: this.oldSpecId, name: 'add(2, 0) = 2' }],109 });110 this.currentFiles.set(srcAdd, srcAddContent);111 this.testCoverage.addTest(factory.testResult({ id: this.newTestId, fileName: testAdd, name: 'add(2, 0) = 2' }));112 if (isStatic) {113 this.testCoverage.hasCoverage = true;114 this.testCoverage.staticCoverage[this.mutantId] = true;115 } else {116 this.testCoverage.addCoverage(this.mutantId, [this.newTestId]);117 }118 return this;119 }120 public withoutTestCoverage(): this {121 Object.keys(this.incrementalTestFiles).forEach((testFile) => delete this.incrementalTestFiles[testFile]);122 this.testCoverage.clear();123 this.testCoverage.hasCoverage = false;124 return this;125 }126 public withTestFile(): this {127 this.currentFiles.set(testAdd, testAddContent);128 this.incrementalTestFiles[testAdd].source = testAddContent;129 return this;130 }131 public withLocatedTest({ includeEnd = false } = {}): this {132 this.incrementalTestFiles[testAdd].tests[0].location = loc(4, 2);133 if (includeEnd) {134 this.incrementalTestFiles[testAdd].tests[0].location.end = pos(6, 5);135 }136 [...this.testCoverage.forMutant(this.mutantId)!][0].startPosition = pos(4, 2);137 return this;138 }139 public withAddedLinesAboveTest(...lines: string[]): this {140 this.currentFiles.set(testAdd, `${lines.join('\n')}\n${testAddContent}`);141 for (const test of this.testCoverage.forMutant(this.mutantId)!) {142 if (test.startPosition) {143 test.startPosition = pos(4 + lines.length, 2);144 }145 }146 return this;147 }148 public withAddedLinesAboveMutant(...lines: string[]): this {149 this.currentFiles.set(srcAdd, `${lines.join('\n')}\n${srcAddContent}`);150 this.mutants[0].location = loc(1 + lines.length, 11, 1 + lines.length, 12);151 return this;152 }153 public withCrlfLineEndingsInIncrementalReport(): this {154 Object.values(this.incrementalFiles).forEach((file) => {155 file.source = file.source.replace(/\n/g, '\r\n');156 });157 Object.values(this.incrementalTestFiles).forEach((file) => {158 file.source = file.source?.replace(/\n/g, '\r\n');159 });160 return this;161 }162 public withRemovedLinesAboveMutant(...lines: string[]): this {163 this.incrementalFiles[srcAdd].source = `${lines.join('\n')}\n${srcAddContent}`;164 this.incrementalFiles[srcAdd].mutants[0].location = loc(1 + lines.length, 11, 1 + lines.length, 12);165 return this;166 }167 public withAddedTextBeforeMutant(text: string): this {168 this.currentFiles.set(169 srcAdd,170 srcAddContent171 .split('\n')172 .map((line, nr) => (nr === 1 ? `${text}${line}` : line))173 .join('\n')174 );175 this.mutants[0].location = loc(1, 11 + text.length, 1, 12 + text.length);176 return this;177 }178 public withAddedTextBeforeTest(text: string): this {179 this.currentFiles.set(180 testAdd,181 testAddContent182 .split('\n')183 .map((line, nr) => (nr === 4 ? `${text}${line}` : line))184 .join('\n')185 );186 for (const test of this.testCoverage.forMutant(this.mutantId)!) {187 if (test.startPosition) {188 test.startPosition = pos(4, 2 + text.length);189 }190 }191 return this;192 }193 public withAddedCodeInsideTheTest(code: string): this {194 this.currentFiles.set(195 testAdd,196 testAddContent197 .split('\n')198 .map((line, nr) => (nr === 5 ? ` ${code}\n${line}` : line))199 .join('\n')200 );201 for (const test of this.testCoverage.forMutant(this.mutantId)!) {202 if (test.startPosition) {203 test.startPosition = pos(4, 2);204 }205 }206 return this;207 }208 public withSecondTest({ located }: { located: boolean }): this {209 this.currentFiles.set(testAdd, testAddContentTwoTests);210 const secondTest = factory.testResult({ id: 'spec2', fileName: testAdd, name: 'add(45, -3) = 42' });211 if (located) {212 secondTest.startPosition = pos(7, 2);213 }214 this.testCoverage.addTest(secondTest);215 this.testCoverage.addCoverage(this.mutantId, [secondTest.id]);216 return this;217 }218 public withSecondTestInIncrementalReport({ isKillingTest = false } = {}): this {219 this.incrementalTestFiles[testAdd].tests.unshift(220 factory.mutationTestReportSchemaTestDefinition({ id: 'spec2', name: 'add(45, -3) = 42', location: loc(7, 0) })221 );222 if (isKillingTest) {223 this.incrementalFiles[srcAdd].mutants[0].killedBy = ['spec2'];224 }225 if (this.incrementalTestFiles[testAdd].source) {226 this.incrementalTestFiles[testAdd].source = testAddContentTwoTests;227 }228 return this;229 }230 public withUpdatedTestGeneration(): this {231 this.currentFiles.set(testAdd, testAddContentWithTestGenerationUpdated);232 const createAddWithTestGenerationTestResult = (a: number, b: number, answer: number) =>233 factory.testResult({ id: `spec${a}`, fileName: testAdd, name: `should result in ${answer} for ${a} and ${b}`, startPosition: pos(5, 4) });234 this.testCoverage.clear();235 this.testCoverage.addTest(factory.testResult({ id: 'new-spec-2', fileName: testAdd, name: 'should have name "add"', startPosition: pos(9, 2) }));236 const gen1 = createAddWithTestGenerationTestResult(40, 2, 42);237 const gen2 = createAddWithTestGenerationTestResult(45, -3, 42);238 this.testCoverage.addTest(gen1, gen2);239 this.testCoverage.addCoverage(this.mutantId, ['new-spec-2', gen1.id, gen2.id]);240 return this;241 }242 public withTestGenerationIncrementalReport(): this {243 this.incrementalTestFiles[testAdd].source = testAddContentWithTestGeneration;244 const createAddWithTestGenerationTestDefinition = (id: string, a: number, b: number, answer: number) =>245 factory.mutationTestReportSchemaTestDefinition({246 id,247 name: `should result in ${answer} for ${a} and ${b}`,248 location: loc(5, 4),249 });250 while (this.incrementalTestFiles[testAdd].tests.shift()) {}251 this.incrementalTestFiles[testAdd].tests.push(252 factory.mutationTestReportSchemaTestDefinition({ id: 'spec3', name: 'should have name "add"', location: loc(9, 2) }),253 createAddWithTestGenerationTestDefinition('spec4', 40, 2, 42),254 createAddWithTestGenerationTestDefinition('spec5', 45, -3, 42)255 );256 this.incrementalFiles[srcAdd].mutants[0].coveredBy = ['spec4', 'spec5'];257 this.incrementalFiles[srcAdd].mutants[0].killedBy = ['spec4'];258 return this;259 }260 public withRemovedTextBeforeMutant(text: string): this {261 this.incrementalFiles[srcAdd].source = srcAddContent262 .split('\n')263 .map((line, nr) => (nr === 1 ? `${text}${line}` : line))264 .join('\n');265 this.incrementalFiles[srcAdd].mutants[0].location = loc(1, 11 + text.length, 1, 12 + text.length);266 return this;267 }268 public withAddedTextAfterTest(text: string): this {269 const cnt = testAddContent270 .split('\n')271 .map((line, nr) => `${line}${nr === 6 ? text : ''}`)272 .join('\n');273 this.currentFiles.set(testAdd, cnt);274 return this;275 }276 public withChangedMutantText(replacement: string): this {277 this.currentFiles.set(srcAdd, srcAddContent.replace('+', replacement));278 return this;279 }280 public withDifferentMutator(mutatorName: string): this {281 this.mutants[0].mutatorName = mutatorName;282 return this;283 }284 public withDifferentReplacement(replacement: string): this {285 this.mutants[0].replacement = replacement;286 return this;287 }288 public withDifferentMutantLocation(): this {289 this.incrementalFiles[srcAdd].mutants[0].location = loc(2, 11, 2, 12);290 return this;291 }292 public withDifferentFileName(fileName: string): this {293 this.incrementalFiles[fileName] = this.incrementalFiles[srcAdd];294 delete this.incrementalFiles[srcAdd];295 return this;296 }297 public withSecondSourceAndTestFileInIncrementalReport(): this {298 this.incrementalTestFiles[testMultiply] = factory.mutationTestReportSchemaTestFile({299 source: testMultiplyContent,300 tests: [301 factory.mutationTestReportSchemaTestDefinition({ id: 'spec-3', location: loc(4, 2), name: 'multiply should result in 42 for 2 and 21' }),302 ],303 });304 this.incrementalFiles[srcMultiply] = factory.mutationTestReportSchemaFileResult({305 mutants: [306 factory.mutationTestReportSchemaMutantResult({307 id: 'mut-3',308 coveredBy: ['spec-3'],309 killedBy: ['spec-3'],310 replacement: '/',311 testsCompleted: 1,312 status: MutantStatus.Killed,313 location: loc(1, 11, 1, 12),314 }),315 ],316 source: srcMultiplyContent,317 });318 return this;319 }320 public withSecondSourceFile(): this {321 this.currentFiles.set(srcMultiply, srcMultiplyContent);322 return this;323 }324 public withSecondTestFile(): this {325 this.currentFiles.set(testMultiply, testMultiplyContent);326 return this;327 }328 public act() {329 this.sut = testInjector.injector.injectClass(IncrementalDiffer);330 deepFreeze(this.mutants); // make sure mutants aren't changed at all331 return this.sut.diff(332 this.mutants,333 this.testCoverage,334 factory.mutationTestReportSchemaMutationTestResult({335 files: this.incrementalFiles,336 testFiles: this.incrementalTestFiles,337 }),338 this.currentFiles339 );340 }341}342describe(IncrementalDiffer.name, () => {343 describe('mutant changes', () => {344 it('should copy status, statusReason, testsCompleted if nothing changed', () => {345 // Arrange346 const actualDiff = new ScenarioBuilder().withMathProjectExample().act();347 // Assert348 const actualMutant = actualDiff[0];349 const expected: Partial<Mutant> = {350 id: '2',351 fileName: srcAdd,352 replacement: '-',353 mutatorName: 'min-replacement',354 location: loc(1, 11, 1, 12),355 status: MutantStatus.Killed,356 statusReason: 'Killed by first test',357 testsCompleted: 1,358 };359 expect(actualMutant).deep.contains(expected);360 });361 it('should not reuse the result when --force is active', () => {362 // Arrange363 testInjector.options.force = true;364 const actualDiff = new ScenarioBuilder().withMathProjectExample().act();365 // Assert366 const actualMutant = actualDiff[0];367 expect(actualMutant.status).undefined;368 });369 it('should not reuse when the mutant was ignored', () => {370 // Arrange371 const actualDiff = new ScenarioBuilder().withMathProjectExample({ mutantState: MutantStatus.Ignored }).act();372 // Assert373 const actualMutant = actualDiff[0];374 expect(actualMutant.status).undefined;375 });376 it('should normalize line endings when comparing diffs', () => {377 const actualDiff = new ScenarioBuilder()378 .withMathProjectExample()379 .withTestFile()380 .withLocatedTest()381 .withCrlfLineEndingsInIncrementalReport()382 .act();383 const actualMutant = actualDiff[0];384 expect(actualMutant.status).eq(MutantStatus.Killed);385 });386 it('should map killedBy and coveredBy to the new test ids if a mutant result is reused', () => {387 const scenario = new ScenarioBuilder().withMathProjectExample();388 const actualDiff = scenario.act();389 const actualMutant = actualDiff[0];390 const expectedTestIds = [scenario.newTestId];391 const expected: Partial<Mutant> = {392 coveredBy: expectedTestIds,393 killedBy: expectedTestIds,394 };395 expect(actualMutant).deep.contains(expected);396 });397 it("should identify that a mutant hasn't changed if lines got added above", () => {398 const actualDiff = new ScenarioBuilder().withMathProjectExample().withAddedLinesAboveMutant("import path from 'path';", '', '').act();399 expect(actualDiff[0].status).eq(MutantStatus.Killed);400 });401 it("should identify that a mutant hasn't changed if characters got added before", () => {402 const actualDiff = new ScenarioBuilder().withMathProjectExample().withAddedTextBeforeMutant("/* text added this shouldn't matter */").act();403 expect(actualDiff[0].status).eq(MutantStatus.Killed);404 });405 it("should identify that a mutant hasn't changed if lines got removed above", () => {406 const actualDiff = new ScenarioBuilder().withMathProjectExample().withRemovedLinesAboveMutant('import path from "path";', '').act();407 expect(actualDiff[0].status).eq(MutantStatus.Killed);408 });409 it("should identify that a mutant hasn't changed if characters got removed before", () => {410 const actualDiff = new ScenarioBuilder().withMathProjectExample().withRemovedTextBeforeMutant("/* text removed, this shouldn't matter*/").act();411 expect(actualDiff[0].status).eq(MutantStatus.Killed);412 });413 it('should not reuse the status of a mutant in changed text', () => {414 const actualDiff = new ScenarioBuilder().withMathProjectExample().withChangedMutantText('*').act();415 expect(actualDiff[0].status).undefined;416 });417 it('should reuse the status when there is no test coverage', () => {418 const actualDiff = new ScenarioBuilder().withMathProjectExample().withoutTestCoverage().act();419 expect(actualDiff[0].status).eq(MutantStatus.Killed);420 });421 it('should not copy the status if the mutant came from a different mutator', () => {422 const scenario = new ScenarioBuilder().withMathProjectExample().withDifferentMutator('max-replacement');423 const actualDiff = scenario.act();424 expect(actualDiff[0]).deep.eq(scenario.mutants[0]);425 });426 it('should not copy the status if the mutant has a different replacement', () => {427 const scenario = new ScenarioBuilder().withMathProjectExample().withDifferentReplacement('other replacement');428 const actualDiff = scenario.act();429 expect(actualDiff[0]).deep.eq(scenario.mutants[0]);430 });431 it('should not copy the status if the mutant has a different location', () => {432 const scenario = new ScenarioBuilder().withMathProjectExample().withDifferentMutantLocation();433 const actualDiff = scenario.act();434 expect(actualDiff[0]).deep.eq(scenario.mutants[0]);435 });436 it('should not copy the status if the mutant has a different file name', () => {437 const scenario = new ScenarioBuilder().withMathProjectExample().withDifferentFileName('src/some-other-file.js');438 const actualDiff = scenario.act();439 expect(actualDiff).deep.eq(scenario.mutants);440 });441 it('should collect 1 added mutant and 1 removed mutant if the mutant changed', () => {442 const scenario = new ScenarioBuilder().withMathProjectExample().withChangedMutantText('*');443 scenario.act();444 expect(scenario.sut!.mutantStatisticsCollector!.changesByFile).lengthOf(1);445 const changes = scenario.sut!.mutantStatisticsCollector!.changesByFile.get(srcAdd)!;446 expect(changes).property('added', 1);447 expect(changes).property('removed', 1);448 });449 it('should collect the removed mutants if the file got removed', () => {450 const scenario = new ScenarioBuilder().withMathProjectExample().withDifferentFileName('src/some-other-file.js');451 scenario.act();452 expect(scenario.sut!.mutantStatisticsCollector!.changesByFile).lengthOf(2);453 const changesOldFile = scenario.sut!.mutantStatisticsCollector!.changesByFile.get('src/some-other-file.js')!;454 const changesNewFile = scenario.sut!.mutantStatisticsCollector!.changesByFile.get(srcAdd)!;455 expect(changesNewFile).property('added', 1);456 expect(changesNewFile).property('removed', 0);457 expect(changesOldFile).property('added', 0);458 expect(changesOldFile).property('removed', 1);459 });460 it('should collect 1 added mutant and 1 removed mutant if a mutant changed', () => {461 const scenario = new ScenarioBuilder().withMathProjectExample().withChangedMutantText('*');462 scenario.act();463 expect(scenario.sut!.mutantStatisticsCollector!.changesByFile).lengthOf(1);464 const changes = scenario.sut!.mutantStatisticsCollector!.changesByFile.get(srcAdd)!;465 expect(changes).property('added', 1);466 expect(changes).property('removed', 1);467 });468 it('should log an incremental report', () => {469 const scenario = new ScenarioBuilder().withMathProjectExample().withChangedMutantText('*');470 testInjector.logger.isInfoEnabled.returns(true);471 scenario.act();472 const { mutantStatisticsCollector, testStatisticsCollector } = scenario.sut!;473 sinon.assert.calledWithExactly(474 testInjector.logger.info,475 `Incremental report:\n\tMutants:\t${mutantStatisticsCollector!.createTotalsReport()}` +476 `\n\tTests:\t\t${testStatisticsCollector!.createTotalsReport()}` +477 `\n\tResult:\t\t${chalk.yellowBright(0)} of 1 mutant result(s) are reused.`478 );479 });480 it('should not log test diff when there is no test coverage', () => {481 const scenario = new ScenarioBuilder().withMathProjectExample().withoutTestCoverage();482 testInjector.logger.isInfoEnabled.returns(true);483 scenario.act();484 const { mutantStatisticsCollector } = scenario.sut!;485 sinon.assert.calledWithExactly(486 testInjector.logger.info,487 `Incremental report:\n\tMutants:\t${mutantStatisticsCollector!.createTotalsReport()}` +488 `\n\tResult:\t\t${chalk.yellowBright(1)} of 1 mutant result(s) are reused.`489 );490 });491 it('should log a detailed incremental report', () => {492 const scenario = new ScenarioBuilder().withMathProjectExample().withChangedMutantText('*');493 testInjector.logger.isDebugEnabled.returns(true);494 scenario.act();495 const { mutantStatisticsCollector } = scenario.sut!;496 const lineSeparator = '\n\t\t';497 const detailedMutantSummary = `${lineSeparator}${mutantStatisticsCollector!.createDetailedReport().join(lineSeparator)}`;498 sinon.assert.calledWithExactly(499 testInjector.logger.debug,500 `Detailed incremental report:\n\tMutants: ${detailedMutantSummary}\n\tTests: ${lineSeparator}No changes`501 );502 });503 it('should not log if logLevel "info" or "debug" aren\'t enabled', () => {504 const scenario = new ScenarioBuilder().withMathProjectExample().withChangedMutantText('*');505 testInjector.logger.isInfoEnabled.returns(false);506 testInjector.logger.isDebugEnabled.returns(false);507 scenario.act();508 sinon.assert.notCalled(testInjector.logger.debug);509 sinon.assert.notCalled(testInjector.logger.info);510 });511 });512 describe('test changes', () => {513 it('should identify that a mutant state can be reused when no tests changed', () => {514 const actualDiff = new ScenarioBuilder().withMathProjectExample().withTestFile().act();515 expect(actualDiff[0].status).eq(MutantStatus.Killed);516 });517 it('should identify that mutant state can be reused with changes above', () => {518 const actualDiff = new ScenarioBuilder()519 .withMathProjectExample()520 .withTestFile()521 .withLocatedTest()522 .withAddedLinesAboveTest("import foo from 'bar'", '')523 .act();524 // Assert525 expect(actualDiff[0].status).eq(MutantStatus.Killed);526 });527 it('should identify that mutant state can be reused with changes before', () => {528 const actualDiff = new ScenarioBuilder()529 .withMathProjectExample()530 .withTestFile()531 .withLocatedTest()532 .withAddedTextBeforeTest('/*text-added*/')533 .act();534 expect(actualDiff[0].status).eq(MutantStatus.Killed);535 });536 it('should identify that mutant state can be reused with changes below', () => {537 const actualDiff = new ScenarioBuilder()538 .withMathProjectExample()539 .withTestFile()540 .withLocatedTest({ includeEnd: true })541 .withSecondTest({ located: true })542 .act();543 expect(actualDiff[0].status).eq(MutantStatus.Killed);544 });545 it('should identify that mutant state can be reused with changes behind', () => {546 const actualDiff = new ScenarioBuilder()547 .withMathProjectExample()548 .withTestFile()549 .withLocatedTest({ includeEnd: true })550 .withAddedTextAfterTest('/*text-added*/')551 .act();552 expect(actualDiff[0].status).eq(MutantStatus.Killed);553 });554 it('should not reuse a mutant state when a covering test gets code added', () => {555 const actualDiff = new ScenarioBuilder()556 .withMathProjectExample()557 .withTestFile()558 .withLocatedTest({ includeEnd: true })559 .withAddedCodeInsideTheTest('addedText();')560 .act();561 expect(actualDiff[0].status).undefined;562 });563 it('should close locations of tests in the incremental report', () => {564 // All test runners currently only report the start positions of tests.565 // Add a workaround for 'inventing' the end position based on the next test's start position.566 const actualDiff = new ScenarioBuilder()567 .withMathProjectExample()568 .withTestFile()569 .withLocatedTest({ includeEnd: true })570 .withSecondTest({ located: true })571 .withSecondTestInIncrementalReport()572 .act();573 expect(actualDiff[0].status).eq(MutantStatus.Killed);574 });575 it('should close locations for tests on the same location in the incremental report', () => {576 // Test cases can generate tests, make sure the correct end position is chosen in those cases577 const actualDiff = new ScenarioBuilder().withMathProjectExample().withUpdatedTestGeneration().withTestGenerationIncrementalReport().act();578 expect(actualDiff[0].status).eq(MutantStatus.Killed);579 });580 it('should identify that a non-"Killed" state can be reused when a test is removed', () => {581 const actualDiff = new ScenarioBuilder()582 .withMathProjectExample({ mutantState: MutantStatus.Survived })583 .withSecondTestInIncrementalReport()584 .act();585 expect(actualDiff[0].status).eq(MutantStatus.Survived);586 });587 it('should identify that a non-"Killed" state cannot be reused when a test is added', () => {588 const actualDiff = new ScenarioBuilder()589 .withMathProjectExample({ mutantState: MutantStatus.Survived })590 .withSecondTest({ located: false })591 .act();592 expect(actualDiff[0].status).undefined;593 });594 it('should identify that a "Killed" state can be reused when the killing test didn\'t change', () => {595 const actualDiff = new ScenarioBuilder()596 .withMathProjectExample({ mutantState: MutantStatus.Killed })597 .withTestFile()598 .withLocatedTest()599 .withSecondTestInIncrementalReport()600 .act();601 expect(actualDiff[0].status).eq(MutantStatus.Killed);602 });603 it('should identify that a "Killed" state cannot be reused when the killing test was removed', () => {604 const actualDiff = new ScenarioBuilder()605 .withMathProjectExample({ mutantState: MutantStatus.Killed })606 .withTestFile()607 .withSecondTestInIncrementalReport({ isKillingTest: true })608 .act();609 expect(actualDiff[0].status).undefined;610 });611 it('should identify that a "Killed" state for a static mutant (no covering tests) can be reused when the killing test didn\'t change', () => {612 const actualDiff = new ScenarioBuilder().withMathProjectExample({ mutantState: MutantStatus.Killed, isStatic: true }).act();613 expect(actualDiff[0].status).eq(MutantStatus.Killed);614 });615 it('should collect an added test', () => {616 const scenario = new ScenarioBuilder()617 .withMathProjectExample()618 .withTestFile()619 .withLocatedTest({ includeEnd: true })620 .withSecondTest({ located: true });621 scenario.act();622 const actualCollector = scenario.sut!.testStatisticsCollector!;623 expect(actualCollector.changesByFile).lengthOf(1);624 const changes = actualCollector.changesByFile.get(testAdd)!;625 expect(changes).property('added', 1);626 expect(changes).property('removed', 0);627 });628 it('should collect an added and removed test when a test changes', () => {629 const scenario = new ScenarioBuilder()630 .withMathProjectExample()631 .withTestFile()632 .withLocatedTest()633 .withAddedCodeInsideTheTest('arrangeSomething()');634 scenario.act();635 const actualCollector = scenario.sut!.testStatisticsCollector!;636 expect(actualCollector.changesByFile).lengthOf(1);637 const changes = actualCollector.changesByFile.get(testAdd)!;638 expect(changes).property('added', 1);639 expect(changes).property('removed', 1);640 });641 });642 describe('with history', () => {643 it('should keep historic mutants in other files', () => {644 const scenario = new ScenarioBuilder().withMathProjectExample().withSecondSourceAndTestFileInIncrementalReport().withSecondSourceFile();645 const mutants = scenario.act();646 expect(mutants).lengthOf(2);647 const actualMutant = mutants[1];648 expect(actualMutant.id).includes('src/multiply.js@1:11-1:12');649 expect(actualMutant.status).eq(MutantStatus.Killed);650 expect(actualMutant.fileName).eq(path.resolve(srcMultiply));651 });652 it("should keep historic tests that didn't run this time around", () => {653 const scenario = new ScenarioBuilder()654 .withMathProjectExample()655 .withSecondSourceAndTestFileInIncrementalReport()656 .withSecondSourceFile()657 .withSecondTestFile();658 const mutants = scenario.act();659 const actualTest = scenario.testCoverage.testsById.get(`${testMultiply}@4:2\nmultiply should result in 42 for 2 and 21`)!;660 expect(actualTest).ok;661 expect(actualTest.fileName).eq(path.resolve(testMultiply));662 expect(actualTest.name).eq('multiply should result in 42 for 2 and 21');663 expect(actualTest.startPosition).deep.eq(pos(4, 2));664 expect(scenario.testCoverage.forMutant(mutants[1].id)).deep.eq(new Set([actualTest]));665 });666 it('should not keep historic mutants when they are inside of a mutated file', () => {667 testInjector.fileDescriptions[path.resolve(srcMultiply)] = { mutate: true };668 const scenario = new ScenarioBuilder().withMathProjectExample().withSecondSourceAndTestFileInIncrementalReport().withSecondSourceFile();669 const mutants = scenario.act();670 expect(mutants).lengthOf(1);671 });672 it('should not keep historic mutants when they are inside of a mutated scope of a file', () => {673 testInjector.fileDescriptions[path.resolve(srcMultiply)] = { mutate: [loc(1, 11, 1, 12), loc(2, 2, 2, 3)] };674 const scenario = new ScenarioBuilder().withMathProjectExample().withSecondSourceAndTestFileInIncrementalReport().withSecondSourceFile();675 const mutants = scenario.act();676 expect(mutants).lengthOf(1);677 });678 it('should keep historic mutants when they are outside of a mutated scope of a file', () => {679 testInjector.fileDescriptions[path.resolve(srcMultiply)] = { mutate: [loc(1, 9, 1, 10), loc(2, 11, 2, 12)] };680 const scenario = new ScenarioBuilder().withMathProjectExample().withSecondSourceAndTestFileInIncrementalReport().withSecondSourceFile();681 const mutants = scenario.act();682 expect(mutants).lengthOf(2);683 });684 });...
Using AI Code Generation
1var changesOldFile = require('stryker-parent').changesOldFile;2var changesNewFile = require('stryker-parent').changesNewFile;3var changesOldFile = require('stryker-child').changesOldFile;4var changesNewFile = require('stryker-child').changesNewFile;5var changesOldFile = require('stryker-child1').changesOldFile;6var changesNewFile = require('stryker-child1').changesNewFile;7var changesOldFile = require('stryker-child2').changesOldFile;8var changesNewFile = require('stryker-child2').changesNewFile;9var changesOldFile = require('stryker-child3').changesOldFile;10var changesNewFile = require('stryker-child3').changesNewFile;11var changesOldFile = require('stryker-child4').changesOldFile;12var changesNewFile = require('stryker-child4').changesNewFile;13var changesOldFile = require('stryker-child5').changesOldFile;14var changesNewFile = require('stryker-child5').changesNewFile;15var changesOldFile = require('stryker-child6').changesOldFile;16var changesNewFile = require('stryker-child6').changesNewFile;17var changesOldFile = require('stryker-child
Using AI Code Generation
1changesOldFile('test.js');2changesNewFile('test.js');3changesOldFile('test.js');4changesNewFile('test.js');5changesOldFile('test.js');6changesNewFile('test.js');7changesOldFile('test.js');8changesNewFile('test.js');9changesOldFile('test.js');10changesNewFile('test.js');11changesOldFile('test.js');12changesNewFile('test.js');13changesOldFile('test.js');14changesNewFile('test.js');15changesOldFile('test.js');16changesNewFile('test.js');17changesOldFile('test.js');18changesNewFile('test.js');19changesOldFile('test.js');20changesNewFile('test.js');21changesOldFile('test.js');22changesNewFile('test.js');23changesOldFile('test.js');24changesNewFile('test.js');
Using AI Code Generation
1const { changesOldFile } = require('stryker-parent');2const { changesOldFile } = require('stryker-parent');3const { changesOldFile } = require('stryker-parent');4const { changesOldFile } = require('stryker-parent');5const { changesOldFile } = require('stryker-parent');6const { changesOldFile } = require('stryker-parent');7const { changesOldFile } = require('stryker-parent');8const { changesOldFile } = require('stryker-parent');9const { changesOldFile } = require('stryker-parent');10const { changesOldFile } = require('stryker-parent');11const { changesOldFile } = require('stryker-parent');12const { changesOldFile } = require('stryker-parent');13const { changesOldFile } = require('stryker-parent');14const { changesOldFile } = require('stryker-parent');15const { changesOldFile } = require('stryker-parent');16const { changesOldFile } = require('stryker-parent');17const { changesOldFile } = require('stryker-parent');18const { changesOldFile } = require('stryker-parent');19const { changesOldFile } = require('stryker-parent');
Using AI Code Generation
1var changesOldFile = require('stryker-parent').changesOldFile;2var changesOldFile = require('stryker-parent').changesOldFile;3var changesOldFile = require('stryker-parent').changesOldFile;4var changesOldFile = require('stryker-parent').changesOldFile;5var changesOldFile = require('stryker-parent').changesOldFile;6var changesOldFile = require('stryker-parent').changesOldFile;7var changesOldFile = require('stryker-parent').changesOldFile;8var changesOldFile = require('stryker-parent').changesOldFile;9var changesOldFile = require('stryker-parent').changesOldFile;10var changesOldFile = require('stryker-parent').changesOldFile;11var changesOldFile = require('stryker-parent').changesOldFile;12var changesOldFile = require('stryker-parent').changesOldFile;13var changesOldFile = require('stryker-parent').changesOldFile;14var changesOldFile = require('stryker-parent').changesOldFile;15var changesOldFile = require('stryker-parent').changesOldFile;16var changesOldFile = require('stryker-parent').changesOldFile;17var changesOldFile = require('stryker-parent').changesOldFile;18var changesOldFile = require('stryker-parent').changesOldFile;19var changesOldFile = require('stryker-parent').changesOldFile;20var changesOldFile = require('stryker-parent').changesOldFile;21var changesOldFile = require('stryker-parent').changesOldFile;22var changesOldFile = require('stryker-parent').changesOldFile;23var changesOldFile = require('stryker-parent').changesOldFile;
Using AI Code Generation
1var changesOldFile = require('stryker-parent').changesOldFile;2var changesOldFile = require('stryker-parent').changesOldFile;3var changesOldFile = require('stryker-parent').changesOldFile;4var changesOldFile = require('stryker-parent').changesOldFile;5var changesOldFile = require('stryker-parent').changesOldFile;6var changesOldFile = require('stryker-parent').changesOldFile;7var changesOldFile = require('stryker-parent').changesOldFile;8var changesOldFile = require('stryker-parent').changesOldFile;9var changesOldFile = require('stryker-parent').changesOldFile;10var changesOldFile = require('stryker-parent').changesOldFile;11var changesOldFile = require('stryker-parent').changesOldFile;12var changesOldFile = require('stryker-parent').changesOldFile;13var changesOldFile = require('stryker-parent').changesOldFile;14var changesOldFile = require('stryker-parent').changesOldFile;15var changesOldFile = require('stryker-parent').changesOldFile;16var changesOldFile = require('stryker-parent').changesOldFile;17var changesOldFile = require('stryker-parent').changesOldFile;18var changesOldFile = require('stryker-parent').changesOldFile;19var changesOldFile = require('stryker-parent').changesOldFile;20var changesOldFile = require('stryker-parent').changesOldFile;
Using AI Code Generation
1var file = require('stryker-parent/changesOldFile');2file.changesOldFile();3var newFile = require('stryker-parent/changesNewFile');4newFile.changesNewFile();5module.exports.changesOldFile = require('./changesOldFile');6module.exports.changesNewFile = require('./changesNewFile');7module.exports.changesOldFile = function() {8 console.log("changesOldFile");9}10module.exports.changesNewFile = function() {11 console.log("changesNewFile");12}13module.exports = function(config) {14 config.set({15 });16};
Using AI Code Generation
1const changesOldFile = require('stryker-parent').changesOldFile;2const oldFile = 'oldFile.js';3const newFile = 'newFile.js';4const changes = changesOldFile(oldFile, newFile);5console.log(changes);6const changesOldFile = require('stryker-parent').changesOldFile;7const oldFile = 'oldFile.js';8const newFile = 'newFile.js';9const changes = changesOldFile(oldFile, newFile);10console.log(changes);11const changesOldFile = require('stryker-parent').changesOldFile;12const oldFile = 'oldFile.js';13const newFile = 'newFile.js';14const changes = changesOldFile(oldFile, newFile);15console.log(changes);16module.exports = function(config) {17 config.set({18 });19};20module.exports = {21 changesOldFile: function(oldFile, newFile) {22 return 'oldFile: ' + oldFile + ' newFile: ' + newFile;23 }24};25{26 "dependencies": {27 },28 "devDependencies": {29 },30 "scripts": {
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!