Skip to content

Commit

Permalink
feat: support aliases for jest globals (e.g. context) (#1129)
Browse files Browse the repository at this point in the history
  • Loading branch information
G-Rath committed Jun 4, 2022
1 parent 8beaad6 commit 02ec945
Show file tree
Hide file tree
Showing 34 changed files with 287 additions and 97 deletions.
19 changes: 19 additions & 0 deletions README.md
Expand Up @@ -59,6 +59,25 @@ doing:
This is included in all configs shared by this plugin, so can be omitted if
extending them.

#### Aliased Jest globals

You can tell this plugin about any global Jests you have aliased using the
`globalAliases` setting:

```json
{
"settings": {
"jest": {
"globalAliases": {
"describe": ["context"],
"fdescribe": ["fcontext"],
"xdescribe": ["xcontext"]
}
}
}
}
```

### Running rules only on test-related files

The rules provided by this plugin assume that the files they are checking are
Expand Down
17 changes: 17 additions & 0 deletions src/rules/__tests__/no-focused-tests.test.ts
Expand Up @@ -44,6 +44,23 @@ ruleTester.run('no-focused-tests', rule, {
},
],
},
{
code: 'context.only()',
errors: [
{
messageId: 'focusedTest',
column: 9,
line: 1,
suggestions: [
{
messageId: 'suggestRemoveFocus',
output: 'context()',
},
],
},
],
settings: { jest: { globalAliases: { describe: ['context'] } } },
},
{
code: 'describe.only.each()()',
errors: [
Expand Down
10 changes: 10 additions & 0 deletions src/rules/__tests__/no-identical-title.test.ts
Expand Up @@ -243,5 +243,15 @@ ruleTester.run('no-identical-title', rule, {
`,
errors: [{ messageId: 'multipleTestTitle', column: 6, line: 3 }],
},
{
code: dedent`
context('foo', () => {
describe('foe', () => {});
});
describe('foo', () => {});
`,
errors: [{ messageId: 'multipleDescribeTitle', column: 10, line: 4 }],
settings: { jest: { globalAliases: { describe: ['context'] } } },
},
],
});
21 changes: 21 additions & 0 deletions src/rules/__tests__/valid-expect-in-promise.test.ts
Expand Up @@ -1613,5 +1613,26 @@ ruleTester.run('valid-expect-in-promise', rule, {
},
],
},
{
code: dedent`
promiseThatThis('is valid', async () => {
const promise = loadNumber().then(number => {
expect(typeof number).toBe('number');
return number + 1;
});
expect(anotherPromise).resolves.toBe(1);
});
`,
errors: [
{
messageId: 'expectInFloatingPromise',
line: 2,
column: 9,
},
],
settings: { jest: { globalAliases: { xit: ['promiseThatThis'] } } },
},
],
});
5 changes: 2 additions & 3 deletions src/rules/consistent-test-it.ts
Expand Up @@ -72,8 +72,7 @@ export default createRule<

return {
CallExpression(node: TSESTree.CallExpression) {
const scope = context.getScope();
const jestFnCall = parseJestFnCall(node, scope);
const jestFnCall = parseJestFnCall(node, context);

if (!jestFnCall) {
return;
Expand Down Expand Up @@ -129,7 +128,7 @@ export default createRule<
}
},
'CallExpression:exit'(node) {
if (isTypeOfJestFnCall(node, context.getScope(), ['describe'])) {
if (isTypeOfJestFnCall(node, context, ['describe'])) {
describeNestingLevel--;
}
},
Expand Down
4 changes: 2 additions & 2 deletions src/rules/expect-expect.ts
Expand Up @@ -96,7 +96,7 @@ export default createRule<
const testCallExpressions =
getTestCallExpressionsFromDeclaredVariables(
declaredVariables,
context.getScope(),
context,
);

checkCallExpressionUsed(testCallExpressions);
Expand All @@ -114,7 +114,7 @@ export default createRule<
const name = getNodeName(node.callee) ?? '';

if (
isTypeOfJestFnCall(node, context.getScope(), ['test']) ||
isTypeOfJestFnCall(node, context, ['test']) ||
additionalTestBlockFunctions.includes(name)
) {
if (
Expand Down
4 changes: 2 additions & 2 deletions src/rules/max-nested-describe.ts
Expand Up @@ -38,7 +38,7 @@ export default createRule({

if (
parent?.type !== AST_NODE_TYPES.CallExpression ||
!isTypeOfJestFnCall(parent, context.getScope(), ['describe'])
!isTypeOfJestFnCall(parent, context, ['describe'])
) {
return;
}
Expand All @@ -61,7 +61,7 @@ export default createRule({

if (
parent?.type === AST_NODE_TYPES.CallExpression &&
isTypeOfJestFnCall(parent, context.getScope(), ['describe'])
isTypeOfJestFnCall(parent, context, ['describe'])
) {
describeCallbackStack.pop();
}
Expand Down
6 changes: 3 additions & 3 deletions src/rules/no-conditional-expect.ts
Expand Up @@ -42,15 +42,15 @@ export default createRule({
const declaredVariables = context.getDeclaredVariables(node);
const testCallExpressions = getTestCallExpressionsFromDeclaredVariables(
declaredVariables,
context.getScope(),
context,
);

if (testCallExpressions.length > 0) {
inTestCase = true;
}
},
CallExpression(node: TSESTree.CallExpression) {
if (isTypeOfJestFnCall(node, context.getScope(), ['test'])) {
if (isTypeOfJestFnCall(node, context, ['test'])) {
inTestCase = true;
}

Expand All @@ -73,7 +73,7 @@ export default createRule({
}
},
'CallExpression:exit'(node) {
if (isTypeOfJestFnCall(node, context.getScope(), ['test'])) {
if (isTypeOfJestFnCall(node, context, ['test'])) {
inTestCase = false;
}

Expand Down
4 changes: 2 additions & 2 deletions src/rules/no-conditional-in-test.ts
Expand Up @@ -30,12 +30,12 @@ export default createRule({

return {
CallExpression(node: TSESTree.CallExpression) {
if (isTypeOfJestFnCall(node, context.getScope(), ['test'])) {
if (isTypeOfJestFnCall(node, context, ['test'])) {
inTestCase = true;
}
},
'CallExpression:exit'(node) {
if (isTypeOfJestFnCall(node, context.getScope(), ['test'])) {
if (isTypeOfJestFnCall(node, context, ['test'])) {
inTestCase = false;
}
},
Expand Down
4 changes: 2 additions & 2 deletions src/rules/no-disabled-tests.ts
Expand Up @@ -31,7 +31,7 @@ export default createRule({

return {
CallExpression(node) {
const jestFnCall = parseJestFnCall(node, context.getScope());
const jestFnCall = parseJestFnCall(node, context);

if (!jestFnCall) {
return;
Expand Down Expand Up @@ -65,7 +65,7 @@ export default createRule({
}
},
'CallExpression:exit'(node) {
const jestFnCall = parseJestFnCall(node, context.getScope());
const jestFnCall = parseJestFnCall(node, context);

if (!jestFnCall) {
return;
Expand Down
6 changes: 3 additions & 3 deletions src/rules/no-done-callback.ts
Expand Up @@ -4,13 +4,13 @@ import { createRule, getNodeName, isFunction, parseJestFnCall } from './utils';
const findCallbackArg = (
node: TSESTree.CallExpression,
isJestEach: boolean,
scope: TSESLint.Scope.Scope,
context: TSESLint.RuleContext<string, unknown[]>,
): TSESTree.CallExpression['arguments'][0] | null => {
if (isJestEach) {
return node.arguments[1];
}

const jestFnCall = parseJestFnCall(node, scope);
const jestFnCall = parseJestFnCall(node, context);

if (jestFnCall?.type === 'hook' && node.arguments.length >= 1) {
return node.arguments[0];
Expand Down Expand Up @@ -60,7 +60,7 @@ export default createRule({
return;
}

const callback = findCallbackArg(node, isJestEach, context.getScope());
const callback = findCallbackArg(node, isJestEach, context);
const callbackArgIndex = Number(isJestEach);

if (
Expand Down
6 changes: 2 additions & 4 deletions src/rules/no-duplicate-hooks.ts
Expand Up @@ -20,9 +20,7 @@ export default createRule({

return {
CallExpression(node) {
const scope = context.getScope();

const jestFnCall = parseJestFnCall(node, scope);
const jestFnCall = parseJestFnCall(node, context);

if (jestFnCall?.type === 'describe') {
hookContexts.push({});
Expand All @@ -45,7 +43,7 @@ export default createRule({
}
},
'CallExpression:exit'(node) {
if (isTypeOfJestFnCall(node, context.getScope(), ['describe'])) {
if (isTypeOfJestFnCall(node, context, ['describe'])) {
hookContexts.pop();
}
},
Expand Down
2 changes: 1 addition & 1 deletion src/rules/no-export.ts
Expand Up @@ -34,7 +34,7 @@ export default createRule({
},

CallExpression(node) {
if (isTypeOfJestFnCall(node, context.getScope(), ['test'])) {
if (isTypeOfJestFnCall(node, context, ['test'])) {
hasTestCase = true;
}
},
Expand Down
4 changes: 1 addition & 3 deletions src/rules/no-focused-tests.ts
Expand Up @@ -22,9 +22,7 @@ export default createRule({
create(context) {
return {
CallExpression(node) {
const scope = context.getScope();

const jestFnCall = parseJestFnCall(node, scope);
const jestFnCall = parseJestFnCall(node, context);

if (jestFnCall?.type !== 'test' && jestFnCall?.type !== 'describe') {
return;
Expand Down
2 changes: 1 addition & 1 deletion src/rules/no-hooks.ts
Expand Up @@ -32,7 +32,7 @@ export default createRule<
create(context, [{ allow = [] }]) {
return {
CallExpression(node) {
const jestFnCall = parseJestFnCall(node, context.getScope());
const jestFnCall = parseJestFnCall(node, context);

if (
jestFnCall?.type === 'hook' &&
Expand Down
5 changes: 2 additions & 3 deletions src/rules/no-identical-title.ts
Expand Up @@ -40,10 +40,9 @@ export default createRule({

return {
CallExpression(node) {
const scope = context.getScope();
const currentLayer = contexts[contexts.length - 1];

const jestFnCall = parseJestFnCall(node, scope);
const jestFnCall = parseJestFnCall(node, context);

if (!jestFnCall) {
return;
Expand Down Expand Up @@ -87,7 +86,7 @@ export default createRule({
currentLayer.describeTitles.push(title);
},
'CallExpression:exit'(node) {
if (isTypeOfJestFnCall(node, context.getScope(), ['describe'])) {
if (isTypeOfJestFnCall(node, context, ['describe'])) {
contexts.pop();
}
},
Expand Down
4 changes: 2 additions & 2 deletions src/rules/no-if.ts
Expand Up @@ -75,7 +75,7 @@ export default createRule({

return {
CallExpression(node) {
const jestFnCall = parseJestFnCall(node, context.getScope());
const jestFnCall = parseJestFnCall(node, context);

if (jestFnCall?.type === 'test') {
stack.push(true);
Expand All @@ -92,7 +92,7 @@ export default createRule({
const declaredVariables = context.getDeclaredVariables(node);
const testCallExpressions = getTestCallExpressionsFromDeclaredVariables(
declaredVariables,
context.getScope(),
context,
);

stack.push(testCallExpressions.length > 0);
Expand Down
11 changes: 5 additions & 6 deletions src/rules/no-standalone-expect.ts
Expand Up @@ -10,7 +10,7 @@ import {

const getBlockType = (
statement: TSESTree.BlockStatement,
scope: TSESLint.Scope.Scope,
context: TSESLint.RuleContext<string, unknown[]>,
): 'function' | 'describe' | null => {
const func = statement.parent;

Expand All @@ -37,7 +37,7 @@ const getBlockType = (
// if it's not a variable, it will be callExpr, we only care about describe
if (
expr.type === AST_NODE_TYPES.CallExpression &&
isTypeOfJestFnCall(expr, scope, ['describe'])
isTypeOfJestFnCall(expr, context, ['describe'])
) {
return 'describe';
}
Expand Down Expand Up @@ -85,7 +85,7 @@ export default createRule<
additionalTestBlockFunctions.includes(getNodeName(node) || '');

const isTestBlock = (node: TSESTree.CallExpression): boolean =>
isTypeOfJestFnCall(node, context.getScope(), ['test']) ||
isTypeOfJestFnCall(node, context, ['test']) ||
isCustomTestBlockFunction(node);

return {
Expand Down Expand Up @@ -123,16 +123,15 @@ export default createRule<
},

BlockStatement(statement) {
const blockType = getBlockType(statement, context.getScope());
const blockType = getBlockType(statement, context);

if (blockType) {
callStack.push(blockType);
}
},
'BlockStatement:exit'(statement: TSESTree.BlockStatement) {
if (
callStack[callStack.length - 1] ===
getBlockType(statement, context.getScope())
callStack[callStack.length - 1] === getBlockType(statement, context)
) {
callStack.pop();
}
Expand Down
3 changes: 1 addition & 2 deletions src/rules/no-test-prefixes.ts
Expand Up @@ -20,8 +20,7 @@ export default createRule({
create(context) {
return {
CallExpression(node) {
const scope = context.getScope();
const jestFnCall = parseJestFnCall(node, scope);
const jestFnCall = parseJestFnCall(node, context);

if (jestFnCall?.type !== 'describe' && jestFnCall?.type !== 'test') {
return;
Expand Down
4 changes: 2 additions & 2 deletions src/rules/no-test-return-statement.ts
Expand Up @@ -38,7 +38,7 @@ export default createRule({
create(context) {
return {
CallExpression(node) {
if (!isTypeOfJestFnCall(node, context.getScope(), ['test'])) {
if (!isTypeOfJestFnCall(node, context, ['test'])) {
return;
}

Expand All @@ -55,7 +55,7 @@ export default createRule({
const declaredVariables = context.getDeclaredVariables(node);
const testCallExpressions = getTestCallExpressionsFromDeclaredVariables(
declaredVariables,
context.getScope(),
context,
);

if (testCallExpressions.length === 0) return;
Expand Down

0 comments on commit 02ec945

Please sign in to comment.