Release 0.3.0
This commit is contained in:
1 parent
08e8875cb5
commit
7590be66a5
31 files changed
+3270
-151
No files matched your search
+125
-23
@@ -178,23 +178,16 @@ test('desktop fundus is a compact, filterable list with persistent themes', asyn
|
||||
expect(firstRow?.y).toBeLessThan(secondRow?.y ?? 0);
|
||||
expect(firstRow?.height ?? 999).toBeLessThan(130);
|
||||
const searchBox = await page.locator('.search-field').boundingBox();
|
||||
const filtersBox = await page.locator('.filter-tabs').boundingBox();
|
||||
expect(searchBox?.height).toBe(filtersBox?.height);
|
||||
await expect(page.getByRole('button', { name: 'In Arbeit' })).toHaveCSS('white-space', 'nowrap');
|
||||
|
||||
const notice = page.locator('.preview-notice');
|
||||
await expect(page.getByText('Vorschau · Fundus', { exact: true })).toBeVisible();
|
||||
await expect(notice.getByText('Diese Ansicht ist schreibgeschützt.')).toBeHidden();
|
||||
await notice.locator('summary').focus();
|
||||
await expect(notice.locator('summary')).toBeFocused();
|
||||
await page.keyboard.press('Enter');
|
||||
await expect(notice.getByText('Diese Ansicht ist schreibgeschützt.')).toBeVisible();
|
||||
const statusBox = await page.getByLabel('Status').boundingBox();
|
||||
expect(searchBox?.height).toBe(statusBox?.height);
|
||||
|
||||
await page.getByRole('searchbox', { name: 'Fundus durchsuchen' }).fill('Pixelart');
|
||||
await page.getByRole('button', { name: 'Anwenden' }).click();
|
||||
await expect(page.locator('.piece-card')).toHaveCount(1);
|
||||
await page.getByRole('button', { name: 'In Arbeit' }).click();
|
||||
await expect(page.getByRole('heading', { name: 'Kein passendes Stück' })).toBeVisible();
|
||||
await page.getByRole('button', { name: 'Filter zurücksetzen' }).click();
|
||||
await page.getByLabel('Status').selectOption('preparing');
|
||||
await page.getByRole('button', { name: 'Anwenden' }).click();
|
||||
await expect(page.getByRole('heading', { name: 'Kein passendes Piece' })).toBeVisible();
|
||||
await page.getByRole('link', { name: 'Filter zurücksetzen' }).click();
|
||||
await expect(page.locator('.piece-card')).toHaveCount(4);
|
||||
|
||||
await page.getByRole('button', { name: 'Darstellung: System' }).click();
|
||||
@@ -334,17 +327,16 @@ test('long titles and longer fundus lists reflow without overflow', async ({ pag
|
||||
});
|
||||
});
|
||||
|
||||
test('empty states and administration stay concise', async ({ page }) => {
|
||||
test('inbox, archive and administration stay concise', async ({ page }) => {
|
||||
for (const width of [390, 1280]) {
|
||||
await page.setViewportSize({ width, height: 900 });
|
||||
for (const route of ['/eingang', '/archiv']) {
|
||||
await page.goto(route);
|
||||
const emptyState = page.locator('.planned-panel');
|
||||
await expect(emptyState).toBeVisible();
|
||||
const box = await emptyState.boundingBox();
|
||||
expect(box?.height ?? 999).toBeLessThan(150);
|
||||
await expectNoHorizontalOverflow(page);
|
||||
}
|
||||
await page.goto('/eingang');
|
||||
await expect(page.locator('.capture-panel')).toBeVisible();
|
||||
await expect(page.locator('.inbox-item')).toHaveCount(1);
|
||||
await expectNoHorizontalOverflow(page);
|
||||
await page.goto('/archiv');
|
||||
await expect(page.locator('.archive-list article')).toHaveCount(1);
|
||||
await expectNoHorizontalOverflow(page);
|
||||
}
|
||||
|
||||
await page.setViewportSize({ width: 1280, height: 900 });
|
||||
@@ -378,3 +370,113 @@ test('live preview retains its existing readable controls', async ({ page }) =>
|
||||
await expect(page.locator('.research-details')).toHaveAttribute('open', '');
|
||||
await expectNoHorizontalOverflow(page);
|
||||
});
|
||||
|
||||
test('pieces autosave safely, detect conflicts and protect uploaded images', async ({
|
||||
page,
|
||||
browser
|
||||
}, testInfo) => {
|
||||
await page.setViewportSize({ width: 1280, height: 1000 });
|
||||
await page.goto('/fundus');
|
||||
await page.getByText('Neues Piece anlegen').click();
|
||||
await page.getByRole('button', { name: /Reaction \/ Fundstück/ }).click();
|
||||
await expect(page).toHaveURL(/\/fundus\/[a-f0-9-]+$/);
|
||||
const pieceUrl = page.url();
|
||||
|
||||
await page.getByLabel('Titel').fill('E2E Fundstück mit Markdown');
|
||||
await page.getByRole('link', { name: '← Fundus', exact: true }).click();
|
||||
await expect(page).toHaveURL(/\/fundus$/);
|
||||
await page.getByRole('heading', { name: 'E2E Fundstück mit Markdown' }).click();
|
||||
await expect(page).toHaveURL(pieceUrl);
|
||||
await page
|
||||
.getByLabel('Kurzbeschreibung')
|
||||
.fill('Persistiert nach Neuladen und ist gezielt suchbar.');
|
||||
await page.getByLabel('Status').selectOption('ready');
|
||||
await page.getByLabel('Dauer in Sekunden').fill('615');
|
||||
await page.getByLabel('Gaming').check();
|
||||
await page.getByLabel('Private Recherche').fill('Nur intern: **Hintergrund prüfen**.');
|
||||
await page
|
||||
.getByLabel('Präsentationstext')
|
||||
.fill('## Sichere Vorschau\n\n<script>globalThis.e2eXss = true</script> **sichtbar**');
|
||||
await page.getByRole('button', { name: 'Quelle hinzufügen' }).click();
|
||||
const source = page.locator('.source-row').last();
|
||||
await source.getByLabel('Name').fill('Originalbeitrag');
|
||||
await source.getByLabel('URL').fill('https://example.com/e2e-fundstueck');
|
||||
await source.getByLabel('Zeitmarke in Sekunden').fill('42');
|
||||
await expect(page.locator('.save-indicator')).toContainText('Gespeichert', { timeout: 10_000 });
|
||||
await page.waitForTimeout(1_200);
|
||||
await expect(page.locator('.save-indicator')).toContainText('Gespeichert');
|
||||
await expect(page.locator('.markdown-preview script')).toHaveCount(0);
|
||||
await expect(page.locator('.markdown-preview').last()).toContainText('Sichere Vorschau');
|
||||
await page.reload();
|
||||
await expect(page.getByLabel('Titel')).toHaveValue('E2E Fundstück mit Markdown');
|
||||
await expect(page.getByLabel('Private Recherche')).toHaveValue(
|
||||
'Nur intern: **Hintergrund prüfen**.'
|
||||
);
|
||||
|
||||
const png = Buffer.from(
|
||||
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=',
|
||||
'base64'
|
||||
);
|
||||
await page.getByLabel('Bild', { exact: true }).setInputFiles({
|
||||
name: 'redaktionsbild.png',
|
||||
mimeType: 'image/png',
|
||||
buffer: png
|
||||
});
|
||||
await page.getByLabel('Alternativtext').fill('Ein Testpixel');
|
||||
await page.getByRole('button', { name: 'Bild hochladen' }).click();
|
||||
const image = page.locator('.media-grid img');
|
||||
await expect(image).toHaveCount(1);
|
||||
await expect(image).toHaveAttribute('alt', 'Ein Testpixel');
|
||||
const mediaUrl = await image.getAttribute('src');
|
||||
const anonymous = await browser.newContext();
|
||||
const anonymousResponse = await anonymous.request.get(new URL(mediaUrl!, page.url()).toString(), {
|
||||
maxRedirects: 0
|
||||
});
|
||||
expect(anonymousResponse.status()).toBe(303);
|
||||
await anonymous.close();
|
||||
|
||||
const concurrent = await page.context().newPage();
|
||||
await concurrent.goto(pieceUrl);
|
||||
await page.getByLabel('Titel').fill('E2E Fundstück, extern aktualisiert');
|
||||
await expect(page.locator('.save-indicator')).toContainText('Gespeichert', { timeout: 10_000 });
|
||||
await concurrent
|
||||
.getByLabel('Kurzbeschreibung')
|
||||
.fill('Diese veraltete Änderung darf nicht gewinnen.');
|
||||
await expect(concurrent.locator('.save-indicator')).toContainText('neuere Änderung', {
|
||||
timeout: 10_000
|
||||
});
|
||||
await concurrent.reload();
|
||||
await expect(concurrent.getByLabel('Titel')).toHaveValue('E2E Fundstück, extern aktualisiert');
|
||||
await expect(concurrent.getByLabel('Kurzbeschreibung')).not.toHaveValue(
|
||||
'Diese veraltete Änderung darf nicht gewinnen.'
|
||||
);
|
||||
await concurrent.close();
|
||||
|
||||
await page.goto('/fundus?q=extern+aktualisiert');
|
||||
await expect(page.locator('.piece-card')).toHaveCount(1);
|
||||
await expect(
|
||||
page.getByRole('heading', { name: 'E2E Fundstück, extern aktualisiert' })
|
||||
).toBeVisible();
|
||||
await page.getByRole('link', { name: 'Bearbeiten' }).click();
|
||||
await page.getByRole('button', { name: 'Piece archivieren' }).click();
|
||||
await expect(page).toHaveURL(/\/archiv$/);
|
||||
const archived = page.locator('.archive-list article').filter({ hasText: 'extern aktualisiert' });
|
||||
await expect(archived).toBeVisible();
|
||||
await archived.getByRole('button', { name: 'Wiederherstellen' }).click();
|
||||
await expect(archived).toHaveCount(0);
|
||||
await page.goto('/fundus?q=extern+aktualisiert');
|
||||
await expect(page.locator('.piece-card')).toHaveCount(1);
|
||||
await page.locator('.piece-card').getByRole('button', { name: 'Duplizieren' }).click();
|
||||
await expect(page.getByLabel('Titel')).toHaveValue(
|
||||
'Kopie von E2E Fundstück, extern aktualisiert'
|
||||
);
|
||||
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await setTheme(page, 'dark');
|
||||
await page.reload();
|
||||
await expectNoHorizontalOverflow(page);
|
||||
await page.screenshot({
|
||||
path: testInfo.outputPath('piece-editor-mobile-dark.png'),
|
||||
fullPage: true
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user