Fix silent market CSV export
This commit is contained in:
@@ -0,0 +1,263 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { createSilentExportController } from "../src/content/market/silent-export-controller";
|
||||
|
||||
describe("silent-export-controller", () => {
|
||||
test("replays exports from the live market page state when the request snapshot attribute is missing", async () => {
|
||||
document.body.innerHTML = '<div class="base-author-list"></div>';
|
||||
const marketRoot = document.querySelector(".base-author-list") as HTMLElement & {
|
||||
__vue__?: {
|
||||
_setupState?: Record<string, unknown>;
|
||||
};
|
||||
};
|
||||
marketRoot.__vue__ = {
|
||||
_setupState: {
|
||||
__$temp_1: {
|
||||
reqParams: {
|
||||
scene_param: {
|
||||
platform_source: 1
|
||||
},
|
||||
page_param: {
|
||||
limit: "20",
|
||||
page: "2"
|
||||
},
|
||||
search_param: {
|
||||
seach_type: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const requestedPages: number[] = [];
|
||||
const requestedHeaders: Array<HeadersInit | undefined> = [];
|
||||
const requestedUrls: string[] = [];
|
||||
const controller = createSilentExportController({
|
||||
document,
|
||||
fetchImpl: async (url, init) => {
|
||||
const body = JSON.parse(String(init?.body ?? "{}")) as {
|
||||
page_param?: { page?: number | string };
|
||||
};
|
||||
const pageNo = Number(body.page_param?.page ?? 0);
|
||||
requestedPages.push(pageNo);
|
||||
requestedHeaders.push(init?.headers);
|
||||
requestedUrls.push(url);
|
||||
|
||||
return {
|
||||
json: async () => ({
|
||||
authors: [
|
||||
{
|
||||
attribute_datas: {
|
||||
nickname: `达人${pageNo}`,
|
||||
price_20_60: pageNo * 1000
|
||||
},
|
||||
star_id: String(pageNo)
|
||||
}
|
||||
],
|
||||
pagination: {
|
||||
limit: 20,
|
||||
page: pageNo,
|
||||
total_count: 100
|
||||
}
|
||||
}),
|
||||
ok: true
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const records = await controller.exportRecords({
|
||||
mode: "count",
|
||||
pageCount: 2
|
||||
});
|
||||
|
||||
expect(requestedPages).toEqual([2, 3]);
|
||||
expect(
|
||||
requestedUrls.every((url) =>
|
||||
url.endsWith("/gw/api/gsearch/search_for_author_square")
|
||||
)
|
||||
).toBe(true);
|
||||
expect(requestedHeaders).toEqual([
|
||||
{
|
||||
Accept: "application/json, text/plain, */*",
|
||||
"Agw-Js-Conv": "str",
|
||||
"Content-Type": "application/json",
|
||||
"x-login-source": "1"
|
||||
},
|
||||
{
|
||||
Accept: "application/json, text/plain, */*",
|
||||
"Agw-Js-Conv": "str",
|
||||
"Content-Type": "application/json",
|
||||
"x-login-source": "1"
|
||||
}
|
||||
]);
|
||||
expect(records?.map((record) => record.authorId)).toEqual(["2", "3"]);
|
||||
});
|
||||
|
||||
test("replays paged exports when the page number is nested inside the request body", async () => {
|
||||
document.documentElement.setAttribute(
|
||||
"data-sces-market-request-snapshot",
|
||||
JSON.stringify({
|
||||
body: JSON.stringify({
|
||||
page_param: {
|
||||
page: 2
|
||||
}
|
||||
}),
|
||||
method: "POST",
|
||||
url: "https://xingtu.cn/api/mock-market-search"
|
||||
})
|
||||
);
|
||||
|
||||
const requestedPages: number[] = [];
|
||||
const controller = createSilentExportController({
|
||||
document,
|
||||
fetchImpl: async (_url, init) => {
|
||||
const body = JSON.parse(String(init?.body ?? "{}")) as {
|
||||
page_param?: { page?: number };
|
||||
};
|
||||
const pageNo = body.page_param?.page ?? 0;
|
||||
requestedPages.push(pageNo);
|
||||
|
||||
return {
|
||||
json: async () => ({
|
||||
authors: [
|
||||
{
|
||||
attribute_datas: {
|
||||
nickname: `达人${pageNo}`,
|
||||
price_20_60: pageNo * 1000
|
||||
},
|
||||
star_id: String(pageNo)
|
||||
}
|
||||
],
|
||||
pagination: {
|
||||
limit: 20,
|
||||
page: pageNo,
|
||||
total_count: 100
|
||||
}
|
||||
}),
|
||||
ok: true
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const records = await controller.exportRecords({
|
||||
mode: "count",
|
||||
pageCount: 2
|
||||
});
|
||||
|
||||
expect(requestedPages).toEqual([2, 3]);
|
||||
expect(records?.map((record) => record.authorId)).toEqual(["2", "3"]);
|
||||
});
|
||||
|
||||
test("starts from page 1 when the captured request omits an explicit page number", async () => {
|
||||
document.documentElement.setAttribute(
|
||||
"data-sces-market-request-snapshot",
|
||||
JSON.stringify({
|
||||
body: JSON.stringify({
|
||||
filters: {
|
||||
keyword: "test"
|
||||
}
|
||||
}),
|
||||
method: "POST",
|
||||
url: "https://xingtu.cn/api/mock-market-search"
|
||||
})
|
||||
);
|
||||
|
||||
const requestedPages: number[] = [];
|
||||
const controller = createSilentExportController({
|
||||
document,
|
||||
fetchImpl: async (_url, init) => {
|
||||
const body = JSON.parse(String(init?.body ?? "{}")) as { page?: number };
|
||||
const page = body.page ?? 0;
|
||||
requestedPages.push(page);
|
||||
|
||||
return {
|
||||
json: async () => ({
|
||||
data: {
|
||||
marketList: [
|
||||
{
|
||||
attribute_datas: {
|
||||
nickname: `达人${page}`,
|
||||
price_20_60: page * 1000
|
||||
},
|
||||
star_id: String(page)
|
||||
}
|
||||
]
|
||||
}
|
||||
}),
|
||||
ok: true
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const records = await controller.exportRecords({
|
||||
mode: "count",
|
||||
pageCount: 2
|
||||
});
|
||||
|
||||
expect(requestedPages).toEqual([1, 2]);
|
||||
expect(records?.map((record) => record.authorId)).toEqual(["1", "2"]);
|
||||
});
|
||||
|
||||
test("accepts snapshot headers that contain non-string values from the live XHR capture", async () => {
|
||||
document.body.innerHTML = "";
|
||||
document.documentElement.setAttribute(
|
||||
"data-sces-market-request-snapshot",
|
||||
JSON.stringify({
|
||||
body: JSON.stringify({
|
||||
page_param: {
|
||||
page: "1",
|
||||
limit: "20"
|
||||
}
|
||||
}),
|
||||
headers: {
|
||||
Accept: "application/json, text/plain, */*",
|
||||
"Content-Type": "application/json",
|
||||
"x-login-source": 1,
|
||||
"Agw-Js-Conv": "str"
|
||||
},
|
||||
method: "POST",
|
||||
url: "/gw/api/gsearch/search_for_author_square"
|
||||
})
|
||||
);
|
||||
|
||||
const requestedPages: number[] = [];
|
||||
const controller = createSilentExportController({
|
||||
document,
|
||||
fetchImpl: async (_url, init) => {
|
||||
const body = JSON.parse(String(init?.body ?? "{}")) as {
|
||||
page_param?: { page?: number | string };
|
||||
};
|
||||
requestedPages.push(Number(body.page_param?.page ?? 0));
|
||||
|
||||
return {
|
||||
json: async () => ({
|
||||
authors: [
|
||||
{
|
||||
attribute_datas: {
|
||||
nickname: "达人1"
|
||||
},
|
||||
star_id: "1"
|
||||
}
|
||||
],
|
||||
pagination: {
|
||||
limit: 20,
|
||||
page: 1,
|
||||
total_count: 20
|
||||
}
|
||||
}),
|
||||
ok: true
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const records = await controller.exportRecords({
|
||||
mode: "count",
|
||||
pageCount: 1
|
||||
});
|
||||
|
||||
expect(requestedPages).toEqual([1]);
|
||||
expect(records?.map((record) => record.authorId)).toEqual(["1"]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user