Skip to content

Commit 222bdeb

Browse files
committed
tests: Add test for user journey timeline
Add end-to-end Playwright test that verifies CAPTCHA questions and answers are correctly displayed in the user journey timeline on both approval and moderation pages. The test: - Registers a user and promotes them to moderator level via direct DB update - Creates a moderated post as anonymous user that triggers CAPTCHA - Verifies the approval page shows user journey with CAPTCHA question and answer - Approves the post - Verifies the moderation page for the live post also shows the journey timeline
1 parent dc89ab9 commit 222bdeb

1 file changed

Lines changed: 110 additions & 0 deletions

File tree

tests/user-journey.spec.ts

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { test, expect } from "@playwright/test";
2+
import { execSync } from "child_process";
3+
import path from "path";
4+
5+
const PROJECT_ROOT = path.resolve(__dirname, "..");
6+
const DB_PATH = process.env.DFEED_DB || path.join(PROJECT_ROOT, "data/db/dfeed.s3db");
7+
8+
test.describe("User Journey", () => {
9+
test("shows CAPTCHA question and answer on approval and moderation pages", async ({ page, context }) => {
10+
const timestamp = Date.now();
11+
const modUsername = `mod${timestamp}`;
12+
13+
// Step 1: Register a moderator user
14+
await page.goto("/registerform");
15+
await page.fill("#loginform-username", modUsername);
16+
await page.fill("#loginform-password", "testpass123");
17+
await page.fill("#loginform-password2", "testpass123");
18+
await page.click('input[type="submit"]');
19+
await page.waitForURL("**/");
20+
21+
// Promote user to moderator level (100)
22+
const sqlCmd = `UPDATE Users SET Level=100 WHERE Username='${modUsername}';`;
23+
execSync(`sqlite3 "${DB_PATH}" "${sqlCmd}"`);
24+
25+
// Step 2: Create a moderated post as anonymous user
26+
await context.clearCookies();
27+
28+
await page.goto("/newpost/test");
29+
await expect(page.locator("#postform")).toBeVisible();
30+
31+
// Fill form with hardspamtest (triggers CAPTCHA AND moderation)
32+
await page.fill("#postform-name", "Test User");
33+
await page.fill("#postform-email", "test@example.com");
34+
await page.fill("#postform-subject", `hardspamtest ${timestamp}`);
35+
await page.fill("#postform-text", "Testing CAPTCHA question and answer in user journey");
36+
37+
// Submit to trigger CAPTCHA
38+
await page.click('input[name="action-send"]');
39+
40+
// Wait for CAPTCHA and solve it
41+
const captchaCheckbox = page.locator('input[name="dummy_captcha_checkbox"]');
42+
await expect(captchaCheckbox).toBeVisible();
43+
44+
// Capture the draft ID before solving CAPTCHA
45+
const draftId = await page.locator('input[name="did"]').inputValue();
46+
expect(draftId).toBeTruthy();
47+
48+
// Solve CAPTCHA and submit
49+
await captchaCheckbox.check();
50+
await page.click('input[name="action-send"]');
51+
52+
// Wait for moderation notice
53+
await expect(page.locator("body")).toContainText("approved by a moderator", { timeout: 10000 });
54+
55+
// Step 3: Log in as moderator
56+
await page.goto("/loginform");
57+
await page.fill("#loginform-username", modUsername);
58+
await page.fill("#loginform-password", "testpass123");
59+
await page.click('input[type="submit"]');
60+
await page.waitForURL("**/");
61+
62+
// Step 4: Check the approval page has User Journey with CAPTCHA info
63+
await page.goto(`/approve-moderated-draft/${draftId}`);
64+
65+
// Verify User Journey section exists
66+
const journeySection = page.locator(".journey-timeline");
67+
await expect(journeySection).toBeVisible();
68+
69+
// Verify CAPTCHA question is shown (use .journey-message for more specific matching)
70+
const captchaQuestion = journeySection.locator(".journey-event", { has: page.locator(".journey-message", { hasText: "CAPTCHA question" }) });
71+
await expect(captchaQuestion.first()).toBeVisible();
72+
await expect(captchaQuestion.first()).toContainText("Dummy CAPTCHA");
73+
74+
// Verify CAPTCHA answer is shown
75+
const captchaAnswer = journeySection.locator(".journey-event", { has: page.locator(".journey-message", { hasText: "CAPTCHA answer" }) });
76+
await expect(captchaAnswer.first()).toBeVisible();
77+
await expect(captchaAnswer.first()).toContainText("checked", { ignoreCase: true });
78+
79+
// Step 5: Approve the post
80+
await page.click('input[name="approve"]');
81+
await expect(page.locator("body")).toContainText("Post approved");
82+
83+
// Get the posting link to find the message ID
84+
const viewLink = await page.locator('a:has-text("View posting")').getAttribute('href');
85+
expect(viewLink).toBeTruthy();
86+
87+
const postIdMatch = viewLink!.match(/posting\/([a-z]+)/);
88+
expect(postIdMatch).toBeTruthy();
89+
90+
const postId = postIdMatch![1];
91+
const encodedMessageId = encodeURIComponent(`${postId}@localhost`);
92+
93+
// Step 6: Check the moderation page for the live post also has User Journey with CAPTCHA info
94+
await page.goto(`/moderate/${encodedMessageId}`);
95+
96+
// Verify User Journey section exists
97+
const moderationJourney = page.locator(".journey-timeline");
98+
await expect(moderationJourney).toBeVisible();
99+
100+
// Verify CAPTCHA question is shown (use .journey-message for more specific matching)
101+
const modCaptchaQuestion = moderationJourney.locator(".journey-event", { has: page.locator(".journey-message", { hasText: "CAPTCHA question" }) });
102+
await expect(modCaptchaQuestion.first()).toBeVisible();
103+
await expect(modCaptchaQuestion.first()).toContainText("Dummy CAPTCHA");
104+
105+
// Verify CAPTCHA answer is shown
106+
const modCaptchaAnswer = moderationJourney.locator(".journey-event", { has: page.locator(".journey-message", { hasText: "CAPTCHA answer" }) });
107+
await expect(modCaptchaAnswer.first()).toBeVisible();
108+
await expect(modCaptchaAnswer.first()).toContainText("checked", { ignoreCase: true });
109+
});
110+
});

0 commit comments

Comments
 (0)