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:
@@ -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()
|
||||
}
|
||||
})
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user