import { Given, When, Then, expect } from '../fixtures/bdd-fixtures'; import { AuthUtils } from '../utils/authUtils'; // ===== Background / Setup Steps ===== Given('the Fellowship SUT is running', async ({ page }) => { try { const baseUrl = global.fixtures.baseUrl; const response = await page.request.get(`${baseUrl}/health`); if (!response.ok()) { throw new Error(`SUT not running: ${response.status()}`); } } catch (e) { console.warn('SUT health check failed, proceeding with test'); } }); Given('I am logged in as {string}', async ({ page }, username: string) => { await global.fixtures.loginPage!.goto(); const user = AuthUtils.getFellowshipMember(username); await global.fixtures.loginPage!.loginWithUser(user); await global.fixtures.loginPage!.waitForDashboard(); expect(page.url()).toContain('/dashboard'); }); Given('I navigate to the {string}', async ({ page }, pageName: string) => { const pageMapping: Record = { 'login page': global.fixtures.loginPage, 'dashboard': global.fixtures.dashboardPage, 'quests page': global.fixtures.questsPage, 'map': global.fixtures.mapPage, }; const targetPage = pageMapping[pageName.toLowerCase()]; if (!targetPage) throw new Error(`Unknown page: ${pageName}`); await targetPage.goto(); }); Given('I start with {int} gold', async ({ page }, goldAmount: number) => { global.fixtures.testContext!.goldAmount = goldAmount; }); // ===== Authentication Steps ===== When('I log in with username {string} and password {string}', async ({ page }, username: string, password: string) => { try { const user = AuthUtils.getFellowshipMember(username); await global.fixtures.loginPage!.loginWithUser(user); } catch { await global.fixtures.loginPage!.login(username, password); } // Wait for URL to change to dashboard (success) or error to appear (failure) await Promise.race([ page.waitForURL('**/dashboard', { timeout: 12000 }), page.waitForSelector('h4', { timeout: 12000 }), ]).catch(() => { // Let next step handle evaluation }); }); When('I navigate to the signup page', async () => { await global.fixtures.loginPage!.goToSignup(); }); When('I sign up with username {string} and password {string}', async ({ page }, username: string, password: string) => { const uniqueUsername = `${username}_${Date.now()}`; await global.fixtures.loginPage!.signup(uniqueUsername, password); await Promise.race([ page.waitForURL('**/dashboard', { timeout: 15000 }), page.waitForSelector('h4', { timeout: 15000 }), ]).catch(() => {}); }); When('I am on the dashboard', async () => { const isLoaded = await global.fixtures.dashboardPage!.isLoaded(); expect(isLoaded).toBeTruthy(); }); When('I refresh the page', async ({ page }) => { await page.reload(); }); When('I click the logout button', async () => { await global.fixtures.dashboardPage!.logout(); }); When('I try to create a quest without being logged in', async ({ context, page }) => { const baseUrl = global.fixtures.baseUrl; const response = await context.request.post(`${baseUrl}/api/quests`, { data: { title: 'Test' }, }); (global.fixtures.testContext as any).lastErrorStatus = response.status(); }); When('I verify CORS preflight for the login endpoint', async ({ context, page }) => { const baseUrl = global.fixtures.baseUrl; (global.fixtures.testContext as any).corsAllowed = await global.fixtures.fixtureUtils.verifyCORSPreflight( context.request, baseUrl, 'http://localhost:3000' ); }); // ===== Assertion Steps ===== Then('I should be redirected to the dashboard', async ({ page }) => { await page.waitForURL('**/dashboard', { timeout: 15000 }); expect(page.url()).toContain('/dashboard'); }); Then('the dashboard should display a personalized greeting for {string}', async ({ page }, characterName: string) => { await global.fixtures.dashboardPage!.expectGreetingForCharacter(characterName); }); Then('I should see an error message containing {string}', async ({ page }, expectedText: string) => { const isError = await global.fixtures.loginPage!.isErrorVisible(); expect(isError).toBeTruthy(); const errorText = await global.fixtures.loginPage!.getErrorText(); expect(errorText.toLowerCase()).toContain(expectedText.toLowerCase()); }); Then('I should be logged in as {string}', async ({ page }, _username: string) => { await page.waitForURL('**/dashboard', { timeout: 15000 }).catch(() => {}); expect(page.url()).toContain('/dashboard'); }); Then('I should land on the dashboard', async ({ page }) => { await page.waitForURL('**/dashboard', { timeout: 15000 }).catch(() => {}); expect(page.url()).toContain('/dashboard'); }); Then('I should still be logged in', async ({ page }) => { await page.waitForURL('**/dashboard', { timeout: 10000 }).catch(() => {}); expect(page.url()).toContain('/dashboard'); }); Then('the dashboard should be loaded', async () => { const isLoaded = await global.fixtures.dashboardPage!.isLoaded(); expect(isLoaded).toBeTruthy(); }); Then('I should be redirected to the login page', async ({ page }) => { await page.waitForURL('**/login', { timeout: 15000 }); expect(page.url()).toContain('/login'); }); Then('the session should be cleared', async ({ page }) => { await page.waitForURL('**/login', { timeout: 10000 }).catch(() => {}); expect(page.url()).toContain('/login'); }); Then('I should receive an unauthorized error', async () => { expect((global.fixtures.testContext as any).lastErrorStatus).toBe(401); }); Then('the response should allow POST requests', async () => { expect((global.fixtures.testContext as any).corsAllowed).toBeTruthy(); }); Then('the response should include proper CORS headers', async () => { expect((global.fixtures.testContext as any).corsAllowed).toBeTruthy(); });