mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
feat: add minimal reproducer for moderation UI bug
Added a Playwright test reproducer for the known issue where the 'Show anyway' button fails to render in headless environments. The reproducer is located in `examples/reproducers/issue-moderation-ui/` and includes: - `repro.spec.ts`: The test script derived from `tests/visual/moderation.spec.ts` with failing assertions enabled. - `README.md`: Instructions on how to run the reproducer. - `playwright.config.ts`: Configuration to run the test in the reproducer context. This helps triage and verify fixes for the moderation UI visibility issue. Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
1 parent
8c331f8c14
commit
353f140ec7
3 files changed
+147
-35
No files matched your search
@@ -1,24 +1,22 @@
|
||||
# Moderation UI "Show Anyway" Button Visibility Issue Reproducer
|
||||
# Moderation UI Failure Reproducer
|
||||
|
||||
This reproducer demonstrates the issue where the "Show anyway" button in the moderation UI is not visible (or not interactable) in the test environment, even though the logic seems correct.
|
||||
This reproducer demonstrates a known issue where the "Show anyway" button and related moderation badges fail to render or be interactable in the test environment (headless mode), despite logic indicating they should be present.
|
||||
|
||||
## Issue Description
|
||||
- **Known Issue**: `KNOWN_ISSUES.md`: Moderation UI (`tests/visual/moderation.spec.ts`): The "Show anyway" button and related moderation badges fail to render in the test environment, causing `toBeVisible()` assertions to fail.
|
||||
- **Symptoms**: `Error: element(s) not found` when asserting visibility of the "Show anyway" button.
|
||||
As noted in `KNOWN_ISSUES.md`:
|
||||
> **Moderation UI (`tests/visual/moderation.spec.ts`)**: The "Show anyway" button and related moderation badges fail to render in the test environment, causing `toBeVisible()` assertions to fail. The logic for creating the button appears correct (`allowOverride` is true), but the button element is not found in the DOM during the test execution.
|
||||
|
||||
## How to Run
|
||||
|
||||
1. Navigate to the repository root.
|
||||
2. Ensure dependencies are installed and the project is built:
|
||||
1. Ensure the project is built:
|
||||
```bash
|
||||
npm ci
|
||||
npm run build
|
||||
npx playwright install chromium
|
||||
```
|
||||
3. Run the reproducer script using the provided config:
|
||||
|
||||
2. Run the reproducer test using the custom config (which sets the correct test directory and server context):
|
||||
```bash
|
||||
npx playwright test -c examples/reproducers/issue-moderation-ui/playwright.config.ts
|
||||
npx playwright test -c examples/reproducers/playwright.config.ts examples/reproducers/issue-moderation-ui/repro.spec.ts
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
The test `repro: show anyway override button visibility` should **fail** with a timeout or "element not found" error on the assertion `await expect(showAnywayButton).toBeVisible();`.
|
||||
The test should FAIL with timeout errors waiting for the "Show anyway" button to be visible or clickable.
|
||||
@@ -40,6 +40,34 @@ test.afterEach(async ({ page }) => {
|
||||
});
|
||||
|
||||
test.describe("moderation fixtures", () => {
|
||||
test("blur fixture masks thumbnails and blocks autoplay", async ({ page }) => {
|
||||
await page.goto(FIXTURE_URL, { waitUntil: "networkidle" });
|
||||
await waitForFixtureReady(page);
|
||||
|
||||
const blurCard = page.locator('[data-test-id="blur-threshold"]');
|
||||
const thumbnail = blurCard.locator('img[data-video-thumbnail]');
|
||||
|
||||
await expect(blurCard).toHaveAttribute("data-moderation-report-count", "3");
|
||||
await expect(blurCard).toHaveAttribute("data-autoplay-policy", "blocked");
|
||||
await expect(thumbnail).toHaveAttribute("data-thumbnail-state", "blurred");
|
||||
await expect(blurCard).not.toHaveAttribute(
|
||||
"data-moderation-override",
|
||||
"show-anyway"
|
||||
);
|
||||
});
|
||||
|
||||
test("autoplay fixture disables preview without blurring", async ({ page }) => {
|
||||
await page.goto(FIXTURE_URL, { waitUntil: "networkidle" });
|
||||
await waitForFixtureReady(page);
|
||||
|
||||
const autoplayCard = page.locator('[data-test-id="autoplay-threshold"]');
|
||||
const thumbnail = autoplayCard.locator('img[data-video-thumbnail]');
|
||||
|
||||
await expect(autoplayCard).toHaveAttribute("data-moderation-report-count", "2");
|
||||
await expect(autoplayCard).toHaveAttribute("data-autoplay-policy", "blocked");
|
||||
await expect(thumbnail).not.toHaveAttribute("data-thumbnail-state", "blurred");
|
||||
});
|
||||
|
||||
test("show anyway override persists across reloads", async ({ page }) => {
|
||||
await page.goto(FIXTURE_URL, { waitUntil: "networkidle" });
|
||||
await waitForFixtureReady(page);
|
||||
@@ -59,14 +87,13 @@ test.describe("moderation fixtures", () => {
|
||||
await expect(overrideCard).toHaveAttribute("data-autoplay-policy", "blocked");
|
||||
await expect(thumbnail).toHaveAttribute("data-thumbnail-state", "blurred");
|
||||
|
||||
// Uncommented failures:
|
||||
// Uncommented failing assertions
|
||||
await expect(showAnywayButton).toBeVisible();
|
||||
await expect(restoreButtonQuery).toHaveCount(0);
|
||||
|
||||
// Uncommented failure:
|
||||
// Uncommented failing interactions
|
||||
await showAnywayButton.click({ force: true });
|
||||
|
||||
/*
|
||||
await expect(overrideCard).toHaveAttribute(
|
||||
"data-moderation-override",
|
||||
"show-anyway"
|
||||
@@ -113,6 +140,105 @@ test.describe("moderation fixtures", () => {
|
||||
await expect(
|
||||
reloadedCard.getByRole("button", { name: "Show anyway" })
|
||||
).toBeVisible();
|
||||
*/
|
||||
});
|
||||
|
||||
test("trusted report hide fixture supports show anyway override", async ({ page }) => {
|
||||
await page.goto(FIXTURE_URL, { waitUntil: "networkidle" });
|
||||
await waitForFixtureReady(page);
|
||||
|
||||
const hideCard = page.locator('[data-test-id="trusted-report-hide"]');
|
||||
const badge = hideCard.locator('[data-moderation-badge="true"]');
|
||||
|
||||
await expect(hideCard).toHaveAttribute(
|
||||
"data-moderation-override-available",
|
||||
"true"
|
||||
);
|
||||
const showAnywayButton = hideCard.getByRole("button", { name: "Show anyway" });
|
||||
const restoreButtonQuery = hideCard.getByRole("button", {
|
||||
name: RESTORE_BUTTON_LABEL,
|
||||
});
|
||||
|
||||
await expect(hideCard).toHaveAttribute("data-moderation-hidden", "true");
|
||||
await expect(hideCard).toHaveAttribute("data-moderation-hide-reason", "trusted-report-hide");
|
||||
await expect(hideCard).toHaveAttribute("data-moderation-hide-trusted-report-count", "3");
|
||||
await expect(badge).toContainText("Hidden · 3 trusted spam reports");
|
||||
|
||||
// Uncommented failing assertions
|
||||
await expect(showAnywayButton).toBeVisible();
|
||||
await expect(restoreButtonQuery).toHaveCount(0);
|
||||
|
||||
// Uncommented failing interactions
|
||||
await showAnywayButton.click({ force: true });
|
||||
|
||||
await expect(hideCard).not.toHaveAttribute("data-moderation-hidden", "true");
|
||||
await expect(hideCard).toHaveAttribute("data-moderation-override", "show-anyway");
|
||||
await expect(hideCard.locator('[data-moderation-badge="true"]')).toContainText(
|
||||
"Showing despite 3 trusted spam reports",
|
||||
);
|
||||
|
||||
const restoreButton = hideCard.getByRole("button", {
|
||||
name: RESTORE_BUTTON_LABEL,
|
||||
});
|
||||
await expect(restoreButton).toBeVisible();
|
||||
|
||||
await restoreButton.click();
|
||||
|
||||
await expect(hideCard).toHaveAttribute("data-moderation-hidden", "true");
|
||||
await expect(hideCard).not.toHaveAttribute("data-moderation-override", "show-anyway");
|
||||
await expect(hideCard.getByRole("button", { name: "Show anyway" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("trusted mute hide fixture annotates mute reason and can be overridden", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto(FIXTURE_URL, { waitUntil: "networkidle" });
|
||||
await waitForFixtureReady(page);
|
||||
|
||||
const muteCard = page.locator('[data-test-id="trusted-mute-hide"]');
|
||||
const badge = muteCard.locator('[data-moderation-badge="true"]');
|
||||
const thumbnail = muteCard.locator('img[data-video-thumbnail]');
|
||||
|
||||
await expect(muteCard).toHaveAttribute(
|
||||
"data-moderation-override-available",
|
||||
"true"
|
||||
);
|
||||
const showAnywayButton = muteCard.getByRole("button", { name: "Show anyway" });
|
||||
const restoreButtonQuery = muteCard.getByRole("button", {
|
||||
name: RESTORE_BUTTON_LABEL,
|
||||
});
|
||||
|
||||
await expect(muteCard).toHaveAttribute("data-moderation-hidden", "true");
|
||||
await expect(muteCard).toHaveAttribute("data-moderation-hide-reason", "trusted-mute-hide");
|
||||
await expect(muteCard).toHaveAttribute("data-moderation-hide-trusted-mute-count", "1");
|
||||
await expect(muteCard).toHaveAttribute("data-moderation-trusted-mute", "true");
|
||||
await expect(muteCard).toHaveAttribute("data-moderation-trusted-mute-count", "1");
|
||||
await expect(badge).toContainText("Hidden · 1 trusted mute");
|
||||
await expect(thumbnail).toHaveAttribute("data-thumbnail-state", "blurred");
|
||||
|
||||
// Uncommented failing assertions
|
||||
await expect(showAnywayButton).toBeVisible();
|
||||
await expect(restoreButtonQuery).toHaveCount(0);
|
||||
|
||||
// Uncommented failing interactions
|
||||
await showAnywayButton.click({ force: true });
|
||||
|
||||
await expect(muteCard).not.toHaveAttribute("data-moderation-hidden", "true");
|
||||
await expect(muteCard).toHaveAttribute("data-moderation-override", "show-anyway");
|
||||
await expect(muteCard.locator('[data-moderation-badge="true"]')).toContainText(
|
||||
"Showing despite 1 trusted mute",
|
||||
);
|
||||
await expect(thumbnail).not.toHaveAttribute("data-thumbnail-state", "blurred");
|
||||
|
||||
const restoreButton = muteCard.getByRole("button", {
|
||||
name: RESTORE_BUTTON_LABEL,
|
||||
});
|
||||
await expect(restoreButton).toBeVisible();
|
||||
|
||||
await restoreButton.click();
|
||||
|
||||
await expect(muteCard).toHaveAttribute("data-moderation-hidden", "true");
|
||||
await expect(muteCard).not.toHaveAttribute("data-moderation-override", "show-anyway");
|
||||
await expect(thumbnail).toHaveAttribute("data-thumbnail-state", "blurred");
|
||||
await expect(muteCard.getByRole("button", { name: "Show anyway" })).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -1,30 +1,18 @@
|
||||
import { defineConfig } from "@playwright/test";
|
||||
|
||||
const HOST = process.env.PLAYWRIGHT_HOST ?? "127.0.0.1";
|
||||
const PORT = Number.parseInt(process.env.PLAYWRIGHT_PORT ?? "4173", 10);
|
||||
const BASE_URL = process.env.PLAYWRIGHT_BASE_URL ?? `http://${HOST}:${PORT}`;
|
||||
import baseConfig from "../../playwright.config.ts";
|
||||
|
||||
export default defineConfig({
|
||||
testDir: "../../",
|
||||
outputDir: "../../artifacts/test-results-repro",
|
||||
timeout: 60_000,
|
||||
reporter: [["list"]],
|
||||
use: {
|
||||
baseURL: BASE_URL,
|
||||
viewport: { width: 1280, height: 720 },
|
||||
ignoreHTTPSErrors: true,
|
||||
...baseConfig,
|
||||
testDir: ".",
|
||||
webServer: {
|
||||
...baseConfig.webServer,
|
||||
cwd: "../../",
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
name: "repro",
|
||||
testMatch: "examples/reproducers/**/*.spec.ts",
|
||||
testMatch: "**/*.spec.ts",
|
||||
use: baseConfig.use,
|
||||
},
|
||||
],
|
||||
webServer: {
|
||||
command: `npx http-server . -p ${PORT} -a ${HOST} -c-1 --silent`,
|
||||
cwd: "../../",
|
||||
url: `${BASE_URL}/docs/kitchen-sink.html`,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
timeout: 120_000,
|
||||
},
|
||||
});
|
||||
Reference in new issue
Block a user