Skip to content

Commit

Permalink
Added tests and cleaned up code
Browse files Browse the repository at this point in the history
  • Loading branch information
christianalfoni committed Sep 13, 2015
1 parent 9f557b0 commit 0dbf69a
Show file tree
Hide file tree
Showing 11 changed files with 318 additions and 58 deletions.
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The library just exposes the `addressbar`. It is a single entity in your app whe
addressbar.value // "http://www.example.com"

// Change addressbar value does NOT trigger route change
addressbar.value = "http://wwww.example.com/test";
addressbar.value = "http://wwww.example.com/test";

// Prevent route changes on hyperlinks
addressbar.addEventListener('change', function (event) {
Expand All @@ -21,4 +21,15 @@ addressbar.addEventListener('change', function (event) {
});
```

This is low level code, so there is no routing logic here. Please check out [url-mapper](https://github.com/christianalfoni/url-mapper) which can be used to create routing logic.
This is low level code, so there is no routing logic here. Please check out [url-mapper](https://github.com/christianalfoni/url-mapper) which can be used to create routing logic.

## Under the hood
Addressbar listens to `popstate` events and handles hyperlinks. It basically has logic to simulate how an input works, also handling a few edge cases.

## Tests
Addressbar is running with selenium-driver and nodeunit to test live in Chrome. Requires [selenium chrome driver](https://sites.google.com/a/chromium.org/chromedriver/downloads) to be installed and added to **PATH**.

Run tests:
- `npm install`
- `npm start` (fires up a python webservice)
- `npm test` (Runs tests)
25 changes: 0 additions & 25 deletions build/index.html

This file was deleted.

44 changes: 21 additions & 23 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ module.exports = (function () {

var origin = location.origin;
var isPreventingDefault = false;
var isSilent = false;
var index = 0;
var doReplace = false;
var prevUrl = null;
var initialUrl = location.href;
var prevUrl = '';
var linkClicked = false;
var isEmitting = false;
var setSyncUrl = false;
Expand All @@ -33,33 +32,26 @@ module.exports = (function () {
});
};

var hasHash = function (url) {
return location.href.indexOf('#') !== -1;
};

var onUrlChange = function (type) {
return function (event) {

console.log('got event', type, location.href, prevUrl);
if (location.href === prevUrl) {
console.log('retuning!');
return;
}

// If going back or if using trailing slash
if (event.state && event.state.index < index || location.href[location.href.length - 1] === '/') {
// Fixes bug where trailing slash is converted to normal url
if (location.href[location.href.length - 1] === '/') {
doReplace = true;
}

isEmitting = true;
emitChange();
isEmitting = false;

if (!setSyncUrl) {
history.replaceState({url: prevUrl, index: index}, '', prevUrl.replace(origin, ''));
if (!setSyncUrl && isPreventingDefault) {
history.replaceState({}, '', (prevUrl || initialUrl).replace(origin, ''));
}

isSilent = false;
prevUrl = location.href;
isPreventingDefault = false;
setSyncUrl = false;
Expand All @@ -76,34 +68,41 @@ module.exports = (function () {
},
set: function (value) {

// If emitting a change we flag that we are setting
// a url based on the event being emitted
if (isEmitting) {
setSyncUrl = true;
}

// Ensure full url
if (value.indexOf(origin) === -1) {
value = origin + value;
}

// If it is same url, forget about it
if (value === location.href) {
return;
}

if (isPreventingDefault && !isEmitting && !linkClicked) {
return;
}

if (!doReplace) {
history.pushState({url: value, index: index++}, '', value.replace(origin, ''));
} else {
history.replaceState({url: value, index: index}, '', value.replace(origin, ''));
// We might need to replace the url if we are fixing
// for example trailing slash issue
if (doReplace) {
history.replaceState({}, '', value.replace(origin, ''));
doReplace = false;
} else {
history.pushState({}, '', value.replace(origin, ''));
}

isPreventingDefault = false;

}
});

/*
This code is from the Page JS source code. Amazing work on handling all
kinds of scenarios with hyperlinks, thanks!
*/

var isSameOrigin = function (href) {
var origin = location.protocol + '//' + location.hostname;
if (location.port) origin += ':' + location.port;
Expand Down Expand Up @@ -151,7 +150,6 @@ module.exports = (function () {
if (isPreventingDefault) {
linkClicked = false;
}
isSilent = false;
prevUrl = href;
isPreventingDefault = false;
}
Expand Down
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "addressbar",
"version": "0.1.23",
"version": "0.2.0",
"description": "Makes the addressbar of the browser work just like a normal input",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server --devtool eval --progress --colors --content-base build",
"test": "echo \"Error: no test specified\" && exit 1"
"start": "python -m SimpleHTTPServer 3001",
"test": "webpack && nodeunit test.js"
},
"repository": {
"type": "git",
Expand All @@ -23,7 +23,8 @@
},
"homepage": "https://github.com/christianalfoni/addressbar#readme",
"devDependencies": {
"webpack": "^1.12.0",
"webpack-dev-server": "^1.10.1"
"nodeunit": "^0.9.1",
"selenium-webdriver": "^2.46.1",
"webpack": "^1.12.1"
}
}
198 changes: 198 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
var webdriver = require('selenium-webdriver');
var by = webdriver.By;
var baseUrl = 'http://localhost:3001/';
var preventUrl = baseUrl + 'tests/preventdefault/';
var setUrl = baseUrl + 'tests/set/';
var popstateUrl = baseUrl + 'tests/popstate/';
var hashUrl = baseUrl + 'tests/hash/';
var trailingUrl = baseUrl + 'tests/trailing/';

exports['should display current url'] = function (test) {

var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
build();
driver.get(preventUrl);
driver.getCurrentUrl().then(function (url) {
test.equal(url, preventUrl);
});
driver.quit().then(test.done);

};

exports['should not allow going to a new url'] = function (test) {

var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
build();
driver.get(preventUrl);
driver.navigate().to(preventUrl + '#/foo');
driver.getCurrentUrl().then(function (url) {
test.equal(url, preventUrl);
});
driver.quit().then(test.done);

};

exports['should set url manually when prevented'] = function (test) {

var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
build();
driver.get(setUrl);
driver.navigate().to(setUrl + '#/foo');
driver.getCurrentUrl().then(function (url) {
test.equal(url, setUrl + '#/foo');
});
driver.quit().then(test.done);

};

exports['should go to popstate url'] = function (test) {

var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
build();
driver.get(popstateUrl);

driver.findElement(by.id('messages')).click();
driver.getCurrentUrl().then(function (url) {
test.equal(url, baseUrl + 'messages');
});

driver.findElement(by.id('message')).click();
driver.getCurrentUrl().then(function (url) {
test.equal(url, baseUrl + 'messages/123');
});

driver.quit().then(test.done);

};

exports['should handle back and forward with popstate'] = function (test) {

var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
build();
driver.get(popstateUrl);

driver.findElement(by.id('messages')).click();
driver.findElement(by.id('message')).click();
driver.getCurrentUrl().then(function (url) {
test.equal(url, baseUrl + 'messages/123');
});

driver.navigate().back();
driver.getCurrentUrl().then(function (url) {
test.equal(url, baseUrl + 'messages');
});

driver.navigate().forward();
driver.getCurrentUrl().then(function (url) {
test.equal(url, baseUrl + 'messages/123');
});

driver.quit().then(test.done);

};

exports['should go to hash url'] = function (test) {

var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
build();
driver.get(hashUrl);

driver.findElement(by.id('messages')).click();
driver.getCurrentUrl().then(function (url) {
test.equal(url, baseUrl + '#/messages');
});

driver.findElement(by.id('message')).click();
driver.getCurrentUrl().then(function (url) {
test.equal(url, baseUrl + '#/messages/123');
});

driver.quit().then(test.done);

};

exports['should handle back and forward with hash'] = function (test) {

var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
build();
driver.get(hashUrl);

driver.findElement(by.id('messages')).click();
driver.findElement(by.id('message')).click();
driver.getCurrentUrl().then(function (url) {
test.equal(url, baseUrl + '#/messages/123');
});

driver.navigate().back();
driver.getCurrentUrl().then(function (url) {
test.equal(url, baseUrl + '#/messages');
});

driver.navigate().forward();
driver.getCurrentUrl().then(function (url) {
test.equal(url, baseUrl + '#/messages/123');
});

driver.quit().then(test.done);

};

exports['should handle trailing slash convertion'] = function (test) {

var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
build();
driver.get(trailingUrl + '#/messages/123');
driver.navigate().to(trailingUrl + '#/messages/');
driver.getCurrentUrl().then(function (url) {
test.equal(url, trailingUrl + '#/messages');
});

driver.navigate().back();
driver.getCurrentUrl().then(function (url) {
test.equal(url, trailingUrl + '#/messages/123');
});

driver.navigate().forward();
driver.getCurrentUrl().then(function (url) {
test.equal(url, trailingUrl + '#/messages');
});

driver.quit().then(test.done);

};

exports['should resume history when changing url when on "back" url'] = function (test) {

var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
build();
driver.get(hashUrl);

driver.findElement(by.id('messages')).click();
driver.findElement(by.id('message')).click();
driver.getCurrentUrl().then(function (url) {
test.equal(url, baseUrl + '#/messages/123');
});

driver.navigate().back();
driver.getCurrentUrl().then(function (url) {
test.equal(url, baseUrl + '#/messages');
});

driver.navigate().to(baseUrl + '#/messages/456');
driver.navigate().forward();
driver.getCurrentUrl().then(function (url) {
test.equal(url, baseUrl + '#/messages/456');
});

driver.quit().then(test.done);

};
Loading

0 comments on commit 0dbf69a

Please sign in to comment.