video-accessibility/frontend/tests/e2e/vtt-editing.spec.ts
2025-08-24 16:28:33 -05:00

149 lines
No EOL
5.6 KiB
TypeScript

import { test, expect } from '@playwright/test';
import { MockAPIHelper } from '../helpers/auth';
import { testJobs, testVttContent } from '../fixtures/test-data';
test.describe('VTT Editing Workflow', () => {
let mockAPI: MockAPIHelper;
test.beforeEach(async ({ page }) => {
mockAPI = new MockAPIHelper(page);
// Mock authentication
await mockAPI.mockLoginSuccess('reviewer');
// Mock job data
await mockAPI.mockJobDetail(testJobs.pendingQC.id, testJobs.pendingQC);
await mockAPI.mockVttContent(testJobs.pendingQC.id, 'en', {
captions_vtt: testVttContent.captions,
audio_description_vtt: testVttContent.audioDescription,
});
});
test('should display VTT editor with content', async ({ page }) => {
await page.goto(`/jobs/${testJobs.pendingQC.id}/edit`);
// Should show VTT editors
await expect(page.getByText('Captions')).toBeVisible();
await expect(page.getByText('Audio Description')).toBeVisible();
// Should show VTT content
await expect(page.getByText('Welcome to our video accessibility platform.')).toBeVisible();
await expect(page.getByText('A person sits at a modern desk with a computer.')).toBeVisible();
});
test('should show timing information', async ({ page }) => {
await page.goto(`/jobs/${testJobs.pendingQC.id}/edit`);
// Should show timing information in proper format
await expect(page.getByText('0:01.000 → 0:03.500')).toBeVisible();
await expect(page.getByText('(2500ms)')).toBeVisible();
});
test('should enter edit mode on cue click', async ({ page }) => {
await page.goto(`/jobs/${testJobs.pendingQC.id}/edit`);
// Hover over first cue to show edit button
const firstCue = page.getByText('Welcome to our video accessibility platform.').locator('..');
await firstCue.hover();
// Click edit button
await page.getByText('Edit text').first().click();
// Should show edit interface
await expect(page.getByRole('textbox')).toBeVisible();
await expect(page.getByRole('textbox')).toHaveValue('Welcome to our video accessibility platform.');
await expect(page.getByText('Save (Ctrl+Enter)')).toBeVisible();
await expect(page.getByText('Cancel (Esc)')).toBeVisible();
});
test('should save edited cue content', async ({ page }) => {
// Mock the VTT update API
await page.route(`**/api/v1/jobs/${testJobs.pendingQC.id}/vtt`, async route => {
if (route.request().method() === 'PATCH') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ ...testJobs.pendingQC, updated_at: new Date().toISOString() }),
});
}
});
await page.goto(`/jobs/${testJobs.pendingQC.id}/edit`);
// Enter edit mode
const firstCue = page.getByText('Welcome to our video accessibility platform.').locator('..');
await firstCue.hover();
await page.getByText('Edit text').first().click();
// Edit the content
const textarea = page.getByRole('textbox');
await textarea.clear();
await textarea.fill('Updated welcome message for accessibility platform.');
// Save changes
await page.getByText('Save (Ctrl+Enter)').click();
// Should exit edit mode and show updated content
await expect(page.getByText('Updated welcome message for accessibility platform.')).toBeVisible();
await expect(page.getByRole('textbox')).not.toBeVisible();
});
test('should cancel editing without saving', async ({ page }) => {
await page.goto(`/jobs/${testJobs.pendingQC.id}/edit`);
// Enter edit mode
const firstCue = page.getByText('Welcome to our video accessibility platform.').locator('..');
await firstCue.hover();
await page.getByText('Edit text').first().click();
// Edit the content
const textarea = page.getByRole('textbox');
await textarea.clear();
await textarea.fill('This should not be saved');
// Cancel changes
await page.getByText('Cancel (Esc)').click();
// Should exit edit mode and show original content
await expect(page.getByText('Welcome to our video accessibility platform.')).toBeVisible();
await expect(page.getByText('This should not be saved')).not.toBeVisible();
await expect(page.getByRole('textbox')).not.toBeVisible();
});
test('should support keyboard shortcuts', async ({ page }) => {
await page.goto(`/jobs/${testJobs.pendingQC.id}/edit`);
// Enter edit mode
const firstCue = page.getByText('Welcome to our video accessibility platform.').locator('..');
await firstCue.hover();
await page.getByText('Edit text').first().click();
const textarea = page.getByRole('textbox');
await textarea.clear();
await textarea.fill('Keyboard shortcut test');
// Test Escape to cancel
await page.keyboard.press('Escape');
// Should cancel editing
await expect(page.getByText('Welcome to our video accessibility platform.')).toBeVisible();
await expect(page.getByRole('textbox')).not.toBeVisible();
});
test('should show validation errors for invalid VTT', async ({ page }) => {
// Mock invalid VTT content
await mockAPI.mockVttContent(testJobs.pendingQC.id, 'en', {
captions_vtt: `WEBVTT
00:00:03.000 --> 00:00:01.000
Invalid timing order`,
audio_description_vtt: testVttContent.audioDescription,
});
await page.goto(`/jobs/${testJobs.pendingQC.id}/edit`);
// Should show validation errors
await expect(page.getByText('Validation Errors:')).toBeVisible();
await expect(page.getByText(/Start time must be before end time/)).toBeVisible();
});
});