veza/tests/e2e/27-upload.spec.ts

234 lines
10 KiB
TypeScript
Raw Normal View History

import { test, expect } from '@chromatic-com/playwright';
import { loginViaAPI, CONFIG, navigateTo } from './helpers';
/**
* UPLOAD - Track upload flow tests
* STRICT: every step must succeed or the test fails.
* No silent skips, no console.log fallbacks.
*/
function createTestMP3Buffer(): Buffer {
return Buffer.from(
'4944330300000000000a544954320000000500000054657374fffb90440000000000000000000000000000000000000000',
'hex',
);
}
test.describe('UPLOAD - Track upload flow @critical', () => {
test.beforeEach(async ({ page }) => {
await loginViaAPI(page, CONFIG.users.creator.email, CONFIG.users.creator.password);
});
test('should show upload button on library page', async ({ page }) => {
await navigateTo(page, '/library');
fix(e2e): stable upload-trigger testid, unskip v107-e2e-04 — rc1-day2 root cause #2 12 @critical failures on 27-upload + 43-upload-deep + the skipped 04-tracks:207 shared one root cause: the LibraryPageToolbar "New" button (renders t('library.new'), localized to "New"/"Nouveau") was targeted by regex `/upload|uploader/i` or `/upload|importer| ajouter/i` — none matched the actual label. The 2026-04-08 console.log → expect conversion pinned assertions against a label the UI never produced. Fix: `data-testid="library-upload-cta"` on the toolbar CTA + aria-label fallback ("Upload track"). Tests target by testid, immune to future i18n/copy changes. Results after fix: * 27-upload.spec.ts — 6/7 now pass. The remaining failure (test 54 "full upload flow") is a DIFFERENT root cause: dialog doesn't close after upload submit (60s timeout). Not a locator issue — tracked separately as #55 (upload backend hangs on submit, suspected ClamAV or validation silently failing in test env). * 04-tracks.spec.ts:207 — unskipped, passes (was #50, now closed; SKIPPED_TESTS.md updated with resolution note). * 43-upload-deep.spec.ts helper — migrated to the same testid so the "button not found" class of failure is gone. Remaining 43-upload-deep failures are same upload-flow class as 27-upload:54 (tracked in #55). Gain: 8/12 upload-family tests recovered. Remaining 4 are a separate investigation. Post-fix validation: ran `27-upload + 04-tracks` under Playwright — 7 passed, 2 failed, 1 skipped (skip unrelated). The 2 failures are both the #55 submit-hang root cause, not the locator one. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:38:28 +00:00
// v1.0.7-rc1 pre-fix: the library "Upload" trigger is a Plus-icon
// button labelled t('library.new') (= "New" / "Nouveau"), not
// "Upload". Historical regex /upload|uploader/i never matched,
// producing 12 @critical failures. Now targeted via testid for
// stability against future i18n / label changes.
const uploadBtn = page.getByTestId('library-upload-cta');
await expect(uploadBtn, 'Upload button must be visible on /library').toBeVisible({ timeout: 10_000 });
});
test('should open upload modal when clicking upload button', async ({ page }) => {
await navigateTo(page, '/library');
fix(e2e): stable upload-trigger testid, unskip v107-e2e-04 — rc1-day2 root cause #2 12 @critical failures on 27-upload + 43-upload-deep + the skipped 04-tracks:207 shared one root cause: the LibraryPageToolbar "New" button (renders t('library.new'), localized to "New"/"Nouveau") was targeted by regex `/upload|uploader/i` or `/upload|importer| ajouter/i` — none matched the actual label. The 2026-04-08 console.log → expect conversion pinned assertions against a label the UI never produced. Fix: `data-testid="library-upload-cta"` on the toolbar CTA + aria-label fallback ("Upload track"). Tests target by testid, immune to future i18n/copy changes. Results after fix: * 27-upload.spec.ts — 6/7 now pass. The remaining failure (test 54 "full upload flow") is a DIFFERENT root cause: dialog doesn't close after upload submit (60s timeout). Not a locator issue — tracked separately as #55 (upload backend hangs on submit, suspected ClamAV or validation silently failing in test env). * 04-tracks.spec.ts:207 — unskipped, passes (was #50, now closed; SKIPPED_TESTS.md updated with resolution note). * 43-upload-deep.spec.ts helper — migrated to the same testid so the "button not found" class of failure is gone. Remaining 43-upload-deep failures are same upload-flow class as 27-upload:54 (tracked in #55). Gain: 8/12 upload-family tests recovered. Remaining 4 are a separate investigation. Post-fix validation: ran `27-upload + 04-tracks` under Playwright — 7 passed, 2 failed, 1 skipped (skip unrelated). The 2 failures are both the #55 submit-hang root cause, not the locator one. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:38:28 +00:00
// v1.0.7-rc1 pre-fix: the library "Upload" trigger is a Plus-icon
// button labelled t('library.new') (= "New" / "Nouveau"), not
// "Upload". Historical regex /upload|uploader/i never matched,
// producing 12 @critical failures. Now targeted via testid for
// stability against future i18n / label changes.
const uploadBtn = page.getByTestId('library-upload-cta');
await expect(uploadBtn).toBeVisible({ timeout: 10_000 });
await uploadBtn.click();
const dialog = page.locator('[role="dialog"]').first();
await expect(dialog, 'Upload dialog must appear after clicking upload').toBeVisible({ timeout: 5_000 });
// Dialog must contain a file input
const fileInput = dialog.locator('input[type="file"]');
expect(await fileInput.count(), 'File input must exist in upload dialog').toBeGreaterThan(0);
});
test(e2e): skip 14 remaining @critical baseline failures, document per root-cause — rc1-day2 finish After two rounds of root-cause fixes (40 → 14 failures), the residual 14 tests all fall into seven classes that are orthogonal to v1.0.7 money-movement surface AND require investigations that exceed the rc1 scope: #57/v107-e2e-05 (5 tests) — upload backend submit hangs 27-upload:54, 43-upload-deep:663/713/747/781 #58/v107-e2e-06 (2 tests) — chat backend echo missing 29-chat-functional:70, :142 #59/v107-e2e-07 (2 tests) — workflow cascade under parallel load 13-workflows:17, :148 #60/v107-e2e-08 (1 test) — /feed page crash (browser-level) 11-accessibility-ethics:342 #61/v107-e2e-09 (2 tests) — chat DOM-detach race conditions 41-chat-deep:266, :604 #62/v107-e2e-10 (1 test) — playlist edit redirect playlists-edit-audit:14 #63/v107-e2e-11 (1 test) — Playwright 50MB buffer limit (test bug) 43-upload-deep:364 Each test skipped with a test.skip + inline comment pointing at its ticket, and SKIPPED_TESTS.md updated with the classification table + unskip procedure. Baseline trajectory over the rc1 sprint: Pre-fixes: 122 pass / 40 fail / 9 skip Round 1 (6 RC): 144 pass / 17 fail / 10 skip (-23 fail) Round 2 (wide): 146 pass / 14 fail / 11 skip (-3 fail) Post-skip: expected 146 pass / 0 fail / ~25 skip Rationale vs "fix now": * Each of the seven classes requires a backend-infra dive (ClamAV, WebSocket, chat worker config) or test-infra refactor (per-worker DB isolation, animation waits). Each 2-4h minimum, with non-trivial regression risk on adjacent tests. * 146/171 passing, 0 failing is a strictly more auditable release state than SKIP_E2E=1 masking. The skips are explicit per-test with documented root cause, not a blanket gate bypass. * Satisfies the three conditions the user set yesterday for formalising a scope reduction: each skip is documented, each has an owner ticket, unskip procedure is traceable. No v1.0.7 surface code touched. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 18:05:31 +00:00
// v1.0.7-rc1-day2 (task #57 / v107-e2e-05): upload dialog doesn't
// close after submit (60s timeout). The locator fix (previous
// commit) brought this test out of the locator-class failures,
// revealing the backend submit-hang root cause. Suspected ClamAV
// missing in test env OR endpoint silently stalling. Not v1.0.7
// surface.
// eslint-disable-next-line playwright/no-skipped-test
test.skip('should complete full upload flow: file, metadata, publish @critical', async ({ page }) => {
test.setTimeout(120_000);
await navigateTo(page, '/library');
// Step 1: Open upload modal
fix(e2e): stable upload-trigger testid, unskip v107-e2e-04 — rc1-day2 root cause #2 12 @critical failures on 27-upload + 43-upload-deep + the skipped 04-tracks:207 shared one root cause: the LibraryPageToolbar "New" button (renders t('library.new'), localized to "New"/"Nouveau") was targeted by regex `/upload|uploader/i` or `/upload|importer| ajouter/i` — none matched the actual label. The 2026-04-08 console.log → expect conversion pinned assertions against a label the UI never produced. Fix: `data-testid="library-upload-cta"` on the toolbar CTA + aria-label fallback ("Upload track"). Tests target by testid, immune to future i18n/copy changes. Results after fix: * 27-upload.spec.ts — 6/7 now pass. The remaining failure (test 54 "full upload flow") is a DIFFERENT root cause: dialog doesn't close after upload submit (60s timeout). Not a locator issue — tracked separately as #55 (upload backend hangs on submit, suspected ClamAV or validation silently failing in test env). * 04-tracks.spec.ts:207 — unskipped, passes (was #50, now closed; SKIPPED_TESTS.md updated with resolution note). * 43-upload-deep.spec.ts helper — migrated to the same testid so the "button not found" class of failure is gone. Remaining 43-upload-deep failures are same upload-flow class as 27-upload:54 (tracked in #55). Gain: 8/12 upload-family tests recovered. Remaining 4 are a separate investigation. Post-fix validation: ran `27-upload + 04-tracks` under Playwright — 7 passed, 2 failed, 1 skipped (skip unrelated). The 2 failures are both the #55 submit-hang root cause, not the locator one. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:38:28 +00:00
// v1.0.7-rc1 pre-fix: the library "Upload" trigger is a Plus-icon
// button labelled t('library.new') (= "New" / "Nouveau"), not
// "Upload". Historical regex /upload|uploader/i never matched,
// producing 12 @critical failures. Now targeted via testid for
// stability against future i18n / label changes.
const uploadBtn = page.getByTestId('library-upload-cta');
await expect(uploadBtn).toBeVisible({ timeout: 10_000 });
await uploadBtn.click();
const dialog = page.locator('[role="dialog"]').first();
await expect(dialog).toBeVisible({ timeout: 5_000 });
// Step 2: Set file
const fileInput = dialog.locator('input[type="file"]').first();
expect(await fileInput.count(), 'File input must exist').toBeGreaterThan(0);
const uniqueTitle = `E2E Upload ${Date.now()}`;
await fileInput.setInputFiles({
name: 'test-track.mp3',
mimeType: 'audio/mpeg',
buffer: createTestMP3Buffer(),
});
// Step 3: Fill metadata — title input must appear after file is processed
const titleInput = dialog.locator('#title').or(dialog.locator('input[name="title"]'));
await expect(titleInput, 'Title input must appear after file upload').toBeVisible({ timeout: 10_000 });
await titleInput.fill(uniqueTitle);
const artistInput = dialog.locator('#artist').or(dialog.locator('input[name="artist"]'));
if (await artistInput.isVisible({ timeout: 2_000 }).catch(() => false)) {
await artistInput.fill('E2E Test Artist');
}
const genreInput = dialog.locator('#genre').or(dialog.locator('input[name="genre"]'));
if (await genreInput.isVisible({ timeout: 2_000 }).catch(() => false)) {
await genreInput.fill('Electronic');
}
// Step 4: Submit
const submitBtn = dialog.locator('button[type="submit"]')
.or(dialog.locator('button[form="upload-track-form"]'))
.or(dialog.getByRole('button', { name: /uploader/i }));
await expect(submitBtn, 'Submit button must be visible').toBeVisible({ timeout: 3_000 });
await submitBtn.click();
// Step 5: Wait for upload to complete — dialog must close or show success
await expect(dialog, 'Upload dialog must close after successful upload').not.toBeVisible({ timeout: 60_000 });
// Step 6: Verify track appears in library
await navigateTo(page, '/library');
await page.waitForTimeout(2_000);
const trackInLibrary = page.locator(`text=${uniqueTitle}`).first();
await expect(
trackInLibrary,
`Uploaded track "${uniqueTitle}" must be visible in library`,
).toBeVisible({ timeout: 15_000 });
});
test('should show error for invalid file format', async ({ page }) => {
await navigateTo(page, '/library');
fix(e2e): stable upload-trigger testid, unskip v107-e2e-04 — rc1-day2 root cause #2 12 @critical failures on 27-upload + 43-upload-deep + the skipped 04-tracks:207 shared one root cause: the LibraryPageToolbar "New" button (renders t('library.new'), localized to "New"/"Nouveau") was targeted by regex `/upload|uploader/i` or `/upload|importer| ajouter/i` — none matched the actual label. The 2026-04-08 console.log → expect conversion pinned assertions against a label the UI never produced. Fix: `data-testid="library-upload-cta"` on the toolbar CTA + aria-label fallback ("Upload track"). Tests target by testid, immune to future i18n/copy changes. Results after fix: * 27-upload.spec.ts — 6/7 now pass. The remaining failure (test 54 "full upload flow") is a DIFFERENT root cause: dialog doesn't close after upload submit (60s timeout). Not a locator issue — tracked separately as #55 (upload backend hangs on submit, suspected ClamAV or validation silently failing in test env). * 04-tracks.spec.ts:207 — unskipped, passes (was #50, now closed; SKIPPED_TESTS.md updated with resolution note). * 43-upload-deep.spec.ts helper — migrated to the same testid so the "button not found" class of failure is gone. Remaining 43-upload-deep failures are same upload-flow class as 27-upload:54 (tracked in #55). Gain: 8/12 upload-family tests recovered. Remaining 4 are a separate investigation. Post-fix validation: ran `27-upload + 04-tracks` under Playwright — 7 passed, 2 failed, 1 skipped (skip unrelated). The 2 failures are both the #55 submit-hang root cause, not the locator one. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:38:28 +00:00
// v1.0.7-rc1 pre-fix: the library "Upload" trigger is a Plus-icon
// button labelled t('library.new') (= "New" / "Nouveau"), not
// "Upload". Historical regex /upload|uploader/i never matched,
// producing 12 @critical failures. Now targeted via testid for
// stability against future i18n / label changes.
const uploadBtn = page.getByTestId('library-upload-cta');
await expect(uploadBtn).toBeVisible({ timeout: 10_000 });
await uploadBtn.click();
const dialog = page.locator('[role="dialog"]').first();
await expect(dialog).toBeVisible({ timeout: 5_000 });
const fileInput = dialog.locator('input[type="file"]').first();
expect(await fileInput.count()).toBeGreaterThan(0);
// Upload a text file — must be rejected
await fileInput.setInputFiles({
name: 'invalid.txt',
mimeType: 'text/plain',
buffer: Buffer.from('This is not an audio file'),
});
await page.waitForTimeout(1_000);
// Either: error message appears, OR dropzone is still shown (file was rejected silently)
const errorMsg = dialog.locator('text=/format|invalid|non supporté|rejected/i').first();
const dropzoneStillVisible = dialog.locator('text=/glissez|drag|drop/i').first();
const hasError = await errorMsg.isVisible({ timeout: 3_000 }).catch(() => false);
const dropzoneBack = await dropzoneStillVisible.isVisible({ timeout: 3_000 }).catch(() => false);
expect(
hasError || dropzoneBack,
'Invalid file must be rejected: error message or dropzone should remain',
).toBeTruthy();
});
test('should disable submit button when no file is selected', async ({ page }) => {
await navigateTo(page, '/library');
fix(e2e): stable upload-trigger testid, unskip v107-e2e-04 — rc1-day2 root cause #2 12 @critical failures on 27-upload + 43-upload-deep + the skipped 04-tracks:207 shared one root cause: the LibraryPageToolbar "New" button (renders t('library.new'), localized to "New"/"Nouveau") was targeted by regex `/upload|uploader/i` or `/upload|importer| ajouter/i` — none matched the actual label. The 2026-04-08 console.log → expect conversion pinned assertions against a label the UI never produced. Fix: `data-testid="library-upload-cta"` on the toolbar CTA + aria-label fallback ("Upload track"). Tests target by testid, immune to future i18n/copy changes. Results after fix: * 27-upload.spec.ts — 6/7 now pass. The remaining failure (test 54 "full upload flow") is a DIFFERENT root cause: dialog doesn't close after upload submit (60s timeout). Not a locator issue — tracked separately as #55 (upload backend hangs on submit, suspected ClamAV or validation silently failing in test env). * 04-tracks.spec.ts:207 — unskipped, passes (was #50, now closed; SKIPPED_TESTS.md updated with resolution note). * 43-upload-deep.spec.ts helper — migrated to the same testid so the "button not found" class of failure is gone. Remaining 43-upload-deep failures are same upload-flow class as 27-upload:54 (tracked in #55). Gain: 8/12 upload-family tests recovered. Remaining 4 are a separate investigation. Post-fix validation: ran `27-upload + 04-tracks` under Playwright — 7 passed, 2 failed, 1 skipped (skip unrelated). The 2 failures are both the #55 submit-hang root cause, not the locator one. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:38:28 +00:00
// v1.0.7-rc1 pre-fix: the library "Upload" trigger is a Plus-icon
// button labelled t('library.new') (= "New" / "Nouveau"), not
// "Upload". Historical regex /upload|uploader/i never matched,
// producing 12 @critical failures. Now targeted via testid for
// stability against future i18n / label changes.
const uploadBtn = page.getByTestId('library-upload-cta');
await expect(uploadBtn).toBeVisible({ timeout: 10_000 });
await uploadBtn.click();
const dialog = page.locator('[role="dialog"]').first();
await expect(dialog).toBeVisible({ timeout: 5_000 });
// Submit button should either not exist yet (no file) or be disabled
const submitBtn = dialog.locator('button[type="submit"]')
.or(dialog.locator('button[form="upload-track-form"]'))
.or(dialog.getByRole('button', { name: /uploader/i }));
const isVisible = await submitBtn.isVisible({ timeout: 3_000 }).catch(() => false);
if (isVisible) {
await expect(submitBtn, 'Submit button must be disabled when no file is selected').toBeDisabled();
}
// If submit button is not visible at all (only appears after file selection), that's also correct
});
test('should close modal with Escape key', async ({ page }) => {
await navigateTo(page, '/library');
fix(e2e): stable upload-trigger testid, unskip v107-e2e-04 — rc1-day2 root cause #2 12 @critical failures on 27-upload + 43-upload-deep + the skipped 04-tracks:207 shared one root cause: the LibraryPageToolbar "New" button (renders t('library.new'), localized to "New"/"Nouveau") was targeted by regex `/upload|uploader/i` or `/upload|importer| ajouter/i` — none matched the actual label. The 2026-04-08 console.log → expect conversion pinned assertions against a label the UI never produced. Fix: `data-testid="library-upload-cta"` on the toolbar CTA + aria-label fallback ("Upload track"). Tests target by testid, immune to future i18n/copy changes. Results after fix: * 27-upload.spec.ts — 6/7 now pass. The remaining failure (test 54 "full upload flow") is a DIFFERENT root cause: dialog doesn't close after upload submit (60s timeout). Not a locator issue — tracked separately as #55 (upload backend hangs on submit, suspected ClamAV or validation silently failing in test env). * 04-tracks.spec.ts:207 — unskipped, passes (was #50, now closed; SKIPPED_TESTS.md updated with resolution note). * 43-upload-deep.spec.ts helper — migrated to the same testid so the "button not found" class of failure is gone. Remaining 43-upload-deep failures are same upload-flow class as 27-upload:54 (tracked in #55). Gain: 8/12 upload-family tests recovered. Remaining 4 are a separate investigation. Post-fix validation: ran `27-upload + 04-tracks` under Playwright — 7 passed, 2 failed, 1 skipped (skip unrelated). The 2 failures are both the #55 submit-hang root cause, not the locator one. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:38:28 +00:00
// v1.0.7-rc1 pre-fix: the library "Upload" trigger is a Plus-icon
// button labelled t('library.new') (= "New" / "Nouveau"), not
// "Upload". Historical regex /upload|uploader/i never matched,
// producing 12 @critical failures. Now targeted via testid for
// stability against future i18n / label changes.
const uploadBtn = page.getByTestId('library-upload-cta');
await expect(uploadBtn).toBeVisible({ timeout: 10_000 });
await uploadBtn.click();
const dialog = page.locator('[role="dialog"]').first();
await expect(dialog).toBeVisible({ timeout: 5_000 });
// Close via Escape
await page.keyboard.press('Escape');
await expect(dialog, 'Dialog must close after pressing Escape').not.toBeVisible({ timeout: 3_000 });
});
test('should close modal with close button', async ({ page }) => {
await navigateTo(page, '/library');
fix(e2e): stable upload-trigger testid, unskip v107-e2e-04 — rc1-day2 root cause #2 12 @critical failures on 27-upload + 43-upload-deep + the skipped 04-tracks:207 shared one root cause: the LibraryPageToolbar "New" button (renders t('library.new'), localized to "New"/"Nouveau") was targeted by regex `/upload|uploader/i` or `/upload|importer| ajouter/i` — none matched the actual label. The 2026-04-08 console.log → expect conversion pinned assertions against a label the UI never produced. Fix: `data-testid="library-upload-cta"` on the toolbar CTA + aria-label fallback ("Upload track"). Tests target by testid, immune to future i18n/copy changes. Results after fix: * 27-upload.spec.ts — 6/7 now pass. The remaining failure (test 54 "full upload flow") is a DIFFERENT root cause: dialog doesn't close after upload submit (60s timeout). Not a locator issue — tracked separately as #55 (upload backend hangs on submit, suspected ClamAV or validation silently failing in test env). * 04-tracks.spec.ts:207 — unskipped, passes (was #50, now closed; SKIPPED_TESTS.md updated with resolution note). * 43-upload-deep.spec.ts helper — migrated to the same testid so the "button not found" class of failure is gone. Remaining 43-upload-deep failures are same upload-flow class as 27-upload:54 (tracked in #55). Gain: 8/12 upload-family tests recovered. Remaining 4 are a separate investigation. Post-fix validation: ran `27-upload + 04-tracks` under Playwright — 7 passed, 2 failed, 1 skipped (skip unrelated). The 2 failures are both the #55 submit-hang root cause, not the locator one. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:38:28 +00:00
// v1.0.7-rc1 pre-fix: the library "Upload" trigger is a Plus-icon
// button labelled t('library.new') (= "New" / "Nouveau"), not
// "Upload". Historical regex /upload|uploader/i never matched,
// producing 12 @critical failures. Now targeted via testid for
// stability against future i18n / label changes.
const uploadBtn = page.getByTestId('library-upload-cta');
await expect(uploadBtn).toBeVisible({ timeout: 10_000 });
await uploadBtn.click();
const dialog = page.locator('[role="dialog"]').first();
await expect(dialog).toBeVisible({ timeout: 5_000 });
// Close via button
const closeBtn = dialog.getByRole('button', { name: /close|cancel|fermer|annuler/i }).first();
await expect(closeBtn, 'Close/Cancel button must exist in dialog').toBeVisible({ timeout: 3_000 });
await closeBtn.click();
await expect(dialog, 'Dialog must close after clicking close button').not.toBeVisible({ timeout: 3_000 });
});
});