Skip to content

Commit

Permalink
Interactivity API: Add timeout option to navigate() (#54474)
Browse files Browse the repository at this point in the history
* Add timeout to the navigate function

* Add test for timeout

* Update changelog

* Throw error if timeout finish

* Revert "Throw error if timeout finish"

This reverts commit 92f1333.

* Do not reject when timeout ends
  • Loading branch information
DAreRodz committed Sep 19, 2023
1 parent 90c49ff commit c103a65
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
data-wp-text="state.router.status"
>undefined</output>

<button
data-wp-on--click="actions.router.toggleTimeout"
data-testid="toggle timeout"
>
Timeout <span data-wp-text="state.router.timeout">NaN</span>
</button>

<?php
if ( isset( $attributes['links'] ) ) {
foreach ( $attributes['links'] as $key => $link ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
router: {
status: 'idle',
navigations: 0,
timeout: 10000,
}
},
actions: {
Expand All @@ -20,15 +21,20 @@
state.router.status = 'busy';

const force = e.target.dataset.forceNavigation === 'true';
const { timeout } = state.router;

await navigate( e.target.href, { force } );
await navigate( e.target.href, { force, timeout } );

state.router.navigations -= 1;

if ( state.router.navigations === 0) {
state.router.status = 'idle';
}
},
toggleTimeout: ( { state }) => {
state.router.timeout =
state.router.timeout === 10000 ? 0 : 10000;
}
},
},
} );
Expand Down
2 changes: 2 additions & 0 deletions packages/interactivity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

- Improve `navigate()` to render only the result of the last call when multiple happen simultaneously. ([#54201](https://github.com/WordPress/gutenberg/pull/54201))

- Add `timeout` option to `navigate()`, with a default value of `10000` milliseconds. ([#54474](https://github.com/WordPress/gutenberg/pull/54474))

## 2.2.0 (2023-08-31)

### Enhancements
Expand Down
10 changes: 9 additions & 1 deletion packages/interactivity/src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,14 @@ export const navigate = async ( href, options = {} ) => {
const url = cleanUrl( href );
navigatingTo = href;
prefetch( url, options );
const page = await pages.get( url );

// Create a promise that resolves when the specified timeout ends. The
// timeout value is 10 seconds by default.
const timeoutPromise = new Promise( ( resolve ) =>
setTimeout( resolve, options.timeout ?? 10000 )
);

const page = await Promise.race( [ pages.get( url ), timeoutPromise ] );

// Once the page is fetched, the destination URL could have changed (e.g.,
// by clicking another link in the meantime). If so, bail out, and let the
Expand All @@ -102,6 +109,7 @@ export const navigate = async ( href, options = {} ) => {
);
} else {
window.location.assign( href );
await new Promise( () => {} );
}
};

Expand Down
50 changes: 42 additions & 8 deletions test/e2e/specs/interactivity/router-navigate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,24 +106,58 @@ test.describe( 'Router navigate', () => {
await expect( status ).toHaveText( 'busy' );
await expect( title ).toHaveText( 'Main' );

{
const resolver = resolvers.pop();
if ( resolver ) resolver();
}
resolvers.pop()!();

await expect( navigations ).toHaveText( '1' );
await expect( status ).toHaveText( 'busy' );
await expect( title ).toHaveText( 'Link 1' );
await expect( page ).toHaveURL( href );

{
const resolver = resolvers.pop();
if ( resolver ) resolver();
}
resolvers.pop()!();

await expect( navigations ).toHaveText( '0' );
await expect( status ).toHaveText( 'idle' );
await expect( title ).toHaveText( 'Link 1' );
await expect( page ).toHaveURL( href );
} );

test( 'should reload the next page when the timeout ends', async ( {
page,
interactivityUtils: utils,
} ) => {
const link1 = utils.getLink( 'router navigate - link 1' );

const title = page.getByTestId( 'title' );
const toggleTimeout = page.getByTestId( 'toggle timeout' );

let resolver: Function;

await page.route( link1, async ( route ) => {
// Only capture the first request.
if ( ! resolver ) {
await new Promise( ( r ) => ( resolver = r ) );
await route.abort();
} else {
await route.continue();
}
} );

await expect( toggleTimeout ).toHaveText( 'Timeout 10000' );

// Set timeout to 0.
await toggleTimeout.click();
await expect( toggleTimeout ).toHaveText( 'Timeout 0' );

// Navigation should timeout almost instantly.
await page.getByTestId( 'link 1' ).click();

await expect( page ).toHaveURL( link1 );
await expect( title ).toHaveText( 'Link 1' );

// If timeout is 10000, that means the page has been reloaded.
await expect( toggleTimeout ).toHaveText( 'Timeout 10000' );

// Make the fetch abort, just in case.
resolver!();
} );
} );

0 comments on commit c103a65

Please sign in to comment.