58 lines
2.6 KiB
TypeScript
58 lines
2.6 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
|
|
|
const CONTROL_URL = '/control/'
|
|
const LIVE = process.env.OPENSQUILLA_E2E_LIVE === '1'
|
|
|
|
test.describe('Code block syntax highlighting', () => {
|
|
test('idle chat renders no highlighted code blocks', async ({ page }) => {
|
|
await page.goto(CONTROL_URL + 'chat/new')
|
|
await page.waitForSelector('.conn-pill', { timeout: 10000 })
|
|
|
|
await expect(page.locator('code.hljs')).toHaveCount(0)
|
|
await expect(page.locator('.code-lang')).toHaveCount(0)
|
|
})
|
|
|
|
test('live python snippet renders distinct token colors and a language label', async ({ page }) => {
|
|
test.skip(!LIVE, 'Live gateway test; set OPENSQUILLA_E2E_LIVE=1 to run.')
|
|
test.setTimeout(240000)
|
|
|
|
await page.goto(CONTROL_URL + 'chat/new')
|
|
await page.waitForSelector('.conn-pill', { timeout: 10000 })
|
|
|
|
await page.locator('.chat-textarea').fill(
|
|
'Reply with exactly one fenced python code block (```python) defining def greet(name): return f"hello {name}" — keep the def keyword and the string literal. No prose outside the block.',
|
|
)
|
|
await page.locator('.chat-send-btn[aria-label="Send"]').click()
|
|
|
|
const block = page.locator('.msg-ai .msg-ai-text pre code.hljs').first()
|
|
await expect(block).toBeVisible({ timeout: 180000 })
|
|
await expect(page.locator('.stream-activity')).toHaveCount(0, { timeout: 180000 })
|
|
|
|
// Highlighter token spans survive sanitization.
|
|
const keyword = block.locator('.hljs-keyword').first()
|
|
const literal = block.locator('.hljs-string').first()
|
|
await expect(keyword).toBeVisible()
|
|
await expect(literal).toBeVisible()
|
|
|
|
// Two token kinds resolve to different computed colors, and both differ
|
|
// from the block's base text color — the --syntax-* tokens applied.
|
|
const keywordColor = await keyword.evaluate(node => getComputedStyle(node).color)
|
|
const stringColor = await literal.evaluate(node => getComputedStyle(node).color)
|
|
const baseColor = await block.evaluate(node => getComputedStyle(node).color)
|
|
expect(keywordColor).not.toBe(stringColor)
|
|
expect(keywordColor).not.toBe(baseColor)
|
|
expect(stringColor).not.toBe(baseColor)
|
|
|
|
// The language label chip renders on the block.
|
|
const label = page.locator('.msg-ai .msg-ai-text pre .code-lang').first()
|
|
await expect(label).toBeVisible()
|
|
await expect(label).toHaveText(/python/i)
|
|
|
|
// Highlighting survives a reload: history replays through the same renderer.
|
|
await page.reload()
|
|
await page.waitForSelector('.conn-pill', { timeout: 10000 })
|
|
const replayed = page.locator('.msg-ai .msg-ai-text pre code.hljs .hljs-keyword').first()
|
|
await expect(replayed).toBeVisible({ timeout: 30000 })
|
|
})
|
|
})
|