merge: 최신 main 정렬 제어 변경을 갱신 제어 작업에 통합
This commit is contained in:
@@ -130,6 +130,45 @@ const generals = [
|
||||
},
|
||||
];
|
||||
|
||||
const npcGenerals = [
|
||||
{
|
||||
id: 10,
|
||||
name: '낮은장수',
|
||||
ownerName: '',
|
||||
npcState: 0,
|
||||
level: 4,
|
||||
nationId: 2,
|
||||
nationName: '촉',
|
||||
personality: null,
|
||||
specialDomestic: null,
|
||||
specialWar: null,
|
||||
statTotal: 120,
|
||||
leadership: 30,
|
||||
strength: 50,
|
||||
intelligence: 40,
|
||||
experience: 100,
|
||||
dedication: 50,
|
||||
},
|
||||
{
|
||||
id: 20,
|
||||
name: '높은장수',
|
||||
ownerName: '빙의자',
|
||||
npcState: 1,
|
||||
level: 8,
|
||||
nationId: 1,
|
||||
nationName: '위',
|
||||
personality: null,
|
||||
specialDomestic: null,
|
||||
specialWar: null,
|
||||
statTotal: 240,
|
||||
leadership: 90,
|
||||
strength: 70,
|
||||
intelligence: 80,
|
||||
experience: 500,
|
||||
dedication: 300,
|
||||
},
|
||||
];
|
||||
|
||||
const parseSort = (route: Route): number => {
|
||||
try {
|
||||
const request = route.request();
|
||||
@@ -224,6 +263,20 @@ const install = async (
|
||||
sort === 8 ? [...generals].sort((left, right) => left.killturn - right.killturn) : generals;
|
||||
return response({ sort, generals: rows });
|
||||
}
|
||||
if (operation === 'public.getNpcList') {
|
||||
const sort = parseSort(route);
|
||||
const rows = [...npcGenerals].sort((left, right) => {
|
||||
if (sort === 2) return left.nationId - right.nationId || left.id - right.id;
|
||||
if (sort === 3) return right.statTotal - left.statTotal || left.id - right.id;
|
||||
if (sort === 4) return right.leadership - left.leadership || left.id - right.id;
|
||||
if (sort === 5) return right.strength - left.strength || left.id - right.id;
|
||||
if (sort === 6) return right.intelligence - left.intelligence || left.id - right.id;
|
||||
if (sort === 7) return right.experience - left.experience || left.id - right.id;
|
||||
if (sort === 8) return right.dedication - left.dedication || left.id - right.id;
|
||||
return left.name.localeCompare(right.name) || left.id - right.id;
|
||||
});
|
||||
return response({ sort, generals: rows, tokenKeepCounts: {} });
|
||||
}
|
||||
return { error: { message: `unhandled ${operation}`, data: { code: 'BAD_REQUEST' } } };
|
||||
});
|
||||
await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(results) });
|
||||
@@ -340,7 +393,7 @@ test('nation and general directories preserve the fixed legacy Chromium geometry
|
||||
await expect.poll(() => accessPages).toContain('nation-list');
|
||||
expect(accessPages).not.toContain('general-list');
|
||||
|
||||
const header = page.locator('.general-table thead td').first();
|
||||
const header = page.locator('.general-table thead th').first();
|
||||
expect(await header.evaluate((element) => getComputedStyle(element).backgroundImage)).toContain('back_green.jpg');
|
||||
const icon = page.locator('.general-icon').first();
|
||||
await expect(icon).toBeVisible();
|
||||
@@ -392,6 +445,78 @@ test('general directory submits the legacy sort selector and keeps wounded/bonus
|
||||
expect(await page.locator('#viewType').evaluate((element) => document.activeElement === element)).toBe(true);
|
||||
});
|
||||
|
||||
test('directory sort controls stay legible in dark mode and sortable headers apply the matching option', async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
await install(page);
|
||||
await page.goto('general-list');
|
||||
|
||||
const select = page.locator('#viewType');
|
||||
const submit = page.getByRole('button', { name: '정렬하기' });
|
||||
const colors = await select.evaluate((element) => {
|
||||
const selectStyle = getComputedStyle(element);
|
||||
const optionStyle = getComputedStyle(element.querySelector('option')!);
|
||||
return {
|
||||
selectBackground: selectStyle.backgroundColor,
|
||||
selectColor: selectStyle.color,
|
||||
optionBackground: optionStyle.backgroundColor,
|
||||
optionColor: optionStyle.color,
|
||||
};
|
||||
});
|
||||
expect(colors).toEqual({
|
||||
selectBackground: 'rgb(24, 35, 29)',
|
||||
selectColor: 'rgb(247, 250, 248)',
|
||||
optionBackground: 'rgb(24, 35, 29)',
|
||||
optionColor: 'rgb(247, 250, 248)',
|
||||
});
|
||||
const defaultButton = await submit.evaluate((element) => {
|
||||
const style = getComputedStyle(element);
|
||||
return {
|
||||
background: style.backgroundColor,
|
||||
color: style.color,
|
||||
borderBottomWidth: style.borderBottomWidth,
|
||||
cursor: style.cursor,
|
||||
};
|
||||
});
|
||||
expect(defaultButton).toEqual({
|
||||
background: 'rgb(55, 90, 127)',
|
||||
color: 'rgb(255, 255, 255)',
|
||||
borderBottomWidth: '3px',
|
||||
cursor: 'pointer',
|
||||
});
|
||||
await submit.hover();
|
||||
await page.mouse.down();
|
||||
expect(await submit.evaluate((element) => getComputedStyle(element).borderBottomWidth)).toBe('1px');
|
||||
await page.mouse.up();
|
||||
|
||||
await page.getByRole('button', { name: '삭턴 기준 정렬' }).click();
|
||||
await expect(select).toHaveValue('8');
|
||||
await expect(page.locator('th[aria-sort="ascending"]')).toContainText('삭턴');
|
||||
await expect(page.locator('tbody tr[data-general-id]').first()).toHaveAttribute('data-general-id', '20');
|
||||
await page.screenshot({ path: testInfo.outputPath('directory-sort-controls-desktop.png'), fullPage: true });
|
||||
|
||||
await page.setViewportSize({ width: 500, height: 844 });
|
||||
await expect(select).toHaveCSS('background-color', 'rgb(24, 35, 29)');
|
||||
await expect(submit).toHaveCSS('border-bottom-width', '3px');
|
||||
await page.screenshot({ path: testInfo.outputPath('directory-sort-controls-mobile.png'), fullPage: true });
|
||||
});
|
||||
|
||||
test('npc directory reuses the dark sort controls and sorts from a table header', async ({ page }, testInfo) => {
|
||||
await install(page);
|
||||
await page.goto('npc-list');
|
||||
await expect(page.locator('.npc-table tbody tr[data-general-id]')).toHaveCount(2);
|
||||
await page.getByRole('button', { name: '통솔 기준 정렬' }).click();
|
||||
await expect(page.locator('#npc-list-sort')).toHaveValue('4');
|
||||
await expect(page.locator('.npc-table th[aria-sort="descending"]')).toContainText('통솔');
|
||||
await expect(page.locator('.npc-table tbody tr[data-general-id]').first()).toHaveAttribute('data-general-id', '20');
|
||||
await expect(page.locator('#npc-list-sort')).toHaveCSS('background-color', 'rgb(24, 35, 29)');
|
||||
await expect(page.getByRole('button', { name: '정렬하기' })).toHaveCSS('background-color', 'rgb(55, 90, 127)');
|
||||
await page.screenshot({ path: testInfo.outputPath('npc-sort-controls-desktop.png'), fullPage: true });
|
||||
await page.setViewportSize({ width: 500, height: 844 });
|
||||
await expect(page.locator('#npc-list-sort')).toHaveCSS('color', 'rgb(247, 250, 248)');
|
||||
await page.screenshot({ path: testInfo.outputPath('npc-sort-controls-mobile.png'), fullPage: true });
|
||||
});
|
||||
|
||||
test('nation directory reuses only the public general-directory row on hover and keyboard focus', async ({ page }) => {
|
||||
const requestedOperations: string[] = [];
|
||||
await install(page, 'general', [], requestedOperations);
|
||||
|
||||
@@ -353,6 +353,15 @@ test('암행부 행을 도시별로 나누고 수뇌의 인사부 즉시 임명
|
||||
await expect(page.locator('.city-user-table')).toHaveCount(0);
|
||||
await expect(page.getByRole('button', { name: '인사부 연동' })).toHaveCount(0);
|
||||
|
||||
const citySort = page.locator('#nation-city-sort');
|
||||
await expect(citySort).toHaveCSS('background-color', 'rgb(24, 35, 29)');
|
||||
await citySort.selectOption('5');
|
||||
await page.getByRole('button', { name: '정렬하기' }).click();
|
||||
await expect(page.locator('.city th[aria-sort="descending"]').first()).toContainText('농업');
|
||||
await page.getByRole('button', { name: '시세 기준 정렬' }).first().click();
|
||||
await expect(citySort).toHaveValue('10');
|
||||
await expect(page.locator('.city th[aria-sort="descending"]').first()).toContainText('시세');
|
||||
|
||||
await page.getByRole('button', { name: '암행부 연동' }).click();
|
||||
await expect(page.locator('.city-user-table')).toHaveCount(2);
|
||||
await expect(page.locator('.city[data-city-id="1"] .city-user-table tr[data-general-id="21"]')).toContainText(
|
||||
|
||||
@@ -149,6 +149,30 @@ const install = async (page: Page, secretAllowed = true) => {
|
||||
{ action: '휴식', args: {} },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '부유장수',
|
||||
npcState: 0,
|
||||
injury: 0,
|
||||
stats: { leadership: 60, strength: 50, intelligence: 40 },
|
||||
leadershipBonus: 0,
|
||||
experienceLevel: 8,
|
||||
troopId: 1,
|
||||
troopName: '제1부대',
|
||||
gold: 3000,
|
||||
rice: 1000,
|
||||
cityId: 2,
|
||||
cityName: '낙양',
|
||||
defenceTrain: 80,
|
||||
defenceTrainText: '◎',
|
||||
crewTypeId: 2,
|
||||
crew: 100,
|
||||
train: 80,
|
||||
atmos: 80,
|
||||
killTurn: 3,
|
||||
turnTime: '2026-01-01T02:02:00.000Z',
|
||||
reservedCommands: [],
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
@@ -381,7 +405,7 @@ test('secret office renders five Ref-style command briefs and the forbidden erro
|
||||
'5 : 휴식',
|
||||
]);
|
||||
await expect(commandRows.nth(2)).toHaveAttribute('title', '【다른장수】에게 쌀 200을 증여');
|
||||
const geometry = await page.locator('#secret-general-list .turns').evaluate((element) => {
|
||||
const geometry = await page.locator('#secret-general-list .turns').first().evaluate((element) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const style = getComputedStyle(element);
|
||||
return {
|
||||
@@ -416,3 +440,22 @@ test('secret office renders five Ref-style command briefs and the forbidden erro
|
||||
await expect(page.getByRole('alert')).toContainText('권한이 부족합니다.');
|
||||
await expect(page.locator('#secret-general-list')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('secret office applies the selected sort on submit and immediately from sortable headers', async ({ page }) => {
|
||||
await install(page);
|
||||
await page.goto('nation/secret');
|
||||
const rows = page.locator('#secret-general-list tbody tr[data-general-id]');
|
||||
await expect(rows.first()).toHaveAttribute('data-general-id', '1');
|
||||
|
||||
await page.locator('#secret-list-sort').selectOption('1');
|
||||
await expect(rows.first()).toHaveAttribute('data-general-id', '1');
|
||||
await page.getByRole('button', { name: '정렬하기' }).click();
|
||||
await expect(rows.first()).toHaveAttribute('data-general-id', '2');
|
||||
await expect(page.locator('#secret-general-list th[aria-sort="descending"]')).toContainText('자 금');
|
||||
|
||||
await page.getByRole('button', { name: '도시 기준 정렬' }).click();
|
||||
await expect(page.locator('#secret-list-sort')).toHaveValue('3');
|
||||
await expect(rows.first()).toHaveAttribute('data-general-id', '1');
|
||||
await expect(page.locator('#secret-list-sort')).toHaveCSS('color', 'rgb(247, 250, 248)');
|
||||
await expect(page.getByRole('button', { name: '정렬하기' })).toHaveCSS('border-bottom-width', '3px');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user