-// @ts-check
-const fakePromise = require('faked-promise')
-const { AbstractHistory } = require('../src/history/abstract')
-const { Router } = require('../src/router')
-const {
- NavigationAborted,
- NavigationCancelled,
- NavigationGuardRedirect,
-} = require('../src/errors')
-const { components, tick } = require('./utils')
+import { AbstractHistory } from '../src/history/abstract'
+import { Router } from '../src/router'
+import { NavigationAborted, NavigationGuardRedirect } from '../src/errors'
+import { components, tick } from './utils'
+import { RouteRecord } from '../src/types'
-/** @type {import('../src/types').RouteRecord[]} */
-const routes = [
+const routes: RouteRecord[] = [
{ path: '/', component: components.Home },
{ path: '/foo', component: components.Foo, name: 'Foo' },
{ path: '/to-foo', redirect: '/foo' },
-// @ts-check
-const { extractComponentsGuards } = require('../src/utils')
-const { START_LOCATION_NORMALIZED } = require('../src/types')
-const { components, normalizeRouteRecord } = require('./utils')
+import { extractComponentsGuards } from '../src/utils'
+import {
+ START_LOCATION_NORMALIZED,
+ RouteRecord,
+ MatchedRouteRecord,
+} from '../src/types'
+import { components, normalizeRouteRecord } from './utils'
/** @typedef {import('../src/types').RouteRecord} RouteRecord */
/** @typedef {import('../src/types').MatchedRouteRecord} MatchedRouteRecord */
const to = START_LOCATION_NORMALIZED
const from = START_LOCATION_NORMALIZED
-/** @type {RouteRecord} */
-const NoGuard = { path: '/', component: components.Home }
-/** @type {RouteRecord} */
-const SingleGuard = {
+const NoGuard: RouteRecord = { path: '/', component: components.Home }
+const SingleGuard: RouteRecord = {
path: '/',
component: { ...components.Home, beforeRouteEnter },
}
-/** @type {RouteRecord} */
-const SingleGuardNamed = {
+const SingleGuardNamed: RouteRecord = {
path: '/',
components: {
default: { ...components.Home, beforeRouteEnter },
},
}
-/**
- *
- * @param {Exclude<RouteRecord, { redirect: any}>} record
- * @returns {MatchedRouteRecord}
- */
-function makeAsync(record) {
+function makeAsync(
+ record: Exclude<RouteRecord, { redirect: any }>
+): MatchedRouteRecord {
if ('components' in record) {
const copy = { ...record }
copy.components = Object.keys(record.components).reduce(
(components, name) => {
+ // @ts-ignore
components[name] = () => Promise.resolve(record.components[name])
return components
},
- {}
+ {} as typeof record['components']
)
return copy
} else {
})
})
-/**
- *
- * @param {Exclude<RouteRecord, { redirect: any }>[]} components
- * @param {number} n
- */
-async function checkGuards(components, n) {
+async function checkGuards(
+ components: Exclude<RouteRecord, { redirect: any }>[],
+ n: number
+) {
beforeRouteEnter.mockClear()
const guards = await extractComponentsGuards(
// type is fine as we excluded RouteRecordRedirect in components argument
-// @ts-check
-const { HTML5History } = require('../../src/history/html5')
-const { Router } = require('../../src/router')
-const fakePromise = require('faked-promise')
-const { NAVIGATION_TYPES, createDom, noGuard } = require('../utils')
-
-/** @typedef {import('../../src/types').RouteRecord} RouteRecord */
-/** @typedef {import('../../src/router').RouterOptions} RouterOptions */
-
-/**
- * @param {Partial<RouterOptions> & { routes: RouteRecord[]}} options
- */
-function createRouter(options) {
+import { HTML5History } from '../../src/history/html5'
+import { Router, RouterOptions } from '../../src/router'
+import fakePromise from 'faked-promise'
+import { NAVIGATION_TYPES, createDom, noGuard } from '../utils'
+import { RouteRecord } from '../../src/types'
+
+function createRouter(
+ options: Partial<RouterOptions> & { routes: RouteRecord[] }
+) {
return new Router({
history: new HTML5History(),
...options,
nestedNestedParam: jest.fn(),
}
-/** @type {RouteRecord[]} */
-const routes = [
+const routes: RouteRecord[] = [
{ path: '/', component: Home },
{ path: '/foo', component: Foo },
{
function resetMocks() {
beforeRouteEnter.mockReset()
for (const key in named) {
- named[key].mockReset()
+ named[key as keyof typeof named].mockReset()
}
for (const key in nested) {
- nested[key].mockReset()
- nested[key].mockImplementation(noGuard)
+ nested[key as keyof typeof nested].mockReset()
+ nested[key as keyof typeof nested].mockImplementation(noGuard)
}
}
template: `<div></div>`,
beforeRouteEnter: spy,
}
- const [promise, resolve] = fakePromise()
+ const [promise, resolve] = fakePromise<typeof component>()
const router = createRouter({
routes: [...routes, { path: '/async', component: () => promise }],
})
-// @ts-check
-const { HTML5History } = require('../../src/history/html5')
-const { Router } = require('../../src/router')
-const fakePromise = require('faked-promise')
-const { NAVIGATION_TYPES, createDom, noGuard } = require('../utils')
+import { HTML5History } from '../../src/history/html5'
+import { Router, RouterOptions } from '../../src/router'
+import { NAVIGATION_TYPES, createDom, noGuard } from '../utils'
+import { RouteRecord } from '../../src/types'
-/** @typedef {import('../../src/types').RouteRecord} RouteRecord */
-/** @typedef {import('../../src/router').RouterOptions} RouterOptions */
-
-/**
- * @param {Partial<RouterOptions> & { routes: RouteRecord[]}} options
- */
-function createRouter(options) {
+// TODO: refactor in utils
+function createRouter(
+ options: Partial<RouterOptions> & { routes: RouteRecord[] }
+) {
return new Router({
history: new HTML5History(),
...options,
}
const beforeRouteLeave = jest.fn()
-/** @type {RouteRecord[]} */
-const routes = [
+const routes: RouteRecord[] = [
{ path: '/', component: Home },
{ path: '/foo', component: Foo },
{
function resetMocks() {
beforeRouteLeave.mockReset()
for (const key in nested) {
- nested[key].mockReset()
- nested[key].mockImplementation(noGuard)
+ nested[key as keyof typeof nested].mockReset()
+ nested[key as keyof typeof nested].mockImplementation(noGuard)
}
}
-// @ts-check
-const { HTML5History } = require('../../src/history/html5')
-const { Router } = require('../../src/router')
-const fakePromise = require('faked-promise')
-const { NAVIGATION_TYPES, createDom, noGuard } = require('../utils')
+import { HTML5History } from '../../src/history/html5'
+import { Router } from '../../src/router'
+import fakePromise from 'faked-promise'
+import { NAVIGATION_TYPES, createDom, noGuard } from '../utils'
-/**
- * @param {Partial<import('../../src/router').RouterOptions> & { routes: import('../../src/types').RouteRecord[]}} options
- */
-function createRouter(options) {
+function createRouter(
+ options: Partial<import('../../src/router').RouterOptions> & {
+ routes: import('../../src/types').RouteRecord[]
+ }
+) {
return new Router({
history: new HTML5History(),
...options,
-// @ts-check
-const { HTML5History } = require('../../src/history/html5')
-const { Router } = require('../../src/router')
-const { NAVIGATION_TYPES, createDom } = require('../utils')
+import { HTML5History } from '../../src/history/html5'
+import { Router } from '../../src/router'
+import { NAVIGATION_TYPES, createDom } from '../utils'
-/**
- * @param {Partial<import('../../src/router').RouterOptions> & { routes: import('../../src/types').RouteRecord[]}} options
- */
-function createRouter(options) {
+function createRouter(
+ options: Partial<import('../../src/router').RouterOptions> & {
+ routes: import('../../src/types').RouteRecord[]
+ }
+) {
return new Router({
history: new HTML5History(),
...options,
-// @ts-check
-const { HTML5History } = require('../../src/history/html5')
-const { Router } = require('../../src/router')
-const fakePromise = require('faked-promise')
-const { NAVIGATION_TYPES, createDom, tick, noGuard } = require('../utils')
-
-/** @typedef {import('../../src/types').RouteRecord} RouteRecord */
-/** @typedef {import('../../src/router').RouterOptions} RouterOptions */
-
-/**
- * @param {Partial<RouterOptions> & { routes: RouteRecord[]}} options
- */
-function createRouter(options) {
+import { HTML5History } from '../../src/history/html5'
+import { Router, RouterOptions } from '../../src/router'
+import fakePromise from 'faked-promise'
+import { NAVIGATION_TYPES, createDom, tick, noGuard } from '../utils'
+import { RouteRecord, RouteLocation } from '../../src/types'
+
+function createRouter(
+ options: Partial<RouterOptions> & { routes: RouteRecord[] }
+) {
return new Router({
history: new HTML5History(),
...options,
expect(router.currentRoute.fullPath).toBe('/other')
})
- async function assertRedirect(redirectFn) {
+ async function assertRedirect(redirectFn: (i: string) => RouteLocation) {
const spy = jest.fn()
const router = createRouter({ routes })
await router.push('/')
// only allow going to /other
const i = Number(to.params.i)
if (i >= 3) next()
- else next(redirectFn(i + 1))
+ else next(redirectFn(String(i + 1)))
})
router.beforeEach(spy)
expect(spy).not.toHaveBeenCalled()
-// @ts-check
-const { HTML5History } = require('../../src/history/html5')
-const { Router } = require('../../src/router')
-const fakePromise = require('faked-promise')
-const { NAVIGATION_TYPES, createDom, noGuard, tick } = require('../utils')
+import { HTML5History } from '../../src/history/html5'
+import { Router, RouterOptions } from '../../src/router'
+import fakePromise from 'faked-promise'
+import { NAVIGATION_TYPES, createDom, noGuard, tick } from '../utils'
+import { RouteRecord } from '../../src/types'
-/** @typedef {import('../../src/types').RouteRecord} RouteRecord */
-/** @typedef {import('../../src/router').RouterOptions} RouterOptions */
-
-/**
- * @param {Partial<RouterOptions> & { routes: RouteRecord[]}} options
- */
-function createRouter(options) {
+function createRouter(
+ options: Partial<RouterOptions> & { routes: RouteRecord[] }
+) {
return new Router({
history: new HTML5History(),
...options,
spy.mockImplementationOnce(noGuard)
})
for (const key in nested) {
- nested[key].mockReset()
- nested[key].mockImplementation(noGuard)
+ nested[key as keyof typeof nested].mockReset()
+ nested[key as keyof typeof nested].mockImplementation(noGuard)
}
}
-// @ts-check
-const { AbstractHistory } = require('../../src/history/abstract')
-const { START } = require('../../src/history/base')
+import { AbstractHistory } from '../../src/history/abstract'
+import { START } from '../../src/history/base'
/** @type {import('../../src/history/base').HistoryLocation} */
const loc = {
-// @ts-check
-const { HTML5History } = require('../../src/history/html5')
-const { createDom } = require('../utils')
+import { HTML5History } from '../../src/history/html5'
+import { createDom } from '../utils'
// TODO: is it really worth testing this implementation on jest or is it
// better to directly use e2e tests instead
-// @ts-check
-const { createRouteMatcher } = require('../src/matcher')
-
-/** @type {RouteComponent} */
-const component = null
-
-/** @typedef {import('../src/types').RouteRecord} RouteRecord */
-/** @typedef {import('../src/types').RouteComponent} RouteComponent */
-/** @typedef {import('../src/types').MatchedRouteRecord} MatchedRouteRecord */
-/** @typedef {import('../src/types').MatcherLocation} MatcherLocation */
-/** @typedef {import('../src/types').MatcherLocationRedirect} MatcherLocationRedirect */
-/** @typedef {import('../src/types').MatcherLocationNormalized} MatcherLocationNormalized */
-/** @typedef {import('../src/matcher').RouteMatcher} RouteMatcher */
-/** @typedef {import('path-to-regexp').RegExpOptions} RegExpOptions */
-
-function stringifyOptions(options) {
+import { createRouteMatcher } from '../src/matcher'
+import { RegExpOptions } from 'path-to-regexp'
+import { RouteComponent } from '../src/types'
+
+// @ts-ignore
+const component: RouteComponent = null
+
+function stringifyOptions(options: any) {
return Object.keys(options).length ? ` (${JSON.stringify(options)})` : ''
}
describe('createRouteMatcher', () => {
- /**
- *
- * @param {Array<string | [string, RegExpOptions]>} paths
- * @param {RegExpOptions} options
- */
- function checkPathOrder(paths, options = {}) {
+ function checkPathOrder(
+ paths: Array<string | [string, RegExpOptions]>,
+ options: RegExpOptions = {}
+ ) {
const normalizedPaths = paths.map(pathOrCombined => {
if (Array.isArray(pathOrCombined))
return [pathOrCombined[0], { ...options, ...pathOrCombined[1] }]
-// @ts-check
-const { RouterMatcher } = require('../src/matcher')
-const { START_LOCATION_NORMALIZED } = require('../src/types')
-const { normalizeRouteRecord } = require('./utils')
-
-/** @type {RouteComponent} */
-const component = null
-
-/** @typedef {import('../src/types').RouteRecord} RouteRecord */
-/** @typedef {import('../src/types').RouteComponent} RouteComponent */
-/** @typedef {import('../src/types').MatchedRouteRecord} MatchedRouteRecord */
-/** @typedef {import('../src/types').MatcherLocation} MatcherLocation */
-/** @typedef {import('../src/types').MatcherLocationRedirect} MatcherLocationRedirect */
-/** @typedef {import('../src/types').MatcherLocationNormalized} MatcherLocationNormalized */
+import { RouterMatcher } from '../src/matcher'
+import {
+ START_LOCATION_NORMALIZED,
+ RouteComponent,
+ RouteRecord,
+ MatcherLocation,
+ MatcherLocationNormalized,
+ MatcherLocationRedirect,
+} from '../src/types'
+import { normalizeRouteRecord } from './utils'
+
+// @ts-ignore
+const component: RouteComponent = null
+
+// for normalized records
+const components = { default: component }
describe('Router Matcher', () => {
describe('resolve', () => {
- /**
- *
- * @param {RouteRecord | RouteRecord[]} record Record or records we are testing the matcher against
- * @param {MatcherLocation} location location we want to reolve against
- * @param {Partial<import('../src/types').Override<MatcherLocationNormalized, { matched: Array<Exclude<RouteRecord, { redirect: any}>> }>>} resolved Expected resolved location given by the matcher
- * @param {import('../src/types').Override<MatcherLocationNormalized, { matched: Array<Exclude<RouteRecord, { redirect: any}>> }>} [start] Optional currentLocation used when resolving
- */
function assertRecordMatch(
- record,
- location,
- resolved,
- start = START_LOCATION_NORMALIZED
+ record: RouteRecord | RouteRecord[],
+ location: MatcherLocation,
+ resolved: Partial<MatcherLocationNormalized>,
+ start: MatcherLocationNormalized = START_LOCATION_NORMALIZED
) {
record = Array.isArray(record) ? record : [record]
const matcher = new RouterMatcher(record)
throw new Error('not handled')
} else {
// use one single record
- if (!('matched' in resolved))
+ if (!resolved.matched)
+ // @ts-ignore
resolved.matched = record.map(normalizeRouteRecord)
else resolved.matched = resolved.matched.map(normalizeRouteRecord)
}
* @returns {any} error
*/
function assertErrorMatch(
- record,
- location,
- start = START_LOCATION_NORMALIZED
+ record: RouteRecord | RouteRecord[],
+ location: MatcherLocation,
+ start: MatcherLocationNormalized = START_LOCATION_NORMALIZED
) {
try {
assertRecordMatch(record, location, {}, start)
describe('LocationAsPath', () => {
it('resolves a normal path', () => {
assertRecordMatch(
- { path: '/', name: 'Home', component },
+ { path: '/', name: 'Home', components },
{ path: '/' },
{ name: 'Home', path: '/', params: {} }
)
it('resolves a normal path without name', () => {
assertRecordMatch(
- { path: '/', component },
+ { path: '/', components },
{ path: '/' },
{ name: undefined, path: '/', params: {} }
)
it('resolves a path with params', () => {
assertRecordMatch(
- { path: '/users/:id', name: 'User', component },
+ { path: '/users/:id', name: 'User', components },
{ path: '/users/posva' },
{ name: 'User', params: { id: 'posva' } }
)
it('resolves a path with multiple params', () => {
assertRecordMatch(
- { path: '/users/:id/:other', name: 'User', component },
+ { path: '/users/:id/:other', name: 'User', components },
{ path: '/users/posva/hey' },
{ name: 'User', params: { id: 'posva', other: 'hey' } }
)
it('resolves a path with multiple params but no name', () => {
assertRecordMatch(
- { path: '/users/:id/:other', component },
+ { path: '/users/:id/:other', components },
{ path: '/users/posva/hey' },
{ name: undefined, params: { id: 'posva', other: 'hey' } }
)
it('throws if the path does not exists', () => {
expect(
- assertErrorMatch({ path: '/', component }, { path: '/foo' })
+ assertErrorMatch({ path: '/', components }, { path: '/foo' })
).toMatchInlineSnapshot(
`[NoRouteMatchError: No match for {"path":"/foo","params":{},"query":{},"hash":"","fullPath":"/"}]`
)
describe('LocationAsName', () => {
it('matches a name', () => {
assertRecordMatch(
- { path: '/home', name: 'Home', component },
+ { path: '/home', name: 'Home', components },
{ name: 'Home' },
{ name: 'Home', path: '/home' }
)
it('matches a name and fill params', () => {
assertRecordMatch(
- { path: '/users/:id/m/:role', name: 'UserEdit', component },
+ { path: '/users/:id/m/:role', name: 'UserEdit', components },
{ name: 'UserEdit', params: { id: 'posva', role: 'admin' } },
{ name: 'UserEdit', path: '/users/posva/m/admin' }
)
it('throws if the named route does not exists', () => {
expect(
- assertErrorMatch({ path: '/', component }, { name: 'Home' })
+ assertErrorMatch({ path: '/', components }, { name: 'Home' })
).toMatchInlineSnapshot(
`[NoRouteMatchError: No match for {"path":"/","name":"Home","params":{},"query":{},"hash":"","fullPath":"/"}]`
)
describe('LocationAsRelative', () => {
it('matches with nothing', () => {
- const record = { path: '/home', name: 'Home', component }
+ const record = { path: '/home', name: 'Home', components }
assertRecordMatch(
record,
{},
})
it('replace params even with no name', () => {
- const record = { path: '/users/:id/m/:role', component }
+ const record = { path: '/users/:id/m/:role', components }
assertRecordMatch(
record,
{ params: { id: 'posva', role: 'admin' } },
const record = {
path: '/users/:id/m/:role',
name: 'UserEdit',
- component,
+ components,
}
assertRecordMatch(
record,
const record = {
path: '/users/:id/m/:role',
name: 'UserEdit',
- component,
+ components,
}
assertRecordMatch(
record,
})
it('keep params if not provided even with no name', () => {
- const record = { path: '/users/:id/m/:role', component }
+ const record = { path: '/users/:id/m/:role', components }
assertRecordMatch(
record,
{},
})
describe('redirects', () => {
- /**
- *
- * @param {RouteRecord[]} records Record or records we are testing the matcher against
- * @param {MatcherLocation} location location we want to reolve against
- * @param {MatcherLocationNormalized | MatcherLocationRedirect} expected Expected resolved location given by the matcher
- * @param {MatcherLocationNormalized} [currentLocation] Optional currentLocation used when resolving
- */
function assertRedirect(
- records,
- location,
- expected,
- currentLocation = START_LOCATION_NORMALIZED
+ records: RouteRecord[],
+ location: MatcherLocation,
+ expected: MatcherLocationNormalized | MatcherLocationRedirect,
+ currentLocation: MatcherLocationNormalized = START_LOCATION_NORMALIZED
) {
const matcher = new RouterMatcher(records)
const resolved = matcher.resolve(location, currentLocation)
it('resolves a redirect string', () => {
const records = [
- { path: '/home', component },
+ { path: '/home', components },
{ path: '/redirect', redirect: '/home' },
]
assertRedirect(
it('resolves a redirect function that returns a string', () => {
const redirect = () => '/home'
const records = [
- { path: '/home', component },
+ { path: '/home', components },
{ path: '/redirect', redirect },
]
assertRedirect(
path: '/home'
}
const records = [
- { path: '/home', component },
+ { path: '/home', components },
{ path: '/redirect', redirect },
]
assertRedirect(
it('resolves a redirect as an object', () => {
const records = [
- { path: '/home', component },
+ { path: '/home', components },
{ path: '/redirect', redirect: { path: 'home' } },
]
assertRedirect(
it('works with a named location', () => {
const records = [
- { path: '/home', component },
+ { path: '/home', components },
{ path: '/redirect', name: 'redirect', redirect: { path: 'home' } },
]
assertRedirect(
})
it('throws if relative location when redirecting', () => {
- const records = [
- { path: '/home', component },
- { path: '/redirect', redirect: '/home' },
- ]
expect(
assertErrorMatch(
{ path: '/redirect', redirect: '/home' },
})
it('normalize a location when redirecting', () => {
- const redirect = to => ({ name: 'b', params: to.params })
+ const redirect = (to: any) => ({ name: 'b', params: to.params })
const records = [
- { path: '/home', component },
+ { path: '/home', components },
{
path: '/a/:a',
name: 'a',
redirect,
},
- { path: '/b/:a', name: 'b', component },
+ { path: '/b/:a', name: 'b', components },
]
assertRedirect(
records,
})
it('throws if the current named route does not exists', () => {
- const record = { path: '/', component }
+ const record = { path: '/', components }
const start = {
name: 'home',
params: {},
})
describe('children', () => {
- const ChildA = { path: 'a', name: 'child-a', component }
- const ChildB = { path: 'b', name: 'child-b', component }
- const ChildC = { path: 'c', name: 'child-c', component }
- const ChildWithParam = { path: ':p', name: 'child-params', component }
+ const ChildA = { path: 'a', name: 'child-a', components }
+ const ChildB = { path: 'b', name: 'child-b', components }
+ const ChildC = { path: 'c', name: 'child-c', components }
+ const ChildWithParam = { path: ':p', name: 'child-params', components }
const NestedChildWithParam = {
...ChildWithParam,
name: 'nested-child-params',
const Nested = {
path: 'nested',
name: 'nested',
- component,
+ components,
children: [NestedChildA, NestedChildB, NestedChildC],
}
const NestedWithParam = {
path: 'nested/:n',
name: 'nested',
- component,
+ components,
children: [NestedChildWithParam],
}
const Foo = {
path: '/foo',
name: 'Foo',
- component,
+ components,
children: [ChildA, ChildB, ChildC],
}
assertRecordMatch(
})
it('resolves children with empty paths', () => {
- const Nested = { path: '', name: 'nested', component }
+ const Nested = { path: '', name: 'nested', components }
const Foo = {
path: '/foo',
name: 'Foo',
- component,
+ components,
children: [Nested],
}
assertRecordMatch(
})
it('resolves nested children with empty paths', () => {
- const NestedNested = { path: '', name: 'nested', component }
+ const NestedNested = { path: '', name: 'nested', components }
const Nested = {
path: '',
name: 'nested-nested',
- component,
+ components,
children: [NestedNested],
}
const Foo = {
path: '/foo',
name: 'Foo',
- component,
+ components,
children: [Nested],
}
assertRecordMatch(
const Foo = {
path: '/foo',
name: 'Foo',
- component,
+ components,
children: [Nested],
}
assertRecordMatch(
const Foo = {
path: '/foo',
name: 'Foo',
- component,
+ components,
children: [Nested],
}
assertRecordMatch(
const Foo = {
path: '/foo',
name: 'Foo',
- component,
+ components,
children: [Nested],
}
assertRecordMatch(
const Foo = {
path: '/foo',
name: 'Foo',
- component,
+ components,
children: [NestedWithParam],
}
assertRecordMatch(
const Foo = {
path: '/foo',
name: 'Foo',
- component,
+ components,
children: [NestedWithParam],
}
assertRecordMatch(
-// @ts-check
-const { parseQuery } = require('../src/history/utils')
+import { parseQuery } from '../src/history/utils'
describe('parseQuery', () => {
it('works with leading ?', () => {
/**
* @jest-environment jsdom
*/
-// @ts-check
// NOTE: these tests only run when using jest `yarn jest --watch`
-const { default: RouterLink } = require('../src/components/Link')
-const { components, isMocha, HistoryMock } = require('./utils')
-const { START_LOCATION_NORMALIZED } = require('../src/types')
+import RouterLink from '../src/components/Link'
+import { HistoryMock } from './utils'
+import {
+ START_LOCATION_NORMALIZED,
+ RouteQueryAndHash,
+ MatcherLocation,
+ RouteLocationNormalized,
+} from '../src/types'
+import { mount } from '@vue/test-utils'
-/** @typedef {import('../src/types').RouteLocationNormalized} RouteLocationNormalized */
-/** @typedef {import('../src/types').RouteRecord} RouteRecord */
-/** @typedef {import('../src/types').RouteLocation} RouteLocation */
-/** @typedef {import('../src/types').MatcherLocation} MatcherLocation */
-/** @typedef {import('../src/types').RouteQueryAndHash} RouteQueryAndHash */
-
-/** @type {Record<string, { string: string, normalized: RouteLocationNormalized, toResolve?: MatcherLocation & Required<RouteQueryAndHash> }>} */
-const locations = {
+const locations: Record<
+ string,
+ {
+ string: string
+ normalized: RouteLocationNormalized
+ toResolve?: MatcherLocation & Required<RouteQueryAndHash>
+ }
+> = {
basic: {
string: '/home',
// toResolve: { path: '/home', fullPath: '/home', undefined, query: {}, hash: '' },
}
describe('RouterLink', () => {
- // skip these tests on mocha because @vue/test-utils
- // do not work correctly
- if (isMocha()) return
- const { mount } = require('@vue/test-utils')
-
- /**
- *
- * @param {RouteLocationNormalized} currentLocation
- * @param {Object} propsData
- * @param {RouteLocationNormalized} resolvedLocation
- */
- function factory(currentLocation, propsData, resolvedLocation) {
+ function factory(
+ currentLocation: RouteLocationNormalized,
+ propsData: any,
+ resolvedLocation: RouteLocationNormalized
+ ) {
const router = {
history: new HistoryMock(),
resolve: jest.fn(),
/**
* @jest-environment jsdom
*/
-// @ts-check
// NOTE: these tests only run when using jest `yarn jest --watch`
-const { default: RouterView } = require('../src/components/View')
-const { components, isMocha } = require('./utils')
-const { START_LOCATION_NORMALIZED } = require('../src/types')
+import RouterView from '../src/components/View'
+import { components } from './utils'
+import {
+ START_LOCATION_NORMALIZED,
+ RouteLocationNormalized,
+} from '../src/types'
+import { mount } from '@vue/test-utils'
-/** @typedef {import('../src/types').RouteLocationNormalized} RouteLocationNormalized */
-
-/** @type {Record<string, RouteLocationNormalized>} */
-const routes = {
+const routes: Record<string, RouteLocationNormalized> = {
root: {
fullPath: '/',
name: undefined,
}
describe('RouterView', () => {
- // skip these tests on mocha because @vue/test-utils
- // do not work correctly
- if (isMocha()) return
- const { mount } = require('@vue/test-utils')
-
- /**
- *
- * @param {RouteLocationNormalized} $route
- * @param {Object} [props]
- */
- function factory($route, props = {}) {
+ function factory($route: RouteLocationNormalized, props: any = {}) {
// @ts-ignore cannot mount functional component?
const wrapper = mount(RouterView, {
context: {
-// @ts-check
-const fakePromise = require('faked-promise')
-const { HTML5History } = require('../src/history/html5')
-const { AbstractHistory } = require('../src/history/abstract')
-const { Router } = require('../src/router')
-const { NavigationCancelled } = require('../src/errors')
-const { createDom, components, tick, HistoryMock } = require('./utils')
+import fakePromise from 'faked-promise'
+import { AbstractHistory } from '../src/history/abstract'
+import { Router } from '../src/router'
+import { NavigationCancelled } from '../src/errors'
+import { createDom, components, tick, HistoryMock } from './utils'
+import { RouteRecord, RouteLocation } from '../src/types'
-/** @type {import('../src/types').RouteRecord[]} */
-const routes = [
+const routes: RouteRecord[] = [
{ path: '/', component: components.Home },
{ path: '/search', component: components.Home },
{ path: '/foo', component: components.Foo, name: 'Foo' },
})
describe('navigation', () => {
- async function checkNavigationCancelledOnPush(target) {
+ async function checkNavigationCancelledOnPush(
+ target?: RouteLocation | false | ((vm: any) => void)
+ ) {
const [p1, r1] = fakePromise()
const [p2, r2] = fakePromise()
const history = new HistoryMock()
if (to.name !== 'Param') return next()
if (to.params.p === 'a') {
await p1
- next(target)
+ // @ts-ignore: for some reason it's not handling the string here
+ target == null ? next() : next(target)
} else {
await p2
next()
await checkNavigationCancelledOnPush(undefined)
})
- async function checkNavigationCancelledOnPopstate(target) {
+ async function checkNavigationCancelledOnPopstate(
+ target?: RouteLocation | false | ((vm: any) => void)
+ ) {
const [p1, r1] = fakePromise()
const [p2, r2] = fakePromise()
const history = new AbstractHistory()
next()
} else if (from.fullPath === '/p/b') {
await p2
+ // @ts-ignore: same as function above
next(target)
} else {
next()
-// @ts-check
-const { renderApp, renderer } = require('./shared')
+import { renderApp, renderer } from './shared'
describe('SSR: basicRenderer', () => {
it('renders the view', async () => {
},
components: {
test: {
- render() {
- return this.$createElement('div', { class: ['a'] }, 'test')
- },
+ template: `<div class="a">test</div>`,
},
testAsync(resolve) {
resolve({
-import Vue from 'vue'
+import Vue, { ComponentOptions } from 'vue'
import Router from '../../src'
import { components } from '../utils'
export function renderApp(
context: { url: string },
routerOptions?: Partial<RouterOptions>,
- vueOptions?: any
+ vueOptions?: ComponentOptions<Vue>
) {
return new Promise<ReturnType<typeof createApp>['app']>((resolve, reject) => {
const { app, router } = createApp(routerOptions, vueOptions)
+++ /dev/null
-{
- "include": ["./**/*.ts", "./**/*.js"],
- "exclude": ["./helper.js"],
- "compilerOptions": {
- "target": "esnext",
- "module": "commonjs",
- "noEmit": true,
- "checkJs": true,
- "allowJs": true,
- "esModuleInterop": true
- }
-}
-// @ts-check
-const { Router } = require('../src/router')
-const { createDom, components, tick, HistoryMock } = require('./utils')
+import { Router } from '../src/router'
+import { createDom, components, HistoryMock } from './utils'
+import { RouteRecord } from '../src/types'
-/** @type {import('../src/types').RouteRecord[]} */
-const routes = [
+const routes: RouteRecord[] = [
{ path: '/', name: 'home', component: components.Home },
{ path: '/%25', name: 'percent', component: components.Home },
{ path: '/to-p/:p', redirect: to => `/p/${to.params.p}` },
{ path: '/p/:p', component: components.Bar, name: 'params' },
]
-function createHistory(initialUrl) {
- return new HistoryMock(initialUrl)
+// this function is meant to easy refactor in the future as Histories are going to be
+// function-based
+function createHistory(...args: ConstructorParameters<typeof HistoryMock>) {
+ return new HistoryMock(...args)
}
describe('URL Encoding', () => {
-// @ts-check
-const {
+import {
parseURL,
stringifyURL,
normalizeLocation,
-} = require('../src/history/utils')
+} from '../src/history/utils'
describe('parseURL', () => {
it('works with no query no hash', () => {
export const tick = () => new Promise(resolve => process.nextTick(resolve))
-export const NAVIGATION_TYPES = ['push', 'replace']
+export type NAVIGATION_METHOD = 'push' | 'replace'
+export const NAVIGATION_TYPES: NAVIGATION_METHOD[] = ['push', 'replace']
declare global {
namespace NodeJS {
},
}
-// allow using a .jest modifider to skip some tests on mocha
-// specifically, skip component tests as they are a pain to correctly
-// adapt to mocha
-export const isMocha = () => typeof global.before === 'function'
-
/**
* Copies and normalizes the record so it always contains an object of `components`
*
'src/consola.ts',
],
testMatch: [
- '**/__tests__/**/*.spec.[j]s?(x)',
+ '**/__tests__/**/*.spec.ts?(x)',
// '**/__tests__/**/*.spec.[jt]s?(x)',
// '**/?(*.)+(spec|test).[jt]s?(x)',
],
"types": "dist/index.d.ts",
"license": "MIT",
"scripts": {
- "test:types:src": "tsc --build tsconfig.check-types.json",
- "test:types:test": "tsc --build __tests__/tsconfig.json",
- "test:types": "yarn test:types:src && yarn test:types:test",
+ "test:types": "tsc --build tsconfig.json",
"test:unit": "jest --coverage",
"test": "yarn run test:types && yarn run test:unit && yarn build",
"build": "yarn rollup -c rollup.config.js",
"codecov": "^3.6.1",
"consola": "^2.10.1",
"expect": "^24.9.0",
- "faked-promise": "^2.1.0",
+ "faked-promise": "^2.2.2",
"html-webpack-plugin": "^3.2.0",
"jest": "^24.9.0",
"jsdom": "^15.1.1",
+++ /dev/null
-{
- "include": ["src/**/*.ts"],
- "compilerOptions": {
- "target": "esnext",
- "module": "commonjs",
- // "lib": ["es2017.object"] ,
- "allowJs": true,
- "checkJs": true,
- // "declaration": true ,
- // "sourceMap": true ,
- // "outFile": "./", /* Concatenate and emit output to single file. */
- // "outDir": "./dist" ,
- // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
- // "composite": true, /* Enable project compilation */
- "noEmit": true,
-
- "strict": true,
- "noUnusedLocals": true,
- // "noUnusedParameters": true,
- "noImplicitReturns": true,
-
- "moduleResolution": "node",
- "esModuleInterop": true
- }
-}
{
- "include": ["src/**/*.ts"],
+ "include": ["src/**/*.ts", "__tests__/**/*.ts"],
"compilerOptions": {
- /* Basic Options */
- "target": "esnext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
- // Necessary for tests with mocha
- "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
+ "target": "esnext",
+ "module": "commonjs",
// "lib": ["es2017.object"] /* Specify library files to be included in the compilation. */,
- // "allowJs": true, /* Allow javascript files to be compiled. */
- // "checkJs": true, /* Report errors in .js files. */
- // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
- "declaration": true /* Generates corresponding '.d.ts' file. */,
- // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
- "sourceMap": true /* Generates corresponding '.map' file. */,
- // "outFile": "./", /* Concatenate and emit output to single file. */
- "outDir": "./dist" /* Redirect output structure to the directory. */,
- // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
- // "composite": true, /* Enable project compilation */
- "removeComments": false /* Do not emit comments to output. */,
- // "noEmit": true, /* Do not emit outputs. */
- // "importHelpers": true, /* Import emit helpers from 'tslib'. */
- // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
- // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
+ "declaration": true,
+ // "declarationMap": true,
+ "sourceMap": true,
+ "outDir": "./dist",
+ "removeComments": false,
+ "noEmit": true,
- /* Strict Type-Checking Options */
- "strict": true /* Enable all strict type-checking options. */,
- // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
- // "strictNullChecks": true, /* Enable strict null checks. */
- // "strictFunctionTypes": true, /* Enable strict checking of function types. */
- // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
- // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
- // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
+ "strict": true,
- /* Additional Checks */
- "noUnusedLocals": true /* Report errors on unused locals. */,
- // "noUnusedParameters": true, /* Report errors on unused parameters. */
- "noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
- // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
+ "noUnusedLocals": true,
+ // "noUnusedParameters": true,
+ "noImplicitReturns": true,
- /* Module Resolution Options */
- "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
- // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
- // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
- // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
- // "typeRoots": [], /* List of folders to include type definitions from. */
- // "types": [], /* Type declaration files to be included in compilation. */
- // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
- "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
- // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
-
- /* Source Map Options */
- // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
- // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */
- // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
- // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
-
- /* Experimental Options */
- // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
- // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
+ "moduleResolution": "node",
+ "esModuleInterop": true
}
}
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
-faked-promise@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/faked-promise/-/faked-promise-2.1.0.tgz#988dd6f7e1c30638be2cd0d67e944b51d5dbbaeb"
- integrity sha512-p5QCxMj8OsHjBs0aIEbg1WFW019Tib3LIWpz6Fyl5uVf4A3FRJzcMrJgiTgwVB5k99k3M566U6NUa/rEi473fA==
+faked-promise@^2.2.2:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/faked-promise/-/faked-promise-2.2.2.tgz#c89dd11d29a561bb03229813e3aa13a369df137c"
+ integrity sha512-1kaSWavyNHJw83/aJ0dZAhKWID/FAED9vlgBa43kW8Vb61BSXORXf8f9W6NJ7qepTtlPSaJc557qkpxT1HCUBw==
fast-deep-equal@^2.0.1:
version "2.0.1"