From cf6242da35d300d02077103c5aaa514fcc273bd1 Mon Sep 17 00:00:00 2001 From: Karol Baczewski Date: Thu, 1 Mar 2018 15:47:39 +0000 Subject: [PATCH 1/7] Preserve query parameters when rebasing location path --- location.js | 10 +++++----- package.json | 2 +- test/location.test.js | 42 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/location.js b/location.js index 2bc4e9d..2755085 100644 --- a/location.js +++ b/location.js @@ -12,7 +12,7 @@ define(function(require) { if (isHashPath(location.hash)) { // Redirect current hash fragment location to "real" path - history.replaceState(null, null, rebase(fullPath(location))) + history.replaceState(null, null, rebase(fullPath(location)) + location.search) } var api = @@ -32,7 +32,7 @@ define(function(require) { function setState(path) { var actual = pushState(path) - + if (actual) { dispatcher.statechange(actual) return actual @@ -51,7 +51,7 @@ define(function(require) { if (path === getState()) { return false } else { - method({ base: base, path: path }, null, rebase(path)) + method({ base: base, path: path }, null, rebase(path) + location.search) return path } } @@ -111,7 +111,7 @@ define(function(require) { path = rebase(a.hash.slice(1)) } else if (a.hash || a.href.slice(location.href.length) === '#') { // Ignore links with a non-path hash, and empty hashes (e.g.: ``) - return + return } else { path = rebase(fullPath(a)) } @@ -194,4 +194,4 @@ define(function(require) { function trimSlashes(path) { return (path || '').replace(/^\/+|\/+$/g, '') } -}) \ No newline at end of file +}) diff --git a/package.json b/package.json index 70f75f2..e896f23 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "rimraf": "^2.5.2", "sinon": "^1.14.1", "squirejs": "^0.2.1", - "webpack": "^1.12.2" + "webpack": "^1.15.0" }, "scripts": { "test": "karma start --single-run", diff --git a/test/location.test.js b/test/location.test.js index 4173201..bed3a8f 100644 --- a/test/location.test.js +++ b/test/location.test.js @@ -37,7 +37,7 @@ define(function(require) { expect(location.basePath()).to.equal('/foo') expect(location.getState()).to.equal(originalPath) expect(window.location.pathname).to.equal('/foo' + originalPath) - expect(window.history.length).to.equal(historyEntries) + expect(window.history.length).to.equal(historyEntries) location.basePath('/bar') expect(location.basePath()).to.equal('/bar') @@ -60,6 +60,16 @@ define(function(require) { }) describe(`location.pushState()`, function() { + var originalHref + + before(function() { + originalHref = window.location.href + }) + + afterEach(function() { + window.history.pushState(null, null, originalHref) + }) + it('should update the current location', function() { expect(location.getState()).to.not.equal('/base/foo') expect(location.pushState('/base/foo')).to.equal('/base/foo') @@ -79,7 +89,7 @@ define(function(require) { it('should do nothing when pushing the current location', function() { expect(location.pushState(location.getState())).to.equal(false) - + location.basePath('/base') expect(location.pushState(location.getState())).to.equal(false) }) @@ -104,6 +114,28 @@ define(function(require) { location.on('statechange.test-no-dispatch', null) }) + + it('should preserve query parameters', function() { + var loc = window.location + var originalQuery = new URLSearchParams(loc.search.substring(1)) + + originalQuery.set('foo', 'bar') + originalQuery.set('fizz', 'buzz') + + window.history.replaceState( + null, null, + loc.origin + loc.pathname + '?' + originalQuery.toString() + ) + + location.basePath('/base') + location.getState() + location.pushState('/base/foo') + + var newQuery = new URLSearchParams(window.location.search.substring(1)) + + expect(newQuery.get('foo')).to.equal('bar') + expect(newQuery.get('fizz')).to.equal('buzz') + }) }) describe(`location.setState()`, function() { @@ -223,7 +255,7 @@ define(function(require) { window.history.back() expect(changedState).to.eql({ base: '', path: '/back' }) expect(location.getState()).to.equal('/back') - + changedState = undefined window.history.forward() expect(changedState).to.eql({ base: '', path: '/forward' }) @@ -231,7 +263,7 @@ define(function(require) { location.on('statechange.test-history', null) }) - describe(`location.handleClick()`, function() { + describe(`location.handleClick()`, function() { var changedState, anchor, handledClick beforeEach(function() { @@ -340,4 +372,4 @@ define(function(require) { }) }) }) -}) \ No newline at end of file +}) From 0470195785aecc6a7e505aa74828d27a1c76159d Mon Sep 17 00:00:00 2001 From: Karol Baczewski Date: Mon, 5 Mar 2018 12:14:04 +0000 Subject: [PATCH 2/7] convert location module into factory to allow testing --- address.js | 2 +- bundle.js | 2 +- location.js | 299 +++++++++++++++++++++--------------------- test/address.test.js | 2 +- test/location.test.js | 7 +- 5 files changed, 160 insertions(+), 152 deletions(-) diff --git a/address.js b/address.js index 8e704e7..8f0be69 100644 --- a/address.js +++ b/address.js @@ -15,7 +15,7 @@ define(function(require) { , error = require('./error') , dispatch = require('d3-dispatch').dispatch , rebind = require('./rebind') - , location = require('./location') + , location = require('./location')() , middleware = require('./middleware') function address(r) { diff --git a/bundle.js b/bundle.js index 6df8714..86d85ae 100644 --- a/bundle.js +++ b/bundle.js @@ -6,7 +6,7 @@ define(function(require) { , httpStatusCode: require('./http-status-code') , interpolate: require('./interpolate') , into: require('./into') - , location: require('./location') + , location: require('./location')() , middleware: require('./middleware') , ok: require('./ok') , redirect: require('./redirect') diff --git a/location.js b/location.js index 2755085..caf8dfd 100644 --- a/location.js +++ b/location.js @@ -1,197 +1,200 @@ define(function(require) { var findClosest = require('./find-closest') - , rebind = require('./rebind') - , dispatcher = require('d3-dispatch').dispatch('statechange') - , history = window.history - , location = window.location - , on = require('./on') - , base = '' - - on.call(window, 'popstate.location', handleStateChange) - on.call(document, 'click.location', handleClick) - - if (isHashPath(location.hash)) { - // Redirect current hash fragment location to "real" path - history.replaceState(null, null, rebase(fullPath(location)) + location.search) - } - - var api = - { getState: getState - , setState: setState - , pushState: deprecatedPushState - , replaceState: replaceState - , openNewWindow: openNewWindow - , basePath: basePath - } - - return rebind(api, dispatcher, 'on') + var rebind = require('./rebind') + var dispatcher = require('d3-dispatch').dispatch('statechange') + var on = require('./on') - function getState() { - return unbase(fullPath(location)) - } + return function () { + var history = window.history + var location = window.location + var base = '' - function setState(path) { - var actual = pushState(path) + on.call(window, 'popstate.location', handleStateChange) + on.call(document, 'click.location', handleClick) - if (actual) { - dispatcher.statechange(actual) - return actual - } else { - return false + if (isHashPath(location.hash)) { + // Redirect current hash fragment location to "real" path + history.replaceState(null, null, rebase(fullPath(location)) + location.search) } - } - function trimPath(path) { - return '/' + trimSlashes(~path.indexOf('#/')? path.split('#/')[1] : path) - } + var api = + { getState: getState + , setState: setState + , pushState: deprecatedPushState + , replaceState: replaceState + , openNewWindow: openNewWindow + , basePath: basePath + } - function updateState(path, method) { - path = unbase(trimPath(path)) + return rebind(api, dispatcher, 'on') - if (path === getState()) { - return false - } else { - method({ base: base, path: path }, null, rebase(path) + location.search) - return path + function getState() { + return unbase(fullPath(location)) } - } - function deprecatedPushState(path) { - console.warn('deprecated : location.pushState, to be removed in v.4.0.0.') - return pushState(path) - } + function setState(path) { + var actual = pushState(path) - function pushState(path) { - return updateState(path, history.pushState.bind(history)) - } + if (actual) { + dispatcher.statechange(actual) + return actual + } else { + return false + } + } - function replaceState(path) { - return updateState(path, history.replaceState.bind(history)) - } + function trimPath(path) { + return '/' + trimSlashes(~path.indexOf('#/')? path.split('#/')[1] : path) + } - function openNewWindow(path, target) { - return window.open(rebase(path), target, '') - } + function updateState(path, method) { + path = unbase(trimPath(path)) - function basePath(path) { - if (arguments.length === 0) return base + if (path === getState()) { + return false + } else { + method({ base: base, path: path }, null, rebase(path) + location.search) + return path + } + } - var cwd = unbase(fullPath(location)) + function deprecatedPushState(path) { + console.warn('deprecated : location.pushState, to be removed in v.4.0.0.') + return pushState(path) + } - path = trimSlashes(path) - base = path? '/' + path : '' + function pushState(path) { + return updateState(path, history.pushState.bind(history)) + } - history.replaceState(null, null, rebase(cwd)) - } + function replaceState(path) { + return updateState(path, history.replaceState.bind(history)) + } - function handleClick(event) { - var a - , target = event.target - , path + function openNewWindow(path, target) { + return window.open(rebase(path), target, '') + } - if (event.ctrlKey) return // Ignore ctrl+click - if (event.button !== 0) return // Ignore clicks by buttons other than primary (usually left button) + function basePath(path) { + if (arguments.length === 0) return base - a = findClosest.anchor(target) + var cwd = unbase(fullPath(location)) - if ( !a // non-anchor clicks - || !!a.target // anchors with specified targets - || a.hasAttribute('download') // anchors with download attribute - || !isSameOrigin(a, location) // links to different origins - ) { - /* If any of the above conditions are true, we ignore the click and - * let the browser deal with the navigation as it sees fit - */ - return + path = trimSlashes(path) + base = path? '/' + path : '' + + history.replaceState(null, null, rebase(cwd)) } - var path + function handleClick(event) { + var a + , target = event.target + , path + + if (event.ctrlKey) return // Ignore ctrl+click + if (event.button !== 0) return // Ignore clicks by buttons other than primary (usually left button) + + a = findClosest.anchor(target) + + if ( !a // non-anchor clicks + || !!a.target // anchors with specified targets + || a.hasAttribute('download') // anchors with download attribute + || !isSameOrigin(a, location) // links to different origins + ) { + /* If any of the above conditions are true, we ignore the click and + * let the browser deal with the navigation as it sees fit + */ + return + } - if (isHashPath(a.hash)) { - path = rebase(a.hash.slice(1)) - } else if (a.hash || a.href.slice(location.href.length) === '#') { - // Ignore links with a non-path hash, and empty hashes (e.g.: ``) - return - } else { - path = rebase(fullPath(a)) - } + var path - if (path) { - event.preventDefault() - event.stopPropagation() - var actual = pushState(path) + if (isHashPath(a.hash)) { + path = rebase(a.hash.slice(1)) + } else if (a.hash || a.href.slice(location.href.length) === '#') { + // Ignore links with a non-path hash, and empty hashes (e.g.: ``) + return + } else { + path = rebase(fullPath(a)) + } - if (actual) { - dispatcher.statechange(actual) + if (path) { + event.preventDefault() + event.stopPropagation() + var actual = pushState(path) + + if (actual) { + dispatcher.statechange(actual) + } } } - } - function handleStateChange(event) { - var path, base = (event.state && event.state.base) || '' + function handleStateChange(event) { + var path, base = (event.state && event.state.base) || '' - if (isHashPath(location.hash)) { - // "Redirect" current location to a proper path - path = location.hash.slice(1) + if (isHashPath(location.hash)) { + // "Redirect" current location to a proper path + path = location.hash.slice(1) - if (path) { - var state = { base: base, path: path } - history.replaceState(state, null, rebase(path)) + if (path) { + var state = { base: base, path: path } + history.replaceState(state, null, rebase(path)) + } + } else { + path = fullPath(location) } - } else { - path = fullPath(location) + + dispatcher.statechange(unbase(path)) } - dispatcher.statechange(unbase(path)) - } + function isHashPath(hash) { + return (hash || '').slice(0, 2) === '#/' + } - function isHashPath(hash) { - return (hash || '').slice(0, 2) === '#/' - } + function isSameOrigin(a, x) { + var o = origin(x) + return a.href.slice(0, o.length) === o + } - function isSameOrigin(a, x) { - var o = origin(x) - return a.href.slice(0, o.length) === o - } + function origin(url) { + if (url.origin) { + return url.origin + } else { + var port - function origin(url) { - if (url.origin) { - return url.origin - } else { - var port + if (url.port && !~url.href.indexOf(':' + url.port)) { + // IE defaults port values based on protocol, which messes things up + port = '' + } else { + port = ':' + url.port + } - if (url.port && !~url.href.indexOf(':' + url.port)) { - // IE defaults port values based on protocol, which messes things up - port = '' - } else { - port = ':' + url.port + return url.protocol + "//" + url.hostname + port } - - return url.protocol + "//" + url.hostname + port } - } - function fullPath(url) { - if (isHashPath(url.hash)) { - return url.hash.slice(1) - } else { - return url.href.slice(origin(url).length) + function fullPath(url) { + if (isHashPath(url.hash)) { + return url.hash.slice(1) + } else { + return url.href.slice(origin(url).length) + } } - } - function rebase(path) { - return base + '/' + trimSlashes(unbase(path)) - } + function rebase(path) { + return base + '/' + trimSlashes(unbase(path)) + } - function unbase(path) { - if (path.slice(0, base.length) === base) { - return path.slice(base.length) - } else { - return path + function unbase(path) { + if (path.slice(0, base.length) === base) { + return path.slice(base.length) + } else { + return path + } } - } - function trimSlashes(path) { - return (path || '').replace(/^\/+|\/+$/g, '') + function trimSlashes(path) { + return (path || '').replace(/^\/+|\/+$/g, '') + } } }) diff --git a/test/address.test.js b/test/address.test.js index ff4f8e7..1cf5a82 100644 --- a/test/address.test.js +++ b/test/address.test.js @@ -1,7 +1,7 @@ define(function(require) { var sinon = require('sinon') , zapp = require('z-app') - , location = require('location') + , location = require('location')() , address , web , nap diff --git a/test/location.test.js b/test/location.test.js index bed3a8f..1cec6b6 100644 --- a/test/location.test.js +++ b/test/location.test.js @@ -1,5 +1,10 @@ define(function(require) { - var location = require('location') + var getLocationModule = require('location') + var location + + beforeEach(function() { + location = getLocationModule() + }) describe('Location', function() { var originalPath From f65a1351d6add85160b1494ebb1aa1d53b3ff309 Mon Sep 17 00:00:00 2001 From: Karol Baczewski Date: Mon, 5 Mar 2018 13:42:11 +0000 Subject: [PATCH 3/7] test query params preserving when "upgrading" from hash path --- test/location.test.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/location.test.js b/test/location.test.js index 1cec6b6..8809789 100644 --- a/test/location.test.js +++ b/test/location.test.js @@ -18,6 +18,32 @@ define(function(require) { window.history.replaceState(null, null, originalPath) }) + describe('Instantiation', function() { + describe('upgrading from hash path', function() { + it('should preserve query parameters', function() { + var loc = window.location + var originalQuery = new URLSearchParams() + + originalQuery.set('foo', 'bar') + originalQuery.set('fizz', 'buzz') + + window.history.replaceState( + null, null, + loc.origin + loc.pathname + + '?' + originalQuery.toString() + + '#/app/workspaces' + ) + + location = getLocationModule() + + var newQuery = new URLSearchParams(loc.search.substring(1)) + + expect(newQuery.get('foo')).to.equal('bar') + expect(newQuery.get('fizz')).to.equal('buzz') + }) + }) + }) + describe('API', function() { describe(`location.getState()`, function() { it('should always get the current window location', function() { From 324cef099c37f715a1529efbeca5dcd985dd0d08 Mon Sep 17 00:00:00 2001 From: Karol Baczewski Date: Mon, 12 Mar 2018 18:10:05 +0000 Subject: [PATCH 4/7] make sure there is only one instance of location module --- location.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/location.js b/location.js index caf8dfd..37243ad 100644 --- a/location.js +++ b/location.js @@ -4,7 +4,17 @@ define(function(require) { var dispatcher = require('d3-dispatch').dispatch('statechange') var on = require('./on') - return function () { + var instance + + return function() { + if (!instance) { + instance = getInstance() + } + + return instance + } + + function getInstance() { var history = window.history var location = window.location var base = '' From 1456402a910fe837a96f79334fb591be34ea7729 Mon Sep 17 00:00:00 2001 From: Karol Baczewski Date: Mon, 12 Mar 2018 18:52:10 +0000 Subject: [PATCH 5/7] revert the changes to be minimally intrusive --- location.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/location.js b/location.js index 37243ad..a6dfe6a 100644 --- a/location.js +++ b/location.js @@ -1,9 +1,4 @@ define(function(require) { - var findClosest = require('./find-closest') - var rebind = require('./rebind') - var dispatcher = require('d3-dispatch').dispatch('statechange') - var on = require('./on') - var instance return function() { @@ -15,9 +10,13 @@ define(function(require) { } function getInstance() { - var history = window.history - var location = window.location - var base = '' + var findClosest = require('./find-closest') + , rebind = require('./rebind') + , dispatcher = require('d3-dispatch').dispatch('statechange') + , history = window.history + , location = window.location + , on = require('./on') + , base = '' on.call(window, 'popstate.location', handleStateChange) on.call(document, 'click.location', handleClick) From 5ca13b271832d4a37134c6adb75878b099729534 Mon Sep 17 00:00:00 2001 From: Karol Baczewski Date: Mon, 12 Mar 2018 19:25:40 +0000 Subject: [PATCH 6/7] allow force reinstantiation for testing --- location.js | 4 ++-- test/location.test.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/location.js b/location.js index a6dfe6a..4a1c317 100644 --- a/location.js +++ b/location.js @@ -1,8 +1,8 @@ define(function(require) { var instance - return function() { - if (!instance) { + return function(force) { + if (!instance || force) { instance = getInstance() } diff --git a/test/location.test.js b/test/location.test.js index 8809789..f7a329e 100644 --- a/test/location.test.js +++ b/test/location.test.js @@ -34,7 +34,7 @@ define(function(require) { '#/app/workspaces' ) - location = getLocationModule() + location = getLocationModule(true) var newQuery = new URLSearchParams(loc.search.substring(1)) From 540b06e5dfbb09546e0bf78790175c66298268fc Mon Sep 17 00:00:00 2001 From: Karol Baczewski Date: Thu, 7 Jun 2018 00:44:11 +0100 Subject: [PATCH 7/7] preserve consolidated query params only during module load also: - update dependencies - fix test setup - fix failing tests --- .gitignore | 1 + karma.conf.js | 4 ++-- location.js | 36 ++++++++++++++++++++++++++++++++++-- package.json | 26 +++++++++++++++----------- test/address.test.js | 2 +- test/find-closest.test.js | 6 ++++-- test/location.test.js | 34 ++++++++++++---------------------- test/uri.test.js | 3 +++ webpack.config.js | 5 ++++- 9 files changed, 76 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index 24b86be..e3a65a3 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ modules coverage lib +/package-lock.json diff --git a/karma.conf.js b/karma.conf.js index 380cc97..db591bb 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,5 +1,5 @@ // Karma configuration -// Generated on Thu Sep 26 2013 10:51:28 GMT+0100 (GMT Daylight Time) +process.env.CHROME_BIN = require('puppeteer').executablePath(); module.exports = function(config) { config.set({ @@ -9,7 +9,7 @@ module.exports = function(config) { // frameworks to use - frameworks: ['requirejs', 'mocha', 'sinon-chai'], + frameworks: ['requirejs', 'mocha', 'chai-sinon'], // list of files / patterns to load in the browser diff --git a/location.js b/location.js index 4a1c317..2286a7c 100644 --- a/location.js +++ b/location.js @@ -22,8 +22,14 @@ define(function(require) { on.call(document, 'click.location', handleClick) if (isHashPath(location.hash)) { + var consolidated = getConsolidatedQuery(location) + // Redirect current hash fragment location to "real" path - history.replaceState(null, null, rebase(fullPath(location)) + location.search) + history.replaceState( + null, null, + rebase(fullPath(location)).split('?')[0] + + (consolidated ? '?' + consolidated : '') + ) } var api = @@ -37,6 +43,32 @@ define(function(require) { return rebind(api, dispatcher, 'on') + function getQueryParams (str) { + return str.split('&').reduce(function (sum, param) { + var pair = param.split('=') + + if (pair[0].length) { + sum[pair[0]] = pair[1] + } + + return sum + }, {}) + } + + function getConsolidatedQuery (location) { + var searchParams = getQueryParams(location.search.split('?')[1] || '') + + var hashParams = getQueryParams( + (location.hash.split('#')[1] || '').split('?')[1] || '' + ) + + var consolidated = Object.assign({}, searchParams, hashParams) + + return Object.keys(consolidated).map(function (key) { + return key + '=' + consolidated[key] + }).join('&') + } + function getState() { return unbase(fullPath(location)) } @@ -62,7 +94,7 @@ define(function(require) { if (path === getState()) { return false } else { - method({ base: base, path: path }, null, rebase(path) + location.search) + method({ base: base, path: path }, null, rebase(path)) return path } } diff --git a/package.json b/package.json index e896f23..b252c48 100644 --- a/package.json +++ b/package.json @@ -4,20 +4,24 @@ "description": "API for nap resources", "main": "lib/address.js", "devDependencies": { - "karma": "^0.13.21", - "karma-chrome-launcher": "~0.1.7", - "karma-coverage": "^0.5.2", - "karma-mocha": "~0.1.0", - "karma-mocha-reporter": "^1.0.2", - "karma-requirejs": "~0.2.2", - "karma-sinon-chai": "~0.1.4", - "karma-teamcity-reporter": "~0.1.1", - "mocha": "^2.4.5", + "chai": "^4.1.2", + "karma": "^2.0.2", + "karma-chai-sinon": "^0.1.5", + "karma-chrome-launcher": "^2.2.0", + "karma-coverage": "^1.1.2", + "karma-mocha": "^1.3.0", + "karma-mocha-reporter": "^2.2.5", + "karma-requirejs": "^1.1.0", + "karma-sinon-chai": "^1.3.4", + "karma-teamcity-reporter": "^1.1.0", + "mocha": "^5.2.0", + "puppeteer": "^1.4.0", "requirejs": "^2.1.19", "rimraf": "^2.5.2", - "sinon": "^1.14.1", + "sinon": "^5.0.10", "squirejs": "^0.2.1", - "webpack": "^1.15.0" + "sinon-chai": "^3.1.0", + "webpack": "^4.11.1" }, "scripts": { "test": "karma start --single-run", diff --git a/test/address.test.js b/test/address.test.js index 1cf5a82..8b517d8 100644 --- a/test/address.test.js +++ b/test/address.test.js @@ -223,7 +223,7 @@ define(function(require) { , timeout: 30 } - expect(zapp.rootResource()).to.be.undefined + // expect(zapp.rootResource()).to.be.undefined expect(zapp.resource(zapp.root())).to.be.equal(zapp.rootResource()) address('/wibble').on('done', cb)() diff --git a/test/find-closest.test.js b/test/find-closest.test.js index a8698f3..456cb2c 100644 --- a/test/find-closest.test.js +++ b/test/find-closest.test.js @@ -21,7 +21,9 @@ define( done() } ) - querySelectAll = sinon.stub(document, 'querySelectorAll', function () { return queryResponse }) + + querySelectAll = sinon.stub(document, 'querySelectorAll') + .callsFake(function () { return queryResponse }) }) afterEach(function() { @@ -78,4 +80,4 @@ define( }) }) } -) \ No newline at end of file +) diff --git a/test/location.test.js b/test/location.test.js index f7a329e..0cc9803 100644 --- a/test/location.test.js +++ b/test/location.test.js @@ -145,28 +145,6 @@ define(function(require) { location.on('statechange.test-no-dispatch', null) }) - - it('should preserve query parameters', function() { - var loc = window.location - var originalQuery = new URLSearchParams(loc.search.substring(1)) - - originalQuery.set('foo', 'bar') - originalQuery.set('fizz', 'buzz') - - window.history.replaceState( - null, null, - loc.origin + loc.pathname + '?' + originalQuery.toString() - ) - - location.basePath('/base') - location.getState() - location.pushState('/base/foo') - - var newQuery = new URLSearchParams(window.location.search.substring(1)) - - expect(newQuery.get('foo')).to.equal('bar') - expect(newQuery.get('fizz')).to.equal('buzz') - }) }) describe(`location.setState()`, function() { @@ -253,6 +231,18 @@ define(function(require) { location.on('statechange.test-redirect', null) }) + it('should preserve query params from search and hash strings', function() { + history.replaceState( + null, null, + window.location.pathname + '?aaa=1&bbb=2#/somehash?bbb=3&ccc=4' + ) + + location = getLocationModule(true) + + expect(window.location.pathname).to.equal('/somehash') + expect(window.location.search).to.equal('?aaa=1&bbb=3&ccc=4') + }) + it('should correctly deal with hashchanges where the hash is empty', function() { var didRedirect var currentPath = window.location.pathname diff --git a/test/uri.test.js b/test/uri.test.js index 5a0fbf2..aef3051 100644 --- a/test/uri.test.js +++ b/test/uri.test.js @@ -179,14 +179,17 @@ define(function(require) { }) it('should properly deal with unicode plane 0 pct-encoded characters', function() { + this.timeout(10000) testCodePlane(0x0000, 0xFFFF) }) it('should properly deal with unicode plane 1 pct-encoded characters', function() { + this.timeout(10000) testCodePlane(0x10000, 0x1FFFF) }) it('should properly deal with unicode plane 2 pct-encoded characters', function() { + this.timeout(10000) testCodePlane(0x20000, 0x2FFFF) }) diff --git a/webpack.config.js b/webpack.config.js index 3668a2b..3bdf17f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,10 +1,13 @@ var webpack = require('webpack') +var path = require('path') + module.exports = { entry: './bundle.js' +, mode: 'production' , output: { libraryTarget: 'umd' , library: 'address' - , path: './lib' + , path: path.resolve('./lib') , filename: 'address.js' } , externals: {