Files
m038andClaude Opus 4.8 d3c17791b7 test(post-form): add edit/delete/anon coverage and fix stale photo-gate assumptions
New specs: edit-mode (ES1 save round-trip + ES2/ES3 prefill 404/500 states),
delete-flow (DEL1-3 happy/cancel/failed), anon-view (AN1 no owner controls,
AN2 draft hidden from anon), photo-editor (live add/delete/reorder). Existing:
P3-P8 now attach a photo to satisfy the create photo-gate; V3 picker cap 4->6.
Full post suite 38/38, stable across parallel (3-worker) runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-05 23:42:45 +02:00

73 lines
3.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// @ts-check
// Tests: V1V4 — form validation and input constraints
const { test, expect } = require('@playwright/test');
const path = require('path');
const { fillEditor } = require('../helpers');
const TEST_PHOTO = path.join(__dirname, '../../fixtures/test-photo.jpg');
const TEST_NONIMAGE = path.join(__dirname, '../../fixtures/test-nonimage.txt');
// ── V1: Missing title ─────────────────────────────────────────────────────────
test('V1: submit without title shows a validation error or stays on /post', async ({ page }) => {
await page.goto('/post');
// Leave title empty, fill only content
await fillEditor(page, 'Content without a title.');
await page.locator('.btn-post').evaluate(el => el.click());
// Grav either shows an error message OR re-renders the form (stays on /post).
// Either outcome is acceptable — what should NOT happen is a success message.
await page.waitForTimeout(2_000);
const bodyText = await page.locator('body').textContent();
expect(bodyText).not.toContain('Entry posted successfully');
});
// ── V2: Missing content ───────────────────────────────────────────────────────
test('V2: submit without content shows a validation error or stays on /post', async ({ page }) => {
await page.goto('/post');
await page.fill('input[name="data[title]"]', 'V2 title no content');
// Leave content (editor) empty
await page.locator('.btn-post').evaluate(el => el.click());
await page.waitForTimeout(2_000);
const bodyText = await page.locator('body').textContent();
expect(bodyText).not.toContain('Entry posted successfully');
});
// ── V3: Photo limit (max 6) ───────────────────────────────────────────────────
// The blueprint limit is 6 (asserted directly as maxFiles===6 in the UX suite);
// this is the behavioral counterpart — the picker must refuse a 7th attachment.
test('V3: FilePond caps attachments at the limit (6)', async ({ page }) => {
await page.goto('/post');
const browser = page.locator('input.filepond--browser');
// Attach 6 photos (same fixture — we only need six items).
await browser.setInputFiles([TEST_PHOTO, TEST_PHOTO, TEST_PHOTO, TEST_PHOTO, TEST_PHOTO, TEST_PHOTO]);
await page.waitForFunction(() =>
document.querySelectorAll('.filepond--item').length === 6, { timeout: 10_000 });
// A 7th is ignored once the limit is reached.
await browser.setInputFiles([TEST_PHOTO]);
await page.waitForTimeout(500);
expect(await page.locator('.filepond--item').count()).toBe(6);
});
// ── V4: Non-image file rejected ───────────────────────────────────────────────
test('V4: FilePond rejects a non-image file', async ({ page }) => {
await page.goto('/post');
await page.locator('input.filepond--browser').setInputFiles(TEST_NONIMAGE);
await page.waitForTimeout(1_000);
const items = page.locator('.filepond--item');
const count = await items.count();
if (count > 0) {
// If added, it must not reach processing-complete.
const state = await items.first().getAttribute('data-filepond-item-state');
expect(state).not.toBe('processing-complete');
} else {
// Silently rejected before adding — also a pass.
expect(count).toBe(0);
}
});