feat: add mock protected api server
This commit is contained in:
parent
668aec45c5
commit
2c7ea3cc45
@ -5,9 +5,13 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node scripts/build.mjs",
|
"build": "node scripts/build.mjs",
|
||||||
|
"mock:protected-api": "node scripts/mock-protected-api.mjs",
|
||||||
"test": "vitest run --passWithNoTests",
|
"test": "vitest run --passWithNoTests",
|
||||||
"test:watch": "vitest --passWithNoTests"
|
"test:watch": "vitest --passWithNoTests"
|
||||||
},
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@logto/chrome-extension": "^0.1.27"
|
||||||
|
},
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"jsdom": "^29.0.2",
|
"jsdom": "^29.0.2",
|
||||||
|
|||||||
72
scripts/mock-protected-api.mjs
Normal file
72
scripts/mock-protected-api.mjs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import http from "node:http";
|
||||||
|
|
||||||
|
export function createMockProtectedApiServer({ port = 4319 } = {}) {
|
||||||
|
let server;
|
||||||
|
|
||||||
|
return {
|
||||||
|
get baseUrl() {
|
||||||
|
const address = server?.address();
|
||||||
|
const resolvedPort =
|
||||||
|
typeof address === "object" && address ? address.port : port;
|
||||||
|
|
||||||
|
return `http://127.0.0.1:${resolvedPort}`;
|
||||||
|
},
|
||||||
|
async start() {
|
||||||
|
server = http.createServer((request, response) => {
|
||||||
|
if (request.url !== "/api/mock/protected") {
|
||||||
|
response.writeHead(404, { "content-type": "application/json" });
|
||||||
|
response.end(JSON.stringify({ ok: false, error: "not-found" }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const authHeader = request.headers.authorization ?? "";
|
||||||
|
const isBearer =
|
||||||
|
typeof authHeader === "string" &&
|
||||||
|
authHeader.startsWith("Bearer ") &&
|
||||||
|
authHeader.length > "Bearer ".length;
|
||||||
|
|
||||||
|
if (!isBearer) {
|
||||||
|
response.writeHead(401, { "content-type": "application/json" });
|
||||||
|
response.end(JSON.stringify({ ok: false, error: "unauthorized" }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
response.writeHead(200, { "content-type": "application/json" });
|
||||||
|
response.end(
|
||||||
|
JSON.stringify({
|
||||||
|
ok: true,
|
||||||
|
source: "mock-protected-api",
|
||||||
|
message: "authorized",
|
||||||
|
receivedAuthHeader: authHeader
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
server.listen(port, "127.0.0.1", resolve);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async close() {
|
||||||
|
if (!server) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
server.close((error) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||||
|
const server = createMockProtectedApiServer();
|
||||||
|
await server.start();
|
||||||
|
console.log(`mock protected api listening on ${server.baseUrl}`);
|
||||||
|
}
|
||||||
47
tests/mock-protected-api.test.ts
Normal file
47
tests/mock-protected-api.test.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { afterEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
import { createMockProtectedApiServer } from "../scripts/mock-protected-api.mjs";
|
||||||
|
|
||||||
|
const servers: Array<{ close: () => Promise<void> }> = [];
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
while (servers.length > 0) {
|
||||||
|
await servers.pop()?.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("mock-protected-api", () => {
|
||||||
|
test("returns mock data when a Bearer token is present", async () => {
|
||||||
|
const server = createMockProtectedApiServer({ port: 0 });
|
||||||
|
await server.start();
|
||||||
|
servers.push(server);
|
||||||
|
|
||||||
|
const response = await fetch(`${server.baseUrl}/api/mock/protected`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer abc123"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
await expect(response.json()).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
ok: true,
|
||||||
|
source: "mock-protected-api"
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns 401 when the Authorization header is missing", async () => {
|
||||||
|
const server = createMockProtectedApiServer({ port: 0 });
|
||||||
|
await server.start();
|
||||||
|
servers.push(server);
|
||||||
|
|
||||||
|
const response = await fetch(`${server.baseUrl}/api/mock/protected`);
|
||||||
|
|
||||||
|
expect(response.status).toBe(401);
|
||||||
|
await expect(response.json()).resolves.toEqual({
|
||||||
|
ok: false,
|
||||||
|
error: "unauthorized"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user