Merged in chore/fix-tests (pull request #3430)

Chore/fix tests

* chore: Upgrade nextjs@16.1.1

* chore: upgrade next@16.1.1

* upgrade underlying types

* merge

* Fix broken tests

* bump @swc/plugin-formatjs to latest version

* bump sentry

* transpile "import-in-the-middle" & "require-in-the-middle"

* revert next@16.1.1 upgrade

* revert transpilation addition

* .
This commit is contained in:
Joakim Jäderberg
2026-01-13 13:48:06 +00:00
parent dba4c81618
commit d284e82828
15 changed files with 334 additions and 157 deletions

View File

@@ -27,7 +27,7 @@
"@scandic-hotels/design-system": "workspace:*",
"@scandic-hotels/tracking": "workspace:*",
"@scandic-hotels/trpc": "workspace:*",
"@sentry/nextjs": "^10.26.0",
"@sentry/nextjs": "^10.33.0",
"@swc/plugin-formatjs": "^3.2.2",
"@tanstack/react-query": "^5.75.5",
"@tanstack/react-query-devtools": "^5.75.5",
@@ -45,7 +45,6 @@
"@playwright/test": "^1.53.1",
"@scandic-hotels/common": "workspace:*",
"@scandic-hotels/typescript-config": "workspace:*",
"@swc/plugin-formatjs": "^3.2.2",
"@types/node": "^20",
"@types/react": "19.2.7",
"@types/react-dom": "19.2.3",

View File

@@ -38,7 +38,7 @@
"@scandic-hotels/design-system": "workspace:*",
"@scandic-hotels/tracking": "workspace:*",
"@scandic-hotels/trpc": "workspace:*",
"@sentry/nextjs": "^10.26.0",
"@sentry/nextjs": "^10.33.0",
"@swc/plugin-formatjs": "^3.2.2",
"@t3-oss/env-nextjs": "^0.13.4",
"@tanstack/react-query": "^5.75.5",

View File

@@ -40,7 +40,8 @@ export const Default: Story = {
ariaRole: "alert",
},
play: async ({ canvas }) => {
canvas.findByRole("alert")
const alert = await canvas.findByRole("alert")
expect(alert).toBeVisible()
},
}

View File

@@ -560,8 +560,8 @@ export const TextWithIcon: Story = {
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
expect(canvas.getByText("Text with icon")).toBeDefined()
expect(canvas.getByTestId("MaterialIcon")).toBeDefined()
expect(await canvas.findByText("Text with icon")).toBeDefined()
expect(await canvas.findByTestId("MaterialIcon")).toBeDefined()
},
}
@@ -575,7 +575,7 @@ export const TextWithIconInverted: Story = {
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
expect(canvas.getByText("Text with icon")).toBeDefined()
expect(canvas.getByTestId("MaterialIcon")).toBeDefined()
expect(await canvas.findByText("Text with icon")).toBeDefined()
expect(await canvas.findByTestId("MaterialIcon")).toBeDefined()
},
}

View File

