Skip to content

Commit

Permalink
add support for easily mounting an app, also added babel
Browse files Browse the repository at this point in the history
  • Loading branch information
dereke committed Mar 10, 2017
1 parent 61ece90 commit e2deaab
Show file tree
Hide file tree
Showing 12 changed files with 307 additions and 4 deletions.
1 change: 1 addition & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "presets": ["latest", "react"] }
4 changes: 3 additions & 1 deletion actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ module.exports = {
if (activeElement && !$(activeElement).is(':focus') && notSillyBlankIEObject(activeElement)) {
$(activeElement).trigger('blur');
}
document.activeElement = element;
if (document.toString() !== '[object HTMLDocument]'){
document.activeElement = element;
}
$(element).focus();
}
},
Expand Down
4 changes: 3 additions & 1 deletion karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ module.exports = function(config) {
],

browserify: {
debug: true
debug: true,
extensions: ['.jsx'],
transform: ['babelify'],
},

client: {
Expand Down
110 changes: 110 additions & 0 deletions mount.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
var runningInBrowser = !require('is-node');
var createBrowser = require('./create');
var VineHill = require('vinehill');
var window = require('global');
var document = window.document;

function addRefreshButton() {
var refreshLink = document.createElement('a');
refreshLink.href = window.location.href;
refreshLink.innerText = 'refresh';
document.body.appendChild(refreshLink);
document.body.appendChild(document.createElement('hr'));
}

var div;
function createTestDiv() {
if (div) {
div.parentNode.removeChild(div);
}
div = document.createElement('div');
document.body.appendChild(div);
return div;
}

if (runningInBrowser) {
if (/\/debug\.html$/.test(window.location.pathname)) {
localStorage['debug'] = 'browser-monkey';
addRefreshButton();
}
} else {
require('./stubBrowser');
}

function Mount(options) {
this.vinehill = new VineHill();
this.startApp = options.startApp.bind(this);
this.stopApp = options.stopApp.bind(this);
}

Mount.prototype.setOrigin = function(host) {
this.vinehill.setOrigin(host);
return this;
}

Mount.prototype.withServer = function(host, app) {
this.vinehill.add(host, app);
return this;
}

Mount.prototype.withApp = function(getApp) {
this.getApp = getApp;
return this;
}

Mount.prototype.start = function() {
this.vinehill.start();
this.app = this.getApp();
this.startApp();
return this;
}

Mount.prototype.stop = function(){
this.stopApp();
this.vinehill.stop();
}

module.exports = {
angular: function() {
return new Mount({
stopApp: function(){},
startApp: function(){
var app = this.app;

var div = createTestDiv();
div.setAttribute(app.directiveName, '');
angular.bootstrap(div, [app.moduleName]);

this.browser = createBrowser(document.body);
}
});
},

hyperdom: function() {
var hyperdom = require('hyperdom');
var router = require('hyperdom-router');
var vquery = require('vdom-query');
router.start();

return new Mount({
stopApp: function(){
router.clear();
},
startApp: function(){
var app = this.app;

if (runningInBrowser) {
this.browser = createBrowser(document.body);
hyperdom.append(createTestDiv(), app);
} else {
var vdom = hyperdom.html('body');

this.browser = createBrowser(vdom);
this.browser.set({$: vquery, visibleOnly: false, document: {}});

hyperdom.appendVDom(vdom, app, { requestRender: setTimeout, window: window });
}
}
});
}
}
13 changes: 12 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,26 @@
"description": "reliable dom testing",
"main": "index.js",
"scripts": {
"test": "mocha && karma start --single-run"
"test": "mocha --compilers js:babel-register && karma start --single-run"
},
"author": "Tim Macfarlane <[email protected]>",
"license": "MIT",
"devDependencies": {
"2vdom": "^0.2.0",
"angular": "^1.6.0",
"babel-cli": "^6.18.0",
"babel-preset-latest": "^6.16.0",
"babel-preset-react": "^6.16.0",
"babel-register": "^6.18.0",
"babelify": "^7.3.0",
"browserify": "^13.1.1",
"chai-as-promised": "6.0.0",
"detect-node": "^2.0.3",
"express": "^4.14.0",
"httpism": "^2.6.2",
"hyperdom": "^0.2.0",
"hyperdom-router": "^2.18.0",
"is-node": "^1.0.2",
"karma": "1.3.0",
"karma-browserify": "5.1.0",
"karma-browserstack-launcher": "1.1.1",
Expand All @@ -27,6 +37,7 @@
"lie": "^3.0.1",
"mocha": "3.1.2",
"vdom-query": "https://github.com/featurist/vdom-query",
"vinehill": "^0.4.1",
"virtual-dom": "^2.1.1",
"watchify": "^3.7.0"
},
Expand Down
39 changes: 39 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,45 @@ Or to be more specific:
localStorage['debug'] = 'browser-monkey';
```

# mount

Typically you will need to mount your application into the DOM before running your tests.

Browser monkey comes with a handy way of doing this for popular web frameworks (currently hyperdom and angular are supported)

```js
var mount = require('browser-monkey/mount');


// for hyperdom
// where YourHyperdomApp is a class that has a render method. [see here](test/app/hyperdom.js) for an example

var monkey = mount.hyperdom()
.withApp(() => new YourHyperdomApp())
.start()

// for angular
// where YourAngularApp is a class with fields 'directiveName' and 'moduleName' [see here](test/app/angular.js) for an example
var monkey = mount.hyperdom()
.withApp(() => new YourAngularApp())
.start()


monkey.browser.find('h1').shouldHave({text: 'Hello World'});
```

The mount functions (hyperdom/angular etc.) return a `Mount` object with the following chainable functions:

* withApp - accepts a single function as a parameter that returns an object containing the application
* withServer - allows you to route http requests to an express server using [Vinehill](https://www.npmjs.com/package/vinehill)
* start - starts the application and returns a `monkey`
* stop - stops the application and performs any cleanup necessary

The `monkey` has the following properties:

* browser - a browser monkey object that scoped to your application
* app - the application passed to withApp

# api

The API is made up of three concepts: scopes, actions and assertions.
Expand Down
27 changes: 27 additions & 0 deletions stubBrowser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
var window = require('global');


var registeredEvents = {};
var pushState, replaceState;

pushState = replaceState = function(state, title, url) {
window.location.pathname = url;
(registeredEvents['onpopstate'] || []).forEach(cb => cb({}));
};

window.location = window.location || {};
window.location.pathname = window.location.pathname || '/';
window.location.origin = window.location.origin || '';
window.location.search = window.location.search || '';
window.history = {
pushState,
replaceState,
};

window.addEventListener = function(eventName, cb) {
eventName = 'on'+eventName;
if (!registeredEvents[eventName]) {
registeredEvents[eventName] = [];
}
registeredEvents[eventName].push(cb);
};
2 changes: 1 addition & 1 deletion test/actionsSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ describe('actions', function(){
var clicked;
var buttonState = 'disabled';

button = dom.insert('<button disabled>a button</button>');
var button = dom.insert('<button disabled>a button</button>');
button.on('click', function () {
clicked = buttonState;
});
Expand Down
29 changes: 29 additions & 0 deletions test/app/angular.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
var angular = require('angular');
var httpism = require('httpism');

angular
.module('FrameworksApp', [])
.directive('bestFrameworks', function () {
return {
restrict: 'A',
controller: 'FrameworksController',
template: `<div ng-controller="FrameworksController">
<ul>
<li ng-repeat="framework in frameworks">{{framework}}</li>
</ul>
</div>`
};
})
.controller('FrameworksController', function($scope){
httpism.get('/api/frameworks').then(response => {
$scope.frameworks = response.body;
$scope.$digest();
});
});

module.exports = class WebApp {
constructor() {
this.directiveName = 'best-frameworks';
this.moduleName = 'FrameworksApp';
}
}
27 changes: 27 additions & 0 deletions test/app/hyperdom.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/** @jsx hyperdom.jsx */
var httpism = require('httpism/browser');
var hyperdom = require('hyperdom');
var html = hyperdom.html;

module.exports = class WebApp {
constructor() {
var self = this;
this.model = {
frameworks: []
};

httpism.get('/api/frameworks').then(response => {
self.model.frameworks = response.body;
self.model.refresh();
});
}


render() {
this.model.refresh = html.refresh;

return <ul>
{this.model.frameworks.map(name => <li>{name}</li>)}
</ul>
}
}
10 changes: 10 additions & 0 deletions test/app/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
var expressApp = (require('express'))();
expressApp.get('/api/frameworks', (req, res) => {
res.json([
'browser-monkey',
'hyperdom',
'vinehill',
]);
});

module.exports = expressApp;
45 changes: 45 additions & 0 deletions test/mountSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
var expect = require('chai').expect
var isBrowser = !require('is-node');
if (isBrowser) {
var mount = require('../mount');
var expressApp= require('./app/server');

require('./app/angular');
require('./app/hyperdom');

[
'hyperdom',
'angular'
].forEach(appType => {
var WebApp = require('./app/'+appType);
var monkeyBuilder = mount[appType];

describe(`mount ${appType}`, () => {
var monkey, app;

beforeEach(() => {
monkey = monkeyBuilder()
.withServer('http://localhost:1234', expressApp)
.withApp(() => {
app = new WebApp();
return app;
})
.start();
});

afterEach(() => monkey.stop());

it('loads some data', () => {
return monkey.browser.find('li').shouldHave({text: [
'browser-monkey',
'hyperdom',
'vinehill',
]})
});

it('exposes the app', () => {
expect(monkey.app).to.equal(app);
});
});
});
}

0 comments on commit e2deaab

Please sign in to comment.