mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 19:01:54 +00:00
When an app rides onion, Playwright routes through the node Tor SOCKS proxy, which cannot resolve the clearnet-internal SeaweedFS filer UI domain (net::ERR_SOCKS_CONNECTION_FAILED). Skip the filer storage check on onion targets in all consumer specs — same pattern already proven in the nextcloud spec. Clearnet runs are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
89 lines
3.9 KiB
JavaScript
89 lines
3.9 KiB
JavaScript
// SeaweedFS object-store scenario for Pixelfed.
|
|
//
|
|
// Pixelfed is configured with the S3 cloud filesystem (env.j2:
|
|
// PF_ENABLE_CLOUD=true, FILESYSTEM_DRIVER=s3, FILESYSTEM_CLOUD=s3, AWS_BUCKET),
|
|
// so media a user uploads through the compose flow is flushed to the consumer
|
|
// bucket instead of the local disk. The action logs the administrator in and
|
|
// publishes a tiny PNG through the new-post composer; the shared check proves
|
|
// the bucket grew via the Filer UI.
|
|
//
|
|
// IMPORTANT: Pixelfed's web composer (ComposeModal.vue, route /i/web/compose)
|
|
// does NOT upload media when the hidden #pf-dz file input changes — onInputFile
|
|
// only buffers the file client-side and advances the wizard to its caption
|
|
// step. The POST to /api/compose/v0/media/upload (the actual S3 write) and the
|
|
// subsequent /api/compose/v0/publish only fire when the "Post" action runs
|
|
// compose(). So selecting the file is not enough; the test must click "Post"
|
|
// and wait for the post redirect, otherwise no object ever reaches the bucket.
|
|
//
|
|
// Required env (rendered by templates/playwright.env.j2):
|
|
// PIXELFED_BASE_URL, the login vars consumed by loginToPixelfed, and the
|
|
// SEAWEEDFS_* keys consumed by runSeaweedfsStorageCheck.
|
|
|
|
const { test, expect } = require("@playwright/test");
|
|
const { resolveTimeout, isOnionTarget } = require("./timeouts");
|
|
const { skipUnlessServiceEnabled } = require("./service-gating");
|
|
const { runSeaweedfsStorageCheck } = require("./personas");
|
|
const shared = require("./_shared");
|
|
|
|
const PNG_1x1 = Buffer.from(
|
|
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
|
|
"base64",
|
|
);
|
|
|
|
function pixelfedAdminScenario() {
|
|
const scenarios = shared.loginScenarios || [];
|
|
return scenarios.find((scenario) => scenario.label === "administrator") || scenarios[0];
|
|
}
|
|
|
|
test.use({ ignoreHTTPSErrors: true });
|
|
|
|
test("seaweedfs: an uploaded Pixelfed photo is stored in the SeaweedFS bucket", async ({ page, browser }) => {
|
|
test.skip(isOnionTarget(), "SeaweedFS filer UI is not a Tor surface on an onion node (headless backend)");
|
|
skipUnlessServiceEnabled("seaweedfs");
|
|
test.setTimeout(resolveTimeout(180_000));
|
|
|
|
await runSeaweedfsStorageCheck(page, browser, {
|
|
label: "a Pixelfed composer photo upload",
|
|
action: async (appPage) => {
|
|
const scenario = pixelfedAdminScenario();
|
|
expect(scenario, "a login scenario must be configured for the Pixelfed seaweedfs check").toBeTruthy();
|
|
|
|
await shared.loginToPixelfed(appPage, scenario);
|
|
|
|
const baseUrl = shared.env.pixelfedBaseUrl.replace(/\/$/, "");
|
|
await appPage.goto(`${baseUrl}/i/web/compose`, { waitUntil: "domcontentloaded" });
|
|
|
|
const fileInput = appPage.locator('input#pf-dz, input[type="file"][name="media"], input[type="file"]').first();
|
|
await expect(
|
|
fileInput,
|
|
"the Pixelfed composer must expose a file input to attach a photo",
|
|
).toBeAttached({ timeout: resolveTimeout(60_000) });
|
|
|
|
const marker = `infinito-storage-check-${Date.now()}.png`;
|
|
await fileInput.setInputFiles({
|
|
name: marker,
|
|
mimeType: "image/png",
|
|
buffer: PNG_1x1,
|
|
});
|
|
|
|
const postAction = appPage
|
|
.getByRole("link", { name: /^Post$/i })
|
|
.or(appPage.getByRole("button", { name: /^Post$/i }))
|
|
.first();
|
|
await expect(
|
|
postAction,
|
|
"the Pixelfed composer must advance to its caption step and expose a Post action after a photo is attached",
|
|
).toBeVisible({ timeout: resolveTimeout(60_000) });
|
|
await postAction.click({ timeout: resolveTimeout(30_000) });
|
|
|
|
await expect
|
|
.poll(() => appPage.url(), {
|
|
timeout: resolveTimeout(90_000),
|
|
message:
|
|
"Pixelfed must publish the composed photo (media upload to S3 + /api/compose/v0/publish), then redirect away from /i/web/compose to the new post",
|
|
})
|
|
.not.toContain("/i/web/compose");
|
|
},
|
|
});
|
|
});
|