test: enforce ESLint test-quality rules and Jest coverage floors#364
Conversation
Add vitest/jest/RTL lint plugins, fix flagged tests, and align mobile and shared-tests coverage thresholds with existing Vitest discipline.
CI Coverage & Test Summary
Suites: 62 passed, 0 failed (62 total) · Tests: 658 passed, 0 failed (658 total) ✅ All reported test suites passed. Coverage artifacts: Updated at: May 23, 2026 at 2:00 PM PDT |
There was a problem hiding this comment.
Pull request overview
This PR tightens test quality enforcement across the monorepo by adding ESLint plugins/rules for Vitest/Jest/Testing Library patterns and by introducing Jest coverage floors (with platform-specific coverage exclusions) for mobile and shared-tests.
Changes:
- Add ESLint test-quality plugins/rules (Vitest, Jest, Testing Library, jest-dom) to detect skipped/focused tests, conditional expects, and async RTL anti-patterns.
- Refactor existing tests across web/mobile/shared/integration/packages to comply with the new lint rules.
- Add/adjust Jest coverage collection exclusions and enforce global coverage thresholds for mobile and shared-tests.
Reviewed changes
Copilot reviewed 27 out of 28 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/integration/marketing-email-queue.test.ts | Replaces null-error expectations with throwing on Supabase errors in integration setup/teardown. |
| tests/integration/billing-edge.test.ts | Refactors Edge integration test assertions and conditional test registration. |
| tests/integration/auth.test.ts | Refactors conditional expect logic in auth integration tests to satisfy lint rules. |
| tests/integration/auth-rls.test.ts | Refactors RLS integration assertions (includes a logic change that affects correctness). |
| packages/shared-tests/jest.web.cjs | Adds web coverage exclusions for native-only shared code + sets global coverage threshold. |
| packages/shared-tests/jest.native.cjs | Adds native coverage exclusions for web-only shared code + sets global coverage threshold. |
| packages/shared-tests/tests/validation/profileSchema.test.ts | Adds helper to avoid conditional expects in schema validation tests. |
| packages/shared-tests/tests/hooks/useAvatarUpload.coverage.test.ts | Updates coverage-gap tests to satisfy expect-expect and remove try/catch swallowing. |
| packages/shared-tests/tests/hooks/useAuth.native.test.ts | Refactors error assertions to avoid conditional expects. |
| packages/shared-tests/tests/components/profile/ProfileEditor.test.tsx | Removes waitFor side-effects pattern in favor of explicit waits + assertions. |
| packages/shared-tests/tests/components/profile/ProfileEditor.native.test.tsx | Same as web: refactors waitFor usage to avoid side-effects. |
| packages/shared-tests/tests/components/navigation/UserMenu.native.test.tsx | Converts “findByText only” usage into an explicit assertion to satisfy linting. |
| packages/shared-tests/tests/components/navigation/UserMenu.native.coverage.test.tsx | Same as above for coverage-gap suite. |
| packages/shared-tests/tests/components/forms/FormInput.test.tsx | Uses jest-dom matchers (toBeDisabled/toBeRequired) per new lint rules. |
| packages/shared-tests/tests/components/forms/FormButton.test.tsx | Uses jest-dom matchers (toBeDisabled/toBeEnabled) per new lint rules. |
| packages/marketing-email/src/tests/kitClient.test.ts | Expands/clarifies kit client tests and adds new error-message case. |
| packages/marketing-email/src/tests/kitAdapter.test.ts | Refactors error assertions to avoid conditional expects and ensure assertions always run. |
| packages/billing/src/BillingProvider.test.tsx | Adds an assertion to prevent late async work after unmount. |
| package.json | Adds ESLint plugins for test-quality enforcement. |
| package-lock.json | Locks new ESLint plugin dependencies (and transitive updates). |
| apps/web/src/pages/tests/DashboardPage.test.tsx | Simplifies user-menu querying and sign-out assertions. |
| apps/web/src/lib/supabase.test.ts | Converts manual runtime skip logic to Vitest it.skipIf. |
| apps/web/src/components/dashboard/tests/CollectionDetail.test.tsx | Switches to toBeEnabled matcher. |
| apps/web/src/components/billing/tests/PlanCard.web.test.tsx | Switches to toBeEnabled matcher. |
| apps/web/src/components/tests/SocialLoginButton.test.tsx | Switches to toBeEnabled matcher. |
| apps/mobile/package.json | Adds Jest global coverageThreshold floors for the mobile app. |
| apps/mobile/tests/screens/SignupScreen.test.tsx | Refactors waitFor usage to avoid side-effects and satisfy lint rules. |
| .eslintrc.js | Adds targeted overrides for Vitest/Jest/Testing Library/jest-dom test-quality rules. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Align CI merged coverage totals with local npm run test:coverage by running test:coverage:logger in the matrix and restoring its artifact.
Last deployed: 14:08 PDT 📱 Mobile preview: Channel 📱 Mobile Preview BuildsNative builds are available for download: iOS Simulator Build:
Android Build (Device & Emulator):
Note: These builds include the preview Supabase configuration and are ready to use. 📖 See Mobile Build Testing Guide for detailed instructions. |
…pass. Separate shared coverage outputs per platform and merge them so CI reports both web and native shared code instead of native overwriting web results.
…tests. Copilot review: !== undefined treated null success responses as errors.
Guard source-map spreads with nullish coalescing, add regression coverage, and register the merge test in test:unit:scripts.
Integration suite lives in supabase-tests, but tests/integration/** only set app_code so run_supabase stayed false on test-only PR pushes.
Refactor aggregation/derived-flag logic so --self-test verifies integration-only paths trigger Supabase CI without preview reset.
Align engines, docs, and CI setup-node with eslint-visitor-keys@5 and existing Node 20 CI; add .nvmrc for local development.
Summary
Test plan
npm run lintandnpm run lint:repo