Skip to content

Commit a4443b1

Browse files
author
alex-vuong_sfemu
committed
Sync from monorepo
Template version: 1.0.0-alpha.0 Uses NPM packages @salesforce/storefront-next-* v1.0.0-alpha.0 Synced by: alex-vuong_sfemu Monorepo SHA: e0139adc75f182232acd1bd53fd40038c451752c Latest change: e0139adc7 - fix(wishlist): skip 1.5s sleep when create response has id (#1893)
1 parent 1dbd1ea commit a4443b1

3 files changed

Lines changed: 78 additions & 6 deletions

File tree

pnpm-lock.yaml

Lines changed: 10 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/api/wishlist.server.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { TrackingConsent } from '@/types/tracking-consent';
2121
import {
2222
appendWishlistMergeFlag,
2323
captureGuestWishlistSnapshot,
24+
getOrCreateWishlist,
2425
getWishlist,
2526
loadWishlistPageData,
2627
mergeWishlist,
@@ -687,3 +688,56 @@ describe('appendWishlistMergeFlag', () => {
687688
expect(result2.setCookie).toContain('wishlist_merge');
688689
});
689690
});
691+
692+
describe('getOrCreateWishlist — create branch', () => {
693+
const mockContext = {} as any;
694+
695+
beforeEach(() => {
696+
vi.clearAllMocks();
697+
});
698+
699+
test('fast path: returns the POST body without re-fetching when id is present', async () => {
700+
// No existing list: getCustomerProductLists returns empty.
701+
mockGetCustomerProductLists.mockResolvedValueOnce({ data: { data: [] } });
702+
703+
const created = { id: 'list-new', type: 'wish_list', customerProductListItems: [] };
704+
mockCreateCustomerProductList.mockResolvedValue({ data: created });
705+
706+
const result = await getOrCreateWishlist(mockContext, 'cust-1');
707+
708+
expect(result).toEqual(created);
709+
expect(mockCreateCustomerProductList).toHaveBeenCalledTimes(1);
710+
// Only the initial lookup before create — no second GET after the POST.
711+
expect(mockGetCustomerProductLists).toHaveBeenCalledTimes(1);
712+
expect(mockLoggerWarn).not.toHaveBeenCalled();
713+
});
714+
715+
test('fallback path: waits for index, re-fetches when POST returns no id', async () => {
716+
vi.useFakeTimers();
717+
try {
718+
// No existing list: initial lookup empty.
719+
// After the create, the post-sleep GET returns the indexed list.
720+
const created = { id: 'list-indexed', type: 'wish_list', customerProductListItems: [] };
721+
mockGetCustomerProductLists
722+
.mockResolvedValueOnce({ data: { data: [] } })
723+
.mockResolvedValueOnce({ data: { data: [created] } });
724+
725+
// POST resolves with a body that lacks id (the schema-anomaly we're guarding against).
726+
mockCreateCustomerProductList.mockResolvedValue({ data: { type: 'wish_list' } });
727+
728+
const promise = getOrCreateWishlist(mockContext, 'cust-1');
729+
await vi.advanceTimersByTimeAsync(1500);
730+
const result = await promise;
731+
732+
expect(result).toEqual(created);
733+
expect(mockCreateCustomerProductList).toHaveBeenCalledTimes(1);
734+
expect(mockGetCustomerProductLists).toHaveBeenCalledTimes(2);
735+
expect(mockLoggerWarn).toHaveBeenCalledWith(
736+
'Wishlist: createCustomerProductList returned without an id, waiting for index propagation',
737+
expect.objectContaining({ customerId: 'cust-1' })
738+
);
739+
} finally {
740+
vi.useRealTimers();
741+
}
742+
});
743+
});

src/lib/api/wishlist.server.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,13 @@ export async function getOrCreateWishlist(
224224
throw new Error(t('account:wishlist.unableToRetrieveId'));
225225
}
226226

227-
// Create a new wishlist if it doesn't exist.
228-
// Commerce SDK createCustomerProductList might not return listId immediately
229-
// so we re-fetch after creation.
230-
await clients.shopperCustomers.createCustomerProductList({
227+
// Create a new wishlist if it doesn't exist. The POST response body comes from the
228+
// write path and is not subject to the index-propagation delay that affects the GET
229+
// endpoints (see the retry branch above and the comment in getWishlist). When the
230+
// response carries an id we can return it immediately. Only when it doesn't do we
231+
// wait for the index to catch up and re-read — the original behavior — because that
232+
// GET is what the indexing-delay sleep was protecting all along.
233+
const { data: created } = await clients.shopperCustomers.createCustomerProductList({
231234
params: {
232235
path: { customerId },
233236
},
@@ -238,6 +241,13 @@ export async function getOrCreateWishlist(
238241
},
239242
});
240243

244+
if (created?.id) {
245+
return created;
246+
}
247+
248+
logger.warn('Wishlist: createCustomerProductList returned without an id, waiting for index propagation', {
249+
customerId,
250+
});
241251
await new Promise((resolve) => setTimeout(resolve, WISHLIST_CREATION_DELAY_MS));
242252

243253
const { wishlist: createdWishlist, id: createdListId } = await getWishlist(context, customerId);

0 commit comments

Comments
 (0)