|
import { readFileSync } from "node:fs"; |
|
import { fileURLToPath } from "node:url"; |
|
|
|
import { expect, type Route, test } from "@playwright/test"; |
|
|
|
const userscript = readFileSync( |
|
fileURLToPath( |
|
new URL("./github-pr-review-shortcuts.user.js", import.meta.url), |
|
), |
|
"utf8", |
|
); |
|
|
|
/** Returns representative signed-in GitHub changed-file markup for shortcut tests. */ |
|
function githubFilesMarkup(): string { |
|
return ` |
|
<style> |
|
body { margin: 0; } |
|
.sticky-toolbar { background: white; height: 60px; left: 0; position: fixed; right: 0; top: 0; z-index: 10; } |
|
.page-intro { height: 120px; } |
|
.diff-viewport { margin-left: 16px; overflow: hidden; } |
|
.js-file { height: 700px; margin-bottom: 24px; } |
|
.file-header { height: 48px; } |
|
</style> |
|
<div class="sticky-toolbar"></div> |
|
<input aria-label="Unrelated page input" /> |
|
<div class="page-intro"></div> |
|
<div class="diff-viewport"> |
|
<div id="file-1" class="file js-file" data-details-container-group="file"> |
|
<div class="file-header" data-path="src/first.rs"> |
|
<input class="js-reviewed-toggle" type="checkbox" aria-label="Viewed" /> |
|
</div> |
|
</div> |
|
<div id="file-2" class="file js-file" data-details-container-group="file"> |
|
<div class="file-header" data-path="src/second.rs"> |
|
<label class="js-reviewed-toggle"> |
|
<input type="checkbox" /> Viewed |
|
</label> |
|
</div> |
|
</div> |
|
<div id="file-3" class="file js-file" data-details-container-group="file"> |
|
<div class="file-header" data-path="src/third.rs"> |
|
<input class="js-reviewed-checkbox" type="checkbox" /> |
|
</div> |
|
</div> |
|
</div> |
|
`; |
|
} |
|
|
|
/** Returns GitHub's virtualized large-PR changed-file markup. */ |
|
function githubVirtualizedFilesMarkup(): string { |
|
return ` |
|
<style> |
|
body { margin: 0; } |
|
.page-intro { height: 120px; } |
|
[role="region"] { height: 700px; margin-bottom: 24px; } |
|
</style> |
|
<div class="page-intro"></div> |
|
<div id="diff-first" role="region" aria-labelledby="heading-first" data-estimated-height="700"> |
|
<div data-diff-header-wrapper="true"> |
|
<h3 id="heading-first">src/first.rs</h3> |
|
<button type="button" aria-pressed="false" aria-label="Not Viewed" onclick="this.setAttribute('aria-pressed', 'true'); this.setAttribute('aria-label', 'Viewed')">Viewed</button> |
|
</div> |
|
</div> |
|
<div id="diff-second" role="region" aria-labelledby="heading-second" data-estimated-height="700"> |
|
<div data-diff-header-wrapper="true"> |
|
<h3 id="heading-second">src/second.rs</h3> |
|
<button type="button" aria-pressed="true" aria-label="Viewed" onclick="this.setAttribute('aria-pressed', 'false'); this.setAttribute('aria-label', 'Not Viewed')">Viewed</button> |
|
</div> |
|
</div> |
|
<div id="diff-third" role="region" aria-labelledby="heading-third" data-estimated-height="700"> |
|
<div data-diff-header-wrapper="true"> |
|
<h3 id="heading-third">src/third.rs</h3> |
|
<button type="button" aria-pressed="false" aria-label="Not Viewed" onclick="this.setAttribute('aria-pressed', 'true'); this.setAttribute('aria-label', 'Viewed')">Viewed</button> |
|
</div> |
|
</div> |
|
`; |
|
} |
|
|
|
/** Returns a virtualized diff whose first file spans multiple viewport segments. */ |
|
function githubTallFileMarkup(): string { |
|
return ` |
|
<style> |
|
body { margin: 0; } |
|
.page-intro { height: 120px; } |
|
[role="region"] { margin-bottom: 24px; } |
|
#diff-tall { height: 1727px; } |
|
#diff-next { height: 700px; } |
|
</style> |
|
<div class="page-intro"></div> |
|
<div id="diff-tall" role="region" aria-labelledby="heading-tall"> |
|
<h3 id="heading-tall">.vscode/launch.json</h3> |
|
<button type="button" aria-pressed="false" aria-label="Not Viewed" onclick="this.setAttribute('aria-pressed', 'true'); this.setAttribute('aria-label', 'Viewed')">Viewed</button> |
|
</div> |
|
<div id="diff-next" role="region" aria-labelledby="heading-next"> |
|
<h3 id="heading-next">src/next.rs</h3> |
|
<button type="button" aria-pressed="false" aria-label="Not Viewed" onclick="this.setAttribute('aria-pressed', 'true'); this.setAttribute('aria-label', 'Viewed')">Viewed</button> |
|
</div> |
|
`; |
|
} |
|
|
|
/** Returns a virtual list that mounts its next file only after scrolling. */ |
|
function githubDeferredVirtualFileMarkup(): string { |
|
return ` |
|
<style> |
|
body { margin: 0; } |
|
.page-intro { height: 120px; } |
|
#virtual-list { height: 4000px; position: relative; } |
|
.virtual-row { left: 0; position: absolute; right: 0; } |
|
[role="region"] { height: 700px; } |
|
</style> |
|
<div class="page-intro"></div> |
|
<div id="virtual-list"> |
|
<div class="virtual-row" data-index="0" data-path-digest="tall" style="top: 0"> |
|
<div id="diff-tall" role="region" aria-labelledby="heading-tall"> |
|
<h3 id="heading-tall">.vscode/launch.json</h3> |
|
<button type="button" aria-pressed="false" aria-label="Not Viewed">Viewed</button> |
|
</div> |
|
</div> |
|
</div> |
|
<template id="next-file-template"> |
|
<div class="virtual-row" data-index="1" data-path-digest="next" style="top: 724px"> |
|
<div id="diff-next" role="region" aria-labelledby="heading-next"> |
|
<h3 id="heading-next">.vscode/settings.json</h3> |
|
<button type="button" aria-pressed="false" aria-label="Not Viewed">Viewed</button> |
|
</div> |
|
</div> |
|
</template> |
|
<script> |
|
/** Mounts the next simulated virtual row after navigation enters unloaded space. */ |
|
function mountNextVirtualFile() { |
|
const template = document.querySelector("#next-file-template"); |
|
if (window.scrollY < 500 || !template) return; |
|
document.querySelector("#virtual-list").append(template.content.cloneNode(true)); |
|
template.remove(); |
|
} |
|
window.addEventListener("scroll", mountNextVirtualFile, { passive: true }); |
|
</script> |
|
`; |
|
} |
|
|
|
/** Returns GitHub's progressive diff markup before the next header is hydrated. */ |
|
function githubProgressiveDiffMarkup(): string { |
|
return ` |
|
<style> |
|
body { margin: 0; } |
|
.page-intro { height: 120px; } |
|
[role="region"] { height: 700px; margin-bottom: 24px; } |
|
</style> |
|
<div class="page-intro"></div> |
|
<div id="diff-current" role="region" aria-labelledby="heading-current"> |
|
<h3 id="heading-current">scripts/report-browser-demo-size.mjs</h3> |
|
<button type="button" aria-pressed="false" aria-label="Not Viewed" onclick="this.setAttribute('aria-pressed', 'true'); this.setAttribute('aria-label', 'Viewed'); hydrateNextDiff()">Viewed</button> |
|
</div> |
|
<div id="diff-next" role="region"> |
|
<div id="diff-next" role="region" aria-label="Loading scripts/run-playwright-vite.mjs"></div> |
|
</div> |
|
<div id="diff-third" role="region" aria-labelledby="heading-third"> |
|
<h3 id="heading-third">scripts/run-playwright.mjs</h3> |
|
</div> |
|
<script> |
|
/** Simulates GitHub hydrating a progressive diff after its preceding file is viewed. */ |
|
function hydrateNextDiff() { |
|
requestAnimationFrame(() => { |
|
const nextDiff = document.querySelector("#diff-next"); |
|
nextDiff.setAttribute("aria-labelledby", "heading-next"); |
|
nextDiff.removeAttribute("aria-label"); |
|
nextDiff.innerHTML = '<h3 id="heading-next">scripts/run-playwright-vite.mjs</h3>'; |
|
}); |
|
} |
|
</script> |
|
`; |
|
} |
|
|
|
/** Returns a file whose generated diff is deferred behind GitHub's load control. */ |
|
function githubDeferredLargeDiffMarkup(): string { |
|
return ` |
|
<style> |
|
body { margin: 0; } |
|
.page-intro { height: 120px; } |
|
[role="region"] { height: 700px; } |
|
</style> |
|
<div class="page-intro"></div> |
|
<div id="diff-generated" role="region" aria-labelledby="heading-generated"> |
|
<h3 id="heading-generated">Cargo.lock</h3> |
|
<button type="button" aria-pressed="false" aria-label="Not Viewed">Viewed</button> |
|
<button type="button" data-loading="false" onclick="loadDeferredDiff(this)">Load Diff</button> |
|
</div> |
|
<script> |
|
/** Simulates GitHub replacing a diff region after its loading spinner appears. */ |
|
function loadDeferredDiff(button) { |
|
button.dataset.loading = "true"; |
|
button.textContent = "Loading"; |
|
requestAnimationFrame(() => { |
|
const currentDiff = document.querySelector("#diff-generated"); |
|
const loadedDiff = document.createElement("div"); |
|
loadedDiff.id = "diff-generated"; |
|
loadedDiff.setAttribute("role", "region"); |
|
loadedDiff.setAttribute("aria-labelledby", "heading-generated-loaded"); |
|
loadedDiff.innerHTML = '<h3 id="heading-generated-loaded">Cargo.lock</h3><div data-loaded="true">Loaded</div>'; |
|
currentDiff.replaceWith(loadedDiff); |
|
}); |
|
} |
|
</script> |
|
`; |
|
} |
|
|
|
/** Loads a PR files route with a controlled GitHub diff fixture and the userscript. */ |
|
async function loadUserscriptFixture( |
|
page: import("@playwright/test").Page, |
|
markup = githubFilesMarkup(), |
|
beforeUserscript = "", |
|
) { |
|
/** Serves the controlled diff fixture without contacting GitHub. */ |
|
async function fulfillGitHubRoute(route: Route) { |
|
await route.fulfill({ |
|
body: markup, |
|
contentType: "text/html", |
|
}); |
|
} |
|
|
|
const fixtureUrl = "https://github.com/owner/repository/pull/123/files"; |
|
await page.route(fixtureUrl, fulfillGitHubRoute); |
|
await page.goto(fixtureUrl); |
|
if (beforeUserscript) await page.addScriptTag({ content: beforeUserscript }); |
|
await page.addScriptTag({ content: userscript }); |
|
} |
|
|
|
/** Returns the changed file currently highlighted by the userscript. */ |
|
function activeFile(page: import("@playwright/test").Page) { |
|
return page.locator('[data-github-pr-shortcuts-active="true"]'); |
|
} |
|
|
|
/** Verifies j and k move through rendered changed-file segments without wrapping. */ |
|
test("navigates forward and backward between changed files", async ({ |
|
page, |
|
}) => { |
|
await loadUserscriptFixture(page); |
|
await expect(activeFile(page)).toHaveCount(0); |
|
|
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("file-1"); |
|
|
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("file-2"); |
|
|
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("file-3"); |
|
|
|
await page.keyboard.press("k"); |
|
await expect(activeFile(page)).toHaveId("file-2"); |
|
|
|
await page.keyboard.press("k"); |
|
await expect(activeFile(page)).toHaveId("file-1"); |
|
|
|
await page.keyboard.press("k"); |
|
await expect(activeFile(page)).toHaveId("file-1"); |
|
}); |
|
|
|
/** Verifies ordinary navigation includes files already marked viewed. */ |
|
test("navigates through viewed files after startup", async ({ page }) => { |
|
const markup = githubFilesMarkup().replace( |
|
'<input type="checkbox" /> Viewed', |
|
'<input type="checkbox" checked /> Viewed', |
|
); |
|
await loadUserscriptFixture(page, markup); |
|
|
|
await expect(activeFile(page)).toHaveCount(0); |
|
expect(await page.evaluate<number>("window.scrollY")).toBe(0); |
|
|
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("file-1"); |
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("file-2"); |
|
await expect |
|
.poll(() => |
|
activeFile(page).evaluate((file) => file.getBoundingClientRect().top), |
|
) |
|
.toBe(68); |
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("file-3"); |
|
}); |
|
|
|
/** Verifies collapsed viewed files remain visible below GitHub's sticky toolbar. */ |
|
test("keeps a selected collapsed file below the sticky toolbar", async ({ |
|
page, |
|
}) => { |
|
const markup = `${githubFilesMarkup().replace( |
|
".js-file { height: 700px;", |
|
".js-file { height: 42px;", |
|
)}<div style="height: 1000px"></div>`; |
|
await loadUserscriptFixture(page, markup); |
|
|
|
await page.locator("#file-1").click({ position: { x: 100, y: 20 } }); |
|
await page.keyboard.press("j"); |
|
|
|
await expect(activeFile(page)).toHaveId("file-2"); |
|
await expect |
|
.poll(() => |
|
activeFile(page).evaluate((file) => file.getBoundingClientRect().top), |
|
) |
|
.toBe(68); |
|
}); |
|
|
|
/** Verifies installing the userscript leaves initial selection and scrolling untouched. */ |
|
test("does not select or scroll to a file on startup", async ({ page }) => { |
|
await loadUserscriptFixture(page); |
|
|
|
await expect(activeFile(page)).toHaveCount(0); |
|
expect(await page.evaluate<number>("window.scrollY")).toBe(0); |
|
}); |
|
|
|
/** Verifies v marks an unviewed file and advances to the following changed file. */ |
|
test("marks the current file viewed and advances", async ({ page }) => { |
|
await loadUserscriptFixture(page); |
|
|
|
await page.keyboard.press("v"); |
|
|
|
await expect(page.locator("#file-1 .js-reviewed-toggle")).toBeChecked(); |
|
await expect(activeFile(page)).toHaveId("file-2"); |
|
}); |
|
|
|
/** Verifies v unmarks a viewed file and still advances to the next file. */ |
|
test("unmarks an already viewed file and advances", async ({ page }) => { |
|
await loadUserscriptFixture(page); |
|
await page.locator("#file-1 .js-reviewed-toggle").check(); |
|
|
|
await page.keyboard.press("v"); |
|
|
|
await expect(page.locator("#file-1 .js-reviewed-toggle")).not.toBeChecked(); |
|
await expect(activeFile(page)).toHaveId("file-2"); |
|
}); |
|
|
|
/** Verifies nested and legacy GitHub viewed controls remain usable. */ |
|
test("supports nested and legacy viewed controls", async ({ page }) => { |
|
await loadUserscriptFixture(page); |
|
|
|
await page.keyboard.press("j"); |
|
await page.keyboard.press("j"); |
|
await page.keyboard.press("v"); |
|
await expect(page.locator("#file-2 input[type='checkbox']")).toBeChecked(); |
|
await expect(activeFile(page)).toHaveId("file-3"); |
|
|
|
await page.keyboard.press("v"); |
|
await expect(page.locator("#file-3 .js-reviewed-checkbox")).toBeChecked(); |
|
await expect(activeFile(page)).toHaveId("file-3"); |
|
}); |
|
|
|
/** Verifies GitHub's virtualized large-PR regions and pressed buttons work. */ |
|
test("supports the virtualized large pull request viewer", async ({ page }) => { |
|
await loadUserscriptFixture(page, githubVirtualizedFilesMarkup()); |
|
await expect(activeFile(page)).toHaveCount(0); |
|
|
|
await page.keyboard.press("v"); |
|
await expect(page.locator("#diff-first button")).toHaveAttribute( |
|
"aria-pressed", |
|
"true", |
|
); |
|
await expect(page.locator("#diff-second button")).toHaveAttribute( |
|
"aria-pressed", |
|
"true", |
|
); |
|
await expect(activeFile(page)).toHaveId("diff-second"); |
|
|
|
await page.keyboard.press("v"); |
|
await expect(page.locator("#diff-second button")).toHaveAttribute( |
|
"aria-pressed", |
|
"false", |
|
); |
|
await expect(activeFile(page)).toHaveId("diff-third"); |
|
}); |
|
|
|
/** Verifies j and k traverse viewport-sized segments before changing files. */ |
|
test("navigates within a changed file taller than the viewport", async ({ |
|
page, |
|
}) => { |
|
await loadUserscriptFixture(page, githubTallFileMarkup()); |
|
await expect(activeFile(page)).toHaveCount(0); |
|
|
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("diff-tall"); |
|
const fileTop = await page.evaluate<number>("window.scrollY"); |
|
|
|
await page.keyboard.press("j"); |
|
const nextSegment = await page.evaluate<number>("window.scrollY"); |
|
expect(nextSegment).toBeGreaterThan(fileTop + 500); |
|
await expect(activeFile(page)).toHaveId("diff-tall"); |
|
|
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("diff-next"); |
|
|
|
await page.keyboard.press("k"); |
|
await expect(activeFile(page)).toHaveId("diff-tall"); |
|
const previousSegment = await page.evaluate<number>("window.scrollY"); |
|
expect(previousSegment).toBeGreaterThan(fileTop + 500); |
|
|
|
await page.keyboard.press("k"); |
|
expect(await page.evaluate<number>("window.scrollY")).toBeLessThan( |
|
previousSegment - 500, |
|
); |
|
await expect(activeFile(page)).toHaveId("diff-tall"); |
|
}); |
|
|
|
/** Verifies v skips remaining viewport segments and advances to the next file. */ |
|
test("marking a tall file viewed advances to the next diff block", async ({ |
|
page, |
|
}) => { |
|
await loadUserscriptFixture(page, githubTallFileMarkup()); |
|
|
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("diff-tall"); |
|
await page.keyboard.press("v"); |
|
|
|
await expect(page.locator("#diff-tall button")).toHaveAttribute( |
|
"aria-pressed", |
|
"true", |
|
); |
|
await expect(activeFile(page)).toHaveId("diff-next"); |
|
}); |
|
|
|
/** Verifies navigation wakes GitHub's virtualizer when no next file is mounted. */ |
|
test("reveals an unmounted next file in the virtualized viewer", async ({ |
|
page, |
|
}) => { |
|
await loadUserscriptFixture(page, githubDeferredVirtualFileMarkup()); |
|
await expect(activeFile(page)).toHaveCount(0); |
|
|
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("diff-tall"); |
|
await expect(page.locator("#diff-next")).toHaveCount(0); |
|
|
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("diff-next"); |
|
expect(await page.evaluate<number>("window.scrollY")).toBeGreaterThan(500); |
|
}); |
|
|
|
/** Verifies v can select GitHub's next progressive diff before it is hydrated. */ |
|
test("keeps the next progressive diff highlighted while it loads", async ({ |
|
page, |
|
}) => { |
|
await loadUserscriptFixture(page, githubProgressiveDiffMarkup()); |
|
|
|
await page.keyboard.press("v"); |
|
|
|
await expect(page.locator("#diff-current button")).toHaveAttribute( |
|
"aria-pressed", |
|
"true", |
|
); |
|
await expect(activeFile(page)).toHaveId("diff-next"); |
|
await expect(page.locator("#diff-next")).toHaveAttribute( |
|
"aria-labelledby", |
|
"heading-next", |
|
); |
|
await expect(activeFile(page)).toHaveId("diff-next"); |
|
}); |
|
|
|
/** Verifies nested loading regions are not mistaken for additional changed files. */ |
|
test("skips nested progressive diff placeholders during navigation", async ({ |
|
page, |
|
}) => { |
|
await loadUserscriptFixture(page, githubProgressiveDiffMarkup()); |
|
|
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("diff-current"); |
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("diff-next"); |
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("diff-third"); |
|
}); |
|
|
|
/** Verifies l activates GitHub's deferred generated-file diff control. */ |
|
test("loads the active file's deferred large diff", async ({ page }) => { |
|
await loadUserscriptFixture(page, githubDeferredLargeDiffMarkup()); |
|
await expect(activeFile(page)).toHaveCount(0); |
|
|
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("diff-generated"); |
|
await page.keyboard.press("l"); |
|
|
|
await expect(page.locator("#diff-generated [data-loaded='true']")).toHaveText( |
|
"Loaded", |
|
); |
|
await expect(activeFile(page)).toHaveId("diff-generated"); |
|
}); |
|
|
|
/** Verifies GitHub cannot pre-empt the userscript by default-preventing letter keys. */ |
|
test("captures shortcuts before GitHub's key handler", async ({ page }) => { |
|
await loadUserscriptFixture( |
|
page, |
|
githubFilesMarkup(), |
|
'/** Simulates GitHub claiming a keyboard event first. */ function preventShortcut(event) { event.preventDefault(); } window.addEventListener("keydown", preventShortcut, { capture: true });', |
|
); |
|
|
|
await expect(activeFile(page)).toHaveCount(0); |
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveId("file-1"); |
|
}); |
|
|
|
/** Verifies the page advertises the injected userscript version for diagnosis. */ |
|
test("marks the document when the userscript is running", async ({ page }) => { |
|
await loadUserscriptFixture(page); |
|
|
|
await expect(page.locator("html")).toHaveAttribute( |
|
"data-github-pr-review-shortcuts", |
|
"1.0.13", |
|
); |
|
await expect(activeFile(page)).toHaveCount(0); |
|
}); |
|
|
|
/** Verifies letter shortcuts remain available while typing or using modifiers. */ |
|
test("ignores editable targets and modified shortcuts", async ({ page }) => { |
|
await loadUserscriptFixture(page); |
|
|
|
await page.getByRole("textbox", { name: "Unrelated page input" }).focus(); |
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveCount(0); |
|
|
|
await page.getByRole("textbox", { name: "Unrelated page input" }).blur(); |
|
await page.keyboard.press("Control+j"); |
|
await expect(activeFile(page)).toHaveCount(0); |
|
}); |
|
|
|
/** Verifies pressing a changed-file body selects it without requiring a shortcut. */ |
|
test("selects a changed file by clicking its body", async ({ page }) => { |
|
await loadUserscriptFixture(page); |
|
|
|
await page.locator("#file-2").click({ position: { x: 100, y: 100 } }); |
|
await expect(activeFile(page)).toHaveId("file-2"); |
|
}); |
|
|
|
/** Verifies the current file has a visible red marker in its left gutter. */ |
|
test("visually marks the active changed file gutter", async ({ |
|
page, |
|
}, testInfo) => { |
|
await loadUserscriptFixture(page); |
|
|
|
await page.keyboard.press("j"); |
|
await expect(activeFile(page)).toHaveCSS("position", "relative"); |
|
await expect |
|
.poll(() => |
|
activeFile(page).evaluate( |
|
(file) => getComputedStyle(file, "::before").backgroundColor, |
|
), |
|
) |
|
.toBe("rgb(248, 81, 73)"); |
|
await expect |
|
.poll(() => |
|
activeFile(page).evaluate( |
|
(file) => getComputedStyle(file, "::before").width, |
|
), |
|
) |
|
.toBe("4px"); |
|
await expect |
|
.poll(() => |
|
activeFile(page).evaluate( |
|
(file) => getComputedStyle(file, "::before").zIndex, |
|
), |
|
) |
|
.toBe("2147483647"); |
|
await page.evaluate(() => { |
|
const opaqueGitHubSurface = document.createElement("div"); |
|
opaqueGitHubSurface.style.cssText = |
|
"position:absolute;inset:0;background:white;z-index:1"; |
|
document.querySelector("#file-1")?.append(opaqueGitHubSurface); |
|
}); |
|
await activeFile(page).screenshot({ |
|
path: testInfo.outputPath("github-pr-review-shortcuts-active-file.png"), |
|
}); |
|
}); |