diff --git a/packages/instrumenter/src/mutant-placers/expression-mutant-placer.ts b/packages/instrumenter/src/mutant-placers/expression-mutant-placer.ts index c740f4901d..c2b7c66ba3 100644 --- a/packages/instrumenter/src/mutant-placers/expression-mutant-placer.ts +++ b/packages/instrumenter/src/mutant-placers/expression-mutant-placer.ts @@ -102,12 +102,13 @@ function isValidExpression(path: NodePath) { * foo.bar(); * foo?.bar(); * baz[foo.bar()] + * bar?.baz[0] */ function isPartOfChain() { return ( isMemberOrCallOrNonNullExpression(path) && - ((isMemberExpression(parent) && !parent.node.computed) || - path.isTSNonNullExpression() || + ((isMemberExpression(parent) && !(parent.node.computed && parent.node.property === path.node)) || + parent.isTSNonNullExpression() || (isCallExpression(parent) && parent.node.callee === path.node)) ); } diff --git a/packages/instrumenter/test/unit/mutant-placers/expression-mutant-placer.spec.ts b/packages/instrumenter/test/unit/mutant-placers/expression-mutant-placer.spec.ts index 1fdcbf267e..18f4bbd7ab 100644 --- a/packages/instrumenter/test/unit/mutant-placers/expression-mutant-placer.spec.ts +++ b/packages/instrumenter/test/unit/mutant-placers/expression-mutant-placer.spec.ts @@ -81,10 +81,11 @@ describe('expressionMutantPlacer', () => { ['foo.bar?.baz', (p) => p.isMemberExpression() && types.isIdentifier(p.node.property, { name: 'bar' })], ['foo?.bar.baz', (p) => p.isOptionalMemberExpression() && types.isIdentifier(p.node.property, { name: 'bar' })], ['foo?.bar!.baz', (p) => p.isTSNonNullExpression()], + ['bar?.baz[0]', (p) => p.isOptionalMemberExpression() && types.isIdentifier(p.node.object, { name: 'bar' })], ]; - falsePointers.forEach(([js, query]) => { + falsePointers.forEach(([js, query, only]) => { const path = findNodePath(parseTS(js), query); - it(`should not allow placing in \`${path.toString()}\` of \`${js}\``, () => { + (only ? it.only : it)(`should not allow placing in \`${path.toString()}\` of \`${js}\``, () => { expect(expressionMutantPlacer.canPlace(path)).false; }); }); diff --git a/packages/instrumenter/testResources/instrumenter/optional-chains.ts b/packages/instrumenter/testResources/instrumenter/optional-chains.ts index f80905846a..dfa9325c0f 100644 --- a/packages/instrumenter/testResources/instrumenter/optional-chains.ts +++ b/packages/instrumenter/testResources/instrumenter/optional-chains.ts @@ -8,3 +8,5 @@ const directiveRanges = comments?.map(tryParseTSDirective) const qux = quux(corge?.cov()); input?.id!.toString(); + +bar?.baz[0] diff --git a/packages/instrumenter/testResources/instrumenter/optional-chains.ts.out.snap b/packages/instrumenter/testResources/instrumenter/optional-chains.ts.out.snap index b640352f97..d2285cbaf6 100644 --- a/packages/instrumenter/testResources/instrumenter/optional-chains.ts.out.snap +++ b/packages/instrumenter/testResources/instrumenter/optional-chains.ts.out.snap @@ -63,9 +63,10 @@ function stryMutAct_9fa48(id) { return isActive(id); } -const baz = stryMutAct_9fa48(\\"0\\") ? foo?.bar?.()?.[1] && 'qux' : (stryCov_9fa48(\\"0\\"), (stryMutAct_9fa48(\\"1\\") ? foo?.bar?.()[1] : (stryCov_9fa48(\\"1\\"), (stryMutAct_9fa48(\\"3\\") ? foo.bar?.() : stryMutAct_9fa48(\\"2\\") ? foo?.bar() : (stryCov_9fa48(\\"2\\", \\"3\\"), foo?.bar?.()))?.[1])) ?? (stryMutAct_9fa48(\\"4\\") ? \\"\\" : (stryCov_9fa48(\\"4\\"), 'qux'))); +const baz = stryMutAct_9fa48(\\"0\\") ? foo?.bar?.()?.[1] && 'qux' : (stryCov_9fa48(\\"0\\"), (stryMutAct_9fa48(\\"3\\") ? foo.bar?.()?.[1] : stryMutAct_9fa48(\\"2\\") ? foo?.bar()?.[1] : stryMutAct_9fa48(\\"1\\") ? foo?.bar?.()[1] : (stryCov_9fa48(\\"1\\", \\"2\\", \\"3\\"), foo?.bar?.()?.[1])) ?? (stryMutAct_9fa48(\\"4\\") ? \\"\\" : (stryCov_9fa48(\\"4\\"), 'qux'))); stryMutAct_9fa48(\\"5\\") ? qux().map() : (stryCov_9fa48(\\"5\\"), qux()?.map()); const directiveRanges = stryMutAct_9fa48(\\"6\\") ? comments.map(tryParseTSDirective) : (stryCov_9fa48(\\"6\\"), comments?.map(tryParseTSDirective)); const qux = quux(stryMutAct_9fa48(\\"7\\") ? corge.cov() : (stryCov_9fa48(\\"7\\"), corge?.cov())); -(stryMutAct_9fa48(\\"8\\") ? input.id : (stryCov_9fa48(\\"8\\"), input?.id))!.toString();" +stryMutAct_9fa48(\\"8\\") ? input.id!.toString() : (stryCov_9fa48(\\"8\\"), input?.id!.toString()); +stryMutAct_9fa48(\\"9\\") ? bar.baz[0] : (stryCov_9fa48(\\"9\\"), bar?.baz[0]);" `;