5.9 KiB
Reddit Post Sidecar — Design
Purpose
A standalone Playwright acceptance test, living under sidecars/, that logs into Reddit with supplied credentials and creates a text post in a given subreddit. It is invoked as a CLI tool (not an HTTP service) so an external caller — most likely the AI agent that also manages this project's Sites/Social Accounts/Posts data — can shell out to it, passing credentials and post content as arguments, and get back a structured success/failure result it can act on (e.g. to PATCH the Laravel Posts API's status field to published or failed).
This is a sidecar: independent of the Laravel app's PHP/Composer/npm toolchain, with its own package.json and dependencies, callable standalone.
Scope
- One Playwright Test (
@playwright/test) that:- Logs into Reddit with a given username/password
- Navigates to a given subreddit's submit page
- Creates a text post with a given title and body
- Verifies the post was created and captures its URL
- A thin CLI wrapper script that accepts friendly
--flagarguments and translates them into the environment variables the Playwright test reads, then invokesnpx playwright test - Structured JSON output (success or failure) printed to stdout, with a matching process exit code, so any caller can parse the result reliably
Out of scope:
- Link posts (URL posts) — text posts only
- Interactive CAPTCHA/2FA solving — if login doesn't complete cleanly, the test fails with a descriptive error rather than waiting for a human
- Any wiring back into the Laravel app's Posts API — this sidecar only performs the Reddit action and reports the result; calling it and acting on the result is the caller's (the AI's) responsibility
- Any other social network — this is Reddit-only for now; the same pattern could be repeated per-network later, but that's not part of this spec
Arguments
Via the wrapper script (run.sh):
| Flag | Required | Description |
|---|---|---|
--username |
yes | Reddit username or email to log in with |
--password |
yes | Reddit account password |
--subreddit |
yes | Subreddit to post to (without the r/ prefix) |
--title |
yes | Post title |
--body |
yes | Post body text |
--headed |
no | If passed, runs with a visible browser window instead of headless (for debugging) |
The wrapper translates these into environment variables (REDDIT_USERNAME, REDDIT_PASSWORD, SUBREDDIT, POST_TITLE, POST_BODY, HEADLESS) that the Playwright config and test read, since Playwright Test reserves its own CLI argument syntax and custom flags cannot be passed through directly to npx playwright test.
Behavior
Login:
- Navigate to Reddit's login page
- Fill username and password fields, submit
- Wait for a reliable "logged in" signal (e.g. presence of the user menu/avatar) within a bounded timeout
- If the logged-in state isn't reached in time — whether due to a CAPTCHA, 2FA/"verify it's you" prompt, or wrong credentials — fail immediately with a descriptive error. No interactive fallback.
Posting:
- Navigate to
https://www.reddit.com/r/{subreddit}/submit - Select the text-post type (as opposed to link/image/poll)
- Fill in the title and body fields
- Submit the post
- Wait for navigation to the new post's permalink (or another reliable success signal) within a bounded timeout
- If the post doesn't appear to succeed within the timeout, fail with a descriptive error (e.g. "post submission did not complete" or a captured error banner's text if Reddit shows one)
Assertions: Playwright's expect() is used at each key step (login success, submit page loaded, post created) so this genuinely functions as an acceptance test, not just an unassertive script — a failed assertion is what produces the failure exit path.
Output Contract
Regardless of how it's invoked, the wrapper script always prints exactly one JSON object to stdout as its last line, and exits with a matching code:
- Success: exit code
0, stdout ends with{"success": true, "url": "<permalink of the new post>"} - Failure: exit code
1, stdout ends with{"success": false, "error": "<human-readable description of what went wrong>"}
The Playwright test itself writes this result to a fixed JSON file (e.g. test-results/result.json) during its run (in a step that always executes, success or failure, so the file exists either way); the wrapper reads that file after the playwright test process exits and echoes its contents to stdout as the final line, then exits with the same code Playwright produced.
Technical Setup
- New directory:
sidecars/reddit-post/ - Own
package.jsonwith@playwright/testas the sole dependency playwright.config.js: headless by default (HEADLESSenv var can override tofalse), single browser project (Chromium is sufficient — no cross-browser requirement for this internal tool), no automatic retries (a retry would mask a flaky login/post flow rather than surface it), screenshot-on-failure enabled for debugging- Setup note (in this sidecar's own short README) that
npx playwright install chromiummust be run once afternpm install, since Playwright needs its browser binaries downloaded separately
Testing / Verification
Since this automates a real third-party site (Reddit) with real credentials, there is no "test the test" step in the traditional sense — verification means actually running the wrapper against a real (test) Reddit account and confirming:
- A successful run produces a real post visible on Reddit, and the JSON result's
urlresolves to it - A run with wrong credentials fails cleanly with a descriptive error and exit code 1
- A run with an invalid/nonexistent subreddit fails cleanly with a descriptive error and exit code 1
These are manual verification steps to run once the implementation is complete, not automated CI tests (there's no sandboxed "fake Reddit" to test against, and using real Reddit in automated CI is undesirable — rate limits, ToS, account flagging risk).