Skip to content

Commit

Permalink
Add dark mode snapshots to storybook
Browse files Browse the repository at this point in the history
  • Loading branch information
obulat committed Sep 12, 2024
1 parent 74533ee commit 440bd40
Show file tree
Hide file tree
Showing 390 changed files with 185 additions and 74 deletions.
4 changes: 2 additions & 2 deletions frontend/.storybook/decorators/with-screenshot-area.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ export const WithScreenshotArea = (story) => {
h(
"div",
{
class: "screenshot-area",
style: "display: inline-block; padding: 2rem;",
class: "screenshot-area inline-block",
style: "padding: 2rem;",
},
[h(story())]
)
Expand Down
34 changes: 34 additions & 0 deletions frontend/.storybook/decorators/with-theme-switcher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useDarkMode } from "#imports"

import { ref, watch, onMounted, h } from "vue"

import VThemeSelect from "~/components/VThemeSelect/VThemeSelect.vue"

export const WithThemeSwitcher = (story) => {
return {
components: { story },
setup() {
const element = ref()
const { cssClass } = useDarkMode()

onMounted(() => {
watch(cssClass, async (newClass, oldClass) => {
if (element.value) {
element.value.ownerDocument
.querySelector("#storybook-root")
.classList.add("bg-default")
element.value.ownerDocument.body.classList.add(newClass)
if (oldClass) {
element.value.ownerDocument.body.classList.remove(oldClass)
}
}
})
})
return () =>
h("div", { ref: element }, [
h(story()),
h("div", { class: "absolute bottom-0" }, [h(VThemeSelect)]),
])
},
}
}
1 change: 1 addition & 0 deletions frontend/.storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const config: StorybookConfig = {
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
"@storybook/addon-themes",
],
framework: {
name: "@storybook-vue/nuxt",
Expand Down
4 changes: 3 additions & 1 deletion frontend/.storybook/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { VIEWPORTS } from "~/constants/screens"
import { WithUiStore } from "~~/.storybook/decorators/with-ui-store"
import { WithRTL } from "~~/.storybook/decorators/with-rtl"

import { WithThemeSwitcher } from "~~/.storybook/decorators/with-theme-switcher"

import type { Preview } from "@storybook/vue3"

const preview: Preview = {
decorators: [WithRTL, WithUiStore],
decorators: [WithRTL, WithUiStore, WithThemeSwitcher],
globalTypes: {
languageDirection: {
name: "RTL",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const Default: Story = {
setup() {
return () =>
h("div", { id: "teleports" }, [
h("div", { class: "fixed inset-0 w-full h-full" }, [
h("div", { class: "fixed inset-0 w-full h-full bg-default" }, [
h(VHeaderInternal, args),
]),
])
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { h } from "vue"

import { WithScreenshotArea } from "~~/.storybook/decorators/with-screenshot-area"

import VLanguageSelect from "~/components/VLanguageSelect/VLanguageSelect.vue"

import type { Meta, StoryObj } from "@storybook/vue3"

const meta = {
title: "Components/VLanguageSelect",
component: VLanguageSelect,
decorators: [WithScreenshotArea],
} satisfies Meta<typeof VLanguageSelect>

export default meta
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { h, ref } from "vue"

import { WithScreenshotArea } from "~~/.storybook/decorators/with-screenshot-area"

import VIcon from "~/components/VIcon/VIcon.vue"
import VSelectField from "~/components/VSelectField/VSelectField.vue"

Expand All @@ -21,7 +19,6 @@ const baseArgs = {
const meta = {
title: "Components/VSelectField",
component: VSelectField,
decorators: [WithScreenshotArea],

argTypes: {
"onUpdate:modelValue": {
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/meta/VButton.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { h } from "vue"
import { buttonForms, buttonSizes, buttonVariants } from "~/types/button"
import { capitalCase } from "~/utils/case"

import { WithScreenshotArea } from "~~/.storybook/decorators/with-screenshot-area"

import VButton from "~/components/VButton.vue"
import VIcon from "~/components/VIcon/VIcon.vue"

Expand All @@ -21,6 +23,7 @@ export default {
viewport: {
defaultViewport: "sm",
},
decorators: [WithScreenshotArea],
},
args: {
size: "medium",
Expand Down
27 changes: 14 additions & 13 deletions frontend/test/playwright/utils/breakpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ const themeSelectLabel = (dir: LanguageDirection) => t("theme.theme", dir)
const themeOption = (colorMode: EffectiveColorMode, dir: LanguageDirection) =>
t(`theme.choices.${colorMode}`, dir)

const turnOnDarkMode = async (page: Page, dir: LanguageDirection) => {
await page
.getByLabel(themeSelectLabel(dir))
.selectOption(themeOption("dark", dir))
}

const makeBreakpointDescribe =
(breakpoint: Breakpoint, screenWidth: number) =>
<T extends BreakpointBlock | Options>(
Expand All @@ -98,30 +104,25 @@ const makeBreakpointDescribe =
const getSnapshotName = (
name: string,
colorMode: EffectiveColorMode = "light",
dir: LanguageDirection = "ltr"
) => `${name}-${dir}-${breakpoint}-${colorMode}.png` as const
dir?: LanguageDirection
) => {
const dirString = dir ? `-${dir}` : ""
return `${name}${dirString}-${breakpoint}-${colorMode}.png` as const
}

const expectSnapshot = async <T extends ScreenshotAble>(
page: Page,
name: string,
screenshotAble: T,
{
dir = "ltr",
options,
snapshotOptions,
}: Parameters<ExpectSnapshot>[3] = { dir: "ltr" }
{ dir, options, snapshotOptions }: Parameters<ExpectSnapshot>[3] = {}
) => {
await page
.getByLabel(themeSelectLabel(dir))
.selectOption(themeOption("light", dir))
expect(await screenshotAble.screenshot(options)).toMatchSnapshot({
name: getSnapshotName(name, "light", dir),
...snapshotOptions,
})

await page
.getByLabel(themeSelectLabel(dir))
.selectOption(themeOption("dark", dir))
await turnOnDarkMode(page, dir ?? "ltr")

return expect(await screenshotAble.screenshot(options)).toMatchSnapshot(
{
name: getSnapshotName(name, "dark", dir),
Expand Down
35 changes: 32 additions & 3 deletions frontend/test/storybook/utils/expect-snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,47 @@ import {
PageScreenshotOptions,
} from "@playwright/test"

import { LanguageDirection, t } from "~~/test/playwright/utils/i18n"

export type ExpectSnapshotOptions = {
screenshotOptions: LocatorScreenshotOptions | PageScreenshotOptions
snapshotOptions: Parameters<ReturnType<Expect>["toMatchSnapshot"]>[0]
screenshotOptions?: LocatorScreenshotOptions | PageScreenshotOptions
snapshotOptions?: Parameters<ReturnType<Expect>["toMatchSnapshot"]>[0]
dir?: LanguageDirection
}
type EffectiveColorMode = "dark" | "light"
const themeSelectLabel = (dir: LanguageDirection) => t("theme.theme", dir)
const themeOption = (colorMode: EffectiveColorMode, dir: LanguageDirection) =>
t(`theme.choices.${colorMode}`, dir)

const turnOnDarkMode = async (page: Page, dir: LanguageDirection) => {
await page
.getByLabel(themeSelectLabel(dir))
.selectOption(themeOption("dark", dir))
}

export const expectSnapshot = async (
page: Page,
name: string,
locator: Locator | Page,
options?: ExpectSnapshotOptions
) => {
const snapshotName = `${name}-light.png`
expect(await locator.screenshot(options?.screenshotOptions)).toMatchSnapshot(
snapshotName,
options?.snapshotOptions
)

await turnOnDarkMode(page, options?.dir ?? "ltr")

return expect(
await locator.screenshot(options?.screenshotOptions)
).toMatchSnapshot(snapshotName, options?.snapshotOptions)
).toMatchSnapshot(`${name}-dark.png`, options?.snapshotOptions)
}

export const expectScreenshotAreaSnapshot = async (
page: Page,
name: string,
options?: ExpectSnapshotOptions
) => {
return expectSnapshot(page, name, page.locator(".screenshot-area"), options)
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions frontend/test/storybook/visual-regression/focus.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { test, Page } from "@playwright/test"

import { expectSnapshot } from "~~/test/storybook/utils/expect-snapshot"
import { expectScreenshotAreaSnapshot } from "~~/test/storybook/utils/expect-snapshot"

const goTo = async (page: Page, slug: string) => {
await page.goto(`/iframe.html?id=meta-focus--${slug}`)
Expand All @@ -22,7 +22,7 @@ test.describe("Focus", () => {
await goTo(page, slug)
await page.focus('[data-testid="focus-target"]')

await expectSnapshot(`focus-${slug}`, page.locator(".screenshot-area"))
await expectScreenshotAreaSnapshot(page, `focus-${slug}`)
})
}
})
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 16 additions & 3 deletions frontend/test/storybook/visual-regression/v-button.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,39 @@ test.describe("VButton", () => {
for (const variant of nonPressedVariants) {
test(`${variant} resting`, async ({ page }) => {
await gotoWithArgs(page, { variant })
await expectSnapshot(`${variant}-resting`, page.locator(wrapperLocator))
await expectSnapshot(
page,
`${variant}-resting`,
page.locator(wrapperLocator)
)
})

test(`${variant} hovered`, async ({ page }) => {
await gotoWithArgs(page, { variant })
await page.hover(buttonLocator)
await expectSnapshot(`${variant}-hovered`, page.locator(wrapperLocator))
await expectSnapshot(
page,
`${variant}-hovered`,
page.locator(wrapperLocator)
)
})

test(`${variant} focused`, async ({ page }) => {
await gotoWithArgs(page, { variant })
await page.focus(buttonLocator)
await expectSnapshot(`${variant}-focused`, page.locator(wrapperLocator))
await expectSnapshot(
page,
`${variant}-focused`,
page.locator(wrapperLocator)
)
})

test(`${variant} focused hovered`, async ({ page }) => {
await gotoWithArgs(page, { variant })
await page.focus(buttonLocator)
await page.hover(buttonLocator)
await expectSnapshot(
page,
`${variant}-focused-hovered`,
page.locator(wrapperLocator)
)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 13 additions & 12 deletions frontend/test/storybook/visual-regression/v-checkbox.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { test } from "@playwright/test"

import { expectSnapshot } from "~~/test/storybook/utils/expect-snapshot"
import { expectScreenshotAreaSnapshot } from "~~/test/storybook/utils/expect-snapshot"

test.describe.configure({ mode: "parallel" })

Expand All @@ -11,40 +11,41 @@ test.describe("v-checkbox", () => {
})

test("default", async ({ page }) => {
await expectSnapshot("default", page.locator(".screenshot-area"))
await expectScreenshotAreaSnapshot(page, "default")
})

test("hover", async ({ page }) => {
const checkbox = page.locator('input[type="checkbox"]')
const checkbox = page.getByRole("checkbox")
await checkbox.hover()
await expectSnapshot("hover", page.locator(".screenshot-area"))

await expectScreenshotAreaSnapshot(page, "hover")
})

test("focused", async ({ page }) => {
const checkbox = page.locator('input[type="checkbox"]')
const checkbox = page.getByRole("checkbox")
await checkbox.focus()
await expectSnapshot("focused", page.locator(".screenshot-area"))
await expectScreenshotAreaSnapshot(page, "focused")
})

test("disabled", async ({ page }) => {
const checkbox = page.locator('input[type="checkbox"]')
const checkbox = page.getByRole("checkbox")
await checkbox.evaluate((checkbox) => {
;(checkbox as HTMLInputElement).disabled = true
})
await expectSnapshot("disabled", page.locator(".screenshot-area"))
await expectScreenshotAreaSnapshot(page, "disabled")
})

test("on", async ({ page }) => {
const checkbox = page.getByRole("checkbox")
await checkbox.click()
await expectSnapshot("on", page.locator(".screenshot-area"))
await expectScreenshotAreaSnapshot(page, "on")
})

test("on focused", async ({ page }) => {
const checkbox = page.getByRole("checkbox")
await checkbox.focus()
await page.keyboard.press("Space")
await expectSnapshot("on-focused", page.locator(".screenshot-area"))
await expectScreenshotAreaSnapshot(page, "on-focused")
})

test("on disabled", async ({ page }) => {
Expand All @@ -53,15 +54,15 @@ test.describe("v-checkbox", () => {
await checkbox.evaluate((checkbox) => {
;(checkbox as HTMLInputElement).disabled = true
})
await expectSnapshot("on-disabled", page.locator(".screenshot-area"))
await expectScreenshotAreaSnapshot(page, "on-disabled")
})

test("on-and-off", async ({ page }) => {
// toggle on and off again
const checkbox = page.getByRole("checkbox")
await checkbox.click()
await checkbox.click()
await expectSnapshot("default", page.locator(".screenshot-area"))
await expectScreenshotAreaSnapshot(page, "on-and-off")
})
})
})
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import { test } from "@playwright/test"

import breakpoints from "~~/test/playwright/utils/breakpoints"
import { dirParam } from "~~/test/storybook/utils/args"

test.describe.configure({ mode: "parallel" })

test.describe("VCollectionHeader", () => {
breakpoints.describeEvery(({ expectSnapshot }) => {
for (const languageDirection of ["ltr", "rtl"]) {
test(`All headers ${languageDirection}`, async ({ page }) => {
for (const dir of ["ltr", "rtl"] as const) {
test(`All headers ${dir}`, async ({ page }) => {
await page.goto(
`/iframe.html?id=components-vcollectionheader--all-collections`
`/iframe.html?id=components-vcollectionheader--all-collections${dirParam(dir)}`
)
await expectSnapshot(
page,
`VCollectionHeaders-${languageDirection}`,
page.locator(".wrapper")
"VCollectionHeaders",
page.locator(".wrapper"),
{ dir }
)
})
}
Expand Down
Loading

0 comments on commit 440bd40

Please sign in to comment.