Description
When the result of test.extend(...) is bound as it (the standard fixture idiom), every it(...) call inside a describe is reported with "Prefer using it instead of test within describe", although the callee is already spelled it. The rule compares the resolved original import name (test) and never consults the local binding name. The autofix rewrites it to it, so ESLint counts these as fixable warnings that --fix leaves unchanged.
This is distinct from #884: that issue covers the report on the .extend() factory call itself, while this one covers the reports on the extended function's invocations. A fix that skips factory calls leaves this case in place.
Reproduction
eslint.config.mjs:
import vitest from '@vitest/eslint-plugin';
export default [
{
files: ['**/*.test.js'],
plugins: { vitest },
rules: { 'vitest/consistent-test-it': 'warn' },
},
];
extended-binding.test.js:
import { describe, expect, test } from 'vitest';
const it = test.extend({
fixture: async ({}, use) => {
await use('hello');
},
});
describe('example', () => {
it('uses the fixture', ({ fixture }) => {
expect(fixture).toBe('hello');
});
});
Observed:
10:3 warning Prefer using it instead of test within describe vitest/consistent-test-it
Expected: no warning; the describe-nested calls already use it.
Root cause
parseVitestFnCall sets name = resolved.original ?? resolved.local, and resolveScope follows const it = test.extend(...) back to the test import, keeping imported: 'test'; the rule then checks vitestFnCall.name.endsWith('it') against that resolved name. Because the resolved name is shared by every call through the binding, no choice of import origin can satisfy the rule both at top level (which wants test) and inside describe (which wants it); the invocation checks would need to consider the local binding name (head.local).
Environment
@vitest/eslint-plugin: 1.6.27
eslint: 10.8.1
vitest: 4.1.10
Related: #884 (factory-call variant), #891 (further it.extend false positives).
Description
When the result of
test.extend(...)is bound asit(the standard fixture idiom), everyit(...)call inside adescribeis reported with "Prefer using it instead of test within describe", although the callee is already spelledit. The rule compares the resolved original import name (test) and never consults the local binding name. The autofix rewritesittoit, so ESLint counts these as fixable warnings that--fixleaves unchanged.This is distinct from #884: that issue covers the report on the
.extend()factory call itself, while this one covers the reports on the extended function's invocations. A fix that skips factory calls leaves this case in place.Reproduction
eslint.config.mjs:extended-binding.test.js:Observed:
Expected: no warning; the describe-nested calls already use
it.Root cause
parseVitestFnCallsetsname = resolved.original ?? resolved.local, andresolveScopefollowsconst it = test.extend(...)back to thetestimport, keepingimported: 'test'; the rule then checksvitestFnCall.name.endsWith('it')against that resolved name. Because the resolved name is shared by every call through the binding, no choice of import origin can satisfy the rule both at top level (which wantstest) and insidedescribe(which wantsit); the invocation checks would need to consider the local binding name (head.local).Environment
@vitest/eslint-plugin: 1.6.27eslint: 10.8.1vitest: 4.1.10Related: #884 (factory-call variant), #891 (further
it.extendfalse positives).