@@ -46,9 +46,8 @@ export const Default: Story = {
href: "#",
children: "Button link",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -59,9 +58,8 @@ export const PrimaryLarge: Story = {
variant: "Primary",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -71,9 +69,8 @@ export const PrimaryMedium: Story = {
...PrimaryLarge.args,
size: "md",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -83,9 +80,8 @@ export const PrimarySmall: Story = {
...PrimaryLarge.args,
size: "sm",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -97,9 +93,8 @@ export const PrimaryOnDarkBackground: Story = {
variant: "Primary",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -113,9 +108,8 @@ export const PrimaryInvertedLarge: Story = {
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -126,9 +120,8 @@ export const PrimaryInvertedMedium: Story = {
...PrimaryInvertedLarge.args,
size: "md",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -139,9 +132,8 @@ export const PrimaryInvertedSmall: Story = {
...PrimaryInvertedLarge.args,
size: "sm",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -152,9 +144,8 @@ export const SecondaryLarge: Story = {
variant: "Secondary",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -164,9 +155,8 @@ export const SecondaryMedium: Story = {
...SecondaryLarge.args,
size: "md",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -176,9 +166,8 @@ export const SecondarySmall: Story = {
...SecondaryLarge.args,
size: "sm",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -191,9 +180,8 @@ export const SecondaryInvertedLarge: Story = {
color: "Inverted",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -204,9 +192,8 @@ export const SecondaryInvertedMedium: Story = {
...SecondaryInvertedLarge.args,
size: "md",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -217,9 +204,8 @@ export const SecondaryInvertedSmall: Story = {
...SecondaryInvertedLarge.args,
size: "sm",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -230,9 +216,8 @@ export const TertiaryLarge: Story = {
variant: "Tertiary",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -242,9 +227,8 @@ export const TertiaryMedium: Story = {
...TertiaryLarge.args,
size: "md",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -254,9 +238,8 @@ export const TertiarySmall: Story = {
...TertiaryLarge.args,
size: "sm",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -267,9 +250,8 @@ export const TextLarge: Story = {
variant: "Text",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -279,9 +261,8 @@ export const TextMedium: Story = {
...TextLarge.args,
size: "md",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -291,9 +272,8 @@ export const TextSmall: Story = {
...TextLarge.args,
size: "sm",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -304,9 +284,8 @@ export const TextNoWrapping: Story = {
children: "Text button with wrapping false",
wrapping: false,
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -319,9 +298,8 @@ export const TextInvertedLarge: Story = {
color: "Inverted",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -332,9 +310,8 @@ export const TextInvertedMedium: Story = {
...TextInvertedLarge.args,
size: "md",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -345,9 +322,8 @@ export const TextInvertedSmall: Story = {
...TextInvertedLarge.args,
size: "sm",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -359,9 +335,8 @@ export const TextWithIcon: Story = {
children: "Text with icon",
trailingIconName: "chevron_right",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link", { name: /Text with icon/i })
expect(link).toBeInTheDocument()
},
}
@@ -372,9 +347,8 @@ export const TextWithIconInverted: Story = {
...TextWithIcon.args,
color: "Inverted",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}

View File

@@ -116,7 +116,7 @@ export const Default: Story = {
iconName: "search",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -268,7 +268,7 @@ export const Filled: Story = {
variant: "Filled",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -279,7 +279,7 @@ export const FilledDisabled: Story = {
isDisabled: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -290,7 +290,7 @@ export const FilledOnDarkBackground: Story = {
...Filled.args,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -302,7 +302,7 @@ export const FilledWithEmphasis: Story = {
emphasis: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -313,7 +313,7 @@ export const FilledWithEmphasisDisabled: Story = {
isDisabled: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -325,7 +325,7 @@ export const Outlined: Story = {
variant: "Outlined",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -336,7 +336,7 @@ export const OutlinedDisabled: Story = {
isDisabled: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -348,7 +348,7 @@ export const Elevated: Story = {
variant: "Elevated",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -359,7 +359,7 @@ export const ElevatedDisabled: Story = {
isDisabled: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -372,7 +372,7 @@ export const Faded: Story = {
variant: "Faded",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -384,7 +384,7 @@ export const FadedDisabled: Story = {
isDisabled: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -397,7 +397,7 @@ export const Muted: Story = {
variant: "Muted",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -409,7 +409,7 @@ export const MutedDisabled: Story = {
isDisabled: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -420,7 +420,7 @@ export const MutedWithEmphasis: Story = {
emphasis: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -431,7 +431,7 @@ export const MutedWithEmphasisDisabled: Story = {
isDisabled: true,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}

View File

@@ -52,7 +52,12 @@ export function MaterialIcon({
const iconClassName = iconVariants({ color })
return (
<span className={`${styles.iconWrapper}`} {...props}>
<span
data-testid="MaterialIcon"
data-icon-name={icon}
className={`${styles.iconWrapper}`}
{...props}
>
<IconComponent
width={size}
height={size}

View File

@@ -115,7 +115,6 @@ const meta: Meta<typeof InfoCard> = {
style={{ display: "grid", gap: "1rem" }}
>
{Object.keys(infoCardConfig.variants.theme).map((theme) => {
console.log(theme)
const args = {
...context.args,
backgroundImage:

View File

@@ -71,35 +71,37 @@ describe("Input", () => {
expect(screen.queryByLabelText("Clear content")).toBeNull()
})
it("does not show clear button when input is empty", () => {
it("does not show clear button when input is empty", async () => {
renderInput({
label: "Email",
value: "",
onChange: vi.fn(),
showClearContentIcon: true,
})
expect(await screen.findByRole("textbox")).toBeTruthy()
expect(screen.queryByLabelText("Clear content")).toBeNull()
})
it("shows clear button when input has value and showClearContentIcon is true", () => {
it("shows clear button when input has value and showClearContentIcon is true", async () => {
renderInput({
label: "Email",
value: "test",
onChange: vi.fn(),
showClearContentIcon: true,
})
expect(screen.getByLabelText("Clear content")).toBeTruthy()
expect(await screen.findByLabelText("Clear content")).toBeTruthy()
})
})
describe("icons", () => {
it("renders left icon when provided", () => {
it("renders left icon when provided", async () => {
renderInput({
label: "Search",
// eslint-disable-next-line formatjs/no-literal-string-in-jsx
leftIcon: <span data-testid="left-icon">🔍</span>,
})
expect(screen.getByTestId("left-icon")).toBeTruthy()
expect(await screen.findByTestId("left-icon")).toBeTruthy()
})
it("renders right icon when provided", () => {
@@ -111,7 +113,7 @@ describe("Input", () => {
expect(screen.getByTestId("right-icon")).toBeTruthy()
})
it("hides right icon when clear button is shown", () => {
it("hides right icon when clear button is shown", async () => {
renderInput({
label: "Email",
value: "test",
@@ -120,8 +122,8 @@ describe("Input", () => {
// eslint-disable-next-line formatjs/no-literal-string-in-jsx
rightIcon: <span data-testid="right-icon">👁</span>,
})
expect(await screen.findByLabelText("Clear content")).toBeTruthy()
expect(screen.queryByTestId("right-icon")).toBeNull()
expect(screen.getByLabelText("Clear content")).toBeTruthy()
})
it("shows right icon when clear button condition not met", () => {

View File

@@ -39,39 +39,43 @@ const renderPasswordInput = (
describe("PasswordInput", () => {
describe("rendering", () => {
it("renders with default password label", () => {
it("renders with default password label", async () => {
renderPasswordInput()
expect(screen.getByLabelText("Password")).toBeTruthy()
expect(await screen.findByLabelText("Password")).toBeTruthy()
})
it("renders with custom label", () => {
it("renders with custom label", async () => {
renderPasswordInput({ label: "Enter your password" })
expect(screen.getByLabelText("Enter your password")).toBeTruthy()
expect(await screen.findByLabelText("Enter your password")).toBeTruthy()
})
it("renders with new password label when isNewPassword is true", () => {
it("renders with new password label when isNewPassword is true", async () => {
renderPasswordInput({ isNewPassword: true })
expect(screen.getByLabelText("New password")).toBeTruthy()
expect(await screen.findByLabelText("New password")).toBeTruthy()
})
})
describe("visibility toggle", () => {
it("shows visibility toggle button by default", () => {
it("shows visibility toggle button by default", async () => {
renderPasswordInput()
expect(screen.getByLabelText("Show password")).toBeTruthy()
expect(await screen.findByLabelText("Show password")).toBeTruthy()
})
it("hides visibility toggle when visibilityToggleable is false", () => {
it("hides visibility toggle when visibilityToggleable is false", async () => {
renderPasswordInput({ visibilityToggleable: false })
expect(await screen.findByLabelText("Password")).toBeTruthy()
expect(screen.queryByLabelText("Show password")).toBeNull()
expect(screen.queryByLabelText("Hide password")).toBeNull()
})
})
describe("disabled state", () => {
it("disables the input when disabled prop is true", () => {
it("disables the input when disabled prop is true", async () => {
renderPasswordInput({ disabled: true })
expect(screen.getByLabelText("Password")).toHaveProperty("disabled", true)
expect(await screen.findByLabelText("Password")).toHaveProperty(
"disabled",
true
)
})
})
@@ -80,7 +84,7 @@ describe("PasswordInput", () => {
const user = userEvent.setup()
renderPasswordInput()
const input = screen.getByLabelText("Password")
const input = await screen.findByLabelText("Password")
await user.type(input, "secret123")
expect(input).toHaveProperty("value", "secret123")
@@ -90,7 +94,7 @@ describe("PasswordInput", () => {
const user = userEvent.setup()
renderPasswordInput({ name: "confirmPassword" }, { confirmPassword: "" })
const input = screen.getByLabelText("Password")
const input = await screen.findByLabelText("Password")
await user.type(input, "test")
expect(input).toHaveProperty("value", "test")

View File

@@ -39,9 +39,8 @@ export const Default: Story = {
href: "https://www.scandichotels.com/en",
},
render: (args) => <TextLink {...args}>Default link</TextLink>,
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -52,9 +51,8 @@ export const Inverted: Story = {
theme: "Inverted",
},
render: (args) => <TextLink {...args}>Inverted link</TextLink>,
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -65,9 +63,8 @@ export const Disabled: Story = {
isDisabled: true,
},
render: (args) => <TextLink {...args}>Disabled link</TextLink>,
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -82,9 +79,8 @@ export const WithIcon: Story = {
<MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
</TextLink>
),
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -95,9 +91,8 @@ export const Small: Story = {
typography: "Link/sm",
},
render: (args) => <TextLink {...args}>Small link</TextLink>,
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -113,9 +108,8 @@ export const SmallWithIcon: Story = {
<MaterialIcon icon="arrow_forward" size={20} color="CurrentColor" />
</TextLink>
),
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}
@@ -135,9 +129,8 @@ export const Inline: Story = {
</p>
</Typography>
),
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
play: async ({ canvas }) => {
const link = await canvas.findByRole("link")
expect(link).toBeInTheDocument()
},
}

View File

@@ -1,7 +1,7 @@
import { Toast } from "./Toast"
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { expect } from "storybook/test"
import { expect, within } from "storybook/test"
import { config } from "./variants.ts"
@@ -52,7 +52,7 @@ export const DefaultWithCustomContent: Story = {
play: async ({ canvas }) => {
const toast = await canvas.findByRole("status")
expect(toast).toBeVisible()
expect(canvas.getByText("This is a custom info toast")).toBeVisible()
expect(await canvas.findByText("This is a custom info toast")).toBeVisible()
},
}
@@ -61,10 +61,11 @@ export const Success: Story = {
variant: "success",
message: "This is a success toast",
},
play: async ({ canvas, args }) => {
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement)
const toast = await canvas.findByRole("status")
expect(toast).toBeVisible()
expect(canvas.getByText(args.message as string)).toBeVisible()
expect(await canvas.findByText(args.message as string)).toBeVisible()
},
}
@@ -73,10 +74,11 @@ export const Error: Story = {
variant: "error",
message: "This is an error toast",
},
play: async ({ canvas, args }) => {
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement)
const toast = await canvas.findByRole("alert")
expect(toast).toBeVisible()
expect(canvas.getByText(args.message as string)).toBeVisible()
expect(await canvas.findByText(args.message as string)).toBeVisible()
},
}
@@ -85,9 +87,10 @@ export const Warning: Story = {
variant: "warning",
message: "This is a warning toast",
},
play: async ({ canvas, args }) => {
play: async ({ args, canvasElement }) => {
const canvas = within(canvasElement)
const toast = await canvas.findByRole("alert")
expect(toast).toBeVisible()
expect(canvas.getByText(args.message as string)).toBeVisible()
expect(await canvas.findByText(args.message as string)).toBeVisible()
},
}

View File

@@ -7,6 +7,11 @@ import { config as videoPlayerConfig } from "./variants"
const meta: Meta<typeof VideoPlayer> = {
title: "Core Components/Video/VideoPlayer",
component: VideoPlayer,
beforeEach: () => {
// Mock video methods to prevent actual playback
window.HTMLMediaElement.prototype.play = () => Promise.resolve()
window.HTMLMediaElement.prototype.pause = () => {}
},
parameters: {
docs: {

View File

@@ -52,6 +52,7 @@ export default mergeConfig(
headless: true,
instances: browserInstances,
},
fileParallelism: false,
setupFiles: ["./.storybook/vitest.setup.ts"],
},
},

199
yarn.lock
View File

@@ -5159,7 +5159,7 @@ __metadata:
"@scandic-hotels/tracking": "workspace:*"
"@scandic-hotels/trpc": "workspace:*"
"@scandic-hotels/typescript-config": "workspace:*"
"@sentry/nextjs": "npm:^10.26.0"
"@sentry/nextjs": "npm:^10.33.0"
"@swc/plugin-formatjs": "npm:^3.2.2"
"@tanstack/react-query": "npm:^5.75.5"
"@tanstack/react-query-devtools": "npm:^5.75.5"
@@ -5248,7 +5248,7 @@ __metadata:
"@scandic-hotels/tracking": "workspace:*"
"@scandic-hotels/trpc": "workspace:*"
"@scandic-hotels/typescript-config": "workspace:*"
"@sentry/nextjs": "npm:^10.26.0"
"@sentry/nextjs": "npm:^10.33.0"
"@swc/plugin-formatjs": "npm:^3.2.2"
"@t3-oss/env-nextjs": "npm:^0.13.4"
"@tanstack/react-query": "npm:^5.75.5"
@@ -5406,6 +5406,15 @@ __metadata:
languageName: node
linkType: hard
"@sentry-internal/browser-utils@npm:10.33.0":
version: 10.33.0
resolution: "@sentry-internal/browser-utils@npm:10.33.0"
dependencies:
"@sentry/core": "npm:10.33.0"
checksum: 10c0/aee888fd7f5a0af50522ed5138604f470d370d35f9cc07369ec16a16a1fe4f2a749551838449c1c21532cd00d3cc35bb9f95225330af06b3f29bb271aeca46f0
languageName: node
linkType: hard
"@sentry-internal/feedback@npm:10.27.0":
version: 10.27.0
resolution: "@sentry-internal/feedback@npm:10.27.0"
@@ -5415,6 +5424,15 @@ __metadata:
languageName: node
linkType: hard
"@sentry-internal/feedback@npm:10.33.0":
version: 10.33.0
resolution: "@sentry-internal/feedback@npm:10.33.0"
dependencies:
"@sentry/core": "npm:10.33.0"
checksum: 10c0/e203a01094bab810bb223a908c4b46ce9f02f81bb39125820e844a89f5301213cf1a205e8937629db91143c8f0201c946001b6e6641005ddc43ca0d01dfdb37a
languageName: node
linkType: hard
"@sentry-internal/replay-canvas@npm:10.27.0":
version: 10.27.0
resolution: "@sentry-internal/replay-canvas@npm:10.27.0"
@@ -5425,6 +5443,16 @@ __metadata:
languageName: node
linkType: hard
"@sentry-internal/replay-canvas@npm:10.33.0":
version: 10.33.0
resolution: "@sentry-internal/replay-canvas@npm:10.33.0"
dependencies:
"@sentry-internal/replay": "npm:10.33.0"
"@sentry/core": "npm:10.33.0"
checksum: 10c0/40abac10efb635faa797049d60f076aa741810fd7a350f23ed4f51e487d1cbde2e21bfa5834deace19d8825ef6e3f02b07e9525cec35f74691750b20f479924d
languageName: node
linkType: hard
"@sentry-internal/replay@npm:10.27.0":
version: 10.27.0
resolution: "@sentry-internal/replay@npm:10.27.0"
@@ -5435,6 +5463,16 @@ __metadata:
languageName: node
linkType: hard
"@sentry-internal/replay@npm:10.33.0":
version: 10.33.0
resolution: "@sentry-internal/replay@npm:10.33.0"
dependencies:
"@sentry-internal/browser-utils": "npm:10.33.0"
"@sentry/core": "npm:10.33.0"
checksum: 10c0/37261f2da729a623d3a1b7756c36a5ee4c2cb598791770273dc73eab6c3f69eb364a56ca2d41e2f951eedc58d7b099807e2a5805afa8e08feafb42cc5a6abbad
languageName: node
linkType: hard
"@sentry-internal/tracing@npm:7.120.4":
version: 7.120.4
resolution: "@sentry-internal/tracing@npm:7.120.4"
@@ -5466,6 +5504,19 @@ __metadata:
languageName: node
linkType: hard
"@sentry/browser@npm:10.33.0":
version: 10.33.0
resolution: "@sentry/browser@npm:10.33.0"
dependencies:
"@sentry-internal/browser-utils": "npm:10.33.0"
"@sentry-internal/feedback": "npm:10.33.0"
"@sentry-internal/replay": "npm:10.33.0"
"@sentry-internal/replay-canvas": "npm:10.33.0"
"@sentry/core": "npm:10.33.0"
checksum: 10c0/c8ac3d387de8d16582cd2726dfac80c27f82d676140e62210e233e767d30b4e9de82d8c692630b0ca17a9ed1f646af0ac421e364d078aed0756c6a82fac0eb34
languageName: node
linkType: hard
"@sentry/bun@npm:10.31.0":
version: 10.31.0
resolution: "@sentry/bun@npm:10.31.0"
@@ -5602,6 +5653,13 @@ __metadata:
languageName: node
linkType: hard
"@sentry/core@npm:10.33.0":
version: 10.33.0
resolution: "@sentry/core@npm:10.33.0"
checksum: 10c0/60573a58f406b8b667347cabf9b5292f6b726765d914498eeb2678cb7a2f581dd78b4ce35da23e50660a588ec532f1c26464a9971453fea478efea2490fdb28f
languageName: node
linkType: hard
"@sentry/core@npm:7.120.4":
version: 7.120.4
resolution: "@sentry/core@npm:7.120.4"
@@ -5636,6 +5694,29 @@ __metadata:
languageName: node
linkType: hard
"@sentry/nextjs@npm:^10.33.0":
version: 10.33.0
resolution: "@sentry/nextjs@npm:10.33.0"
dependencies:
"@opentelemetry/api": "npm:^1.9.0"
"@opentelemetry/semantic-conventions": "npm:^1.37.0"
"@rollup/plugin-commonjs": "npm:28.0.1"
"@sentry-internal/browser-utils": "npm:10.33.0"
"@sentry/bundler-plugin-core": "npm:^4.6.1"
"@sentry/core": "npm:10.33.0"
"@sentry/node": "npm:10.33.0"
"@sentry/opentelemetry": "npm:10.33.0"
"@sentry/react": "npm:10.33.0"
"@sentry/vercel-edge": "npm:10.33.0"
"@sentry/webpack-plugin": "npm:^4.6.1"
rollup: "npm:^4.35.0"
stacktrace-parser: "npm:^0.1.10"
peerDependencies:
next: ^13.2.0 || ^14.0 || ^15.0.0-rc.0 || ^16.0.0-0
checksum: 10c0/61f63d99bae2487a0042b43ebc96dddf4ee43145bc638e717d7f21dfd85ee676491958eb150d0e90cf62ba6b717b3d625f4ca5c15167e1ed6e348d03992a683b
languageName: node
linkType: hard
"@sentry/node-core@npm:10.27.0":
version: 10.27.0
resolution: "@sentry/node-core@npm:10.27.0"
@@ -5676,6 +5757,26 @@ __metadata:
languageName: node
linkType: hard
"@sentry/node-core@npm:10.33.0":
version: 10.33.0
resolution: "@sentry/node-core@npm:10.33.0"
dependencies:
"@apm-js-collab/tracing-hooks": "npm:^0.3.1"
"@sentry/core": "npm:10.33.0"
"@sentry/opentelemetry": "npm:10.33.0"
import-in-the-middle: "npm:^2.0.1"
peerDependencies:
"@opentelemetry/api": ^1.9.0
"@opentelemetry/context-async-hooks": ^1.30.1 || ^2.1.0 || ^2.2.0
"@opentelemetry/core": ^1.30.1 || ^2.1.0 || ^2.2.0
"@opentelemetry/instrumentation": ">=0.57.1 <1"
"@opentelemetry/resources": ^1.30.1 || ^2.1.0 || ^2.2.0
"@opentelemetry/sdk-trace-base": ^1.30.1 || ^2.1.0 || ^2.2.0
"@opentelemetry/semantic-conventions": ^1.37.0
checksum: 10c0/f2ef7de1d6ef361d9395a3f985aaf9f03390cd788816cd58881dd7f56a91bd3373592b4a4ce5927229813a686e67bef465e1f0794ca0b19bb182fd3ba911d193
languageName: node
linkType: hard
"@sentry/node@npm:10.27.0":
version: 10.27.0
resolution: "@sentry/node@npm:10.27.0"
@@ -5762,6 +5863,49 @@ __metadata:
languageName: node
linkType: hard
"@sentry/node@npm:10.33.0":
version: 10.33.0
resolution: "@sentry/node@npm:10.33.0"
dependencies:
"@opentelemetry/api": "npm:^1.9.0"
"@opentelemetry/context-async-hooks": "npm:^2.2.0"
"@opentelemetry/core": "npm:^2.2.0"
"@opentelemetry/instrumentation": "npm:^0.208.0"
"@opentelemetry/instrumentation-amqplib": "npm:0.55.0"
"@opentelemetry/instrumentation-connect": "npm:0.52.0"
"@opentelemetry/instrumentation-dataloader": "npm:0.26.0"
"@opentelemetry/instrumentation-express": "npm:0.57.0"
"@opentelemetry/instrumentation-fs": "npm:0.28.0"
"@opentelemetry/instrumentation-generic-pool": "npm:0.52.0"
"@opentelemetry/instrumentation-graphql": "npm:0.56.0"
"@opentelemetry/instrumentation-hapi": "npm:0.55.0"
"@opentelemetry/instrumentation-http": "npm:0.208.0"
"@opentelemetry/instrumentation-ioredis": "npm:0.56.0"
"@opentelemetry/instrumentation-kafkajs": "npm:0.18.0"
"@opentelemetry/instrumentation-knex": "npm:0.53.0"
"@opentelemetry/instrumentation-koa": "npm:0.57.0"
"@opentelemetry/instrumentation-lru-memoizer": "npm:0.53.0"
"@opentelemetry/instrumentation-mongodb": "npm:0.61.0"
"@opentelemetry/instrumentation-mongoose": "npm:0.55.0"
"@opentelemetry/instrumentation-mysql": "npm:0.54.0"
"@opentelemetry/instrumentation-mysql2": "npm:0.55.0"
"@opentelemetry/instrumentation-pg": "npm:0.61.0"
"@opentelemetry/instrumentation-redis": "npm:0.57.0"
"@opentelemetry/instrumentation-tedious": "npm:0.27.0"
"@opentelemetry/instrumentation-undici": "npm:0.19.0"
"@opentelemetry/resources": "npm:^2.2.0"
"@opentelemetry/sdk-trace-base": "npm:^2.2.0"
"@opentelemetry/semantic-conventions": "npm:^1.37.0"
"@prisma/instrumentation": "npm:6.19.0"
"@sentry/core": "npm:10.33.0"
"@sentry/node-core": "npm:10.33.0"
"@sentry/opentelemetry": "npm:10.33.0"
import-in-the-middle: "npm:^2.0.1"
minimatch: "npm:^9.0.0"
checksum: 10c0/df3212d02dc63526184707a144d664b486acc0c1019342a4616e5b638ab8061459e57e2e1d89acee381bc9674cb28c738eb576d8d85c271a07f724a983415900
languageName: node
linkType: hard
"@sentry/opentelemetry@npm:10.27.0":
version: 10.27.0
resolution: "@sentry/opentelemetry@npm:10.27.0"
@@ -5792,6 +5936,21 @@ __metadata:
languageName: node
linkType: hard
"@sentry/opentelemetry@npm:10.33.0":
version: 10.33.0
resolution: "@sentry/opentelemetry@npm:10.33.0"
dependencies:
"@sentry/core": "npm:10.33.0"
peerDependencies:
"@opentelemetry/api": ^1.9.0
"@opentelemetry/context-async-hooks": ^1.30.1 || ^2.1.0 || ^2.2.0
"@opentelemetry/core": ^1.30.1 || ^2.1.0 || ^2.2.0
"@opentelemetry/sdk-trace-base": ^1.30.1 || ^2.1.0 || ^2.2.0
"@opentelemetry/semantic-conventions": ^1.37.0
checksum: 10c0/6861ec231642388a2d69b6d9702b16c5f3c75c279db878bf16319103d0b7d40bbda8507753c3448e4038bfb761e68570008ef1310eb51a4ae24b97a06239dffa
languageName: node
linkType: hard
"@sentry/react@npm:10.27.0":
version: 10.27.0
resolution: "@sentry/react@npm:10.27.0"
@@ -5805,6 +5964,18 @@ __metadata:
languageName: node
linkType: hard
"@sentry/react@npm:10.33.0":
version: 10.33.0
resolution: "@sentry/react@npm:10.33.0"
dependencies:
"@sentry/browser": "npm:10.33.0"
"@sentry/core": "npm:10.33.0"
peerDependencies:
react: ^16.14.0 || 17.x || 18.x || 19.x
checksum: 10c0/82e70c86c506ac17cb4d73231078a548de5e010981d707c56b55dc27844bbef69d1eb5b35907db90cce2c3abebd09aee5fff3687151279cbf37793c1f21cc253
languageName: node
linkType: hard
"@sentry/tracing@npm:7.120.4":
version: 7.120.4
resolution: "@sentry/tracing@npm:7.120.4"
@@ -5841,7 +6012,18 @@ __metadata:
languageName: node
linkType: hard
"@sentry/webpack-plugin@npm:^4.3.0":
"@sentry/vercel-edge@npm:10.33.0":
version: 10.33.0
resolution: "@sentry/vercel-edge@npm:10.33.0"
dependencies:
"@opentelemetry/api": "npm:^1.9.0"
"@opentelemetry/resources": "npm:^2.2.0"
"@sentry/core": "npm:10.33.0"
checksum: 10c0/007dd1954d46373519628da760b40420213381098ffbd2d94b898dd9d68e60876f9025f3d40a0b063f32dbee18aab6e4628cba215ad90d329875f571426d7a75
languageName: node
linkType: hard
"@sentry/webpack-plugin@npm:^4.3.0, @sentry/webpack-plugin@npm:^4.6.1":
version: 4.6.1
resolution: "@sentry/webpack-plugin@npm:4.6.1"
dependencies:
@@ -6904,7 +7086,16 @@ __metadata:
languageName: node
linkType: hard
"@types/react@npm:16 || 17 || 18 || 19, @types/react@npm:19.2.7":
"@types/react@npm:16 || 17 || 18 || 19":
version: 19.2.8
resolution: "@types/react@npm:19.2.8"
dependencies:
csstype: "npm:^3.2.2"
checksum: 10c0/832834998c4ee971fca72ecf1eb95dc924ad3931a2112c687a4dae498aabd115c5fa4db09186853e34a646226b0223808c8f867df03d17601168f9cf119448de
languageName: node
linkType: hard
"@types/react@npm:19.2.7":
version: 19.2.7
resolution: "@types/react@npm:19.2.7"
dependencies: