mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-04-26 17:27:09 -05:00
Initial user page e2e tests
This commit is contained in:
parent
74f6d28c39
commit
23e78f7033
|
|
@ -2,6 +2,7 @@ import clsx from "clsx";
|
||||||
|
|
||||||
export function Input({
|
export function Input({
|
||||||
name,
|
name,
|
||||||
|
id,
|
||||||
className,
|
className,
|
||||||
minLength,
|
minLength,
|
||||||
maxLength,
|
maxLength,
|
||||||
|
|
@ -11,10 +12,12 @@ export function Input({
|
||||||
pattern,
|
pattern,
|
||||||
list,
|
list,
|
||||||
"data-cy": dataCy,
|
"data-cy": dataCy,
|
||||||
|
"aria-label": ariaLabel,
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
}: {
|
}: {
|
||||||
name?: string;
|
name?: string;
|
||||||
|
id?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
minLength?: number;
|
minLength?: number;
|
||||||
maxLength?: number;
|
maxLength?: number;
|
||||||
|
|
@ -24,6 +27,7 @@ export function Input({
|
||||||
pattern?: string;
|
pattern?: string;
|
||||||
list?: string;
|
list?: string;
|
||||||
"data-cy"?: string;
|
"data-cy"?: string;
|
||||||
|
"aria-label"?: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -32,6 +36,7 @@ export function Input({
|
||||||
{leftAddon ? <div className="input-addon">{leftAddon}</div> : null}
|
{leftAddon ? <div className="input-addon">{leftAddon}</div> : null}
|
||||||
<input
|
<input
|
||||||
name={name}
|
name={name}
|
||||||
|
id={id}
|
||||||
minLength={minLength}
|
minLength={minLength}
|
||||||
maxLength={maxLength}
|
maxLength={maxLength}
|
||||||
defaultValue={defaultValue}
|
defaultValue={defaultValue}
|
||||||
|
|
@ -40,6 +45,7 @@ export function Input({
|
||||||
data-cy={dataCy}
|
data-cy={dataCy}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
aria-label={ariaLabel}
|
||||||
/>
|
/>
|
||||||
{icon}
|
{icon}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,7 @@ function CustomUrlInput({
|
||||||
<Label htmlFor="customUrl">{t("user:customUrl")}</Label>
|
<Label htmlFor="customUrl">{t("user:customUrl")}</Label>
|
||||||
<Input
|
<Input
|
||||||
name="customUrl"
|
name="customUrl"
|
||||||
|
id="customUrl"
|
||||||
leftAddon="https://sendou.ink/u/"
|
leftAddon="https://sendou.ink/u/"
|
||||||
maxLength={USER.CUSTOM_URL_MAX_LENGTH}
|
maxLength={USER.CUSTOM_URL_MAX_LENGTH}
|
||||||
defaultValue={parentRouteData.customUrl ?? undefined}
|
defaultValue={parentRouteData.customUrl ?? undefined}
|
||||||
|
|
@ -235,6 +236,7 @@ function InGameNameInputs({
|
||||||
<Input
|
<Input
|
||||||
className="u-edit__in-game-name-text"
|
className="u-edit__in-game-name-text"
|
||||||
name="inGameNameText"
|
name="inGameNameText"
|
||||||
|
aria-label="In game name"
|
||||||
maxLength={USER.IN_GAME_NAME_TEXT_MAX_LENGTH}
|
maxLength={USER.IN_GAME_NAME_TEXT_MAX_LENGTH}
|
||||||
defaultValue={inGameNameParts?.[0]}
|
defaultValue={inGameNameParts?.[0]}
|
||||||
/>
|
/>
|
||||||
|
|
@ -242,6 +244,7 @@ function InGameNameInputs({
|
||||||
<Input
|
<Input
|
||||||
className="u-edit__in-game-name-discriminator"
|
className="u-edit__in-game-name-discriminator"
|
||||||
name="inGameNameDiscriminator"
|
name="inGameNameDiscriminator"
|
||||||
|
aria-label="In game name discriminator"
|
||||||
maxLength={USER.IN_GAME_NAME_DISCRIMINATOR_LENGTH}
|
maxLength={USER.IN_GAME_NAME_DISCRIMINATOR_LENGTH}
|
||||||
pattern="[0-9]{4}"
|
pattern="[0-9]{4}"
|
||||||
defaultValue={inGameNameParts?.[1]}
|
defaultValue={inGameNameParts?.[1]}
|
||||||
|
|
@ -265,8 +268,9 @@ function SensSelects({
|
||||||
return (
|
return (
|
||||||
<div className="stack horizontal md">
|
<div className="stack horizontal md">
|
||||||
<div>
|
<div>
|
||||||
<Label>{t("user:stickSens")}</Label>
|
<Label htmlFor="stickSens">{t("user:stickSens")}</Label>
|
||||||
<select
|
<select
|
||||||
|
id="stickSens"
|
||||||
name="stickSens"
|
name="stickSens"
|
||||||
defaultValue={parentRouteData.stickSens ?? undefined}
|
defaultValue={parentRouteData.stickSens ?? undefined}
|
||||||
className="u-edit__sens-select"
|
className="u-edit__sens-select"
|
||||||
|
|
@ -281,8 +285,9 @@ function SensSelects({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Label>{t("user:motionSens")}</Label>
|
<Label htmlFor="motionSens">{t("user:motionSens")}</Label>
|
||||||
<select
|
<select
|
||||||
|
id="motionSens"
|
||||||
name="motionSens"
|
name="motionSens"
|
||||||
defaultValue={parentRouteData.motionSens ?? undefined}
|
defaultValue={parentRouteData.motionSens ?? undefined}
|
||||||
className="u-edit__sens-select"
|
className="u-edit__sens-select"
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,9 @@ export default function UserInfoPage() {
|
||||||
{data.country ? (
|
{data.country ? (
|
||||||
<div className="u__country">
|
<div className="u__country">
|
||||||
<span className="u__country-emoji">{data.country.emoji}</span>{" "}
|
<span className="u__country-emoji">{data.country.emoji}</span>{" "}
|
||||||
<span className="u__country-name">{data.country.name}</span>
|
<span className="u__country-name" data-testid="country">
|
||||||
|
{data.country.name}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="u__socials">
|
<div className="u__socials">
|
||||||
|
|
|
||||||
|
|
@ -18,3 +18,11 @@ export async function navigate({ page, url }: { page: Page; url: string }) {
|
||||||
await page.goto(url);
|
await page.goto(url);
|
||||||
page.getByTestId("hydrated");
|
page.getByTestId("hydrated");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function seed(page: Page) {
|
||||||
|
return page.request.post("/seed");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function impersonate(page: Page, userId = 1) {
|
||||||
|
return page.request.post(`/auth/impersonate?id=${userId}`);
|
||||||
|
}
|
||||||
|
|
|
||||||
60
e2e/user-page.spec.ts
Normal file
60
e2e/user-page.spec.ts
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { expect, type Page, test } from "@playwright/test";
|
||||||
|
import { ADMIN_DISCORD_ID } from "~/constants";
|
||||||
|
import { impersonate, navigate, seed } from "~/utils/playwright";
|
||||||
|
import { userPage } from "~/utils/urls";
|
||||||
|
|
||||||
|
const goToEditPage = (page: Page) =>
|
||||||
|
page.getByText("Edit", { exact: true }).click();
|
||||||
|
const submitEditForm = (page: Page) =>
|
||||||
|
page.getByText("Save", { exact: true }).click();
|
||||||
|
|
||||||
|
test.describe("User page", () => {
|
||||||
|
test("edits user profile", async ({ page }) => {
|
||||||
|
await seed(page);
|
||||||
|
await impersonate(page);
|
||||||
|
await navigate({
|
||||||
|
page,
|
||||||
|
url: userPage({ discordId: ADMIN_DISCORD_ID, customUrl: "sendou" }),
|
||||||
|
});
|
||||||
|
|
||||||
|
const country = page.getByTestId("country");
|
||||||
|
|
||||||
|
await expect(country).toHaveText("Finland");
|
||||||
|
await goToEditPage(page);
|
||||||
|
|
||||||
|
await page
|
||||||
|
.getByRole("textbox", { name: "In game name", exact: true })
|
||||||
|
.fill("Lean");
|
||||||
|
await page
|
||||||
|
.getByRole("textbox", { name: "In game name discriminator" })
|
||||||
|
.fill("1234");
|
||||||
|
await page.getByLabel("R-stick sens").selectOption("0");
|
||||||
|
await page.getByLabel("Motion sens").selectOption("-50");
|
||||||
|
await page.getByLabel("Country").selectOption("SE");
|
||||||
|
await page.getByLabel("Bio").type("My awesome bio");
|
||||||
|
await submitEditForm(page);
|
||||||
|
|
||||||
|
await expect(country).toHaveText("Sweden");
|
||||||
|
await page.getByText("My awesome bio").isVisible();
|
||||||
|
await page.getByText("Lean#1234").isVisible();
|
||||||
|
await page.getByText("Stick 0 / Motion -5").isVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("has redirecting custom url", async ({ page }) => {
|
||||||
|
await seed(page);
|
||||||
|
await impersonate(page);
|
||||||
|
await navigate({
|
||||||
|
page,
|
||||||
|
url: userPage({ discordId: ADMIN_DISCORD_ID }),
|
||||||
|
});
|
||||||
|
|
||||||
|
// got redirected
|
||||||
|
await expect(page).toHaveURL(/sendou/);
|
||||||
|
|
||||||
|
await goToEditPage(page);
|
||||||
|
await page.getByLabel("Custom URL").fill("lean");
|
||||||
|
await submitEditForm(page);
|
||||||
|
|
||||||
|
await expect(page).toHaveURL(/lean/);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
"test:unit": "uvu -r tsm -r tsconfig-paths/register -i e2e",
|
"test:unit": "uvu -r tsm -r tsconfig-paths/register -i e2e",
|
||||||
"test:e2e": "npx playwright test",
|
"test:e2e": "npx playwright test",
|
||||||
"checks": "npm run test:unit && npm run lint:styles && npm run lint:ts && npm run prettier:check && npm run typecheck",
|
"checks": "npm run test:unit && npm run lint:styles && npm run lint:ts && npm run prettier:check && npm run typecheck",
|
||||||
"cf": "npm run test:unit && npm run check-translation-jsons && npm run lint:styles -- --fix && npm run lint:ts -- --fix && npm run prettier:write && npm run typecheck"
|
"cf": "npm run test:unit && npm run check-translation-jsons && npm run lint:styles -- --fix && npm run lint:ts -- --fix && npm run prettier:write && npm run typecheck && npm run test:e2e"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@faker-js/faker": "^7.6.0",
|
"@faker-js/faker": "^7.6.0",
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ const config: PlaywrightTestConfig = {
|
||||||
forbidOnly: !!process.env["CI"],
|
forbidOnly: !!process.env["CI"],
|
||||||
/* Retry on CI only */
|
/* Retry on CI only */
|
||||||
retries: process.env["CI"] ? 2 : 0,
|
retries: process.env["CI"] ? 2 : 0,
|
||||||
/* Opt out of parallel tests on CI. */
|
/* Opt out of parallel tests. */
|
||||||
workers: process.env["CI"] ? 1 : undefined,
|
workers: 1,
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
reporter: "list",
|
reporter: "list",
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user