From 730ef73d0fedc87b096529a6e3712dc6ab9d9d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Kamy=C5=9Fev?= Date: Thu, 30 Nov 2023 09:32:30 +0700 Subject: [PATCH] Do not flick `.$status` during cancellation (#411) * Add test case * Do not flick `.$status` during cancellation * Add fix --- .changeset/metal-scissors-collect.md | 5 +++ ...ate_json_query.fetching.concurrent.test.ts | 44 +++++++++++++++++++ .../create_remote_operation.ts | 13 +++++- 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 .changeset/metal-scissors-collect.md diff --git a/.changeset/metal-scissors-collect.md b/.changeset/metal-scissors-collect.md new file mode 100644 index 000000000..38494d621 --- /dev/null +++ b/.changeset/metal-scissors-collect.md @@ -0,0 +1,5 @@ +--- +'@farfetched/core': patch +--- + +Do not flick `.$status` during cancellation diff --git a/packages/core/src/query/__tests__/create_json_query.fetching.concurrent.test.ts b/packages/core/src/query/__tests__/create_json_query.fetching.concurrent.test.ts index 922215bab..fc3214dfd 100644 --- a/packages/core/src/query/__tests__/create_json_query.fetching.concurrent.test.ts +++ b/packages/core/src/query/__tests__/create_json_query.fetching.concurrent.test.ts @@ -188,4 +188,48 @@ describe('createJsonQuery concurrency.strategy', () => { expect.objectContaining({ error: abortError() }) ); }); + + test('do not flick $status', async () => { + const query = createJsonQuery({ + request: { method: 'GET', url: 'https://api.salo.com' }, + response: { contract: unknownContract }, + concurrency: { strategy: 'TAKE_LATEST' }, + }); + + const statusListener = vi.fn(); + const abortedListener = vi.fn(); + + const scope = fork({ + handlers: [ + [ + // We have to mock fetchFx because executeFx contains cancellation logic + fetchFx, + vi.fn().mockImplementation(async () => { + await setTimeout(100); + throw new Error('cannot'); + }), + ], + ], + }); + + createWatch({ unit: query.$status, fn: statusListener, scope }); + createWatch({ unit: query.aborted, fn: abortedListener, scope }); + + allSettled(query.start, { scope }); + allSettled(query.start, { scope }); + + await allSettled(scope); + + expect(abortedListener).toBeCalledTimes(1); + expect(statusListener.mock.calls).toMatchInlineSnapshot(` + [ + [ + "pending", + ], + [ + "fail", + ], + ] + `); + }); }); diff --git a/packages/core/src/remote_operation/create_remote_operation.ts b/packages/core/src/remote_operation/create_remote_operation.ts index a4dbfe2d8..22721cce9 100644 --- a/packages/core/src/remote_operation/create_remote_operation.ts +++ b/packages/core/src/remote_operation/create_remote_operation.ts @@ -214,8 +214,17 @@ export function createRemoteOperation< finished.failure.map(() => 'fail' as const), sample({ clock: aborted, - source: $statusHistory, - fn: (history) => history[history.length - 2] ?? 'initial', + source: { + history: $statusHistory, + retrieveDataPengind: retrieveDataFx.pending, + }, + fn: ({ history, retrieveDataPengind }) => { + if (retrieveDataPengind) { + return 'pending'; + } + + return history[history.length - 2] ?? 'initial'; + }, }), ], target: $status,