feat: add mock batch submit endpoint
This commit is contained in:
parent
766c6a624f
commit
b1bb28f5aa
12
README.md
12
README.md
@ -56,6 +56,18 @@ The popup dev panel is controlled by `enableDevAuthPanel`.
|
|||||||
6. Click `测试受保护接口`
|
6. Click `测试受保护接口`
|
||||||
7. Confirm the popup shows JSON containing `"source": "mock-protected-api"` and `"message": "authorized"`
|
7. Confirm the popup shows JSON containing `"source": "mock-protected-api"` and `"message": "authorized"`
|
||||||
|
|
||||||
|
## Batch Submit Mock Test
|
||||||
|
|
||||||
|
1. Run `npm run mock:protected-api`
|
||||||
|
2. Run `npm run build`
|
||||||
|
3. Reload the unpacked extension from `dist/`
|
||||||
|
4. Open `https://xingtu.cn/ad/creator/market`
|
||||||
|
5. Choose an export range in the plugin toolbar
|
||||||
|
6. Click `提交批次`
|
||||||
|
7. Enter a batch name in the browser prompt
|
||||||
|
8. Confirm the toolbar shows `批次提交成功`
|
||||||
|
9. Confirm the mock batch response accepts the payload and reports the submitted `batchId`
|
||||||
|
|
||||||
## Market Auth Gate
|
## Market Auth Gate
|
||||||
|
|
||||||
When the market page is opened without a valid auth state, the content script renders
|
When the market page is opened without a valid auth state, the content script renders
|
||||||
|
|||||||
@ -12,22 +12,10 @@ export function createMockProtectedApiServer({ port = 4319 } = {}) {
|
|||||||
return `http://127.0.0.1:${resolvedPort}`;
|
return `http://127.0.0.1:${resolvedPort}`;
|
||||||
},
|
},
|
||||||
async start() {
|
async start() {
|
||||||
server = http.createServer((request, response) => {
|
server = http.createServer(async (request, response) => {
|
||||||
if (request.url !== "/api/mock/protected") {
|
if (request.url === "/api/mock/protected") {
|
||||||
response.writeHead(404, { "content-type": "application/json" });
|
const authHeader = readBearerToken(request, response);
|
||||||
response.end(JSON.stringify({ ok: false, error: "not-found" }));
|
if (!authHeader) {
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,6 +28,33 @@ export function createMockProtectedApiServer({ port = 4319 } = {}) {
|
|||||||
receivedAuthHeader: authHeader
|
receivedAuthHeader: authHeader
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.url === "/api/mock/batches" && request.method === "POST") {
|
||||||
|
const authHeader = readBearerToken(request, response);
|
||||||
|
if (!authHeader) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = await readJsonBody(request);
|
||||||
|
const authors = Array.isArray(payload?.authors) ? payload.authors : [];
|
||||||
|
response.writeHead(200, { "content-type": "application/json" });
|
||||||
|
response.end(
|
||||||
|
JSON.stringify({
|
||||||
|
ok: true,
|
||||||
|
source: "mock-batch-submit",
|
||||||
|
acceptedCount: authors.length,
|
||||||
|
batchId:
|
||||||
|
typeof payload?.batchId === "string" ? payload.batchId : null,
|
||||||
|
receivedAuthHeader: authHeader
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
response.writeHead(404, { "content-type": "application/json" });
|
||||||
|
response.end(JSON.stringify({ ok: false, error: "not-found" }));
|
||||||
});
|
});
|
||||||
|
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
@ -65,6 +80,36 @@ export function createMockProtectedApiServer({ port = 4319 } = {}) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readBearerToken(request, response) {
|
||||||
|
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 null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return authHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readJsonBody(request) {
|
||||||
|
const chunks = [];
|
||||||
|
|
||||||
|
for await (const chunk of request) {
|
||||||
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chunks.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
||||||
|
}
|
||||||
|
|
||||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||||
const server = createMockProtectedApiServer();
|
const server = createMockProtectedApiServer();
|
||||||
await server.start();
|
await server.start();
|
||||||
|
|||||||
@ -44,4 +44,37 @@ describe("mock-protected-api", () => {
|
|||||||
error: "unauthorized"
|
error: "unauthorized"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("accepts a batch payload 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/batches`, {
|
||||||
|
body: JSON.stringify({
|
||||||
|
authors: [{ authorId: "111", authorName: "达人A" }],
|
||||||
|
batchId: "批次A-2026-04-22T12:30:00.000Z",
|
||||||
|
batchName: "批次A",
|
||||||
|
createdAt: "2026-04-22T12:30:00.000Z",
|
||||||
|
creatorName: "王少卿",
|
||||||
|
logtoUserId: "p7pdhhtde8kj",
|
||||||
|
resource: "https://talent-search.intelligrow.cn"
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer abc123",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
method: "POST"
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
await expect(response.json()).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
acceptedCount: 1,
|
||||||
|
batchId: "批次A-2026-04-22T12:30:00.000Z",
|
||||||
|
ok: true,
|
||||||
|
source: "mock-batch-submit"
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user