release: 0.2.0421.2
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
|
||||
import { registerBackgroundMessageHandler } from "../src/background/index";
|
||||
|
||||
describe("background-index", () => {
|
||||
test("downloads csv files when the content script sends a download message", async () => {
|
||||
const listeners: Array<
|
||||
(message: unknown, sender: unknown, sendResponse: (response: unknown) => void) => boolean | void
|
||||
> = [];
|
||||
const download = vi.fn(async () => undefined);
|
||||
const sendResponse = vi.fn();
|
||||
|
||||
registerBackgroundMessageHandler({
|
||||
downloads: {
|
||||
download
|
||||
},
|
||||
runtime: {
|
||||
onMessage: {
|
||||
addListener(listener) {
|
||||
listeners.push(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(listeners).toHaveLength(1);
|
||||
const result = listeners[0](
|
||||
{
|
||||
csv: "列1,列2\n值1,值2",
|
||||
filename: "market.csv",
|
||||
type: "download-market-csv"
|
||||
},
|
||||
{},
|
||||
sendResponse
|
||||
);
|
||||
|
||||
expect(result).toBe(true);
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
expect(download).toHaveBeenCalledTimes(1);
|
||||
expect(download).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
filename: "market.csv",
|
||||
saveAs: false,
|
||||
url: expect.stringContaining("data:text/csv;charset=utf-8,")
|
||||
})
|
||||
);
|
||||
expect(sendResponse).toHaveBeenCalledWith({ ok: true });
|
||||
});
|
||||
});
|
||||
@@ -4,7 +4,7 @@ import { buildMarketCsv } from "../src/content/market/csv-exporter";
|
||||
import type { MarketRecord } from "../src/content/market/types";
|
||||
|
||||
describe("csv-exporter", () => {
|
||||
test("uses the expected header order", () => {
|
||||
test("uses fallback header order when no page export fields are available", () => {
|
||||
const csv = buildMarketCsv([]);
|
||||
const [headerLine] = csv.split("\n");
|
||||
|
||||
@@ -15,12 +15,38 @@ describe("csv-exporter", () => {
|
||||
"地区",
|
||||
"21-60s报价",
|
||||
"单视频看后搜率",
|
||||
"个人视频看后搜率",
|
||||
"插件数据状态"
|
||||
"个人视频看后搜率"
|
||||
].join(",")
|
||||
);
|
||||
});
|
||||
|
||||
test("uses page export field order and appends the two plugin columns", () => {
|
||||
const csv = buildMarketCsv([
|
||||
{
|
||||
authorId: "123",
|
||||
authorName: "Alice",
|
||||
exportFields: {
|
||||
达人信息: "Alice",
|
||||
粉丝数: "100w",
|
||||
"21-60s报价": "¥450,000"
|
||||
},
|
||||
status: "success",
|
||||
rates: {
|
||||
singleVideoAfterSearchRate: "0.5%-1%",
|
||||
personalVideoAfterSearchRate: "1% - 3%"
|
||||
}
|
||||
} satisfies MarketRecord
|
||||
]);
|
||||
|
||||
const [headerLine, rowLine] = csv.split("\n");
|
||||
expect(headerLine).toBe(
|
||||
["达人信息", "粉丝数", "21-60s报价", "单视频看后搜率", "个人视频看后搜率"].join(
|
||||
","
|
||||
)
|
||||
);
|
||||
expect(rowLine).toBe('Alice,100w,"¥450,000",0.5% - 1%,1% - 3%');
|
||||
});
|
||||
|
||||
test("escapes commas and quotes", () => {
|
||||
const csv = buildMarketCsv([
|
||||
{
|
||||
@@ -51,7 +77,7 @@ describe("csv-exporter", () => {
|
||||
]);
|
||||
|
||||
const [, rowLine] = csv.split("\n");
|
||||
expect(rowLine).toBe("123,Alice,,,,,failed");
|
||||
expect(rowLine).toBe("123,Alice,,,,");
|
||||
});
|
||||
|
||||
test("uses normalized display values in export rows", () => {
|
||||
|
||||
@@ -10,4 +10,11 @@ describe("manifest", () => {
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
test("declares the downloads permission and background worker for csv export", () => {
|
||||
expect(manifest.permissions).toEqual(
|
||||
expect.arrayContaining(["downloads"])
|
||||
);
|
||||
expect(manifest.background?.service_worker).toBe("background/index.js");
|
||||
});
|
||||
});
|
||||
|
||||
+1124
-56
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,9 @@ import { beforeEach, describe, expect, test } from "vitest";
|
||||
import {
|
||||
applyRowOrder,
|
||||
applyRowVisibility,
|
||||
findNextPageControl,
|
||||
isPageControlDisabled,
|
||||
readMarketPageSignature,
|
||||
renderMarketRowState,
|
||||
syncMarketTable
|
||||
} from "../src/content/market/dom-sync";
|
||||
@@ -154,6 +157,11 @@ describe("market-dom-sync", () => {
|
||||
|
||||
expect(readAuthorNames()).toEqual(["达人 B", "达人 A"]);
|
||||
expect(readRightRowTexts(0)).toEqual(["¥20,000", "", "", "下单"]);
|
||||
expect(table.rows[0].exportFields).toMatchObject({
|
||||
"21-60s报价": "¥450,000",
|
||||
"代表视频": "代表视频A",
|
||||
"达人信息": "达人 A"
|
||||
});
|
||||
});
|
||||
|
||||
test("falls back to the market vue state when the DOM has no author id", () => {
|
||||
@@ -208,6 +216,33 @@ describe("market-dom-sync", () => {
|
||||
singleVideoAfterSearchRate: "0.02%"
|
||||
});
|
||||
});
|
||||
|
||||
test("finds the real next-page button in Xingtu pagination", () => {
|
||||
document.body.innerHTML = `
|
||||
${buildRealMarketGridFixture()}
|
||||
<div class="pagination xt-space xt-space--medium">
|
||||
<div class="el-pagination is-background xt-pagination xt-pagination--normal">
|
||||
<button type="button" disabled="disabled" class="btn-prev">
|
||||
<i class="el-icon el-icon-arrow-left"></i>
|
||||
</button>
|
||||
<ul class="el-pager">
|
||||
<li class="number active">1</li>
|
||||
<li class="number">2</li>
|
||||
</ul>
|
||||
<button type="button" class="btn-next">
|
||||
<i class="el-icon el-icon-arrow-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const nextControl = findNextPageControl(document);
|
||||
|
||||
expect(nextControl).not.toBeNull();
|
||||
expect(nextControl?.className).toContain("btn-next");
|
||||
expect(isPageControlDisabled(nextControl)).toBe(false);
|
||||
expect(readMarketPageSignature(document)).toContain("1::111|222");
|
||||
});
|
||||
});
|
||||
|
||||
function buildRealMarketGridFixture() {
|
||||
|
||||
Reference in New Issue
Block a user