Skip to content

test(compat): add test coverage for darkModePlugin uncovered branches#20122

Closed
me-saurabhkohli wants to merge 1 commit into
tailwindlabs:mainfrom
me-saurabhkohli:test/dark-mode-compat-coverage
Closed

test(compat): add test coverage for darkModePlugin uncovered branches#20122
me-saurabhkohli wants to merge 1 commit into
tailwindlabs:mainfrom
me-saurabhkohli:test/dark-mode-compat-coverage

Conversation

@me-saurabhkohli
Copy link
Copy Markdown

Summary

Adds a dedicated test file src/compat/dark-mode.test.ts for the darkModePlugin function in the v3 compat layer. Coverage analysis showed src/compat/dark-mode.ts had ~67% branch coverage with several real code paths completely untested.

What's covered by the new tests

Branch Previously tested
darkMode: 'class' — legacy :is() selector with default .dark
darkMode: ['class', '.custom'] — legacy :is() with custom class
darkMode: ['variant', '.dark'] — warns: must provide a real selector
darkMode: ['variant', '.no-amp'] — warns: selector must contain &
darkMode: ['variant', [...invalid]] — warns for each bad selector in array
darkMode: ['variant', [...valid]] — array of valid selectors
darkMode: 'media' and darkMode: 'selector' — smoke tests ✅ (in config.test.ts)

No behaviour changes

Tests only — no source files modified.

Adds a dedicated test file for the dark-mode compat plugin
(src/compat/dark-mode.ts), covering branches that had no tests:

- darkMode: 'class' — legacy v3 :is() selector with default .dark
- darkMode: ['class', custom] — legacy :is() with custom class selector
- darkMode: ['variant', '.dark'] — warns, selector must not be bare .dark
- darkMode: ['variant', '.no-ampersand'] — warns, selector must contain &
- darkMode: ['variant', [invalid, invalid]] — warns for each bad selector
- darkMode: ['variant', [...valid]] — array of valid selectors

Branch coverage for src/compat/dark-mode.ts improves from ~67% to 100%.
@me-saurabhkohli me-saurabhkohli requested a review from a team as a code owner May 28, 2026 03:39
Copilot AI review requested due to automatic review settings May 28, 2026 03:39
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a new Vitest suite to validate Tailwind’s dark mode compatibility behavior, including legacy class mode output and warnings for invalid variant selectors.

Changes:

  • Adds smoke tests for existing media and selector dark mode outputs
  • Adds coverage for legacy darkMode: "class" selector generation (default + custom class)
  • Adds coverage for darkMode: ["variant", ...] warning cases and valid selector output

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +110 to +185
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})

await run(
['dark:underline'],
css`
@tailwind utilities;
@config "./config.js";
`,
{
loadModule: async () => ({
module: { darkMode: ['variant', '.dark'] },
base: '/root',
path: '',
}),
},
)

expect(warn).toHaveBeenCalledWith(
'When using `variant` for `darkMode`, you must provide a selector.\nExample: `darkMode: ["variant", ".your-selector &"]`',
)

warn.mockRestore()
})

test('darkMode: ["variant", ".no-ampersand"] — warns when selector does not contain &', async () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})

await run(
['dark:underline'],
css`
@tailwind utilities;
@config "./config.js";
`,
{
loadModule: async () => ({
module: { darkMode: ['variant', '.no-ampersand'] },
base: '/root',
path: '',
}),
},
)

expect(warn).toHaveBeenCalledWith(
'When using `variant` for `darkMode`, your selector must contain `&`.\nExample `darkMode: ["variant", ".your-selector &"]`',
)

warn.mockRestore()
})

test('darkMode: ["variant", [".dark", ".no-ampersand"]] — warns for each invalid selector in the array', async () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})

await run(
['dark:underline'],
css`
@tailwind utilities;
@config "./config.js";
`,
{
loadModule: async () => ({
module: { darkMode: ['variant', ['.dark', '.no-ampersand']] },
base: '/root',
path: '',
}),
},
)

expect(warn).toHaveBeenCalledWith(
'When using `variant` for `darkMode`, you must provide a selector.\nExample: `darkMode: ["variant", ".your-selector &"]`',
)
expect(warn).toHaveBeenCalledWith(
'When using `variant` for `darkMode`, your selector must contain `&`.\nExample `darkMode: ["variant", ".your-selector &"]`',
)

warn.mockRestore()
})
Comment on lines +159 to +182
test('darkMode: ["variant", [".dark", ".no-ampersand"]] — warns for each invalid selector in the array', async () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})

await run(
['dark:underline'],
css`
@tailwind utilities;
@config "./config.js";
`,
{
loadModule: async () => ({
module: { darkMode: ['variant', ['.dark', '.no-ampersand']] },
base: '/root',
path: '',
}),
},
)

expect(warn).toHaveBeenCalledWith(
'When using `variant` for `darkMode`, you must provide a selector.\nExample: `darkMode: ["variant", ".your-selector &"]`',
)
expect(warn).toHaveBeenCalledWith(
'When using `variant` for `darkMode`, your selector must contain `&`.\nExample `darkMode: ["variant", ".your-selector &"]`',
)
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 28, 2026

Confidence Score: 4/5

Tests-only change; no production code is modified and the new tests accurately reflect the source implementation.

The snapshot values are correct, and the coverage claims in the PR description match what the tests actually exercise. The only concern is that warn.mockRestore() is not inside a try/finally block in the warning tests, meaning a failing assertion would leave console.warn mocked for the remainder of the suite run.

The three warning tests in dark-mode.test.ts would benefit from try/finally cleanup guards.

