Skip to content

Commit

Permalink
fix(loaders): ensure loads when a navigation is missed
Browse files Browse the repository at this point in the history
Fix #495
  • Loading branch information
posva committed Sep 9, 2024
1 parent c9c792e commit b799598
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/data-loaders/defineColadaLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,8 @@ export function defineColadaLoader<Data>(
!entry ||
// we are nested and the parent is loading a different route than us
(parentEntry && entry.pendingTo !== route)
// The user somehow rendered the page without a navigation
|| !entry.pendingLoad
) {
// console.log(
// `🔁 loading from useData for "${options.key}": "${route.fullPath}"`
Expand Down
3 changes: 3 additions & 0 deletions src/data-loaders/defineLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,9 @@ export function defineBasicLoader<Data>(
(parentEntry && entry.pendingTo !== route)
// we could also check for: but that would break nested loaders since they need to be always called to be associated with the parent
// && entry.to !== route
// the user managed to render the router view after a valid navigation + a failed navigation
// https://github.com/posva/unplugin-vue-router/issues/495
|| !entry.pendingLoad
) {
// console.log(
// `🔁 loading from useData for "${options.key}": "${route.fullPath}"`
Expand Down
62 changes: 61 additions & 1 deletion tests/data-loaders/tester.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
/**
* @vitest-environment happy-dom
*/
import { type App, defineComponent, inject, type Plugin } from 'vue'
import {
type App,
defineComponent,
h,
inject,
nextTick,
type Plugin,
ref,
} from 'vue'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { flushPromises, mount } from '@vue/test-utils'
import { getRouter } from 'vue-router-mock'
Expand Down Expand Up @@ -1109,6 +1117,58 @@ export function testDefineLoader<Context = void>(
it.todo('can be first non-lazy then lazy', async () => {})
it.todo('can be first non-lazy then lazy', async () => {})

// https://github.com/posva/unplugin-vue-router/issues/495
// in the issue above we have one page with a loader
// this page is conditionally rendered based on an error state
// when resetting the error state, there is also a duplicated navigation
// that invalidates any pendingLoad and renders the page again
// since there is no navigation, loaders are not called again and
// there is no pendingLoad
it('gracefully handles a loader without a pendingLoad', async () => {
const l1 = mockedLoader({ lazy: false, key: 'l1' })
const router = getRouter()
router.addRoute({
name: 'a',
path: '/a',
component: defineComponent({
setup() {
const { data } = l1.loader()
return { data }
},
template: `<p>{{ data }}</p>`,
}),
meta: {
loaders: [l1.loader],
},
})
l1.spy.mockResolvedValue('ok')

const isVisible = ref(true)


const wrapper = mount(
() => (isVisible.value ? h(RouterViewMock) : h('p', ['hidden'])),
{
global: {
plugins: [
[DataLoaderPlugin, { router }],
...(plugins?.(customContext!) || []),
],
},
}
)

await router.push('/a')
expect(wrapper.text()).toBe('ok')
isVisible.value = false
await nextTick()
expect(wrapper.text()).toBe('hidden')
await router.push('/a') // failed duplicated navigation
isVisible.value = true
await nextTick()
expect(wrapper.text()).toBe('ok')
})

describe('app.runWithContext()', () => {
it('can inject globals', async () => {
const { router, useData, app } = singleLoaderOneRoute(
Expand Down

0 comments on commit b799598

Please sign in to comment.