diff --git a/test/use-swr-local-mutation.test.tsx b/test/use-swr-local-mutation.test.tsx
index ba9918b66..65c64a15f 100644
--- a/test/use-swr-local-mutation.test.tsx
+++ b/test/use-swr-local-mutation.test.tsx
@@ -1,7 +1,9 @@
import { act, render, screen, fireEvent } from '@testing-library/react'
import React, { useEffect, useState } from 'react'
import useSWR, { mutate, cache } from '../src'
-import { sleep } from './utils'
+import { createResponse, sleep } from './utils'
+
+const waitForNextTick = () => act(() => sleep(1))
describe('useSWR - local mutation', () => {
it('should trigger revalidation programmatically', async () => {
@@ -13,10 +15,10 @@ describe('useSWR - local mutation', () => {
})
return
data: {data}
}
- const { container } = render()
+ render()
// hydration
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: "`)
+ screen.getByText('data:')
// mount
await screen.findByText('data: 0')
@@ -25,9 +27,7 @@ describe('useSWR - local mutation', () => {
// mutate and revalidate
mutate('dynamic-7')
})
- await act(() => sleep(1))
-
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: 1"`)
+ await screen.findByText('data: 1')
})
it('should trigger revalidation programmatically within a dedupingInterval', async () => {
@@ -39,10 +39,11 @@ describe('useSWR - local mutation', () => {
})
return data: {data}
}
- const { container } = render()
+ render()
// hydration
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: "`)
+ screen.getByText('data:')
+
// mount
await screen.findByText('data: 0')
@@ -50,9 +51,7 @@ describe('useSWR - local mutation', () => {
// trigger revalidation
mutate('dynamic-12')
})
- await act(() => sleep(1))
-
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: 1"`)
+ await screen.findByText('data: 1')
})
it('should mutate the cache and revalidate', async () => {
@@ -64,10 +63,10 @@ describe('useSWR - local mutation', () => {
})
return data: {data}
}
- const { container } = render()
+ render()
// hydration
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: "`)
+ screen.getByText('data:')
//mount
await screen.findByText('data: 0')
@@ -76,8 +75,7 @@ describe('useSWR - local mutation', () => {
// mutate and revalidate
mutate('dynamic-8', 'mutate')
})
- await act(() => sleep(1))
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: 1"`)
+ await screen.findByText('data: 1')
})
it('should dedupe extra requests after mutation', async () => {
@@ -92,10 +90,10 @@ describe('useSWR - local mutation', () => {
})
return data: {data}
}
- const { container } = render()
+ render()
// hydration
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: "`)
+ screen.getByText('data:')
//mount
await screen.findByText('data: 0')
@@ -103,23 +101,21 @@ describe('useSWR - local mutation', () => {
// mutate and revalidate
mutate('dynamic-13')
})
- await act(() => sleep(1))
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: 1"`)
+ await screen.findByText('data: 1')
})
it('should mutate the cache and revalidate in async', async () => {
function Page() {
- const { data } = useSWR(
- 'dynamic-9',
- () => new Promise(res => setTimeout(() => res('truth'), 200)),
- { dedupingInterval: 0 }
- )
+ const { data } = useSWR('dynamic-9', () => createResponse('truth'), {
+ dedupingInterval: 0
+ })
return data: {data}
}
- const { container } = render()
+ render()
// hydration
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: "`)
+ screen.getByText('data:')
+
//mount
await screen.findByText('data: truth')
@@ -127,17 +123,11 @@ describe('useSWR - local mutation', () => {
// mutate and revalidate
mutate('dynamic-9', 'local')
})
- await act(() => sleep(1))
-
- expect(container.firstChild.textContent).toMatchInlineSnapshot(
- `"data: local"`
- )
- await act(() => sleep(200)) // recovers
+ await screen.findByText('data: local')
- expect(container.firstChild.textContent).toMatchInlineSnapshot(
- `"data: truth"`
- )
+ // recovers
+ await screen.findByText('data: truth')
})
it('should support async mutation with promise', async () => {
@@ -147,24 +137,20 @@ describe('useSWR - local mutation', () => {
})
return data: {data}
}
- const { container } = render()
+ render()
// hydration
- expect(container.textContent).toMatchInlineSnapshot(`"data: "`)
+ screen.getByText('data:')
//mount
await screen.findByText('data: 0')
- await act(() => sleep(1))
+
+ await waitForNextTick()
await act(() => {
// mutate and revalidate
- return mutate(
- 'mutate-promise',
- new Promise(res => setTimeout(() => res(999), 100)),
- false
- )
+ return mutate('mutate-promise', createResponse(999), false)
})
- await act(() => sleep(110))
- expect(container.textContent).toMatchInlineSnapshot(`"data: 999"`)
+ await screen.findByText('data: 999')
})
it('should support async mutation with async function', async () => {
@@ -174,22 +160,18 @@ describe('useSWR - local mutation', () => {
})
return data: {data}
}
- const { container } = render()
+ render()
// hydration
- expect(container.textContent).toMatchInlineSnapshot(`"data: "`)
+ screen.getByText('data:')
+
//mount
await screen.findByText('data: 0')
- // wait for the next tick
- await act(() => sleep(1))
+ await waitForNextTick()
await act(() => {
// mutate and revalidate
- return mutate(
- 'mutate-async-fn',
- async () => new Promise(res => setTimeout(() => res(999), 100)),
- false
- )
+ return mutate('mutate-async-fn', async () => createResponse(999), false)
})
await screen.findByText('data: 999')
})
@@ -203,10 +185,10 @@ describe('useSWR - local mutation', () => {
})
return data: {data}
}
- const { container } = render()
+ render()
// hydration
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: "`)
+ screen.getByText('data:')
//mount
await screen.findByText('data: 0')
@@ -215,8 +197,7 @@ describe('useSWR - local mutation', () => {
// trigger revalidation
mutate('dynamic-14')
})
- await act(() => sleep(1))
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: 1"`)
+ await screen.findByText('data: 1')
})
it('should call function as data passing current cached value', async () => {
@@ -268,19 +249,18 @@ describe('useSWR - local mutation', () => {
boundMutate('mutated', false)}>data: {data}
)
}
- const { container } = render()
+ render()
// hydration
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: "`)
+ screen.getByText('data:')
+
//mount
await screen.findByText('data: fetched')
+
// call bound mutate
- fireEvent.click(container.firstElementChild)
+ fireEvent.click(screen.getByText('data: fetched'))
// expect new updated value (after a tick)
- await act(async () => await 0)
- expect(container.firstChild.textContent).toMatchInlineSnapshot(
- `"data: mutated"`
- )
+ await screen.findByText('data: mutated')
})
it('should ignore in flight requests when mutating', async () => {
@@ -290,61 +270,54 @@ describe('useSWR - local mutation', () => {
})
function Section() {
- const { data } = useSWR(
- 'mutate-2',
- () => new Promise(res => setTimeout(() => res(2), 200))
+ const { data } = useSWR('mutate-2', () =>
+ createResponse(2, { delay: 150 })
)
return {data}
}
- const { container } = render()
-
- expect(container.textContent).toMatchInlineSnapshot(`"1"`) // directly from cache
- await act(() => sleep(150)) // still suspending
+ render()
+ screen.getByText('1') // directly from cache
+ await act(() => sleep(100)) // still suspending
act(() => {
mutate('mutate-2', 3)
}) // set it to 3. this will drop the ongoing request
- await act(async () => await 0)
- expect(container.textContent).toMatchInlineSnapshot(`"3"`)
+
+ await screen.findByText('3')
+
await act(() => sleep(100))
- expect(container.textContent).toMatchInlineSnapshot(`"3"`)
+ screen.getByText('3')
})
it('should ignore in flight mutations when calling another async mutate', async () => {
let value = 'off'
function Page() {
- const { data } = useSWR(
- 'mutate-3',
- () => new Promise(res => setTimeout(() => res(value), 200))
+ const { data } = useSWR('mutate-3', () =>
+ createResponse(value, { delay: 100 })
)
return {data}
}
- const { container } = render()
+ render()
- await act(() => sleep(250))
- expect(container.textContent).toMatchInlineSnapshot(`"off"`) // Initial state
+ await screen.findByText('off') // Initial state
act(() => {
mutate('mutate-3', 'on', false)
})
-
// Validate local state is now "on"
- await act(async () => await 0)
- expect(container.textContent).toMatchInlineSnapshot(`"on"`)
+ await screen.findByText('on')
// Simulate toggling "on"
await act(async () => {
expect(
mutate(
'mutate-3',
- new Promise(res =>
- setTimeout(() => {
- value = 'on'
- res('on')
- }, 200)
- ),
+ () => {
+ value = 'on'
+ return createResponse('on', { delay: 100 })
+ },
false
)
).resolves.toBe('on')
@@ -355,32 +328,29 @@ describe('useSWR - local mutation', () => {
})
// Validate local state is now "off"
- await act(async () => await 0)
- expect(container.textContent).toMatchInlineSnapshot(`"off"`)
+ await screen.findByText('off')
// Simulate toggling "off"
await act(async () => {
expect(
mutate(
'mutate-3',
- new Promise(res =>
- setTimeout(() => {
- value = 'off'
- res('off')
- }, 400)
- ),
+ () => {
+ value = 'off'
+ return createResponse('off', { delay: 100 })
+ },
false
)
).resolves.toBe('off')
})
// Wait for toggling "on" promise to resolve, but the "on" mutation is cancelled
- await act(() => sleep(210))
- expect(container.textContent).toMatchInlineSnapshot(`"off"`)
+ await act(() => sleep(50))
+ screen.getByText('off')
// Wait for toggling "off" promise to resolve
- await act(() => sleep(210))
- expect(container.textContent).toMatchInlineSnapshot(`"off"`)
+ await act(() => sleep(100))
+ screen.getByText('off')
})
it('null is stringified when found inside an array', async () => {
@@ -392,18 +362,19 @@ describe('useSWR - local mutation', () => {
})
return data: {data}
}
- const { container } = render()
+ render()
// hydration
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: "`)
+ screen.getByText('data:')
+
//mount
await screen.findByText('data: 0')
+
act(() => {
// trigger revalidation
mutate([null])
})
- await act(() => sleep(1))
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: 1"`)
+ await screen.findByText('data: 1')
})
it('should return promise from mutate without data', async () => {
@@ -414,10 +385,13 @@ describe('useSWR - local mutation', () => {
})
return data: {data}
}
- const { container } = render()
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: "`)
+
+ render()
+ screen.getByText('data:')
+
// mount
await screen.findByText('data: 0')
+
let promise
await act(() => {
promise = mutate('dynamic-18')
@@ -425,7 +399,7 @@ describe('useSWR - local mutation', () => {
})
expect(promise).toBeInstanceOf(Promise) // mutate returns a promise
expect(promise).resolves.toBe(1) // the return value should be the new cache
- expect(container.firstChild.textContent).toMatchInlineSnapshot(`"data: 1"`)
+ screen.getByText('data: 1')
})
it('should update error in cache when mutate failed with error', async () => {
@@ -436,7 +410,9 @@ describe('useSWR - local mutation', () => {
const { data, error } = useSWR(key, () => value)
return {error ? error.message : `data: ${data}`}
}
- const { container } = render()
+
+ render()
+
//mount
await screen.findByText('data: 0')
await act(async () => {
@@ -454,18 +430,15 @@ describe('useSWR - local mutation', () => {
}
})
+ screen.getByText(message)
const [keyData, , keyErr] = cache.serializeKey(key)
let cacheError = cache.get(keyErr)
expect(cacheError.message).toMatchInlineSnapshot(`"${message}"`)
- expect(container.firstChild.textContent).toMatchInlineSnapshot(
- `"${message}"`
- )
// if mutate throws an error synchronously, the cache shouldn't be updated
expect(cache.get(keyData)).toBe(value)
+
// if mutate succeed, error should be cleared
- await act(async () => {
- return mutate(key, value, false)
- })
+ await act(() => mutate(key, value, false))
cacheError = cache.get(keyErr)
expect(cacheError).toMatchInlineSnapshot(`undefined`)
})
@@ -475,13 +448,10 @@ describe('useSWR - local mutation', () => {
function Section() {
const [key, setKey] = useState(null)
- const { data, mutate: boundMutate } = useSWR(
- key,
- () => new Promise(res => setTimeout(() => res(1), 10))
- )
+ const { data, mutate: boundMutate } = useSWR(key, () => createResponse(1))
useEffect(() => {
- const timeout = setTimeout(() => setKey('mutate-5'), 100)
+ const timeout = setTimeout(() => setKey('mutate-5'), 50)
return () => clearTimeout(timeout)
}, [])
@@ -490,7 +460,7 @@ describe('useSWR - local mutation', () => {
}
render()
- await act(() => sleep(120))
+ await act(() => sleep(100))
act(() => {
mutate('mutate-5', 2)
})
@@ -533,7 +503,6 @@ describe('useSWR - local mutation', () => {
render()
await act(() => sleep(50))
-
expect(mutationRecivedValues).toEqual([0, 1])
expect(renderRecivedValues).toEqual([undefined, 0, 1, 2])
})