diff --git a/tests/ui/post/post-form-ux.spec.js b/tests/ui/post/post-form-ux.spec.js index f1768b0..2d3688a 100644 --- a/tests/ui/post/post-form-ux.spec.js +++ b/tests/ui/post/post-form-ux.spec.js @@ -49,11 +49,10 @@ test('AE1: a HEIC photo is converted to JPEG client-side and posted', async ({ p expect(files.some(f => /\.heic$/i.test(f)), 'the original HEIC must NOT be posted').toBe(false); }); -// ── AE4: corrupt HEIC fails closed; Submit + other photos stay usable ───────── -test('AE4: a corrupt HEIC is blocked (fail-closed) and never posted', async ({ page }) => { - const tag = `heicfail-${Date.now()}`; +// ── AE4: corrupt HEIC fails closed — it is the only "photo", so submit blocks ── +test('AE4: a corrupt HEIC is blocked (fail-closed) and cannot be posted alone', async ({ page }) => { await page.goto('/post'); - await page.fill('input[name="data[title]"]', `UI Test ${tag}`); + await page.fill('input[name="data[title]"]', `UI Test heicfail-${Date.now()}`); await fillEditor(page, 'HEIC failure test. Safe to delete.'); await page.locator('input.filepond--browser').setInputFiles(TEST_CORRUPT_HEIC); @@ -61,14 +60,31 @@ test('AE4: a corrupt HEIC is blocked (fail-closed) and never posted', async ({ p await expect(page.locator('.photo-convert-status.form-status--err')).toBeVisible({ timeout: 15_000 }); await expect(page.locator('.btn-post')).toBeEnabled(); // Submit still usable + // The corrupt file was never added, so there are zero photos — the ≥1-photo + // requirement blocks submit, which is exactly what keeps the corrupt HEIC + // (fail-closed) from ever being posted. No entry is created. await page.locator('.btn-post').evaluate(el => el.click()); - await expect(page.locator('.notices')).toContainText('Entry posted successfully!', { timeout: 15_000 }); - created.push(tag); + await expect(page.locator('.photos-collapse .field-error')).toBeVisible(); + await expect(page.locator('.notices.success, .notices.green')).toHaveCount(0); +}); - const dir = findEntry(tag); - expect(dir).toBeTruthy(); - const files = fs.readdirSync(dir); - expect(files.some(f => /\.heic$/i.test(f)), 'the corrupt HEIC must never be posted').toBe(false); +// ── Photo count: at least one is required; the picker caps at 6 ──────────────── +test('a post requires at least one photo and the picker allows at most 6', async ({ page }) => { + await page.goto('/post'); + + // FilePond is configured from the blueprint limit (6). + await page.waitForFunction( + () => window.GravFilePond && window.GravFilePond.getInstances().length > 0, + { timeout: 10_000 }); + expect(await page.evaluate(() => window.GravFilePond.getInstances()[0].maxFiles)).toBe(6); + + // Title + content filled, date prefilled, but no photo → submit is blocked + // with an error on the photo section and no success notice. + await page.fill('input[name="data[title]"]', `UI photoreq-${Date.now()}`); + await fillEditor(page, 'photo-required test'); + await page.locator('.btn-post').evaluate(el => el.click()); + await expect(page.locator('.photos-collapse .field-error')).toContainText('at least one photo'); + await expect(page.locator('.notices.success, .notices.green')).toHaveCount(0); }); // ── Photo section collapses to a summary after upload, re-expands on tap ────── @@ -179,6 +195,9 @@ test('post success shows a confirmation with a working "View your journal" link' await page.goto('/post'); await page.fill('input[name="data[title]"]', `UI Test ${tag}`); await fillEditor(page, `success cta test ${tag}`); + // A photo is required to post. + await page.locator('input.filepond--browser').setInputFiles(TEST_JPG); + await waitForPhotoUpload(page, 1); await page.locator('.btn-post').evaluate(el => el.click()); await expect(page.locator('.notices')).toContainText('Entry posted successfully!', { timeout: 15_000 }); created.push(tag);