From: Eduardo San Martin Morote Date: Thu, 11 Apr 2019 15:45:03 +0000 (+0200) Subject: test: add tests for parseURL X-Git-Tag: v4.0.0-alpha.0~460 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bd48be1e1a564dd3f04e1df414d7d789c4db40de;p=thirdparty%2Fvuejs%2Frouter.git test: add tests for parseURL --- diff --git a/__tests__/url.spec.ts b/__tests__/url.spec.ts new file mode 100644 index 00000000..18ae8051 --- /dev/null +++ b/__tests__/url.spec.ts @@ -0,0 +1,40 @@ +import { BaseHistory } from '../src/history/base' + +const parseURL = BaseHistory.prototype.parseURL + +describe('URL parsing', () => { + it('works with no query no hash', () => { + expect(parseURL('/foo')).toEqual({ + path: '/foo', + hash: '', + query: {}, + }) + }) + + it('extracts the query', () => { + expect(parseURL('/foo?a=one&b=two')).toEqual({ + path: '/foo', + hash: '', + query: { + a: 'one', + b: 'two', + }, + }) + }) + + it('extracts the hash', () => { + expect(parseURL('/foo#bar')).toEqual({ + path: '/foo', + hash: '#bar', + query: {}, + }) + }) + + it('extracts query and hash', () => { + expect(parseURL('/foo?a=one#bar')).toEqual({ + path: '/foo', + hash: '#bar', + query: { a: 'one' }, + }) + }) +}) diff --git a/src/history/abstract.ts b/src/history/abstract.ts index d21ee4c9..93e8460a 100644 --- a/src/history/abstract.ts +++ b/src/history/abstract.ts @@ -1,21 +1,11 @@ import consola from 'consola' import { BaseHistory } from './base' -import { - HistoryLocation, - NavigationCallback, - HistoryState, - NavigationType, - HistoryURL, -} from './base' +import { HistoryLocation, NavigationCallback, HistoryState } from './base' -const cs = consola.withTag('html5') - -type PopStateListener = (this: Window, ev: PopStateEvent) => any +const cs = consola.withTag('abstract') export class AbstractHistory extends BaseHistory { - private history = window.history - private _popStateListeners: PopStateListener[] = [] - private _listeners: NavigationCallback[] = [] + // private _listeners: NavigationCallback[] = [] private _teardowns: Array<() => void> = [] constructor() { @@ -23,137 +13,14 @@ export class AbstractHistory extends BaseHistory { } // TODO: is this necessary - ensureLocation() { - const to = buildFullPath() - cs.log('ensureLocation', to) - this.history.replaceState( - { - _back: null, - _current: to, - _forward: null, - }, - '', - to - ) - this.location = to - } + ensureLocation() {} - replace(to: HistoryLocation) { - if (to === this.location) return - cs.info('replace', this.location, to) - this.history.replaceState( - { - // TODO: this should be user's responsibility - // _replacedState: this.history.state || null, - _back: this.location, - _current: to, - _forward: null, - _replaced: true, - }, - '', - to - ) - this.location = to - } + replace(to: HistoryLocation) {} - push(to: HistoryLocation, data?: HistoryState) { - // replace current entry state to add the forward value - this.history.replaceState( - { - ...this.history.state, - _forward: to, - }, - '' - ) - // TODO: compare current location to prevent navigation - // NEW NOTE: I think it shouldn't be history responsibility to check that - // if (to === this.location) return - const state = { - _back: this.location, - _current: to, - _forward: null, - ...data, - } - cs.info('push', this.location, '->', to, 'with state', state) - this.history.pushState(state, '', to) - this.location = to - } + push(to: HistoryLocation, data?: HistoryState) {} listen(callback: NavigationCallback) { - // state is the same as history.state - const handler: PopStateListener = ({ state }) => { - cs.log(this) - cs.info('popstate fired', { - state, - location: this.location, - }) - const from = this.location - // we have the state from the old entry, not the current one being removed - // TODO: correctly parse pathname - this.location = state ? state._current : buildFullPath - callback(this.location, from, { - type: - from === state._forward - ? NavigationType.back - : NavigationType.forward, - }) - } - - // settup the listener and prepare teardown callbacks - this._popStateListeners.push(handler) - this._listeners.push(callback) - window.addEventListener('popstate', handler) - - const teardown = () => { - this._popStateListeners.splice( - this._popStateListeners.indexOf(handler), - 1 - ) - this._listeners.splice(this._listeners.indexOf(callback), 1) - window.removeEventListener('popstate', handler) - } - - this._teardowns.push(teardown) - return teardown - } - - parseURL(location: string): HistoryURL { - let path = '', - search: HistoryURL['search'] = {}, - searchString = '', - hash = '' - - // Could use URL and URLSearchParams but IE 11 doesn't support it - const searchPos = location.indexOf('?') - const hashPos = location.indexOf(location, searchPos > -1 ? searchPos : 0) - if (searchPos > -1) { - path = location.slice(0, searchPos) - searchString = location.slice( - searchPos + 1, - hashPos > -1 ? hashPos : location.length - 1 - ) - - // TODO: properly do this in a util function - search = searchString.split('&').reduce((search, entry) => { - const [key, value] = entry.split('=') - search[key] = value - return search - }, search) - } - - if (hashPos > -1) { - path = path || location.slice(0, hashPos) - hash = location.slice(hashPos, location.length - 1) - } - - path = path || location - - return { - path, - // TODO: transform searchString - search, - hash, - } + return () => {} } destroy() { @@ -161,6 +28,3 @@ export class AbstractHistory extends BaseHistory { this._teardowns = [] } } - -const buildFullPath = () => - window.location.pathname + window.location.search + window.location.hash diff --git a/src/history/base.ts b/src/history/base.ts index 2001c368..767ffffc 100644 --- a/src/history/base.ts +++ b/src/history/base.ts @@ -1,7 +1,7 @@ export type HistoryLocation = string export interface HistoryURL { path: string - search: Record + query: Record // TODO: handle arrays hash: string } @@ -72,7 +72,45 @@ export abstract class BaseHistory { * @param location location to normalize * @param currentLocation current location, to reuse params and location */ - abstract parseURL(location: HistoryLocation): HistoryURL + parseURL(location: string): HistoryURL { + let path = '', + query: HistoryURL['query'] = {}, + searchString = '', + hash = '' + + // Could use URL and URLSearchParams but IE 11 doesn't support it + // TODO: move this utility to base.ts so it can be used by any history implementation + const searchPos = location.indexOf('?') + const hashPos = location.indexOf('#', searchPos > -1 ? searchPos : 0) + if (searchPos > -1) { + path = location.slice(0, searchPos) + searchString = location.slice( + searchPos + 1, + hashPos > -1 ? hashPos : location.length + ) + + // TODO: properly do this in a util function + query = searchString.split('&').reduce((query, entry) => { + const [key, value] = entry.split('=') + query[key] = value + return query + }, query) + } + + if (hashPos > -1) { + path = path || location.slice(0, hashPos) + hash = location.slice(hashPos, location.length) + } + + path = path || location + + return { + path, + // TODO: transform searchString + query, + hash, + } + } /** * ensure the current location matches the external source diff --git a/src/history/html5.ts b/src/history/html5.ts index bac509b5..209d5eb1 100644 --- a/src/history/html5.ts +++ b/src/history/html5.ts @@ -5,7 +5,6 @@ import { NavigationCallback, HistoryState, NavigationType, - HistoryURL, } from './base' const cs = consola.withTag('html5') @@ -101,45 +100,6 @@ export class HTML5History extends BaseHistory { return teardown } - parseURL(location: string): HistoryURL { - let path = '', - search: HistoryURL['search'] = {}, - searchString = '', - hash = '' - - // Could use URL and URLSearchParams but IE 11 doesn't support it - const searchPos = location.indexOf('?') - const hashPos = location.indexOf(location, searchPos > -1 ? searchPos : 0) - if (searchPos > -1) { - path = location.slice(0, searchPos) - searchString = location.slice( - searchPos + 1, - hashPos > -1 ? hashPos : location.length - 1 - ) - - // TODO: properly do this in a util function - search = searchString.split('&').reduce((search, entry) => { - const [key, value] = entry.split('=') - search[key] = value - return search - }, search) - } - - if (hashPos > -1) { - path = path || location.slice(0, hashPos) - hash = location.slice(hashPos, location.length - 1) - } - - path = path || location - - return { - path, - // TODO: transform searchString - search, - hash, - } - } - /** * Remove all listeners attached to the history and cleanups the history * instance