91 lines
3.9 KiB
TypeScript
91 lines
3.9 KiB
TypeScript
|
|
import { test as base, expect } from '@playwright/test';
|
|
import { request } from '@playwright/test';
|
|
import { exec as cp_exec } from 'child_process';
|
|
import { promisify } from 'util';
|
|
|
|
const exec = promisify(cp_exec);
|
|
|
|
// Define the type for our custom fixtures
|
|
type MyFixtures = {
|
|
createUniqueUser: () => Promise<{ email: string, password: string, id: string, token: string }>;
|
|
createAdminUser: () => Promise<{ email: string, password: string, id: string, token: string }>;
|
|
};
|
|
|
|
// Extend the base test with our custom fixture
|
|
export const test = base.extend<MyFixtures>({
|
|
createUniqueUser: async ({ }, use) => {
|
|
// We use a new API context for setup to avoid polluting request history,
|
|
// although setup requests are usually separate anyway.
|
|
const apiContext = await request.newContext({
|
|
baseURL: 'http://127.0.0.1:3001' // Direct access to backend
|
|
});
|
|
|
|
// Setup: Helper function to create a user
|
|
const createUser = async () => {
|
|
const uniqueId = Math.random().toString(36).substring(7);
|
|
const email = `test.user.${uniqueId}@example.com`;
|
|
const password = 'StrongPassword123!';
|
|
|
|
const response = await apiContext.post('/api/auth/register', {
|
|
data: {
|
|
email,
|
|
password
|
|
}
|
|
});
|
|
|
|
const body = await response.json();
|
|
|
|
// If registration fails because we hit a collision (unlikely) or other error, fail the test
|
|
if (!response.ok() || !body.success) {
|
|
console.error(`REGISTRATION FAILED: ${response.status()} ${response.statusText()}`);
|
|
console.error(`RESPONSE BODY: ${JSON.stringify(body, null, 2)}`);
|
|
throw new Error(`Failed to register user: ${JSON.stringify(body)}`);
|
|
}
|
|
|
|
return { email, password, id: body.data.user.id, token: body.data.token };
|
|
};
|
|
|
|
// Use the fixture
|
|
await use(createUser);
|
|
|
|
// Cleanup: In a real "test:full" env with ephemeral db, cleanup might not be needed.
|
|
// But if we want to be clean, we can delete the user.
|
|
// Requires admin privileges usually, or specific delete-me endpoint.
|
|
// Given the requirements "delete own account" exists (5.6), we could theoretically login and delete.
|
|
// For now we skip auto-cleanup to keep it simple, assuming test DB is reset periodically.
|
|
},
|
|
|
|
createAdminUser: async ({ createUniqueUser }, use) => {
|
|
// Setup: Helper function to create an admin user (create regular -> promote)
|
|
const createAdmin = async () => {
|
|
const user = await createUniqueUser(); // Create a regular user first
|
|
|
|
console.log(`Promoting user ${user.email} to ADMIN...`);
|
|
try {
|
|
const { stdout, stderr } = await exec(`npx ts-node promote_admin.ts ${user.email}`, {
|
|
cwd: 'server',
|
|
env: { ...process.env, APP_MODE: 'test', DATABASE_URL: 'file:d:/Coding/gymflow/server/test.db', DATABASE_URL_TEST: 'file:d:/Coding/gymflow/server/test.db' }
|
|
});
|
|
if (stderr) {
|
|
console.error(`Promote Admin Stderr: ${stderr}`);
|
|
}
|
|
console.log(`Promote Admin Stdout: ${stdout}`);
|
|
if (!stdout.includes(`User ${user.email} promoted to ADMIN`)) {
|
|
throw new Error('Admin promotion failed or unexpected output.');
|
|
}
|
|
} catch (error: any) {
|
|
console.error(`Error promoting user ${user.email} to ADMIN:`, error);
|
|
if (error.stdout) console.log(`Failed CMD Stdout: ${error.stdout}`);
|
|
if (error.stderr) console.error(`Failed CMD Stderr: ${error.stderr}`);
|
|
throw error;
|
|
}
|
|
return user;
|
|
};
|
|
|
|
await use(createAdmin);
|
|
},
|
|
});
|
|
|
|
export { expect };
|