chore: import existing Endoleap Pages Router project
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { createServer } from "node:http";
|
||||
import { spawn } from "node:child_process";
|
||||
import { once } from "node:events";
|
||||
import { fileURLToPath } from "node:url";
|
||||
const host = "http://127.0.0.1:3005";
|
||||
const upstream = createServer((req, res) => {
|
||||
res.setHeader("Content-Type", "application/json");
|
||||
if (req.url.endsWith("/auth/login")) {
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
access_token: "test-only-session",
|
||||
expires_in: 28800,
|
||||
token_type: "Bearer",
|
||||
}),
|
||||
);
|
||||
} else if (req.url.endsWith("/profile")) {
|
||||
res.statusCode =
|
||||
req.headers.authorization === "Bearer test-only-session" ? 200 : 401;
|
||||
res.end(
|
||||
JSON.stringify(
|
||||
res.statusCode === 200
|
||||
? { username: "test" }
|
||||
: { error: "invalid_session" },
|
||||
),
|
||||
);
|
||||
} else {
|
||||
res.statusCode = 404;
|
||||
res.end("{}");
|
||||
}
|
||||
});
|
||||
await new Promise((r) => upstream.listen(0, "127.0.0.1", r));
|
||||
const port = upstream.address().port;
|
||||
const app = spawn(
|
||||
process.execPath,
|
||||
[
|
||||
"node_modules/next/dist/bin/next",
|
||||
"start",
|
||||
"--hostname",
|
||||
"127.0.0.1",
|
||||
"--port",
|
||||
"3005",
|
||||
],
|
||||
{
|
||||
cwd: fileURLToPath(new URL("../", import.meta.url)),
|
||||
env: { ...process.env, FOUNDRY_API_ORIGIN: "http://127.0.0.1:" + port },
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
},
|
||||
);
|
||||
let startup = "";
|
||||
app.stdout.on("data", (x) => (startup += x));
|
||||
app.stderr.on("data", (x) => (startup += x));
|
||||
try {
|
||||
let ready = false;
|
||||
for (let n = 0; n < 100; n++) {
|
||||
if (app.exitCode !== null)
|
||||
throw new Error("Frontend failed to start: " + startup);
|
||||
try {
|
||||
if ((await fetch(host)).ok) {
|
||||
ready = true;
|
||||
break;
|
||||
}
|
||||
} catch {}
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
}
|
||||
assert(ready, "Frontend did not start");
|
||||
const res = await fetch(host + "/api/foundry/auth/login", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", Origin: host },
|
||||
body: "{}",
|
||||
});
|
||||
assert.equal(res.status, 200);
|
||||
assert.match(res.headers.get("server-timing") || "", /upstream;dur=\d/);
|
||||
const body = await res.json();
|
||||
assert.equal(body.access_token, undefined);
|
||||
const cookie = res.headers.get("set-cookie");
|
||||
assert(cookie?.includes("HttpOnly"));
|
||||
assert(cookie.includes("SameSite=Lax"));
|
||||
assert(cookie.includes("Max-Age=28800"));
|
||||
const session = cookie.split(";")[0];
|
||||
assert.equal(
|
||||
(
|
||||
await fetch(host + "/api/foundry/profile", {
|
||||
headers: { Cookie: session },
|
||||
})
|
||||
).status,
|
||||
200,
|
||||
);
|
||||
assert.equal((await fetch(host + "/api/foundry/profile")).status, 401);
|
||||
for (const origin of ["https://example.com", "null"])
|
||||
assert.equal(
|
||||
(
|
||||
await fetch(host + "/api/foundry/auth/login", {
|
||||
method: "POST",
|
||||
headers: { Origin: origin, "Content-Type": "application/json" },
|
||||
body: "{}",
|
||||
})
|
||||
).status,
|
||||
403,
|
||||
);
|
||||
assert.equal((await fetch(host + "/api/foundry/unlisted")).status, 404);
|
||||
assert.equal(
|
||||
(await fetch(host + "/api/oauth/slack?challenge=bad")).status,
|
||||
400,
|
||||
);
|
||||
console.log(
|
||||
"PASS: session cookie, token removal, authenticated proxy, invalid session, cross-origin rejection, path allowlist, OAuth validation",
|
||||
);
|
||||
} finally {
|
||||
const exited = once(app, "exit");
|
||||
app.kill("SIGTERM");
|
||||
await exited;
|
||||
await new Promise((r) => upstream.close(r));
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { createBoard, loadWorkspaceHome } from "../src/lib/workspace.ts";
|
||||
|
||||
test("profile and workspace reads both start before either completes", async () => {
|
||||
const calls = [];
|
||||
const resolve = {};
|
||||
const pending = loadWorkspaceHome((path) => {
|
||||
calls.push(path);
|
||||
return new Promise((done) => {
|
||||
resolve[path] = done;
|
||||
});
|
||||
});
|
||||
assert.deepEqual(calls, ["profile", "workspaces"]);
|
||||
resolve.profile({ id: "user" });
|
||||
resolve.workspaces({ items: [{ id: "space", name: "个人空间" }] });
|
||||
const result = await pending;
|
||||
assert.equal(result.profile.id, "user");
|
||||
assert.equal(result.workspaces[0].id, "space");
|
||||
});
|
||||
|
||||
test("a first board creates its personal workspace before posting the board", async () => {
|
||||
const calls = [];
|
||||
let selected = "";
|
||||
const result = await createBoard(
|
||||
async (path, options) => {
|
||||
calls.push([path, JSON.parse(options.body)]);
|
||||
if (path === "workspaces") return { id: "space", name: "个人空间" };
|
||||
assert.equal(selected, "space");
|
||||
return { id: "board" };
|
||||
},
|
||||
" 周末的灵感 ",
|
||||
"",
|
||||
(w) => {
|
||||
selected = w.id;
|
||||
},
|
||||
);
|
||||
assert.equal(result.id, "board");
|
||||
assert.deepEqual(
|
||||
calls.map(([p]) => p),
|
||||
["workspaces", "workspaces/space/materials"],
|
||||
);
|
||||
assert.equal(calls[1][1].title, "周末的灵感");
|
||||
});
|
||||
|
||||
test("a board failure retains the new workspace, so retry creates no duplicate space", async () => {
|
||||
let selected = "";
|
||||
let spaces = 0;
|
||||
let fail = true;
|
||||
const request = async (path) => {
|
||||
if (path === "workspaces") {
|
||||
spaces++;
|
||||
return { id: "space", name: "个人空间" };
|
||||
}
|
||||
if (fail) throw new Error("upstream_unavailable");
|
||||
return { id: "board" };
|
||||
};
|
||||
await assert.rejects(
|
||||
createBoard(request, "作品", selected, (w) => {
|
||||
selected = w.id;
|
||||
}),
|
||||
);
|
||||
fail = false;
|
||||
await createBoard(request, "作品", selected, () =>
|
||||
assert.fail("duplicate workspace"),
|
||||
);
|
||||
assert.equal(spaces, 1);
|
||||
});
|
||||
|
||||
test("an existing workspace posts a board directly", async () => {
|
||||
const calls = [];
|
||||
await createBoard(
|
||||
async (path) => {
|
||||
calls.push(path);
|
||||
return { id: "board" };
|
||||
},
|
||||
"作品",
|
||||
"existing",
|
||||
() => assert.fail("unexpected workspace"),
|
||||
);
|
||||
assert.deepEqual(calls, ["workspaces/existing/materials"]);
|
||||
});
|
||||
Reference in New Issue
Block a user