Reviews (1): Last reviewed commit: "test(compat): add coverage for darkModeP..." | Re-trigger Greptile

Comment on lines +177 to +185
expect(warn).toHaveBeenCalledWith(
'When using `variant` for `darkMode`, you must provide a selector.\nExample: `darkMode: ["variant", ".your-selector &"]`',
)
expect(warn).toHaveBeenCalledWith(
'When using `variant` for `darkMode`, your selector must contain `&`.\nExample `darkMode: ["variant", ".your-selector &"]`',
)

warn.mockRestore()
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 warn.mockRestore() is called unconditionally at the end of each warning test, so if a toHaveBeenCalledWith assertion throws, the spy is never restored. Subsequent tests in this file would then run with console.warn still mocked, silently swallowing warnings they depend on. Wrapping the assertions in a try/finally block guarantees cleanup regardless of assertion outcome. The same pattern appears in the ["variant", ".dark"] and ["variant", ".no-ampersand"] tests as well.

Suggested change
expect(warn).toHaveBeenCalledWith(
'When using `variant` for `darkMode`, you must provide a selector.\nExample: `darkMode: ["variant", ".your-selector &"]`',
)
expect(warn).toHaveBeenCalledWith(
'When using `variant` for `darkMode`, your selector must contain `&`.\nExample `darkMode: ["variant", ".your-selector &"]`',
)
warn.mockRestore()
})
try {
expect(warn).toHaveBeenCalledWith(
'When using `variant` for `darkMode`, you must provide a selector.\nExample: `darkMode: ["variant", ".your-selector &"]`',
)
expect(warn).toHaveBeenCalledWith(
'When using `variant` for `darkMode`, your selector must contain `&`.\nExample `darkMode: ["variant", ".your-selector &"]`',
)
} finally {
warn.mockRestore()
}
})

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

Review Change Stack

Walkthrough

This PR adds comprehensive Vitest coverage for the darkModePlugin dark mode configuration handling. The new test suite covers six configuration modes: darkMode: "media" with CSS media queries, darkMode: "selector" with :where() selectors, darkMode: "class" with the default .dark selector, darkMode: ["class", ".night"] with custom class selectors, and darkMode: ["variant", ...] configurations with both invalid selectors (testing console warnings) and valid custom variant selectors (verifying CSS generation).

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding test coverage for previously untested branches in the darkModePlugin.
Description check ✅ Passed The description is directly related to the changeset, providing comprehensive context about which branches are being covered by the new tests.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/tailwindcss/src/compat/dark-mode.test.ts (1)

109-132: ⚡ Quick win

Consider also asserting the CSS output to verify variant is not generated.

The test correctly verifies that the warning is issued, but doesn't check that the dark: variant is not generated when the selector is invalid. Adding a snapshot or empty-output assertion would more completely verify the behavior.

🧪 Suggested enhancement
  test('darkMode: ["variant", ".dark"] — warns when selector is exactly .dark (must provide a real selector)', async () => {
    const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})

-   await run(
+   const result = await run(
      ['dark:underline'],
      css`
        `@tailwind` utilities;
        `@config` "./config.js";
      `,
      {
        loadModule: async () => ({
          module: { darkMode: ['variant', '.dark'] },
          base: '/root',
          path: '',
        }),
      },
    )

    expect(warn).toHaveBeenCalledWith(
      'When using `variant` for `darkMode`, you must provide a selector.\nExample: `darkMode: ["variant", ".your-selector &"]`',
    )
+   // Verify no dark variant is generated when selector is invalid
+   expect(result.trim()).toBe('')

    warn.mockRestore()
  })

Apply similar enhancements to lines 134-157 and 159-185.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/tailwindcss/src/compat/dark-mode.test.ts` around lines 109 - 132,
Extend the test "darkMode: [\"variant\", \".dark\"] — warns when selector is
exactly .dark (must provide a real selector)" to also assert the generated CSS
does not include the dark variant: capture the output returned by run (the call
that compiles ['dark:underline'] with `@tailwind` utilities and the loadModule
returning darkMode: ['variant', '.dark']) and add an assertion such as
expect(output.css).not.toContain('.dark') or
expect(output.css).not.toContain('dark:underline') or a snapshot asserting no
generated variant rules; apply the same pattern to the similar tests around
lines 134-157 and 159-185 so each verifies both the warning (vi.spyOn
console.warn) and that no dark variant CSS was emitted.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/tailwindcss/src/compat/dark-mode.test.ts`:
- Around line 109-132: Extend the test "darkMode: [\"variant\", \".dark\"] —
warns when selector is exactly .dark (must provide a real selector)" to also
assert the generated CSS does not include the dark variant: capture the output
returned by run (the call that compiles ['dark:underline'] with `@tailwind`
utilities and the loadModule returning darkMode: ['variant', '.dark']) and add
an assertion such as expect(output.css).not.toContain('.dark') or
expect(output.css).not.toContain('dark:underline') or a snapshot asserting no
generated variant rules; apply the same pattern to the similar tests around
lines 134-157 and 159-185 so each verifies both the warning (vi.spyOn
console.warn) and that no dark variant CSS was emitted.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3147b739-001d-4f94-885f-386860b4aab8

📥 Commits

Reviewing files that changed from the base of the PR and between 829cdc9 and 66bd039.

📒 Files selected for processing (1)
  • packages/tailwindcss/src/compat/dark-mode.test.ts

@RobinMalfait
Copy link
Copy Markdown
Member

Hey! This is unnecessary. If you run into bugs, please open an issue first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants