// @ts-check
require('./helper')
const expect = require('expect')
-const { normalizeRecord } = require('../src/matcher')
const { extractComponentsGuards } = require('../src/utils')
const { START_LOCATION_NORMALIZED } = require('../src/types')
-const { components } = require('./utils')
+const { components, normalizeRouteRecord } = require('./utils')
/** @typedef {import('../src/types').RouteRecord} RouteRecord */
/** @typedef {import('../src/types').MatchedRouteRecord} MatchedRouteRecord */
/**
*
- * @param {MatchedRouteRecord} record
+ * @param {Exclude<RouteRecord, { redirect: any}>} record
* @returns {MatchedRouteRecord}
*/
function makeAsync(record) {
)
return copy
} else {
- if (typeof record.component === 'function') return { ...record }
- // @ts-ignore
+ const { component, ...copy } = record
+ if (typeof component === 'function')
+ return { ...copy, components: { default: component } }
+
return {
- ...record,
- component: () => Promise.resolve(record.component),
+ ...copy,
+ components: {
+ default: () => Promise.resolve(component),
+ },
}
}
}
/**
*
- * @param {Exclude<RouteRecord, RouteRecordRedirect>[]} components
+ * @param {Exclude<RouteRecord, { redirect: any }>[]} components
+ * @param {number} n
*/
async function checkGuards(components, n) {
beforeRouteEnter.mockClear()
- const ncomps = components.map(normalizeRecord)
const guards = await extractComponentsGuards(
// type is fine as we excluded RouteRecordRedirect in components argument
- components.map(normalizeRecord),
+ components.map(normalizeRouteRecord),
'beforeRouteEnter',
to,
from
const expect = require('expect')
const { RouterMatcher } = require('../src/matcher')
const { START_LOCATION_NORMALIZED } = require('../src/types')
+const { normalizeRouteRecord } = require('./utils')
const component = null
/** @typedef {import('../src/types').RouteRecord} RouteRecord */
+/** @typedef {import('../src/types').MatchedRouteRecord} MatchedRouteRecord */
/** @typedef {import('../src/types').MatcherLocation} MatcherLocation */
/** @typedef {import('../src/types').MatcherLocationRedirect} MatcherLocationRedirect */
/** @typedef {import('../src/types').MatcherLocationNormalized} MatcherLocationNormalized */
record,
{},
{ name: 'Home', path: '/home' },
- { name: 'Home', params: {}, path: '/home', matched: [record] }
+ {
+ name: 'Home',
+ params: {},
+ path: '/home',
+ matched: [normalizeRouteRecord(record)],
+ }
)
})
path: '/users/ed/m/user',
name: undefined,
params: { id: 'ed', role: 'user' },
- matched: [record],
+ matched: [record].map(normalizeRouteRecord),
}
)
})
path: '/users/ed/m/user',
name: 'UserEdit',
params: { id: 'ed', role: 'user' },
- matched: [record],
+ matched: [record].map(normalizeRouteRecord),
}
)
})
path: '/users/ed/m/user',
name: undefined,
params: { id: 'ed', role: 'user' },
- matched: [record],
+ matched: [record].map(normalizeRouteRecord),
}
)
})
name: 'home',
params: {},
path: '/',
- matched: [record],
+ matched: [record].map(normalizeRouteRecord),
}
// the property should be non enumerable
Object.defineProperty(start, 'matched', { enumerable: false })
name: 'child-b',
path: '/foo/b',
params: {},
- matched: [Foo, { ...ChildB, path: `${Foo.path}/${ChildB.path}` }],
+ matched: [
+ Foo,
+ { ...ChildB, path: `${Foo.path}/${ChildB.path}` },
+ ].map(normalizeRouteRecord),
}
)
})
name: 'nested',
path: '/foo',
params: {},
- matched: [Foo, { ...Nested, path: `${Foo.path}` }],
+ matched: [Foo, { ...Nested, path: `${Foo.path}` }].map(
+ normalizeRouteRecord
+ ),
}
)
})
Foo,
{ ...Nested, path: `${Foo.path}` },
{ ...NestedNested, path: `${Foo.path}` },
- ],
+ ].map(normalizeRouteRecord),
}
)
})
...NestedChildA,
path: `${Foo.path}/${Nested.path}/${NestedChildA.path}`,
},
- ],
+ ].map(normalizeRouteRecord),
}
)
})
...NestedChildA,
path: `${Foo.path}/${Nested.path}/${NestedChildA.path}`,
},
- ],
+ ].map(normalizeRouteRecord),
}
)
})
...NestedChildA,
path: `${Foo.path}/${Nested.path}/${NestedChildA.path}`,
},
- ],
+ ].map(normalizeRouteRecord),
},
{
name: 'nested-child-a',
...NestedChildWithParam,
path: `${Foo.path}/${NestedWithParam.path}/${NestedChildWithParam.path}`,
},
- ],
+ ].map(normalizeRouteRecord),
}
)
})
...NestedChildWithParam,
path: `${Foo.path}/${NestedWithParam.path}/${NestedChildWithParam.path}`,
},
- ],
+ ].map(normalizeRouteRecord),
}
)
})
query: {},
params: {},
hash: '',
- meta: {},
+ // meta: {},
matched: [{ components: { default: components.Home }, path: '/' }],
},
}
if (isMocha()) return
const { mount } = require('@vue/test-utils')
- it('displays current route component', async () => {
- const wrapper = await mount(RouterView, {
- mocks: {
- $route: routes.root,
- },
+ /**
+ *
+ * @param {RouteLocationNormalized} $route
+ */
+ function factory($route) {
+ // @ts-ignore
+ const wrapper = mount(RouterView, {
+ mocks: { $route },
})
+ return wrapper
+ }
+
+ it('displays current route component', async () => {
+ const wrapper = factory(routes.root)
expect(wrapper.html()).toMatchInlineSnapshot(`"<div>Home</div>"`)
})
})
import { JSDOM, ConstructorOptions } from 'jsdom'
-import { NavigationGuard } from '../src/types'
-import { Component } from 'vue'
+import { NavigationGuard, RouteRecord, MatchedRouteRecord } from '../src/types'
export { HistoryMock } from './HistoryMock'
next()
}
-export const components: Record<string, Component> = {
- Home: { render: h => h('div', {}, 'Home') },
- Foo: { render: h => h('div', {}, 'Foo') },
- Bar: { render: h => h('div', {}, 'Bar') },
+export const components = {
+ Home: { render: (h: Function) => h('div', {}, 'Home') },
+ Foo: { render: (h: Function) => h('div', {}, 'Foo') },
+ Bar: { render: (h: Function) => h('div', {}, 'Bar') },
}
// allow using a .jest modifider to skip some tests on mocha
// adapt to mocha
// @ts-ignore
export const isMocha = () => typeof global.before === 'function'
+
+/**
+ * Copies and normalizes the record so it always contains an object of `components`
+ *
+ * @param record
+ * @returns a normalized copy
+ */
+export function normalizeRouteRecord(
+ record: Exclude<RouteRecord, { redirect: any }>
+): MatchedRouteRecord {
+ if ('components' in record) return { ...record }
+ const { component, ...rest } = record
+
+ return {
+ ...rest,
+ components: { default: component },
+ }
+}
import { HistoryQuery, RawHistoryQuery } from '../history/base'
+// import Vue, { ComponentOptions, AsyncComponent } from 'vue'
+
+// type Component = ComponentOptions<Vue> | typeof Vue | AsyncComponent
export type Lazy<T> = () => Promise<T>
}
// TODO: have a real type with augmented properties
-// export type RouteComponent = TODO & RouteComponentInterface
-export type RouteComponent = {
+// export type RouteComponent = Component & RouteComponentInterface
+type Component = {
template?: string
render?: Function
} & RouteComponentInterface
+export type RouteComponent = Component | Lazy<Component>
+
// NOTE not sure the whole PropsTransformer thing can be usefull
// since in callbacks we don't know where we are coming from
// and I don't thin it's possible to filter out the route
}
interface RouteRecordSingleView extends RouteRecordCommon {
- component: RouteComponent | Lazy<RouteComponent>
+ component: RouteComponent
children?: RouteRecord[]
}
interface RouteRecordMultipleViews extends RouteRecordCommon {
- components: Record<string, RouteComponent | Lazy<RouteComponent>>
+ components: Record<string, RouteComponent>
// TODO: add tests
children?: RouteRecord[]
}
// TODO: cache async routes per record
for (const name in record.components) {
const component = record.components[name]
+ // TODO: handle Vue.extend views
+ // if ('options' in component) throw new Error('TODO')
const resolvedComponent = await (typeof component === 'function'
? component()
: component)