121 lines
3.7 KiB
TypeScript
121 lines
3.7 KiB
TypeScript
// @vitest-environment jsdom
|
|
|
|
import { render, screen } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { useState } from "react";
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
Button,
|
|
Drawer,
|
|
Pagination,
|
|
Tabs,
|
|
} from "../../src/presentation/design-system/index.ts";
|
|
import {
|
|
LocaleProvider,
|
|
useLocale,
|
|
type SupportedLocale,
|
|
} from "../../src/presentation/i18n/index.ts";
|
|
|
|
function LocaleHarness() {
|
|
const { direction, locale, message, setLocale } = useLocale();
|
|
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
return (
|
|
<>
|
|
<label htmlFor="test-locale">{message("shell.locale")}</label>
|
|
<select
|
|
id="test-locale"
|
|
onChange={(event) =>
|
|
setLocale(event.currentTarget.value as SupportedLocale)
|
|
}
|
|
value={locale}
|
|
>
|
|
<option value="ko-KR">한국어</option>
|
|
<option value="en-US">English</option>
|
|
<option value="ar-EG">RTL</option>
|
|
</select>
|
|
<output>{`${locale}:${direction}`}</output>
|
|
<Button onClick={() => setDrawerOpen(true)}>
|
|
{message("shell.menu")}
|
|
</Button>
|
|
<Drawer
|
|
closeLabel={message("shell.closeMenu")}
|
|
onClose={() => setDrawerOpen(false)}
|
|
open={drawerOpen}
|
|
title={message("shell.menu")}
|
|
>
|
|
content
|
|
</Drawer>
|
|
</>
|
|
);
|
|
}
|
|
|
|
describe("locale provider runtime", () => {
|
|
it("switches copy and synchronizes the document language and direction", async () => {
|
|
const user = userEvent.setup();
|
|
render(
|
|
<LocaleProvider>
|
|
<LocaleHarness />
|
|
</LocaleProvider>,
|
|
);
|
|
|
|
expect(document.documentElement).toHaveAttribute("lang", "ko-KR");
|
|
await user.selectOptions(screen.getByLabelText("언어"), "en-US");
|
|
expect(screen.getByLabelText("Language")).toHaveValue("en-US");
|
|
expect(document.documentElement).toHaveAttribute("lang", "en-US");
|
|
expect(document.documentElement).toHaveAttribute("dir", "ltr");
|
|
|
|
await user.selectOptions(screen.getByLabelText("Language"), "ar-EG");
|
|
expect(document.documentElement).toHaveAttribute("lang", "ar-EG");
|
|
expect(document.documentElement).toHaveAttribute("dir", "rtl");
|
|
await user.click(screen.getByRole("button", { name: "Menu" }));
|
|
expect(screen.getByRole("dialog", { name: "Menu" })).toHaveAttribute(
|
|
"open",
|
|
);
|
|
});
|
|
|
|
it("reverses horizontal tab focus semantics in RTL", async () => {
|
|
const user = userEvent.setup();
|
|
render(
|
|
<LocaleProvider initialLocale="ar-EG">
|
|
<Tabs
|
|
activation="manual"
|
|
label="sections"
|
|
tabs={[
|
|
{ id: "one", label: "One", panel: "One panel" },
|
|
{ id: "two", label: "Two", panel: "Two panel" },
|
|
{ id: "three", label: "Three", panel: "Three panel" },
|
|
]}
|
|
/>
|
|
</LocaleProvider>,
|
|
);
|
|
const first = screen.getByRole("tab", { name: "One" });
|
|
first.focus();
|
|
await user.keyboard("{ArrowRight}");
|
|
expect(screen.getByRole("tab", { name: "Three" })).toHaveFocus();
|
|
await user.keyboard("{ArrowLeft}");
|
|
expect(first).toHaveFocus();
|
|
});
|
|
|
|
it("keeps pagination semantics while direction-aware icons remain decorative", () => {
|
|
render(
|
|
<LocaleProvider initialLocale="ar-EG">
|
|
<Pagination
|
|
label="pages"
|
|
nextLabel="Next page"
|
|
onChange={() => {}}
|
|
page={2}
|
|
pageCount={3}
|
|
pageLabel={(page) => `Page ${page}`}
|
|
previousLabel="Previous page"
|
|
/>
|
|
</LocaleProvider>,
|
|
);
|
|
expect(
|
|
screen.getByRole("button", { name: "Previous page" }),
|
|
).toBeEnabled();
|
|
expect(screen.getByRole("button", { name: "Next page" })).toBeEnabled();
|
|
expect(screen.queryByRole("img")).not.toBeInTheDocument();
|
|
});
|
|
});
|