Ctrl K
ComunidadGuías…

tests/e2e/switch-appearance.spec.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import {
  expect,
  fulfillJson,
  mockTeamSettings,
  TEAM,
  TEAM_SETTINGS_PATH,
  test,
} from "./helpers/run-checks-fixtures";
import type { Locator } from "@playwright/test";

async function switchAppearance(control: Locator) {
  return control.evaluate((element) => {
    const canvas = document.createElement("canvas");
    canvas.width = 1;
    canvas.height = 1;
    const context = canvas.getContext("2d")!;
    const luminance = (color: string) => {
      context.clearRect(0, 0, 1, 1);
      context.fillStyle = color;
      context.fillRect(0, 0, 1, 1);
      const [red, green, blue] = context.getImageData(0, 0, 1, 1).data;
      const linear = (channel: number) => {
        const value = channel / 255;
        return value <= 0.04045
          ? value / 12.92
          : ((value + 0.055) / 1.055) ** 2.4;
      };
      return (
        0.2126 * linear(red) + 0.7152 * linear(green) + 0.0722 * linear(blue)
      );
    };
    const contrast = (first: string, second: string) => {
      const a = luminance(first);
      const b = luminance(second);
      return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
    };
    const style = getComputedStyle(element);
    const thumb = element.querySelector('[data-slot="switch-thumb"]')!;
    const secondarySurface = document.createElement("span");
    secondarySurface.style.backgroundColor = "var(--secondary)";
    element.append(secondarySurface);
    const secondaryColor = getComputedStyle(secondarySurface).backgroundColor;
    secondarySurface.style.backgroundColor = "var(--switch-on)";
    const onColor = getComputedStyle(secondarySurface).backgroundColor;
    secondarySurface.remove();
    const pageColor = getComputedStyle(document.body).backgroundColor;
    secondarySurface.style.backgroundColor = "var(--ring)";
    element.append(secondarySurface);
    const ringColor = getComputedStyle(secondarySurface).backgroundColor;
    secondarySurface.remove();
    return {
      border: style.borderColor,
      background: style.backgroundColor,
      secondaryColor,
      onColor,
      ringColor,
      thumbColor: getComputedStyle(thumb).backgroundColor,
      outlineContrast: contrast(style.borderColor, pageColor),
      thumbPageContrast: contrast(
        getComputedStyle(thumb).backgroundColor,
        pageColor
      ),
      thumbContrast: contrast(
        getComputedStyle(thumb).backgroundColor,
        style.backgroundColor
      ),
      thumbX: thumb.getBoundingClientRect().x,
      thumbRight: thumb.getBoundingClientRect().right,
      padding:
        Number.parseFloat(style.paddingRight) +
        Number.parseFloat(style.borderRightWidth),
      right: element.getBoundingClientRect().right,
    };
  });
}

for (const theme of ["light", "dark"] as const) {
  test(`${theme} switches show a grey thumb on an outlined track when off and a white thumb on green when on`, async ({
    page,
  }) => {
    await mockTeamSettings(page);
    await page.route(/\/api\/settings(?:\?.*)?$/, (route) =>
      fulfillJson(route, { default_model: null, theme })
    );
    await page.emulateMedia({ colorScheme: theme, reducedMotion: "reduce" });
    await page.addInitScript(
      (value) => localStorage.setItem("theme", value),
      theme
    );
    let enabled = false;
    await page.route(`**/api/teams/${TEAM.id}/signup-domain`, (route) => {
      if (route.request().method() === "PATCH") {
        enabled = route.request().postDataJSON().enabled;
      }
      return fulfillJson(route, {
        enabled,
        domain: "example.com",
        eligibleDomain: "example.com",
        viewer: { canManage: true },
      });
    });
    await page.goto(`${TEAM_SETTINGS_PATH}/members`);
    await expect(page.locator("html")).toHaveClass(new RegExp(theme));
    const control = page.getByRole("switch", {
      name: "Allow people from @example.com to join",
    });
    await expect(control).toBeEnabled();
    const off = await switchAppearance(control);
    expect(off.border).not.toBe("rgba(0, 0, 0, 0)");
    // The off track is deliberately quiet; the thumb carries the 3:1 contrast.
    expect(off.thumbPageContrast).toBeGreaterThanOrEqual(3);
    expect(off.background).toBe(off.secondaryColor);
    expect(off.thumbContrast).toBeGreaterThanOrEqual(3);
    await expect(control).toHaveText("");
    await control.focus();
    await expect(control).toBeFocused();
    await page.keyboard.press("Tab");
    await page.keyboard.press("Shift+Tab");
    await expect(control).toBeFocused();
    const focused = await switchAppearance(control);
    // Keyboard focus recolors the border with --ring, as before the restyle.
    expect(focused.border).toBe(focused.ringColor);
    await page.keyboard.press("Space");
    await expect(control).toBeChecked();
    await expect(control).toHaveText("");
    const on = await switchAppearance(control);
    expect(on.thumbX).toBeGreaterThan(off.thumbX + 10);
    expect(on.onColor).not.toBe("rgba(0, 0, 0, 0)");
    expect(on.background).toBe(on.onColor);
    expect(on.thumbColor).toBe("rgb(255, 255, 255)");
    expect(on.outlineContrast).toBeGreaterThanOrEqual(3);
    expect(on.thumbContrast).toBeGreaterThanOrEqual(3);
    await control.evaluate((element) => {
      element.style.width = "80px";
      element.style.height = "32px";
      element.style.padding = "4px";
    });
    const resized = await switchAppearance(control);
    expect(resized.right - resized.thumbRight).toBeCloseTo(resized.padding);
    await page.setViewportSize({ width: 390, height: 844 });
    expect((await switchAppearance(control)).right).toBeLessThanOrEqual(390);
    await page.screenshot({
      path: test.info().outputPath(`${theme}-switches.png`),
    });
  });
}