diff --git a/sidecars/reddit-post/tests/reddit-post.spec.js b/sidecars/reddit-post/tests/reddit-post.spec.js new file mode 100644 index 0000000..bdd6677 --- /dev/null +++ b/sidecars/reddit-post/tests/reddit-post.spec.js @@ -0,0 +1,90 @@ +// @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' }; + + 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}` }; + 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', + }; + 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' }; + throw new Error(outcome.error); + } + + outcome = { success: true, url: page.url() }; + expect(outcome.success).toBe(true); + } catch (err) { + if (outcome.success !== false || !outcome.error) { + outcome = { success: false, error: err instanceof Error ? err.message : String(err) }; + } + throw err; + } + }); +});