Skip to content

Commit

Permalink
Fix FP S2699 (assertions-in-tests): add support for vitest library (
Browse files Browse the repository at this point in the history
  • Loading branch information
ilia-kebets-sonarsource authored Oct 31, 2023
1 parent be2ebd9 commit 8c2a4c3
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 5 deletions.
11 changes: 7 additions & 4 deletions packages/jsts/src/rules/S2699/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
import { Rule, SourceCode } from 'eslint';
import * as estree from 'estree';
import { childrenOf } from '../../linter';
import { Chai, isFunctionCall, Mocha, resolveFunction } from '../helpers';
import { Sinon } from '../helpers/sinon';
import { Chai, isFunctionCall, Mocha, resolveFunction, Sinon, Vitest } from '../helpers';

/**
* We assume that the user is using a single assertion library per file,
Expand All @@ -41,7 +40,7 @@ export const rule: Rule.RuleModule = {
}
},
'Program:exit': () => {
if (Chai.isImported(context) || Sinon.isImported(context)) {
if (Chai.isImported(context) || Sinon.isImported(context) || Vitest.isImported(context)) {
potentialIssues.forEach(issue => {
context.report(issue);
});
Expand Down Expand Up @@ -82,7 +81,11 @@ class TestCaseAssertionVisitor {
if (this.hasAssertions) {
return;
}
if (Chai.isAssertion(context, node) || Sinon.isAssertion(context, node)) {
if (
Chai.isAssertion(context, node) ||
Sinon.isAssertion(context, node) ||
Vitest.isAssertion(context, node)
) {
this.hasAssertions = true;
return;
}
Expand Down
25 changes: 25 additions & 0 deletions packages/jsts/src/rules/S2699/vitest.fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// sum.test.js
const vitest = require('vitest');
const { describe, expect, it } = require('vitest');

describe('vitest test cases', () => {
it('no assertion', () => { // Noncompliant {{Add at least one assertion to this test case.}}
alert('msg');
});

it('expect', () => { // Compliant
expect(1).toEqual(2);
});

it('vitest.expect', () => { // Compliant
vitest.expect(1).toEqual(2);
});

it('transitive assertion', () => { // Compliant
check();
});

function check() {
expect(1).toEqual(2);
}
});
4 changes: 3 additions & 1 deletion packages/jsts/src/rules/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export * from './ancestor';
export * from './ast';
export * from './chai';
export * from './collection';
export * from './decorators';
export * from './express';
export * from './file';
export * from './globals';
Expand All @@ -31,8 +32,9 @@ export * from './module';
export * from './quickfix';
export * from './reaching-definitions';
export * from './rule-detect-react';
export * from './sinon';
export * from './type';
export * from './decorators';
export * from './vitest';
export * from './vue';

export * from 'eslint-plugin-sonarjs/lib/utils/parser-services';
48 changes: 48 additions & 0 deletions packages/jsts/src/rules/helpers/vitest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2023 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { Rule } from 'eslint';
import * as estree from 'estree';
import { getFullyQualifiedName, getImportDeclarations, getRequireCalls } from '.';

export namespace Vitest {
export function isImported(context: Rule.RuleContext): boolean {
return (
getRequireCalls(context).some(
r => r.arguments[0].type === 'Literal' && r.arguments[0].value === 'vitest',
) || getImportDeclarations(context).some(i => i.source.value === 'vitest')
);
}

export function isAssertion(context: Rule.RuleContext, node: estree.Node): boolean {
return isExpectUsage(context, node);
}

function isExpectUsage(context: Rule.RuleContext, node: estree.Node) {
// expect(), vitest.expect()
return extractFQNforCallExpression(context, node) === 'vitest.expect';
}

function extractFQNforCallExpression(context: Rule.RuleContext, node: estree.Node) {
if (node.type !== 'CallExpression') {
return undefined;
}
return getFullyQualifiedName(context, node);
}
}

0 comments on commit 8c2a4c3

Please sign in to comment.