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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ node_modules
dist
dist-ssr
*.local
playwright-report/
test-results/

# Editor directories and files
.vscode/*
Expand Down
80 changes: 80 additions & 0 deletions e2e/focused-bounty-flow.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { expect, test } from "@playwright/test";

test.describe.configure({ mode: "serial" });

test("home explains one authorized security-bounty workflow", async ({
page,
}) => {
await page.goto("/");
await expect(
page.getByRole("heading", { name: /test security with scope and proof/i }),
).toBeVisible();
await expect(
page.getByRole("region", { name: /from bounty to verified result/i }),
).toBeVisible();
await expect(
page.getByRole("region", {
name: /scope is visible. authorization stays separate/i,
}),
).toBeVisible();
expect(
await page.evaluate(
() =>
document.documentElement.scrollWidth <=
document.documentElement.clientWidth,
),
).toBe(true);
});

test("mobile home keeps controls out of the content flow", async ({ page }) => {
await page.setViewportSize({ width: 390, height: 844 });
await page.goto("/");
await expect(
page.getByRole("heading", { name: /test security/i }),
).toBeVisible();
const themeToggle = page.getByRole("button", {
name: /switch to (?:light|dark) mode/i,
});
await expect(themeToggle).toBeVisible();
expect(
await themeToggle.evaluate((element) => getComputedStyle(element).position),
).not.toBe("fixed");
expect(
await page.evaluate(
() =>
document.documentElement.scrollWidth <=
document.documentElement.clientWidth,
),
).toBe(true);
});

test("discovery is a scannable bounty catalog", async ({ page }) => {
await page.goto("/ideas");
await expect(
page.getByRole("heading", { name: /authorized security bounties/i }),
).toBeVisible();
await expect(page.getByText("27 bounties", { exact: true })).toBeVisible();
await expect(page.locator("main article")).toHaveCount(27);
await expect(page.getByText("Attack scenario", { exact: true })).toHaveCount(
0,
);
});

test("bounty detail keeps authorization and proof together", async ({
page,
}) => {
await page.goto("/ideas/project-time-capsule");
await expect(
page.getByRole("heading", {
name: "Time Capsule Disclosure Bounty",
exact: true,
}),
).toBeVisible();
await expect(
page.getByRole("heading", { name: /scope the test. verify the result/i }),
).toBeVisible();
await expect(
page.getByRole("heading", { name: "Rules of engagement", exact: true }),
).toBeVisible();
await expect(page.getByText("Proof required", { exact: true })).toBeVisible();
});
8 changes: 4 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
name="description"
content="Review Ideascape security briefs with explicit threat scenarios, control boundaries, and proof requirements before systems earn trust."
content="Publish and review authorized security bounties with explicit attack scenarios, rules of engagement, and proof requirements."
/>
<meta name="theme-color" content="#ffffff" />
<meta name="theme-color" content="#f2efe6" />
<script>
(() => {
let savedTheme = null;
Expand All @@ -28,11 +28,11 @@
document.documentElement.style.colorScheme = isDark ? "dark" : "light";
document
.querySelector('meta[name="theme-color"]')
?.setAttribute("content", isDark ? "#000000" : "#ffffff");
?.setAttribute("content", isDark ? "#050505" : "#f2efe6");
})();
</script>
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<title>IdeascapeSecurity validation fieldwork</title>
<title>IdeaScapeAuthorized security bounties</title>
</head>
<body>
<div id="root"></div>
Expand Down
29 changes: 29 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { defineConfig, devices } from "@playwright/test";

const port = 5190;
const baseURL = `http://127.0.0.1:${port}`;

export default defineConfig({
testDir: "./e2e",
fullyParallel: false,
forbidOnly: Boolean(process.env.CI),
retries: process.env.CI ? 2 : 0,
reporter: "list",
use: {
baseURL,
trace: "on-first-retry",
},
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
],
webServer: {
command:
'bash -lc \'eval "$(supabase status -o env)"; export VITE_SUPABASE_URL="$API_URL" VITE_SUPABASE_PUBLISHABLE_KEY="$PUBLISHABLE_KEY"; npm run dev -- --host 127.0.0.1 --port 5190\'',
url: baseURL,
reuseExistingServer: !process.env.CI,
timeout: 120_000,
},
});
Loading
Loading