@@ -25,6 +25,7 @@ import {
2525 preferDirectTestFiles ,
2626 resolveVitestBinary ,
2727 packageForPath ,
28+ runManifest ,
2829 selectFromGit ,
2930 testsFromMutationReport ,
3031 validateDisableDirectives ,
@@ -40,11 +41,14 @@ describe("mutation testing workflow", () => {
4041 assert . ok ( ! workflow . includes ( "pull_request_target:" ) )
4142 assert . ok ( workflow . includes ( " contents: read" ) )
4243 assert . ok ( workflow . includes ( "- name: Checkout pull request merge result" ) )
43- assert . ok ( workflow . includes ( "ref: refs/pull/${{ github.event.pull_request.number }}/merge" ) )
44+ assert . ok ( workflow . includes ( "ref: ${{ github.sha }}" ) )
45+ assert . ok ( ! workflow . includes ( "ref: refs/pull/${{ github.event.pull_request.number }}/merge" ) )
4446 assert . ok ( workflow . includes ( "fetch-depth: 0" ) )
4547 assert . ok ( workflow . includes ( "persist-credentials: false" ) )
4648 assert . ok ( ! workflow . includes ( "repository: ${{ github.event.pull_request.head.repo.full_name }}" ) )
4749 assert . ok ( ! workflow . includes ( "ref: ${{ github.event.pull_request.head.sha }}" ) )
50+ assert . ok ( workflow . includes ( "HEAD_SHA: ${{ github.sha }}" ) )
51+ assert . ok ( ! workflow . includes ( "HEAD_SHA: ${{ github.event.pull_request.head.sha }}" ) )
4852 assert . ok ( workflow . includes ( "steps.mutation_report.outputs.artifact-url" ) )
4953 assert . ok ( workflow . includes ( "open the package's mutation.html file" ) )
5054 } )
@@ -291,6 +295,43 @@ describe("selectFromGit", () => {
291295 fs . rmSync ( repo , { recursive : true , force : true } )
292296 }
293297 } )
298+
299+ it ( "uses merge-result line coordinates when the base shifts a pull request edit" , ( ) => {
300+ const repo = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "stryker-merge-diff-" ) )
301+ const runGit = ( ...args ) => execFileSync ( "git" , args , { cwd : repo , encoding : "utf8" } ) . trim ( )
302+
303+ try {
304+ runGit ( "init" , "--initial-branch=main" )
305+ runGit ( "config" , "user.name" , "Mutation Test" )
306+ runGit ( "config" , "user.email" , "mutation@example.com" )
307+ fs . mkdirSync ( path . join ( repo , "packages/core/src" ) , { recursive : true } )
308+ fs . writeFileSync ( path . join ( repo , "packages/core/src/value.ts" ) , "const first = 1\nconst changed = true\n" )
309+ runGit ( "add" , "." )
310+ runGit ( "commit" , "-m" , "initial" )
311+
312+ runGit ( "checkout" , "-b" , "feature" )
313+ fs . writeFileSync ( path . join ( repo , "packages/core/src/value.ts" ) , "const first = 1\nconst changed = false\n" )
314+ runGit ( "commit" , "-am" , "change value" )
315+
316+ runGit ( "checkout" , "main" )
317+ fs . writeFileSync (
318+ path . join ( repo , "packages/core/src/value.ts" ) ,
319+ "const inserted = 0\nconst first = 1\nconst changed = true\n" ,
320+ )
321+ runGit ( "commit" , "-am" , "shift source lines" )
322+ const baseSha = runGit ( "rev-parse" , "HEAD" )
323+ runGit ( "merge" , "--no-ff" , "feature" , "-m" , "merge feature" )
324+ const mergeSha = runGit ( "rev-parse" , "HEAD" )
325+
326+ const manifest = selectFromGit ( repo , baseSha , mergeSha )
327+ assert . deepEqual (
328+ manifest . packages . map ( ( { id, selectors } ) => ( { id, selectors } ) ) ,
329+ [ { id : "core" , selectors : [ "src/value.ts:3-3" ] } ] ,
330+ )
331+ } finally {
332+ fs . rmSync ( repo , { recursive : true , force : true } )
333+ }
334+ } )
294335} )
295336
296337describe ( "mutation exclusions" , ( ) => {
@@ -446,6 +487,36 @@ describe("failure output", () => {
446487 )
447488 } )
448489
490+ it ( "reports a Stryker preflight launch error when the binary is missing" , ( ) => {
491+ const repo = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "stryker-launch-" ) )
492+ const reportRoot = path . join ( repo , "reports" )
493+
494+ try {
495+ fs . mkdirSync ( path . join ( repo , "packages/core" ) , { recursive : true } )
496+ assert . throws (
497+ ( ) =>
498+ runManifest (
499+ repo ,
500+ {
501+ packages : [
502+ {
503+ id : "core" ,
504+ root : "packages/core" ,
505+ vitestConfig : "vitest.unit.config.ts" ,
506+ selectors : [ "src/value.ts:1-1" ] ,
507+ changedExecutableLines : 1 ,
508+ } ,
509+ ] ,
510+ } ,
511+ reportRoot ,
512+ ) ,
513+ / c o r e S t r y k e r p r e f l i g h t c o u l d n o t s t a r t : .* E N O E N T / ,
514+ )
515+ } finally {
516+ fs . rmSync ( repo , { recursive : true , force : true } )
517+ }
518+ } )
519+
449520 it ( "uses the actual tests recorded by Stryker" , ( ) => {
450521 assert . deepEqual (
451522 testsFromMutationReport ( { testFiles : { "src/value.test.ts" : { } , "src/other.spec.ts" : { } } } , [
0 commit comments