├── .gitignore ├── test ├── data │ ├── data.json │ ├── library.js │ ├── angular.register-form.js │ └── ajaxwrapper.js ├── 06.localstorage.spec.js ├── 05.ractive.spec.js ├── 01.basic.spec.js ├── 03.angular.spec.js ├── 07.injectjs.spec.js ├── 08.console.log.spec.js ├── 04.xmlhttprequest.spec.js └── 02.events.spec.js ├── .jshintrc ├── package.json ├── LICENSE ├── lib ├── network.js ├── polyfills │ └── localStorage.js ├── index.js └── vendor │ └── jquery-1.11.1.min.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /test/data/data.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "multistr": true 3 | } -------------------------------------------------------------------------------- /test/data/library.js: -------------------------------------------------------------------------------- 1 | var AwesomeLibrary = { 2 | answer: function() { 3 | return 42; 4 | } 5 | } -------------------------------------------------------------------------------- /test/06.localstorage.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | suite('Local storage', function() { 3 | 4 | test('Creating a component', function(done) { 5 | var atomus = require('../lib'); 6 | var b = atomus() 7 | .html('
') 8 | .ready(function(errors, window) { 9 | assert(!!window.localStorage); 10 | window.localStorage.setItem('foo', 42); 11 | assert.deepEqual(window.localStorage.getItem('foo'), 42); 12 | done(); 13 | }); 14 | }); 15 | 16 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atomus", 3 | "version": "2.0.0", 4 | "description": "A small utility for running client-side tests in Node.js environment", 5 | "main": "./lib/index.js", 6 | "author": { 7 | "name": "Krasimir Tsonev", 8 | "email": "info@krasimirtsonev.com", 9 | "url": "http://krasimirtsonev.com" 10 | }, 11 | "license": "MIT", 12 | "dependencies": { 13 | "jsdom": "^9.0.0" 14 | }, 15 | "devDependencies": { 16 | "mocha": "2.0.1", 17 | "jshint": "2.5.10" 18 | }, 19 | "keywords": [ 20 | "testing", 21 | "client-side", 22 | "front-end", 23 | "dom" 24 | ], 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/krasimir/atomus.git" 28 | }, 29 | "scripts": { 30 | "test": "./node_modules/mocha/bin/mocha --ui tdd --recursive ./test/*.spec.js && (./node_modules/jshint/bin/jshint lib/index.js ; echo)" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test/05.ractive.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | suite('Ractivejs', function() { 3 | 4 | test('Creating a component', function(done) { 5 | var atomus = require('../lib'); 6 | var b = atomus() 7 | .html('
') 8 | .external(__dirname + '/data/ractive.js') 9 | .ready(function(errors, window) { 10 | var Ractive = window.Ractive.extend({ 11 | el: 'main', 12 | data: { 13 | value: null 14 | }, 15 | template: '\ 16 | \ 17 | ', 18 | onrender: function() { 19 | this.observe('value', function(v) { 20 | assert.equal(b.$('input').is(':checked'), true); 21 | assert.equal(this.get('value'), true); 22 | done(); 23 | }, { init: false }); 24 | } 25 | }); 26 | var r = new Ractive(); 27 | this.selected(this.$('input')); 28 | r.updateModel(); 29 | }); 30 | }); 31 | 32 | }); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Krasimir Tsonev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /test/data/angular.register-form.js: -------------------------------------------------------------------------------- 1 | registerFormDirective = function() { 2 | return { 3 | restrict: 'E', 4 | template: '\ 5 |
\ 6 |

Please fill the form below

\ 7 | \ 8 | \ 9 | \ 10 | \ 11 |
\ 12 | \ 13 |
\ 14 | {{message}}\ 15 |
\ 16 | ', 17 | controller: function($scope) { 18 | var validateInput = function() { 19 | var u = $scope.username; 20 | var p = $scope.password; 21 | if (u === '' || u === undefined) { 22 | return { status: false, message: 'Missing username.'} 23 | } else if (p === '' || p === undefined) { 24 | return { status: false, message: 'Missing password.'} 25 | } else if (u.length < 10) { 26 | return { status: false, message: 'Too short username.'} 27 | } else if (p.length < 6) { 28 | return { status: false, message: 'Too short password.'} 29 | } 30 | return { status: true } 31 | } 32 | $scope.register = function() { 33 | var isValid = validateInput(); 34 | if(false === isValid.status) { 35 | $scope.message = isValid.message; 36 | return; 37 | } else { 38 | $scope.message = ''; 39 | } 40 | } 41 | } 42 | } 43 | }; -------------------------------------------------------------------------------- /test/01.basic.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'), 2 | path = require('path'); 3 | suite('Basics', function () { 4 | 5 | test('default options', function (done) { 6 | var atomus = require('../lib'); 7 | var b = atomus(); 8 | b.ready(function (errors, window) { 9 | done(); 10 | }); 11 | }); 12 | 13 | test('adding initial html', function (done) { 14 | var atomus = require('../lib'); 15 | var b = atomus().html('

Hello atomus

').ready(function (errors, window) { 16 | assert.equal(b.$('body').html(), '

Hello atomus

'); 17 | done(); 18 | }); 19 | }); 20 | 21 | test('adding external libs', function (done) { 22 | var atomus = require('../lib'); 23 | var b = atomus().external(__dirname + '/data/library.js').ready(function (errors, window) { 24 | assert.equal(b.window.AwesomeLibrary.answer(), 42); 25 | done(); 26 | }); 27 | }); 28 | 29 | test('testing waitUntil', function (done) { 30 | var atomus = require('../lib'); 31 | var b = atomus().html('').ready(function (errors, window) { 32 | b.waitUntil('#awesome', function ($el) { 33 | done(); 34 | }); 35 | setTimeout(function () { 36 | b.$('body').html('
'); 37 | }, 110); 38 | }); 39 | }); 40 | 41 | test('testing waitUntil with promise interface', function (done) { 42 | var atomus = require('../lib'); 43 | var b = atomus().html('').ready(function (errors, window) { 44 | b.waitUntil('#awesome').then(function (el) { 45 | assert.equal(this.$('body') instanceof b.window.jQuery, true); 46 | assert.equal(el.attr('id'), 'awesome'); 47 | done(); 48 | }); 49 | setTimeout(function () { 50 | b.$('body').html('
'); 51 | }, 110); 52 | }); 53 | }); 54 | 55 | }); 56 | -------------------------------------------------------------------------------- /test/03.angular.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | suite('AngularJS test', function() { 3 | 4 | test('Testing AngularJS directive', function(done) { 5 | this.timeout(5000); 6 | 7 | var atomus = require('../lib'); 8 | var b = atomus() 9 | .html('
') 10 | .external(__dirname + '/data/angular.js') 11 | .external(__dirname + '/data/angular.register-form.js') 12 | .ready(function(errors, window) { 13 | if(errors !== null) console.log(errors); 14 | 15 | var Controller = function($scope) { 16 | setTimeout(function() { 17 | runTests(); 18 | }, 300); 19 | }; 20 | 21 | var runTests = function() { 22 | 23 | var register = b.$('#register-button'); 24 | var message = b.$('#message'); 25 | var username = b.$('#username'); 26 | var password = b.$('#password'); 27 | 28 | b.clicked(register); 29 | assert.equal(message.text(), 'Missing username.'); 30 | 31 | username.val('test'); 32 | b.changed(username); 33 | b.clicked(register); 34 | assert.equal(message.text(), 'Missing password.'); 35 | 36 | password.val('test'); 37 | b.changed(password); 38 | b.clicked(register); 39 | assert.equal(message.text(), 'Too short username.'); 40 | 41 | username.val('testtesttesttest'); 42 | b.changed(username); 43 | b.clicked(register); 44 | assert.equal(message.text(), 'Too short password.'); 45 | 46 | password.val('testtesttesttest'); 47 | b.changed(password); 48 | b.clicked(register); 49 | assert.equal(message.text(), ''); 50 | 51 | done(); 52 | 53 | }; 54 | 55 | var app = window 56 | .angular 57 | .module('app', []) 58 | .controller('Controller', Controller) 59 | .directive('registerForm', window.registerFormDirective); 60 | 61 | window.angular.bootstrap(window.document, ['app']); 62 | }); 63 | }); 64 | 65 | }); -------------------------------------------------------------------------------- /test/07.injectjs.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | suite('Injecting', function() { 3 | 4 | test('Injecting JavaScript', function(done) { 5 | var atomus = require('../lib'); 6 | var b = atomus({ injectJS: 'var getTheAnswer = function() { return 42; }' }) 7 | .ready(function(errors, window) { 8 | assert(window.getTheAnswer() === 42); 9 | assert(window.$('html')[0].outerHTML.indexOf('') > 0); 10 | done(); 11 | }); 12 | }); 13 | 14 | test('Injecting JavaScript with already predefined html', function(done) { 15 | var atomus = require('../lib'); 16 | var b = atomus({ injectJS: 'var getTheAnswer = function() { return 42; }' }) 17 | .html('') 18 | .ready(function(errors, window) { 19 | assert(window.getTheAnswer() === 42); 20 | assert(window.$('html')[0].outerHTML.indexOf('') > 0); 21 | done(); 22 | }); 23 | }); 24 | 25 | test('Using the API method', function(done) { 26 | var atomus = require('../lib'); 27 | var b = atomus() 28 | .html('') 29 | .injectJS('var getTheAnswer = function() { return 42; }') 30 | .ready(function(errors, window) { 31 | assert(window.getTheAnswer() === 42); 32 | assert(window.$('html')[0].outerHTML.indexOf('') > 0); 33 | done(); 34 | }); 35 | }); 36 | 37 | test('Using the API method and change the html', function(done) { 38 | var atomus = require('../lib'); 39 | var b = atomus() 40 | .injectJS('var getTheAnswer = function() { return 42; }') 41 | .html('') 42 | .ready(function(errors, window) { 43 | assert(window.getTheAnswer() === 42); 44 | assert(window.$('html')[0].outerHTML.indexOf('') > 0); 45 | done(); 46 | }); 47 | }); 48 | 49 | }); -------------------------------------------------------------------------------- /test/08.console.log.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | suite('Transferring console.logs', function() { 3 | 4 | var original = console.log; 5 | 6 | test('Keeping the old window.log', function(done) { 7 | var atomus = require('../lib'); 8 | var b = atomus() 9 | .injectJS('var doSomething = function() { window.log(\'hello\'); };') 10 | .ready(function(errors, window) { 11 | var logs = []; 12 | console.log = function(o) { 13 | logs.push(o); 14 | }; 15 | console.log('test'); 16 | assert.deepEqual(logs, ['test']) 17 | window.doSomething(); 18 | assert.deepEqual(logs, ['test', 'hello']) 19 | console.log = original; 20 | done(); 21 | }); 22 | }); 23 | 24 | test('Calling console.log', function(done) { 25 | var atomus = require('../lib'); 26 | var b = atomus() 27 | .injectJS('var doSomething = function() { console.log(\'hello\'); };') 28 | .ready(function(errors, window) { 29 | var logs = []; 30 | console.log = function(o) { 31 | logs.push(o); 32 | }; 33 | console.log('test'); 34 | assert.deepEqual(logs, ['test']) 35 | window.doSomething(); 36 | assert.deepEqual(logs, ['test', 'hello']) 37 | console.log = original; 38 | done(); 39 | }); 40 | }); 41 | 42 | test('Calling console.log before having a window object', function(done) { 43 | var logs = []; 44 | console.log = function(o) { 45 | logs.push(o); 46 | }; 47 | var atomus = require('../lib'); 48 | var b = atomus() 49 | .injectJS('console.log(\'hello\');') 50 | .ready(function(errors, window) { 51 | assert.deepEqual(logs, ['hello']) 52 | console.log = original; 53 | done(); 54 | }); 55 | }); 56 | 57 | test('Make sure that it polyfills all the console methods', function(done) { 58 | var logs = []; 59 | console.log = function(o) { 60 | logs.push(o); 61 | }; 62 | var atomus = require('../lib'); 63 | var b = atomus() 64 | .injectJS('console.info(\'hello\');console.group(\'world\');') 65 | .ready(function(errors, window) { 66 | assert.deepEqual(logs, ['hello', 'world']) 67 | console.log = original; 68 | done(); 69 | }); 70 | }); 71 | 72 | }); -------------------------------------------------------------------------------- /lib/network.js: -------------------------------------------------------------------------------- 1 | /* 2 | Credits: Robin Allen 3 | GitHub: https://github.com/robin-allen 4 | Site: http://foon.uk 5 | */ 6 | 7 | var assign = function(a, b) { 8 | for(var key in b) { 9 | a[key] = b[key]; 10 | } 11 | return a; 12 | } 13 | 14 | module.exports = function(w) { 15 | 16 | var log = { rq: null, requests: [] }; 17 | var fakeResult = []; 18 | 19 | function FakeXHR() { 20 | 21 | var rq = log.rq = this; 22 | var queueIndex = 0; 23 | 24 | rq.sent = null; 25 | rq.headers = {}; 26 | 27 | rq.onreadystatechange = function() {}; 28 | 29 | rq.open = function(method, url, async) { 30 | rq.method = method; 31 | rq.url = url; 32 | rq.async = async; 33 | log.requests.push({ 34 | method: method, 35 | url: url, 36 | async: async 37 | }); 38 | }; 39 | 40 | rq.setHeaders = function(headers) { 41 | rq.headers = headers; 42 | }; 43 | 44 | rq.setRequestHeader = function(x, y) { 45 | rq.headers[x] = y; 46 | }; 47 | 48 | rq.getAllResponseHeaders = function() {}; 49 | 50 | rq.send = function(data) { 51 | rq.sent = data; 52 | 53 | rq.readyState = 4; 54 | 55 | if(fakeResult instanceof Array) { 56 | var filtered = fakeResult.filter(function(r) { 57 | if(!r.method) r.method = 'GET'; 58 | return r.url === rq.url && r.method === rq.method; 59 | }); 60 | if(filtered.length > 0) { 61 | assign(rq, filtered[0].response); 62 | } else { 63 | throw new Error('Missing mock for ' + rq.url + ' (method: ' + rq.method + ')'); 64 | } 65 | } else if(typeof fakeResult === 'function') { 66 | assign(rq, fakeResult(rq)); 67 | } else { 68 | assign(rq, fakeResult); 69 | }; 70 | 71 | // making it close to the real http request 72 | setTimeout(function() { 73 | rq.onreadystatechange(); 74 | }, 100); 75 | }; 76 | 77 | } 78 | 79 | global.window = window = w || {}; 80 | global.XMLHttpRequest = window.XMLHttpRequest = FakeXHR; 81 | 82 | return { 83 | getLog: function() { 84 | return log; 85 | }, 86 | addMock: function(m) { 87 | if(m instanceof Array) { 88 | fakeResult = fakeResult.concat(m); 89 | } else if(typeof m === 'function') { 90 | fakeResult = m; 91 | } else { 92 | fakeResult.push(m); 93 | } 94 | }, 95 | clearXHRMocks: function() { 96 | fakeResult = []; 97 | }, 98 | getMocks: function() { 99 | return fakeResult; 100 | } 101 | }; 102 | 103 | }; -------------------------------------------------------------------------------- /lib/polyfills/localStorage.js: -------------------------------------------------------------------------------- 1 | if (typeof window.localStorage == 'undefined' || typeof window.sessionStorage == 'undefined') (function () { 2 | 3 | var Storage = function (type) { 4 | function createCookie(name, value, days) { 5 | var date, expires; 6 | 7 | if (days) { 8 | date = new Date(); 9 | date.setTime(date.getTime()+(days*24*60*60*1000)); 10 | expires = "; expires="+date.toGMTString(); 11 | } else { 12 | expires = ""; 13 | } 14 | document.cookie = name+"="+value+expires+"; path=/"; 15 | } 16 | 17 | function readCookie(name) { 18 | var nameEQ = name + "=", 19 | ca = document.cookie.split(';'), 20 | i, c; 21 | 22 | for (i=0; i < ca.length; i++) { 23 | c = ca[i]; 24 | while (c.charAt(0)==' ') { 25 | c = c.substring(1,c.length); 26 | } 27 | 28 | if (c.indexOf(nameEQ) == 0) { 29 | return c.substring(nameEQ.length,c.length); 30 | } 31 | } 32 | return null; 33 | } 34 | 35 | function setData(data) { 36 | data = JSON.stringify(data); 37 | if (type == 'session') { 38 | window.name = data; 39 | } else { 40 | createCookie('localStorage', data, 365); 41 | } 42 | } 43 | 44 | function clearData() { 45 | if (type == 'session') { 46 | window.name = ''; 47 | } else { 48 | createCookie('localStorage', '', 365); 49 | } 50 | } 51 | 52 | function getData() { 53 | try { 54 | var data = type == 'session' ? window.name : readCookie('localStorage'); 55 | return data ? JSON.parse(data) : {}; 56 | } catch(err) { 57 | return {}; 58 | } 59 | } 60 | 61 | 62 | // initialise if there's already data 63 | var data = getData(); 64 | 65 | return { 66 | length: 0, 67 | clear: function () { 68 | data = {}; 69 | this.length = 0; 70 | clearData(); 71 | }, 72 | getItem: function (key) { 73 | return data[key] === undefined ? null : data[key]; 74 | }, 75 | key: function (i) { 76 | // not perfect, but works 77 | var ctr = 0; 78 | for (var k in data) { 79 | if (ctr == i) return k; 80 | else ctr++; 81 | } 82 | return null; 83 | }, 84 | removeItem: function (key) { 85 | delete data[key]; 86 | this.length--; 87 | setData(data); 88 | }, 89 | setItem: function (key, value) { 90 | data[key] = value+''; // forces the value to a string 91 | this.length++; 92 | setData(data); 93 | } 94 | }; 95 | }; 96 | 97 | if (typeof window.localStorage == 'undefined') window.localStorage = new Storage('local'); 98 | if (typeof window.sessionStorage == 'undefined') window.sessionStorage = new Storage('session'); 99 | 100 | })(); -------------------------------------------------------------------------------- /test/04.xmlhttprequest.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | suite('XMLHTTPRequest', function() { 3 | 4 | test('faking HTTP request', function(done) { 5 | var mockups = { 6 | url: '/api/method/action', 7 | response: { 8 | status: 200, 9 | responseText: JSON.stringify({"id": "AAA"}) 10 | } 11 | }; 12 | var atomus = require('../lib'); 13 | var b = atomus() 14 | .external(__dirname + '/data/ajaxwrapper.js') 15 | .ready(function(errors, window) { 16 | b.addXHRMock(mockups) 17 | window.AjaxWrapper().request({ 18 | url: '/api/method/action', 19 | json: true 20 | }).done(function(result) { 21 | assert(result.id, 'AAA'); 22 | done(); 23 | }) 24 | }); 25 | }); 26 | 27 | test('faking HTTP request and make difference between GET and POST', function(done) { 28 | var mockups = [ 29 | { 30 | url: '/api/method/action', 31 | response: { 32 | status: 200, 33 | responseText: JSON.stringify({"id": "AAA"}) 34 | } 35 | }, 36 | { 37 | url: '/api/method/action', 38 | method: 'POST', 39 | response: { 40 | status: 200, 41 | responseText: JSON.stringify({"success": "OK"}) 42 | } 43 | } 44 | ]; 45 | var atomus = require('../lib'); 46 | var b = atomus() 47 | .external(__dirname + '/data/ajaxwrapper.js') 48 | .ready(function(errors, window) { 49 | b.addXHRMock(mockups) 50 | window.AjaxWrapper().request({ 51 | url: '/api/method/action', 52 | json: true 53 | }).done(function(result) { 54 | assert(result.id, 'AAA'); 55 | 56 | var log = b.network.getLog(); 57 | window.AjaxWrapper().request({ 58 | url: '/api/method/action', 59 | json: true, 60 | method: 'POST' 61 | }).done(function(result) { 62 | assert(result.success, 'OK'); 63 | assert.deepEqual(log.requests, 64 | [ 65 | { method: 'GET', url: '/api/method/action', async: true }, 66 | { method: 'POST', url: '/api/method/action', async: true } 67 | ] 68 | ); 69 | done(); 70 | }); 71 | 72 | }); 73 | }); 74 | }); 75 | 76 | test('Runtime XHR mock', function(done) { 77 | // var mockups = { 78 | // url: '/api/method/action', 79 | // response: { 80 | // status: 200, 81 | // responseText: JSON.stringify({"id": "AAA"}) 82 | // } 83 | // }; 84 | var mock = function(params) { 85 | if(params.url === '/api/method/action' && params.method === 'GET') { 86 | return { 87 | status: 200, 88 | responseText: JSON.stringify({"id": "AAA"}) 89 | } 90 | } 91 | }; 92 | var atomus = require('../lib'); 93 | var b = atomus() 94 | .external(__dirname + '/data/ajaxwrapper.js') 95 | .ready(function(errors, window) { 96 | b.addXHRMock(mock) 97 | window.AjaxWrapper().request({ 98 | url: '/api/method/action', 99 | json: true 100 | }).done(function(result) { 101 | assert(result.id, 'AAA'); 102 | done(); 103 | }) 104 | }); 105 | }); 106 | 107 | }); -------------------------------------------------------------------------------- /test/data/ajaxwrapper.js: -------------------------------------------------------------------------------- 1 | function AjaxWrapper() { 2 | return { 3 | request: function(ops, callback) { 4 | if(typeof ops == 'string') ops = { url: ops }; 5 | ops.url = ops.url || ''; 6 | ops.method = ops.method || 'get' 7 | ops.data = ops.data || {}; 8 | ops.prepareParams = typeof ops.prepareParams === 'undefined' ? true : false; 9 | var getParams = function(data, url) { 10 | var arr = [], str; 11 | for(var name in data) { 12 | arr.push(name + '=' + encodeURIComponent(data[name])); 13 | } 14 | str = arr.join('&'); 15 | if(str != '') { 16 | return url ? (url.indexOf('?') < 0 ? '?' + str : '&' + str) : str; 17 | } 18 | return ''; 19 | } 20 | var api = { 21 | host: {}, 22 | doneCallback: callback, 23 | process: function(ops) { 24 | var self = this; 25 | this.xhr = null; 26 | if(window.ActiveXObject) { this.xhr = new ActiveXObject('Microsoft.XMLHTTP'); } 27 | else if(window.XMLHttpRequest) { this.xhr = new XMLHttpRequest(); } 28 | if(this.xhr) { 29 | this.xhr.onreadystatechange = function() { 30 | if(self.xhr.readyState == 4 && self.xhr.status == 200) { 31 | var result = self.xhr.responseText, resultJSON; 32 | if(ops.json === true && typeof JSON != 'undefined') { 33 | try { 34 | resultJSON = JSON.parse(result); 35 | } catch(e) { 36 | resultJSON = result; 37 | } 38 | } 39 | self.doneCallback && self.doneCallback.apply(self.host, [resultJSON, self.xhr]); 40 | } else if(self.xhr.readyState == 4) { 41 | self.failCallback && self.failCallback.apply(self.host, [self.xhr]); 42 | } 43 | self.alwaysCallback && self.alwaysCallback.apply(self.host, [self.xhr]); 44 | } 45 | } 46 | if(ops.method == 'get') { 47 | this.xhr.open("GET", ops.url + getParams(ops.data, ops.url), true); 48 | } else { 49 | this.xhr.open(ops.method, ops.url, true); 50 | this.setHeaders({ 51 | 'X-Requested-With': 'XMLHttpRequest', 52 | 'Content-type': 'application/x-www-form-urlencoded' 53 | }); 54 | } 55 | if(ops.headers && typeof ops.headers == 'object') { 56 | this.setHeaders(ops.headers); 57 | } 58 | setTimeout(function() { 59 | var data = ops.prepareParams ? getParams(ops.data) : ops.data; 60 | ops.method == 'get' ? self.xhr.send() : self.xhr.send(data); 61 | }, 20); 62 | return this; 63 | }, 64 | done: function(callback) { 65 | this.doneCallback = callback; 66 | return this; 67 | }, 68 | fail: function(callback) { 69 | this.failCallback = callback; 70 | return this; 71 | }, 72 | always: function(callback) { 73 | this.alwaysCallback = callback; 74 | return this; 75 | }, 76 | setHeaders: function(headers) { 77 | for(var name in headers) { 78 | this.xhr && this.xhr.setRequestHeader(name, headers[name]); 79 | } 80 | } 81 | } 82 | return api.process(ops); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /test/02.events.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | suite('Events', function() { 3 | 4 | test('Attach event listener + triggering', function(done) { 5 | var atomus = require('../lib'); 6 | var b = atomus().html('').ready(function(errors, window) { 7 | var input = b.$('input'); 8 | input.val('hello world'); 9 | input.on('change', function(event) { 10 | assert.equal(event.target.value, 'hello world'); 11 | done(); 12 | }); 13 | b.changed(input); 14 | }); 15 | }); 16 | 17 | test('Make sure that there is only one triggering', function(done) { 18 | var atomus = require('../lib'); 19 | var b = atomus().html('