fix: harden favorites controller lifecycle
This commit is contained in:
@@ -4573,6 +4573,43 @@ describe("market-content-entry", () => {
|
||||
expect(document.querySelector('[data-testid="action-cell-111"]')?.textContent).toContain("下单");
|
||||
});
|
||||
|
||||
test("disposes an open favorite picker without retaining row callbacks", async () => {
|
||||
document.body.innerHTML = buildRealMarketFixture([
|
||||
{ authorId: "111", authorName: "达人 A", price21To60s: "¥11,000" }
|
||||
]);
|
||||
const repository = createTestFavoritesRepository();
|
||||
const createFolder = vi.fn(repository.createFolder.bind(repository));
|
||||
const setCreatorFolderIds = vi.fn(repository.setCreatorFolderIds.bind(repository));
|
||||
repository.createFolder = createFolder;
|
||||
repository.setCreatorFolderIds = setCreatorFolderIds;
|
||||
|
||||
const { createMarketController } = await import("../src/content/market/index");
|
||||
const controller = createMarketController({
|
||||
document,
|
||||
favoritesRepository: repository,
|
||||
loadAuthorMetrics: async () => ({ success: false, reason: "request-failed" }),
|
||||
window
|
||||
});
|
||||
|
||||
await controller.ready;
|
||||
const favoriteButton = document.querySelector(
|
||||
'[data-sces-favorite-row-action="button"]'
|
||||
) as HTMLButtonElement;
|
||||
favoriteButton.click();
|
||||
expect(document.querySelector('[data-sces-favorite-row-picker="root"]')).not.toBeNull();
|
||||
|
||||
controller.dispose();
|
||||
|
||||
expect(document.querySelector('[data-sces-favorite-row-picker="root"]')).toBeNull();
|
||||
document.body.dispatchEvent(new Event("pointerdown", { bubbles: true }));
|
||||
document.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape" }));
|
||||
favoriteButton.click();
|
||||
await flush();
|
||||
|
||||
expect(createFolder).not.toHaveBeenCalled();
|
||||
expect(setCreatorFolderIds).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("saves the serialized market row identity through its favorite picker", async () => {
|
||||
document.body.innerHTML = buildRealMarketFixtureWithoutAuthorIds([
|
||||
{ authorName: "达人 A", price21To60s: "¥11,000" }
|
||||
@@ -4834,6 +4871,85 @@ describe("market-content-entry", () => {
|
||||
expect(document.querySelector('[data-plugin-export="button"]')).not.toBeNull();
|
||||
expect(document.querySelector('[data-plugin-batch-submit="button"]')).not.toBeNull();
|
||||
});
|
||||
|
||||
test("clears stale favorite pickers when a later repository refresh fails", async () => {
|
||||
document.body.innerHTML = buildRealMarketFixture([
|
||||
{ authorId: "111", authorName: "达人 A", price21To60s: "¥11,000" }
|
||||
]);
|
||||
const repository = createTestFavoritesRepository();
|
||||
const folder = await repository.createFolder("母婴优质达人");
|
||||
await repository.setCreatorFolderIds({ authorId: "111", authorName: "达人 A" }, [folder.id]);
|
||||
const originalRead = repository.read.bind(repository);
|
||||
let shouldRejectRead = false;
|
||||
repository.read = async () => {
|
||||
if (shouldRejectRead) {
|
||||
throw new Error("storage unavailable");
|
||||
}
|
||||
return originalRead();
|
||||
};
|
||||
const observer = createMutationObserverFactory();
|
||||
|
||||
const { createMarketController } = await import("../src/content/market/index");
|
||||
const controller = trackController(createMarketController({
|
||||
document,
|
||||
favoritesRepository: repository,
|
||||
loadAuthorMetrics: async () => ({ success: false, reason: "request-failed" }),
|
||||
mutationObserverFactory: observer.factory,
|
||||
window
|
||||
}));
|
||||
|
||||
await controller.ready;
|
||||
expect(
|
||||
document.querySelector('[data-sces-favorite-row-action="button"]')?.dataset.scesFavoriteState
|
||||
).toBe("saved");
|
||||
|
||||
shouldRejectRead = true;
|
||||
document.querySelector('[data-testid="action-cell-111"]')!.replaceChildren(
|
||||
document.createTextNode("下单")
|
||||
);
|
||||
observer.trigger();
|
||||
await waitForCondition(
|
||||
() =>
|
||||
document.querySelector('[data-sces-favorites-drawer="error"]')?.textContent ===
|
||||
"收藏夹暂不可用"
|
||||
);
|
||||
|
||||
expect(document.querySelector('[data-sces-favorite-row-action="button"]')).toBeNull();
|
||||
expect(document.querySelector('[data-plugin-export="button"]')).not.toBeNull();
|
||||
});
|
||||
|
||||
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" }
|
||||
]);
|
||||
const repository = createTestFavoritesRepository();
|
||||
repository.createFolder = async () => {
|
||||
throw new Error();
|
||||
};
|
||||
|
||||
const { createMarketController } = await import("../src/content/market/index");
|
||||
const controller = trackController(createMarketController({
|
||||
document,
|
||||
favoritesRepository: repository,
|
||||
loadAuthorMetrics: async () => ({ success: false, reason: "request-failed" }),
|
||||
promptFavoriteFolderName: () => "不应出现的收藏夹",
|
||||
window
|
||||
}));
|
||||
|
||||
await controller.ready;
|
||||
click('[data-sces-favorites-tab="button"]');
|
||||
click('[data-sces-favorites-drawer="create-folder"]');
|
||||
await waitForCondition(
|
||||
() =>
|
||||
document.querySelector('[data-sces-favorites-drawer="error"]')?.textContent ===
|
||||
"收藏夹操作失败,请稍后重试"
|
||||
);
|
||||
|
||||
expect(document.querySelectorAll('[data-sces-favorites-folder-id]')).toHaveLength(0);
|
||||
expect(document.querySelector('[data-sces-favorites-drawer="creators"]')?.textContent).toContain(
|
||||
"暂无收藏达人"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
function clearLocalStorage(): void {
|
||||
|
||||
Reference in New Issue
Block a user