ci / module boundaries / boundaries (push) Successful in 6s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 2m1s
ci / ts / ts (packages + web) (push) Failing after 5m13s
ci / api / api (push) Successful in 41s
ci / db / db (push) Failing after 1m33s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 2m25s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 2m19s
63 lines
3.8 KiB
TypeScript
63 lines
3.8 KiB
TypeScript
import { mkdir, writeFile } from 'node:fs/promises';
|
|
import { join } from 'node:path';
|
|
import { expect, test } from '@playwright/test';
|
|
|
|
test('an artist directory uploads each album as a separate batch with a shared portrait', async ({ page }, info) => {
|
|
const root = info.outputPath('творожный бизнес');
|
|
const albums = ['(2026) творог грехов - творожный бизнес', '(2025) молчанка - творожный бизнес'];
|
|
for (const album of albums) {
|
|
await mkdir(join(root, album), { recursive: true });
|
|
await writeFile(join(root, album, 'song.flac'), Buffer.alloc(128));
|
|
}
|
|
const portrait = Buffer.from('portrait');
|
|
await writeFile(join(root, 'artist.jpg'), portrait);
|
|
await writeFile(join(root, albums[0]!, 'cover.jpg'), Buffer.from('album cover'));
|
|
type Batch = { artist_image_base64?: string; cover_base64?: string; files: { client_id: string; rel_path: string }[] };
|
|
const batches: Batch[] = [];
|
|
await page.exposeFunction('recordArtistBatch', (batch: Batch) => { batches.push(batch); });
|
|
await page.addInitScript(() => localStorage.setItem('pipu.locale', 'ru'));
|
|
await page.goto('/login');
|
|
await page.getByLabel('Логин', { exact: true }).fill('mobile-admin');
|
|
await page.getByRole('textbox', { name: 'Пароль', exact: true }).fill('mobile-admin-password');
|
|
await page.getByRole('button', { name: 'Войти', exact: true }).click();
|
|
await expect(page.getByRole('button', { name: 'Меню профиля' })).toBeVisible();
|
|
await page.evaluate(() => {
|
|
const original = window.fetch;
|
|
window.fetch = async (input, init) => {
|
|
const req = new Request(input, init);
|
|
const path = new URL(req.url).pathname;
|
|
const json = (data: unknown) => new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json' } });
|
|
if (path === '/api/v1/uploads/precheck') {
|
|
const body = await req.json();
|
|
return json({ files: body.files.map((f: { client_id: string }) => ({ client_id: f.client_id, result: 'accepted' })) });
|
|
}
|
|
if (path === '/api/v1/uploads' && req.method === 'POST') {
|
|
const body = await req.json();
|
|
await (window as unknown as { recordArtistBatch: (body: unknown) => Promise<void> }).recordArtistBatch(body);
|
|
return json({ batch_id: crypto.randomUUID(), files: body.files.map((f: { client_id: string }) => ({ client_id: f.client_id, upload_file_id: f.client_id, tus_url: `/api/v1/uploads/files/${f.client_id}` })) });
|
|
}
|
|
return original(input, init);
|
|
};
|
|
history.pushState({}, '', '/uploads/new');
|
|
window.dispatchEvent(new PopStateEvent('popstate'));
|
|
});
|
|
await page.route('**/api/v1/uploads/files/*', async (route) => {
|
|
await route.fulfill({ status: route.request().method() === 'HEAD' ? 200 : 204,
|
|
headers: { 'Upload-Length': '128', 'Upload-Offset': route.request().method() === 'HEAD' ? '0' : '128', 'Tus-Resumable': '1.0.0' } });
|
|
});
|
|
await page.locator('input[webkitdirectory]').setInputFiles(root);
|
|
const send = page.getByRole('button', { name: /^Отправить/ });
|
|
await expect(send).toBeEnabled();
|
|
await expect(page.getByText(/Пропущен/)).toHaveCount(0);
|
|
await send.click();
|
|
await expect(page.getByText(/Готово: 2 файла/)).toBeVisible();
|
|
expect(batches).toHaveLength(2);
|
|
expect(batches.map((batch) => batch.files[0]!.rel_path).sort()).toEqual(albums.map((album) => `творожный бизнес/${album}/song.flac`).sort());
|
|
for (const batch of batches) {
|
|
expect(batch.files).toHaveLength(1);
|
|
expect(batch.artist_image_base64).toBe(portrait.toString('base64'));
|
|
}
|
|
expect(batches.find((batch) => batch.files[0]!.rel_path.includes(albums[0]!))!.cover_base64).toBe(Buffer.from('album cover').toString('base64'));
|
|
expect(batches.find((batch) => batch.files[0]!.rel_path.includes(albums[1]!))!.cover_base64).toBeUndefined();
|
|
});
|