open-design/e2e/resources/playwright.ts
PerishFire 526c7f7c26
Fix packaged auto-update release validation (#2565)
* fix: tighten packaged updater flow

* test: prune noisy extended ui coverage

* fix: hide unpublished release artifacts

* test: validate release updater channels

* fix: align prerelease release namespaces
2026-05-21 18:15:53 +08:00

597 lines
21 KiB
TypeScript

import type { UiScenario } from '@/playwright/resources';
export const playwrightUiScenarios: UiScenario[] = [
{
id: 'prototype-basic',
title: 'Prototype project creates and previews a generated artifact',
kind: 'prototype',
flow: 'standard',
automated: true,
description:
'Validates the primary happy path: create a prototype project, send one prompt, persist the generated HTML, and render it in the preview iframe.',
create: {
projectName: 'UI automation smoke',
tab: 'prototype',
},
prompt: 'Create a small test artifact',
mockArtifact: {
identifier: 'mock-artifact',
title: 'Mock Artifact',
fileName: 'mock-artifact.html',
heading: 'Mock Artifact',
html:
'<!doctype html><html><body><main><h1>Mock Artifact</h1><p>Generated by Playwright.</p></main></body></html>',
},
expectedFiles: [
{
name: 'mock-artifact.html',
kind: 'html',
previewText: 'Generated by Playwright.',
},
],
expectedPreviewText: 'Generated by Playwright.',
notes: [
'This is the seed smoke test and should stay fast.',
'It uses mocked SSE so the UI path stays deterministic.',
],
},
{
id: 'deck-basic',
title: 'Deck project renders a mocked slide artifact',
kind: 'deck',
flow: 'standard',
automated: true,
description:
'Covers the deck tab in project creation and verifies that a deck artifact lands in the workspace preview.',
create: {
projectName: 'Deck automation smoke',
tab: 'deck',
},
prompt: 'Create a short deck with two slides',
mockArtifact: {
identifier: 'mock-deck',
title: 'Mock Deck',
fileName: 'mock-deck.html',
heading: 'Mock Deck',
html:
'<!doctype html><html><body><section class="slide"><h1>Mock Deck</h1></section></body></html>',
},
expectedFiles: [
{
name: 'mock-deck.html',
kind: 'html',
previewText: 'Mock Deck',
},
],
notes: [
'Confirms the deck creation tab still routes into the same generation path.',
],
},
{
id: 'hyperframes-basic',
title: 'HyperFrames project routes through media video creation and previews generated motion content',
kind: 'hyperframes',
flow: 'hyperframes-project-routing',
automated: true,
description:
'Covers the current product path for HyperFrames: create a project from New project → Media → Video with the hyperframes-html model, confirm the create payload stays pinned to the hyperframes skill, and preview the generated HTML motion artifact.',
create: {
projectName: 'HyperFrames automation smoke',
tab: 'media',
mediaSurface: 'video',
videoModel: 'hyperframes-html',
},
prompt: 'Create a five-second HyperFrames product reveal with a live HTML-in-canvas composition',
mockArtifact: {
identifier: 'mock-hyperframes',
title: 'Mock HyperFrames Motion',
fileName: 'mock-hyperframes.html',
heading: 'Mock HyperFrames Motion',
html:
'<!doctype html><html><body><main data-duration="5" data-width="1920" data-height="1080"><h1>Mock HyperFrames Motion</h1><p>Generated by the HyperFrames media video path.</p></main></body></html>',
},
expectedProjectMetadata: {
kind: 'video',
videoModel: 'hyperframes-html',
},
expectedRunRequest: {
message: 'Create a five-second HyperFrames product reveal with a live HTML-in-canvas composition',
},
expectedFiles: [
{
name: 'mock-hyperframes.html',
kind: 'html',
previewText: 'Mock HyperFrames Motion',
},
],
expectedPreviewText: 'Generated by the HyperFrames media video path.',
notes: [
'Replaces the removed home-rail HyperFrames flow with the current create-project architecture.',
'Pins the model to hyperframes-html and verifies the project create request still resolves to the hyperframes skill.',
],
},
{
id: 'image-basic',
title: 'Image project routes through media image creation with the expected metadata',
kind: 'image',
flow: 'image-project-routing',
automated: true,
description:
'Covers the current image creation path: create a project from New project → Media → Image and verify the image metadata persisted on the project matches the selected surface defaults.',
create: {
projectName: 'Image automation smoke',
tab: 'media',
mediaSurface: 'image',
},
prompt: 'Create a launch poster image prompt',
expectedProjectMetadata: {
kind: 'image',
imageModel: 'gpt-image-2',
},
notes: [
'Keeps this smoke focused on create-time routing and metadata, not downstream image generation providers.',
],
},
{
id: 'video-basic',
title: 'Video project routes through media video creation with the expected default metadata',
kind: 'workspace',
flow: 'video-project-routing',
automated: true,
description:
'Covers the current default video creation path: create a project from New project → Media → Video and verify the project metadata persists the expected default model, aspect, and duration.',
create: {
projectName: 'Video automation smoke',
tab: 'media',
mediaSurface: 'video',
},
prompt: 'Create a short product teaser video prompt',
expectedProjectMetadata: {
kind: 'video',
videoModel: 'doubao-seedance-2-0-260128',
videoAspect: '16:9',
videoLength: 5,
},
notes: [
'Keeps this smoke on create-time routing and metadata instead of provider execution.',
],
},
{
id: 'audio-sfx-basic',
title: 'Audio SFX project routes through media audio creation with the expected metadata',
kind: 'audio',
flow: 'audio-project-routing',
automated: true,
description:
'Covers the current audio creation path: create a project from New project → Media → Audio, switch to SFX, and verify the audio metadata persisted on the project matches the SFX defaults.',
create: {
projectName: 'Audio SFX automation smoke',
tab: 'media',
mediaSurface: 'audio',
audioKind: 'sfx',
},
prompt: 'Create a short impact sound effect prompt',
expectedProjectMetadata: {
kind: 'audio',
audioKind: 'sfx',
audioModel: 'elevenlabs-sfx',
},
notes: [
'Verifies the media audio branch still saves SFX-specific metadata without depending on provider execution.',
],
},
{
id: 'live-artifact-basic',
title: 'Live artifact project routes through its modal tab with the expected metadata',
kind: 'prototype',
flow: 'live-artifact-project-routing',
automated: true,
description:
'Covers the current live artifact creation path: create a project from New project → Live artifact and verify the project metadata persists prototype kind, live-artifact intent, and locked high-fidelity rendering.',
create: {
projectName: 'Live artifact automation smoke',
tab: 'live-artifact',
},
prompt: 'Create a data-connected live artifact prompt',
expectedProjectMetadata: {
kind: 'prototype',
intent: 'live-artifact',
fidelity: 'high-fidelity',
},
notes: [
'Keeps this smoke focused on create-time routing and metadata instead of connector execution.',
],
},
{
id: 'comment-attachment-flow',
title: 'Preview comments attach to chat and send as structured context',
kind: 'prototype',
flow: 'comment-attachment-flow',
automated: true,
description:
'Exercises V1 comment mode: save a latest element comment, attach/remove it from the composer, and send it as an empty visible prompt with structured comment context.',
create: {
projectName: 'Comment attachment flow',
tab: 'prototype',
},
prompt: 'Create a commentable preview artifact',
mockArtifact: {
identifier: 'commentable-artifact',
title: 'Commentable Artifact',
fileName: 'commentable-artifact.html',
heading: 'Prototype headline',
html:
'<!doctype html><html><body><main data-od-id="hero-section"><h1 data-od-id="hero-title" data-screen-label="Hero title">Prototype headline</h1><p data-od-id="hero-copy">Preview copy for comment mode.</p></main></body></html>',
},
notes: [
'The composer textarea stays empty; selected preview comments are sent through commentAttachments.',
],
},
{
id: 'example-use-prompt',
title: 'Using an example prompt creates a project with a seeded draft',
kind: 'prototype',
flow: 'example-use-prompt',
automated: true,
description:
'Verifies the Examples tab fast path: click Use this prompt, create a project immediately, and carry the example prompt into the chat composer.',
create: {
projectName: 'Example prompt project',
tab: 'prototype',
},
prompt: 'Draft a warm utility landing page for a productivity app',
notes: [
'Uses a mocked skills list so the examples gallery stays deterministic.',
'Targets the pendingPrompt fast-create path instead of the standard new-project form.',
],
},
{
id: 'conversation-persistence',
title: 'Conversation history survives refresh and switching',
kind: 'workspace',
flow: 'conversation-persistence',
automated: true,
description:
'Exercises conversation creation, persistence, refresh reload, and switching between threads in one project.',
create: {
projectName: 'Conversation persistence',
tab: 'prototype',
},
prompt: 'Create a small test artifact',
secondaryPrompt: 'Create another artifact in a fresh conversation',
mockArtifact: {
identifier: 'mock-artifact',
title: 'Mock Artifact',
fileName: 'mock-artifact.html',
heading: 'Mock Artifact',
html:
'<!doctype html><html><body><main><h1>Mock Artifact</h1><p>Generated by Playwright.</p></main></body></html>',
},
expectedFiles: [
{
name: 'mock-artifact.html',
kind: 'html',
previewText: 'Generated by Playwright.',
},
],
expectedPreviewText: 'Generated by Playwright.',
notes: [
'Should use the same mock SSE flow as the prototype smoke path.',
'Reload should keep the original conversation content available from the history menu.',
],
},
{
id: 'file-mention',
title: 'Uploaded files can be mentioned and sent back to the agent',
kind: 'workspace',
flow: 'file-mention',
automated: true,
description:
'Validates the upload, staged attachment, and @ mention flow inside the chat composer.',
create: {
projectName: 'File mention flow',
tab: 'prototype',
},
prompt: 'Review @reference.txt and use it as context',
expectedRunRequest: {
message: 'Review @reference.txt',
attachments: ['reference.txt'],
},
expectedFiles: [
{
name: 'reference.txt',
previewText: 'Reference content for mention flow.',
},
],
notes: [
'Seeds a tiny text fixture through the project file API, then exercises the composer mention flow.',
],
},
{
id: 'deep-link-preview',
title: 'Deep-linking to a file route opens the expected preview tab',
kind: 'workspace',
flow: 'deep-link-preview',
automated: true,
description:
'Verifies that /projects/:id/files/:name restores the matching open tab and preview frame after navigation or refresh.',
create: {
projectName: 'Deep link preview',
tab: 'prototype',
},
prompt: 'Create a small test artifact',
mockArtifact: {
identifier: 'mock-artifact',
title: 'Mock Artifact',
fileName: 'mock-artifact.html',
heading: 'Mock Artifact',
html:
'<!doctype html><html><body><main><h1>Mock Artifact</h1><p>Generated by Playwright.</p></main></body></html>',
},
expectedFiles: [
{
name: 'mock-artifact.html',
kind: 'html',
previewText: 'Generated by Playwright.',
},
],
expectedPreviewText: 'Generated by Playwright.',
notes: [
'Can reuse the generated HTML from prototype-basic, then revisit with a routed URL.',
],
},
{
id: 'file-upload-send',
title: 'Composer file picker uploads a file and sends it with the prompt',
kind: 'workspace',
flow: 'file-upload-send',
automated: true,
description:
'Exercises the real attach button and hidden file input, then verifies the staged file is sent and shown back on the user message.',
create: {
projectName: 'File upload send flow',
tab: 'prototype',
},
prompt: 'Use the uploaded reference as context',
notes: [
'Uses Playwright setInputFiles on the hidden composer picker instead of seeding through the API.',
],
},
{
id: 'design-files-upload',
title: 'Design Files panel uploads an image and opens it in the workspace',
kind: 'workspace',
flow: 'design-files-upload',
automated: true,
description:
'Exercises the Design Files upload flow in the workspace, then verifies the uploaded image can be previewed and opened as a tab.',
create: {
projectName: 'Design files upload flow',
tab: 'prototype',
},
prompt: 'Upload an image through the design files browser',
notes: [
'Uses the FileWorkspace upload input rather than the chat composer upload path.',
],
},
{
id: 'design-files-delete',
title: 'Design Files panel deletes an uploaded file and clears its tab',
kind: 'workspace',
flow: 'design-files-delete',
automated: true,
description:
'Uploads a file through the Design Files panel, deletes it from the row menu, and verifies it disappears from both the list and open tabs.',
create: {
projectName: 'Design files delete flow',
tab: 'prototype',
},
prompt: 'Delete an uploaded image through the design files browser',
notes: [
'Builds on the same workspace file flow as design-files-upload, then verifies cleanup behavior.',
],
},
{
id: 'design-files-tab-persistence',
title: 'Open file tabs survive refresh with the correct active tab',
kind: 'workspace',
flow: 'design-files-tab-persistence',
automated: true,
description:
'Uploads multiple files through the Design Files flow, switches the active tab, reloads the page, and verifies both the tab set and selected tab are restored.',
create: {
projectName: 'Design files tab persistence',
tab: 'prototype',
},
prompt: 'Restore open file tabs after refresh',
notes: [
'Covers the persisted tabs state stored by ProjectView and restored by FileWorkspace.',
],
},
{
id: 'conversation-delete-recovery',
title: 'Deleting the active conversation falls back cleanly',
kind: 'workspace',
flow: 'conversation-delete-recovery',
automated: true,
description:
'Creates multiple conversations, deletes the active one, and verifies the UI falls back to the remaining thread instead of getting stuck.',
create: {
projectName: 'Conversation delete recovery',
tab: 'prototype',
},
prompt: 'Create a small test artifact',
secondaryPrompt: 'Create another artifact before deleting this thread',
mockArtifact: {
identifier: 'mock-artifact',
title: 'Mock Artifact',
fileName: 'mock-artifact.html',
heading: 'Mock Artifact',
html:
'<!doctype html><html><body><main><h1>Mock Artifact</h1><p>Generated by Playwright.</p></main></body></html>',
},
notes: [
'Confirms the project still has a live conversation after deleting the current thread.',
],
},
{
id: 'question-form-selection-limit',
title: 'Question form checkbox limits block selecting more than the allowed maximum',
kind: 'workspace',
flow: 'question-form-selection-limit',
automated: true,
description:
'Verifies that a discovery-style checkbox question with maxSelections=2 cannot be pushed past two selected options.',
create: {
projectName: 'Question form selection limit',
tab: 'prototype',
},
prompt: 'Help me plan a restaurant homepage',
notes: [
'Mocks a question-form response instead of an artifact so the test can exercise the inline clarifying UI.',
'Confirms both the interaction guard and the rendered checked state stay capped at two options.',
],
},
{
id: 'question-form-submit-persistence',
title: 'Question form answers persist into chat history and reload in a locked state',
kind: 'workspace',
flow: 'question-form-submit-persistence',
automated: true,
description:
'Verifies that answering a question form writes a user follow-up message, then rehydrates the form in an answered and locked state after reload.',
create: {
projectName: 'Question form submit persistence',
tab: 'prototype',
},
prompt: 'Plan a small restaurant homepage',
expectedRunRequest: {
message: 'Plan a small restaurant homepage',
},
notes: [
'Mocks an inline question form on the first assistant turn and a plain acknowledgment on the follow-up turn.',
'Confirms the answered state survives a full page reload instead of relying only on local submit state.',
],
},
{
id: 'generation-does-not-create-extra-file',
title: 'Generated artifacts stay stable when no new prompt is sent',
kind: 'workspace',
flow: 'generation-does-not-create-extra-file',
automated: true,
description:
'Generates one HTML artifact, then verifies reload and idle time do not create any additional project files without a new user prompt.',
create: {
projectName: 'No extra generated file',
tab: 'prototype',
},
prompt: 'Create one landing page artifact',
mockArtifact: {
identifier: 'stable-artifact',
title: 'Stable Artifact',
fileName: 'stable-artifact.html',
heading: 'Stable Artifact',
html:
'<!doctype html><html><body><main><h1>Stable Artifact</h1><p>Only one file should exist.</p></main></body></html>',
},
expectedFiles: [
{
name: 'stable-artifact.html',
kind: 'html',
previewText: 'Only one file should exist.',
},
],
expectedPreviewText: 'Only one file should exist.',
notes: [
'Targets the trust-sensitive bug where a project can appear to generate a fresh file on its own.',
'Uses the files API after reload to assert the project file set is unchanged.',
],
},
{
id: 'deck-pagination-next-prev-correctness',
title: 'Deck preview previous and next controls move in the correct direction',
kind: 'deck',
flow: 'deck-pagination-next-prev-correctness',
automated: true,
description:
'Should verify that deck preview pagination moves to the actual previous and next slide instead of routing both actions to the same page.',
create: {
projectName: 'Deck pagination controls',
tab: 'deck',
},
prompt: 'Review pagination behavior in a multi-slide deck preview',
notes: [
'Seeds deterministic deck HTML through the project files API and verifies previous/next controls in Playwright.',
],
},
{
id: 'deck-pagination-per-file-isolated',
title: 'Each HTML deck tab preserves its own pagination state',
kind: 'deck',
flow: 'deck-pagination-per-file-isolated',
automated: true,
description:
'Should verify that switching between multiple deck HTML files does not leak page position across tabs or reset both files to page 1.',
create: {
projectName: 'Deck pagination isolation',
tab: 'deck',
},
prompt: 'Keep pagination state isolated per generated deck file',
notes: [
'Seeds two deterministic deck HTML files and verifies each open tab preserves its own active slide.',
],
},
{
id: 'uploaded-image-renders-in-preview',
title: 'Uploaded reference images render correctly in generated deck preview',
kind: 'workspace',
flow: 'uploaded-image-renders-in-preview',
automated: true,
description:
'Should verify that uploaded images resolve to loadable src paths inside generated HTML instead of rendering as broken images.',
create: {
projectName: 'Uploaded image preview render',
tab: 'prototype',
},
prompt: 'Use uploaded brand images inside a generated deck preview',
expectedFiles: [
{
name: 'brand.png',
kind: 'image',
},
{
name: 'image-preview.html',
kind: 'html',
previewText: 'Image Preview',
},
],
expectedPreviewText: 'Image Preview',
notes: [
'Seeds an image plus relative HTML reference and asserts the preview iframe loads the image.',
],
},
{
id: 'python-source-preview',
title: 'Python files should open with a readable inline source preview',
kind: 'workspace',
flow: 'python-source-preview',
automated: true,
description:
'Should verify that opening a .py file in the main workspace renders a readable source/code preview instead of an unsupported blank state.',
create: {
projectName: 'Python source preview',
tab: 'prototype',
},
prompt: 'Open a generated Python file and inspect its source inline',
expectedFiles: [
{
name: 'app.py',
kind: 'code',
previewText: 'hello from python',
},
],
notes: [
'Seeds a deterministic .py file through the project files API, opens it from the file list, and asserts the source viewer renders readable code text.',
],
},
];