Skip to content

Commit 07e883f

Browse files
committed
feat(prefer-expect-assertions): support afterEach hook
1 parent 8980276 commit 07e883f

File tree

2 files changed

+220
-17
lines changed

2 files changed

+220
-17
lines changed

src/rules/__tests__/prefer-expect-assertions.test.ts

Lines changed: 205 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ ruleTester.run('prefer-expect-assertions', rule, {
115115
});
116116
`,
117117
dedent`
118-
beforeEach(() => {
118+
afterEach(() => {
119119
expect.hasAssertions();
120120
});
121121
@@ -130,7 +130,7 @@ ruleTester.run('prefer-expect-assertions', rule, {
130130
});
131131
`,
132132
dedent`
133-
beforeEach(() => {
133+
afterEach(() => {
134134
expect.hasAssertions();
135135
});
136136
@@ -228,6 +228,27 @@ ruleTester.run('prefer-expect-assertions', rule, {
228228
describe('my tests', () => {
229229
beforeEach(() => { expect.hasAssertions(); });
230230
231+
describe('left', () => {
232+
afterEach(() => { expect.hasAssertions(); });
233+
234+
it('responds ok', function () {
235+
client.get('/user', response => {
236+
expect(response.status).toBe(200);
237+
});
238+
});
239+
});
240+
241+
describe('right', () => {
242+
it("is a number that is greater than four", () => {
243+
expect(number).toBeGreaterThan(4);
244+
});
245+
});
246+
});
247+
`,
248+
dedent`
249+
describe('my tests', () => {
250+
beforeEach(() => { expect.hasAssertions(); });
251+
231252
it('responds ok', function () {
232253
client.get('/user', response => {
233254
expect(response.status).toBe(200);
@@ -423,6 +444,65 @@ ruleTester.run('prefer-expect-assertions', rule, {
423444
},
424445
],
425446
},
447+
{
448+
code: dedent`
449+
it("it1", function() {
450+
someFunctionToDo();
451+
someFunctionToDo2();
452+
});
453+
454+
describe('some tests', () => {
455+
afterEach(() => { expect.hasAssertions(); });
456+
it("it1", function() {
457+
someFunctionToDo();
458+
someFunctionToDo2();
459+
});
460+
});
461+
`,
462+
errors: [
463+
{
464+
messageId: 'haveExpectAssertions',
465+
column: 1,
466+
line: 1,
467+
suggestions: [
468+
{
469+
messageId: 'suggestAddingHasAssertions',
470+
output: dedent`
471+
it("it1", function() {expect.hasAssertions();
472+
someFunctionToDo();
473+
someFunctionToDo2();
474+
});
475+
476+
describe('some tests', () => {
477+
afterEach(() => { expect.hasAssertions(); });
478+
it("it1", function() {
479+
someFunctionToDo();
480+
someFunctionToDo2();
481+
});
482+
});
483+
`,
484+
},
485+
{
486+
messageId: 'suggestAddingAssertions',
487+
output: dedent`
488+
it("it1", function() {expect.assertions();
489+
someFunctionToDo();
490+
someFunctionToDo2();
491+
});
492+
493+
describe('some tests', () => {
494+
afterEach(() => { expect.hasAssertions(); });
495+
it("it1", function() {
496+
someFunctionToDo();
497+
someFunctionToDo2();
498+
});
499+
});
500+
`,
501+
},
502+
],
503+
},
504+
],
505+
},
426506
{
427507
// todo: this should be considered valid, as hooks are evaluated before tests are run
428508
code: dedent`
@@ -717,6 +797,38 @@ ruleTester.run('prefer-expect-assertions', rule, {
717797
},
718798
],
719799
},
800+
{
801+
code: 'afterEach(() => { expect.hasAssertions("1") })',
802+
errors: [
803+
{
804+
messageId: 'hasAssertionsTakesNoArguments',
805+
column: 26,
806+
line: 1,
807+
suggestions: [
808+
{
809+
messageId: 'suggestRemovingExtraArguments',
810+
output: 'afterEach(() => { expect.hasAssertions() })',
811+
},
812+
],
813+
},
814+
],
815+
},
816+
{
817+
code: 'afterEach(() => expect.hasAssertions("1"))',
818+
errors: [
819+
{
820+
messageId: 'hasAssertionsTakesNoArguments',
821+
column: 24,
822+
line: 1,
823+
suggestions: [
824+
{
825+
messageId: 'suggestRemovingExtraArguments',
826+
output: 'afterEach(() => expect.hasAssertions())',
827+
},
828+
],
829+
},
830+
],
831+
},
720832
{
721833
code: 'it("it1", function() {expect.hasAssertions("1");})',
722834
errors: [
@@ -1876,6 +1988,75 @@ ruleTester.run('prefer-expect-assertions (loops)', rule, {
18761988
},
18771989
],
18781990
},
1991+
{
1992+
code: dedent`
1993+
describe('my tests', () => {
1994+
afterEach(() => { expect.hasAssertions(); });
1995+
1996+
it("it1", async () => {
1997+
for (const number of getNumbers()) {
1998+
expect(number).toBeGreaterThan(4);
1999+
}
2000+
});
2001+
});
2002+
2003+
it("it1", () => {
2004+
for (const number of getNumbers()) {
2005+
expect(number).toBeGreaterThan(4);
2006+
}
2007+
});
2008+
`,
2009+
options: [{ onlyFunctionsWithExpectInLoop: true }],
2010+
errors: [
2011+
{
2012+
messageId: 'haveExpectAssertions',
2013+
column: 1,
2014+
line: 11,
2015+
suggestions: [
2016+
{
2017+
messageId: 'suggestAddingHasAssertions',
2018+
output: dedent`
2019+
describe('my tests', () => {
2020+
afterEach(() => { expect.hasAssertions(); });
2021+
2022+
it("it1", async () => {
2023+
for (const number of getNumbers()) {
2024+
expect(number).toBeGreaterThan(4);
2025+
}
2026+
});
2027+
});
2028+
2029+
it("it1", () => {expect.hasAssertions();
2030+
for (const number of getNumbers()) {
2031+
expect(number).toBeGreaterThan(4);
2032+
}
2033+
});
2034+
`,
2035+
},
2036+
{
2037+
messageId: 'suggestAddingAssertions',
2038+
output: dedent`
2039+
describe('my tests', () => {
2040+
afterEach(() => { expect.hasAssertions(); });
2041+
2042+
it("it1", async () => {
2043+
for (const number of getNumbers()) {
2044+
expect(number).toBeGreaterThan(4);
2045+
}
2046+
});
2047+
});
2048+
2049+
it("it1", () => {expect.assertions();
2050+
for (const number of getNumbers()) {
2051+
expect(number).toBeGreaterThan(4);
2052+
}
2053+
});
2054+
`,
2055+
},
2056+
],
2057+
},
2058+
],
2059+
},
18792060
{
18802061
code: dedent`
18812062
it.skip.each\`\`("it1", async () => {
@@ -2224,6 +2405,28 @@ ruleTester.run('prefer-expect-assertions (callbacks)', rule, {
22242405
`,
22252406
options: [{ onlyFunctionsWithExpectInCallback: true }],
22262407
},
2408+
{
2409+
code: dedent`
2410+
it('responds ok', function () {
2411+
expect.assertions(1);
2412+
2413+
client.get('/user', response => {
2414+
expect(response.status).toBe(200);
2415+
});
2416+
});
2417+
2418+
describe('my test', () => {
2419+
afterEach(() => expect.hasAssertions());
2420+
2421+
it('responds ok', function () {
2422+
client.get('/user', response => {
2423+
expect(response.status).toBe(200);
2424+
});
2425+
});
2426+
});
2427+
`,
2428+
options: [{ onlyFunctionsWithExpectInCallback: true }],
2429+
},
22272430
],
22282431
invalid: [
22292432
{

src/rules/prefer-expect-assertions.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -194,14 +194,14 @@ export default createRule<[RuleOptions], MessageIds>({
194194
const enterForLoop = () => (inForLoop = true);
195195
const exitForLoop = () => (inForLoop = false);
196196

197-
let inBeforeEach = false;
197+
let inEachHook = false;
198198

199199
// when set to a non-negative value, all expect calls within describes whose depth
200200
// are equal to or higher than this value as covered by an expect.hasAssertions set
201-
// up within a beforeEach hook
201+
// up within a beforeEach or afterEach hook
202202
//
203203
// when the describe depth is lower than the current value, it gets reset to -1
204-
let coveredByBeforeEachAtDepth = -1;
204+
let coveredByHookAtDepth = -1;
205205

206206
return {
207207
FunctionExpression: enterExpression,
@@ -221,8 +221,8 @@ export default createRule<[RuleOptions], MessageIds>({
221221
describeDepth += 1;
222222
}
223223

224-
if (jestFnCall?.type === 'hook' && jestFnCall.name === 'beforeEach') {
225-
inBeforeEach = true;
224+
if (jestFnCall?.type === 'hook' && jestFnCall.name.endsWith('Each')) {
225+
inEachHook = true;
226226
}
227227

228228
if (jestFnCall?.type === 'test') {
@@ -231,12 +231,12 @@ export default createRule<[RuleOptions], MessageIds>({
231231
return;
232232
}
233233

234-
if (jestFnCall?.type === 'expect' && inBeforeEach) {
234+
if (jestFnCall?.type === 'expect' && inEachHook) {
235235
if (getAccessorValue(jestFnCall.members[0]) === 'hasAssertions') {
236236
checkExpectHasAssertions(jestFnCall, node);
237237

238-
if (coveredByBeforeEachAtDepth < 0) {
239-
coveredByBeforeEachAtDepth = describeDepth;
238+
if (coveredByHookAtDepth < 0) {
239+
coveredByHookAtDepth = describeDepth;
240240
}
241241
}
242242
}
@@ -271,15 +271,15 @@ export default createRule<[RuleOptions], MessageIds>({
271271
if (jestFnCall?.type === 'describe') {
272272
describeDepth -= 1;
273273

274-
// clear the "covered by beforeEach" flag if we have left the describe
274+
// clear the "covered by each hook" flag if we have left the describe
275275
// depth that it applies to
276-
if (coveredByBeforeEachAtDepth > describeDepth) {
277-
coveredByBeforeEachAtDepth = -1;
276+
if (coveredByHookAtDepth > describeDepth) {
277+
coveredByHookAtDepth = -1;
278278
}
279279
}
280280

281-
if (jestFnCall?.type === 'hook' && jestFnCall.name === 'beforeEach') {
282-
inBeforeEach = false;
281+
if (jestFnCall?.type === 'hook' && jestFnCall.name.endsWith('Each')) {
282+
inEachHook = false;
283283
}
284284

285285
if (jestFnCall?.type !== 'test') {
@@ -308,8 +308,8 @@ export default createRule<[RuleOptions], MessageIds>({
308308
}
309309

310310
if (
311-
coveredByBeforeEachAtDepth >= 0 &&
312-
coveredByBeforeEachAtDepth <= describeDepth
311+
coveredByHookAtDepth >= 0 &&
312+
coveredByHookAtDepth <= describeDepth
313313
) {
314314
return;
315315
}

0 commit comments

Comments
 (0)