mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-14 20:21:39 +03:00
932 lines
48 KiB
TypeScript
932 lines
48 KiB
TypeScript
import { expect, sourceURL, story } from "../../stories/playwright/story"
|
|
|
|
const source = (path: string) => sourceURL(new URL(path, import.meta.url))
|
|
|
|
const modules = {
|
|
fixture: source("../../gui-plugins/src/browser/panel.fixture.tsx"),
|
|
embeds: source("../src/runtime/plugin/embeds.tsx"),
|
|
panelMotion: source("../src/shell/panel-motion.ts"),
|
|
language: source("../src/runtime/i18n/language.tsx"),
|
|
}
|
|
|
|
story.beforeEach(async ({ mount, page }) => {
|
|
// Any story loads the app styles; the fixture mounts the pane beside it on the real host embeds.
|
|
await mount("ui-line-comment--editor")
|
|
await page.evaluate(async (modules) => {
|
|
const [{ mountBrowserPane }, { createEmbeds }, panelMotion, language] = await Promise.all([
|
|
import(modules.fixture),
|
|
import(modules.embeds),
|
|
import(modules.panelMotion),
|
|
import(modules.language),
|
|
])
|
|
|
|
mountBrowserPane({
|
|
createEmbeds,
|
|
panelMotion,
|
|
LanguageProvider: language.LanguageProvider,
|
|
UiI18nBridge: language.UiI18nBridge,
|
|
useLanguage: language.useLanguage,
|
|
})
|
|
}, modules)
|
|
await expect(page.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
})
|
|
|
|
story("hides a native page when another takes the pane, the pane hides, or it unmounts", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const alpha = root.getByTestId("native-Alpha")
|
|
const beta = root.getByTestId("native-Beta")
|
|
await root.getByRole("button", { name: "Beta", exact: true }).click()
|
|
await expect(beta).toHaveAttribute("data-visible", "true")
|
|
await expect(alpha).toHaveAttribute("data-visible", "false")
|
|
await root.getByRole("button", { name: "Empty", exact: true }).click()
|
|
await expect(root.locator("#browser-panel")).toHaveCount(0)
|
|
await expect(beta).toHaveAttribute("data-visible", "false")
|
|
await root.getByRole("button", { name: "Alpha", exact: true }).click()
|
|
await expect(alpha).toHaveAttribute("data-visible", "true")
|
|
await root.getByRole("button", { name: "Toggle Review tab", exact: true }).click()
|
|
await expect(alpha).toHaveAttribute("data-visible", "false")
|
|
await root.getByRole("button", { name: "Toggle Review tab", exact: true }).click()
|
|
await expect(alpha).toHaveAttribute("data-visible", "true")
|
|
await root.getByRole("button", { name: "Unmount pane", exact: true }).click()
|
|
await expect(alpha).toHaveAttribute("data-visible", "false")
|
|
})
|
|
|
|
story("hides the native view immediately while the pane stays mounted", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const toggle = root.getByRole("button", { name: "Toggle Review tab", exact: true })
|
|
await expect(toggle).toBeEnabled()
|
|
|
|
// Read in the same task as the click so a deferred animation-frame hide cannot pass.
|
|
const visible = await toggle.evaluate((element) => {
|
|
element.dispatchEvent(new MouseEvent("click", { bubbles: true }))
|
|
|
|
return document.querySelector('[data-testid="native-Alpha"]')?.getAttribute("data-visible")
|
|
})
|
|
|
|
expect(visible).toBe("false")
|
|
await expect(root.locator("#browser-panel")).toHaveCount(1)
|
|
await toggle.click()
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
})
|
|
|
|
story("paints a still of the page in place of the native view while a panel moves", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const motion = root.getByRole("button", { name: "Toggle panel motion", exact: true })
|
|
const pane = root.getByRole("button", { name: "Toggle Review tab", exact: true })
|
|
const native = root.getByTestId("native-Alpha")
|
|
const still = root.locator("#browser-panel img")
|
|
|
|
// Read in the same task as the click: a native view left up for even one frame floats over the moving app.
|
|
const visible = await motion.evaluate((element) => {
|
|
element.dispatchEvent(new MouseEvent("click", { bubbles: true }))
|
|
|
|
return document.querySelector('[data-testid="native-Alpha"]')?.getAttribute("data-visible")
|
|
})
|
|
|
|
expect(visible).toBe("false")
|
|
// A close: the page flies out as a still of itself rather than a blank box.
|
|
await expect(still).toBeVisible()
|
|
await pane.click()
|
|
await expect(still).toBeVisible()
|
|
await motion.click()
|
|
await expect(still).toHaveCount(0)
|
|
|
|
// An open shows the still the close left, until the flight lands and the page is back.
|
|
await motion.click()
|
|
await pane.click()
|
|
await expect(still).toBeVisible()
|
|
await expect(native).toHaveAttribute("data-visible", "false")
|
|
await motion.click()
|
|
await expect(native).toHaveAttribute("data-visible", "true")
|
|
await expect(still).toHaveCount(0)
|
|
})
|
|
|
|
story("paints a still of the page in place of the native view while a resize handle is dragged", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const handle = root.getByTestId("pane-resize-handle")
|
|
const native = root.getByTestId("native-Alpha")
|
|
const still = root.locator("#browser-panel img")
|
|
|
|
// A native view's bounds land on screen frames before the DOM around it, so one left up through a drag jumps against
|
|
// its pane on every move. A click on the handle moves nothing and must not blink the page out. Read in the same task
|
|
// as each event, so a view hidden and shown again before the next frame cannot pass.
|
|
const visible = await handle.evaluate((element) => {
|
|
const read = () => document.querySelector('[data-testid="native-Alpha"]')?.getAttribute("data-visible")
|
|
const box = element.getBoundingClientRect()
|
|
const at = { bubbles: true, pointerId: 1, clientX: box.x + box.width / 2, clientY: box.y + box.height / 2 }
|
|
element.dispatchEvent(new PointerEvent("pointerdown", { ...at, button: 0 }))
|
|
document.dispatchEvent(new PointerEvent("pointerup", at))
|
|
const click = read()
|
|
element.dispatchEvent(new PointerEvent("pointerdown", { ...at, button: 0 }))
|
|
const pressed = read()
|
|
document.dispatchEvent(new PointerEvent("pointermove", { ...at, clientX: at.clientX - 40 }))
|
|
|
|
return { click, pressed, dragging: read() }
|
|
})
|
|
|
|
expect(visible).toEqual({ click: "true", pressed: "true", dragging: "false" })
|
|
await expect(still).toBeVisible()
|
|
await handle.evaluate((element) => {
|
|
const box = element.getBoundingClientRect()
|
|
document.dispatchEvent(
|
|
new PointerEvent("pointerup", { bubbles: true, pointerId: 1, clientX: box.x, clientY: box.y }),
|
|
)
|
|
})
|
|
await expect(native).toHaveAttribute("data-visible", "true")
|
|
await expect(still).toHaveCount(0)
|
|
})
|
|
|
|
story("shows the native view again when the window loses focus mid-drag", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const handle = root.getByTestId("pane-resize-handle")
|
|
const native = root.getByTestId("native-Alpha")
|
|
const still = root.locator("#browser-panel img")
|
|
|
|
// Alt+Tab mid-drag delivers no pointerup; the page must not stay locked behind a still.
|
|
await handle.evaluate((element) => {
|
|
const box = element.getBoundingClientRect()
|
|
const at = { bubbles: true, pointerId: 1, clientX: box.x + box.width / 2, clientY: box.y + box.height / 2 }
|
|
element.dispatchEvent(new PointerEvent("pointerdown", { ...at, button: 0 }))
|
|
document.dispatchEvent(new PointerEvent("pointermove", { ...at, clientX: at.clientX - 40 }))
|
|
})
|
|
await expect(native).toHaveAttribute("data-visible", "false")
|
|
await expect(handle).toHaveAttribute("data-dragging", "")
|
|
|
|
await handle.evaluate(() => window.dispatchEvent(new FocusEvent("blur")))
|
|
await expect(native).toHaveAttribute("data-visible", "true")
|
|
await expect(still).toHaveCount(0)
|
|
await expect(handle).not.toHaveAttribute("data-dragging")
|
|
expect(await handle.evaluate(() => document.body.style.userSelect)).toBe("")
|
|
})
|
|
|
|
story("never flies a still of a page the tab has navigated away from", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const motion = root.getByRole("button", { name: "Toggle panel motion", exact: true })
|
|
const native = root.getByTestId("native-Alpha")
|
|
const still = root.locator("#browser-panel img")
|
|
await motion.click()
|
|
await expect(still).toBeVisible()
|
|
await motion.click()
|
|
await expect(native).toHaveAttribute("data-visible", "true")
|
|
await expect(still).toHaveCount(0)
|
|
|
|
await root.getByRole("button", { name: "Hold capture", exact: true }).click()
|
|
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
|
|
await address.fill("https://example.com/")
|
|
await address.press("Enter")
|
|
await expect(address).toHaveValue("https://example.com/")
|
|
await expect(native).toHaveAttribute("data-visible", "true")
|
|
await motion.click()
|
|
await expect(native).toHaveAttribute("data-visible", "false")
|
|
await expect(still).toHaveCount(0)
|
|
// The new page's own still stands in once it arrives.
|
|
await root.getByRole("button", { name: "Release capture", exact: true }).click()
|
|
await expect(still).toBeVisible()
|
|
})
|
|
|
|
story("refreshes page stills by the window's focus, not the document's", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const captures = async () => Number((await root.getByText(/^Captures: \d+$/).textContent())?.split(": ")[1])
|
|
await page.clock.install()
|
|
await expect(root.getByText(/^Captures: [1-9]/)).toBeVisible()
|
|
|
|
// Main reports the window unfocused while this document keeps focus: stills follow the window, so they stop.
|
|
await root.getByRole("button", { name: "Blur window", exact: true }).click()
|
|
const paused = await captures()
|
|
await page.clock.runFor(120_000)
|
|
expect(await captures()).toBe(paused)
|
|
|
|
// Focus coming back to the window, even straight into the embed, which never focuses this document, takes a fresh
|
|
// still at once.
|
|
await root.getByRole("button", { name: "Focus window", exact: true }).click()
|
|
await page.clock.runFor(10)
|
|
await expect(root.getByText(`Captures: ${paused + 1}`, { exact: true })).toBeVisible()
|
|
})
|
|
|
|
story("keeps a still of the page under floating content that covers it", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const still = root.locator("#browser-panel img")
|
|
const native = root.getByTestId("native-Alpha")
|
|
// Reduced motion lands panels at once, so the pane keeps no flight still and captures only for the cover.
|
|
await page.emulateMedia({ reducedMotion: "reduce" })
|
|
await root.getByRole("button", { name: "Hold capture", exact: true }).click()
|
|
await root.getByRole("button", { name: "Toggle popover", exact: true }).click()
|
|
await expect(root.getByText("Captures: 1", { exact: true })).toBeVisible()
|
|
// The native page stays up until its still is ready, so the pane never shows blank.
|
|
await expect(native).toHaveAttribute("data-visible", "true")
|
|
await expect(still).toHaveCount(0)
|
|
|
|
// Main hides the native page at once, so the pane hides it only after a frame has presented the still.
|
|
const order = await native.evaluateHandle((element) => {
|
|
const events: string[] = []
|
|
new PerformanceObserver((list) => {
|
|
if (list.getEntries().length > 0) events.push("still presented")
|
|
}).observe({ type: "element" })
|
|
new MutationObserver(() => {
|
|
if (element.getAttribute("data-visible") === "false") events.push("page hidden")
|
|
}).observe(element, { attributeFilter: ["data-visible"] })
|
|
|
|
return events
|
|
})
|
|
|
|
await root.getByRole("button", { name: "Release capture", exact: true }).click()
|
|
await expect(native).toHaveAttribute("data-visible", "false")
|
|
await expect(still).toBeVisible()
|
|
expect(await order.jsonValue()).toEqual(["still presented", "page hidden"])
|
|
|
|
await root.getByRole("button", { name: "Toggle popover", exact: true }).click()
|
|
await expect(native).toHaveAttribute("data-visible", "true")
|
|
await expect(still).toHaveCount(0)
|
|
await expect(root.getByText("Captures: 1", { exact: true })).toBeVisible()
|
|
})
|
|
|
|
story(
|
|
"freezes on the latest capture when floating content closes and reopens before a capture lands",
|
|
async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const popover = root.getByRole("button", { name: "Toggle popover", exact: true })
|
|
const still = root.locator("#browser-panel img")
|
|
const native = root.getByTestId("native-Alpha")
|
|
await page.emulateMedia({ reducedMotion: "reduce" })
|
|
await root.getByRole("button", { name: "Hold capture", exact: true }).click()
|
|
await popover.click()
|
|
await expect(root.getByText("Captures: 1", { exact: true })).toBeVisible()
|
|
await popover.click()
|
|
await expect(page.locator("[data-popper-positioner]")).toHaveCount(0)
|
|
// The pane measures the overlap on the next animation frame; nothing on screen changes while the capture is held.
|
|
await page.evaluate(() => new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve))))
|
|
await popover.click()
|
|
await expect(root.getByText("Captures: 2", { exact: true })).toBeVisible()
|
|
|
|
// Both captures land in order; the first one belongs to the cover that already closed.
|
|
await root.getByRole("button", { name: "Release capture", exact: true }).click()
|
|
await expect(native).toHaveAttribute("data-visible", "false")
|
|
await expect(still).toBeVisible()
|
|
// The fixture draws each capture a pixel wider: the second one is 5 pixels wide.
|
|
await expect(still).toHaveJSProperty("naturalWidth", 5)
|
|
},
|
|
)
|
|
|
|
story("keeps a still of the page under an open dialog instead of blanking the pane", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const still = root.locator("#browser-panel img")
|
|
const native = root.getByTestId("native-Alpha")
|
|
const toggle = root.getByRole("button", { name: "Toggle dialog", exact: true })
|
|
await root.getByRole("button", { name: "Hold capture", exact: true }).click()
|
|
|
|
// Read in the same task as the click: the page must not hide before its still exists.
|
|
const visible = await toggle.evaluate((element) => {
|
|
element.dispatchEvent(new MouseEvent("click", { bubbles: true }))
|
|
|
|
return document.querySelector('[data-testid="native-Alpha"]')?.getAttribute("data-visible")
|
|
})
|
|
|
|
expect(visible).toBe("true")
|
|
await expect(root.getByText("Captures: 1", { exact: true })).toBeVisible()
|
|
await expect(native).toHaveAttribute("data-visible", "true")
|
|
await expect(still).toHaveCount(0)
|
|
|
|
await root.getByRole("button", { name: "Release capture", exact: true }).click()
|
|
await expect(native).toHaveAttribute("data-visible", "false")
|
|
await expect(still).toBeVisible()
|
|
|
|
await toggle.click()
|
|
await expect(native).toHaveAttribute("data-visible", "true")
|
|
await expect(still).toHaveCount(0)
|
|
await expect(root.getByText("Captures: 1", { exact: true })).toBeVisible()
|
|
})
|
|
|
|
story("hides the native page under a dialog even when its still never arrives", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const native = root.getByTestId("native-Alpha")
|
|
const toggle = root.getByRole("button", { name: "Toggle dialog", exact: true })
|
|
await page.clock.install()
|
|
await root.getByRole("button", { name: "Hold capture", exact: true }).click()
|
|
await toggle.click()
|
|
await page.clock.runFor(100)
|
|
await expect(native).toHaveAttribute("data-visible", "true")
|
|
|
|
// The capture never settles: after its timeout the page hides over the box background instead of the dialog.
|
|
await page.clock.runFor(5_000)
|
|
await expect(native).toHaveAttribute("data-visible", "false")
|
|
await expect(root.locator("#browser-panel img")).toHaveCount(0)
|
|
|
|
await toggle.click()
|
|
await page.clock.runFor(100)
|
|
await expect(native).toHaveAttribute("data-visible", "true")
|
|
})
|
|
|
|
story("comments on a picked element over a still of the page", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
await root.getByRole("combobox", { name: "Picked element scenario" }).selectOption("zoomed")
|
|
const picker = root.getByRole("button", { name: "Select an element to comment on", exact: true })
|
|
await picker.click()
|
|
await expect(picker).toHaveAttribute("aria-pressed", "true")
|
|
await expect(root.getByText("Picker: on", { exact: true })).toBeVisible()
|
|
await expect(root.getByText("Session getter reads: 0", { exact: true })).toBeVisible()
|
|
await expect(root.getByRole("status")).toHaveText(
|
|
"Click an element in the page to comment on it. Press Escape to cancel.",
|
|
)
|
|
|
|
await root.getByRole("button", { name: "Pick element", exact: true }).click()
|
|
await expect(picker).toHaveAttribute("aria-pressed", "false")
|
|
const editor = root.locator('[data-slot="browser-comment-editor"] textarea')
|
|
await expect(editor).toBeFocused()
|
|
await expect(editor).toHaveAttribute("placeholder", "Add an optional comment...")
|
|
await expect(editor).toHaveAccessibleName("Comment on this element")
|
|
await expect(root.getByText("Session getter reads: 0", { exact: true })).toBeVisible()
|
|
await expect(root.locator('[data-slot="browser-comment-editor"]')).toContainText("button.primary")
|
|
// The spotlight frames the picked element in surface pixels.
|
|
await expect(root.locator('[data-slot="browser-comment-spotlight"]')).toHaveCSS("left", "38.4px")
|
|
await expect(root.locator('[data-slot="browser-comment-spotlight"]')).toHaveCSS("width", "128px")
|
|
// The native page hides behind its still so the editor can float over it.
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "false")
|
|
await expect(root.locator("#browser-panel img")).toBeVisible()
|
|
|
|
await editor.fill("Make this the primary colour")
|
|
await root.getByRole("button", { name: "Add element comment", exact: true }).click()
|
|
await expect(root.getByTestId("fixture-comments")).toHaveText("button.primary @e7: Make this the primary colour")
|
|
await expect(root.locator('[data-component="browser-comment"]')).toHaveCount(0)
|
|
await expect(root.getByText("Highlights: clear", { exact: true })).toBeVisible()
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
await expect(root.getByTestId("fixture-comment-metadata")).toContainText('selector \\"main > button.primary\\"')
|
|
await expect(root.getByTestId("fixture-comment-metadata")).toContainText("accessible name")
|
|
|
|
// The pane stays mounted when Beta is routed, and its picker then listens to Beta's page.
|
|
await root.getByRole("button", { name: "Beta", exact: true }).click()
|
|
await expect(root.getByTestId("native-Beta")).toHaveAttribute("data-visible", "true")
|
|
await picker.click()
|
|
await root.getByRole("button", { name: "Pick element", exact: true }).click()
|
|
await expect(editor).toBeFocused()
|
|
await editor.fill("Beta's button too")
|
|
await editor.press("Enter")
|
|
await expect(root.getByTestId("fixture-comments").getByRole("listitem")).toHaveText([
|
|
"button.primary @e7: Make this the primary colour",
|
|
"button.primary @e7: Beta's button too",
|
|
])
|
|
})
|
|
|
|
story("cancels the picker and a comment with Escape", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const picker = root.getByRole("button", { name: "Select an element to comment on", exact: true })
|
|
await picker.click()
|
|
await expect(picker).toHaveAttribute("aria-pressed", "true")
|
|
await page.keyboard.press("Escape")
|
|
await expect(picker).toHaveAttribute("aria-pressed", "false")
|
|
await expect(root.getByText("Picker: off", { exact: true })).toBeVisible()
|
|
|
|
await picker.click()
|
|
await root.getByRole("button", { name: "Pick element", exact: true }).click()
|
|
const editor = root.locator('[data-slot="browser-comment-editor"] textarea')
|
|
await expect(editor).toBeFocused()
|
|
await editor.press("Escape")
|
|
await expect(root.locator('[data-component="browser-comment"]')).toHaveCount(0)
|
|
await expect(root.getByTestId("fixture-comments")).toHaveText("")
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
})
|
|
|
|
story("leaves the picker off and Escape to the app when main never answers", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const picker = root.getByRole("button", { name: "Select an element to comment on", exact: true })
|
|
await root.getByRole("button", { name: "Drop picker requests", exact: true }).click()
|
|
await picker.click()
|
|
await expect(picker).toHaveAttribute("aria-pressed", "false")
|
|
|
|
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
|
|
await address.click()
|
|
await expect(address).toBeFocused()
|
|
await address.press("Escape")
|
|
await expect(address).not.toBeFocused()
|
|
})
|
|
|
|
story("replaces an open page note with the comment for an element picked meanwhile", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
await root.locator('[data-component="browser-address"]').hover()
|
|
await root.getByRole("button", { name: "Add page to session", exact: true }).click()
|
|
await expect(root.locator('[data-slot="browser-comment-editor"] textarea')).toBeFocused()
|
|
|
|
await root.getByRole("button", { name: "Pick element", exact: true }).click()
|
|
await expect(root.locator('[data-component="browser-comment"]')).toHaveCount(1)
|
|
await expect(root.locator('[data-slot="browser-comment-editor"]')).toContainText("button.primary")
|
|
})
|
|
|
|
story("cleans up the originating session's picker and comment after a session switch", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const picker = root.getByRole("button", { name: "Select an element to comment on", exact: true })
|
|
await picker.click()
|
|
await expect(root.getByText("Picker Alpha: on", { exact: true })).toBeVisible()
|
|
await root.getByRole("button", { name: "Beta", exact: true }).click()
|
|
await expect(root.getByTestId("native-Beta")).toHaveAttribute("data-visible", "true")
|
|
await expect(root.getByText("Picker Alpha: off", { exact: true })).toBeVisible()
|
|
await expect(picker).toHaveAttribute("aria-pressed", "false")
|
|
|
|
await root.getByRole("button", { name: "Alpha", exact: true }).click()
|
|
await picker.click()
|
|
await root.getByRole("button", { name: "Pick element", exact: true }).click()
|
|
await expect(root.locator('[data-slot="browser-comment-editor"] textarea')).toBeFocused()
|
|
await root.getByRole("button", { name: "Beta", exact: true }).click()
|
|
await expect(root.locator('[data-component="browser-comment"]')).toHaveCount(0)
|
|
await expect(root.getByText("Highlights: clear", { exact: true })).toBeVisible()
|
|
await expect(root.getByText("Highlight owners: Alpha", { exact: true })).toBeVisible()
|
|
})
|
|
|
|
story("ends the native picker and highlight when the pane unmounts", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const picker = root.getByRole("button", { name: "Select an element to comment on", exact: true })
|
|
await picker.click()
|
|
await expect(root.getByText("Picker: on", { exact: true })).toBeVisible()
|
|
await root.getByRole("button", { name: "Unmount pane", exact: true }).click()
|
|
await expect(root.locator("#browser-panel")).toHaveCount(0)
|
|
await expect(root.getByText("Picker: off", { exact: true })).toBeVisible()
|
|
|
|
await root.getByRole("button", { name: "Alpha", exact: true }).click()
|
|
await picker.click()
|
|
await root.getByRole("button", { name: "Pick element", exact: true }).click()
|
|
await expect(root.locator('[data-slot="browser-comment-editor"] textarea')).toBeFocused()
|
|
await root.getByRole("button", { name: "Unmount pane", exact: true }).click()
|
|
await expect(root.locator("#browser-panel")).toHaveCount(0)
|
|
await expect(root.getByText("Highlights: clear", { exact: true })).toBeVisible()
|
|
})
|
|
|
|
story("keeps a comment draft but drops its ref when the page navigates", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
await root.getByRole("button", { name: "Select an element to comment on", exact: true }).click()
|
|
await root.getByRole("button", { name: "Pick element", exact: true }).click()
|
|
const editor = root.locator('[data-slot="browser-comment-editor"] textarea')
|
|
await editor.fill("Still misaligned after the reload")
|
|
await root.getByRole("button", { name: "Load current page", exact: true }).click()
|
|
await expect(editor).toHaveValue("Still misaligned after the reload")
|
|
await editor.press("Enter")
|
|
await expect(root.getByTestId("fixture-comments")).toHaveText(
|
|
"button.primary (no ref): Still misaligned after the reload",
|
|
)
|
|
})
|
|
|
|
story("grows the compact comment upward without flipping and keeps its actions inside the page", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
await root.getByRole("combobox", { name: "Picked element scenario" }).selectOption("low")
|
|
await root.getByRole("button", { name: "Select an element to comment on", exact: true }).click()
|
|
await root.getByRole("button", { name: "Pick element", exact: true }).click()
|
|
const editor = root.locator('[data-slot="browser-comment-editor"]')
|
|
const field = editor.locator("textarea")
|
|
await expect(editor).toHaveCSS("width", "320px")
|
|
await expect(field).toBeFocused()
|
|
await page.evaluate(() => document.fonts.ready.then(() => undefined))
|
|
const opening = await editor.boundingBox()
|
|
|
|
if (!opening) throw new Error("Missing opening annotation")
|
|
await field.fill("A line of feedback\n".repeat(6))
|
|
await expect(field).toHaveCSS("height", "140px")
|
|
// The field lays out before ResizeObserver repositions its parent.
|
|
await expect
|
|
.poll(async () => {
|
|
const grown = await editor.boundingBox()
|
|
|
|
return !!grown && grown.y < opening.y && Math.abs(grown.y + grown.height - opening.y - opening.height) < 0.5
|
|
})
|
|
.toBe(true)
|
|
await field.fill("A line of feedback\n".repeat(30))
|
|
await expect(field).toHaveCSS("height", "160px")
|
|
expect(await field.evaluate((element) => element.scrollHeight > element.clientHeight)).toBe(true)
|
|
await expect
|
|
.poll(async () => {
|
|
const surface = await root.locator('[data-component="browser-comment"]').boundingBox()
|
|
const box = await editor.boundingBox()
|
|
|
|
return !!surface && !!box && box.y >= surface.y && box.y + box.height <= surface.y + surface.height
|
|
})
|
|
.toBe(true)
|
|
const submit = editor.getByRole("button", { name: "Add element comment", exact: true })
|
|
await submit.scrollIntoViewIfNeeded()
|
|
await expect(submit).toBeInViewport()
|
|
// Near the surface's top, growth stops at the opening bottom rather than pushing the card down.
|
|
await field.press("Escape")
|
|
await root.getByRole("combobox", { name: "Picked element scenario" }).selectOption("default")
|
|
await root.getByRole("button", { name: "Select an element to comment on", exact: true }).click()
|
|
await root.getByRole("button", { name: "Pick element", exact: true }).click()
|
|
await expect(field).toBeFocused()
|
|
const nearTop = await editor.boundingBox()
|
|
|
|
if (!nearTop) throw new Error("Missing near-top annotation")
|
|
await field.fill("A line of feedback\n".repeat(30))
|
|
await expect
|
|
.poll(() => field.evaluate((element) => element.clientHeight < 160 && element.scrollHeight > element.clientHeight))
|
|
.toBe(true)
|
|
await expect
|
|
.poll(async () => {
|
|
const box = await editor.boundingBox()
|
|
|
|
return !!box && Math.abs(box.y + box.height - nearTop.y - nearTop.height) < 0.5
|
|
})
|
|
.toBe(true)
|
|
// A narrow, short pane still keeps the compact editor and action within its surface.
|
|
await root.locator("#browser-panel").evaluate((element) => {
|
|
const container = element.parentElement
|
|
|
|
if (!container) throw new Error("Missing pane container")
|
|
container.style.width = "280px"
|
|
container.style.height = "150px"
|
|
})
|
|
await expect(editor).toHaveCSS("width", "262px")
|
|
await expect
|
|
.poll(async () => {
|
|
const surface = await root.locator('[data-component="browser-comment"]').boundingBox()
|
|
const box = await editor.boundingBox()
|
|
|
|
return !!surface && !!box && box.y >= surface.y && box.y + box.height <= surface.y + surface.height
|
|
})
|
|
.toBe(true)
|
|
await expect(submit).toBeInViewport()
|
|
})
|
|
|
|
story(
|
|
"wraps the selector, attaches elements without comments, and cancels only empty drafts on clickaway",
|
|
async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const scenario = root.getByRole("combobox", { name: "Picked element scenario" })
|
|
const picker = root.getByRole("button", { name: "Select an element to comment on", exact: true })
|
|
const editor = root.locator('[data-slot="browser-comment-editor"]')
|
|
const overlay = root.locator('[data-component="browser-comment"]')
|
|
await scenario.selectOption("long")
|
|
await root.evaluate((element) => element.setAttribute("dir", "rtl"))
|
|
await picker.click()
|
|
await root.getByRole("button", { name: "Pick element", exact: true }).click()
|
|
const preview = editor.locator('[data-slot="line-comment-v2-preview"] [dir="ltr"]')
|
|
const selector = `main > section[data-label="إعدادات"] > ${".nested-selector".repeat(24)} > button.primary`
|
|
await expect(preview).toHaveText(selector)
|
|
await expect(preview).toHaveAttribute("dir", "ltr")
|
|
await expect(preview).toHaveCSS("unicode-bidi", "isolate")
|
|
await expect(preview).toHaveCSS("-webkit-line-clamp", "2")
|
|
await expect(preview).toHaveCSS("height", "40px")
|
|
await preview.hover()
|
|
await expect(page.getByRole("tooltip")).toHaveText(selector)
|
|
await editor.locator("textarea").press("Enter")
|
|
await expect(overlay).toHaveCount(0)
|
|
const comments = root.getByTestId("fixture-comments").getByRole("listitem")
|
|
await expect(comments).toHaveText(["button.primary @e7:"])
|
|
|
|
await scenario.selectOption("default")
|
|
await picker.click()
|
|
await root.getByRole("button", { name: "Pick element", exact: true }).click()
|
|
await editor.getByRole("button", { name: "Add element", exact: true }).click()
|
|
await expect(overlay).toHaveCount(0)
|
|
await expect(comments).toHaveText(["button.primary @e7:", "button.primary @e7:"])
|
|
expect(JSON.parse(await root.getByTestId("fixture-comment-metadata").innerText())).toEqual(
|
|
[selector, "main > button.primary"].map((value) =>
|
|
expect.objectContaining({
|
|
type: "note",
|
|
label: "button.primary",
|
|
title: value,
|
|
subtitle: "Browser annotation",
|
|
comment: "",
|
|
subject: `the "button.primary" element in browser tab tab_11111111-1111-1111-1111-111111111111 at https://alpha.example/ (role button; accessible name "Save changes"; selector ${JSON.stringify(value)})`,
|
|
live: {
|
|
href: "tab_11111111-1111-1111-1111-111111111111#e7",
|
|
subject: `the "button.primary" element in browser tab tab_11111111-1111-1111-1111-111111111111 at https://alpha.example/ (role button; accessible name "Save changes"; selector ${JSON.stringify(value)}; browser ref @e7, usable as ref in any browser tool including browser.evaluate until the page navigates)`,
|
|
},
|
|
}),
|
|
),
|
|
)
|
|
|
|
await scenario.selectOption("fallback")
|
|
await picker.click()
|
|
await root.getByRole("button", { name: "Pick element", exact: true }).click()
|
|
await expect(preview).toHaveText("button.primary")
|
|
await editor.locator("textarea").fill("Keep this feedback")
|
|
await overlay.click({ position: { x: 620, y: 290 } })
|
|
await expect(editor.locator("textarea")).toHaveValue("Keep this feedback")
|
|
await editor.locator("textarea").fill("")
|
|
await overlay.click({ position: { x: 620, y: 290 } })
|
|
await expect(overlay).toHaveCount(0)
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
await expect(comments).toHaveText(["button.primary @e7:", "button.primary @e7:"])
|
|
},
|
|
)
|
|
|
|
story("shows the empty state over a blank native page and restores navigation", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
await root.getByRole("button", { name: "Blank page", exact: true }).click()
|
|
await expect(root.getByText("Open a page", { exact: true })).toBeVisible()
|
|
await expect(root.getByText("Preview your app, read docs, or browse the web.", { exact: true })).toBeVisible()
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "false")
|
|
await expect(root.getByRole("button", { name: "Reload", exact: true })).toBeDisabled()
|
|
|
|
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
|
|
await address.fill("https://example.com/")
|
|
await expect(root.getByText("Open a page", { exact: true })).toBeVisible()
|
|
await address.press("Enter")
|
|
await expect(address).not.toBeFocused()
|
|
await expect(root.getByText("Open a page", { exact: true })).toBeHidden()
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
await expect(root.getByRole("button", { name: "Reload", exact: true })).toBeEnabled()
|
|
})
|
|
|
|
story("keeps Stop available and hides the empty state while a blank page loads", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
await root.getByRole("button", { name: "Loading page", exact: true }).click()
|
|
await expect(root.getByText("Open a page", { exact: true })).toBeHidden()
|
|
await root.getByRole("button", { name: "Stop", exact: true }).click()
|
|
await expect(root.getByText("Open a page", { exact: true })).toBeVisible()
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "false")
|
|
})
|
|
|
|
story("keeps the submitted URL visible until the browser reports navigation", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
await root.getByRole("button", { name: "Blank page", exact: true }).click()
|
|
await root.getByRole("button", { name: "Delay navigation", exact: true }).click()
|
|
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
|
|
await address.fill("https://example.com/")
|
|
await address.press("Enter")
|
|
await expect(address).not.toBeFocused()
|
|
await expect(address).toHaveValue("https://example.com/")
|
|
await expect(root.getByText("Open a page", { exact: true })).toBeHidden()
|
|
|
|
// Focusing and leaving the field before the browser reports keeps the submitted address.
|
|
await address.focus()
|
|
await expect(address).toHaveValue("https://example.com/")
|
|
await address.press("Escape")
|
|
await expect(address).not.toBeFocused()
|
|
await expect(address).toHaveValue("https://example.com/")
|
|
await expect(root.getByText("Open a page", { exact: true })).toBeHidden()
|
|
|
|
await root.getByRole("button", { name: "Complete navigation", exact: true }).click()
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
await expect(address).toHaveValue("https://example.com/")
|
|
|
|
await address.fill("https://unsubmitted.example/")
|
|
await root.getByRole("button", { name: "Delay navigation", exact: true }).click()
|
|
await expect(address).toHaveValue("https://example.com/")
|
|
})
|
|
|
|
story("restores the current URL each time the same submitted navigation is blocked", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
await root.getByRole("button", { name: "Delay navigation", exact: true }).click()
|
|
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
|
|
|
|
for (const submission of [1, 2]) {
|
|
await story.step(`blocked submission ${submission}`, async () => {
|
|
await address.fill("https://blocked.example/")
|
|
await address.press("Enter")
|
|
await expect(address).toHaveValue("https://blocked.example/")
|
|
await root.getByRole("button", { name: "Block navigation", exact: true }).click()
|
|
await expect(root.getByRole("alert")).toHaveText("Only web pages can open here.")
|
|
await expect(address).toHaveValue("https://alpha.example/")
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
})
|
|
}
|
|
})
|
|
|
|
story("explains why a typed address cannot open instead of searching for it", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
|
|
|
|
for (const [typed, reason] of [
|
|
["ftp://example.com", "Only web pages can open here."],
|
|
["https://user:pass@example.com", "Addresses with a user name or password can't open here."],
|
|
]) {
|
|
await address.fill(typed)
|
|
await address.press("Enter")
|
|
await expect(root.getByRole("alert")).toHaveText(reason)
|
|
await expect(address).toHaveValue("https://alpha.example/")
|
|
}
|
|
})
|
|
|
|
story("shows a themed failure state for only the failed tab and allows retry", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
await root.getByRole("button", { name: "Failed page", exact: true }).click()
|
|
await expect(root.getByText("URL can't be reached", { exact: true })).toBeVisible()
|
|
await expect(root.getByText("Check the URL and your connection, then try again.", { exact: true })).toBeVisible()
|
|
await expect(root.getByText("Request failed", { exact: true })).toBeHidden()
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "false")
|
|
await expect(root.getByRole("combobox", { name: "Browser address", exact: true })).toHaveValue(
|
|
"https://alpha.example/",
|
|
)
|
|
|
|
await root.getByRole("button", { name: "Beta", exact: true }).click()
|
|
await expect(root.getByText("URL can't be reached", { exact: true })).toBeHidden()
|
|
await expect(root.getByTestId("native-Beta")).toHaveAttribute("data-visible", "true")
|
|
await root.getByRole("button", { name: "Alpha", exact: true }).click()
|
|
await expect(root.getByText("URL can't be reached", { exact: true })).toBeVisible()
|
|
|
|
await root.getByRole("button", { name: "Reload", exact: true }).click()
|
|
await expect(root.getByText("URL can't be reached", { exact: true })).toBeHidden()
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
})
|
|
|
|
story("returns a failed tab to the empty state when an empty URL is submitted", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
await root.getByRole("button", { name: "Failed page", exact: true }).click()
|
|
await expect(root.getByText("URL can't be reached", { exact: true })).toBeVisible()
|
|
await root.getByRole("button", { name: "Delay navigation", exact: true }).click()
|
|
|
|
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
|
|
await address.fill("")
|
|
await address.press("Enter")
|
|
await expect(address).not.toBeFocused()
|
|
await expect(address).toHaveValue("")
|
|
await root.getByRole("button", { name: "Load current page", exact: true }).click()
|
|
await expect(root.getByRole("button", { name: "Stop", exact: true })).toBeEnabled()
|
|
await root.getByRole("button", { name: "Complete navigation", exact: true }).click()
|
|
await expect(root.getByText("URL can't be reached", { exact: true })).toBeHidden()
|
|
await expect(root.getByText("Open a page", { exact: true })).toBeVisible()
|
|
await expect(root.getByRole("button", { name: "Reload", exact: true })).toBeDisabled()
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "false")
|
|
})
|
|
|
|
story("selects the full URL when the address field gains focus", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
|
|
await address.click()
|
|
await expect(address).toHaveJSProperty("selectionStart", 0)
|
|
await expect(address).toHaveJSProperty("selectionEnd", "https://alpha.example/".length)
|
|
await address.pressSequentially("https://example.com/")
|
|
await expect(address).toHaveValue("https://example.com/")
|
|
await address.press("Enter")
|
|
await expect(address).not.toBeFocused()
|
|
await address.focus()
|
|
await expect(address).toHaveJSProperty("selectionStart", 0)
|
|
await expect(address).toHaveJSProperty("selectionEnd", "https://example.com/".length)
|
|
// A click on the focused field places the caret instead of selecting the URL again.
|
|
await address.press("ArrowRight")
|
|
await address.click()
|
|
await expect
|
|
.poll(() => address.evaluate((input: HTMLInputElement) => input.selectionStart === input.selectionEnd))
|
|
.toBe(true)
|
|
})
|
|
|
|
story("draws only the address at rest when focus leaves the window with the field selected", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
|
|
await address.click()
|
|
// Chromium blurs the field when the window or the native page takes focus, and the field keeps its full selection.
|
|
await address.evaluate((input: HTMLInputElement) => {
|
|
input.dispatchEvent(new FocusEvent("blur"))
|
|
input.select()
|
|
})
|
|
await expect(address).toHaveJSProperty("selectionStart", 0)
|
|
await expect(address).toHaveJSProperty("selectionEnd", "https://alpha.example/".length)
|
|
await page.mouse.move(0, 0)
|
|
|
|
// Computed ::selection styles do not report the default highlight, so compare the input's own paint with the
|
|
// selection collapsed. The drawn address is hidden: a selection layer can change how its text is antialiased.
|
|
await page.addStyleTag({ content: '[data-slot="browser-address-display"] { visibility: hidden }' })
|
|
const field = root.locator('[data-component="browser-address"]')
|
|
const selected = (await field.screenshot()).toString("base64")
|
|
await address.evaluate((input: HTMLInputElement) => input.setSelectionRange(0, 0))
|
|
const collapsed = (await field.screenshot()).toString("base64")
|
|
|
|
const changed = await page.evaluate(
|
|
async (shots) => {
|
|
const pixels = await Promise.all(
|
|
shots.map(async (data) => {
|
|
const image = new Image()
|
|
image.src = `data:image/png;base64,${data}`
|
|
await image.decode()
|
|
const canvas = new OffscreenCanvas(image.width, image.height)
|
|
canvas.getContext("2d")?.drawImage(image, 0, 0)
|
|
|
|
return canvas.getContext("2d")?.getImageData(0, 0, image.width, image.height).data ?? new Uint8ClampedArray()
|
|
}),
|
|
)
|
|
|
|
return Array.from({ length: (pixels[0]?.length ?? 0) / 4 }, (_, index) => index * 4).filter((offset) =>
|
|
[0, 1, 2].some((channel) => pixels[0]?.[offset + channel] !== pixels[1]?.[offset + channel]),
|
|
).length
|
|
},
|
|
[selected, collapsed],
|
|
)
|
|
|
|
expect(changed).toBe(0)
|
|
})
|
|
|
|
story("keeps the current page visible while a submitted URL loads", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
await root.getByRole("button", { name: "Delay navigation", exact: true }).click()
|
|
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
|
|
await address.fill("https://example.com/")
|
|
await address.press("Enter")
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
await expect(address).toHaveValue("https://example.com/")
|
|
|
|
await root.getByRole("button", { name: "Load current page", exact: true }).click()
|
|
await expect(root.getByRole("button", { name: "Stop", exact: true })).toBeEnabled()
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
await root.getByRole("button", { name: "Complete navigation", exact: true }).click()
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
await expect(address).toHaveValue("https://example.com/")
|
|
})
|
|
|
|
story("keeps the current page and restores its URL when an empty address is submitted", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
|
|
await address.fill("")
|
|
await address.press("Enter")
|
|
await expect(address).not.toBeFocused()
|
|
await expect(address).toHaveValue("https://alpha.example/")
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
await expect(root.getByText("Open a page", { exact: true })).toBeHidden()
|
|
await expect(root.getByRole("button", { name: "Reload", exact: true })).toBeEnabled()
|
|
})
|
|
|
|
story("suggests visited pages and opens the first one that completes the typed address", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
await root.getByRole("button", { name: "Seed history", exact: true }).click()
|
|
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
|
|
await address.click()
|
|
await address.pressSequentially("localhost")
|
|
const options = page.getByRole("listbox", { name: "Suggestions" }).getByRole("option")
|
|
await expect(options).toHaveCount(1)
|
|
await expect(options.first()).toHaveAttribute("aria-selected", "true")
|
|
// Arrow keys that pick IME candidates leave the suggestions alone.
|
|
await address.dispatchEvent("keydown", { key: "ArrowDown", isComposing: true })
|
|
await expect(options.first()).toHaveAttribute("aria-selected", "true")
|
|
await address.press("Enter")
|
|
await expect(address).toHaveValue("http://localhost:5173/settings")
|
|
|
|
// A search query also opens the first match; stepping past the list leaves the typed text, which searches.
|
|
await address.click()
|
|
await address.pressSequentially("color format")
|
|
await expect(options).toHaveCount(1)
|
|
await expect(options.first()).toHaveAttribute("aria-selected", "true")
|
|
await address.press("ArrowDown")
|
|
await expect(options.first()).toHaveAttribute("aria-selected", "false")
|
|
await address.press("Enter")
|
|
await expect(address).toHaveValue("https://www.google.com/search?q=color%20format")
|
|
})
|
|
|
|
story("lists recent pages on a blank tab and opens one", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
|
|
await root.getByRole("button", { name: "Seed history", exact: true }).click()
|
|
await root.getByRole("button", { name: "Blank page", exact: true }).click()
|
|
await expect(root.getByText("Recent", { exact: true })).toBeVisible()
|
|
// The globe at the field's start belongs to the field: a click there focuses it.
|
|
await expect(address).not.toBeFocused()
|
|
await root.locator('[data-component="browser-address"]').click({ position: { x: 16, y: 14 } })
|
|
await expect(address).toBeFocused()
|
|
await address.blur()
|
|
|
|
await root.getByRole("button", { name: /^Settings - Preview/ }).click()
|
|
await expect(address).toHaveValue("http://localhost:5173/settings")
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
// The opened page owns the field afterwards: an edit that is never submitted shows its URL again.
|
|
await address.click()
|
|
await address.fill("unsubmitted")
|
|
await address.blur()
|
|
await expect(address).toHaveValue("http://localhost:5173/settings")
|
|
})
|
|
|
|
story("adds the whole page to the session and keeps the draft when the button is pressed again", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const field = root.locator('[data-component="browser-address"]')
|
|
const add = root.getByRole("button", { name: "Add page to session", exact: true })
|
|
await field.hover()
|
|
await add.click()
|
|
const editor = root.locator('[data-slot="browser-comment-editor"] textarea')
|
|
await editor.fill("Check the header layout")
|
|
await field.hover()
|
|
await add.click()
|
|
await expect(editor).toHaveValue("Check the header layout")
|
|
await editor.press("Enter")
|
|
await expect(root.getByTestId("fixture-comments").getByRole("listitem")).toHaveText([/: Check the header layout$/])
|
|
})
|
|
|
|
story("shows the page's cookies in the site information and clears them", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
await root.getByRole("button", { name: "Site information", exact: true }).click()
|
|
const site = page.getByRole("dialog")
|
|
await expect(site).toContainText("3 cookies in use")
|
|
await site.getByRole("button", { name: "Clear", exact: true }).click()
|
|
await expect(site).toContainText("0 cookies in use")
|
|
})
|
|
|
|
story("says a failed cookie read failed and reads again on retry", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
await root.getByRole("button", { name: "Fail next site read", exact: true }).click()
|
|
await root.getByRole("button", { name: "Site information", exact: true }).click()
|
|
const site = page.getByRole("dialog")
|
|
await expect(site).toContainText("Request failed")
|
|
const retry = site.getByRole("button", { name: "Try again", exact: true })
|
|
await expect(retry).toBeEnabled()
|
|
await retry.click()
|
|
await expect(site).toContainText("3 cookies in use")
|
|
await expect(site.getByRole("button", { name: "Clear", exact: true })).toBeEnabled()
|
|
})
|
|
|
|
story("zooms the page from the browser options in view and keeps its zoom in the address field", async ({ page }) => {
|
|
const root = page.getByTestId("browser-pane-fixture")
|
|
const options = root.getByRole("button", { name: "Browser options", exact: true })
|
|
await options.click()
|
|
await page.getByRole("menuitem", { name: /^Zoom in/ }).click()
|
|
await expect(root.getByText("Zoom: 110", { exact: true })).toBeVisible()
|
|
// The menu covered the page with a still; it closes so the zoomed page shows at once.
|
|
await expect(page.getByRole("menu")).toBeHidden()
|
|
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
|
|
|
|
const zoom = root.getByRole("button", { name: "110%", exact: true })
|
|
await expect(zoom).toBeVisible()
|
|
await zoom.click()
|
|
await expect(root.getByText("Zoom: 100", { exact: true })).toBeVisible()
|
|
await expect(zoom).toBeHidden()
|
|
})
|