test(e2e): honor configured game base paths
This commit is contained in:
@@ -2,6 +2,7 @@ import { expect, test, type Page, type Route } from '@playwright/test';
|
|||||||
import { readFile } from 'node:fs/promises';
|
import { readFile } from 'node:fs/promises';
|
||||||
import { dirname, resolve } from 'node:path';
|
import { dirname, resolve } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { gameProfile, gameTrpcRoute } from './gameTestPaths.js';
|
||||||
|
|
||||||
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
|
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
|
||||||
const imageRoots = [
|
const imageRoots = [
|
||||||
@@ -185,10 +186,10 @@ const uniqueDetail = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const installFixture = async (page: Page, state: AuctionFixture) => {
|
const installFixture = async (page: Page, state: AuctionFixture) => {
|
||||||
await page.addInitScript(() => {
|
await page.addInitScript((profile) => {
|
||||||
window.localStorage.setItem('sammo-game-token', 'ga_auction_playwright');
|
window.localStorage.setItem('sammo-game-token', 'ga_auction_playwright');
|
||||||
window.localStorage.setItem('sammo-game-profile', 'che:default');
|
window.localStorage.setItem('sammo-game-profile', profile);
|
||||||
});
|
}, gameProfile);
|
||||||
for (const filename of ['back_walnut.jpg', 'back_green.jpg', 'back_blue.jpg']) {
|
for (const filename of ['back_walnut.jpg', 'back_green.jpg', 'back_blue.jpg']) {
|
||||||
await page.route(`**/image/game/${filename}`, async (route) => {
|
await page.route(`**/image/game/${filename}`, async (route) => {
|
||||||
await route.fulfill({
|
await route.fulfill({
|
||||||
@@ -198,7 +199,7 @@ const installFixture = async (page: Page, state: AuctionFixture) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
await page.route('**/che/api/trpc/**', async (route) => {
|
await page.route(gameTrpcRoute, async (route) => {
|
||||||
const results = operationNames(route).map((operation) => {
|
const results = operationNames(route).map((operation) => {
|
||||||
if (operation === 'auth.status') return response({ ok: true });
|
if (operation === 'auth.status') return response({ ok: true });
|
||||||
if (operation === 'lobby.info') {
|
if (operation === 'lobby.info') {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { expect, test, type Page, type Route } from '@playwright/test';
|
|||||||
import { readFile } from 'node:fs/promises';
|
import { readFile } from 'node:fs/promises';
|
||||||
import { dirname, resolve } from 'node:path';
|
import { dirname, resolve } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { gameProfile, gameTrpcRoute } from './gameTestPaths.js';
|
||||||
|
|
||||||
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
|
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
|
||||||
const imageRoots = [
|
const imageRoots = [
|
||||||
@@ -181,17 +182,15 @@ const installImages = async (page: Page) => {
|
|||||||
|
|
||||||
const installApi = async (page: Page, fixture: Fixture) => {
|
const installApi = async (page: Page, fixture: Fixture) => {
|
||||||
await installImages(page);
|
await installImages(page);
|
||||||
await page.addInitScript(() => {
|
await page.addInitScript((profile) => {
|
||||||
window.localStorage.setItem('sammo-game-token', 'ga_battle_sim_playwright');
|
window.localStorage.setItem('sammo-game-token', 'ga_battle_sim_playwright');
|
||||||
window.localStorage.setItem('sammo-game-profile', 'che:default');
|
window.localStorage.setItem('sammo-game-profile', profile);
|
||||||
});
|
}, gameProfile);
|
||||||
await page.route('**/che/api/trpc/**', async (route) => {
|
await page.route(gameTrpcRoute, async (route) => {
|
||||||
const operations = operationNames(route);
|
const operations = operationNames(route);
|
||||||
const rawRequestBody: unknown = route.request().postData() ? route.request().postDataJSON() : {};
|
const rawRequestBody: unknown = route.request().postData() ? route.request().postDataJSON() : {};
|
||||||
const requestBody =
|
const requestBody =
|
||||||
rawRequestBody && typeof rawRequestBody === 'object'
|
rawRequestBody && typeof rawRequestBody === 'object' ? (rawRequestBody as Record<string, unknown>) : {};
|
||||||
? (rawRequestBody as Record<string, unknown>)
|
|
||||||
: {};
|
|
||||||
const results = operations.map((operation, operationIndex) => {
|
const results = operations.map((operation, operationIndex) => {
|
||||||
fixture.requests.push(operation);
|
fixture.requests.push(operation);
|
||||||
if (operation === 'auth.status') return response({ userId: 'battle-sim-user' });
|
if (operation === 'auth.status') return response({ userId: 'battle-sim-user' });
|
||||||
@@ -223,9 +222,7 @@ const installApi = async (page: Page, fixture: Fixture) => {
|
|||||||
input?: { json?: unknown };
|
input?: { json?: unknown };
|
||||||
})
|
})
|
||||||
: undefined;
|
: undefined;
|
||||||
fixture.simulationPayloads.push(
|
fixture.simulationPayloads.push(payload?.json ?? payload?.input?.json ?? rawPayload);
|
||||||
payload?.json ?? payload?.input?.json ?? rawPayload
|
|
||||||
);
|
|
||||||
if (fixture.failNextSimulation) {
|
if (fixture.failNextSimulation) {
|
||||||
fixture.failNextSimulation = false;
|
fixture.failNextSimulation = false;
|
||||||
return errorResponse(operation, '시뮬레이터 입력 오류');
|
return errorResponse(operation, '시뮬레이터 입력 오류');
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { expect, test, type Page, type Route } from '@playwright/test';
|
|||||||
import { readFile } from 'node:fs/promises';
|
import { readFile } from 'node:fs/promises';
|
||||||
import { dirname, resolve } from 'node:path';
|
import { dirname, resolve } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { gamePath, gameProfile, gameTrpcRoute } from './gameTestPaths.js';
|
||||||
|
|
||||||
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
|
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
|
||||||
const imageRoots = [
|
const imageRoots = [
|
||||||
@@ -142,11 +143,11 @@ const emptyMessages = {
|
|||||||
|
|
||||||
const installApi = async (page: Page, state: BoardFixture) => {
|
const installApi = async (page: Page, state: BoardFixture) => {
|
||||||
await installImages(page);
|
await installImages(page);
|
||||||
await page.addInitScript(() => {
|
await page.addInitScript((profile) => {
|
||||||
window.localStorage.setItem('sammo-game-token', 'ga_board_playwright');
|
window.localStorage.setItem('sammo-game-token', 'ga_board_playwright');
|
||||||
window.localStorage.setItem('sammo-game-profile', 'che:default');
|
window.localStorage.setItem('sammo-game-profile', profile);
|
||||||
});
|
}, gameProfile);
|
||||||
await page.route('**/che/api/trpc/**', async (route) => {
|
await page.route(gameTrpcRoute, async (route) => {
|
||||||
const operations = operationNames(route);
|
const operations = operationNames(route);
|
||||||
const results = operations.map((operation) => {
|
const results = operations.map((operation) => {
|
||||||
state.requests.push(operation);
|
state.requests.push(operation);
|
||||||
@@ -444,7 +445,7 @@ test('denies direct secret-room rendering and disables its in-game menu for an o
|
|||||||
state.requests.length = 0;
|
state.requests.length = 0;
|
||||||
await page.goto('');
|
await page.goto('');
|
||||||
const nationMenu = page.locator('.main-nation-menu').first();
|
const nationMenu = page.locator('.main-nation-menu').first();
|
||||||
await expect(nationMenu.locator('[data-navigation-id="meeting"]')).toHaveAttribute('href', '/che/board');
|
await expect(nationMenu.locator('[data-navigation-id="meeting"]')).toHaveAttribute('href', gamePath('/board'));
|
||||||
await expect(nationMenu.locator('[data-navigation-id="secret-board"]')).toHaveAttribute('aria-disabled', 'true');
|
await expect(nationMenu.locator('[data-navigation-id="secret-board"]')).toHaveAttribute('aria-disabled', 'true');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -459,9 +460,9 @@ test('enables both in-game menu entries for a chief or delegated secret role', a
|
|||||||
await installApi(page, state);
|
await installApi(page, state);
|
||||||
await page.goto('');
|
await page.goto('');
|
||||||
const nationMenu = page.locator('.main-nation-menu').first();
|
const nationMenu = page.locator('.main-nation-menu').first();
|
||||||
await expect(nationMenu.locator('[data-navigation-id="meeting"]')).toHaveAttribute('href', '/che/board');
|
await expect(nationMenu.locator('[data-navigation-id="meeting"]')).toHaveAttribute('href', gamePath('/board'));
|
||||||
await expect(nationMenu.locator('[data-navigation-id="secret-board"]')).toHaveAttribute(
|
await expect(nationMenu.locator('[data-navigation-id="secret-board"]')).toHaveAttribute(
|
||||||
'href',
|
'href',
|
||||||
'/che/board/secret'
|
gamePath('/board/secret')
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { expect, test, type Page, type Route } from '@playwright/test';
|
import { expect, test, type Page, type Route } from '@playwright/test';
|
||||||
|
import { gameProfile, gameTrpcRoute } from './gameTestPaths.js';
|
||||||
|
|
||||||
const response = (data: unknown) => ({ result: { data } });
|
const response = (data: unknown) => ({ result: { data } });
|
||||||
const errorResponse = (path: string, message: string) => ({
|
const errorResponse = (path: string, message: string) => ({
|
||||||
@@ -128,12 +129,12 @@ const chiefCenter = {
|
|||||||
|
|
||||||
const install = async (page: Page, rejectGeneral = false) => {
|
const install = async (page: Page, rejectGeneral = false) => {
|
||||||
const requests: unknown[] = [];
|
const requests: unknown[] = [];
|
||||||
await page.addInitScript(() => {
|
await page.addInitScript((profile) => {
|
||||||
localStorage.setItem('sammo-game-token', 'ga_commands');
|
localStorage.setItem('sammo-game-token', 'ga_commands');
|
||||||
localStorage.setItem('sammo-game-profile', 'che:default');
|
localStorage.setItem('sammo-game-profile', profile);
|
||||||
});
|
}, gameProfile);
|
||||||
await page.route('**/image/**', (route) => route.fulfill({ status: 404, body: '' }));
|
await page.route('**/image/**', (route) => route.fulfill({ status: 404, body: '' }));
|
||||||
await page.route('**/che/api/trpc/**', async (route) => {
|
await page.route(gameTrpcRoute, async (route) => {
|
||||||
const names = operations(route);
|
const names = operations(route);
|
||||||
const body = route.request().postDataJSON();
|
const body = route.request().postDataJSON();
|
||||||
const results = names.map((name) => {
|
const results = names.map((name) => {
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
const normalizedBasePath = (process.env.PLAYWRIGHT_GAME_BASE_PATH ?? 'che').replace(/^\/+|\/+$/g, '');
|
||||||
|
|
||||||
|
export const gameBasePath = `/${normalizedBasePath}`;
|
||||||
|
export const gameProfile = process.env.PLAYWRIGHT_GAME_PROFILE ?? 'che:default';
|
||||||
|
export const gameTrpcRoute = `**${gameBasePath}/api/trpc/**`;
|
||||||
|
export const gamePath = (suffix = ''): string => `${gameBasePath}${suffix.startsWith('/') ? suffix : `/${suffix}`}`;
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
||||||
import { basename, resolve } from 'node:path';
|
import { basename, resolve } from 'node:path';
|
||||||
import { expect, test, type Page, type Route } from '@playwright/test';
|
import { expect, test, type Page, type Route } from '@playwright/test';
|
||||||
|
import { gameBasePath, gameProfile, gameTrpcRoute } from './gameTestPaths.js';
|
||||||
|
|
||||||
const response = (data: unknown) => ({ result: { data } });
|
const response = (data: unknown) => ({ result: { data } });
|
||||||
const parityArtifactDir = process.env.MENU_PARITY_ARTIFACT_DIR;
|
const parityArtifactDir = process.env.MENU_PARITY_ARTIFACT_DIR;
|
||||||
@@ -133,12 +134,15 @@ const battleCenter = (state: FixtureState) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const install = async (page: Page, state: FixtureState) => {
|
const install = async (page: Page, state: FixtureState) => {
|
||||||
await page.addInitScript(() => {
|
await page.addInitScript(
|
||||||
if (location.pathname.startsWith('/che/')) {
|
({ basePath, profile }) => {
|
||||||
localStorage.setItem('sammo-game-token', 'ga_menu-token');
|
if (location.pathname.startsWith(`${basePath}/`)) {
|
||||||
localStorage.setItem('sammo-game-profile', 'che:default');
|
localStorage.setItem('sammo-game-token', 'ga_menu-token');
|
||||||
}
|
localStorage.setItem('sammo-game-profile', profile);
|
||||||
});
|
}
|
||||||
|
},
|
||||||
|
{ basePath: gameBasePath, profile: gameProfile }
|
||||||
|
);
|
||||||
await page.route('**/image/game/**', async (route) => {
|
await page.route('**/image/game/**', async (route) => {
|
||||||
const filename = basename(new URL(route.request().url()).pathname);
|
const filename = basename(new URL(route.request().url()).pathname);
|
||||||
if (legacyImageRoot && ['back_walnut.jpg', 'back_green.jpg', 'back_blue.jpg'].includes(filename)) {
|
if (legacyImageRoot && ['back_walnut.jpg', 'back_green.jpg', 'back_blue.jpg'].includes(filename)) {
|
||||||
@@ -151,7 +155,7 @@ const install = async (page: Page, state: FixtureState) => {
|
|||||||
}
|
}
|
||||||
await route.fulfill({ status: 200, contentType: 'image/jpeg', body: Buffer.from('') });
|
await route.fulfill({ status: 200, contentType: 'image/jpeg', body: Buffer.from('') });
|
||||||
});
|
});
|
||||||
await page.route('**/che/api/trpc/**', async (route) => {
|
await page.route(gameTrpcRoute, async (route) => {
|
||||||
const operations = operationNames(route);
|
const operations = operationNames(route);
|
||||||
const rawRequestBody: unknown = route.request().postData() ? route.request().postDataJSON() : {};
|
const rawRequestBody: unknown = route.request().postData() ? route.request().postDataJSON() : {};
|
||||||
const requestBody =
|
const requestBody =
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { expect, test, type Page, type Route } from '@playwright/test';
|
import { expect, test, type Page, type Route } from '@playwright/test';
|
||||||
|
import { gameProfile, gameTrpcRoute } from './gameTestPaths.js';
|
||||||
|
|
||||||
const response = (data: unknown) => ({ result: { data } });
|
const response = (data: unknown) => ({ result: { data } });
|
||||||
const operations = (route: Route) =>
|
const operations = (route: Route) =>
|
||||||
@@ -28,11 +29,11 @@ const general = {
|
|||||||
permission: 'normal',
|
permission: 'normal',
|
||||||
};
|
};
|
||||||
const install = async (page: Page, secretAllowed = true) => {
|
const install = async (page: Page, secretAllowed = true) => {
|
||||||
await page.addInitScript(() => {
|
await page.addInitScript((profile) => {
|
||||||
localStorage.setItem('sammo-game-token', 'ga_general');
|
localStorage.setItem('sammo-game-token', 'ga_general');
|
||||||
localStorage.setItem('sammo-game-profile', 'che:default');
|
localStorage.setItem('sammo-game-profile', profile);
|
||||||
});
|
}, gameProfile);
|
||||||
await page.route('**/che/api/trpc/**', async (route) => {
|
await page.route(gameTrpcRoute, async (route) => {
|
||||||
const results = operations(route).map((operation) => {
|
const results = operations(route).map((operation) => {
|
||||||
if (operation === 'auth.status') return response({ ok: true });
|
if (operation === 'auth.status') return response({ ok: true });
|
||||||
if (operation === 'lobby.info') return response({ myGeneral: { id: 1, name: '테스트장수' } });
|
if (operation === 'lobby.info') return response({ myGeneral: { id: 1, name: '테스트장수' } });
|
||||||
@@ -143,7 +144,7 @@ test('secret office renders summary, turns, and the forbidden error flow', async
|
|||||||
await expect(page.locator('#secret-general-list')).toContainText('1 : 징병');
|
await expect(page.locator('#secret-general-list')).toContainText('1 : 징병');
|
||||||
expect(await page.locator('.secret-page').evaluate((el) => el.getBoundingClientRect().width)).toBe(1000);
|
expect(await page.locator('.secret-page').evaluate((el) => el.getBoundingClientRect().width)).toBe(1000);
|
||||||
|
|
||||||
await page.unroute('**/che/api/trpc/**');
|
await page.unroute(gameTrpcRoute);
|
||||||
await install(page, false);
|
await install(page, false);
|
||||||
await page.goto('nation/secret');
|
await page.goto('nation/secret');
|
||||||
await expect(page.getByRole('alert')).toContainText('권한이 부족합니다.');
|
await expect(page.getByRole('alert')).toContainText('권한이 부족합니다.');
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { expect, test, type Page, type Route } from '@playwright/test';
|
|||||||
import { mkdir, readFile } from 'node:fs/promises';
|
import { mkdir, readFile } from 'node:fs/promises';
|
||||||
import { dirname, resolve } from 'node:path';
|
import { dirname, resolve } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { gameProfile, gameTrpcRoute } from './gameTestPaths.js';
|
||||||
|
|
||||||
type Role = 'leader' | 'head' | 'member';
|
type Role = 'leader' | 'head' | 'member';
|
||||||
type FixtureState = {
|
type FixtureState = {
|
||||||
@@ -186,10 +187,10 @@ const financeFixture = (state: FixtureState) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const installFixture = async (page: Page, state: FixtureState) => {
|
const installFixture = async (page: Page, state: FixtureState) => {
|
||||||
await page.addInitScript(() => {
|
await page.addInitScript((profile) => {
|
||||||
localStorage.setItem('sammo-game-token', 'ga_office_playwright');
|
localStorage.setItem('sammo-game-token', 'ga_office_playwright');
|
||||||
localStorage.setItem('sammo-game-profile', 'che:default');
|
localStorage.setItem('sammo-game-profile', profile);
|
||||||
});
|
}, gameProfile);
|
||||||
for (const filename of ['back_walnut.jpg', 'back_green.jpg', 'back_blue.jpg']) {
|
for (const filename of ['back_walnut.jpg', 'back_green.jpg', 'back_blue.jpg']) {
|
||||||
await page.route(`**/image/game/${filename}`, async (route) =>
|
await page.route(`**/image/game/${filename}`, async (route) =>
|
||||||
route.fulfill({
|
route.fulfill({
|
||||||
@@ -206,7 +207,7 @@ const installFixture = async (page: Page, state: FixtureState) => {
|
|||||||
body: await referenceAsset('icons/default.jpg'),
|
body: await referenceAsset('icons/default.jpg'),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
await page.route('**/che/api/trpc/**', async (route) => {
|
await page.route(gameTrpcRoute, async (route) => {
|
||||||
const operations = operationName(route).split(',');
|
const operations = operationName(route).split(',');
|
||||||
const rawRequestBody: unknown = route.request().postData() ? route.request().postDataJSON() : {};
|
const rawRequestBody: unknown = route.request().postData() ? route.request().postDataJSON() : {};
|
||||||
const requestBody =
|
const requestBody =
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { expect, test, type Page, type Route } from '@playwright/test';
|
|||||||
import { mkdir, readFile } from 'node:fs/promises';
|
import { mkdir, readFile } from 'node:fs/promises';
|
||||||
import { dirname, resolve } from 'node:path';
|
import { dirname, resolve } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { gameProfile, gameTrpcRoute } from './gameTestPaths.js';
|
||||||
|
|
||||||
type FixtureState = {
|
type FixtureState = {
|
||||||
permissionLevel: number;
|
permissionLevel: number;
|
||||||
@@ -138,10 +139,10 @@ const policyFixture = (state: FixtureState) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const installFixture = async (page: Page, state: FixtureState) => {
|
const installFixture = async (page: Page, state: FixtureState) => {
|
||||||
await page.addInitScript(() => {
|
await page.addInitScript((profile) => {
|
||||||
localStorage.setItem('sammo-game-token', 'ga_npc_policy_playwright');
|
localStorage.setItem('sammo-game-token', 'ga_npc_policy_playwright');
|
||||||
localStorage.setItem('sammo-game-profile', 'che:default');
|
localStorage.setItem('sammo-game-profile', profile);
|
||||||
});
|
}, gameProfile);
|
||||||
for (const filename of ['back_walnut.jpg', 'back_green.jpg', 'back_blue.jpg']) {
|
for (const filename of ['back_walnut.jpg', 'back_green.jpg', 'back_blue.jpg']) {
|
||||||
await page.route(`**/image/game/${filename}`, async (route) =>
|
await page.route(`**/image/game/${filename}`, async (route) =>
|
||||||
route.fulfill({
|
route.fulfill({
|
||||||
@@ -151,7 +152,7 @@ const installFixture = async (page: Page, state: FixtureState) => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
await page.route('**/che/api/trpc/**', async (route) => {
|
await page.route(gameTrpcRoute, async (route) => {
|
||||||
const operations = operationName(route).split(',');
|
const operations = operationName(route).split(',');
|
||||||
const results = operations.map((operation) => {
|
const results = operations.map((operation) => {
|
||||||
if (operation === 'auth.status') return response({ ok: true });
|
if (operation === 'auth.status') return response({ ok: true });
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { expect, test, type Page, type Route } from '@playwright/test';
|
import { expect, test, type Page, type Route } from '@playwright/test';
|
||||||
|
import { gameBasePath, gameProfile } from './gameTestPaths.js';
|
||||||
|
|
||||||
const response = (data: unknown) => ({ result: { data } });
|
const response = (data: unknown) => ({ result: { data } });
|
||||||
const basePath = `/${(process.env.PLAYWRIGHT_GAME_BASE_PATH ?? 'che').replace(/^\/+|\/+$/g, '')}`;
|
const basePath = gameBasePath;
|
||||||
const operationNames = (route: Route) =>
|
const operationNames = (route: Route) =>
|
||||||
decodeURIComponent(new URL(route.request().url()).pathname.split('/trpc/')[1] ?? '').split(',');
|
decodeURIComponent(new URL(route.request().url()).pathname.split('/trpc/')[1] ?? '').split(',');
|
||||||
|
|
||||||
@@ -94,10 +95,10 @@ const findInput = (value: unknown): Record<string, unknown> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const installFixture = async (page: Page, state: FixtureState): Promise<void> => {
|
const installFixture = async (page: Page, state: FixtureState): Promise<void> => {
|
||||||
await page.addInitScript(() => {
|
await page.addInitScript((profile) => {
|
||||||
localStorage.setItem('sammo-game-token', 'ga_npc_possession');
|
localStorage.setItem('sammo-game-token', 'ga_npc_possession');
|
||||||
localStorage.setItem('sammo-game-profile', 'che:default');
|
localStorage.setItem('sammo-game-profile', profile);
|
||||||
});
|
}, gameProfile);
|
||||||
await page.route('**/image/**', async (route) => {
|
await page.route('**/image/**', async (route) => {
|
||||||
await route.fulfill({
|
await route.fulfill({
|
||||||
status: 200,
|
status: 200,
|
||||||
|
|||||||
@@ -2,17 +2,18 @@ import { mkdir, writeFile } from 'node:fs/promises';
|
|||||||
import { resolve } from 'node:path';
|
import { resolve } from 'node:path';
|
||||||
|
|
||||||
import { expect, test, type Page, type Route } from '@playwright/test';
|
import { expect, test, type Page, type Route } from '@playwright/test';
|
||||||
|
import { gamePath, gameProfile, gameTrpcRoute } from './gameTestPaths.js';
|
||||||
|
|
||||||
const response = (data: unknown) => ({ result: { data } });
|
const response = (data: unknown) => ({ result: { data } });
|
||||||
const operationNames = (route: Route) =>
|
const operationNames = (route: Route) =>
|
||||||
decodeURIComponent(new URL(route.request().url()).pathname.split('/trpc/')[1] ?? '').split(',');
|
decodeURIComponent(new URL(route.request().url()).pathname.split('/trpc/')[1] ?? '').split(',');
|
||||||
|
|
||||||
const installArchive = async (page: Page) => {
|
const installArchive = async (page: Page) => {
|
||||||
await page.addInitScript(() => {
|
await page.addInitScript((profile) => {
|
||||||
localStorage.setItem('sammo-game-token', 'ga_archive');
|
localStorage.setItem('sammo-game-token', 'ga_archive');
|
||||||
localStorage.setItem('sammo-game-profile', 'che:default');
|
localStorage.setItem('sammo-game-profile', profile);
|
||||||
});
|
}, gameProfile);
|
||||||
await page.route('**/che/api/trpc/**', async (route) => {
|
await page.route(gameTrpcRoute, async (route) => {
|
||||||
const results = operationNames(route).map((operation) => {
|
const results = operationNames(route).map((operation) => {
|
||||||
if (operation === 'auth.status') return response({ ok: true });
|
if (operation === 'auth.status') return response({ ok: true });
|
||||||
if (operation === 'lobby.info') return response({ myGeneral: null });
|
if (operation === 'lobby.info') return response({ myGeneral: null });
|
||||||
@@ -77,7 +78,7 @@ test('past plays is available without a current general and preserves desktop in
|
|||||||
await expect(page.getByRole('heading', { name: '내 지난 플레이 보기' })).toBeVisible();
|
await expect(page.getByRole('heading', { name: '내 지난 플레이 보기' })).toBeVisible();
|
||||||
await expect(page.getByText('천하쟁패 · 51기')).toBeVisible();
|
await expect(page.getByText('천하쟁패 · 51기')).toBeVisible();
|
||||||
await expect(page.locator('.general-name')).toHaveText('관우');
|
await expect(page.locator('.general-name')).toHaveText('관우');
|
||||||
await expect(page.getByRole('link', { name: '이 기수 국가 정보' })).toHaveAttribute('href', '/che/dynasty/7');
|
await expect(page.getByRole('link', { name: '이 기수 국가 정보' })).toHaveAttribute('href', gamePath('/dynasty/7'));
|
||||||
const historyToggle = page.locator('.history-toggle');
|
const historyToggle = page.locator('.history-toggle');
|
||||||
await expect(historyToggle).toHaveText('보기 (2)');
|
await expect(historyToggle).toHaveText('보기 (2)');
|
||||||
await historyToggle.click();
|
await historyToggle.click();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { expect, test, type Page, type Route } from '@playwright/test';
|
import { expect, test, type Page, type Route } from '@playwright/test';
|
||||||
|
import { gameBasePath, gameProfile, gameTrpcRoute } from './gameTestPaths.js';
|
||||||
|
|
||||||
const response = (data: unknown) => ({ result: { data } });
|
const response = (data: unknown) => ({ result: { data } });
|
||||||
|
|
||||||
@@ -24,22 +25,23 @@ const publicResponse = (operation: string): unknown => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const seedGameStorage = async (page: Page, gameToken: string): Promise<void> => {
|
const seedGameStorage = async (page: Page, gameToken: string): Promise<void> => {
|
||||||
await page.addInitScript((token) => {
|
await page.addInitScript(
|
||||||
window.localStorage.setItem('sammo-game-token', token);
|
({ token, profile }) => {
|
||||||
window.localStorage.setItem('sammo-game-profile', 'che:default');
|
window.localStorage.setItem('sammo-game-token', token);
|
||||||
}, gameToken);
|
window.localStorage.setItem('sammo-game-profile', profile);
|
||||||
|
},
|
||||||
|
{ token: gameToken, profile: gameProfile }
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
test('removes an invalid ga_ token and redirects an authenticated route to public', async ({
|
test('removes an invalid ga_ token and redirects an authenticated route to public', async ({ page }) => {
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
await seedGameStorage(page, 'ga_invalid');
|
await seedGameStorage(page, 'ga_invalid');
|
||||||
let gatewayRequests = 0;
|
let gatewayRequests = 0;
|
||||||
await page.route('http://127.0.0.1:15120/api/trpc/**', async (route) => {
|
await page.route('http://127.0.0.1:15120/api/trpc/**', async (route) => {
|
||||||
gatewayRequests += 1;
|
gatewayRequests += 1;
|
||||||
await route.abort();
|
await route.abort();
|
||||||
});
|
});
|
||||||
await page.route('**/che/api/trpc/**', async (route) => {
|
await page.route(gameTrpcRoute, async (route) => {
|
||||||
const operations = operationNames(route);
|
const operations = operationNames(route);
|
||||||
if (operations.includes('auth.status')) {
|
if (operations.includes('auth.status')) {
|
||||||
expect(route.request().headers().authorization).toBe('Bearer ga_invalid');
|
expect(route.request().headers().authorization).toBe('Bearer ga_invalid');
|
||||||
@@ -58,7 +60,7 @@ test('removes an invalid ga_ token and redirects an authenticated route to publi
|
|||||||
});
|
});
|
||||||
|
|
||||||
await page.goto('select-general');
|
await page.goto('select-general');
|
||||||
await expect(page).toHaveURL(/\/che\/public$/);
|
await expect(page).toHaveURL(new RegExp(`${gameBasePath}/public$`));
|
||||||
await expect(page.getByRole('heading', { name: '공개 동향' })).toBeVisible();
|
await expect(page.getByRole('heading', { name: '공개 동향' })).toBeVisible();
|
||||||
expect(await page.evaluate(() => window.localStorage.getItem('sammo-game-token'))).toBeNull();
|
expect(await page.evaluate(() => window.localStorage.getItem('sammo-game-token'))).toBeNull();
|
||||||
expect(gatewayRequests).toBe(0);
|
expect(gatewayRequests).toBe(0);
|
||||||
@@ -74,7 +76,7 @@ test('keeps a valid ga_ token when only lobby.info is unavailable', async ({ pag
|
|||||||
gatewayRequests += 1;
|
gatewayRequests += 1;
|
||||||
await route.abort();
|
await route.abort();
|
||||||
});
|
});
|
||||||
await page.route('**/che/api/trpc/**', async (route) => {
|
await page.route(gameTrpcRoute, async (route) => {
|
||||||
const operations = operationNames(route);
|
const operations = operationNames(route);
|
||||||
if (operations.includes('auth.status')) {
|
if (operations.includes('auth.status')) {
|
||||||
statusRequests += 1;
|
statusRequests += 1;
|
||||||
@@ -103,11 +105,9 @@ test('keeps a valid ga_ token when only lobby.info is unavailable', async ({ pag
|
|||||||
});
|
});
|
||||||
|
|
||||||
await page.goto('select-general');
|
await page.goto('select-general');
|
||||||
await expect(page).toHaveURL(/\/che\/select-general$/);
|
await expect(page).toHaveURL(new RegExp(`${gameBasePath}/select-general$`));
|
||||||
await expect(page.locator('.page-title')).toContainText('장 수 선 택');
|
await expect(page.locator('.page-title')).toContainText('장 수 선 택');
|
||||||
expect(await page.evaluate(() => window.localStorage.getItem('sammo-game-token'))).toBe(
|
expect(await page.evaluate(() => window.localStorage.getItem('sammo-game-token'))).toBe('ga_valid');
|
||||||
'ga_valid'
|
|
||||||
);
|
|
||||||
expect(statusRequests).toBe(1);
|
expect(statusRequests).toBe(1);
|
||||||
expect(lobbyRequests).toBe(1);
|
expect(lobbyRequests).toBe(1);
|
||||||
expect(gatewayRequests).toBe(0);
|
expect(gatewayRequests).toBe(0);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { expect, test, type Page, type Route } from '@playwright/test';
|
|||||||
import { readFile } from 'node:fs/promises';
|
import { readFile } from 'node:fs/promises';
|
||||||
import { dirname, resolve } from 'node:path';
|
import { dirname, resolve } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { gameProfile, gameTrpcRoute } from './gameTestPaths.js';
|
||||||
|
|
||||||
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
|
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
|
||||||
const imageRoots = [
|
const imageRoots = [
|
||||||
@@ -119,10 +120,10 @@ const gotoTroop = async (page: Page) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const installApiFixture = async (page: Page, state: FixtureState) => {
|
const installApiFixture = async (page: Page, state: FixtureState) => {
|
||||||
await page.addInitScript(() => {
|
await page.addInitScript((profile) => {
|
||||||
window.localStorage.setItem('sammo-game-token', 'ga_playwright');
|
window.localStorage.setItem('sammo-game-token', 'ga_playwright');
|
||||||
window.localStorage.setItem('sammo-game-profile', 'che:default');
|
window.localStorage.setItem('sammo-game-profile', profile);
|
||||||
});
|
}, gameProfile);
|
||||||
for (const filename of ['back_walnut.jpg', 'back_green.jpg']) {
|
for (const filename of ['back_walnut.jpg', 'back_green.jpg']) {
|
||||||
await page.route(`**/image/game/${filename}`, async (route) => {
|
await page.route(`**/image/game/${filename}`, async (route) => {
|
||||||
await route.fulfill({
|
await route.fulfill({
|
||||||
@@ -142,7 +143,7 @@ const installApiFixture = async (page: Page, state: FixtureState) => {
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
await page.route('**/che/api/trpc/**', async (route) => {
|
await page.route(gameTrpcRoute, async (route) => {
|
||||||
const operations = operationName(route).split(',');
|
const operations = operationName(route).split(',');
|
||||||
const results = operations.map((operation) => {
|
const results = operations.map((operation) => {
|
||||||
if (operation === 'auth.status') return response({ ok: true });
|
if (operation === 'auth.status') return response({ ok: true });
|
||||||
|
|||||||
Reference in New Issue
Block a user