feat: build compact BO2 grind companion with cumulative ranks
Some checks failed
Test and deploy staging / staging (push) Failing after 2m50s
Some checks failed
Test and deploy staging / staging (push) Failing after 2m50s
This commit is contained in:
@@ -227,7 +227,8 @@ test('weapon/player ranks, challenge progress and osu goals/scores/training pers
|
||||
await page.getByLabel('Prestige', { exact: true }).fill('3');
|
||||
await page.getByRole('button', { name: 'Save rank' }).click();
|
||||
await expect(page.getByRole('dialog')).toHaveCount(0);
|
||||
await expect(page.getByText('Level 42 · Prestige 3')).toBeVisible();
|
||||
await expect(page.getByLabel('Player level and prestige')).toContainText('LEVEL42');
|
||||
await expect(page.getByLabel('Player level and prestige')).toContainText('PRESTIGE3');
|
||||
expect(
|
||||
(
|
||||
await action(page.request, cod + '?/saveRank', {
|
||||
@@ -250,8 +251,10 @@ test('weapon/player ranks, challenge progress and osu goals/scores/training pers
|
||||
await expect(
|
||||
weaponCard.getByRole('button', { name: `Edit ${weapon.name} level and prestige` })
|
||||
).toContainText('17');
|
||||
await expect(weaponCard).toContainText('Max level reached');
|
||||
await page.getByRole('tab', { name: 'challenges', exact: true }).click();
|
||||
await weaponCard.getByRole('button', { name: `${weapon.name} camos and milestones` }).click();
|
||||
await expect(page.getByRole('dialog')).toContainText('Max level reached');
|
||||
await page.keyboard.press('Escape');
|
||||
await page.getByRole('tab', { name: 'Challenges', exact: true }).click();
|
||||
await expect(page.locator('article')).toHaveCount(36);
|
||||
const goal = {
|
||||
kind: 'goal',
|
||||
@@ -526,7 +529,8 @@ test('live weapon controls save immediately, infer max level from prestige, and
|
||||
const cod = '/projects/game-tracker/call-of-duty/black-ops-3';
|
||||
await page.setViewportSize({ width: 1280, height: 800 });
|
||||
await page.goto(cod);
|
||||
const card = page.getByRole('article', { name: weapon.name, exact: true });
|
||||
await page.getByRole('button', { name: `${weapon.name} camos and milestones` }).click();
|
||||
const card = page.getByRole('dialog', { name: weapon.name, exact: true });
|
||||
const level = card.getByRole('button', { name: `Edit ${weapon.name} level and prestige` });
|
||||
await expect(card.getByRole('button', { name: `Level down ${weapon.name}` })).toBeDisabled();
|
||||
await card.getByRole('button', { name: `Level up ${weapon.name}` }).click();
|
||||
@@ -552,6 +556,7 @@ test('live weapon controls save immediately, infer max level from prestige, and
|
||||
);
|
||||
expect(concurrent.every((r) => r.status === 200)).toBe(true);
|
||||
await page.reload();
|
||||
await page.getByRole('button', { name: `${weapon.name} camos and milestones` }).click();
|
||||
await expect(level).toHaveText(/LEVEL5/);
|
||||
await page.route('**/*adjustWeaponRank', (route) => route.abort());
|
||||
await card.getByRole('button', { name: `Level up ${weapon.name}` }).click();
|
||||
@@ -589,6 +594,7 @@ test('live weapon controls save immediately, infer max level from prestige, and
|
||||
).status
|
||||
).toBe(401);
|
||||
await anonymous.dispose();
|
||||
await page.keyboard.press('Escape');
|
||||
const cards = await page
|
||||
.locator('.weapon-card')
|
||||
.evaluateAll((cards) => cards.map((c) => c.getBoundingClientRect().bottom));
|
||||
@@ -748,7 +754,7 @@ test('visible progress reacts to sightings, catches and completed stories withou
|
||||
await expect(
|
||||
page.getByRole('progressbar', { name: 'Badges & trials', exact: true })
|
||||
).toHaveAttribute('aria-valuenow', '12.5');
|
||||
await page.getByRole('button', { name: 'All progress ↗', exact: true }).click();
|
||||
await page.getByRole('button', { name: 'Full breakdown', exact: true }).click();
|
||||
await expect(
|
||||
page.getByRole('dialog', { name: 'Your Pokémon progress' }).getByRole('progressbar')
|
||||
).toHaveCount(16);
|
||||
@@ -799,7 +805,7 @@ test('partial COD challenges and osu goals visibly advance completion meters', a
|
||||
await page.goto(cod);
|
||||
const overall = page.getByRole('progressbar', { name: 'Game completion', exact: true });
|
||||
await expect(overall).toHaveAttribute('aria-valuenow', '0');
|
||||
await page.getByRole('tab', { name: 'challenges', exact: true }).click();
|
||||
await page.getByRole('tab', { name: 'Challenges', exact: true }).click();
|
||||
await page.getByLabel('Search challenges').fill(challenge.name);
|
||||
const card = page
|
||||
.getByRole('article')
|
||||
@@ -815,7 +821,7 @@ test('partial COD challenges and osu goals visibly advance completion meters', a
|
||||
await expect
|
||||
.poll(async () => Number(await overall.getAttribute('aria-valuenow')))
|
||||
.toBeGreaterThan(partial);
|
||||
await page.getByRole('tab', { name: 'weapons', exact: true }).click();
|
||||
await page.getByRole('tab', { name: 'Weapons', exact: true }).click();
|
||||
await page.screenshot({ path: '/tmp/tracker-progress-cod.png' });
|
||||
await action(page.request, '/projects/game-tracker/osu?/save', {
|
||||
kind: 'goal',
|
||||
@@ -839,3 +845,155 @@ test('partial COD challenges and osu goals visibly advance completion meters', a
|
||||
page.getByRole('progressbar', { name: 'Full combo goals', exact: true })
|
||||
).toHaveAttribute('aria-valuenow', '100');
|
||||
});
|
||||
|
||||
test('BO2 armoury fits every gun, enforces caps and advances all rank progress with each level', async ({
|
||||
page
|
||||
}) => {
|
||||
const userId = await register(page.request);
|
||||
const cod = '/projects/game-tracker/call-of-duty/black-ops-2';
|
||||
const [m27] =
|
||||
await sql`select i.id from tracker_items i join tracker_games g on g.id=i.game_id where g.slug='black-ops-2' and i.name='M27'`;
|
||||
await page.setViewportSize({ width: 1280, height: 720 });
|
||||
await page.goto(cod);
|
||||
await expect(page.locator('.weapon-card')).toHaveCount(40);
|
||||
for (const [width, height] of [
|
||||
[1280, 720],
|
||||
[1920, 1080]
|
||||
]) {
|
||||
await page.setViewportSize({ width, height });
|
||||
const bounds = await page.locator('.weapon-card').evaluateAll((cards) =>
|
||||
cards.map((c) => {
|
||||
const b = c.getBoundingClientRect();
|
||||
const section = c.closest('section')!.getBoundingClientRect();
|
||||
return {
|
||||
name: c.getAttribute('aria-label'),
|
||||
fits:
|
||||
b.bottom <= section.bottom + 1 &&
|
||||
b.bottom <= innerHeight &&
|
||||
b.right <= innerWidth &&
|
||||
b.height >= 29
|
||||
};
|
||||
})
|
||||
);
|
||||
expect(bounds.filter((b) => !b.fits)).toEqual([]);
|
||||
expect(await page.evaluate(() => document.documentElement.scrollHeight)).toBeLessThanOrEqual(
|
||||
height
|
||||
);
|
||||
await expect
|
||||
.poll(() =>
|
||||
page
|
||||
.locator('.weapon-card img')
|
||||
.evaluateAll((images) =>
|
||||
images.every(
|
||||
(i) => (i as HTMLImageElement).complete && (i as HTMLImageElement).naturalWidth > 0
|
||||
)
|
||||
)
|
||||
)
|
||||
.toBe(true);
|
||||
}
|
||||
for (const name of [
|
||||
'M27',
|
||||
'AN-94',
|
||||
'DSR 50',
|
||||
'Peacekeeper',
|
||||
'MP7',
|
||||
'Vector K10',
|
||||
'Skorpion EVO'
|
||||
]) {
|
||||
await expect(
|
||||
page
|
||||
.getByRole('article', { name, exact: true })
|
||||
.getByRole('button', { name: `View ${name} artwork` })
|
||||
).toBeVisible();
|
||||
}
|
||||
const card = page.getByRole('article', { name: 'M27', exact: true });
|
||||
const levels = page.getByRole('progressbar', { name: 'Weapon levels', exact: true });
|
||||
const overall = page.getByRole('progressbar', { name: 'Game completion', exact: true });
|
||||
await expect(levels).toHaveAttribute('aria-valuenow', '0');
|
||||
await card.getByRole('button', { name: 'Level up M27', exact: true }).click();
|
||||
await expect(card.getByRole('button', { name: 'Edit M27 level and prestige' })).toHaveText(
|
||||
'LEVEL2/17'
|
||||
);
|
||||
const first = Number(await levels.getAttribute('aria-valuenow'));
|
||||
expect(first).toBeGreaterThan(0);
|
||||
const before = Number(await overall.getAttribute('aria-valuenow'));
|
||||
await card.getByRole('button', { name: 'Level up M27', exact: true }).click();
|
||||
await expect
|
||||
.poll(async () => Number(await levels.getAttribute('aria-valuenow')))
|
||||
.toBeGreaterThan(first);
|
||||
await expect
|
||||
.poll(async () => Number(await overall.getAttribute('aria-valuenow')))
|
||||
.toBeGreaterThan(before);
|
||||
expect(
|
||||
(
|
||||
await action(page.request, cod + '?/saveRank', {
|
||||
itemId: String(m27.id),
|
||||
level: '18',
|
||||
prestige: '2'
|
||||
})
|
||||
).status
|
||||
).toBe(400);
|
||||
expect(
|
||||
(
|
||||
await action(page.request, cod + '?/saveRank', {
|
||||
itemId: String(m27.id),
|
||||
level: '17',
|
||||
prestige: '3'
|
||||
})
|
||||
).status
|
||||
).toBe(400);
|
||||
expect(
|
||||
(
|
||||
await action(page.request, cod + '?/adjustWeaponRank', {
|
||||
itemId: String(m27.id),
|
||||
field: 'prestige',
|
||||
delta: '1'
|
||||
})
|
||||
).status
|
||||
).toBe(400);
|
||||
await action(page.request, cod + '?/saveRank', {
|
||||
itemId: String(m27.id),
|
||||
level: '17',
|
||||
prestige: '0'
|
||||
});
|
||||
const simultaneous = await Promise.all(
|
||||
[1, 2].map(() =>
|
||||
action(page.request, cod + '?/adjustWeaponRank', {
|
||||
itemId: String(m27.id),
|
||||
field: 'prestige',
|
||||
delta: '1'
|
||||
})
|
||||
)
|
||||
);
|
||||
expect(simultaneous.filter((r) => r.status === 200)).toHaveLength(1);
|
||||
expect(
|
||||
(
|
||||
await sql`select level,prestige from tracker_weapon_ranks where user_id=${userId} and item_id=${m27.id}`
|
||||
)[0]
|
||||
).toMatchObject({ level: 1, prestige: 1 });
|
||||
await page.reload();
|
||||
await expect(card).toContainText('18/51');
|
||||
await action(page.request, cod + '?/saveRank', {
|
||||
itemId: String(m27.id),
|
||||
level: '17',
|
||||
prestige: '2'
|
||||
});
|
||||
await action(page.request, cod + '?/saveRank', { level: '42', prestige: '3' });
|
||||
await page.reload();
|
||||
await expect(card).toContainText('51/51');
|
||||
await expect(card.getByRole('button', { name: 'Level up M27' })).toBeDisabled();
|
||||
await expect(page.getByRole('img', { name: 'Prestige 3 emblem' })).toBeVisible();
|
||||
const progress = await overall.getAttribute('aria-valuenow');
|
||||
await page.goto('/projects/game-tracker');
|
||||
await expect(
|
||||
page.getByRole('progressbar', { name: 'Black Ops II progress', exact: true })
|
||||
).toHaveAttribute('aria-valuenow', progress!);
|
||||
await page.goto(cod);
|
||||
await page.setViewportSize({ width: 1280, height: 720 });
|
||||
await page.screenshot({ path: '/tmp/bo2-verified-desktop.png' });
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await page.screenshot({ path: '/tmp/bo2-verified-mobile.png', fullPage: true });
|
||||
await expect
|
||||
.poll(() => page.evaluate(() => document.documentElement.scrollWidth))
|
||||
.toBeLessThanOrEqual(390);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user