import { fileURLToPath } from 'node:url' import type { Browser, Page } from 'playwright' import { chromium } from 'playwright' import { afterAll, beforeAll, describe, expect, it, onTestFailed } from 'vitest' import { createMessage, createUserMessage } from '@deepseek-ai/dsh-llm' import { SESSION_FORMAT_VERSION, Session, SessionId } from '@deepseek-ai/dsh-session' import type {} from '@deepseek-ai/dsh-session-title' import { assertFixtureInventory, captureStableAria, compareOrRefreshGolden, launchWebScaffold, seedSession, watchConsole, webSnapshotMode, type WebScaffold, } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/markdown-inline-code-links', import.meta.url)) const UI_EXPECTED = fileURLToPath(new URL('./snapshots/markdown-inline-code-links/ui.expected.md', import.meta.url)) const MODE = webSnapshotMode() const SEED_ID = 'markdown-inline-code-links-web-e2e' const DONE = 'INLINE_CODE_LINK_DONE' /** Build a settled assistant reply with linkable URL code and inert code controls. */ function markdownFixture(linkUrl: string): string { const session = Session.create(SessionId('markdown-inline-code-links-source')) const eventTimeOrigin = new Date().setHours(12, 0, 0, 0) session.append('turn/start', { turn: 1 }) const user = session.append('user/message', createUserMessage({ content: [{ type: 'text', text: 'Show the local preview URL.' }], source: { kind: 'user' }, }), { surfaceOp: 'append' }) session.append('session/title', { title: 'Inline code links', messageSeqs: [user.seq], source: { kind: 'fallback' }, }) session.append('step/start', { turn: 1, step: 1 }) session.append('assistant/message', { turn: 1, step: 1, message: createMessage({ role: 'assistant', content: [{ type: 'text', text: [ '## Inline code links', '', `Preview: \`${linkUrl}\``, '', `Standard: [Open preview](${linkUrl})`, '', `Command: \`curl ${linkUrl}\``, '', 'Unsafe: `javascript:alert(1)`', '', DONE, ].join('\n'), }], source: { kind: 'model', provider: 'fixture', model: 'fixture' }, }), }, { surfaceOp: 'append' }) session.append('step/end', { turn: 1, step: 1 }) session.append('turn/end', { turn: 1, reason: { kind: 'completed' } }) return [ JSON.stringify({ type: 'session', version: SESSION_FORMAT_VERSION, id: '{{sessionId}}', createdAt: 0, cwd: '{{cwd}}', }), ...session.events.map(event => JSON.stringify({ ...event, time: eventTimeOrigin + event.seq * 1_000, })), '', ].join('\n') } describe('web e2e: Markdown inline-code links', () => { let scaffold: WebScaffold let browser: Browser let page: Page let linkUrl: string let tripwire: ReturnType beforeAll(async () => { scaffold = await launchWebScaffold({}) linkUrl = new URL('/?demo=1', scaffold.baseUrl).toString() await seedSession(scaffold, markdownFixture(linkUrl), SEED_ID) browser = await chromium.launch() page = await newEnglishPage(browser) tripwire = watchConsole(page) await page.goto(scaffold.baseUrl, { waitUntil: 'load' }) await page.waitForSelector('[class*="frame"]', { timeout: 30_000 }) }, 120_000) afterAll(async () => { await browser?.close() await scaffold?.close() }) it.skipIf(MODE === 'record')('opens a complete HTTP URL from inline code and leaves other code inert', async () => { onTestFailed(() => saveFailureShot(page, 'web-e2e-markdown-inline-code-links')) const groupRow = page.locator('[role="treeitem"]').first() await groupRow.waitFor({ timeout: 15_000 }) await groupRow.click() const sessionRow = page.locator('[role="treeitem"]').nth(1) await sessionRow.waitFor({ timeout: 10_000 }) await sessionRow.click() await expect.poll(() => page.getByText(DONE, { exact: true }).count(), { timeout: 15_000 }).toBe(1) const inlineCodeLink = page.locator('[class*="markdown"] code a') await expect.poll(() => inlineCodeLink.count(), { timeout: 10_000 }).toBe(1) expect(await inlineCodeLink.getAttribute('href')).toBe(linkUrl) expect(await inlineCodeLink.getAttribute('target')).toBe('_blank') expect(await inlineCodeLink.getAttribute('rel')).toBe('noopener noreferrer') await inlineCodeLink.focus() expect(await inlineCodeLink.evaluate(element => document.activeElement === element)).toBe(true) const popupPromise = page.waitForEvent('popup') await inlineCodeLink.click() const popup = await popupPromise await popup.waitForURL(linkUrl, { timeout: 15_000 }) expect(popup.url()).toBe(linkUrl) await popup.close() expect(await page.getByText(`curl ${linkUrl}`, { exact: true }).locator('a').count()).toBe(0) expect(await page.getByText('javascript:alert(1)', { exact: true }).locator('a').count()).toBe(0) const snapshot = (await captureStableAria(page, '[class*="centerCol"]', scaffold.workspaceCwd)) .split(SEED_ID).join('{{seededId}}') .split(linkUrl).join('{{linkUrl}}') await compareOrRefreshGolden(UI_EXPECTED, snapshot, MODE) expect(tripwire.pageErrors).toEqual([]) expect(tripwire.warnings).toEqual([]) await assertFixtureInventory(SNAPSHOT_DIR, ['ui.expected.md']) }, 60_000) })