// @ts-check // Tests: V1–V4 — form validation and input constraints const { test, expect } = require('@playwright/test'); const path = require('path'); 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 page.fill('textarea[name="data[content]"]', '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 (textarea) 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 4) ─────────────────────────────────────────────────── test('V3: filepond rejects a 5th photo when limit is 4', async ({ page }) => { await page.goto('/post'); // Upload 4 photos (all the same fixture — we just need 4 items) const fourPhotos = [TEST_PHOTO, TEST_PHOTO, TEST_PHOTO, TEST_PHOTO]; await page.locator('input.filepond--browser').setInputFiles(fourPhotos); // Wait for all 4 items to appear await page.waitForFunction(() => document.querySelectorAll('.filepond--item').length === 4, { timeout: 10_000 } ); // Attempt a 5th — filepond should ignore it once the limit is reached await page.locator('input.filepond--browser').setInputFiles([TEST_PHOTO]); await page.waitForTimeout(500); const itemCount = await page.locator('.filepond--item').count(); expect(itemCount).toBe(4); }); // ── V4: Non-image file rejected ─────────────────────────────────────────────── test('V4: filepond rejects non-image files', 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 filepond added it, it must show an error state — not 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); } });