155 lines
9.1 KiB
TypeScript
155 lines
9.1 KiB
TypeScript
import { expect, test, type Page } from '@playwright/test';
|
|
|
|
async function login(page: Page, username: string) {
|
|
await page.addInitScript(() => localStorage.setItem('pipu.locale', 'ru'));
|
|
await page.goto('/login');
|
|
await page.getByLabel('Логин', { exact: true }).fill(username);
|
|
await page.getByRole('textbox', { name: 'Пароль', exact: true }).fill(`${username}-password`);
|
|
await page.getByRole('button', { name: 'Войти', exact: true }).click();
|
|
await expect(page.getByRole('button', { name: 'Ещё', exact: true })).toBeVisible();
|
|
}
|
|
|
|
async function fits(page: Page) {
|
|
await expect.poll(() => page.evaluate(() => {
|
|
const main = document.querySelector('main')!;
|
|
return Math.max(document.documentElement.scrollWidth - innerWidth, main.scrollWidth - main.clientWidth);
|
|
})).toBeLessThanOrEqual(1);
|
|
}
|
|
|
|
for (const [width, username] of [[320, 'mobile-admin'], [390, 'moderator'], [430, 'alice']] as const) {
|
|
test(`mobile ${width}: ${username} navigation, forms and search`, async ({ page }, info) => {
|
|
test.setTimeout(60_000);
|
|
await page.setViewportSize({ width, height: 844 });
|
|
await login(page, username);
|
|
await fits(page);
|
|
const bottom = page.getByRole('navigation', { name: 'Навигация' }).filter({ has: page.getByRole('button', { name: 'Ещё', exact: true }) });
|
|
await expect(bottom.getByRole('link')).toHaveCount(3);
|
|
await page.getByRole('button', { name: 'Ещё', exact: true }).click();
|
|
const dialog = page.getByRole('dialog', { name: 'Навигация' });
|
|
await expect(dialog).toBeVisible();
|
|
await expect(dialog.getByRole('link', { name: 'Дизлайки', exact: true })).toBeVisible();
|
|
if (username !== 'alice') {
|
|
await expect(dialog.getByRole('link', { name: 'Пользователи', exact: true })).toBeVisible();
|
|
await expect(dialog.getByRole('link', { name: 'Очередь', exact: true })).toBeVisible();
|
|
await expect(dialog.getByRole('link', { name: 'Хранилища', exact: true })).toHaveCount(username === 'mobile-admin' ? 1 : 0);
|
|
await dialog.getByRole('link', { name: 'Пользователи', exact: true }).click();
|
|
await expect(dialog).not.toBeVisible();
|
|
await expect(page.getByRole('heading', { name: 'Пользователи', exact: true })).toBeVisible();
|
|
await fits(page);
|
|
await page.screenshot({ path: info.outputPath('users.png') });
|
|
await page.getByRole('button', { name: /Действия.*alice/ }).click();
|
|
const menu = page.getByRole('menu');
|
|
await expect(menu).toBeVisible();
|
|
const rect = await menu.boundingBox();
|
|
expect(rect!.x).toBeGreaterThanOrEqual(0);
|
|
expect(rect!.x + rect!.width).toBeLessThanOrEqual(width);
|
|
await page.keyboard.press('Escape');
|
|
await page.getByRole('button', { name: 'Создать пользователя', exact: true }).click();
|
|
await expect(page.getByRole('dialog')).toBeVisible();
|
|
await page.screenshot({ path: info.outputPath('create-user.png') });
|
|
await page.getByRole('button', { name: 'Закрыть', exact: true }).click();
|
|
} else {
|
|
await expect(dialog.getByRole('link', { name: 'Пользователи', exact: true })).toHaveCount(0);
|
|
await page.getByRole('button', { name: 'Закрыть', exact: true }).click();
|
|
}
|
|
await page.getByRole('button', { name: 'Меню профиля' }).click();
|
|
await page.getByRole('menuitem', { name: 'Настройки', exact: true }).click();
|
|
await expect(page.getByRole('heading', { name: 'Настройки', exact: true })).toBeVisible();
|
|
await fits(page);
|
|
await page.screenshot({ path: info.outputPath('settings.png') });
|
|
for (const name of ['Слева', 'По центру', 'Справа']) {
|
|
await page.getByRole('button', { name, exact: true }).click();
|
|
await page.getByRole('combobox', { name: 'Поиск', exact: true }).fill('кино');
|
|
await expect(page.getByRole('option', { name: /Кино/ }).first()).toBeVisible();
|
|
await fits(page);
|
|
await page.getByRole('combobox', { name: 'Поиск', exact: true }).press('Escape');
|
|
}
|
|
|
|
if (username !== 'alice') {
|
|
await page.getByRole('button', { name: 'Ещё', exact: true }).click();
|
|
await page.getByRole('dialog').getByRole('link', { name: 'Очередь', exact: true }).click();
|
|
await expect(page.getByRole('heading', { name: 'Очередь на добавление' })).toBeVisible();
|
|
await expect(page.locator('audio')).toBeHidden();
|
|
await page.getByRole('button', { name: 'Развернуть пачку', exact: true }).click();
|
|
await expect(page.locator('audio')).toBeVisible();
|
|
await fits(page);
|
|
await page.getByRole('checkbox', { name: /^Выбрать Длинное/ }).check();
|
|
await expect(page.getByRole('region', { name: 'Действия с выбранными' })).toBeVisible();
|
|
await fits(page);
|
|
await page.screenshot({ path: info.outputPath('upload-queue.png') });
|
|
await page.getByRole('region', { name: 'Действия с выбранными' }).getByRole('button', { name: 'Отклонить' }).click();
|
|
await expect(page.getByRole('dialog')).toBeVisible();
|
|
await page.getByRole('button', { name: 'Закрыть', exact: true }).click();
|
|
}
|
|
if (username === 'mobile-admin') {
|
|
await page.getByRole('button', { name: 'Ещё', exact: true }).click();
|
|
await page.getByRole('dialog').getByRole('link', { name: 'Хранилища', exact: true }).click();
|
|
await expect(page.getByRole('article', { name: 'Музыкальное хранилище' })).toBeVisible();
|
|
await fits(page);
|
|
await page.getByRole('button', { name: 'Шаблоны путей', exact: true }).click();
|
|
await page.getByRole('button', { name: 'Добавить шаблон', exact: true }).click();
|
|
await fits(page);
|
|
await page.screenshot({ path: info.outputPath('patterns.png') });
|
|
}
|
|
});
|
|
}
|
|
|
|
for (const width of [390, 1280]) {
|
|
test(`player artist opens without a browser URL preview at ${width}px`, async ({ page }) => {
|
|
await page.setViewportSize({ width: 390, height: 844 });
|
|
await login(page, 'alice');
|
|
await page.setViewportSize({ width, height: 844 });
|
|
const box = page.getByRole('combobox', { name: 'Поиск', exact: true });
|
|
await box.fill('кино');
|
|
await box.press('Enter');
|
|
await page.getByRole('link', { name: /Группа крови/ }).first().click();
|
|
await page.getByRole('listitem').first().click();
|
|
const artist = page.getByRole('contentinfo', { name: 'Плеер' }).getByRole('link', { name: 'Кино', exact: true });
|
|
await artist.hover();
|
|
await expect(artist).not.toHaveAttribute('href');
|
|
expect(await artist.evaluate((el) => Boolean(el.closest('[title], a[href]')))).toBe(false);
|
|
if (width === 390) {
|
|
await artist.focus();
|
|
await page.keyboard.press('Enter');
|
|
} else {
|
|
await artist.click();
|
|
}
|
|
await expect(page).toHaveURL(/\/artist\//);
|
|
await expect(page.getByRole('heading', { name: 'Кино', exact: true })).toBeVisible();
|
|
});
|
|
}
|
|
|
|
test('mobile player keeps the island above navigation and exposes the queue', async ({ page }, info) => {
|
|
await page.setViewportSize({ width: 320, height: 740 });
|
|
await login(page, 'alice');
|
|
const box = page.getByRole('combobox', { name: 'Поиск', exact: true });
|
|
await box.fill('кино');
|
|
await box.press('Enter');
|
|
await page.getByRole('link', { name: /Группа крови/ }).first().click();
|
|
await page.getByRole('listitem').first().click();
|
|
const player = page.getByRole('contentinfo', { name: 'Плеер' });
|
|
await expect(player.getByRole('button', { name: 'Очередь', exact: true })).toBeVisible();
|
|
expect((await player.getByText('Группа крови', { exact: true }).boundingBox())!.width).toBeGreaterThan(220);
|
|
const artist = player.getByRole('link', { name: 'Кино', exact: true });
|
|
await expect(artist).toBeVisible();
|
|
const artistArea = await artist.locator('..').boundingBox();
|
|
expect(artistArea!.width).toBeGreaterThan(220);
|
|
const trackInfo = await player.getByText('Группа крови', { exact: true }).boundingBox();
|
|
const play = await player.getByRole('button', { name: /^(Пауза|Слушать)$/ }).boundingBox();
|
|
expect(trackInfo!.y + trackInfo!.height).toBeLessThanOrEqual(play!.y);
|
|
await page.screenshot({ path: info.outputPath('player-readable.png') });
|
|
await fits(page);
|
|
await page.getByRole('button', { name: 'Меню профиля' }).click();
|
|
await page.getByRole('menuitem', { name: 'Настройки', exact: true }).click();
|
|
await page.getByRole('button', { name: 'Остров', exact: true }).click();
|
|
const nav = page.getByRole('navigation').filter({ has: page.getByRole('button', { name: 'Ещё', exact: true }) });
|
|
await expect.poll(async () => {
|
|
const p = await player.boundingBox();
|
|
const n = await nav.boundingBox();
|
|
return p!.y + p!.height <= n!.y + 1;
|
|
}).toBe(true);
|
|
await player.getByRole('button', { name: 'Очередь', exact: true }).click();
|
|
await expect(page.getByRole('complementary', { name: 'Очередь', exact: true })).toBeVisible();
|
|
await page.screenshot({ path: info.outputPath('player-queue.png') });
|
|
});
|