1
0
forked from baron/baron-sso
Files
baron-sso/userfront-e2e/tests/auth-routing.spec.ts

183 lines
5.4 KiB
TypeScript

import { expect, test, type Page, type Route } from '@playwright/test';
type MockOptions = {
sessionStatus?: number;
captureApprove?: (pendingRef: string | null) => void;
};
async function seedTokenLogin(page: Page): Promise<void> {
await page.addInitScript(() => {
window.localStorage.setItem('baron_auth_token', 'e30.e30.e30');
window.localStorage.setItem('baron_auth_provider', 'ory');
window.localStorage.removeItem('baron_auth_cookie_mode');
window.localStorage.removeItem('baron_auth_pending_provider');
});
}
async function seedSessionTokenLogin(page: Page): Promise<void> {
await page.addInitScript(() => {
window.sessionStorage.setItem('baron_auth_token', 'e30.e30.e30');
window.sessionStorage.setItem('baron_auth_provider', 'ory');
window.sessionStorage.removeItem('baron_auth_cookie_mode');
window.sessionStorage.removeItem('baron_auth_pending_provider');
window.localStorage.removeItem('baron_auth_token');
window.localStorage.removeItem('baron_auth_provider');
window.localStorage.removeItem('baron_auth_cookie_mode');
window.localStorage.removeItem('baron_auth_pending_provider');
});
}
async function mockUserfrontApis(
page: Page,
options: MockOptions = {},
): Promise<void> {
const sessionStatus = options.sessionStatus ?? 200;
await page.route('**/api/v1/**', async (route: Route) => {
const requestUrl = new URL(route.request().url());
const path = requestUrl.pathname;
if (path.endsWith('/api/v1/user/me')) {
if (sessionStatus === 200) {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
id: 'e2e-user',
email: 'e2e@example.com',
name: 'E2E User',
phone: '+821012341234',
department: 'QA',
affiliationType: 'employee',
companyCode: 'BARON',
tenant: {
id: 'tenant-1',
name: 'Baron',
slug: 'baron',
description: 'E2E tenant',
},
}),
});
return;
}
await route.fulfill({
status: sessionStatus,
contentType: 'application/json',
body: JSON.stringify({ error: 'unauthorized' }),
});
return;
}
if (path.endsWith('/api/v1/user/rp/linked')) {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ items: [] }),
});
return;
}
if (path.endsWith('/api/v1/audit/auth/timeline')) {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ items: [], next_cursor: '' }),
});
return;
}
if (path.endsWith('/api/v1/auth/qr/approve')) {
if (route.request().method() == 'POST') {
let pendingRef: string | null = null;
try {
const body = (route.request().postDataJSON() ?? {}) as {
pendingRef?: string;
};
pendingRef = body.pendingRef ?? null;
console.log(`[E2E-MOCK] /api/v1/auth/qr/approve POST body:`, body);
} catch (e) {
console.log(`[E2E-MOCK] /api/v1/auth/qr/approve POST body parse error:`, e);
pendingRef = null;
}
options.captureApprove?.(pendingRef);
} else {
console.log(`[E2E-MOCK] /api/v1/auth/qr/approve ${route.request().method()} request`);
}
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ ok: true }),
});
return;
}
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({}),
});
});
}
test.describe('UserFront WASM auth routing', () => {
test('비로그인 /ko 진입 시 /ko/signin 으로 리다이렉트된다', async ({ page }) => {
await mockUserfrontApis(page, { sessionStatus: 401 });
await page.goto('/ko');
await expect(page).toHaveURL(/\/ko\/signin(?:\?.*)?$/);
});
test('로그인 상태 /ko 진입 후 새로고침해도 /ko/dashboard 를 유지한다', async ({
page,
}) => {
await seedTokenLogin(page);
await mockUserfrontApis(page);
await page.goto('/ko');
await expect(page).toHaveURL(/\/ko\/dashboard$/);
await page.reload();
await expect(page).toHaveURL(/\/ko\/dashboard$/);
});
test('sessionStorage 기반 로그인 상태에서도 /ko/dashboard 를 유지한다', async ({
page,
}) => {
await seedSessionTokenLogin(page);
await mockUserfrontApis(page);
await page.goto('/ko');
await expect(page).toHaveURL(/\/ko\/dashboard$/);
});
test('비로그인 /ko/approve 는 signin(+notice)으로 이동한다', async ({ page }) => {
await mockUserfrontApis(page, { sessionStatus: 401 });
await page.goto('/ko/approve?ref=e2e-ref');
await expect(page).toHaveURL(/\/ko\/signin\?notice=qr_login_required$/);
});
test('로그인 상태 /ko/approve 는 승인 API 호출 후 dashboard로 이동한다', async ({
page,
}) => {
let approvedRef: string | null = null;
await seedTokenLogin(page);
await mockUserfrontApis(page, {
captureApprove: (pendingRef) => {
approvedRef = pendingRef;
},
});
await page.goto('/ko/approve?ref=e2e-approve-ref');
await expect(page).toHaveURL(/\/ko\/dashboard(?:\?.*)?$/, {
timeout: 10_000,
});
expect(approvedRef).toBe('e2e-approve-ref');
});
});