-
Notifications
You must be signed in to change notification settings - Fork 234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add no-confusing-set-time rule #1425
feat: add no-confusing-set-time rule #1425
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good start but requires more work - I've done an initial review to give you some pointers, but really your whole implementation needs to be redone to use parseJestFnCall
so I've not reviewed that for now.
Thanks for your excellent guidance and review. I've upgrade according your suggestions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have done an initial re-review of the code - its coming together nicely; I'll have a look at the rest during the week, but in the meantime if you have the time to address what I've mentioned currently that'd be great
|
||
if (!jestFnCall) return; | ||
|
||
if ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If jestFnCall
returns non-null it means that we believe the call is something from Jest, even if the type is unknown
- so we should be fine to just check if the call is to setTimeout
or not; and given that I'd move all that logic into isJsetSetTimeout
(i.e. have it take the ParsedJestFnCall
and handle checking that the type
is jest
)
2766207
to
b0338c0
Compare
`jest.setTimeout` can be called multiple times anywhere within a single test | ||
file. However, only the last call will have an effect, and it will actually be | ||
invoked before any other jest functions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
`jest.setTimeout` can be called multiple times anywhere within a single test | |
file. However, only the last call will have an effect, and it will actually be | |
invoked before any other jest functions. | |
While `jest.setTimeout` can be called multiple times anywhere within a single test | |
file only the last call before any test functions run will have an effect. |
This rule describes some tricky ways about `jest.setTimeout` that should not | ||
recommend in Jest: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about this:
This rule describes some tricky ways about `jest.setTimeout` that should not | |
recommend in Jest: | |
This rule checks for several confusing usages of `jest.setTimeout` that looks like it applies to specific tests within the same file, such as: | |
- being called anywhere other than in global scope | |
- being called multiple times | |
- being called after other Jest functions like hooks, `describe`, `test`, or `it` |
function isJestSetTimeout(node: TSESTree.Node) { | ||
return getNodeName(node) === 'jest.setTimeout'; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check is not correct because it does not account for aliases i.e. this will not get caught:
import { jest as Jest } from '@jest/globals';
{
Jest.setTimeout(800);
}
While a bit contrived, this is why parseJestFnCall
exists and is what you should be checking instead:
function isJestSetTimeout(jestFnCall: ParsedJestFnCall) {
return (
jestFnCall.type === 'jest' &&
jestFnCall.members.length === 1 &&
isIdentifier(jestFnCall.members[0], 'setTimeout')
);
}
return; | ||
} | ||
|
||
const result = isJestSetTimeout(node); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's call this something like thisIsJestSetTimeoutCall
- its a bit verbose, but there's no downside and I think its important to be clear given all the "is jest settimeout" names we've got going on
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, naming makes my head burn out.
if (jestFnCall.type !== 'unknown') { | ||
shouldEmitOrderSetTimeout = true; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By definition there is no known Jest function call of type unknown
- it only exists to gracefully handle if Jest ever did get a new type in older versions of the plugin (since we'd have to release a new version adding support); so you shouldn't worry about it here:
if (jestFnCall.type !== 'unknown') { | |
shouldEmitOrderSetTimeout = true; | |
} | |
shouldEmitOrderSetTimeout = true; |
globalSetTimeout: '`jest.setTimeout` should be call in `global` scope.', | ||
multipleSetTimeouts: | ||
'Do not call `jest.setTimeout` multiple times, as only the last call will have an effect.', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Linting messages shouldn't use full stops because they might appear in sentences constructed by IDEs and such:
globalSetTimeout: '`jest.setTimeout` should be call in `global` scope.', | |
multipleSetTimeouts: | |
'Do not call `jest.setTimeout` multiple times, as only the last call will have an effect.', | |
globalSetTimeout: '`jest.setTimeout` should be call in `global` scope', | |
multipleSetTimeouts: | |
'Do not call `jest.setTimeout` multiple times, as only the last call will have an effect', |
meta: { | ||
docs: { | ||
category: 'Best Practices', | ||
description: 'Disallow using confusing setTimeout in test', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
description: 'Disallow using confusing setTimeout in test', | |
description: 'Disallow confusing usages of jest.setTimeout', |
Done~ Thanks for your guidances and patience |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just got a small cleanup and a typo, and then I think this is good to go!
return; | ||
} | ||
|
||
const thisIsJestSetTimeoutCall = isJestSetTimeout(jestFnCall); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We actually don't need this variable or your else
block at the end because we only do more work if this is a jest.setTimeout
- so you can just do:
if (!isJestSetTimeout(jestFnCall)) {
shouldEmitOrderSetTimeout = true;
return;
}
// ...
seenJestTimeout = true;
Prettier is still unhappy about something 😅 |
# [27.3.0](v27.2.3...v27.3.0) (2023-09-15) ### Features * add `no-confusing-set-time` rule ([#1425](#1425)) ([ff8e482](ff8e482))
🎉 This PR is included in version 27.3.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Fix: #1366