test(desktop): pin the group mention popover to the elevated surface in vitest

Replace the Playwright spec from #104065 with one jsdom invariant in the
existing GroupMentionInput suite: the popover carries `bg-(--ui-bg-elevated)`
and never a `--ui-bg-{primary,secondary,tertiary}` fill token. The Desktop
E2E job is `if: false` in ci.yaml, so the 96-line spec (two bots, a group,
a 32-paragraph post, a theme toggle) would never run; the token → opaque
surface chain was verified once in headless Chromium (alpha 62 → 255).
This commit is contained in:
teknium1
2026-09-18 01:52:00 -07:00
committed by Teknium
parent e0f0d2f539
commit e6fa1fd474
2 changed files with 14 additions and 96 deletions

View File

@@ -1,96 +0,0 @@
import { type MockBackendFixture, setupMockBackend, waitForAppReady } from './fixtures'
import { expect, test } from './test'
let fixture: MockBackendFixture | null = null
async function openBots(page: MockBackendFixture['page']): Promise<void> {
const tab = page
.getByRole('button', { name: 'Bots', exact: true })
.or(page.getByRole('tab', { name: 'Bots', exact: true }))
.first()
await tab.click()
await expect(page.getByRole('button', { name: 'New bot or group chat' })).toBeVisible()
}
async function createAgent(page: MockBackendFixture['page'], name: string, title: string): Promise<void> {
await page.getByRole('button', { name: 'New bot or group chat' }).click()
await page.getByRole('menuitem', { name: 'New Bot' }).click()
const dialog = page.getByRole('dialog', { name: 'New Bot' })
await dialog.getByPlaceholder('inbox-triage').fill(name)
await dialog.getByPlaceholder('Inbox Triage').fill(title)
await dialog.getByRole('button', { name: 'Create Bot' }).click()
await expect(dialog).toBeHidden({ timeout: 30_000 })
await expect(page.getByRole('button', { name: new RegExp(`^${title}\\b`) }).first()).toBeVisible({ timeout: 30_000 })
}
test.beforeAll(async () => {
fixture = await setupMockBackend()
await waitForAppReady(fixture, 120_000)
})
test.afterAll(async () => {
await fixture?.cleanup()
fixture = null
})
test('group mentions cover expanded posts in light and dark mode', async () => {
test.setTimeout(240_000)
const page = fixture!.page
await openBots(page)
await createAgent(page, 'programmer', 'Programmer')
await createAgent(page, 'reviewer', 'Reviewer')
await page.getByRole('button', { name: 'New bot or group chat' }).click()
await page.getByRole('menuitem', { name: 'New Group Chat' }).click()
const dialog = page.getByRole('dialog', { name: 'New Group Chat' })
for (const title of ['Programmer', 'Reviewer']) {
await dialog.getByText(title, { exact: true }).locator('xpath=ancestor::label').getByRole('checkbox').click()
}
await dialog.getByRole('textbox', { name: 'Group name' }).fill('Mention surface')
await dialog.getByRole('button', { name: 'Create Group (2)' }).click()
const composer = page.getByRole('textbox', { name: 'Message Mention surface', exact: true }).filter({ visible: true })
await expect(composer).toBeVisible()
await composer.fill(
Array.from({ length: 32 }, (_, i) => `Post line ${i + 1}: content behind the mention menu.`).join('\n\n')
)
await composer.press('Enter')
await expect(page.getByRole('button', { name: 'Collapse thread', exact: true })).toBeVisible()
for (const mode of ['light', 'dark']) {
// The real theme switch updates the semantic surface tokens, not just a
// class on the menu. The shortcut is registered by the desktop shell.
const dark = await page.locator('html').evaluate(el => el.classList.contains('dark'))
if (dark !== (mode === 'dark')) {
await composer.press('Tab')
await page.keyboard.press('Shift+X')
}
await expect(page.locator('html')).toHaveClass(mode === 'dark' ? /dark/ : /^(?!.*\bdark\b)/)
await composer.fill('')
await composer.fill('@')
const option = page.getByRole('button', { name: /^@everyone / }).filter({ visible: true })
await expect(option).toBeVisible()
const painted = await option.evaluate(el => {
const menu = el.parentElement!
const style = getComputedStyle(menu)
const canvas = document.createElement('canvas')
canvas.width = canvas.height = 1
const ctx = canvas.getContext('2d')!
ctx.fillStyle = style.backgroundColor
ctx.fillRect(0, 0, 1, 1)
const rect = el.getBoundingClientRect()
return {
alpha: ctx.getImageData(0, 0, 1, 1).data[3],
receivesPointer: el.contains(document.elementFromPoint(rect.left + 8, rect.top + rect.height / 2))
}
})
expect(painted.alpha, `${mode}: transcript must not show through the menu`).toBe(255)
expect(painted.receivesPointer).toBe(true)
await page.screenshot({ path: test.info().outputPath(`mentions-${mode}.png`) })
await composer.press('ArrowDown')
await composer.press('Enter')
await expect(composer).toHaveValue('@all ')
await composer.fill('@')
await composer.press('Escape')
await expect(option).toBeHidden()
}
})

View File

@@ -171,6 +171,20 @@ describe('insertion', () => {
expect(options().some(label => label.startsWith('@builder'))).toBe(true)
expect(options().some(label => label.startsWith('@undefined'))).toBe(false)
})
it('paints the popover on the elevated surface token, never a translucent fill (#113713)', async () => {
const { input } = await mount()
typeInto(input, '@')
// `--ui-bg-primary` is a hover/interactive FILL (accent mixed into a 10%
// base over transparent) — on it the transcript read straight through the
// menu. Floating menus sit on `--ui-bg-elevated`, an opaque surface.
const menu = screen.getByRole('button', { name: /^@everyone/ }).parentElement
expect(menu?.className).toContain('bg-(--ui-bg-elevated)')
expect(menu?.className).not.toMatch(/bg-\(--ui-bg-(?:primary|secondary|tertiary)\)/)
})
})
// #89884: the composer used to be a single-line Input whose form submitted on