fix: repair Android startup and improve mobile web layouts
This commit is contained in:
1 parent
4c2286e70d
commit
b0cbd0f149
30 files changed
+609
-140
No files matched your search
@@ -0,0 +1,119 @@
|
||||
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')).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') });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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(40);
|
||||
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') });
|
||||
});
|
||||
Reference in new issue
Block a user