Files
muninn/sidecars/reddit-post/tests/reddit-post.spec.js
T
Doar Mihai a6fb5ef1cf fix: preserve specific error message on unexpected test exceptions
The outer catch's overwrite guard checked `!outcome.error`, but outcome.error
is always truthy (even the default placeholder string), so an exception
occurring outside the two explicitly-guarded blocks (e.g. a .fill()/.click()
timeout) would leave the generic "Test did not complete" message instead of
the real error. Replaced with an explicit outcomeFinalized sentinel that is
set exactly where outcome is deliberately finalized (missing env var, login
timeout, post-submission timeout, success), so any other exception correctly
falls through to the catch-all branch with its real message.
2026-07-18 18:15:41 +03:00

96 lines
3.2 KiB
JavaScript

// @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/');
await page.fill('input[name="username"]', /** @type {string} */ (username));
await page.fill('input[name="password"]', /** @type {string} */ (password));
await page.click('button[type="submit"]');
try {
await expect(page.locator('span[name="avatar"], #USER_DROPDOWN_ID, [icon-name="account-circle-outline"]').first()).toBeVisible({ timeout: 20_000 });
} catch {
outcome = {
success: false,
error: 'Login did not complete — possible CAPTCHA, 2FA prompt, or invalid credentials',
};
outcomeFinalized = true;
throw new Error(outcome.error);
}
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;
}
});
});