| @@ -359,6 +359,83 @@ test('公开回答只播放服务端音频,缺失时保留文字且不调用 | |||||
| await expect.poll(() => page.evaluate(() => (window as unknown as { __speechSynthesisUtteranceCalls: number }).__speechSynthesisUtteranceCalls)).toBe(0) | await expect.poll(() => page.evaluate(() => (window as unknown as { __speechSynthesisUtteranceCalls: number }).__speechSynthesisUtteranceCalls)).toBe(0) | ||||
| }) | }) | ||||
| test('悬浮数字人向宿主上报拖动并应用宿主主题', async ({ page }) => { | |||||
| await installMocks(page) | |||||
| await page.route('**/widget-protocol-host', (route) => route.fulfill({ | |||||
| status: 200, | |||||
| contentType: 'text/html; charset=utf-8', | |||||
| body: `<!doctype html><html><body> | |||||
| <iframe id="widget" src="/embed/published-agent" title="数字教员" allow="autoplay; microphone" | |||||
| style="position:fixed;right:16px;bottom:16px;width:208px;height:92px;border:0"></iframe> | |||||
| <script> | |||||
| var frame = document.getElementById('widget'); | |||||
| var drag = null; | |||||
| addEventListener('message', function (event) { | |||||
| var data = event.data || {}; | |||||
| if (event.source !== frame.contentWindow || event.origin !== location.origin || data.source !== 'virtual-instructor-widget') return; | |||||
| if (data.type === 'ready') frame.contentWindow.postMessage({ | |||||
| source: 'virtual-instructor-widget-host', type: 'theme', | |||||
| theme: { scheme:'light', accent:'#197fc8', accentHover:'#1269aa', surface:'#ffffff', surfaceMuted:'#f1f6f9', text:'#17354d', textMuted:'#526d81', border:'#d2dfe8' } | |||||
| }, location.origin); | |||||
| if (data.type === 'resize') { | |||||
| frame.style.width = data.width + 'px'; | |||||
| frame.style.height = data.height + 'px'; | |||||
| } | |||||
| if (data.type === 'drag-start') { | |||||
| var rect = frame.getBoundingClientRect(); | |||||
| drag = { left: rect.left, top: rect.top }; | |||||
| } | |||||
| if (data.type === 'drag-move' && drag) { | |||||
| drag.left += data.deltaX; | |||||
| drag.top += data.deltaY; | |||||
| frame.style.left = drag.left + 'px'; | |||||
| frame.style.top = drag.top + 'px'; | |||||
| frame.style.right = 'auto'; | |||||
| frame.style.bottom = 'auto'; | |||||
| } | |||||
| if (data.type === 'drag-end') { | |||||
| document.body.dataset.dragEnded = 'true'; | |||||
| drag = null; | |||||
| } | |||||
| }); | |||||
| <\/script> | |||||
| </body></html>`, | |||||
| })) | |||||
| await page.goto('/widget-protocol-host') | |||||
| const widgetFrame = page.locator('#widget') | |||||
| const launcher = page.frameLocator('#widget').locator('.embed-launcher') | |||||
| await expect(launcher).toBeVisible() | |||||
| const before = await widgetFrame.boundingBox() | |||||
| const launcherBox = await launcher.boundingBox() | |||||
| expect(before).not.toBeNull() | |||||
| expect(launcherBox).not.toBeNull() | |||||
| await page.mouse.move(launcherBox!.x + launcherBox!.width / 2, launcherBox!.y + launcherBox!.height / 2) | |||||
| await page.mouse.down() | |||||
| await page.mouse.move(launcherBox!.x - 150, launcherBox!.y - 90, { steps: 8 }) | |||||
| await page.mouse.up() | |||||
| await expect(page.locator('body')).toHaveAttribute('data-drag-ended', 'true') | |||||
| await expect.poll(async () => (await widgetFrame.boundingBox())?.x).toBeLessThan(before!.x - 100) | |||||
| await expect(page.frameLocator('#widget').locator('.embed-widget')).not.toHaveClass(/is-expanded/) | |||||
| await launcher.click() | |||||
| const panel = page.frameLocator('#widget').locator('.embed-panel') | |||||
| await expect(panel).toBeVisible() | |||||
| const panelHead = page.frameLocator('#widget').locator('.embed-panel-head') | |||||
| await expect(panelHead).toHaveCSS('background-color', 'rgb(25, 127, 200)') | |||||
| const beforePanelDrag = await widgetFrame.boundingBox() | |||||
| const panelHeadBox = await panelHead.boundingBox() | |||||
| expect(beforePanelDrag).not.toBeNull() | |||||
| expect(panelHeadBox).not.toBeNull() | |||||
| await page.locator('body').evaluate((body) => delete body.dataset.dragEnded) | |||||
| await page.mouse.move(panelHeadBox!.x + panelHeadBox!.width / 2, panelHeadBox!.y + panelHeadBox!.height / 2) | |||||
| await page.mouse.down() | |||||
| await page.mouse.move(panelHeadBox!.x - 80, panelHeadBox!.y - 50, { steps: 6 }) | |||||
| await page.mouse.up() | |||||
| await expect(page.locator('body')).toHaveAttribute('data-drag-ended', 'true') | |||||
| await expect.poll(async () => (await widgetFrame.boundingBox())?.x).toBeLessThan(beforePanelDrag!.x - 50) | |||||
| }) | |||||
| test('标签达到上限时静默淘汰最久未访问项', async ({ page }) => { | test('标签达到上限时静默淘汰最久未访问项', async ({ page }) => { | ||||
| await installMocks(page) | await installMocks(page) | ||||
| await page.addInitScript(() => { | await page.addInitScript(() => { | ||||