diff --git a/packages/core/src/input/InputFileResolver.ts b/packages/core/src/input/InputFileResolver.ts index 340e616afc..17c7b74a43 100644 --- a/packages/core/src/input/InputFileResolver.ts +++ b/packages/core/src/input/InputFileResolver.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import fs = require('fs'); import { from } from 'rxjs'; -import { filter, mergeMap, toArray } from 'rxjs/operators'; +import { filter, map, mergeMap, toArray } from 'rxjs/operators'; import { File, StrykerOptions } from '@stryker-mutator/api/core'; import { Logger } from '@stryker-mutator/api/logging'; import { commonTokens, tokens } from '@stryker-mutator/api/plugin'; @@ -163,7 +163,9 @@ export default class InputFileResolver { .pipe( mergeMap((fileName) => this.readFile(fileName), MAX_CONCURRENT_FILE_IO), filter(notEmpty), - toArray() + toArray(), + // Filter the files here, so we force a deterministic instrumentation process + map((files) => files.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))) ) .toPromise(); return files; diff --git a/packages/core/test/integration/input/InputFileResolver.it.spec.ts b/packages/core/test/integration/input/InputFileResolver.it.spec.ts index c4a8d36d39..0f464608c7 100644 --- a/packages/core/test/integration/input/InputFileResolver.it.spec.ts +++ b/packages/core/test/integration/input/InputFileResolver.it.spec.ts @@ -32,8 +32,7 @@ describe(`${InputFileResolver.name} integration`, () => { it('should by default resolve reasonable project source files to be mutated', async () => { process.chdir(resolveTestResource()); const inputFiles = await sut.resolve(); - // eslint-disable-next-line @typescript-eslint/require-array-sort-compare - expect(inputFiles.filesToMutate.map((file) => file.name).sort()).deep.eq([ + expect(inputFiles.filesToMutate.map((file) => file.name)).deep.eq([ resolveTestResource('lib', 'string-utils.js'), resolveTestResource('src', 'app.ts'), resolveTestResource('src', 'components', 'calculator', 'calculator.component.tsx'), diff --git a/packages/core/test/unit/input/InputFileResolver.spec.ts b/packages/core/test/unit/input/InputFileResolver.spec.ts index d2a1ba193e..150ad62bad 100644 --- a/packages/core/test/unit/input/InputFileResolver.spec.ts +++ b/packages/core/test/unit/input/InputFileResolver.spec.ts @@ -147,9 +147,9 @@ describe(InputFileResolver.name, () => { }); const files = await sut.resolve(); assertions.expectTextFilesEqual(files.files, [ - new File(path.resolve('å.js'), ''), - new File(path.resolve('src/🐱‍👓ninja.cat.js'), ''), new File(path.resolve('a\\test\\file.js'), ''), + new File(path.resolve('src/🐱‍👓ninja.cat.js'), ''), + new File(path.resolve('å.js'), ''), ]); }); @@ -199,10 +199,10 @@ describe(InputFileResolver.name, () => { expect(result.filesToMutate.map((_) => _.name)).to.deep.equal([path.resolve('/mute1.js'), path.resolve('/mute2.js')]); expect(result.files.map((file) => file.name)).to.deep.equal([ path.resolve('/file1.js'), - path.resolve('/mute1.js'), path.resolve('/file2.js'), - path.resolve('/mute2.js'), path.resolve('/file3.js'), + path.resolve('/mute1.js'), + path.resolve('/mute2.js'), ]); }); @@ -221,10 +221,10 @@ describe(InputFileResolver.name, () => { await sut.resolve(); const expected: SourceFile[] = [ { path: path.resolve('/file1.js'), content: 'file 1 content' }, - { path: path.resolve('/mute1.js'), content: 'mutate 1 content' }, { path: path.resolve('/file2.js'), content: 'file 2 content' }, - { path: path.resolve('/mute2.js'), content: 'mutate 2 content' }, { path: path.resolve('/file3.js'), content: 'file 3 content' }, + { path: path.resolve('/mute1.js'), content: 'mutate 1 content' }, + { path: path.resolve('/mute2.js'), content: 'mutate 2 content' }, ]; expect(reporterMock.onAllSourceFilesRead).calledWith(expected); }); @@ -236,10 +236,10 @@ describe(InputFileResolver.name, () => { await sut.resolve(); const expected: SourceFile[] = [ { path: path.resolve('/file1.js'), content: 'file 1 content' }, - { path: path.resolve('/mute1.js'), content: 'mutate 1 content' }, { path: path.resolve('/file2.js'), content: 'file 2 content' }, - { path: path.resolve('/mute2.js'), content: 'mutate 2 content' }, { path: path.resolve('/file3.js'), content: 'file 3 content' }, + { path: path.resolve('/mute1.js'), content: 'mutate 1 content' }, + { path: path.resolve('/mute2.js'), content: 'mutate 2 content' }, ]; expected.forEach((sourceFile) => expect(reporterMock.onSourceFileRead).calledWith(sourceFile)); }); @@ -333,7 +333,7 @@ describe(InputFileResolver.name, () => { it('should order files by expression order', async () => { testInjector.options.files = ['file2', 'file*']; const result = await createSut().resolve(); - assertFilesEqual(result.files, files(['/file2.js', 'file 2 content'], ['/file1.js', 'file 1 content'], ['/file3.js', 'file 3 content'])); + assertFilesEqual(result.files, files(['/file1.js', 'file 1 content'], ['/file2.js', 'file 2 content'], ['/file3.js', 'file 3 content'])); }); });