Commit 82302d92 authored by Robert Knight's avatar Robert Knight Committed by Nick Stenning

Simplify and add tests for the logic on the installer page

The logic on the installer page was completely OTT for the task
at hand. Simplify it, add tests and fix a minor issue where it was
shown when testing the page in responsive mode in Chrome
devtools where the User Agent is spoofed but 'window.chrome'
is still available.
parent 14998be3
var isMobile = navigator.userAgent.match(/\b(Mobile)\b/);
var isMicrosoftEdge = navigator.userAgent.match(/\bEdge\b/);
/**
* Dictionary defining the conditions that can be used
* to show or hide elements on the page depending on
* features of the app or site that are available
* in the current environment.
*
* Keys correspond to hyphenated class names prefixed with 'js-env',
* eg. 'js-env-browser-is-chrome'.
*/
var env = {
browserIsChrome: typeof window.chrome !== 'undefined',
browserIsOther: typeof window.chrome === 'undefined',
installerAvailable: !isMobile && !isMicrosoftEdge,
};
function hypenate(key) {
// 'camelCase' -> 'camel-case'
return key.replace(/[a-z]+/g, '$&-').toLowerCase().slice(0, -1);
}
/**
* Show or hide elements on the page depending on the capabilities
* of the current browser.
*
* Elements to be shown or hidden are marked up with
* 'js-env-$condition' classes. If all conditions evaluate to true,
* the 'is-hidden' class is removed from the element, otherwise
* it is added.
*
* The list of conditions is defined by hyphenated versions of the
* keys of the 'env' dictionary.
*/
function showSupportedElements(rootElement) {
var showElements = [];
var hideElements = [];
Object.keys(env).forEach(function (key) {
var selector = '.js-env-' + hypenate(key);
var elements = rootElement.querySelectorAll(selector);
for (var i = 0; i < elements.length; i++) {
if (env[key]) {
showElements.push(elements[i]);
} else {
hideElements.push(elements[i]);
}
}
});
showElements.forEach(function (el) {
el.classList.remove('is-hidden');
});
hideElements.forEach(function (el) {
el.classList.add('is-hidden');
});
}
module.exports = {
showSupportedElements: showSupportedElements,
};
// Utility functions used on the page that presents the Hypothesis
// extension and bookmarklet installers
var uaDetect = require('./ua-detect');
function showSupportedInstallers(rootElement) {
function showIf(selector, cond) {
var elements = rootElement.querySelectorAll(selector);
for (var i = 0; i < elements.length; i++) {
if (cond) {
elements[i].classList.remove('is-hidden');
} else {
elements[i].classList.add('is-hidden');
}
}
}
var canInstallChromeExt = uaDetect.isChrome && !uaDetect.isMobile;
var canInstallBookmarklet = !uaDetect.isChrome && !uaDetect.isMobile &&
!uaDetect.isMicrosoftEdge;
showIf('.js-install-chrome', canInstallChromeExt);
showIf('.js-install-bookmarklet', canInstallBookmarklet);
showIf('.js-install-any', canInstallChromeExt || canInstallBookmarklet);
}
module.exports = {
showSupportedInstallers: showSupportedInstallers,
};
......@@ -2,7 +2,7 @@ var CreateGroupFormController = require('./create-group-form');
var DropdownMenuController = require('./dropdown-menu');
var ShareGroupFormController = require('./share-group-form');
var envTest = require('./browser-env-test');
var installerController = require('./installer-controller');
// load our customized version of Bootstrap which
// provides a few basic UI components (eg. modal dialogs)
......@@ -17,13 +17,14 @@ function setupGroupsController(path) {
}
document.addEventListener('DOMContentLoaded', function () {
if (document.location.pathname.indexOf('/groups') === 0) {
setupGroupsController(document.location.pathname);
}
// setup components
new DropdownMenuController(document);
// show/hide elements depending on the environment
envTest.showSupportedElements(document);
// setup route
var route = document.location.pathname;
if (route.match('^/$')) {
installerController.showSupportedInstallers(document);
} else if (route.match('^/groups') === 0) {
setupGroupsController(route);
}
});
var proxyquire = require('proxyquire');
describe('installer page', function () {
var rootElement;
var extensionBtn;
var bookmarkletBtn;
var linkField;
beforeEach(function () {
rootElement = document.createElement('div');
rootElement.innerHTML =
'<button class="extension js-install-chrome is-hidden"></button>' +
'<button class="bookmarklet js-install-bookmarklet is-hidden"></button>' +
'<input class="link">';
extensionBtn = rootElement.querySelector('.extension');
bookmarkletBtn = rootElement.querySelector('.bookmarklet');
linkField = rootElement.querySelector('.link');
document.body.appendChild(rootElement);
});
afterEach(function () {
rootElement.parentNode.removeChild(rootElement);
});
function createController(userAgentInfo) {
var controller = proxyquire('../installer-controller', {
'./ua-detect': userAgentInfo
});
controller.showSupportedInstallers(rootElement);
return controller;
}
function isHidden(el) {
return el.classList.contains('is-hidden');
}
it('shows the chrome extension to desktop Chrome users', function () {
var controller = createController({isChrome: true});
assert.isFalse(isHidden(extensionBtn));
assert.isTrue(isHidden(bookmarkletBtn));
});
it('shows the bookmarklet on desktop browsers', function () {
var controller = createController({isChrome: true, isMobile: false});
assert.isFalse(isHidden(extensionBtn));
assert.isTrue(isHidden(bookmarkletBtn));
});
it('shows only the Via link to mobile browsers', function () {
var controller = createController({isChrome: true, isMobile: true});
assert.isTrue(isHidden(extensionBtn));
assert.isTrue(isHidden(bookmarkletBtn));
});
it('shows only the Via link to Microsoft Edge users', function () {
var controller = createController({isMicrosoftEdge: true});
assert.isTrue(isHidden(extensionBtn));
assert.isTrue(isHidden(bookmarkletBtn));
});
});
module.exports = {
isMobile: navigator.userAgent.match(/\b(Mobile)\b/),
isMicrosoftEdge: navigator.userAgent.match(/\bEdge\b/),
// we test for the existence of window.chrome here because Microsoft Edge
// (and possibly others) serve
isChrome: typeof window.chrome !== 'undefined',
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment