Skip to content

[Bug]: reducedMotion: reduce is not respected in UI mode preview #40772

@jsnajdr

Description

@jsnajdr

Version

1.59.1

Steps to reproduce

Run this test file that loads a document and performs two tests on it, in UI mode with --ui:

import { test, expect } from "@playwright/test";

const html = `<!DOCTYPE html>
<title>Reduced Motion Test</title>
<style>
  button { font-size: 100px }
  body { background: green }
  #prefers-yes { display: none }
  #prefers-not { display: inline }
  @media (prefers-reduced-motion: reduce) {
    body { background: blue }
    #prefers-yes { display: inline }
    #prefers-not { display: none }
  }
</style>
<button id="prefers-yes">Prefers yes</button>
<button id="prefers-not">Prefers not</button>`;

test.describe("default", () => {
  test("'Prefers not' is visible, 'Prefers yes' is hidden", async ({ page }) => {
    await page.setContent(html);
    const matches = await page.evaluate(() =>
      window.matchMedia("(prefers-reduced-motion: reduce)").matches
    );
    expect(matches).toBe(false);
    await expect(page.locator("#prefers-not")).toBeVisible();
    await expect(page.locator("#prefers-yes")).toBeHidden();
  });
});

test.describe("reducedMotion", () => {
  test.use({ contextOptions: { reducedMotion: "reduce" } });

  test("'Prefers yes' is visible, 'Prefers not' is hidden", async ({ page }) => {
    await page.setContent(html);
    const matches = await page.evaluate(() =>
      window.matchMedia("(prefers-reduced-motion: reduce)").matches
    );
    expect(matches).toBe(true);
    await expect(page.locator("#prefers-yes")).toBeVisible();
    await expect(page.locator("#prefers-not")).toBeHidden();
  });
});

Expected behavior

When in the UI mode and inspecting the results of the reducedMotion: true test, the browser screen should be a truthful representation of the UI: background should be blue, and the "Prefers yes" button should be visible.

Actual behavior

The browser screen is displayed as if reducedMotion was false. The background is green instead of blue, and the "Prefers not" button is visible:

Image

The actual tests succeed. The assertions that "Prefers yes" is visible and "Prefers not" is hidden are true. Even the screenshot in the top timeline slide is right. Even tests in the --headed mode succeed, there is a browser window displayed for a brief moment with the right rendering. Only the --ui mode preview is wrong. A trace file saved by a CI run will also display wrong preview.

I found this bug when debugging a flaky test that's possibly caused by an animation running despite being gated by a media query and reducedMotion: 'reduce' enabled in config. So I suspect that the wrong behavior sometimes leaks also into the actual test run, but can't prove it.

Additional context

No response

Environment

System:
    OS: macOS 26.4.1
    CPU: (12) arm64 Apple M2 Max
    Memory: 1.55 GB / 32.00 GB
  Binaries:
    Node: 20.20.2 - ~/.nvm/versions/node/v20.20.2/bin/node
    npm: 10.8.2 - ~/.nvm/versions/node/v20.20.2/bin/npm
    Deno: 2.7.13 - /opt/homebrew/bin/deno
  IDEs:
    Cursor: 3.3.30 - /usr/local/bin/cursor
  Languages:
    Bash: 3.2.57 - /bin/bash
  npmPackages:
    @playwright/test: ^1.59.1 => 1.59.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions