Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions e2e/code-snippet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,16 @@ test.describe("CodeSnippet", () => {
await expect(snippet).not.toHaveClass(/bx--snippet--expand/);
await expect(showMore).toBeVisible();
});

test("multi snippet expanded content is visible and has greater height", async ({
page,
}) => {
const snippet = page.getByTestId("snippet-multi");
const codeBlock = snippet.locator("code");
const collapsedHeight = (await codeBlock.boundingBox())?.height ?? 0;
await snippet.getByRole("button", { name: /show more/i }).click();
await expect(snippet).toHaveClass(/bx--snippet--expand/);
const expandedHeight = (await codeBlock.boundingBox())?.height ?? 0;
expect(expandedHeight).toBeGreaterThanOrEqual(collapsedHeight);
});
});
23 changes: 20 additions & 3 deletions e2e/combobox.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { expect, test } from "@playwright/test";

// Prefer getByTestId for reliable selectors (per CONTRIBUTING.md).
// The ComboBox passes data-testid to the input via $$restProps.

test.describe("ComboBox", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/combobox.html");
Expand Down Expand Up @@ -56,4 +53,24 @@ test.describe("ComboBox", () => {
await expect(page.getByRole("option", { name: "Slack" })).toBeVisible();
await expect(page.getByRole("option", { name: "Email" })).not.toBeVisible();
});

test("opens menu with Enter and selects with Arrow Down + Enter", async ({
page,
}) => {
const combobox = page.getByTestId("combobox-contact");
await combobox.focus();
await page.keyboard.press("Enter");
await expect(page.locator(".bx--list-box__menu")).toBeVisible();
await page.keyboard.press("ArrowDown");
await page.keyboard.press("Enter");
await expect(combobox).toHaveValue("Slack");
});

test("closes menu with Escape", async ({ page }) => {
const combobox = page.getByTestId("combobox-contact");
await combobox.click();
await expect(page.locator(".bx--list-box__menu")).toBeVisible();
await page.keyboard.press("Escape");
await expect(page.locator(".bx--list-box__menu")).not.toBeVisible();
});
});
36 changes: 36 additions & 0 deletions e2e/composed-modal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,40 @@ test.describe("ComposedModal", () => {
await page.getByTestId("close-modal").click();
await expect(page.locator(".bx--modal")).not.toHaveClass(/is-visible/);
});

test("closes when Escape is pressed", async ({ page }) => {
await page.getByTestId("open-modal").click();
await expect(page.locator(".bx--modal")).toHaveClass(/is-visible/);
await page.waitForTimeout(400);

await page.getByTestId("modal-primary-focus").focus();
await page.keyboard.press("Escape");
await expect(page.locator(".bx--modal")).not.toHaveClass(/is-visible/);
});

test("primary focus element is focusable when opened", async ({ page }) => {
await page.getByTestId("open-modal").click();
await expect(page.locator(".bx--modal")).toHaveClass(/is-visible/);

const primaryFocus = page.getByTestId("modal-primary-focus");
await primaryFocus.focus();
await expect(primaryFocus).toBeFocused();
});

test("traps focus with Tab", async ({ page }) => {
await page.getByTestId("open-modal").click();
await expect(page.locator(".bx--modal")).toHaveClass(/is-visible/);

const primaryFocus = page.getByTestId("modal-primary-focus");
await primaryFocus.focus();

await page.keyboard.press("Tab");
await expect(page.getByTestId("close-modal")).toBeFocused();

await page.keyboard.press("Tab");
await expect(page.locator(".bx--modal-close")).toBeFocused();

await page.keyboard.press("Tab");
await expect(primaryFocus).toBeFocused();
});
});
137 changes: 131 additions & 6 deletions e2e/date-picker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ test.describe("DatePicker", () => {
});

test("renders with placeholder", async ({ page }) => {
await expect(page.getByPlaceholder("mm/dd/yyyy")).toBeVisible();
await expect(
page.getByTestId("date-picker-single").getByPlaceholder("mm/dd/yyyy"),
).toBeVisible();
});

test("can be located by getByLabel when labelText is set", async ({
Expand All @@ -31,14 +33,20 @@ test.describe("DatePicker", () => {
test("opens calendar on click", async ({ page }) => {
const input = page.getByLabel("Meeting date");
await input.click();
const calendar = page.getByLabel("calendar-container");
const calendar = page
.getByTestId("date-picker-single")
.getByLabel("calendar-container");
await expect(calendar).toBeVisible();
});

test("opens calendar via calendar icon", async ({ page }) => {
const calendarIcon = page.locator(".bx--date-picker__icon");
const calendarIcon = page
.getByTestId("date-picker-single")
.locator(".bx--date-picker__icon");
await calendarIcon.click();
const calendar = page.getByLabel("calendar-container");
const calendar = page
.getByTestId("date-picker-single")
.getByLabel("calendar-container");
await expect(calendar).toBeVisible();
});

Expand All @@ -52,7 +60,9 @@ test.describe("DatePicker", () => {
const input = page.getByLabel("Meeting date");
await input.click();

const calendar = page.getByLabel("calendar-container");
const calendar = page
.getByTestId("date-picker-single")
.getByLabel("calendar-container");
await expect(calendar).toBeVisible();

// Fixture uses defaultDate "03/15/2024" so March 2024 is shown.
Expand All @@ -69,7 +79,9 @@ test.describe("DatePicker", () => {
const input = page.getByLabel("Meeting date");
await input.click();

const calendar = page.getByLabel("calendar-container");
const calendar = page
.getByTestId("date-picker-single")
.getByLabel("calendar-container");
await expect(calendar).toBeVisible();

const day15 = calendar
Expand All @@ -79,4 +91,117 @@ test.describe("DatePicker", () => {

await expect(input).toHaveValue("03/15/2024");
});

test("calendar receives keyboard input after open", async ({ page }) => {
const input = page.getByLabel("Meeting date");
await input.click();
const calendar = page
.getByTestId("date-picker-single")
.getByLabel("calendar-container");
await expect(calendar).toBeVisible();
await page.keyboard.press("ArrowRight");
await page.keyboard.press("ArrowRight");
await page.keyboard.press("Enter");
await expect(input).not.toHaveValue("");
});

test("Escape closes calendar", async ({ page }) => {
const input = page.getByLabel("Meeting date");
await input.click();
const calendar = page
.getByTestId("date-picker-single")
.getByLabel("calendar-container");
await expect(calendar).toHaveClass(/open/);
await input.focus();
await page.keyboard.press("Escape");
await expect(calendar).not.toHaveClass(/open/);
});

test("click outside closes calendar", async ({ page }) => {
const input = page.getByLabel("Meeting date");
await input.click();
const calendar = page
.getByTestId("date-picker-single")
.getByLabel("calendar-container");
await expect(calendar).toHaveClass(/open/);
await page.getByTestId("outside-date-picker").click();
await expect(calendar).not.toHaveClass(/open/);
});

test("min/max: disabled days not selectable", async ({ page }) => {
const input = page.getByLabel("Meeting date");
await input.click();
const calendar = page
.getByTestId("date-picker-single")
.getByLabel("calendar-container");
await expect(calendar).toBeVisible();
// With min 03/01 and max 03/31, days outside March get .flatpickr-disabled
const disabledDay = calendar
.locator(".flatpickr-day.flatpickr-disabled")
.first();
await expect(disabledDay).toBeVisible();
const initialValue = await input.inputValue();
await disabledDay.click();
await expect(input).toHaveValue(initialValue);
});

test("range: renders two inputs", async ({ page }) => {
const startInput = page.getByLabel("Start date");
const endInput = page.getByLabel("End date");
await expect(startInput).toBeVisible();
await expect(endInput).toBeVisible();
await expect(startInput).toHaveAttribute("placeholder", "mm/dd/yyyy");
await expect(endInput).toHaveAttribute("placeholder", "mm/dd/yyyy");
});

test("range: opens calendar from start input", async ({ page }) => {
await page.getByTestId("date-picker-range-start").click();
const calendar = page
.getByTestId("date-picker-range")
.getByLabel("calendar-container");
await expect(calendar).toBeVisible();
});

test("range: opens calendar from end input", async ({ page }) => {
await page.getByTestId("date-picker-range-end").click();
const calendar = page
.getByTestId("date-picker-range")
.getByLabel("calendar-container");
await expect(calendar).toBeVisible();
});

test("range: selecting range updates both inputs", async ({ page }) => {
await page.getByTestId("date-picker-range-start").click();
const calendar = page
.getByTestId("date-picker-range")
.getByLabel("calendar-container");
await expect(calendar).toBeVisible();

const day10 = calendar
.locator(".flatpickr-day:not(.prev-month):not(.next-month)")
.filter({ hasText: /^10$/ });
const day20 = calendar
.locator(".flatpickr-day:not(.prev-month):not(.next-month)")
.filter({ hasText: /^20$/ });
await day10.click();
await day20.click();

await expect(page.getByTestId("date-picker-range-start")).toHaveValue(
"03/10/2024",
);
await expect(page.getByTestId("date-picker-range-end")).toHaveValue(
"03/20/2024",
);
});

test("range: Escape closes calendar", async ({ page }) => {
await page.getByTestId("date-picker-range-start").click();
const calendar = page
.getByTestId("date-picker-range")
.getByLabel("calendar-container");
await expect(calendar).toHaveClass(/open/);
await page.getByTestId("date-picker-range-start").focus();
await page.keyboard.press("Escape");
await expect(calendar).not.toHaveClass(/open/);
});
});
27 changes: 27 additions & 0 deletions e2e/dropdown.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,31 @@ test.describe("Dropdown", () => {
await page.getByRole("option", { name: "Slack" }).click();
await expect(trigger).toContainText("Slack");
});

test("opens menu with Enter key", async ({ page }) => {
const trigger = page.getByTestId("dropdown-contact").getByRole("button");
await trigger.focus();
await page.keyboard.press("Enter");
await expect(page.getByRole("listbox")).toBeVisible();
});

test("opens menu with ArrowDown and navigates with Arrow keys", async ({
page,
}) => {
const trigger = page.getByTestId("dropdown-contact").getByRole("button");
await trigger.focus();
await page.keyboard.press("ArrowDown");
await expect(page.getByRole("listbox")).toBeVisible();
await page.keyboard.press("ArrowDown");
await page.keyboard.press("Enter");
await expect(trigger).toContainText("Email");
});

test("closes menu with Escape", async ({ page }) => {
const trigger = page.getByTestId("dropdown-contact").getByRole("button");
await trigger.click();
await expect(page.getByRole("listbox")).toBeVisible();
await page.keyboard.press("Escape");
await expect(page.getByRole("listbox")).not.toBeVisible();
});
});
10 changes: 9 additions & 1 deletion e2e/fixtures/ComposedModalFixture.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@

<ComposedModal bind:open>
<ModalHeader title="Modal title" />
<ModalBody> <p data-testid="modal-body">Modal content</p> </ModalBody>
<ModalBody>
<p data-testid="modal-body">Modal content</p>
<input
type="text"
data-modal-primary-focus
data-testid="modal-primary-focus"
aria-label="Primary focus input"
>
</ModalBody>
<ModalFooter>
<Button data-testid="close-modal" on:click={() => (open = false)}>
Close
Expand Down
61 changes: 45 additions & 16 deletions e2e/fixtures/DatePickerFixture.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,48 @@
import { DatePicker, DatePickerInput } from "carbon-components-svelte";
</script>

<DatePicker
datePickerType="single"
value="03/15/2024"
flatpickrProps={{
static: true,
minDate: "03/01/2024",
maxDate: "03/31/2024",
}}
on:change
>
<DatePickerInput
data-testid="date-picker-meeting"
labelText="Meeting date"
placeholder="mm/dd/yyyy"
/>
</DatePicker>
<div data-testid="date-picker-single">
<DatePicker
datePickerType="single"
value="03/15/2024"
flatpickrProps={{
static: true,
minDate: "03/01/2024",
maxDate: "03/31/2024",
}}
on:change
>
<DatePickerInput
data-testid="date-picker-meeting"
labelText="Meeting date"
placeholder="mm/dd/yyyy"
/>
</DatePicker>
</div>

<div data-testid="outside-date-picker" style="margin-top: 1rem; padding: 1rem;">
Click target (outside pickers)
</div>

<div data-testid="date-picker-range">
<DatePicker
datePickerType="range"
flatpickrProps={{
static: true,
minDate: "03/01/2024",
maxDate: "03/31/2024",
}}
on:change
>
<DatePickerInput
data-testid="date-picker-range-start"
labelText="Start date"
placeholder="mm/dd/yyyy"
/>
<DatePickerInput
data-testid="date-picker-range-end"
labelText="End date"
placeholder="mm/dd/yyyy"
/>
</DatePicker>
</div>
Loading
Loading