Set up Playwright with dual-project config (API + Web), auth test fixtures, 16 E2E tests covering registration, login, profile, token refresh, and homepage rendering. Added GitHub Actions CI workflow for automated E2E runs. Co-Authored-By: Paperclip <noreply@paperclip.ing>
83 lines
2.4 KiB
TypeScript
83 lines
2.4 KiB
TypeScript
import { test as base, type APIRequestContext } from '@playwright/test';
|
|
|
|
/** Shape returned by POST /auth/register and POST /auth/login */
|
|
export interface TokenPair {
|
|
accessToken: string;
|
|
refreshToken: string;
|
|
}
|
|
|
|
/** Generates a unique test user payload for each test run. */
|
|
export function createTestUser(suffix = Date.now()) {
|
|
return {
|
|
phone: `09${String(suffix).slice(-8).padStart(8, '0')}`,
|
|
password: 'Test@1234!',
|
|
fullName: `Test User ${suffix}`,
|
|
email: `testuser${suffix}@goodgo.test`,
|
|
};
|
|
}
|
|
|
|
/** Registers a new user via the API and returns the token pair. */
|
|
export async function registerUser(
|
|
request: APIRequestContext,
|
|
user = createTestUser(),
|
|
): Promise<TokenPair & { user: ReturnType<typeof createTestUser> }> {
|
|
const res = await request.post('/auth/register', { data: user });
|
|
if (!res.ok()) {
|
|
const body = await res.text();
|
|
throw new Error(`Register failed (${res.status()}): ${body}`);
|
|
}
|
|
const tokens: TokenPair = await res.json();
|
|
return { ...tokens, user };
|
|
}
|
|
|
|
/** Logs in an existing user and returns the token pair. */
|
|
export async function loginUser(
|
|
request: APIRequestContext,
|
|
phone: string,
|
|
password: string,
|
|
): Promise<TokenPair> {
|
|
const res = await request.post('/auth/login', {
|
|
data: { phone, password },
|
|
});
|
|
if (!res.ok()) {
|
|
const body = await res.text();
|
|
throw new Error(`Login failed (${res.status()}): ${body}`);
|
|
}
|
|
return res.json();
|
|
}
|
|
|
|
/**
|
|
* Extended test fixture that provides a pre-authenticated API context.
|
|
*
|
|
* Usage:
|
|
* import { test } from '../fixtures/auth.fixture';
|
|
* test('my test', async ({ authedRequest, testTokens }) => { ... });
|
|
*/
|
|
export const test = base.extend<{
|
|
testUser: ReturnType<typeof createTestUser>;
|
|
testTokens: TokenPair;
|
|
authedRequest: APIRequestContext;
|
|
}>({
|
|
testUser: async ({}, use) => {
|
|
await use(createTestUser());
|
|
},
|
|
|
|
testTokens: async ({ request, testUser }, use) => {
|
|
const { accessToken, refreshToken } = await registerUser(request, testUser);
|
|
await use({ accessToken, refreshToken });
|
|
},
|
|
|
|
authedRequest: async ({ playwright, testTokens, baseURL }, use) => {
|
|
const ctx = await playwright.request.newContext({
|
|
baseURL,
|
|
extraHTTPHeaders: {
|
|
Authorization: `Bearer ${testTokens.accessToken}`,
|
|
},
|
|
});
|
|
await use(ctx);
|
|
await ctx.dispose();
|
|
},
|
|
});
|
|
|
|
export { expect } from '@playwright/test';
|