fix(review): #90 clean cal + dimension-overlay are mandatory (checked + disabled)
REVIEW-5 requires both the clean calibration photo and its dimension-overlay copy to ship. Their keep checkbox is now checked AND disabled (aria-disabled, a lock glyph, cursor:default, tap is a no-op) so the owner can't remove them. Only batch photos are removable. The submission minimum can no longer be broken by the owner, so publish is never lineup-blocked by a missing required photo.
This commit is contained in:
@@ -212,18 +212,30 @@ test.describe('M3 Review photo strip (#90)', () => {
|
||||
const bgImage = await cards.nth(0).evaluate((el) => getComputedStyle(el).backgroundImage);
|
||||
expect(bgImage).toContain('45deg');
|
||||
|
||||
// Remove the primary (cal) → primary auto-promotes to the next leftmost (ov).
|
||||
await cards.nth(0).click();
|
||||
await expect(cards.nth(0)).toHaveAttribute('aria-pressed', 'false');
|
||||
await expect(cards.nth(1)).toHaveAttribute('data-primary', 'true');
|
||||
// Minimum nudge: cal + batch kept, but overlay still present → only cal missing.
|
||||
await expect(page.getByTestId('lineup-nudge')).toBeVisible();
|
||||
await expect(page.getByTestId('lineup-nudge')).toContainText('clean photo');
|
||||
// Mandatory photos: the clean calibration (seq 1) and the dimension-overlay
|
||||
// copy (seq 2) are required — their keep checkbox is checked AND disabled.
|
||||
await expect(cards.nth(0)).toHaveAttribute('data-required', 'true');
|
||||
await expect(cards.nth(1)).toHaveAttribute('data-required', 'true');
|
||||
await expect(cards.nth(2)).toHaveAttribute('data-required', '');
|
||||
await expect(cards.nth(0)).toHaveAttribute('aria-pressed', 'true');
|
||||
await expect(cards.nth(1)).toHaveAttribute('aria-pressed', 'true');
|
||||
|
||||
// Re-add the cal (the original re-check bug) → it's back to the left = primary.
|
||||
await cards.nth(0).click();
|
||||
// Tapping a mandatory photo is a no-op: it stays checked + primary (can't remove).
|
||||
// The card is aria-disabled, so force the click to exercise the handler directly.
|
||||
await cards.nth(0).click({ force: true });
|
||||
await expect(cards.nth(0)).toHaveAttribute('aria-pressed', 'true');
|
||||
await expect(cards.nth(0)).toHaveAttribute('data-primary', 'true');
|
||||
// No minimum nudge — both required photos are kept by construction.
|
||||
await expect(page.getByTestId('lineup-nudge')).toHaveCount(0);
|
||||
|
||||
// Remove the OPTIONAL batch photo (index 2) → it un-keeps; required stay kept.
|
||||
await cards.nth(2).click();
|
||||
await expect(cards.nth(2)).toHaveAttribute('aria-pressed', 'false');
|
||||
// Primary is still the leftmost required (cal, index 0).
|
||||
await expect(cards.nth(0)).toHaveAttribute('data-primary', 'true');
|
||||
// Re-add the batch photo.
|
||||
await cards.nth(2).click();
|
||||
await expect(cards.nth(2)).toHaveAttribute('aria-pressed', 'true');
|
||||
await expect(page.getByTestId('lineup-nudge')).toHaveCount(0);
|
||||
|
||||
// Drag the batch photo (index 2) to the front → it becomes the primary.
|
||||
@@ -259,20 +271,29 @@ test.describe('M3 Review photo strip (#90)', () => {
|
||||
expect(seqs).toEqual([1, 2, 3]);
|
||||
});
|
||||
|
||||
test('removing a photo persists a DELETE and blocks publish when the minimum is broken', async ({ page }) => {
|
||||
test('required photos guarantee the minimum; removing an OPTIONAL batch persists a DELETE', async ({ page }) => {
|
||||
const mock = await mockApi(page);
|
||||
await reachReview(page);
|
||||
const cards = page.getByTestId('photo-card');
|
||||
|
||||
// Remove the overlay (seq 2) → minimum broken (no overlay).
|
||||
await cards.nth(1).click();
|
||||
await expect(cards.nth(1)).toHaveAttribute('aria-pressed', 'false');
|
||||
await expect(page.getByTestId('lineup-nudge')).toContainText('overlay');
|
||||
// The clean calibration + dimension-overlay are mandatory and always kept,
|
||||
// so the submission minimum can never be broken — publish is never lineup-blocked.
|
||||
await expect(page.getByTestId('lineup-nudge')).toHaveCount(0);
|
||||
|
||||
// Complete the rest of the form; the slab fields are ready but the lineup is not.
|
||||
// Removing an OPTIONAL batch photo is allowed and persists a DELETE.
|
||||
await cards.nth(2).click();
|
||||
await expect(cards.nth(2)).toHaveAttribute('aria-pressed', 'false');
|
||||
// Still no nudge: both required photos remain kept.
|
||||
await expect(page.getByTestId('lineup-nudge')).toHaveCount(0);
|
||||
|
||||
// Complete the rest of the form; the lineup is valid (required photos kept).
|
||||
await completeForReady(page);
|
||||
await expect(page.getByTestId('ready-status')).toContainText(/Not ready|remaining/);
|
||||
// Continue is blocked by the lineup minimum even though the fields are set.
|
||||
await expect(page.getByTestId('continue-publish')).toBeDisabled();
|
||||
await expect(page.getByTestId('ready-status')).toContainText('Ready to publish', { timeout: 15000 });
|
||||
await expect(page.getByTestId('continue-publish')).toBeEnabled();
|
||||
await page.getByTestId('continue-publish').click();
|
||||
await expect(page.getByTestId('publish-screen')).toBeVisible();
|
||||
|
||||
// The removed batch photo persisted as a DELETE; the required photos re-uploaded.
|
||||
expect(mock.deletes).toEqual(['ph-b1']);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user