test: add deterministic resilience matrix
This commit is contained in:
89
tests/browser/audio-interruption.spec.ts
Normal file
89
tests/browser/audio-interruption.spec.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { expect, test } from '../helpers/serve-dist';
|
||||
import {
|
||||
assertSemanticFaultOracle,
|
||||
authorizedFaultUrl,
|
||||
collectBrowserErrors,
|
||||
readUnhandledRejections,
|
||||
triggerFaultAction,
|
||||
} from '../helpers/test-build-auth';
|
||||
import { installSceneInstrumentation, readSceneInstrumentation } from '../helpers/scene-instrumentation';
|
||||
|
||||
test.beforeEach(async ({ page }, testInfo) => {
|
||||
test.skip(testInfo.project.name !== 'desktop-chromium', 'Audio fault matrix runs once on current desktop Chromium.');
|
||||
await installSceneInstrumentation(page);
|
||||
});
|
||||
|
||||
const startAudio = async (page: import('@playwright/test').Page): Promise<void> => {
|
||||
await page.getByRole('button', { name: 'START THE DRIVE' }).click();
|
||||
};
|
||||
|
||||
const assertAudioContained = async (
|
||||
page: import('@playwright/test').Page,
|
||||
pageErrors: readonly string[],
|
||||
expectedLiveContexts: number,
|
||||
): Promise<void> => {
|
||||
await assertSemanticFaultOracle(page);
|
||||
expect(pageErrors).toEqual([]);
|
||||
expect(await readUnhandledRejections(page)).toEqual([]);
|
||||
const resources = await readSceneInstrumentation(page);
|
||||
expect(resources.unhandledRejections).toEqual([]);
|
||||
expect(resources.audioContextsConstructed).toBe(1);
|
||||
expect(resources.liveAudioContexts).toBe(expectedLiveContexts);
|
||||
};
|
||||
|
||||
test('F10 contains initial Web Audio start rejection and creates no reusable graph', async ({ page, distUrl }) => {
|
||||
const errors = await collectBrowserErrors(page);
|
||||
await page.goto(authorizedFaultUrl(distUrl, 'F10-audio-start-rejection'), { waitUntil: 'domcontentloaded' });
|
||||
await startAudio(page);
|
||||
|
||||
await expect(page.getByText('Audio unavailable. Continue without sound.')).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: 'START THE DRIVE' })).toHaveCount(0);
|
||||
await assertSemanticFaultOracle(page);
|
||||
expect(errors.pageErrors).toEqual([]);
|
||||
expect(await readUnhandledRejections(page)).toEqual([]);
|
||||
expect((await readSceneInstrumentation(page)).audioContextsConstructed).toBe(0);
|
||||
});
|
||||
|
||||
test('F11 keeps an interrupted intact graph suspended after resume rejection', async ({ page, distUrl }) => {
|
||||
const errors = await collectBrowserErrors(page);
|
||||
await page.goto(authorizedFaultUrl(distUrl, 'F11-audio-resume-rejection'), { waitUntil: 'domcontentloaded' });
|
||||
await startAudio(page);
|
||||
await expect(page.getByRole('button', { name: 'Mute sound' })).toBeVisible();
|
||||
|
||||
await triggerFaultAction(page, 'audio-interruption');
|
||||
await expect(page.getByRole('button', { name: 'Resume sound' })).toBeVisible();
|
||||
await page.getByRole('button', { name: 'Resume sound' }).click();
|
||||
|
||||
await expect(page.getByRole('button', { name: 'Resume sound' })).toBeVisible();
|
||||
await expect(page.getByText('Audio unavailable. Continue without sound.')).toHaveCount(0);
|
||||
await assertAudioContained(page, errors.pageErrors, 1);
|
||||
});
|
||||
|
||||
test('F12 tears down a graph that becomes invalid during resume', async ({ page, distUrl }) => {
|
||||
const errors = await collectBrowserErrors(page);
|
||||
await page.goto(authorizedFaultUrl(distUrl, 'F12-audio-graph-invalid'), { waitUntil: 'domcontentloaded' });
|
||||
await startAudio(page);
|
||||
await triggerFaultAction(page, 'audio-interruption');
|
||||
await expect(page.getByRole('button', { name: 'Resume sound' })).toBeVisible();
|
||||
await page.getByRole('button', { name: 'Resume sound' }).click();
|
||||
|
||||
await expect(page.getByText('Audio unavailable. Continue without sound.')).toBeVisible();
|
||||
await expect.poll(async () => (await readSceneInstrumentation(page)).liveAudioContexts).toBe(0);
|
||||
await assertAudioContained(page, errors.pageErrors, 0);
|
||||
});
|
||||
|
||||
test('F13 synchronously silences and closes the graph when hide-time suspend rejects', async ({ page, distUrl }) => {
|
||||
const errors = await collectBrowserErrors(page);
|
||||
await page.goto(authorizedFaultUrl(distUrl, 'F13-audio-suspend-rejection'), { waitUntil: 'domcontentloaded' });
|
||||
await startAudio(page);
|
||||
await expect(page.getByRole('button', { name: 'Mute sound' })).toBeVisible();
|
||||
|
||||
await page.evaluate(() => {
|
||||
Object.defineProperty(document, 'visibilityState', { configurable: true, value: 'hidden' });
|
||||
document.dispatchEvent(new Event('visibilitychange'));
|
||||
});
|
||||
|
||||
await expect(page.getByText('Audio unavailable. Continue without sound.')).toBeVisible();
|
||||
await expect.poll(async () => (await readSceneInstrumentation(page)).liveAudioContexts).toBe(0);
|
||||
await assertAudioContained(page, errors.pageErrors, 0);
|
||||
});
|
||||
Reference in New Issue
Block a user