66 lines
2.7 KiB
JavaScript
66 lines
2.7 KiB
JavaScript
// @ts-check
|
|
// Functional safety net for the Script Rehearser — guards the parser/cast pipeline
|
|
// while rehearser.js is split into smaller modules (#8).
|
|
const { test, expect } = require('@playwright/test');
|
|
|
|
const SCRIPT = `FADE IN
|
|
|
|
EXT. HARBOR - NIGHT
|
|
|
|
A ship rocks in the dark.
|
|
|
|
JACK
|
|
We need to find the compass.
|
|
|
|
GIBBS
|
|
Aye, Captain. But the tide is against us.
|
|
|
|
JACK
|
|
Then we sail against the tide.`;
|
|
|
|
async function navTo(page, section) {
|
|
await page.waitForFunction(() => typeof window.navTo === 'function', null, { timeout: 15_000 });
|
|
await page.evaluate((s) => window.navTo(s), section);
|
|
}
|
|
|
|
test('parses a screenplay and builds the cast', async ({ page }) => {
|
|
await page.route('**/api/voices*', route => route.fulfill({
|
|
json: [{ id: 'smoke_voice', name: 'Smoke voice', enabled: true }],
|
|
}));
|
|
await page.goto('/', { waitUntil: 'domcontentloaded' });
|
|
await navTo(page, 's-rehearser');
|
|
await page.waitForFunction(() => typeof window.navRehearserPhase === 'function', null, { timeout: 15_000 });
|
|
await page.evaluate(() => window.navRehearserPhase(1));
|
|
|
|
// Go to the Cast tab area: paste a script and parse
|
|
await page.waitForSelector('#reh-script-text', { timeout: 10_000 });
|
|
await page.evaluate(() => window.navRehearserPhase(1));
|
|
await expect(page.locator('#reh-script-text')).toBeVisible({ timeout: 10_000 });
|
|
await page.fill('#reh-script-text', SCRIPT);
|
|
await page.click('#reh-parse-btn');
|
|
|
|
// Cast cards should appear: Narrator + JACK + GIBBS (title page / FADE IN filtered out)
|
|
const cards = page.locator('#reh-cast-list .reh-cast-card');
|
|
await expect(cards).toHaveCount(3, { timeout: 10_000 });
|
|
await expect(page.locator('#reh-cast-list')).toContainText('JACK');
|
|
await expect(page.locator('#reh-cast-list')).toContainText('GIBBS');
|
|
// Scene heading / FADE IN must NOT have become characters
|
|
await expect(page.locator('#reh-cast-list')).not.toContainText('FADE IN');
|
|
await expect(page.locator('#reh-cast-list')).not.toContainText('HARBOR');
|
|
|
|
// A "Hear a line" sample button appears once a character has a voice assigned
|
|
await expect(page.locator('.reh-cc-sample-btn')).toHaveCount(0);
|
|
const realVoiceId = await page.evaluate(async () => {
|
|
const response = await fetch('/api/voices');
|
|
const voices = await response.json();
|
|
return voices.find(v => v && v.id && v.enabled !== false)?.id || voices.find(v => v && v.id)?.id;
|
|
});
|
|
expect(realVoiceId).toBeTruthy();
|
|
await page.evaluate((voiceId) => {
|
|
rehState.cast['JACK'].voice = voiceId;
|
|
renderCastList();
|
|
}, realVoiceId);
|
|
await expect(page.locator('.reh-cc-sample-btn').first()).toContainText('Hear a line');
|
|
await expect(page.locator('.reh-cc-sample-btn').first()).toContainText('Hear a line');
|
|
});
|