chore: import upstream snapshot with attribution
i18n - Build Validation / Validate i18n Builds (24) (push) Has been cancelled
CI - Node.js / Lint (24) (push) Has been cancelled
CI - Node.js / Build (24) (push) Has been cancelled
CI - Node.js / Test (24) (push) Has been cancelled
CI - Node.js / Test - Upcoming Changes (24) (push) Has been cancelled
CI - Node.js / Test - i18n (italian, 24) (push) Has been cancelled
CI - Node.js / Test - i18n (portuguese, 24) (push) Has been cancelled
CD - Docker - GHCR Images / Build and Push Images (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 11:55:53 +08:00
commit dde272c4b8
19405 changed files with 2730632 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
import { BrowserContext } from '@playwright/test';
export async function addGrowthbookCookie({
context,
variation
}: {
context: BrowserContext;
variation: string;
}) {
await context.addCookies([
{
name: 'gbuuid',
value: variation,
// Weirdly, it seems necessary to prefix the domain with a dot. This seems
// to be a peculiarity of Playwright.
domain: process.env.COOKIE_DOMAIN || 'localhost',
path: '/',
expires: Math.floor(Date.now() / 1000) + 400 * 24 * 60 * 60 // 400 days from now
}
]);
}
+4
View File
@@ -0,0 +1,4 @@
import { expect, type Page } from '@playwright/test';
export const alertToBeVisible = async (page: Page, text: string) =>
await expect(page.getByRole('alert').filter({ hasText: text })).toBeVisible();
+41
View File
@@ -0,0 +1,41 @@
import { type Page } from '@playwright/test';
export const getEditors = (page: Page) => {
return page.getByRole('textbox', { name: /editor content/i });
};
export const focusEditor = async ({
page,
isMobile
}: {
page: Page;
isMobile: boolean;
}) => {
if (isMobile) {
const codeBtn = page.getByRole('tab', { name: 'Code' });
// The outer div intercepts the click action of its children,
// preventing Playwright from verifying if the children actually receive the click.
// In reality, the children do receive the click, so we bypass that check here.
await codeBtn.click({ force: true });
}
await getEditors(page).focus();
};
export async function clearEditor({
page,
browserName,
isMobile = false
}: {
page: Page;
browserName: string;
isMobile?: boolean;
}) {
// TODO: replace with ControlOrMeta when it's supported
if (browserName === 'webkit' && !isMobile) {
await page.keyboard.press('Meta+a');
} else {
await page.keyboard.press('Control+a');
}
await page.keyboard.press('Backspace');
}
+33
View File
@@ -0,0 +1,33 @@
type Email = {
Subject: string;
ID: string;
From: { Address: string; Name: string };
To: Array<{ Address: string; Name: string }>;
};
type AllEmails = {
messages: Email[];
total: number;
count: number;
};
const host = process.env.MAILPIT_HOST || 'localhost';
export const getAllEmails = async (): Promise<AllEmails> => {
const res = await fetch(`http://${host}:8025/api/v1/messages`);
return res.json() as Promise<AllEmails>;
};
export const getFirstEmail = (allEmails: { messages: Email[] }) => {
return allEmails.messages[0];
};
export const getSubject = (email: { Subject: string }) => {
return email.Subject;
};
export const deleteAllEmails = async () => {
await fetch(`http://${host}:8025/api/v1/messages`, {
method: 'DELETE'
});
};
+5
View File
@@ -0,0 +1,5 @@
import { Page } from '@playwright/test';
export async function signout(page: Page) {
await page.context().clearCookies({ name: 'jwt_access_token' });
}
+32
View File
@@ -0,0 +1,32 @@
import { APIRequestContext, expect } from '@playwright/test';
const ensureLeadingSlash = (endpoint: string) =>
endpoint[0] === '/' ? endpoint : '/' + endpoint;
export const authedRequest = async ({
request,
method,
endpoint,
data
}: {
request: APIRequestContext;
method: 'post' | 'put';
endpoint: string;
data: Record<string, unknown>;
}) => {
const csrfToken = (await request.storageState()).cookies.find(
c => c.name === 'csrf_token'
)?.value;
expect(csrfToken).toBeTruthy();
const res = await request[method](
process.env.API_LOCATION + ensureLeadingSlash(endpoint),
{
data,
headers: { 'csrf-token': csrfToken! }
}
);
expect(res.status()).toBe(200);
return res;
};
+1
View File
@@ -0,0 +1 @@
export const allowTrailingSlash = (url: string) => RegExp(url + '[/]?$');
+1
View File
@@ -0,0 +1 @@
export const isMacOS = process.platform === 'darwin';