JS-1784 Fix S2699 false positive for uvu/assert and expect.poll#7511
Conversation
Tests cover uvu/assert whitelisted methods and Playwright expect.poll matcher chains being treated as assertions. They also verify bare expect.poll and Cypress query-only chains remain noncompliant. Relates to JS-1784
Recognize documented uvu/assert assertion methods and Playwright expect.poll(...).matcher() chains, including renamed Playwright expect imports, when S2699 scans test callbacks for assertions. The implementation follows the approved proposal by keeping Cypress query chains and bare expect.poll calls non-asserting, using the existing FQN helpers, and documenting uvu/assert in rspec. Relates to JS-1784
Rule Profile
test('has no assertions', () => {
const x = 1 + 2;
});False Positive PatternS2699 was reporting tests that do contain real assertions because the shared assertion detector did not recognize test('ChatwootPlugin exposes getApi()', () => {
assert.instance(createChatwootPlugin(MOCK_CONFIG).getApi(), ChatwootApi)
})test('attach() registers webhook when webhookUrl is configured', async () => {
const { mock, calls } = makeSmartFetch()
const plugin = createChatwootPlugin({ ...MOCK_CONFIG, webhookUrl: 'https://bot.example.com/chatwoot' })
const bot = makeMockBot()
await withFetch(mock, () => plugin.attach(bot as any))
assert.ok(
calls.some((c) => c.startsWith('POST') && c.includes('/webhooks')),
'POST /webhooks was called to register the webhook'
)
})require('@playwright/test').expect.poll(() => 'ready').toBe('ready');False Negative RiskThe risk is bounded by explicit call-shape and library checks. Fix SummaryThe implementation extends the existing assertion-detection layer instead of adding a separate S2699 path. It adds
|
Ruling ReportCode no longer flagged (2 issues)S6551vitest/packages/vitest/src/node/cli/cli-config.ts:785 783 | if (typeof value !== 'object') {
784 | throw new TypeError(
> 785 | `Unexpected value for --expect.poll: ${value}. If you need to configure timeout, use --expect.poll.timeout=<timeout>`,
786 | )
787 | }vitest/packages/vitest/src/node/cli/cli-config.ts:795 793 | if (typeof value !== 'object') {
794 | throw new TypeError(
> 795 | `Unexpected value for --expect: ${value}. If you need to configure expect options, use --expect.{name}=<value> syntax`,
796 | )
797 | }New issues flagged (2 issues)S8982vuetify/packages/docs/src/components/app/search/SearchResults.vue:12 10 | />
11 |
> 12 | <div class="text-high-emphasis font-weight-black text-uppercase">
13 | {{ group.name }}
14 | </div>S8984vuetify/packages/docs/src/components/app/search/SearchResults.vue:7 5 | <v-list ref="rootEl" density="compact" nav bg-color="transparent">
6 | <template v-for="(group, i) in props.groups">
> 7 | <v-divider
8 | v-if="i !== 0"
9 | class="mb-2 mt-2 ms-2 me-n2"Ruling passed with these expected-result updates already present in the branch. No fix PR was needed. |
|
Improvement request: please extend the new Playwright require('@playwright/test').expect.poll(() => 'ready').toBe('ready');I checked the helper behavior on that AST shape: Please add coverage for the direct-require form and either accept both Playwright FQN spellings ( |
Comment: Improvement request: please extend the new Playwright `expect.poll` detection to handle direct CommonJS require chains, for example:
```js
require('@playwright/test').expect.poll(() => 'ready').toBe('ready');
```
I checked the helper behavior on that AST shape: `getFullyQualifiedName(context, innerPollCall)` resolves it as `@playwright/test.expect.poll`, while `getFullyQualifiedName(context, innerPollCall.callee)` returns `null`. The current implementation compares `getFullyQualifiedName(context, callee)` with the dotted Playwright import FQN and only falls back for bare `expect.poll`, so this direct-require form can still leave S2699 reporting the test as assertion-less.
Please add coverage for the direct-require form and either accept both Playwright FQN spellings (`@playwright.test.expect.poll` and `@playwright/test.expect.poll`) or normalize the module name before comparison.
S2699 is a native rule and does not appear in the external/decorated ESLint rule tables, so this PR should introduce no README changes. Revert the drifted external-rule rows to match master per repo guidance on not committing unrelated regenerated metadata. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|




Relates to JS-1784
S2699 now recognizes the remaining documented
uvu/assertassertion methods and Playwrightexpect.poll(...).matcher()chains that were previously reported as assertion-less tests.uvu/assertbounded to its documented method whitelist.expect.pollforms.expect.poll(...)and query-only Cypress chains.