// @ts-check const { test, expect } = require('@playwright/test'); const fs = require('fs'); const path = require('path'); const RESULT_PATH = path.join(__dirname, '..', 'test-results', 'result.json'); function writeResult(result) { fs.mkdirSync(path.dirname(RESULT_PATH), { recursive: true }); fs.writeFileSync(RESULT_PATH, JSON.stringify(result)); } test.describe('reddit post', () => { let outcome = { success: false, error: 'Test did not complete' }; let outcomeFinalized = false; test.afterEach(async () => { writeResult(outcome); }); test('logs into Reddit and creates a post', async ({ page }) => { const username = process.env.REDDIT_USERNAME; const password = process.env.REDDIT_PASSWORD; const subreddit = process.env.SUBREDDIT; const title = process.env.POST_TITLE; const body = process.env.POST_BODY; for (const [name, value] of Object.entries({ REDDIT_USERNAME: username, REDDIT_PASSWORD: password, SUBREDDIT: subreddit, POST_TITLE: title, POST_BODY: body, })) { if (!value) { outcome = { success: false, error: `Missing required environment variable: ${name}` }; outcomeFinalized = true; throw new Error(outcome.error); } } try { await page.goto('https://www.reddit.com/login/'); const blockedHeading = page.getByText(/blocked by network security/i); if (await blockedHeading.isVisible({ timeout: 3_000 }).catch(() => false)) { outcome = { success: false, error: 'Reddit blocked this request at the network level ("blocked by network security") before login could be attempted — this is not a credentials or selector issue, it means the current network/IP is being flagged as automation by Reddit', }; outcomeFinalized = true; throw new Error(outcome.error); } // Screenshot-verified against the live Reddit login page: cookie // dialog button text and the "Log In" submit button's accessible // name are both confirmed correct. const rejectCookies = page.getByRole('button', { name: 'Reject Optional Cookies' }); if (await rejectCookies.isVisible({ timeout: 5_000 }).catch(() => false)) { await rejectCookies.click(); } // Not individually screenshot-verified (only confirmed to resolve // as far as the network block allowed) — watch these first if // login fails on a real, unblocked network. const usernameField = page.getByLabel(/email or username/i); await usernameField.fill(/** @type {string} */ (username)); const passwordField = page.getByLabel(/^password/i); await passwordField.fill(/** @type {string} */ (password)); await page.getByRole('button', { name: 'Log In' }).click(); try { await expect(page.locator('span[name="avatar"], #USER_DROPDOWN_ID, [icon-name="account-circle-outline"]').first()).toBeVisible({ timeout: 20_000 }); } catch { const loginErrorBanner = page.getByText(/something went wrong logging in|invalid username|invalid password/i); const bannerText = await loginErrorBanner.first().textContent().catch(() => null); outcome = { success: false, error: bannerText ? `Login failed: ${bannerText.trim()}` : 'Login did not complete — possible CAPTCHA, 2FA prompt, or invalid credentials', }; outcomeFinalized = true; throw new Error(outcome.error); } // UNVERIFIED: a network block in the dev sandbox prevented ever // reaching this point in a live run, so none of the selectors below // (text-type tab, title field, body field, submit button) have been // confirmed against the real submit page. If posting fails here on // a real, unblocked network, inspect the live page first — e.g. via // `npx playwright codegen https://www.reddit.com/r/test/submit`. await page.goto(`https://www.reddit.com/r/${subreddit}/submit`); const textTab = page.getByRole('button', { name: /^Text$/i }).first(); if (await textTab.isVisible({ timeout: 10_000 }).catch(() => false)) { await textTab.click(); } await page.getByPlaceholder(/title/i).first().fill(/** @type {string} */ (title)); const bodyField = page.locator('[data-testid="post-composer-rte"], div[role="textbox"]').first(); await bodyField.click(); await bodyField.fill(/** @type {string} */ (body)); const submitButton = page.getByRole('button', { name: /^Post$/i }).first(); await expect(submitButton).toBeEnabled({ timeout: 10_000 }); await submitButton.click(); try { await page.waitForURL(/\/comments\//, { timeout: 20_000 }); } catch { outcome = { success: false, error: 'Post submission did not complete — no redirect to the new post' }; outcomeFinalized = true; throw new Error(outcome.error); } outcome = { success: true, url: page.url() }; outcomeFinalized = true; expect(outcome.success).toBe(true); } catch (err) { if (!outcomeFinalized) { outcome = { success: false, error: err instanceof Error ? err.message : String(err) }; } throw err; } }); });