Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions src/rules/no-identical-title.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
createRule,
getStringValue,
hasExpressions,
getAccessorValue,
isDescribe,
isStringNode,
isTemplateLiteral,
Expand Down Expand Up @@ -44,15 +43,15 @@ export default createRule({
if (isDescribe(node)) {
contexts.push(newDescribeContext());
}
const [firstArgument] = node.arguments;
const [argument] = node.arguments;
if (
!firstArgument ||
!isStringNode(firstArgument) ||
(isTemplateLiteral(firstArgument) && hasExpressions(firstArgument))
!argument ||
!isStringNode(argument) ||
(isTemplateLiteral(argument) && argument.expressions.length > 0)
) {
return;
}
const title = getStringValue(firstArgument);
const title = getAccessorValue(argument);
if (isTestCase(node)) {
if (currentLayer.testTitles.includes(title)) {
context.report({ messageId: 'multipleTestTitle', node });
Expand Down
28 changes: 16 additions & 12 deletions src/rules/tsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,22 @@ export const isStringNode = <V extends string>(
export const getStringValue = <S extends string>(node: StringNode<S>): S =>
isTemplateLiteral(node) ? node.quasis[0].value.raw : node.value;

/**
* Gets the value of the given `AccessorNode`,
* account for the different node types.
*
* @param {AccessorNode<S>} accessor
*
* @return {S}
*
* @template S
*/
export const getAccessorValue = <S extends string = string>(
accessor: AccessorNode<S>,
): S => getStringValue(accessor);

type AccessorNode<Specifics extends string = string> = StringNode<Specifics>;

interface JestExpectIdentifier extends TSESTree.Identifier {
name: 'expect';
}
Expand Down Expand Up @@ -138,13 +154,6 @@ interface JestExpectCallMemberExpression extends TSESTree.MemberExpression {
property: TSESTree.Identifier;
}

// represents expect usage like "expect.anything" & "expect.hasAssertions"
interface JestExpectNamespaceMemberExpression
extends TSESTree.MemberExpression {
object: JestExpectIdentifier;
property: TSESTree.Identifier;
}

/**
* Checks if the given `node` is a {@link JestExpectCallExpression}.
*
Expand Down Expand Up @@ -306,11 +315,6 @@ export const isDescribe = (
);
};

export const hasExpressions = (
node: TSESTree.Node,
): node is TSESTree.Expression =>
'expressions' in node && node.expressions.length > 0;

const collectReferences = (scope: TSESLint.Scope.Scope) => {
const locals = new Set();
const unresolved = new Set();
Expand Down