fix: recover favorites controller refresh
This commit is contained in:
@@ -236,6 +236,7 @@ export function createMarketController(options: CreateMarketControllerOptions) {
|
|||||||
let favoritesRefreshVersion = 0;
|
let favoritesRefreshVersion = 0;
|
||||||
let favoriteActionButtons: HTMLButtonElement[] = [];
|
let favoriteActionButtons: HTMLButtonElement[] = [];
|
||||||
let needsFavoritesRefresh = false;
|
let needsFavoritesRefresh = false;
|
||||||
|
let favoritesUnavailable = false;
|
||||||
const favoritesDrawer: FavoritesDrawerController = createFavoritesDrawer(
|
const favoritesDrawer: FavoritesDrawerController = createFavoritesDrawer(
|
||||||
options.document,
|
options.document,
|
||||||
{
|
{
|
||||||
@@ -272,16 +273,19 @@ export function createMarketController(options: CreateMarketControllerOptions) {
|
|||||||
const favoriteControlsMissing =
|
const favoriteControlsMissing =
|
||||||
cachedFavoritesState !== undefined &&
|
cachedFavoritesState !== undefined &&
|
||||||
favoriteActionButtons.some((button) => !button.isConnected);
|
favoriteActionButtons.some((button) => !button.isConnected);
|
||||||
|
const needsUnavailableFavoritesRecovery =
|
||||||
|
favoritesUnavailable && nextPageSignature !== lastKnownPageSignature;
|
||||||
if (
|
if (
|
||||||
nextPageSignature === lastKnownPageSignature &&
|
nextPageSignature === lastKnownPageSignature &&
|
||||||
!toolbarNeedsRemount &&
|
!toolbarNeedsRemount &&
|
||||||
!selectionControlsMissing &&
|
!selectionControlsMissing &&
|
||||||
!favoriteControlsMissing
|
!favoriteControlsMissing &&
|
||||||
|
!needsUnavailableFavoritesRecovery
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (favoriteControlsMissing) {
|
if (favoriteControlsMissing || needsUnavailableFavoritesRecovery) {
|
||||||
needsFavoritesRefresh = true;
|
needsFavoritesRefresh = true;
|
||||||
}
|
}
|
||||||
scheduleSync();
|
scheduleSync();
|
||||||
@@ -529,6 +533,7 @@ export function createMarketController(options: CreateMarketControllerOptions) {
|
|||||||
const ready = (async () => {
|
const ready = (async () => {
|
||||||
await runSyncCycle();
|
await runSyncCycle();
|
||||||
await refreshFavorites();
|
await refreshFavorites();
|
||||||
|
await waitForDomSettled();
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -722,6 +727,7 @@ export function createMarketController(options: CreateMarketControllerOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cachedFavoritesState = state;
|
cachedFavoritesState = state;
|
||||||
|
favoritesUnavailable = false;
|
||||||
favoritesDrawer.setError("");
|
favoritesDrawer.setError("");
|
||||||
favoritesDrawer.render(state);
|
favoritesDrawer.render(state);
|
||||||
runWithoutMutationSync(() => {
|
runWithoutMutationSync(() => {
|
||||||
@@ -734,6 +740,7 @@ export function createMarketController(options: CreateMarketControllerOptions) {
|
|||||||
|
|
||||||
cachedFavoritesState = undefined;
|
cachedFavoritesState = undefined;
|
||||||
favoriteActionButtons = [];
|
favoriteActionButtons = [];
|
||||||
|
favoritesUnavailable = true;
|
||||||
disposeFavoriteRowPickers(options.document);
|
disposeFavoriteRowPickers(options.document);
|
||||||
favoritesDrawer.setError("收藏夹暂不可用");
|
favoritesDrawer.setError("收藏夹暂不可用");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4872,7 +4872,7 @@ describe("market-content-entry", () => {
|
|||||||
expect(document.querySelector('[data-plugin-batch-submit="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 () => {
|
test("recovers favorite pickers after a later refresh failure and page replacement", async () => {
|
||||||
document.body.innerHTML = buildRealMarketFixture([
|
document.body.innerHTML = buildRealMarketFixture([
|
||||||
{ authorId: "111", authorName: "达人 A", price21To60s: "¥11,000" }
|
{ authorId: "111", authorName: "达人 A", price21To60s: "¥11,000" }
|
||||||
]);
|
]);
|
||||||
@@ -4881,12 +4881,13 @@ describe("market-content-entry", () => {
|
|||||||
await repository.setCreatorFolderIds({ authorId: "111", authorName: "达人 A" }, [folder.id]);
|
await repository.setCreatorFolderIds({ authorId: "111", authorName: "达人 A" }, [folder.id]);
|
||||||
const originalRead = repository.read.bind(repository);
|
const originalRead = repository.read.bind(repository);
|
||||||
let shouldRejectRead = false;
|
let shouldRejectRead = false;
|
||||||
repository.read = async () => {
|
const read = vi.fn(async () => {
|
||||||
if (shouldRejectRead) {
|
if (shouldRejectRead) {
|
||||||
throw new Error("storage unavailable");
|
throw new Error("storage unavailable");
|
||||||
}
|
}
|
||||||
return originalRead();
|
return originalRead();
|
||||||
};
|
});
|
||||||
|
repository.read = read;
|
||||||
const observer = createMutationObserverFactory();
|
const observer = createMutationObserverFactory();
|
||||||
|
|
||||||
const { createMarketController } = await import("../src/content/market/index");
|
const { createMarketController } = await import("../src/content/market/index");
|
||||||
@@ -4916,6 +4917,62 @@ describe("market-content-entry", () => {
|
|||||||
|
|
||||||
expect(document.querySelector('[data-sces-favorite-row-action="button"]')).toBeNull();
|
expect(document.querySelector('[data-sces-favorite-row-action="button"]')).toBeNull();
|
||||||
expect(document.querySelector('[data-plugin-export="button"]')).not.toBeNull();
|
expect(document.querySelector('[data-plugin-export="button"]')).not.toBeNull();
|
||||||
|
|
||||||
|
shouldRejectRead = false;
|
||||||
|
document.documentElement.setAttribute("data-test-page-index", "2");
|
||||||
|
document.querySelector('[data-testid="action-cell-111"]')!.replaceChildren(
|
||||||
|
document.createTextNode("下单")
|
||||||
|
);
|
||||||
|
observer.trigger();
|
||||||
|
await waitForCondition(
|
||||||
|
() =>
|
||||||
|
document.querySelector('[data-sces-favorite-row-action="button"]')?.dataset
|
||||||
|
.scesFavoriteState === "saved"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(read).toHaveBeenCalledTimes(3);
|
||||||
|
expect(document.querySelector('[data-sces-favorites-drawer="error"]')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("settles the initial observer resync before ready enables an immediate export", async () => {
|
||||||
|
document.body.innerHTML = buildRealMarketFixture([
|
||||||
|
{ authorId: "111", authorName: "达人 A", price21To60s: "¥11,000" }
|
||||||
|
]);
|
||||||
|
const repository = createTestFavoritesRepository();
|
||||||
|
const originalRead = repository.read.bind(repository);
|
||||||
|
const observer = createMutationObserverFactory();
|
||||||
|
let shouldScheduleInitialResync = true;
|
||||||
|
repository.read = async () => {
|
||||||
|
if (shouldScheduleInitialResync) {
|
||||||
|
shouldScheduleInitialResync = false;
|
||||||
|
document.querySelector('[data-plugin-toolbar="root"]')?.remove();
|
||||||
|
observer.trigger();
|
||||||
|
}
|
||||||
|
return originalRead();
|
||||||
|
};
|
||||||
|
const buildCsv = vi.fn(() => "csv-output");
|
||||||
|
|
||||||
|
const { createMarketController } = await import("../src/content/market/index");
|
||||||
|
const controller = trackController(createMarketController({
|
||||||
|
buildCsv,
|
||||||
|
document,
|
||||||
|
favoritesRepository: repository,
|
||||||
|
loadAuthorMetrics: async () => ({ success: false, reason: "request-failed" }),
|
||||||
|
mutationObserverFactory: observer.factory,
|
||||||
|
onCsvReady: vi.fn(),
|
||||||
|
window
|
||||||
|
}));
|
||||||
|
|
||||||
|
await controller.ready;
|
||||||
|
|
||||||
|
expect(document.querySelector('[data-plugin-toolbar="root"]')).not.toBeNull();
|
||||||
|
setSelectValue('[data-plugin-export-range="select"]', "current");
|
||||||
|
dispatchChange('[data-plugin-export-range="select"]');
|
||||||
|
removeDefaultSpreadMetricFilter();
|
||||||
|
click('[data-plugin-export="button"]');
|
||||||
|
await waitForMockCall(buildCsv, 40, 50);
|
||||||
|
|
||||||
|
expect(buildCsv).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("keeps the friendly drawer error when a direct folder mutation has no message", async () => {
|
test("keeps the friendly drawer error when a direct folder mutation has no message", async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user