// @ts-check // Tests: V1–V4 — 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 4) ─────────────────────────────────────────────────── test('V3: FilePond caps attachments at the limit (4)', async ({ page }) => { await page.goto('/post'); const browser = page.locator('input.filepond--browser'); // Attach 4 photos (same fixture — we only need four items). await browser.setInputFiles([TEST_PHOTO, TEST_PHOTO, TEST_PHOTO, TEST_PHOTO]); await page.waitForFunction(() => document.querySelectorAll('.filepond--item').length === 4, { timeout: 10_000 }); // A 5th is ignored once the limit is reached. await browser.setInputFiles([TEST_PHOTO]); await page.waitForTimeout(500); expect(await page.locator('.filepond--item').count()).toBe(4); }); // ── 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); } });