]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
fix(history): allow hash history with no origin
authorEduardo San Martin Morote <posva13@gmail.com>
Mon, 13 Apr 2020 14:50:12 +0000 (16:50 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Mon, 13 Apr 2020 14:50:12 +0000 (16:50 +0200)
Close #163

__tests__/history/hash.spec.ts [new file with mode: 0644]
__tests__/history/html5.spec.ts
src/history/common.ts
src/history/hash.ts
src/history/html5.ts

diff --git a/__tests__/history/hash.spec.ts b/__tests__/history/hash.spec.ts
new file mode 100644 (file)
index 0000000..07eb78e
--- /dev/null
@@ -0,0 +1,81 @@
+import { JSDOM } from 'jsdom'
+import createWebHashHistory from '../../src/history/hash'
+import createWebHistory from '../../src/history/html5'
+import { createDom } from '../utils'
+
+jest.mock('../../src/history/html5')
+
+describe('History Hash', () => {
+  let dom: JSDOM
+  beforeAll(() => {
+    dom = createDom()
+  })
+
+  beforeEach(() => {
+    ;(createWebHistory as jest.Mock).mockClear()
+  })
+
+  afterAll(() => {
+    dom.window.close()
+  })
+
+  afterEach(() => {
+    // ensure no base element is left after a test as only the first is
+    // respected
+    for (let element of Array.from(document.getElementsByTagName('base')))
+      element.remove()
+  })
+
+  describe('url', () => {
+    beforeEach(() => {
+      dom.reconfigure({ url: 'https://example.com' })
+    })
+
+    it('should use a correct', () => {
+      createWebHashHistory()
+      expect(createWebHistory).toHaveBeenCalledWith('/#')
+    })
+
+    it('should be able to provide a base', () => {
+      createWebHashHistory('/folder/')
+      expect(createWebHistory).toHaveBeenCalledWith('/folder/#')
+    })
+
+    it('should be able to provide a base with no trailing slash', () => {
+      createWebHashHistory('/folder')
+      expect(createWebHistory).toHaveBeenCalledWith('/folder/#')
+    })
+
+    it('should read the base tag', () => {
+      const baseEl = document.createElement('base')
+      baseEl.href = '/foo/'
+      document.head.appendChild(baseEl)
+      createWebHashHistory()
+      expect(createWebHistory).toHaveBeenCalledWith('/foo/#')
+    })
+
+    it('should use the base option over the base tag', () => {
+      const baseEl = document.createElement('base')
+      baseEl.href = '/foo/'
+      document.head.appendChild(baseEl)
+      createWebHashHistory('/bar/')
+      expect(createWebHistory).toHaveBeenCalledWith('/bar/#')
+    })
+  })
+
+  describe('file://', () => {
+    beforeEach(() => {
+      dom.reconfigure({ url: 'file:///usr/some-file.html' })
+    })
+
+    it('should use a correct base', () => {
+      createWebHashHistory()
+      // both, a trailing / and none work
+      expect(createWebHistory).toHaveBeenCalledWith(
+        expect.stringMatching(/^#\/?$/)
+      )
+    })
+
+    it.todo('warns if we provide a base with file://')
+  })
+})
index e0b48448c120a9d90caeb7777af3a13bd268edfd..1d6f0e4138c36675354405fdd07d80dd5cce6bf0 100644 (file)
@@ -68,4 +68,14 @@ describe('History HTMl5', () => {
     expect(createWebHistory('/foo/').base).toBe('/foo')
     expect(createWebHistory('/foo').base).toBe('/foo')
   })
+
+  it('handles a single hash base', () => {
+    expect(createWebHistory('#').base).toBe('#')
+    expect(createWebHistory('#/').base).toBe('#')
+  })
+
+  it('handles a non-empty hash base', () => {
+    expect(createWebHistory('#/bar').base).toBe('#/bar')
+    expect(createWebHistory('#/bar/').base).toBe('#/bar')
+  })
 })
index 314f006f90841c75fe2f0aa419b33a07453c0efa..3fbdd0a117a8c21d0d5ddad12cfa3335a154fa86 100644 (file)
@@ -145,3 +145,32 @@ export function normalizeHistoryLocation(
     fullPath: (location as HistoryLocation).fullPath || (location as string),
   }
 }
+
+/**
+ * Normalizes a base by removing any trailing slash and reading the base tag if
+ * present.
+ *
+ * @param base base to normalize
+ */
+export function normalizeBase(base?: string): string {
+  if (!base) {
+    if (__BROWSER__) {
+      // respect <base> tag
+      const baseEl = document.querySelector('base')
+      base = (baseEl && baseEl.getAttribute('href')) || '/'
+      // strip full URL origin
+      base = base.replace(/^\w+:\/\/[^\/]+/, '')
+    } else {
+      base = '/'
+    }
+  }
+
+  // ensure leading slash when it was removed by the regex above avoid leading
+  // slash with hash because the file could be read from the disk like file://
+  // and the leading slash would cause problems
+  if (base.charAt(0) !== '/' && base.charAt(0) !== '#') base = '/' + base
+
+  // remove the trailing slash so all other method can just do `base + fullPath`
+  // to build an href
+  return base.replace(/\/$/, '')
+}
index baff034196e2dcab41f4ab45368086f4fe2e04db..6b687e93edf24a7dafecd1364d7629cbfa894d4d 100644 (file)
@@ -1,7 +1,7 @@
-import { RouterHistory } from './common'
+import { RouterHistory, normalizeBase } from './common'
 import createWebHistory from './html5'
 
-export default function createWebHashHistory(base: string = ''): RouterHistory {
+export default function createWebHashHistory(base?: string): RouterHistory {
   // Make sure this implementation is fine in terms of encoding, specially for IE11
-  return createWebHistory(base + '/#')
+  return createWebHistory(location.host ? normalizeBase(base) + '/#' : '#')
 }
index 8ac97dd4f33b1f9964bca5489615fde269994ed9..f5cb32202397b1edd6c1177d1d34712e56dd4331 100644 (file)
@@ -8,6 +8,7 @@ import {
   HistoryState,
   RawHistoryLocation,
   ValueContainer,
+  normalizeBase,
 } from './common'
 import { computeScrollPosition, ScrollToPosition } from '../utils/scroll'
 import { warn } from 'vue'
@@ -262,33 +263,6 @@ function useHistoryStateNavigation(base: string) {
   }
 }
 
-/**
- * Normalizes a base by removing any trailing slash and reading the base tag if
- * present.
- *
- * @param base base to normalize
- */
-function normalizeBase(base?: string): string {
-  if (!base) {
-    if (__BROWSER__) {
-      // respect <base> tag
-      const baseEl = document.querySelector('base')
-      base = (baseEl && baseEl.getAttribute('href')) || '/'
-      // strip full URL origin
-      base = base.replace(/^\w+:\/\/[^\/]+/, '')
-    } else {
-      base = '/'
-    }
-  }
-
-  // ensure leading slash when it was removed by the regex above
-  if (base.charAt(0) !== '/') base = '/' + base
-
-  // remove the trailing slash so all other method can just do `base + fullPath`
-  // to build an href
-  return base.replace(/\/$/, '')
-}
-
 export default function createWebHistory(base?: string): RouterHistory {
   base = normalizeBase(base)