fix: align legacy general access call boundaries
This commit is contained in:
@@ -66,13 +66,35 @@ const bettingSummary = {
|
||||
myAmount: 50,
|
||||
};
|
||||
|
||||
type FixtureState = {
|
||||
betCalls: number;
|
||||
joinCalls: number;
|
||||
snapshotQueries: number;
|
||||
summaryQueries: number;
|
||||
rankingQueries: number;
|
||||
accessCalls: number;
|
||||
stage: number;
|
||||
myGeneralId: number;
|
||||
};
|
||||
|
||||
const fixtureByPage = new WeakMap<Page, FixtureState>();
|
||||
|
||||
const installFixture = async (page: Page) => {
|
||||
const state: FixtureState = {
|
||||
betCalls: 0,
|
||||
joinCalls: 0,
|
||||
snapshotQueries: 0,
|
||||
summaryQueries: 0,
|
||||
rankingQueries: 0,
|
||||
accessCalls: 0,
|
||||
stage: snapshot.state.stage,
|
||||
myGeneralId: 64,
|
||||
};
|
||||
fixtureByPage.set(page, state);
|
||||
await page.addInitScript(() => {
|
||||
window.localStorage.setItem('sammo-game-token', 'ga_tournament_visual');
|
||||
window.localStorage.setItem('sammo-game-profile', 'che:default');
|
||||
});
|
||||
let betCalls = 0;
|
||||
let joinCalls = 0;
|
||||
await page.route('**/image/game/**', (route) =>
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
@@ -82,16 +104,32 @@ const installFixture = async (page: Page) => {
|
||||
);
|
||||
await page.route('**/che/api/trpc/**', async (route) => {
|
||||
const results = operationNames(route).map((operation) => {
|
||||
if (operation === 'auth.status') {
|
||||
return response({ userId: 'tournament-user' });
|
||||
}
|
||||
if (operation === 'lobby.info') {
|
||||
return response({ myGeneral: { id: 64, name: '내장수' } });
|
||||
return response({ myGeneral: { id: state.myGeneralId, name: '내장수' } });
|
||||
}
|
||||
if (operation === 'join.getConfig') return response({});
|
||||
if (operation === 'general.me') {
|
||||
return response({ general: { id: 64, name: '내장수' }, nation: null, city: null });
|
||||
return response({ general: { id: state.myGeneralId, name: '내장수' }, nation: null, city: null });
|
||||
}
|
||||
if (operation === 'tournament.getSnapshot') {
|
||||
state.snapshotQueries += 1;
|
||||
return response({
|
||||
...snapshot,
|
||||
state: {
|
||||
...snapshot.state,
|
||||
stage: state.stage,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (operation === 'tournament.getBettingSummary') {
|
||||
state.summaryQueries += 1;
|
||||
return response(bettingSummary);
|
||||
}
|
||||
if (operation === 'tournament.getSnapshot') return response(snapshot);
|
||||
if (operation === 'tournament.getBettingSummary') return response(bettingSummary);
|
||||
if (operation === 'tournament.getRankings') {
|
||||
state.rankingQueries += 1;
|
||||
return response(
|
||||
[
|
||||
['tt', '전 력 전', '종합'],
|
||||
@@ -123,17 +161,21 @@ const installFixture = async (page: Page) => {
|
||||
if (operation === 'tournament.getAdminStatus')
|
||||
return errorResponse(operation, 'Admin permission is required.');
|
||||
if (operation === 'tournament.join') {
|
||||
joinCalls += 1;
|
||||
return joinCalls === 1
|
||||
state.joinCalls += 1;
|
||||
return state.joinCalls === 1
|
||||
? errorResponse(operation, '금이 부족합니다.')
|
||||
: response({ ok: true, count: 64 });
|
||||
}
|
||||
if (operation === 'tournament.placeBet') {
|
||||
betCalls += 1;
|
||||
return betCalls === 1
|
||||
state.betCalls += 1;
|
||||
return state.betCalls === 1
|
||||
? errorResponse(operation, '500금까지만 베팅 가능합니다.')
|
||||
: response({ ok: true });
|
||||
}
|
||||
if (operation === 'public.recordAccess') {
|
||||
state.accessCalls += 1;
|
||||
return response({ recorded: true });
|
||||
}
|
||||
return errorResponse(operation, `Unhandled fixture operation: ${operation}`);
|
||||
});
|
||||
await route.fulfill({
|
||||
@@ -204,11 +246,33 @@ test('tournament keeps the fixed legacy canvas at a 1024px viewport', async ({ p
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeGreaterThanOrEqual(2000);
|
||||
});
|
||||
|
||||
test('tournament reloads its snapshot after failed and successful joins without route access', async ({ page }) => {
|
||||
const state = fixtureByPage.get(page)!;
|
||||
state.stage = 1;
|
||||
state.myGeneralId = 999;
|
||||
await page.goto(`${gameUrl}/che/tournament`);
|
||||
const join = page.getByRole('button', { name: '참가', exact: true });
|
||||
await expect(join).toBeVisible();
|
||||
await expect.poll(() => state.snapshotQueries).toBe(1);
|
||||
|
||||
await join.click();
|
||||
await expect(page.getByRole('status')).toHaveText('금이 부족합니다.');
|
||||
await expect.poll(() => state.snapshotQueries).toBe(2);
|
||||
|
||||
await join.click();
|
||||
await expect(page.getByRole('status')).toHaveText('참가 신청이 반영되었습니다.');
|
||||
await expect.poll(() => state.snapshotQueries).toBe(3);
|
||||
expect(state.summaryQueries).toBe(3);
|
||||
expect(state.accessCalls).toBe(0);
|
||||
});
|
||||
|
||||
test('betting keeps the 1120px and 16 by 70px layout and retains a failed selection', async ({ page }) => {
|
||||
const state = fixtureByPage.get(page)!;
|
||||
await page.setViewportSize({ width: 1280, height: 900 });
|
||||
await page.goto(`${gameUrl}/che/betting`);
|
||||
await expect(page.getByText('베 팅 장')).toBeVisible();
|
||||
await expect(page.locator('.names span')).toHaveCount(16);
|
||||
await expect.poll(() => state.snapshotQueries).toBe(1);
|
||||
|
||||
const geometry = await page.locator('#tournament-betting-container').evaluate((container) => {
|
||||
const rect = container.getBoundingClientRect();
|
||||
@@ -251,7 +315,12 @@ test('betting keeps the 1120px and 16 by 70px layout and retains a failed select
|
||||
await bet.click();
|
||||
await expect(page.getByRole('status')).toHaveText('500금까지만 베팅 가능합니다.');
|
||||
await expect(select).toHaveValue('500');
|
||||
await expect.poll(() => state.snapshotQueries).toBe(2);
|
||||
|
||||
await bet.click();
|
||||
await expect(page.getByRole('status')).toHaveText('베팅이 등록되었습니다.');
|
||||
await expect.poll(() => state.snapshotQueries).toBe(3);
|
||||
expect(state.summaryQueries).toBe(3);
|
||||
expect(state.rankingQueries).toBe(3);
|
||||
expect(state.accessCalls).toBe(0);
|
||||
});
|
||||
|
||||
@@ -16,7 +16,9 @@ const artifactRoot = process.env.FRONTEND_PARITY_ARTIFACT_DIR;
|
||||
const passwordPublicKey = generateKeyPairSync('rsa', {
|
||||
modulusLength: 2048,
|
||||
publicExponent: 0x10001,
|
||||
}).publicKey.export({ format: 'pem', type: 'spki' }).toString();
|
||||
})
|
||||
.publicKey.export({ format: 'pem', type: 'spki' })
|
||||
.toString();
|
||||
|
||||
const response = (data: unknown) => ({ result: { data } });
|
||||
|
||||
@@ -154,9 +156,7 @@ const installGatewayFixture = async (page: Page): Promise<void> => {
|
||||
return {
|
||||
available: true,
|
||||
normalizedValue:
|
||||
fieldInput?.field === 'username'
|
||||
? fieldInput.value?.toLowerCase()
|
||||
: fieldInput?.value,
|
||||
fieldInput?.field === 'username' ? fieldInput.value?.toLowerCase() : fieldInput?.value,
|
||||
message: '사용할 수 있습니다.',
|
||||
};
|
||||
}
|
||||
@@ -216,15 +216,31 @@ const installGatewayFixture = async (page: Page): Promise<void> => {
|
||||
});
|
||||
};
|
||||
|
||||
const installHallFixture = async (page: Page): Promise<void> => {
|
||||
type HallFixtureCalls = {
|
||||
options: number;
|
||||
hallInputs: unknown[];
|
||||
};
|
||||
|
||||
const installHallFixture = async (page: Page): Promise<HallFixtureCalls> => {
|
||||
const calls: HallFixtureCalls = {
|
||||
options: 0,
|
||||
hallInputs: [],
|
||||
};
|
||||
await installImages(page);
|
||||
await page.route('**/che/api/trpc/**', async (route) => {
|
||||
await fulfillOperations(route, (operation) => {
|
||||
if (operation === 'ranking.getHallOfFameOptions') return fixture.game.hallOptions;
|
||||
if (operation === 'ranking.getHallOfFame') return fixture.game.hall;
|
||||
await fulfillOperations(route, (operation, input) => {
|
||||
if (operation === 'ranking.getHallOfFameOptions') {
|
||||
calls.options += 1;
|
||||
return fixture.game.hallOptions;
|
||||
}
|
||||
if (operation === 'ranking.getHallOfFame') {
|
||||
calls.hallInputs.push(input);
|
||||
return fixture.game.hall;
|
||||
}
|
||||
throw new Error(`Unhandled hall fixture operation: ${operation}`);
|
||||
});
|
||||
});
|
||||
return calls;
|
||||
};
|
||||
|
||||
const installAuthenticatedGameFixture = async (page: Page): Promise<void> => {
|
||||
@@ -730,8 +746,10 @@ test.describe('best general legacy parity', () => {
|
||||
});
|
||||
|
||||
test.describe('hall of fame legacy parity', () => {
|
||||
let hallCalls: HallFixtureCalls;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await installHallFixture(page);
|
||||
hallCalls = await installHallFixture(page);
|
||||
});
|
||||
|
||||
for (const viewport of [
|
||||
@@ -742,6 +760,9 @@ test.describe('hall of fame legacy parity', () => {
|
||||
await page.setViewportSize(viewport);
|
||||
await page.goto('http://127.0.0.1:15102/che/hall-of-fame');
|
||||
await expect(page.getByText('유비')).toBeVisible();
|
||||
await expect.poll(() => hallCalls.options).toBe(1);
|
||||
await expect.poll(() => hallCalls.hallInputs.length).toBe(1);
|
||||
expect(hallCalls.hallInputs[0]).toEqual({ season: 1 });
|
||||
await expect(page.locator('.rankView')).toHaveCount(2);
|
||||
if (artifactRoot) {
|
||||
await page.screenshot({
|
||||
@@ -807,14 +828,19 @@ test.describe('hall of fame legacy parity', () => {
|
||||
await expect(scenario).toBeFocused();
|
||||
await scenario.selectOption('scenario:1:22');
|
||||
await expect(scenario).toHaveValue('scenario:1:22');
|
||||
await expect.poll(() => hallCalls.hallInputs.length).toBe(2);
|
||||
expect(hallCalls.hallInputs[1]).toEqual({ season: 1, scenario: 22 });
|
||||
expect(hallCalls.options).toBe(1);
|
||||
});
|
||||
}
|
||||
|
||||
test('keeps the selected scenario after a hall API error', async ({ page }) => {
|
||||
await page.goto('http://127.0.0.1:15102/che/hall-of-fame');
|
||||
await expect(page.getByText('유비')).toBeVisible();
|
||||
let failedHallRequests = 0;
|
||||
await page.route('**/che/api/trpc/**', async (route) => {
|
||||
if (operationNames(route).includes('ranking.getHallOfFame')) {
|
||||
failedHallRequests += 1;
|
||||
await route.fulfill({
|
||||
status: 500,
|
||||
contentType: 'application/json',
|
||||
@@ -829,6 +855,9 @@ test.describe('hall of fame legacy parity', () => {
|
||||
await expect(page.getByRole('alert')).toBeVisible();
|
||||
await expect(scenario).toHaveValue('scenario:1:22');
|
||||
await expect(page.getByText('유비')).toBeVisible();
|
||||
await expect.poll(() => failedHallRequests).toBe(1);
|
||||
await page.waitForTimeout(250);
|
||||
expect(failedHallRequests).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user