Skip to content

Commit 328f5dd

Browse files
committed
feat: support aliases for jest globals (e.g. context)
1 parent 0b2d64d commit 328f5dd

34 files changed

+287
-97
lines changed

README.md

+19
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,25 @@ doing:
5959
This is included in all configs shared by this plugin, so can be omitted if
6060
extending them.
6161

62+
#### Aliased Jest globals
63+
64+
You can tell this plugin about any global Jests you have aliased using the
65+
`globalAliases` setting:
66+
67+
```json
68+
{
69+
"settings": {
70+
"jest": {
71+
"globalAliases": {
72+
"describe": ["context"],
73+
"fdescribe": ["fcontext"],
74+
"xdescribe": ["xcontext"]
75+
}
76+
}
77+
}
78+
}
79+
```
80+
6281
### Running rules only on test-related files
6382

6483
The rules provided by this plugin assume that the files they are checking are

src/rules/__tests__/no-focused-tests.test.ts

+17
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,23 @@ ruleTester.run('no-focused-tests', rule, {
4444
},
4545
],
4646
},
47+
{
48+
code: 'context.only()',
49+
errors: [
50+
{
51+
messageId: 'focusedTest',
52+
column: 9,
53+
line: 1,
54+
suggestions: [
55+
{
56+
messageId: 'suggestRemoveFocus',
57+
output: 'context()',
58+
},
59+
],
60+
},
61+
],
62+
settings: { jest: { globalAliases: { describe: ['context'] } } },
63+
},
4764
{
4865
code: 'describe.only.each()()',
4966
errors: [

src/rules/__tests__/no-identical-title.test.ts

+10
Original file line numberDiff line numberDiff line change
@@ -243,5 +243,15 @@ ruleTester.run('no-identical-title', rule, {
243243
`,
244244
errors: [{ messageId: 'multipleTestTitle', column: 6, line: 3 }],
245245
},
246+
{
247+
code: dedent`
248+
context('foo', () => {
249+
describe('foe', () => {});
250+
});
251+
describe('foo', () => {});
252+
`,
253+
errors: [{ messageId: 'multipleDescribeTitle', column: 10, line: 4 }],
254+
settings: { jest: { globalAliases: { describe: ['context'] } } },
255+
},
246256
],
247257
});

src/rules/__tests__/valid-expect-in-promise.test.ts

+21
Original file line numberDiff line numberDiff line change
@@ -1613,5 +1613,26 @@ ruleTester.run('valid-expect-in-promise', rule, {
16131613
},
16141614
],
16151615
},
1616+
{
1617+
code: dedent`
1618+
promiseThatThis('is valid', async () => {
1619+
const promise = loadNumber().then(number => {
1620+
expect(typeof number).toBe('number');
1621+
1622+
return number + 1;
1623+
});
1624+
1625+
expect(anotherPromise).resolves.toBe(1);
1626+
});
1627+
`,
1628+
errors: [
1629+
{
1630+
messageId: 'expectInFloatingPromise',
1631+
line: 2,
1632+
column: 9,
1633+
},
1634+
],
1635+
settings: { jest: { globalAliases: { xit: ['promiseThatThis'] } } },
1636+
},
16161637
],
16171638
});

src/rules/consistent-test-it.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,7 @@ export default createRule<
7272

7373
return {
7474
CallExpression(node: TSESTree.CallExpression) {
75-
const scope = context.getScope();
76-
const jestFnCall = parseJestFnCall(node, scope);
75+
const jestFnCall = parseJestFnCall(node, context);
7776

7877
if (!jestFnCall) {
7978
return;
@@ -129,7 +128,7 @@ export default createRule<
129128
}
130129
},
131130
'CallExpression:exit'(node) {
132-
if (isTypeOfJestFnCall(node, context.getScope(), ['describe'])) {
131+
if (isTypeOfJestFnCall(node, context, ['describe'])) {
133132
describeNestingLevel--;
134133
}
135134
},

src/rules/expect-expect.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export default createRule<
9696
const testCallExpressions =
9797
getTestCallExpressionsFromDeclaredVariables(
9898
declaredVariables,
99-
context.getScope(),
99+
context,
100100
);
101101

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

116116
if (
117-
isTypeOfJestFnCall(node, context.getScope(), ['test']) ||
117+
isTypeOfJestFnCall(node, context, ['test']) ||
118118
additionalTestBlockFunctions.includes(name)
119119
) {
120120
if (

src/rules/max-nested-describe.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export default createRule({
3838

3939
if (
4040
parent?.type !== AST_NODE_TYPES.CallExpression ||
41-
!isTypeOfJestFnCall(parent, context.getScope(), ['describe'])
41+
!isTypeOfJestFnCall(parent, context, ['describe'])
4242
) {
4343
return;
4444
}
@@ -61,7 +61,7 @@ export default createRule({
6161

6262
if (
6363
parent?.type === AST_NODE_TYPES.CallExpression &&
64-
isTypeOfJestFnCall(parent, context.getScope(), ['describe'])
64+
isTypeOfJestFnCall(parent, context, ['describe'])
6565
) {
6666
describeCallbackStack.pop();
6767
}

src/rules/no-conditional-expect.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,15 @@ export default createRule({
4242
const declaredVariables = context.getDeclaredVariables(node);
4343
const testCallExpressions = getTestCallExpressionsFromDeclaredVariables(
4444
declaredVariables,
45-
context.getScope(),
45+
context,
4646
);
4747

4848
if (testCallExpressions.length > 0) {
4949
inTestCase = true;
5050
}
5151
},
5252
CallExpression(node: TSESTree.CallExpression) {
53-
if (isTypeOfJestFnCall(node, context.getScope(), ['test'])) {
53+
if (isTypeOfJestFnCall(node, context, ['test'])) {
5454
inTestCase = true;
5555
}
5656

@@ -73,7 +73,7 @@ export default createRule({
7373
}
7474
},
7575
'CallExpression:exit'(node) {
76-
if (isTypeOfJestFnCall(node, context.getScope(), ['test'])) {
76+
if (isTypeOfJestFnCall(node, context, ['test'])) {
7777
inTestCase = false;
7878
}
7979

src/rules/no-conditional-in-test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ export default createRule({
3030

3131
return {
3232
CallExpression(node: TSESTree.CallExpression) {
33-
if (isTypeOfJestFnCall(node, context.getScope(), ['test'])) {
33+
if (isTypeOfJestFnCall(node, context, ['test'])) {
3434
inTestCase = true;
3535
}
3636
},
3737
'CallExpression:exit'(node) {
38-
if (isTypeOfJestFnCall(node, context.getScope(), ['test'])) {
38+
if (isTypeOfJestFnCall(node, context, ['test'])) {
3939
inTestCase = false;
4040
}
4141
},

src/rules/no-disabled-tests.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export default createRule({
3131

3232
return {
3333
CallExpression(node) {
34-
const jestFnCall = parseJestFnCall(node, context.getScope());
34+
const jestFnCall = parseJestFnCall(node, context);
3535

3636
if (!jestFnCall) {
3737
return;
@@ -62,7 +62,7 @@ export default createRule({
6262
}
6363
},
6464
'CallExpression:exit'(node) {
65-
const jestFnCall = parseJestFnCall(node, context.getScope());
65+
const jestFnCall = parseJestFnCall(node, context);
6666

6767
if (!jestFnCall) {
6868
return;

src/rules/no-done-callback.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import { createRule, getNodeName, isFunction, parseJestFnCall } from './utils';
44
const findCallbackArg = (
55
node: TSESTree.CallExpression,
66
isJestEach: boolean,
7-
scope: TSESLint.Scope.Scope,
7+
context: TSESLint.RuleContext<string, unknown[]>,
88
): TSESTree.CallExpression['arguments'][0] | null => {
99
if (isJestEach) {
1010
return node.arguments[1];
1111
}
1212

13-
const jestFnCall = parseJestFnCall(node, scope);
13+
const jestFnCall = parseJestFnCall(node, context);
1414

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

63-
const callback = findCallbackArg(node, isJestEach, context.getScope());
63+
const callback = findCallbackArg(node, isJestEach, context);
6464
const callbackArgIndex = Number(isJestEach);
6565

6666
if (

src/rules/no-duplicate-hooks.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ export default createRule({
2020

2121
return {
2222
CallExpression(node) {
23-
const scope = context.getScope();
24-
25-
const jestFnCall = parseJestFnCall(node, scope);
23+
const jestFnCall = parseJestFnCall(node, context);
2624

2725
if (jestFnCall?.type === 'describe') {
2826
hookContexts.push({});
@@ -45,7 +43,7 @@ export default createRule({
4543
}
4644
},
4745
'CallExpression:exit'(node) {
48-
if (isTypeOfJestFnCall(node, context.getScope(), ['describe'])) {
46+
if (isTypeOfJestFnCall(node, context, ['describe'])) {
4947
hookContexts.pop();
5048
}
5149
},

src/rules/no-export.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export default createRule({
3434
},
3535

3636
CallExpression(node) {
37-
if (isTypeOfJestFnCall(node, context.getScope(), ['test'])) {
37+
if (isTypeOfJestFnCall(node, context, ['test'])) {
3838
hasTestCase = true;
3939
}
4040
},

src/rules/no-focused-tests.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ export default createRule({
2222
create(context) {
2323
return {
2424
CallExpression(node) {
25-
const scope = context.getScope();
26-
27-
const jestFnCall = parseJestFnCall(node, scope);
25+
const jestFnCall = parseJestFnCall(node, context);
2826

2927
if (jestFnCall?.type !== 'test' && jestFnCall?.type !== 'describe') {
3028
return;

src/rules/no-hooks.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export default createRule<
3232
create(context, [{ allow = [] }]) {
3333
return {
3434
CallExpression(node) {
35-
const jestFnCall = parseJestFnCall(node, context.getScope());
35+
const jestFnCall = parseJestFnCall(node, context);
3636

3737
if (
3838
jestFnCall?.type === 'hook' &&

src/rules/no-identical-title.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,9 @@ export default createRule({
4040

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

46-
const jestFnCall = parseJestFnCall(node, scope);
45+
const jestFnCall = parseJestFnCall(node, context);
4746

4847
if (!jestFnCall) {
4948
return;
@@ -87,7 +86,7 @@ export default createRule({
8786
currentLayer.describeTitles.push(title);
8887
},
8988
'CallExpression:exit'(node) {
90-
if (isTypeOfJestFnCall(node, context.getScope(), ['describe'])) {
89+
if (isTypeOfJestFnCall(node, context, ['describe'])) {
9190
contexts.pop();
9291
}
9392
},

src/rules/no-if.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export default createRule({
7575

7676
return {
7777
CallExpression(node) {
78-
const jestFnCall = parseJestFnCall(node, context.getScope());
78+
const jestFnCall = parseJestFnCall(node, context);
7979

8080
if (jestFnCall?.type === 'test') {
8181
stack.push(true);
@@ -92,7 +92,7 @@ export default createRule({
9292
const declaredVariables = context.getDeclaredVariables(node);
9393
const testCallExpressions = getTestCallExpressionsFromDeclaredVariables(
9494
declaredVariables,
95-
context.getScope(),
95+
context,
9696
);
9797

9898
stack.push(testCallExpressions.length > 0);

src/rules/no-standalone-expect.ts

+5-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010

1111
const getBlockType = (
1212
statement: TSESTree.BlockStatement,
13-
scope: TSESLint.Scope.Scope,
13+
context: TSESLint.RuleContext<string, unknown[]>,
1414
): 'function' | 'describe' | null => {
1515
const func = statement.parent;
1616

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

8787
const isTestBlock = (node: TSESTree.CallExpression): boolean =>
88-
isTypeOfJestFnCall(node, context.getScope(), ['test']) ||
88+
isTypeOfJestFnCall(node, context, ['test']) ||
8989
isCustomTestBlockFunction(node);
9090

9191
return {
@@ -123,16 +123,15 @@ export default createRule<
123123
},
124124

125125
BlockStatement(statement) {
126-
const blockType = getBlockType(statement, context.getScope());
126+
const blockType = getBlockType(statement, context);
127127

128128
if (blockType) {
129129
callStack.push(blockType);
130130
}
131131
},
132132
'BlockStatement:exit'(statement: TSESTree.BlockStatement) {
133133
if (
134-
callStack[callStack.length - 1] ===
135-
getBlockType(statement, context.getScope())
134+
callStack[callStack.length - 1] === getBlockType(statement, context)
136135
) {
137136
callStack.pop();
138137
}

src/rules/no-test-prefixes.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ export default createRule({
2020
create(context) {
2121
return {
2222
CallExpression(node) {
23-
const scope = context.getScope();
24-
const jestFnCall = parseJestFnCall(node, scope);
23+
const jestFnCall = parseJestFnCall(node, context);
2524

2625
if (jestFnCall?.type !== 'describe' && jestFnCall?.type !== 'test') {
2726
return;

src/rules/no-test-return-statement.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export default createRule({
3838
create(context) {
3939
return {
4040
CallExpression(node) {
41-
if (!isTypeOfJestFnCall(node, context.getScope(), ['test'])) {
41+
if (!isTypeOfJestFnCall(node, context, ['test'])) {
4242
return;
4343
}
4444

@@ -55,7 +55,7 @@ export default createRule({
5555
const declaredVariables = context.getDeclaredVariables(node);
5656
const testCallExpressions = getTestCallExpressionsFromDeclaredVariables(
5757
declaredVariables,
58-
context.getScope(),
58+
context,
5959
);
6060

6161
if (testCallExpressions.length === 0) return;

0 commit comments

Comments
 (0)