From a13dd81105aea134eeb8d27034231e85ba806dca Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Wed, 13 May 2026 10:25:15 +0700 Subject: [PATCH 01/11] [BOOKINGSG-9309][GZ] add visual test --- .../components/[component]/[story]/page.tsx | 9 +- .../dropdown-default.e2e.tsx | 22 +++ .../dropdown-preselected.e2e.tsx | 22 +++ .../language-switcher/link-default.e2e.tsx | 22 +++ .../link-preselected.e2e.tsx | 22 +++ ...nguageSwitcher-Dropdown-Default--mount.png | Bin 0 -> 2086 bytes ...anguageSwitcher-Dropdown-Default--open.png | Bin 0 -> 10669 bytes ...geSwitcher-Dropdown-Preselected--mount.png | Bin 0 -> 1885 bytes .../LanguageSwitcher-Link-Default--mount.png | Bin 0 -> 4449 bytes ...nguageSwitcher-Link-Preselected--mount.png | Bin 0 -> 4452 bytes .../language-switcher.e2e.spec.ts | 164 ++++++++++++++++++ 11 files changed, 257 insertions(+), 4 deletions(-) create mode 100644 e2e/nextjs-app/src/app/components/language-switcher/dropdown-default.e2e.tsx create mode 100644 e2e/nextjs-app/src/app/components/language-switcher/dropdown-preselected.e2e.tsx create mode 100644 e2e/nextjs-app/src/app/components/language-switcher/link-default.e2e.tsx create mode 100644 e2e/nextjs-app/src/app/components/language-switcher/link-preselected.e2e.tsx create mode 100644 e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Dropdown-Default--mount.png create mode 100644 e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Dropdown-Default--open.png create mode 100644 e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Dropdown-Preselected--mount.png create mode 100644 e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Link-Default--mount.png create mode 100644 e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Link-Preselected--mount.png create mode 100644 e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts diff --git a/e2e/nextjs-app/src/app/components/[component]/[story]/page.tsx b/e2e/nextjs-app/src/app/components/[component]/[story]/page.tsx index 59fdf9d8f..9adc0e3f3 100644 --- a/e2e/nextjs-app/src/app/components/[component]/[story]/page.tsx +++ b/e2e/nextjs-app/src/app/components/[component]/[story]/page.tsx @@ -10,14 +10,15 @@ import { */ const CSR_ONLY_COMPONENTS = new Set([ "badge", - "date-range-input", "date-input", - "select", + "date-range-input", + "input-group", "input-multi-select", "input-select", - "nested-select", + "language-switcher", "nested-multi-select", - "input-group", + "nested-select", + "select", ]); export default async function Page({ diff --git a/e2e/nextjs-app/src/app/components/language-switcher/dropdown-default.e2e.tsx b/e2e/nextjs-app/src/app/components/language-switcher/dropdown-default.e2e.tsx new file mode 100644 index 000000000..2c4a512fa --- /dev/null +++ b/e2e/nextjs-app/src/app/components/language-switcher/dropdown-default.e2e.tsx @@ -0,0 +1,22 @@ +"use client"; + +import { + LanguageSwitcher, + type LanguageSwitcherCode, +} from "@lifesg/react-design-system/language-switcher"; +import { useState } from "react"; + +export default function Story() { + const [language, setLanguage] = useState("en"); + + return ( +
+ +
+ ); +} diff --git a/e2e/nextjs-app/src/app/components/language-switcher/dropdown-preselected.e2e.tsx b/e2e/nextjs-app/src/app/components/language-switcher/dropdown-preselected.e2e.tsx new file mode 100644 index 000000000..697e6e113 --- /dev/null +++ b/e2e/nextjs-app/src/app/components/language-switcher/dropdown-preselected.e2e.tsx @@ -0,0 +1,22 @@ +"use client"; + +import { + LanguageSwitcher, + type LanguageSwitcherCode, +} from "@lifesg/react-design-system/language-switcher"; +import { useState } from "react"; + +export default function Story() { + const [language, setLanguage] = useState("zh"); + + return ( +
+ +
+ ); +} diff --git a/e2e/nextjs-app/src/app/components/language-switcher/link-default.e2e.tsx b/e2e/nextjs-app/src/app/components/language-switcher/link-default.e2e.tsx new file mode 100644 index 000000000..b86afed05 --- /dev/null +++ b/e2e/nextjs-app/src/app/components/language-switcher/link-default.e2e.tsx @@ -0,0 +1,22 @@ +"use client"; + +import { + LanguageSwitcher, + type LanguageSwitcherCode, +} from "@lifesg/react-design-system/language-switcher"; +import { useState } from "react"; + +export default function Story() { + const [language, setLanguage] = useState("en"); + + return ( +
+ +
+ ); +} diff --git a/e2e/nextjs-app/src/app/components/language-switcher/link-preselected.e2e.tsx b/e2e/nextjs-app/src/app/components/language-switcher/link-preselected.e2e.tsx new file mode 100644 index 000000000..9ac18eabe --- /dev/null +++ b/e2e/nextjs-app/src/app/components/language-switcher/link-preselected.e2e.tsx @@ -0,0 +1,22 @@ +"use client"; + +import { + LanguageSwitcher, + type LanguageSwitcherCode, +} from "@lifesg/react-design-system/language-switcher"; +import { useState } from "react"; + +export default function Story() { + const [language, setLanguage] = useState("ta"); + + return ( +
+ +
+ ); +} diff --git a/e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Dropdown-Default--mount.png b/e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Dropdown-Default--mount.png new file mode 100644 index 0000000000000000000000000000000000000000..f80c03ebceede9e5ce7156a8b32de61af3364d41 GIT binary patch literal 2086 zcmV+>2-)|EP)j==r}}RMY@C$N+^VXk^Fo4^FrJY0ZS>(3zEmByx-?? zx%_@F`MujrU!BdHMC=hD zNmv!VK3|et9^N;F?As0p+%A=f0V1}E#1spJ1)egnP6I^DBNPZc1QGr{6n!@Ar%~(u zjR0z*460Bx&LEI%27zQV2qc?9AlVE8$z~8pHiJO283YT^%wPZ2ch1-k5HUdXYqrZb z*4E>?mptD%0H0Ij{ChcBDe)p+Tm&VJ-KcGRq~73zJo?(r8JR}Y7de-nTbsQi9z+b6&(p|Q z+=&D(5J&fblffYZ^8-c@ecAezxb2OC8JV9Ad%yj{^|}f@+zRFfE3atH>5W1jpaC|& z@W~A}uyDYIskg86em6s^Rm{G;8gISxwL*1tW>^I zq$s$1cIou$BU>biVGH!xY=^6R-!}&m(h`4RP~_o(c1vLT_L_@5XL^B7C((gGb8A;c z-G~FsnWaLkwmh5gkNxP6&7byprf>52$DXLX2~8i~@cTYmbNt0OBWbmd%Q>bc1Tu1&jKDxG+($<4g5Hvua2b(wd( z+S_chcM=J@5qpg}glpB6dsQ&xDwG8`RSo+Ec%F(Iem8z6F&Kp9tKTY3{!*+qby_B5 zq+KXY*0S&IZn%?>>F2)I51Y5M`?7Yu-U@xc|C^kN`VCFPK&Rz1*RQvw{_1-vfF9@_ zdOh+`qTNFdIRhn|loL7c8T;W$@NwHn~b4W#bR!GaE(tqzO!)g-=vgo=l>} z$1kCBz#_>2jJCM!$&;ANXTi?iPf%YyCr*;)NrBUB+VNUPb&G3o=C{KP`Eo6L+U~q} zcXwZ`*Gk@fdd)=r{>18rXL;$5%Z+{?L}J6;E}PSOPxFmxm_wQZQudt!{N$Z6h`R zv|9nDOA}Ccui}Iw6*-mpII!3bzSXqucmJvGnjWNcX5HO=1CPnuC7CX75c=N!r)FsS zryG-Bd{hJIgf7`o?PJGps*?ooKArVW>1tU#+i1ECXIEep`e3qf`?{nv4Sir=FW~dmV@-)T=hY7_{iFW>4G{20 zW~xLW%8>0hY({{W?MW?E3N#A-T*u{5c~Mci!_sunLUcOE40K+B2V<9ao?6rKxqJVX z6@Y%|lD&WHif!2m@l!KpG7etwbxPn6q=3%;g^vi3%Q!3H&3@i zGL_&<_4@FG^&k*%V1(Xo9&R^Jj2eS8to$TboxjARw8S~`OT%}c3?p2Qm+w&bH z#t;R<@QSzC6lHh zT$Pf;1uQX+7IPQbdNvz|0vvGNR(>+HCs(e+L)KfiQw^g|T)rn;xVWozBrIGrzCe(k z`m5ci8tle_;P~tcF4~%<*lAE06pR0_4l&e>FA!{@VUy0V2_U`->d6=clFcBHYzBd3 zGYBM`K~T(Iu`w(_E}{v;#S7E~Wrcqag=~>f;Pz1bpC1tmcnCr$pje@!kR2}+d40ay z4hO2=F$+`!1rc5!E}~d3UP5_u`CxF&Ieup>bZe{_1-9O>PD9i4y)_nMF@d6S27zQV z2qc?9AlVE8$z~8pHiJO283dBeAdqYZ@qYjS0RR65(NT5)000I_L_t&o0QuJUG`>Oj Q4gdfE07*qoM6N<$f@By7OaK4? literal 0 HcmV?d00001 diff --git a/e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Dropdown-Default--open.png b/e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Dropdown-Default--open.png new file mode 100644 index 0000000000000000000000000000000000000000..e8c2fe0191e9164ba395ff661dae239334db2b33 GIT binary patch literal 10669 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 SwLn|D8-RnI6S4+@x%EFCA(hMk literal 0 HcmV?d00001 diff --git a/e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Link-Default--mount.png b/e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Link-Default--mount.png new file mode 100644 index 0000000000000000000000000000000000000000..20ecf6810593fc025de69ab40988d255f4c753ea GIT binary patch literal 4449 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 G7xOBL+%Iw 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 literal 0 HcmV?d00001 diff --git a/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts b/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts new file mode 100644 index 000000000..056464949 --- /dev/null +++ b/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts @@ -0,0 +1,164 @@ +import { test as base, expect, Locator, Page } from "@playwright/test"; +import { AbstractStoryPage, compareScreenshot } from "../../utils"; + +class StoryPage extends AbstractStoryPage { + protected readonly component = "language-switcher"; + + public readonly locators: { + component: { + trigger: Locator; + panel: Locator; + }; + languageSwitcher: Locator; + }; + + constructor(page: Page) { + super(page); + + this.locators = { + component: { + trigger: page.getByTestId("language-switcher--trigger"), + panel: page.getByTestId("language-switcher--panel"), + }, + languageSwitcher: page.getByTestId("language-switcher"), + }; + } + + public getDropdownOption(name: string) { + return this.page.getByRole("option", { name }); + } + + public getLinkButton(name: string) { + return this.page.getByRole("button", { name, exact: true }); + } +} + +const test = base.extend<{ story: StoryPage }>({ + story: async ({ page }, mountStory) => { + const story = new StoryPage(page); + await mountStory(story); + }, +}); + +test.describe("LanguageSwitcher", () => { + test.describe("Dropdown", () => { + test.beforeEach(async ({ story }) => { + await story.init("dropdown-default"); + }); + + test("Default", async ({ story }) => { + await compareScreenshot(story, "mount", { + locator: story.locators.languageSwitcher, + }); + + await expect(story.locators.languageSwitcher).toMatchAriaSnapshot(` + - combobox "Choose language / 选择语言 / Pilih bahasa / மொழியை தேர்ந்தெடுக்கவும், English" + `); + + await story.locators.component.trigger.click(); + await compareScreenshot(story, "open", { + fullscreen: true, + }); + + await expect(story.locators.languageSwitcher).toMatchAriaSnapshot(` + - combobox "Choose language / 选择语言 / Pilih bahasa / மொழியை தேர்ந்தெடுக்கவும், English" [expanded] + - listbox "Choose language / 选择语言 / Pilih bahasa / மொழியை தேர்ந்தெடுக்கவும்": + - option "English" [selected] + - option "中文" + - option "Melayu" + - option "தமிழ்" + `); + }); + + test("Keyboard Interaction", async ({ story }) => { + await story.locators.component.trigger.focus(); + await story.page.keyboard.press("Enter"); + await expect(story.locators.component.panel).toBeVisible(); + + await story.page.keyboard.press("ArrowDown"); + await expect(story.getDropdownOption("中文")).toBeFocused(); + + await story.page.keyboard.press("End"); + await expect(story.getDropdownOption("தமிழ்")).toBeFocused(); + + await story.page.keyboard.press("Home"); + await expect(story.getDropdownOption("English")).toBeFocused(); + + await story.page.keyboard.press("ArrowDown"); + await story.page.keyboard.press("Enter"); + await expect(story.locators.component.panel).not.toBeVisible(); + await expect(story.locators.component.trigger).toContainText( + "中文" + ); + }); + + test.describe("", () => { + test.beforeEach(async ({ story }) => { + await story.init("dropdown-preselected"); + }); + + test("Preselected", async ({ story }) => { + await expect(story.locators.component.trigger).toContainText( + "中文" + ); + + await compareScreenshot(story, "mount", { + locator: story.locators.languageSwitcher, + }); + }); + }); + }); + + test.describe("Link", () => { + test.beforeEach(async ({ story }) => { + await story.init("link-default"); + }); + + test("Default", async ({ story }) => { + await expect(story.locators.languageSwitcher).toMatchAriaSnapshot(` + - group "Choose language / 选择语言 / Pilih bahasa / மொழியை தேர்ந்தெடுக்கவும்": + - listitem: + - button "English" [pressed] + - listitem: + - button "中文" + - listitem: + - button "Melayu" + - listitem: + - button "தமிழ்" + `); + + await compareScreenshot(story, "mount", { + locator: story.locators.languageSwitcher, + }); + }); + + test("Keyboard Interaction", async ({ story }) => { + const english = story.getLinkButton("English"); + const chinese = story.getLinkButton("中文"); + + await english.focus(); + await story.page.keyboard.press("ArrowRight"); + await expect(chinese).toBeFocused(); + + await story.page.keyboard.press("Enter"); + await expect(chinese).toHaveAttribute("aria-pressed", "true"); + await expect(english).toHaveAttribute("aria-pressed", "false"); + }); + + test.describe("", () => { + test.beforeEach(async ({ story }) => { + await story.init("link-preselected"); + }); + + test("Preselected", async ({ story }) => { + const tamil = story.getLinkButton("தமிழ்"); + + await expect(tamil).toHaveAttribute("aria-pressed", "true"); + + await compareScreenshot(story, "mount", { + locator: story.locators.languageSwitcher, + }); + }); + }); + }); +}); From 2f87d3fcad52e966a75d4c5cb5e1a045633e4d94 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Wed, 13 May 2026 13:56:13 +0700 Subject: [PATCH 02/11] [BOOKINGSG-9309][GZ] remove keyboard navigation from e2e --- .../language-switcher/language-switcher.e2e.spec.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts b/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts index 056464949..98a341baf 100644 --- a/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts +++ b/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts @@ -132,19 +132,6 @@ test.describe("LanguageSwitcher", () => { }); }); - test("Keyboard Interaction", async ({ story }) => { - const english = story.getLinkButton("English"); - const chinese = story.getLinkButton("中文"); - - await english.focus(); - await story.page.keyboard.press("ArrowRight"); - await expect(chinese).toBeFocused(); - - await story.page.keyboard.press("Enter"); - await expect(chinese).toHaveAttribute("aria-pressed", "true"); - await expect(english).toHaveAttribute("aria-pressed", "false"); - }); - test.describe("", () => { test.beforeEach(async ({ story }) => { await story.init("link-preselected"); From 26b1027afd529b0ab8bc5c37cecc3efba4ca4ce1 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Wed, 13 May 2026 14:05:12 +0700 Subject: [PATCH 03/11] [BOOKINGSG-9309][GZ] rename styles filename --- .../{dropdown-variant.style.tsx => dropdown-variant.styles.ts} | 0 src/language-switcher/dropdown-variant.tsx | 2 +- ...ainer-variant.style.tsx => link-container-variant.styles.ts} | 0 src/language-switcher/link-container-variant.tsx | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) rename src/language-switcher/{dropdown-variant.style.tsx => dropdown-variant.styles.ts} (100%) rename src/language-switcher/{link-container-variant.style.tsx => link-container-variant.styles.ts} (100%) diff --git a/src/language-switcher/dropdown-variant.style.tsx b/src/language-switcher/dropdown-variant.styles.ts similarity index 100% rename from src/language-switcher/dropdown-variant.style.tsx rename to src/language-switcher/dropdown-variant.styles.ts diff --git a/src/language-switcher/dropdown-variant.tsx b/src/language-switcher/dropdown-variant.tsx index 1dfa9c861..35d7dcae1 100644 --- a/src/language-switcher/dropdown-variant.tsx +++ b/src/language-switcher/dropdown-variant.tsx @@ -21,7 +21,7 @@ import { LanguageIconWrapper, selectedIndicator, StyledExpandableElement, -} from "./dropdown-variant.style"; +} from "./dropdown-variant.styles"; import type { VariantInternalProps } from "./internal-types"; import type { LanguageSwitcherCode } from "./types"; diff --git a/src/language-switcher/link-container-variant.style.tsx b/src/language-switcher/link-container-variant.styles.ts similarity index 100% rename from src/language-switcher/link-container-variant.style.tsx rename to src/language-switcher/link-container-variant.styles.ts diff --git a/src/language-switcher/link-container-variant.tsx b/src/language-switcher/link-container-variant.tsx index 6c41973a6..668b06a98 100644 --- a/src/language-switcher/link-container-variant.tsx +++ b/src/language-switcher/link-container-variant.tsx @@ -8,7 +8,7 @@ import { LinkItem, LinkList, LinkListItem, -} from "./link-container-variant.style"; +} from "./link-container-variant.styles"; export const LinkContainerVariant = ({ selectedLanguage, From e483cb30af1a51d06b2f2f824e3274aa2ace709f Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Wed, 13 May 2026 14:12:14 +0700 Subject: [PATCH 04/11] [BOOKINGSG-9309][GZ] migrated props interpolation --- .../dropdown-variant.styles.ts | 30 ++++++------- src/language-switcher/dropdown-variant.tsx | 5 ++- .../link-container-variant.styles.ts | 45 +++++++++---------- .../link-container-variant.tsx | 6 ++- 4 files changed, 44 insertions(+), 42 deletions(-) diff --git a/src/language-switcher/dropdown-variant.styles.ts b/src/language-switcher/dropdown-variant.styles.ts index eb51afc41..b9ec2e2f5 100644 --- a/src/language-switcher/dropdown-variant.styles.ts +++ b/src/language-switcher/dropdown-variant.styles.ts @@ -1,10 +1,6 @@ import styled, { css } from "styled-components"; import { ExpandableElement } from "../shared/dropdown-list"; -import { - baseIndicatorStyle, - selectedIndicator, -} from "../shared/dropdown-list/dropdown-list.styles"; import { iconContainer } from "../shared/dropdown-list/expandable-element.styles"; import { Border, Colour, Font, Radius, Spacing } from "../theme"; @@ -67,9 +63,15 @@ export const DropdownList = styled.ul` padding: ${Spacing["spacing-8"]}; `; -export { baseIndicatorStyle, selectedIndicator }; +export { + baseIndicatorStyle, + selectedIndicator, +} from "../shared/dropdown-list/dropdown-list.styles"; + +export const dropdownItemSelectedClassName = + "languageSwitcherDropdownVariantItemSelected"; -export const DropdownItem = styled.li<{ $selected: boolean }>` +export const DropdownItem = styled.li` align-items: center; ${Font["body-md-regular"]} color: ${Colour["text"]}; @@ -78,14 +80,12 @@ export const DropdownItem = styled.li<{ $selected: boolean }>` background: ${Colour["bg-hover-subtle"]}; } - ${(props) => - props.$selected && - css` - background: transparent; - color: ${Colour["text-selected"]}; + &.${dropdownItemSelectedClassName} { + background: transparent; + color: ${Colour["text-selected"]}; - &:hover { - background: ${Colour["bg-hover"]}; - } - `} + &:hover { + background: ${Colour["bg-hover"]}; + } + } `; diff --git a/src/language-switcher/dropdown-variant.tsx b/src/language-switcher/dropdown-variant.tsx index 35d7dcae1..2fb42b600 100644 --- a/src/language-switcher/dropdown-variant.tsx +++ b/src/language-switcher/dropdown-variant.tsx @@ -16,6 +16,7 @@ import { useId } from "../util"; import { ARIA_LABEL, LANGUAGE_CODES, LANGUAGE_DISPLAY_MAP } from "./data"; import { DropdownItem, + dropdownItemSelectedClassName, DropdownList, DropdownPanel, LanguageIconWrapper, @@ -178,11 +179,11 @@ export const DropdownVariant = ({ isFocused && isSelected && listItemActiveSelected, - isFocused && !isSelected && listItemActive + isFocused && !isSelected && listItemActive, + isSelected && dropdownItemSelectedClassName )} aria-selected={isSelected} tabIndex={isFocused ? 0 : -1} - $selected={isSelected} onClick={() => handleItemSelect(code)} data-testid={`${testId}--item-${code}`} > diff --git a/src/language-switcher/link-container-variant.styles.ts b/src/language-switcher/link-container-variant.styles.ts index e345bf50c..561898863 100644 --- a/src/language-switcher/link-container-variant.styles.ts +++ b/src/language-switcher/link-container-variant.styles.ts @@ -1,14 +1,7 @@ -import styled, { css } from "styled-components"; +import styled from "styled-components"; import { Border, Colour, Font, Motion, Radius, Spacing } from "../theme"; -// ============================================================================= -// STYLE INTERFACES -// ============================================================================= -interface LinkItemStyleProps { - $active?: boolean; -} - // ============================================================================= // LINK CONTAINER STYLES // ============================================================================= @@ -36,7 +29,10 @@ export const LinkListItem = styled.li` align-items: center; `; -export const LinkItem = styled.button` +export const linkItemActiveClassName = + "languageSwitcherLinkContainerVariantItemActive"; + +export const LinkItem = styled.button` display: flex; padding: 0.25rem 0.5rem; justify-content: center; @@ -48,23 +44,24 @@ export const LinkItem = styled.button` color: ${Colour["text-subtler"]}; text-align: center; transition: color ${Motion["duration-150"]} ${Motion["ease-default"]}; + background: none; + cursor: pointer; - ${({ $active }) => - $active - ? css` - background: ${Colour["bg-primary-subtler"]}; - color: ${Colour["text-selected"]}; - cursor: default; - ` - : css` - background: none; - cursor: pointer; + &:hover { + color: ${Colour["text-hover"]}; + text-decoration: underline; + } + + &.${linkItemActiveClassName} { + background: ${Colour["bg-primary-subtler"]}; + color: ${Colour["text-selected"]}; + cursor: default; - &:hover { - color: ${Colour["text-hover"]}; - text-decoration: underline; - } - `} + &:hover { + color: ${Colour["text-selected"]}; + text-decoration: none; + } + } &:focus-visible { outline: 2px solid ${Colour["focus-ring"]}; diff --git a/src/language-switcher/link-container-variant.tsx b/src/language-switcher/link-container-variant.tsx index 668b06a98..a1ddb2e90 100644 --- a/src/language-switcher/link-container-variant.tsx +++ b/src/language-switcher/link-container-variant.tsx @@ -1,3 +1,4 @@ +import clsx from "clsx"; import type React from "react"; import { useRef } from "react"; @@ -6,6 +7,7 @@ import type { VariantInternalProps } from "./internal-types"; import { LinkContainerWrapper, LinkItem, + linkItemActiveClassName, LinkList, LinkListItem, } from "./link-container-variant.styles"; @@ -70,7 +72,9 @@ export const LinkContainerVariant = ({ }} type="button" lang={code} - $active={isActive} + className={clsx( + isActive && linkItemActiveClassName + )} aria-pressed={isActive} tabIndex={isActive ? 0 : -1} onClick={() => onSelectLanguage(code)} From d5c1991b594a00ba6fbeb0b2b10511d10c9088a0 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Wed, 13 May 2026 14:31:38 +0700 Subject: [PATCH 05/11] [BOOKINGSG-9309][GZ] migrated to linaria css --- .../dropdown-variant.styles.ts | 34 ++++++--------- src/language-switcher/dropdown-variant.tsx | 43 +++++++++---------- .../link-container-variant.styles.ts | 35 +++++++-------- .../link-container-variant.tsx | 36 +++++++++------- 4 files changed, 69 insertions(+), 79 deletions(-) diff --git a/src/language-switcher/dropdown-variant.styles.ts b/src/language-switcher/dropdown-variant.styles.ts index b9ec2e2f5..72ab02d48 100644 --- a/src/language-switcher/dropdown-variant.styles.ts +++ b/src/language-switcher/dropdown-variant.styles.ts @@ -1,13 +1,12 @@ -import styled, { css } from "styled-components"; +import { css } from "@linaria/core"; -import { ExpandableElement } from "../shared/dropdown-list"; import { iconContainer } from "../shared/dropdown-list/expandable-element.styles"; import { Border, Colour, Font, Radius, Spacing } from "../theme"; // ============================================================================= // TRIGGER STYLES // ============================================================================= -export const StyledExpandableElement = styled(ExpandableElement)` +export const expandableElement = css` min-width: 9rem; width: auto; ${Font["body-md-semibold"]} @@ -32,9 +31,10 @@ export const StyledExpandableElement = styled(ExpandableElement)` } `; -const IconWrapper = css` +export const languageIconWrapper = css` display: flex; align-items: center; + color: ${Colour["icon-primary"]}; svg { height: 1rem; @@ -42,22 +42,17 @@ const IconWrapper = css` } `; -export const LanguageIconWrapper = styled.span` - ${IconWrapper} - color: ${Colour["icon-primary"]}; -`; - // ============================================================================= // DROPDOWN STYLES // ============================================================================= -export const DropdownPanel = styled.div` +export const dropdownPanel = css` border-radius: ${Radius["sm"]}; border: ${Border["width-010"]} ${Border["solid"]} ${Colour["border"]}; background: ${Colour["bg"]}; overflow: hidden; `; -export const DropdownList = styled.ul` +export const dropdownList = css` list-style: none; margin: 0; padding: ${Spacing["spacing-8"]}; @@ -68,10 +63,7 @@ export { selectedIndicator, } from "../shared/dropdown-list/dropdown-list.styles"; -export const dropdownItemSelectedClassName = - "languageSwitcherDropdownVariantItemSelected"; - -export const DropdownItem = styled.li` +export const dropdownItem = css` align-items: center; ${Font["body-md-regular"]} color: ${Colour["text"]}; @@ -79,13 +71,13 @@ export const DropdownItem = styled.li` &:hover { background: ${Colour["bg-hover-subtle"]}; } +`; - &.${dropdownItemSelectedClassName} { - background: transparent; - color: ${Colour["text-selected"]}; +export const dropdownItemSelected = css` + background: transparent; + color: ${Colour["text-selected"]}; - &:hover { - background: ${Colour["bg-hover"]}; - } + &:hover { + background: ${Colour["bg-hover"]}; } `; diff --git a/src/language-switcher/dropdown-variant.tsx b/src/language-switcher/dropdown-variant.tsx index 2fb42b600..d8cf987e4 100644 --- a/src/language-switcher/dropdown-variant.tsx +++ b/src/language-switcher/dropdown-variant.tsx @@ -4,6 +4,7 @@ import clsx from "clsx"; import type React from "react"; import { useEffect, useRef, useState } from "react"; +import { ExpandableElement } from "../shared/dropdown-list"; import { baseIndicatorStyle, listItem, @@ -14,15 +15,7 @@ import type { DropdownRenderProps } from "../shared/dropdown-wrapper"; import { ElementWithDropdown } from "../shared/dropdown-wrapper"; import { useId } from "../util"; import { ARIA_LABEL, LANGUAGE_CODES, LANGUAGE_DISPLAY_MAP } from "./data"; -import { - DropdownItem, - dropdownItemSelectedClassName, - DropdownList, - DropdownPanel, - LanguageIconWrapper, - selectedIndicator, - StyledExpandableElement, -} from "./dropdown-variant.styles"; +import * as styles from "./dropdown-variant.styles"; import type { VariantInternalProps } from "./internal-types"; import type { LanguageSwitcherCode } from "./types"; @@ -128,8 +121,9 @@ export const DropdownVariant = ({ // RENDER FUNCTIONS // ========================================================================= const renderElement = () => ( - - + - + {LANGUAGE_DISPLAY_MAP[selectedLanguage]} - + ); const renderDropdown = ({ elementWidth, - styles, + styles: floatingStyles, setFloatingRef, getFloatingProps, }: DropdownRenderProps) => ( - - { itemRefs.current[index] = el; @@ -175,12 +171,13 @@ export const DropdownVariant = ({ role="option" lang={code} className={clsx( + styles.dropdownItem, listItem, isFocused && isSelected && listItemActiveSelected, isFocused && !isSelected && listItemActive, - isSelected && dropdownItemSelectedClassName + isSelected && styles.dropdownItemSelected )} aria-selected={isSelected} tabIndex={isFocused ? 0 : -1} @@ -191,7 +188,7 @@ export const DropdownVariant = ({ @@ -199,11 +196,11 @@ export const DropdownVariant = ({
)} {LANGUAGE_DISPLAY_MAP[code]} - + ); })} - - + +
); // ========================================================================= diff --git a/src/language-switcher/link-container-variant.styles.ts b/src/language-switcher/link-container-variant.styles.ts index 561898863..9c7672ec0 100644 --- a/src/language-switcher/link-container-variant.styles.ts +++ b/src/language-switcher/link-container-variant.styles.ts @@ -1,11 +1,11 @@ -import styled from "styled-components"; +import { css } from "@linaria/core"; import { Border, Colour, Font, Motion, Radius, Spacing } from "../theme"; // ============================================================================= // LINK CONTAINER STYLES // ============================================================================= -export const LinkContainerWrapper = styled.div` +export const linkContainerWrapper = css` display: inline-flex; padding: ${Spacing["spacing-8"]} ${Spacing["spacing-16"]}; align-items: center; @@ -14,7 +14,7 @@ export const LinkContainerWrapper = styled.div` background: ${Colour["bg"]}; `; -export const LinkList = styled.ul` +export const linkList = css` display: flex; list-style: none; margin: 0; @@ -24,15 +24,12 @@ export const LinkList = styled.ul` flex-wrap: wrap; `; -export const LinkListItem = styled.li` +export const linkListItem = css` display: flex; align-items: center; `; -export const linkItemActiveClassName = - "languageSwitcherLinkContainerVariantItemActive"; - -export const LinkItem = styled.button` +export const linkItem = css` display: flex; padding: 0.25rem 0.5rem; justify-content: center; @@ -52,19 +49,19 @@ export const LinkItem = styled.button` text-decoration: underline; } - &.${linkItemActiveClassName} { - background: ${Colour["bg-primary-subtler"]}; - color: ${Colour["text-selected"]}; - cursor: default; - - &:hover { - color: ${Colour["text-selected"]}; - text-decoration: none; - } - } - &:focus-visible { outline: 2px solid ${Colour["focus-ring"]}; outline-offset: -2px; } `; + +export const linkItemActive = css` + background: ${Colour["bg-primary-subtler"]}; + color: ${Colour["text-selected"]}; + cursor: default; + + &:hover { + color: ${Colour["text-selected"]}; + text-decoration: none; + } +`; diff --git a/src/language-switcher/link-container-variant.tsx b/src/language-switcher/link-container-variant.tsx index a1ddb2e90..8a7671ceb 100644 --- a/src/language-switcher/link-container-variant.tsx +++ b/src/language-switcher/link-container-variant.tsx @@ -4,18 +4,13 @@ import { useRef } from "react"; import { ARIA_LABEL, LANGUAGE_CODES, LANGUAGE_DISPLAY_MAP } from "./data"; import type { VariantInternalProps } from "./internal-types"; -import { - LinkContainerWrapper, - LinkItem, - linkItemActiveClassName, - LinkList, - LinkListItem, -} from "./link-container-variant.styles"; +import * as styles from "./link-container-variant.styles"; export const LinkContainerVariant = ({ selectedLanguage, onSelectLanguage, testId, + className, ...otherProps }: VariantInternalProps): JSX.Element => { // ========================================================================= @@ -60,20 +55,29 @@ export const LinkContainerVariant = ({ // RENDER // ========================================================================= return ( - - +
+
    {LANGUAGE_CODES.map((code, index) => { const isActive = code === selectedLanguage; return ( - - + + ); })} - - +
