Skip to content

Commit

Permalink
Treat thunk abort signal the same as a false condition result
Browse files Browse the repository at this point in the history
  • Loading branch information
markerikson committed Nov 30, 2022
1 parent 87bebec commit 90ff485
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 12 deletions.
24 changes: 13 additions & 11 deletions packages/toolkit/src/createAsyncThunk.ts
Expand Up @@ -590,18 +590,10 @@ If you want to use the AbortController to react to \`abort\` events, please cons
const abortController = new AC()
let abortReason: string | undefined

const abortedPromise = new Promise<never>((_, reject) =>
abortController.signal.addEventListener('abort', () =>
reject({ name: 'AbortError', message: abortReason || 'Aborted' })
)
)

let started = false
function abort(reason?: string) {
if (started) {
abortReason = reason
abortController.abort()
}
abortReason = reason
abortController.abort()
}

const promise = (async function () {
Expand All @@ -611,14 +603,24 @@ If you want to use the AbortController to react to \`abort\` events, please cons
if (isThenable(conditionResult)) {
conditionResult = await conditionResult
}
if (conditionResult === false) {

if (conditionResult === false || abortController.signal.aborted) {
// eslint-disable-next-line no-throw-literal
throw {
name: 'ConditionError',
message: 'Aborted due to condition callback returning false.',
}
}
started = true

const abortedPromise = new Promise<never>((_, reject) =>
abortController.signal.addEventListener('abort', () =>
reject({
name: 'AbortError',
message: abortReason || 'Aborted',
})
)
)
dispatch(
pending(
requestId,
Expand Down
18 changes: 17 additions & 1 deletion packages/toolkit/src/tests/createAsyncThunk.test.ts
Expand Up @@ -13,6 +13,7 @@ import {
getLog,
} from 'console-testing-library/pure'
import { expectType } from './helpers'
import { delay } from '../utils'

declare global {
interface Window {
Expand Down Expand Up @@ -621,6 +622,21 @@ describe('conditional skipping of asyncThunks', () => {
)
})

test('async condition with AbortController signal first', async () => {
const condition = async () => {
await delay(25)
return true
}
const asyncThunk = createAsyncThunk('test', payloadCreator, { condition })

try {
const thunkPromise = asyncThunk(arg)(dispatch, getState, extra)
thunkPromise.abort()
await thunkPromise
} catch (err) {}
expect(dispatch).toHaveBeenCalledTimes(0)
})

test('rejected action is not dispatched by default', async () => {
const asyncThunk = createAsyncThunk('test', payloadCreator, { condition })
await asyncThunk(arg)(dispatch, getState, extra)
Expand All @@ -630,7 +646,7 @@ describe('conditional skipping of asyncThunks', () => {

test('does not fail when attempting to abort a canceled promise', async () => {
const asyncPayloadCreator = jest.fn(async (x: typeof arg) => {
await new Promise((resolve) => setTimeout(resolve, 2000))
await delay(200)
return 10
})

Expand Down

0 comments on commit 90ff485

Please sign in to comment.