fix: format business ability estimates
This commit is contained in:
parent
249e6a5971
commit
39c4191a95
@ -158,19 +158,19 @@ export function mapBusinessAbilityEstimateResponse(
|
|||||||
return {
|
return {
|
||||||
oneToTwenty: {
|
oneToTwenty: {
|
||||||
expectedCpe: formatDecimal(readNumber(data?.cpe_1_20), 1),
|
expectedCpe: formatDecimal(readNumber(data?.cpe_1_20), 1),
|
||||||
expectedCpm: formatDecimal(readNumber(data?.cpm_1_20), 0),
|
expectedCpm: formatFixedDecimal(readNumber(data?.cpm_1_20), 1),
|
||||||
expectedPlay,
|
expectedPlay,
|
||||||
hotRate
|
hotRate
|
||||||
},
|
},
|
||||||
overSixty: {
|
overSixty: {
|
||||||
expectedCpe: formatDecimal(readNumber(data?.cpe_60), 1),
|
expectedCpe: formatDecimal(readNumber(data?.cpe_60), 1),
|
||||||
expectedCpm: formatDecimal(readNumber(data?.cpm_60), 0),
|
expectedCpm: formatFixedDecimal(readNumber(data?.cpm_60), 1),
|
||||||
expectedPlay,
|
expectedPlay,
|
||||||
hotRate
|
hotRate
|
||||||
},
|
},
|
||||||
twentyToSixty: {
|
twentyToSixty: {
|
||||||
expectedCpe: formatDecimal(readNumber(data?.cpe_20_60), 1),
|
expectedCpe: formatDecimal(readNumber(data?.cpe_20_60), 1),
|
||||||
expectedCpm: formatDecimal(readNumber(data?.cpm_20_60), 0),
|
expectedCpm: formatFixedDecimal(readNumber(data?.cpm_20_60), 1),
|
||||||
expectedPlay,
|
expectedPlay,
|
||||||
hotRate
|
hotRate
|
||||||
}
|
}
|
||||||
@ -203,7 +203,7 @@ function formatBasisPointRate(value: number | null): string {
|
|||||||
|
|
||||||
function formatDecimalRate(value: number | null): string {
|
function formatDecimalRate(value: number | null): string {
|
||||||
if (value === null) {
|
if (value === null) {
|
||||||
return "";
|
return "缺失";
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${formatDecimal(value * 100, 0)}%`;
|
return `${formatDecimal(value * 100, 0)}%`;
|
||||||
@ -230,6 +230,14 @@ function formatDecimal(value: number | null, digits: number): string {
|
|||||||
return fixed.replace(/\.0+$/, "").replace(/(\.\d*?)0+$/, "$1");
|
return fixed.replace(/\.0+$/, "").replace(/(\.\d*?)0+$/, "$1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatFixedDecimal(value: number | null, digits: number): string {
|
||||||
|
if (value === null || !Number.isFinite(value)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.toFixed(digits);
|
||||||
|
}
|
||||||
|
|
||||||
function readNestedNumber(
|
function readNestedNumber(
|
||||||
data: Record<string, unknown> | null,
|
data: Record<string, unknown> | null,
|
||||||
objectKey: string,
|
objectKey: string,
|
||||||
|
|||||||
@ -39,15 +39,15 @@ describe("audience-profile-csv", () => {
|
|||||||
estimates: {
|
estimates: {
|
||||||
oneToTwenty: {
|
oneToTwenty: {
|
||||||
expectedCpe: "2.1",
|
expectedCpe: "2.1",
|
||||||
expectedCpm: "120",
|
expectedCpm: "120.0",
|
||||||
expectedPlay: "250w",
|
expectedPlay: "250w",
|
||||||
hotRate: "100%"
|
hotRate: "100%"
|
||||||
},
|
},
|
||||||
twentyToSixty: {
|
twentyToSixty: {
|
||||||
expectedCpe: "3.7",
|
expectedCpe: "3.7",
|
||||||
expectedCpm: "212",
|
expectedCpm: "212.0",
|
||||||
expectedPlay: "250w",
|
expectedPlay: "250w",
|
||||||
hotRate: "100%"
|
hotRate: "缺失"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
status: "success",
|
status: "success",
|
||||||
@ -109,8 +109,8 @@ describe("audience-profile-csv", () => {
|
|||||||
expect(rowLine).toContain("60%");
|
expect(rowLine).toContain("60%");
|
||||||
expect(readCsvValue(csv, "商业能力-个人视频-播放量中位数")).toBe("3738.4w");
|
expect(readCsvValue(csv, "商业能力-个人视频-播放量中位数")).toBe("3738.4w");
|
||||||
expect(readCsvValue(csv, "商业能力-星图视频-平均转发")).toBe("68.4w");
|
expect(readCsvValue(csv, "商业能力-星图视频-平均转发")).toBe("68.4w");
|
||||||
expect(readCsvValue(csv, "商业能力-1-20s视频-预期CPM")).toBe("120");
|
expect(readCsvValue(csv, "商业能力-1-20s视频-预期CPM")).toBe("120.0");
|
||||||
expect(readCsvValue(csv, "商业能力-20-60s视频-爆文率")).toBe("100%");
|
expect(readCsvValue(csv, "商业能力-20-60s视频-爆文率")).toBe("缺失");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("leaves distribution cells empty when profile loading fails", () => {
|
test("leaves distribution cells empty when profile loading fails", () => {
|
||||||
|
|||||||
@ -47,25 +47,57 @@ describe("business-ability-client", () => {
|
|||||||
expect(mapBusinessAbilityEstimateResponse(buildEstimatePayload())).toEqual({
|
expect(mapBusinessAbilityEstimateResponse(buildEstimatePayload())).toEqual({
|
||||||
oneToTwenty: {
|
oneToTwenty: {
|
||||||
expectedCpe: "2.1",
|
expectedCpe: "2.1",
|
||||||
expectedCpm: "120",
|
expectedCpm: "120.0",
|
||||||
expectedPlay: "250w",
|
expectedPlay: "250w",
|
||||||
hotRate: "100%"
|
hotRate: "100%"
|
||||||
},
|
},
|
||||||
overSixty: {
|
overSixty: {
|
||||||
expectedCpe: "4.2",
|
expectedCpe: "4.2",
|
||||||
expectedCpm: "240",
|
expectedCpm: "240.0",
|
||||||
expectedPlay: "250w",
|
expectedPlay: "250w",
|
||||||
hotRate: "100%"
|
hotRate: "100%"
|
||||||
},
|
},
|
||||||
twentyToSixty: {
|
twentyToSixty: {
|
||||||
expectedCpe: "3.7",
|
expectedCpe: "3.7",
|
||||||
expectedCpm: "212",
|
expectedCpm: "212.0",
|
||||||
expectedPlay: "250w",
|
expectedPlay: "250w",
|
||||||
hotRate: "100%"
|
hotRate: "100%"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("keeps decimal CPM values and marks missing hot rate", () => {
|
||||||
|
expect(mapBusinessAbilityEstimateResponse({
|
||||||
|
base_resp: { status_code: 0, status_message: "" },
|
||||||
|
cpe_1_20: "1.6347",
|
||||||
|
cpe_20_60: "2.002",
|
||||||
|
cpe_60: "2.104",
|
||||||
|
cpm_1_20: "21.7955",
|
||||||
|
cpm_20_60: "27.5628",
|
||||||
|
cpm_60: "29.877",
|
||||||
|
vv: "1010234"
|
||||||
|
})).toEqual({
|
||||||
|
oneToTwenty: {
|
||||||
|
expectedCpe: "1.6",
|
||||||
|
expectedCpm: "21.8",
|
||||||
|
expectedPlay: "101w",
|
||||||
|
hotRate: "缺失"
|
||||||
|
},
|
||||||
|
overSixty: {
|
||||||
|
expectedCpe: "2.1",
|
||||||
|
expectedCpm: "29.9",
|
||||||
|
expectedPlay: "101w",
|
||||||
|
hotRate: "缺失"
|
||||||
|
},
|
||||||
|
twentyToSixty: {
|
||||||
|
expectedCpe: "2",
|
||||||
|
expectedCpm: "27.6",
|
||||||
|
expectedPlay: "101w",
|
||||||
|
hotRate: "缺失"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test("loads personal video, Xingtu video, and duration estimate metrics", async () => {
|
test("loads personal video, Xingtu video, and duration estimate metrics", async () => {
|
||||||
const requestedUrls: string[] = [];
|
const requestedUrls: string[] = [];
|
||||||
const fetchImpl = vi.fn(async (input: string) => {
|
const fetchImpl = vi.fn(async (input: string) => {
|
||||||
@ -92,7 +124,7 @@ describe("business-ability-client", () => {
|
|||||||
})
|
})
|
||||||
).resolves.toMatchObject({
|
).resolves.toMatchObject({
|
||||||
estimates: expect.objectContaining({
|
estimates: expect.objectContaining({
|
||||||
twentyToSixty: expect.objectContaining({ expectedCpm: "212" })
|
twentyToSixty: expect.objectContaining({ expectedCpm: "212.0" })
|
||||||
}),
|
}),
|
||||||
status: "success",
|
status: "success",
|
||||||
videos: {
|
videos: {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user