82 lines
3.7 KiB
TypeScript
82 lines
3.7 KiB
TypeScript
import { test, expect, type Page } from '@playwright/test'
|
|
|
|
const CONTROL_URL = '/control/'
|
|
const LIVE = process.env.OPENSQUILLA_E2E_LIVE === '1'
|
|
|
|
const LONG_TASK = 'Write a detailed essay of at least 500 words about the history of the printing press. Do not stop early.'
|
|
|
|
async function openDraft(page: Page) {
|
|
await page.goto(CONTROL_URL + 'chat/new')
|
|
await page.waitForSelector('.conn-pill', { timeout: 10000 })
|
|
}
|
|
|
|
async function startLongRun(page: Page) {
|
|
const textarea = page.locator('.chat-textarea')
|
|
await textarea.fill(LONG_TASK)
|
|
await page.locator('.chat-send-btn[aria-label="Send"]').click()
|
|
// The busy-mode toggle is the streaming signal: it only renders mid-run.
|
|
await expect(page.locator('.chat-busy-mode')).toBeVisible({ timeout: 30000 })
|
|
}
|
|
|
|
test.describe('Queue/Steer composer semantics', () => {
|
|
test('idle composer shows no delivery-mode toggle', async ({ page }) => {
|
|
await openDraft(page)
|
|
|
|
await expect(page.locator('.chat-textarea')).toBeVisible()
|
|
await expect(page.locator('.chat-send-btn[aria-label="Send"]')).toBeVisible()
|
|
await expect(page.locator('.chat-busy-mode')).toHaveCount(0)
|
|
await expect(page.locator('.chat-pending-mode')).toHaveCount(0)
|
|
})
|
|
|
|
test('queue mode holds the message and auto-sends after the turn', async ({ page }) => {
|
|
test.skip(!LIVE, 'Live gateway test; set OPENSQUILLA_E2E_LIVE=1 to run.')
|
|
test.setTimeout(240000)
|
|
|
|
await openDraft(page)
|
|
await startLongRun(page)
|
|
|
|
// Queue is the default mode while running.
|
|
await expect(page.getByRole('button', { name: 'Queue', exact: true })).toHaveAttribute('aria-pressed', 'true')
|
|
|
|
const queuedText = 'After you finish, reply with the single word: queued-done'
|
|
await page.locator('.chat-textarea').fill(queuedText)
|
|
await page.locator('.chat-send-btn[aria-label="Send"]').click()
|
|
|
|
// The draft waits in the visible pending queue, labeled with its mode.
|
|
await expect(page.locator('.chat-pending-chip')).toHaveCount(1)
|
|
await expect(page.locator('.chat-pending-mode')).toHaveText('Queue')
|
|
await expect(page.locator('.msg-user')).toHaveCount(1)
|
|
|
|
// After the first turn ends the queued draft auto-sends FIFO.
|
|
await expect(page.locator('.msg-user')).toHaveCount(2, { timeout: 180000 })
|
|
await expect(page.locator('.msg-user').nth(1)).toContainText('queued-done')
|
|
await expect(page.locator('.chat-pending-chip')).toHaveCount(0)
|
|
})
|
|
|
|
test('steer mode sends immediately into the active run', async ({ page }) => {
|
|
test.skip(!LIVE, 'Live gateway test; set OPENSQUILLA_E2E_LIVE=1 to run.')
|
|
test.setTimeout(240000)
|
|
|
|
await openDraft(page)
|
|
await startLongRun(page)
|
|
|
|
await page.getByRole('button', { name: 'Steer', exact: true }).click()
|
|
await expect(page.getByRole('button', { name: 'Steer', exact: true })).toHaveAttribute('aria-pressed', 'true')
|
|
|
|
const steerText = 'Stop the essay. Acknowledge this steering message and reply with just: steered-ok'
|
|
await page.locator('.chat-textarea').fill(steerText)
|
|
await page.locator('.chat-send-btn[aria-label="Send"]').click()
|
|
|
|
// The steer message lands in the transcript right away — nothing queues.
|
|
await expect(page.locator('.msg-user')).toHaveCount(2, { timeout: 15000 })
|
|
await expect(page.locator('.msg-user').nth(1)).toContainText('steered-ok')
|
|
await expect(page.locator('.chat-pending-chip')).toHaveCount(0)
|
|
|
|
// The run continues mid-turn and reaches a terminal state with a reply
|
|
// produced after the steering message was injected.
|
|
await expect(page.locator('.chat-busy-mode')).toHaveCount(0, { timeout: 180000 })
|
|
await expect(page.locator('.msg-ai').last()).toBeVisible()
|
|
await expect(page.locator('.msg-ai').last()).toContainText(/steer/i, { timeout: 30000 })
|
|
})
|
|
})
|