Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions packages/session-ui/component-tests/file-viewer.fixture.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { render } from "solid-js/web"
import { createSignal } from "solid-js"
import type { SelectedLineRange } from "@pierre/diffs"
import { File } from "../src/components/file"
import { normalize } from "../src/components/session-diff"

const source = (lines: number, revision = 0) =>
Array.from(
{ length: lines },
(_, index) => `const value${index} = ${index % 10 === 0 ? index + revision : index}\n`,
).join("")

const [overflow, setOverflow] = createSignal<"wrap" | "scroll">("wrap")

const [contents, setContents] = createSignal("")

const [selected, setSelected] = createSignal<SelectedLineRange | null>(null)

const [commented, setCommented] = createSignal<SelectedLineRange[]>([])

let first: Element | null = null

export const controls = {
setOverflow,
setSelected,
setCommented,
append: (line: string) => setContents((value) => value + line),
// Keep the first Pierre host so a later check can tell an in-place update from a rebuild.
keepHost: () => (first = document.querySelector("[data-testid='file-viewer-fixture'] diffs-container")),
sameHost: () =>
first !== null && first === document.querySelector("[data-testid='file-viewer-fixture'] diffs-container"),
}

function host() {
const element = document.createElement("div")
element.dataset.testid = "file-viewer-fixture"
element.style.cssText =
"position: fixed; inset: 0 auto auto 0; z-index: 1; width: 800px; height: 400px; overflow: auto"
document.body.appendChild(element)

return element
}

export function mountTextViewer(lines: number) {
setContents(source(lines))
render(
() => (
<File
mode="text"
file={{ name: "a.ts", contents: contents() }}
overflow={overflow()}
enableLineSelection
selectedLines={selected()}
commentedLines={commented()}
/>
),
host(),
)
}

export function mountDiffViewer(lines: number) {
const view = normalize({ file: "a.ts", before: source(lines), after: source(lines, 1), additions: 0, deletions: 0 })
render(
() => (
<File
mode="diff"
fileDiff={view.fileDiff}
diffStyle="unified"
expandUnchanged
enableLineSelection
selectedLines={selected()}
/>
),
host(),
)
}
52 changes: 52 additions & 0 deletions packages/session-ui/component-tests/file-viewer.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { expect, sourceURL, story } from "../../storybook/playwright/story"

const fixture = sourceURL(new URL("./file-viewer.fixture.tsx", import.meta.url))

story("updates a text file in place when its props change", async ({ mount, page }) => {
await mount("components-markdown--compact-result")
await page.evaluate(async (fixture) => (await import(fixture)).mountTextViewer(40), fixture)
const root = page.getByTestId("file-viewer-fixture")
await expect(root.locator('[data-line="40"]')).toHaveCount(1)
await page.evaluate(async (fixture) => (await import(fixture)).controls.keepHost(), fixture)

await page.evaluate(async (fixture) => (await import(fixture)).controls.setOverflow("scroll"), fixture)
await expect(root.locator('pre[data-overflow="scroll"]')).toHaveCount(1)
await page.evaluate(async (fixture) => (await import(fixture)).controls.append("const appended = true\n"), fixture)
await expect(root.locator('[data-line="41"]')).toContainText("appended")

expect(await page.evaluate(async (fixture) => (await import(fixture)).controls.sameHost(), fixture)).toBe(true)
})

story("windows a medium text file and keeps selection and comment marks", async ({ mount, page }) => {
await mount("components-markdown--compact-result")
await page.evaluate(async (fixture) => (await import(fixture)).mountTextViewer(480), fixture)
const root = page.getByTestId("file-viewer-fixture")
await expect(root.locator('[data-line="1"]')).toBeInViewport()
expect(await root.locator("[data-line]").count()).toBeLessThan(200)

await page.evaluate(async (fixture) => {
const { controls } = await import(fixture)
controls.setSelected({ start: 3, end: 5 })
controls.setCommented([{ start: 8, end: 8 }])
}, fixture)
await expect(root.locator("[data-line][data-selected-line]")).toHaveCount(3)
await expect(root.locator('[data-line="8"][data-comment-selected]')).toHaveCount(1)

// File links jump by setting the scroll offset from the line number; the window must follow it.
await root.evaluate((element) => (element.scrollTop = (400 - 4) * 24))
await expect(root.locator('[data-line="400"]')).toBeInViewport()
})

story("scrolls a virtualized diff to an off-screen selection", async ({ mount, page }) => {
await mount("components-markdown--compact-result")
await page.evaluate(async (fixture) => (await import(fixture)).mountDiffViewer(480), fixture)
const root = page.getByTestId("file-viewer-fixture")
await expect(root.locator('[data-line="1"]').first()).toBeVisible()
await expect(root.locator('[data-line="400"]')).toHaveCount(0)

await page.evaluate(
async (fixture) => (await import(fixture)).controls.setSelected({ start: 400, end: 400, side: "additions" }),
fixture,
)
await expect(root.locator('[data-line="400"][data-selected-line]').first()).toBeInViewport()
})
Loading
Loading