fix: preserve favorite identity and ready lifecycle
This commit is contained in:
@@ -4657,6 +4657,75 @@ describe("market-content-entry", () => {
|
||||
).toBe("saved");
|
||||
});
|
||||
|
||||
test("preserves a late serialized core user id through favorite batch import", async () => {
|
||||
document.body.innerHTML = buildRealMarketFixtureWithoutAuthorIds([
|
||||
{ authorName: "达人 A", price21To60s: "¥11,000" }
|
||||
]);
|
||||
const repository = createTestFavoritesRepository();
|
||||
const observer = createMutationObserverFactory();
|
||||
const promptBatchName = vi.fn(() => "收藏夹批次");
|
||||
const promptFavoriteFolderName = vi.fn(() => "母婴优质达人");
|
||||
const submitBatch = vi.fn(async () => ({ ok: true }));
|
||||
|
||||
const { createMarketController } = await import("../src/content/market/index");
|
||||
const controller = trackController(createMarketController({
|
||||
document,
|
||||
favoritesRepository: repository,
|
||||
getAuthState: async () => authenticatedTestState(),
|
||||
loadAuthorMetrics: async () => ({ success: false, reason: "request-failed" }),
|
||||
mutationObserverFactory: observer.factory,
|
||||
promptBatchName,
|
||||
promptFavoriteFolderName,
|
||||
submitBatch,
|
||||
window
|
||||
}));
|
||||
|
||||
await controller.ready;
|
||||
document.documentElement.setAttribute(
|
||||
"data-sces-market-rows",
|
||||
JSON.stringify([
|
||||
{ authorId: "111", authorName: "达人 A", coreUserId: "core-111" }
|
||||
])
|
||||
);
|
||||
document.documentElement.setAttribute("data-test-page-index", "2");
|
||||
observer.trigger();
|
||||
await waitForCondition(
|
||||
() => {
|
||||
const favoriteButton = document.querySelector(
|
||||
'[data-sces-favorite-row-action="button"]'
|
||||
);
|
||||
return favoriteButton instanceof HTMLButtonElement && !favoriteButton.disabled;
|
||||
}
|
||||
);
|
||||
|
||||
click('[data-sces-favorite-row-action="button"]');
|
||||
click('[data-sces-favorite-row-picker="create-folder"]');
|
||||
await waitForCondition(
|
||||
() =>
|
||||
document.querySelector('[data-sces-favorite-row-action="button"]')?.dataset
|
||||
.scesFavoriteState === "saved"
|
||||
);
|
||||
|
||||
click('[data-sces-favorites-tab="button"]');
|
||||
(
|
||||
document.querySelector(
|
||||
'[data-sces-favorites-select-author-id="111"]'
|
||||
) as HTMLInputElement
|
||||
).click();
|
||||
click('[data-sces-favorites-drawer="import-selected"]');
|
||||
await waitForMockCall(submitBatch);
|
||||
|
||||
expect(repository.getStoredState()).toMatchObject({
|
||||
creators: [{ authorId: "111", coreUserId: "core-111" }]
|
||||
});
|
||||
expect(submitBatch).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
authors: [{ authorId: "111", authorName: "达人 A", authorUid: "core-111" }],
|
||||
batchName: "收藏夹批次"
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("renders a creator once in all favorites and in its selected folder", async () => {
|
||||
document.body.innerHTML = buildRealMarketFixture([
|
||||
{ authorId: "111", authorName: "达人 A", price21To60s: "¥11,000" }
|
||||
@@ -5054,6 +5123,89 @@ describe("market-content-entry", () => {
|
||||
expect(maxActiveMetricLoads).toBe(1);
|
||||
});
|
||||
|
||||
test("awaits a follow-up sync triggered during initial scheduled hydration", async () => {
|
||||
document.body.innerHTML = buildRealMarketFixture([
|
||||
{ authorId: "111", authorName: "达人 A", price21To60s: "¥11,000" }
|
||||
]);
|
||||
const repository = createTestFavoritesRepository();
|
||||
const originalRead = repository.read.bind(repository);
|
||||
const observer = createMutationObserverFactory();
|
||||
const successfulMetrics = {
|
||||
rates: {
|
||||
personalVideoAfterSearchRate: "0.2%",
|
||||
singleVideoAfterSearchRate: "0.1%"
|
||||
},
|
||||
success: true as const
|
||||
};
|
||||
const deferredSecondPageMetrics = createDeferred<typeof successfulMetrics>();
|
||||
const deferredThirdPageMetrics = createDeferred<typeof successfulMetrics>();
|
||||
let shouldReplaceInitialPage = true;
|
||||
repository.read = async () => {
|
||||
const state = await originalRead();
|
||||
if (shouldReplaceInitialPage) {
|
||||
shouldReplaceInitialPage = false;
|
||||
document.body.innerHTML = buildRealMarketFixture([
|
||||
{ authorId: "222", authorName: "达人 B", price21To60s: "¥22,000" }
|
||||
]);
|
||||
observer.trigger();
|
||||
}
|
||||
return state;
|
||||
};
|
||||
const loadAuthorMetrics = vi.fn((authorId: string) => {
|
||||
if (authorId === "222") {
|
||||
return deferredSecondPageMetrics.promise;
|
||||
}
|
||||
if (authorId === "333") {
|
||||
return deferredThirdPageMetrics.promise;
|
||||
}
|
||||
return Promise.resolve(successfulMetrics);
|
||||
});
|
||||
|
||||
const { createMarketController } = await import("../src/content/market/index");
|
||||
const controller = trackController(createMarketController({
|
||||
document,
|
||||
favoritesRepository: repository,
|
||||
loadAuthorMetrics,
|
||||
mutationObserverFactory: observer.factory,
|
||||
window
|
||||
}));
|
||||
let readySettled = false;
|
||||
void controller.ready.then(() => {
|
||||
readySettled = true;
|
||||
});
|
||||
|
||||
await waitForCondition(() =>
|
||||
loadAuthorMetrics.mock.calls.some(([authorId]) => authorId === "222")
|
||||
);
|
||||
document.body.innerHTML = buildRealMarketFixture([
|
||||
{ authorId: "333", authorName: "达人 C", price21To60s: "¥33,000" }
|
||||
]);
|
||||
observer.trigger();
|
||||
deferredSecondPageMetrics.resolve(successfulMetrics);
|
||||
await waitForCondition(() =>
|
||||
loadAuthorMetrics.mock.calls.some(([authorId]) => authorId === "333")
|
||||
);
|
||||
await Promise.resolve();
|
||||
|
||||
expect(readySettled).toBe(false);
|
||||
|
||||
deferredThirdPageMetrics.resolve({
|
||||
rates: {
|
||||
personalVideoAfterSearchRate: "0.33%",
|
||||
singleVideoAfterSearchRate: "0.33%"
|
||||
},
|
||||
success: true
|
||||
});
|
||||
await controller.ready;
|
||||
|
||||
expect(
|
||||
document.querySelector('[data-market-selection-checkbox="row"]')?.getAttribute(
|
||||
"data-market-selection-author-id"
|
||||
)
|
||||
).toBe("333");
|
||||
expect(readDivPluginRowTexts(0)[0]).toBe("0.33%");
|
||||
});
|
||||
|
||||
test("keeps the friendly drawer error when a direct folder mutation has no message", async () => {
|
||||
document.body.innerHTML = buildRealMarketFixture([
|
||||
{ authorId: "111", authorName: "达人 A", price21To60s: "¥11,000" }
|
||||
|
||||
@@ -610,6 +610,7 @@ describe("market-dom-sync", () => {
|
||||
{
|
||||
authorId: "111",
|
||||
authorName: "达人 A",
|
||||
coreUserId: "core-111",
|
||||
singleVideoAfterSearchRate: "0.02%"
|
||||
},
|
||||
{
|
||||
@@ -625,6 +626,7 @@ describe("market-dom-sync", () => {
|
||||
}
|
||||
|
||||
expect(table.rows.map((row) => row.authorId)).toEqual(["111", "222"]);
|
||||
expect(table.rows.map((row) => row.coreUserId)).toEqual(["core-111", undefined]);
|
||||
expect(table.rows[0].rates).toEqual({
|
||||
singleVideoAfterSearchRate: "0.02%"
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user