Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ Refactor Focus Manager Event Handling for Enhanced User Experience ✨ #2672

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
2 changes: 0 additions & 2 deletions _internal/src/utils/web-preset.ts
Expand Up @@ -31,12 +31,10 @@ const initFocus = (callback: () => void) => {
if (isDocumentDefined) {
document.addEventListener('visibilitychange', callback)
}
onWindowEvent('focus', callback)
return () => {
if (isDocumentDefined) {
document.removeEventListener('visibilitychange', callback)
}
offWindowEvent('focus', callback)
}
}

Expand Down
5 changes: 1 addition & 4 deletions test/unit/web-preset.test.ts
@@ -1,6 +1,5 @@
import { EventEmitter } from 'events'

const FOCUS_EVENT = 'focus'
const VISIBILITYCHANGE_EVENT = 'visibilitychange'

function createEventTarget() {
Expand All @@ -13,8 +12,7 @@ function createEventTarget() {

function runTests(propertyName) {
let initFocus
const eventName =
propertyName === 'window' ? FOCUS_EVENT : VISIBILITYCHANGE_EVENT
const eventName = VISIBILITYCHANGE_EVENT

describe(`Web Preset ${propertyName}`, () => {
const globalSpy = {
Expand Down Expand Up @@ -88,5 +86,4 @@ function runTests(propertyName) {
})
}

runTests('window')
runTests('document')
12 changes: 6 additions & 6 deletions test/use-swr-cache.test.tsx
Expand Up @@ -6,7 +6,7 @@ import {
createKey,
createResponse,
nextTick,
focusOn,
toggleVisibility,
renderWithConfig,
renderWithGlobalCache
} from './utils'
Expand Down Expand Up @@ -166,7 +166,7 @@ describe('useSWR - cache provider', () => {
await screen.findByText('1')
await nextTick()
// try to trigger revalidation, but shouldn't work
await focusOn(window)
toggleVisibility()
// revalidateOnFocus won't work
screen.getByText('1')
unmount()
Expand All @@ -175,7 +175,7 @@ describe('useSWR - cache provider', () => {
expect(unsubscribeReconnectFn).toBeCalledTimes(1)
})

it('should work with revalidateOnFocus', async () => {
it('should work with revalidateOnFocus 1', async () => {
const key = createKey()
let value = 0
function Page() {
Expand All @@ -190,7 +190,7 @@ describe('useSWR - cache provider', () => {

await screen.findByText('0')
await nextTick()
await focusOn(window)
toggleVisibility()
await nextTick()
screen.getByText('1')
})
Expand Down Expand Up @@ -397,7 +397,7 @@ describe('useSWR - global cache', () => {
await screen.findByText('data:mutated value')
})

it('should work with revalidateOnFocus', async () => {
it('should work with revalidateOnFocus 2', async () => {
const key = createKey()
let value = 0
function Page() {
Expand All @@ -411,7 +411,7 @@ describe('useSWR - global cache', () => {

await screen.findByText('0')
await nextTick()
await focusOn(window)
toggleVisibility()
await nextTick()
screen.getByText('1')
})
Expand Down
37 changes: 17 additions & 20 deletions test/use-swr-focus.test.tsx
Expand Up @@ -4,13 +4,11 @@ import useSWR from 'swr'
import {
sleep,
nextTick as waitForNextTick,
focusOn,
toggleVisibility,
renderWithConfig,
createKey
} from './utils'

const focusWindow = () => focusOn(window)

describe('useSWR - focus', () => {
it('should revalidate on focus by default', async () => {
let value = 0
Expand All @@ -30,8 +28,7 @@ describe('useSWR - focus', () => {

await waitForNextTick()
// trigger revalidation
await focusWindow()

toggleVisibility()
await screen.findByText('data: 1')
})

Expand All @@ -56,7 +53,7 @@ describe('useSWR - focus', () => {

await waitForNextTick()
// trigger revalidation
await focusWindow()
toggleVisibility()
// should not be revalidated
screen.getByText('data: 0')
})
Expand Down Expand Up @@ -84,28 +81,28 @@ describe('useSWR - focus', () => {

await waitForNextTick()
// trigger revalidation
await focusWindow()
toggleVisibility()
// data should not change
screen.getByText('data: 0')

// change revalidateOnFocus to true
fireEvent.click(screen.getByText('data: 0'))
// trigger revalidation
await focusWindow()
toggleVisibility()
// data should update
await screen.findByText('data: 1')

await waitForNextTick()
// trigger revalidation
await focusWindow()
toggleVisibility()
// data should update
await screen.findByText('data: 2')

await waitForNextTick()
// change revalidateOnFocus to false
fireEvent.click(screen.getByText('data: 2'))
// trigger revalidation
await focusWindow()
toggleVisibility()
// data should not change
screen.getByText('data: 2')
})
Expand All @@ -132,17 +129,17 @@ describe('useSWR - focus', () => {

await waitForNextTick()
// trigger revalidation
await focusWindow()
toggleVisibility()
// still in throttling interval
await act(() => sleep(20))
// should be throttled
await focusWindow()
toggleVisibility()
await screen.findByText('data: 1')
// wait for focusThrottleInterval
await act(() => sleep(100))

// trigger revalidation again
await focusWindow()
toggleVisibility()
await screen.findByText('data: 2')
})

Expand All @@ -169,11 +166,11 @@ describe('useSWR - focus', () => {

await waitForNextTick()
// trigger revalidation
await focusWindow()
toggleVisibility()
// wait for throttle interval
await act(() => sleep(100))
// trigger revalidation
await focusWindow()
toggleVisibility()
await screen.findByText('data: 2')

await waitForNextTick()
Expand All @@ -182,17 +179,17 @@ describe('useSWR - focus', () => {
// wait for throttle interval
await act(() => sleep(100))
// trigger revalidation
await focusWindow()
toggleVisibility()
// wait for throttle interval
await act(() => sleep(100))
// should be throttled
await focusWindow()
toggleVisibility()
await screen.findByText('data: 3')

// wait for throttle interval
await act(() => sleep(150))
// trigger revalidation
await focusWindow()
toggleVisibility()
// wait for throttle intervals
await act(() => sleep(150))
await screen.findByText('data: 4')
Expand All @@ -214,7 +211,7 @@ describe('useSWR - focus', () => {
screen.getByText('data:')
await screen.findByText('data: 0')
await waitForNextTick()
await focusWindow()
toggleVisibility()
await screen.findByText('data: 1')
})

Expand All @@ -233,7 +230,7 @@ describe('useSWR - focus', () => {
renderWithConfig(<Page />)
await waitForNextTick()

fireEvent.focus(window)
toggleVisibility()
fireEvent.click(screen.getByText('change key'))

await waitForNextTick()
Expand Down
6 changes: 2 additions & 4 deletions test/use-swr-immutable.test.tsx
Expand Up @@ -6,12 +6,10 @@ import {
sleep,
createKey,
nextTick as waitForNextTick,
focusOn,
toggleVisibility,
renderWithConfig
} from './utils'

const focusWindow = () => focusOn(window)

describe('useSWR - immutable', () => {
it('should revalidate on mount', async () => {
let value = 0
Expand Down Expand Up @@ -138,7 +136,7 @@ describe('useSWR - immutable', () => {

// trigger window focus
await waitForNextTick()
await focusWindow()
toggleVisibility()

// wait for rerender
await act(() => sleep(50))
Expand Down
5 changes: 3 additions & 2 deletions test/use-swr-integration.test.tsx
Expand Up @@ -7,7 +7,8 @@ import {
nextTick as waitForNextTick,
renderWithConfig,
createKey,
renderWithGlobalCache
renderWithGlobalCache,
toggleVisibility
} from './utils'

describe('useSWR', () => {
Expand Down Expand Up @@ -389,7 +390,7 @@ describe('useSWR', () => {
await screen.findByText('hello, Initial')

await waitForNextTick()
fireEvent.focus(window)
toggleVisibility()

await screen.findByText(`hello, ${initialKey}`)

Expand Down
15 changes: 5 additions & 10 deletions test/use-swr-offline.test.tsx
@@ -1,18 +1,13 @@
import { act, screen } from '@testing-library/react'
import { screen } from '@testing-library/react'
import useSWR from 'swr'
import {
nextTick as waitForNextTick,
focusOn,
toggleVisibility,
createKey,
renderWithConfig
renderWithConfig,
dispatchWindowEvent
} from './utils'

const focusWindow = () => focusOn(window)
const dispatchWindowEvent = event =>
act(async () => {
window.dispatchEvent(new Event(event))
})

describe('useSWR - offline', () => {
it('should not revalidate when offline', async () => {
let value = 0
Expand All @@ -36,7 +31,7 @@ describe('useSWR - offline', () => {
await dispatchWindowEvent('offline')

// trigger focus revalidation
await focusWindow()
toggleVisibility()

// should not be revalidated
screen.getByText('data: 0')
Expand Down
13 changes: 9 additions & 4 deletions test/utils.tsx
@@ -1,4 +1,4 @@
import { act, fireEvent, render } from '@testing-library/react'
import { act, render } from '@testing-library/react'
import { SWRConfig } from 'swr'

export function sleep(time: number) {
Expand All @@ -21,9 +21,14 @@ export const createResponse = <T,>(

export const nextTick = () => act(() => sleep(1))

export const focusOn = (element: any) =>
act(async () => {
fireEvent.focus(element)
export const toggleVisibility = (_?: any) =>
act(() => {
document.dispatchEvent(new Event('visibilitychange'))
})

export const dispatchWindowEvent = (event: string) =>
act(() => {
window.dispatchEvent(new Event(event))
})

export const createKey = () => 'swr-key-' + ~~(Math.random() * 1e7)
Expand Down