mirror of
https://github.com/block/buzz.git
synced 2026-11-06 01:11:33 +00:00
desktop: add projects v3 PR screenshot spec
Adds a mock-mode spec that captures the workspace overview, issues tab, issue detail, and PR detail states for PR screenshots. Mock event ids are now full 64-hex so share-link copy buttons render in mock mode, and post-screenshots.sh no longer needs bash 4 (mapfile/declare -A) so it runs on stock macOS bash 3.2. Signed-off-by: Thomas Petersen <thomasp@squareup.com>
This commit is contained in:
@@ -108,6 +108,7 @@ export default defineConfig({
|
||||
"**/send-channel-binding.spec.ts",
|
||||
"**/project-commit-detail.spec.ts",
|
||||
"**/project-inbox.spec.ts",
|
||||
"**/projects-v3-screenshots.spec.ts",
|
||||
"**/project-issue-comments.spec.ts",
|
||||
"**/project-pr-review.spec.ts",
|
||||
"**/persona-model-combobox-screenshots.spec.ts",
|
||||
|
||||
@@ -5571,7 +5571,9 @@ function createMockEvent(
|
||||
tags: string[][],
|
||||
pubkey = DEFAULT_MOCK_IDENTITY.pubkey,
|
||||
createdAt = Math.floor(Date.now() / 1000),
|
||||
id = crypto.randomUUID().replace(/-/g, ""),
|
||||
// 64 hex chars like a real event id — share-link builders reject shorter
|
||||
// ids, so copy-link buttons only render with full-length ids.
|
||||
id = (crypto.randomUUID() + crypto.randomUUID()).replace(/-/g, ""),
|
||||
): RelayEvent {
|
||||
return {
|
||||
id,
|
||||
|
||||
77
desktop/tests/e2e/projects-v3-screenshots.spec.ts
Normal file
77
desktop/tests/e2e/projects-v3-screenshots.spec.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
|
||||
import { waitForAnimations } from "../helpers/animations";
|
||||
import { installMockBridge } from "../helpers/bridge";
|
||||
|
||||
const SHOTS = "test-results/projects-v3-screenshots";
|
||||
|
||||
async function openBuzzProject(page: import("@playwright/test").Page) {
|
||||
await page.goto("/", { waitUntil: "domcontentloaded" });
|
||||
await page.getByTestId("open-projects-view").click();
|
||||
await page.getByTestId("projects-section-projects").click();
|
||||
const projectEntry = page
|
||||
.locator(
|
||||
'[data-testid="project-card-buzz"], [data-testid="project-row-buzz"]',
|
||||
)
|
||||
.first();
|
||||
await expect(projectEntry).toBeVisible({ timeout: 10_000 });
|
||||
await projectEntry.click();
|
||||
}
|
||||
|
||||
// Walks the Projects v3 workspace through its headline states so PR
|
||||
// screenshots capture distinct pixels per feature (overview box, tab-strip
|
||||
// plus, issue detail with inline copy link + avatar timeline, PR detail).
|
||||
test("projects v3 workspace screenshot states", async ({ page }) => {
|
||||
await installMockBridge(page);
|
||||
await openBuzzProject(page);
|
||||
|
||||
// Single-box workspace: pickers + tab strip + readme overview.
|
||||
await expect(page.getByRole("tab", { name: "Files" })).toBeVisible();
|
||||
await waitForAnimations(page);
|
||||
await page.screenshot({ path: `${SHOTS}/01-workspace-overview.png` });
|
||||
|
||||
// Issues tab: the create action lives in the tab strip now.
|
||||
await page.getByRole("tab", { name: "Issues", exact: true }).click();
|
||||
await expect(page.getByRole("button", { name: "New issue" })).toBeVisible();
|
||||
const issueRow = page.getByTestId("project-issue-row").first();
|
||||
await expect(issueRow).toBeVisible({ timeout: 10_000 });
|
||||
await waitForAnimations(page);
|
||||
await page.screenshot({ path: `${SHOTS}/02-issues-tab.png` });
|
||||
|
||||
// Issue detail: inline copy link after the title, assignees rail, and the
|
||||
// avatar comment timeline (seed comments so the timeline renders).
|
||||
await issueRow.getByRole("button", { name: /^#/ }).click();
|
||||
const composer = page.getByTestId("project-issue-comment-composer");
|
||||
await expect(composer).toBeVisible();
|
||||
for (const comment of [
|
||||
"The palette needs the most work — starting there.",
|
||||
"Agreed. Typography pass can land separately.",
|
||||
]) {
|
||||
await composer.locator('[contenteditable="true"]').fill(comment);
|
||||
await composer.getByRole("button", { name: "Send message" }).click();
|
||||
await expect(page.getByText(comment, { exact: true })).toBeVisible({
|
||||
timeout: 10_000,
|
||||
});
|
||||
}
|
||||
await expect(page.getByTestId("project-issue-copy-link")).toBeVisible();
|
||||
await expect(
|
||||
page.getByTestId("project-issue-comment-timeline-row").first(),
|
||||
).toBeVisible();
|
||||
// Let the "Comment posted." toast dismiss so it doesn't photobomb.
|
||||
await expect(page.getByText("Comment posted.")).toHaveCount(0, {
|
||||
timeout: 10_000,
|
||||
});
|
||||
await waitForAnimations(page);
|
||||
await page.screenshot({ path: `${SHOTS}/03-issue-detail.png` });
|
||||
|
||||
// PR detail: inline copy link after the PR title.
|
||||
await page.getByRole("tab", { name: "Pull Request", exact: true }).click();
|
||||
const prRow = page.getByTestId("project-pull-request-row").first();
|
||||
await expect(prRow).toBeVisible({ timeout: 10_000 });
|
||||
await prRow.getByRole("button", { name: /^#/ }).click();
|
||||
await expect(
|
||||
page.getByTestId("project-pull-request-copy-link"),
|
||||
).toBeVisible();
|
||||
await waitForAnimations(page);
|
||||
await page.screenshot({ path: `${SHOTS}/04-pr-detail.png` });
|
||||
});
|
||||
@@ -19,7 +19,11 @@ GH_USER=$(gh api user --jq .login)
|
||||
BRANCH="agent-screenshots/${GH_USER}"
|
||||
REPO="block/buzz"
|
||||
|
||||
mapfile -t PNGS < <(find "$PNG_DIR" -maxdepth 1 -name "*.png" -type f | sort)
|
||||
# macOS ships bash 3.2, which lacks mapfile — build the array with read.
|
||||
PNGS=()
|
||||
while IFS= read -r PNG; do
|
||||
PNGS+=("$PNG")
|
||||
done < <(find "$PNG_DIR" -maxdepth 1 -name "*.png" -type f | sort)
|
||||
if [[ ${#PNGS[@]} -eq 0 ]]; then
|
||||
echo "error: no PNGs found in $PNG_DIR" >&2
|
||||
exit 1
|
||||
@@ -51,18 +55,18 @@ PARENT_ARGS=()
|
||||
if git rev-parse "origin/${BRANCH}" >/dev/null 2>&1; then
|
||||
PARENT_ARGS=(-p "origin/${BRANCH}")
|
||||
fi
|
||||
COMMIT=$(git commit-tree "$TREE" "${PARENT_ARGS[@]}" -m "screenshots: PR #${PR}")
|
||||
# ${arr[@]+...} guards the empty-array case, which trips set -u on bash 3.2.
|
||||
COMMIT=$(git commit-tree "$TREE" ${PARENT_ARGS[@]+"${PARENT_ARGS[@]}"} -m "screenshots: PR #${PR}")
|
||||
git push --force-with-lease origin "${COMMIT}:refs/heads/${BRANCH}"
|
||||
|
||||
RAW_BASE="https://raw.githubusercontent.com/${REPO}/${COMMIT}"
|
||||
|
||||
declare -A IMAGE_URL_MAP
|
||||
# Parallel name/url arrays instead of an associative array (bash 4+ only).
|
||||
IMAGE_NAMES=()
|
||||
IMAGE_URLS=()
|
||||
for i in "${!PNGS[@]}"; do
|
||||
ORIG_NAME="$(basename "${PNGS[$i]}" .png)"
|
||||
URL="${RAW_BASE}/${TREE_PATHS[$i]}"
|
||||
IMAGE_URLS+=("$URL")
|
||||
IMAGE_URL_MAP["$ORIG_NAME"]="$URL"
|
||||
IMAGE_NAMES+=("$(basename "${PNGS[$i]}" .png)")
|
||||
IMAGE_URLS+=("${RAW_BASE}/${TREE_PATHS[$i]}")
|
||||
done
|
||||
|
||||
if [[ -n "$BODY_FILE" ]]; then
|
||||
@@ -70,20 +74,20 @@ if [[ -n "$BODY_FILE" ]]; then
|
||||
"$SCRIPT_DIR/check-pr-image-urls.sh" "$BODY_FILE"
|
||||
COMMENT_BODY="$(cat "$BODY_FILE")"
|
||||
UNREFERENCED=()
|
||||
for NAME in "${!IMAGE_URL_MAP[@]}"; do
|
||||
URL="${IMAGE_URL_MAP[$NAME]}"
|
||||
for i in "${!IMAGE_NAMES[@]}"; do
|
||||
NAME="${IMAGE_NAMES[$i]}"
|
||||
URL="${IMAGE_URLS[$i]}"
|
||||
PLACEHOLDER="{{${NAME}}}"
|
||||
if [[ "$COMMENT_BODY" == *"$PLACEHOLDER"* ]]; then
|
||||
COMMENT_BODY="${COMMENT_BODY//"$PLACEHOLDER"/}"
|
||||
else
|
||||
UNREFERENCED+=("$NAME")
|
||||
UNREFERENCED+=("${NAME}"$'\t'"${URL}")
|
||||
fi
|
||||
done
|
||||
if [[ ${#UNREFERENCED[@]} -gt 0 ]]; then
|
||||
IFS=$'\n' SORTED=($(printf '%s\n' "${UNREFERENCED[@]}" | sort)); unset IFS
|
||||
for NAME in "${SORTED[@]}"; do
|
||||
COMMENT_BODY+=$'\n\n'""
|
||||
done
|
||||
while IFS=$'\t' read -r NAME URL; do
|
||||
COMMENT_BODY+=$'\n\n'""
|
||||
done < <(printf '%s\n' "${UNREFERENCED[@]}" | sort)
|
||||
fi
|
||||
else
|
||||
COMMENT_BODY="## Screenshots"$'\n\n'
|
||||
|
||||
Reference in New Issue
Block a user