+
); }; From e6a673d336b0b3117608d7d8b27069291d53d768 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Wed, 13 May 2026 14:37:40 +0700 Subject: [PATCH 06/11] [BOOKINGSG-9309][GZ] rename internal component locators --- .../language-switcher.e2e.spec.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts b/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts index 98a341baf..8a3340fbe 100644 --- a/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts +++ b/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts @@ -5,7 +5,7 @@ class StoryPage extends AbstractStoryPage { protected readonly component = "language-switcher"; public readonly locators: { - component: { + internal: { trigger: Locator; panel: Locator; }; @@ -16,7 +16,7 @@ class StoryPage extends AbstractStoryPage { super(page); this.locators = { - component: { + internal: { trigger: page.getByTestId("language-switcher--trigger"), panel: page.getByTestId("language-switcher--panel"), }, @@ -55,7 +55,7 @@ test.describe("LanguageSwitcher", () => { - combobox "Choose language / 选择语言 / Pilih bahasa / மொழியை தேர்ந்தெடுக்கவும், English" `); - await story.locators.component.trigger.click(); + await story.locators.internal.trigger.click(); await compareScreenshot(story, "open", { fullscreen: true, }); @@ -71,9 +71,9 @@ test.describe("LanguageSwitcher", () => { }); test("Keyboard Interaction", async ({ story }) => { - await story.locators.component.trigger.focus(); + await story.locators.internal.trigger.focus(); await story.page.keyboard.press("Enter"); - await expect(story.locators.component.panel).toBeVisible(); + await expect(story.locators.internal.panel).toBeVisible(); await story.page.keyboard.press("ArrowDown"); await expect(story.getDropdownOption("中文")).toBeFocused(); @@ -86,10 +86,8 @@ test.describe("LanguageSwitcher", () => { await story.page.keyboard.press("ArrowDown"); await story.page.keyboard.press("Enter"); - await expect(story.locators.component.panel).not.toBeVisible(); - await expect(story.locators.component.trigger).toContainText( - "中文" - ); + await expect(story.locators.internal.panel).not.toBeVisible(); + await expect(story.locators.internal.trigger).toContainText("中文"); }); test.describe("", () => { @@ -98,7 +96,7 @@ test.describe("LanguageSwitcher", () => { }); test("Preselected", async ({ story }) => { - await expect(story.locators.component.trigger).toContainText( + await expect(story.locators.internal.trigger).toContainText( "中文" ); From 5605c153d98fe8e5c52736b7ed1896ee203a0c2c Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Thu, 14 May 2026 15:36:36 +0700 Subject: [PATCH 07/11] [BOOKINGSG-9309][GZ] separate dropdown panel to be on its own --- .../dropdown-panel.styles.ts | 47 ++++++++ src/language-switcher/dropdown-panel.tsx | 109 ++++++++++++++++++ .../dropdown-variant.styles.ts | 43 ------- src/language-switcher/dropdown-variant.tsx | 82 ++----------- 4 files changed, 167 insertions(+), 114 deletions(-) create mode 100644 src/language-switcher/dropdown-panel.styles.ts create mode 100644 src/language-switcher/dropdown-panel.tsx diff --git a/src/language-switcher/dropdown-panel.styles.ts b/src/language-switcher/dropdown-panel.styles.ts new file mode 100644 index 000000000..219563139 --- /dev/null +++ b/src/language-switcher/dropdown-panel.styles.ts @@ -0,0 +1,47 @@ +import { css } from "@linaria/core"; + +import { Border, Colour, Font, Radius, Spacing } from "../theme"; + +export const tokens = { + width: "--fds-internal-languageSwitcher-dropdown-width", +} as const; + +export const dropdownPanel = css` + ${tokens.width}: initial; + + width: var(${tokens.width}); + border-radius: ${Radius["sm"]}; + border: ${Border["width-010"]} ${Border["solid"]} ${Colour["border"]}; + background: ${Colour["bg"]}; + overflow: hidden; +`; + +export const dropdownList = css` + list-style: none; + margin: 0; + padding: ${Spacing["spacing-8"]}; +`; + +export { + baseIndicatorStyle, + selectedIndicator, +} from "../shared/dropdown-list/dropdown-list.styles"; + +export const dropdownItem = css` + align-items: center; + ${Font["body-md-regular"]} + color: ${Colour["text"]}; + + &:hover { + background: ${Colour["bg-hover-subtle"]}; + } +`; + +export const dropdownItemSelected = css` + background: transparent; + color: ${Colour["text-selected"]}; + + &:hover { + background: ${Colour["bg-hover"]}; + } +`; diff --git a/src/language-switcher/dropdown-panel.tsx b/src/language-switcher/dropdown-panel.tsx new file mode 100644 index 000000000..6ca7f486b --- /dev/null +++ b/src/language-switcher/dropdown-panel.tsx @@ -0,0 +1,109 @@ +import { TickIcon } from "@lifesg/react-icons/tick"; +import clsx from "clsx"; +import type React from "react"; +import { useRef } from "react"; + +import { + baseIndicatorStyle, + listItem, + listItemActive, + listItemActiveSelected, +} from "../shared/dropdown-list/dropdown-list.styles"; +import { useDropdownRender } from "../shared/dropdown-wrapper"; +import { useApplyStyle } from "../theme"; +import { mergeRefs } from "../util"; +import { ARIA_LABEL, LANGUAGE_CODES, LANGUAGE_DISPLAY_MAP } from "./data"; +import * as styles from "./dropdown-panel.styles"; +import type { LanguageSwitcherCode } from "./types"; + +interface DropdownPanelProps { + focusedIndex: number; + handleItemSelect: (code: LanguageSwitcherCode) => void; + handleListKeyDown: (event: React.KeyboardEvent) => void; + itemRefs: React.MutableRefObject<(HTMLLIElement | null)[]>; + listboxId: string; + selectedLanguage: LanguageSwitcherCode; + testId: string; +} + +export const DropdownPanel = ({ + focusedIndex, + handleItemSelect, + handleListKeyDown, + itemRefs, + listboxId, + selectedLanguage, + testId, +}: DropdownPanelProps) => { + const { + elementWidth, + styles: floatingStyles, + setFloatingRef, + getFloatingProps, + } = useDropdownRender(); + const panelRef = useRef(null); + + useApplyStyle(panelRef, { + [styles.tokens.width]: `${elementWidth}px`, + }); + + return ( +
+
    + {LANGUAGE_CODES.map((code, index) => { + const isSelected = code === selectedLanguage; + const isFocused = index === focusedIndex; + + return ( +
  • { + itemRefs.current[index] = element; + }} + role="option" + lang={code} + className={clsx( + styles.dropdownItem, + listItem, + isFocused && + isSelected && + listItemActiveSelected, + isFocused && !isSelected && listItemActive, + isSelected && styles.dropdownItemSelected + )} + aria-selected={isSelected} + tabIndex={isFocused ? 0 : -1} + onClick={() => handleItemSelect(code)} + data-testid={`${testId}--item-${code}`} + > + {isSelected ? ( + + ) : ( +
    + )} + {LANGUAGE_DISPLAY_MAP[code]} +
  • + ); + })} +
+
+ ); +}; diff --git a/src/language-switcher/dropdown-variant.styles.ts b/src/language-switcher/dropdown-variant.styles.ts index 72ab02d48..551707ccb 100644 --- a/src/language-switcher/dropdown-variant.styles.ts +++ b/src/language-switcher/dropdown-variant.styles.ts @@ -3,9 +3,6 @@ import { css } from "@linaria/core"; import { iconContainer } from "../shared/dropdown-list/expandable-element.styles"; import { Border, Colour, Font, Radius, Spacing } from "../theme"; -// ============================================================================= -// TRIGGER STYLES -// ============================================================================= export const expandableElement = css` min-width: 9rem; width: auto; @@ -41,43 +38,3 @@ export const languageIconWrapper = css` width: 1rem; } `; - -// ============================================================================= -// DROPDOWN STYLES -// ============================================================================= -export const dropdownPanel = css` - border-radius: ${Radius["sm"]}; - border: ${Border["width-010"]} ${Border["solid"]} ${Colour["border"]}; - background: ${Colour["bg"]}; - overflow: hidden; -`; - -export const dropdownList = css` - list-style: none; - margin: 0; - padding: ${Spacing["spacing-8"]}; -`; - -export { - baseIndicatorStyle, - selectedIndicator, -} from "../shared/dropdown-list/dropdown-list.styles"; - -export const dropdownItem = css` - align-items: center; - ${Font["body-md-regular"]} - color: ${Colour["text"]}; - - &:hover { - background: ${Colour["bg-hover-subtle"]}; - } -`; - -export const dropdownItemSelected = css` - background: transparent; - color: ${Colour["text-selected"]}; - - &:hover { - background: ${Colour["bg-hover"]}; - } -`; diff --git a/src/language-switcher/dropdown-variant.tsx b/src/language-switcher/dropdown-variant.tsx index d8cf987e4..f40e9a81d 100644 --- a/src/language-switcher/dropdown-variant.tsx +++ b/src/language-switcher/dropdown-variant.tsx @@ -1,20 +1,12 @@ import { LanguageIcon } from "@lifesg/react-icons/language"; -import { TickIcon } from "@lifesg/react-icons/tick"; -import clsx from "clsx"; import type React from "react"; import { useEffect, useRef, useState } from "react"; import { ExpandableElement } from "../shared/dropdown-list"; -import { - baseIndicatorStyle, - listItem, - listItemActive, - listItemActiveSelected, -} from "../shared/dropdown-list/dropdown-list.styles"; -import type { DropdownRenderProps } from "../shared/dropdown-wrapper"; import { ElementWithDropdown } from "../shared/dropdown-wrapper"; import { useId } from "../util"; import { ARIA_LABEL, LANGUAGE_CODES, LANGUAGE_DISPLAY_MAP } from "./data"; +import { DropdownPanel } from "./dropdown-panel"; import * as styles from "./dropdown-variant.styles"; import type { VariantInternalProps } from "./internal-types"; import type { LanguageSwitcherCode } from "./types"; @@ -139,68 +131,16 @@ export const DropdownVariant = ({ ); - const renderDropdown = ({ - elementWidth, - styles: floatingStyles, - setFloatingRef, - getFloatingProps, - }: DropdownRenderProps) => ( -
-
    - {LANGUAGE_CODES.map((code, index) => { - const isSelected = code === selectedLanguage; - const isFocused = index === focusedIndex; - return ( -
  • { - itemRefs.current[index] = el; - }} - role="option" - lang={code} - className={clsx( - styles.dropdownItem, - listItem, - isFocused && - isSelected && - listItemActiveSelected, - isFocused && !isSelected && listItemActive, - isSelected && styles.dropdownItemSelected - )} - aria-selected={isSelected} - tabIndex={isFocused ? 0 : -1} - onClick={() => handleItemSelect(code)} - data-testid={`${testId}--item-${code}`} - > - {isSelected ? ( - - ) : ( -
    - )} - {LANGUAGE_DISPLAY_MAP[code]} -
  • - ); - })} -
-
+ const renderDropdown = () => ( + ); // ========================================================================= From 8a31afc948f05529b50090a5fbab97cfb1d7e673 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Thu, 14 May 2026 15:39:46 +0700 Subject: [PATCH 08/11] [BOOKINGSG-9309][GZ] reorder csr component list --- .../src/app/components/[component]/[story]/page.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/e2e/nextjs-app/src/app/components/[component]/[story]/page.tsx b/e2e/nextjs-app/src/app/components/[component]/[story]/page.tsx index 9adc0e3f3..63f1e3317 100644 --- a/e2e/nextjs-app/src/app/components/[component]/[story]/page.tsx +++ b/e2e/nextjs-app/src/app/components/[component]/[story]/page.tsx @@ -10,15 +10,15 @@ import { */ const CSR_ONLY_COMPONENTS = new Set([ "badge", - "date-input", "date-range-input", - "input-group", + "date-input", + "select", "input-multi-select", "input-select", - "language-switcher", - "nested-multi-select", "nested-select", - "select", + "nested-multi-select", + "input-group", + "language-switcher", ]); export default async function Page({ From 44569c1708c6cf76b2642b16096c28ff0df4d515 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Thu, 14 May 2026 15:50:16 +0700 Subject: [PATCH 09/11] [BOOKINGSG-9309][GZ] remove default value for default --- .../dropdown-default.e2e.tsx | 1 - .../language-switcher/link-default.e2e.tsx | 1 - .../LanguageSwitcher-Link-Default--mount.png | Bin 4449 -> 4454 bytes 3 files changed, 2 deletions(-) diff --git a/e2e/nextjs-app/src/app/components/language-switcher/dropdown-default.e2e.tsx b/e2e/nextjs-app/src/app/components/language-switcher/dropdown-default.e2e.tsx index 2c4a512fa..78d2868f4 100644 --- a/e2e/nextjs-app/src/app/components/language-switcher/dropdown-default.e2e.tsx +++ b/e2e/nextjs-app/src/app/components/language-switcher/dropdown-default.e2e.tsx @@ -14,7 +14,6 @@ export default function Story() { diff --git a/e2e/nextjs-app/src/app/components/language-switcher/link-default.e2e.tsx b/e2e/nextjs-app/src/app/components/language-switcher/link-default.e2e.tsx index b86afed05..9739595a2 100644 --- a/e2e/nextjs-app/src/app/components/language-switcher/link-default.e2e.tsx +++ b/e2e/nextjs-app/src/app/components/language-switcher/link-default.e2e.tsx @@ -14,7 +14,6 @@ export default function Story() { diff --git a/e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Link-Default--mount.png b/e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Link-Default--mount.png index 20ecf6810593fc025de69ab40988d255f4c753ea..2c1e589c621306133e57ada82532c7c848475812 100644 GIT binary patch literal 4454 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 G7xO Date: Thu, 14 May 2026 15:58:16 +0700 Subject: [PATCH 10/11] [BOOKINGSG-9309][GZ] restructure e2e test and add dark mode --- ...cher-Dropdown-Default-Dark-Mode--mount.png | Bin 0 -> 2132 bytes ...tcher-Dropdown-Default-Dark-Mode--open.png | Bin 0 -> 10810 bytes .../language-switcher.e2e.spec.ts | 100 +++++++++++------- 3 files changed, 63 insertions(+), 37 deletions(-) create mode 100644 e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Dropdown-Default-Dark-Mode--mount.png create mode 100644 e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Dropdown-Default-Dark-Mode--open.png diff --git a/e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Dropdown-Default-Dark-Mode--mount.png b/e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Dropdown-Default-Dark-Mode--mount.png new file mode 100644 index 0000000000000000000000000000000000000000..3cd02c40cb50f02ab3fd22051263e38405a58b2d GIT binary patch literal 2132 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 KMNUMnLSTY*(-4OM literal 0 HcmV?d00001 diff --git a/e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Dropdown-Default-Dark-Mode--open.png b/e2e/tests/components/language-switcher/__screenshots__/chromium/LanguageSwitcher-Dropdown-Default-Dark-Mode--open.png new file mode 100644 index 0000000000000000000000000000000000000000..28974f37bce20160c0ba05d600db96f96695c345 GIT binary patch literal 10810 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 ax>~`uyW0|G&vSq)YL4gJ&f-pAyZLYNv`&x! literal 0 HcmV?d00001 diff --git a/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts b/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts index 8a3340fbe..91e36acbf 100644 --- a/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts +++ b/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts @@ -34,33 +34,36 @@ class StoryPage extends AbstractStoryPage { } const test = base.extend<{ story: StoryPage }>({ - story: async ({ page }, mountStory) => { + story: async ({ page }, use) => { const story = new StoryPage(page); - await mountStory(story); + await use(story); }, }); test.describe("LanguageSwitcher", () => { test.describe("Dropdown", () => { - test.beforeEach(async ({ story }) => { - await story.init("dropdown-default"); - }); - - test("Default", async ({ story }) => { - await compareScreenshot(story, "mount", { - locator: story.locators.languageSwitcher, + test.describe("", () => { + test.beforeEach(async ({ story }) => { + await story.init("dropdown-default"); }); - await expect(story.locators.languageSwitcher).toMatchAriaSnapshot(` + test("Default", async ({ story }) => { + await compareScreenshot(story, "mount", { + locator: story.locators.languageSwitcher, + }); + + await expect(story.locators.languageSwitcher) + .toMatchAriaSnapshot(` - combobox "Choose language / 选择语言 / Pilih bahasa / மொழியை தேர்ந்தெடுக்கவும், English" `); - await story.locators.internal.trigger.click(); - await compareScreenshot(story, "open", { - fullscreen: true, - }); + await story.locators.internal.trigger.click(); + await compareScreenshot(story, "open", { + fullscreen: true, + }); - await expect(story.locators.languageSwitcher).toMatchAriaSnapshot(` + await expect(story.locators.languageSwitcher) + .toMatchAriaSnapshot(` - combobox "Choose language / 选择语言 / Pilih bahasa / மொழியை தேர்ந்தெடுக்கவும், English" [expanded] - listbox "Choose language / 选择语言 / Pilih bahasa / மொழியை தேர்ந்தெடுக்கவும்": - option "English" [selected] @@ -68,26 +71,46 @@ test.describe("LanguageSwitcher", () => { - option "Melayu" - option "தமிழ்" `); - }); + }); - test("Keyboard Interaction", async ({ story }) => { - await story.locators.internal.trigger.focus(); - await story.page.keyboard.press("Enter"); - await expect(story.locators.internal.panel).toBeVisible(); + test("Keyboard Interaction", async ({ story }) => { + await story.locators.internal.trigger.focus(); + await story.page.keyboard.press("Enter"); + await expect(story.locators.internal.panel).toBeVisible(); - await story.page.keyboard.press("ArrowDown"); - await expect(story.getDropdownOption("中文")).toBeFocused(); + await story.page.keyboard.press("ArrowDown"); + await expect(story.getDropdownOption("中文")).toBeFocused(); - await story.page.keyboard.press("End"); - await expect(story.getDropdownOption("தமிழ்")).toBeFocused(); + await story.page.keyboard.press("End"); + await expect(story.getDropdownOption("தமிழ்")).toBeFocused(); - await story.page.keyboard.press("Home"); - await expect(story.getDropdownOption("English")).toBeFocused(); + await story.page.keyboard.press("Home"); + await expect(story.getDropdownOption("English")).toBeFocused(); - await story.page.keyboard.press("ArrowDown"); - await story.page.keyboard.press("Enter"); - await expect(story.locators.internal.panel).not.toBeVisible(); - await expect(story.locators.internal.trigger).toContainText("中文"); + await story.page.keyboard.press("ArrowDown"); + await story.page.keyboard.press("Enter"); + await expect(story.locators.internal.panel).not.toBeVisible(); + await expect(story.locators.internal.trigger).toContainText( + "中文" + ); + }); + }); + + test.describe("", () => { + test.beforeEach(async ({ story }) => { + await story.init("dropdown-default", { mode: "dark" }); + }); + + test("Default Dark Mode", async ({ story }) => { + await compareScreenshot(story, "mount", { + locator: story.locators.languageSwitcher, + }); + + await story.locators.internal.trigger.click(); + await compareScreenshot(story, "open", { + fullscreen: true, + }); + }); }); test.describe("", () => { @@ -108,12 +131,14 @@ test.describe("LanguageSwitcher", () => { }); test.describe("Link", () => { - test.beforeEach(async ({ story }) => { - await story.init("link-default"); - }); + test.describe("", () => { + test.beforeEach(async ({ story }) => { + await story.init("link-default"); + }); - test("Default", async ({ story }) => { - await expect(story.locators.languageSwitcher).toMatchAriaSnapshot(` + test("Default", async ({ story }) => { + await expect(story.locators.languageSwitcher) + .toMatchAriaSnapshot(` - group "Choose language / 选择语言 / Pilih bahasa / மொழியை தேர்ந்தெடுக்கவும்": - listitem: - button "English" [pressed] @@ -125,8 +150,9 @@ test.describe("LanguageSwitcher", () => { - button "தமிழ்" `); - await compareScreenshot(story, "mount", { - locator: story.locators.languageSwitcher, + await compareScreenshot(story, "mount", { + locator: story.locators.languageSwitcher, + }); }); }); From 33d04346fad28bf5127ca023ca4d9481fab52cb5 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Thu, 14 May 2026 16:02:59 +0700 Subject: [PATCH 11/11] [BOOKINGSG-9309][GZ] add escape key to assert dropdown is collapsed --- .../components/language-switcher/dropdown-default.e2e.tsx | 5 ++++- .../app/components/language-switcher/link-default.e2e.tsx | 5 ++++- .../language-switcher/language-switcher.e2e.spec.ts | 5 +++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/e2e/nextjs-app/src/app/components/language-switcher/dropdown-default.e2e.tsx b/e2e/nextjs-app/src/app/components/language-switcher/dropdown-default.e2e.tsx index 78d2868f4..1af17bc9d 100644 --- a/e2e/nextjs-app/src/app/components/language-switcher/dropdown-default.e2e.tsx +++ b/e2e/nextjs-app/src/app/components/language-switcher/dropdown-default.e2e.tsx @@ -7,13 +7,16 @@ import { import { useState } from "react"; export default function Story() { - const [language, setLanguage] = useState("en"); + const [language, setLanguage] = useState( + undefined + ); return (
diff --git a/e2e/nextjs-app/src/app/components/language-switcher/link-default.e2e.tsx b/e2e/nextjs-app/src/app/components/language-switcher/link-default.e2e.tsx index 9739595a2..78ccba65c 100644 --- a/e2e/nextjs-app/src/app/components/language-switcher/link-default.e2e.tsx +++ b/e2e/nextjs-app/src/app/components/language-switcher/link-default.e2e.tsx @@ -7,13 +7,16 @@ import { import { useState } from "react"; export default function Story() { - const [language, setLanguage] = useState("en"); + const [language, setLanguage] = useState( + undefined + ); return (
diff --git a/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts b/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts index 91e36acbf..b24a6d60f 100644 --- a/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts +++ b/e2e/tests/components/language-switcher/language-switcher.e2e.spec.ts @@ -93,6 +93,11 @@ test.describe("LanguageSwitcher", () => { await expect(story.locators.internal.trigger).toContainText( "中文" ); + + await story.page.keyboard.press("Enter"); + await expect(story.locators.internal.panel).toBeVisible(); + await story.page.keyboard.press("Escape"); + await expect(story.locators.internal.panel).not.toBeVisible(); }); });