diff --git a/.npmignore b/.npmignore new file mode 100644 index 00000000..e69de29b diff --git a/Gruntfile.js b/Gruntfile.js index c79039aa..c0ad76c5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,6 +1,7 @@ module.exports = function(grunt) { + _ = require('lodash'); - var version = "0.1.19" + var version = "0.1.20" var inputFolder = "./docs" var tempFolder = "./temp" @@ -58,6 +59,62 @@ module.exports = function(grunt) { makeTasks("guide", guide) makeTasks("api", api) + var sauceBrowsers =[ + { browserName: 'firefox', version: '19', platform: 'XP' }, + { browserName: "internet explorer", platform: "XP", version: "6"}, + { browserName: "safari", platform: "OS X 10.9", version: "7"}, + { browserName: "iPad", platform: "OS X 10.9", version: "7.1"}, + { browserName: "opera", platform: "Linux", version: "12"}, + { browserName: "chrome", platform: "XP", version: "26"}, + { browserName: "chrome", platform: "Windows 8", version: "26"}, + ]; + + var sauceOnTestComplete = function(result, callback) { + var request = require('request'); + + var user = process.env.SAUCE_USERNAME; + var pass = process.env.SAUCE_ACCESS_KEY; + + request.put({ + url: ['https://saucelabs.com/rest/v1', user, 'jobs', result.job_id].join('/'), + auth: { user: user, pass: pass }, + json: { passed: result.passed } + }, function (error, response, body) { + if (error) { + callback(error); + } else if (response.statusCode !== 200) { + callback(new Error('Unexpected response status: ' + + response.statusCode + "\n ")); + } else { + callback(null, result.passed); + } + }); + }; + + var sauceBaseOptions = { + username: process.env.SAUCE_USERNAME, + key: process.env.SAUCE_ACCESS_KEY, + testname: "Mithril Tests " + new Date().toJSON(), + browsers: sauceBrowsers, + sauceConfig: { + "record-video": false, + "record-screenshots": false, + }, + build: process.env.TRAVIS_JOB_ID, + onTestComplete: sauceOnTestComplete, + tunnelTimeout: 5, + }; + var sauceCustomOptions = { + testname: "Mithril Custom Tests "+ new Date().toJSON(), + urls: ["http://127.0.0.1:8000/tests/index.html"], + }; + _.assign(sauceCustomOptions, sauceBaseOptions); + var sauceQunitOptions = { + testname: "qUnit Tests "+ new Date().toJSON(), + urls: ["http://127.0.0.1:8000/tests/e2e/test.html"], + }; + _.assign(sauceQunitOptions, sauceBaseOptions); + var currentVersionArchiveFolder = archiveFolder + "/v" + version grunt.initConfig({ md2html: md2htmlTasks, @@ -104,7 +161,19 @@ module.exports = function(grunt) { }, qunit: { all: ['tests/e2e/**/*.html'] - }, + }, + "saucelabs-custom": { + all:{ + options: sauceCustomOptions + } + }, + "saucelabs-qunit": { + all:{ + options: sauceQunitOptions + } + }, + watch: {}, + connect: { server: { options: { @@ -129,10 +198,14 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-zip'); grunt.loadNpmTasks('grunt-contrib-qunit'); grunt.loadNpmTasks('grunt-contrib-connect'); + grunt.loadNpmTasks('grunt-saucelabs'); grunt.registerTask("build", ["test", "uglify", "zip", "md2html", "replace", "copy", "clean"]); grunt.registerTask("test", ["concat", "execute"]); grunt.registerTask('teste2e', ['connect', 'qunit']); grunt.registerTask("default", ["build"]); + grunt.registerTask("sauce-qunit", ["connect", "saucelabs-qunit"]); + grunt.registerTask("sauce-custom", ["connect", "saucelabs-custom"]); + grunt.registerTask("sauce-all", ["connect", "saucelabs-qunit", "saucelabs-custom"]); }; diff --git a/archive/v0.1.19/mithril-tests.js b/archive/v0.1.19/mithril-tests.js index 6367c542..401f832e 100644 --- a/archive/v0.1.19/mithril-tests.js +++ b/archive/v0.1.19/mithril-tests.js @@ -674,9 +674,39 @@ if (typeof define == "function" && define.amd) define(function() {return m}) ;;; function test(condition) { - try {if (!condition()) throw new Error} - catch (e) {console.error(e);test.failures.push(condition)} + var duration = 0; + var start = 0; + var result = true; test.total++ + + if (typeof window != "undefined") { + if (typeof performance != "undefined") { + start = performance.now(); + } + try {if (!condition()) throw new Error} + catch (e) {result = false;console.error(e);test.failures.push(condition)} + if (typeof performance != "undefined") { + duration = performance.now() - start; + } + + + test_obj = { + name: "" + test.total, + result: result, + duration: duration + } + if (!result) { + message: "failed: " + condition, + window.global_test_results.tests.push(test_obj) + } + + window.global_test_results.duration += duration; + if (result) { + window.global_test_results.passed++; + } else { + window.global_test_results.failed++; + } + } } test.total = 0 test.failures = [] @@ -2381,7 +2411,17 @@ function testMithril(mock) { } -//mocks -testMithril(mock.window) +//test reporting for saucelabs +if (typeof window != "undefined") { + window.global_test_results = { + tests: [], + duration: 0, + passed: 0, + failed: 0 + }; +} -test.print(console.log) +//mock +testMithril(mock.window); + +test.print(function(value){console.log(value)}); \ No newline at end of file diff --git a/mithril.js b/mithril.js index f36a54bb..688c187b 100644 --- a/mithril.js +++ b/mithril.js @@ -106,7 +106,7 @@ Mithril = m = new function app(window) { var item = build(parentElement, parentTag, cached, index, data[i], cached[cacheCount], shouldReattach, index + subArrayCount || subArrayCount, editable, namespace, configs) if (item === undefined) continue if (!item.nodes.intact) intact = false - var isArray = item instanceof Array + var isArray = type.call(item) == "[object Array]" subArrayCount += isArray ? item.length : 1 cached[cacheCount++] = item } @@ -246,7 +246,7 @@ Mithril = m = new function app(window) { function unload(cached) { if (cached.configContext && typeof cached.configContext.onunload == "function") cached.configContext.onunload() if (cached.children) { - if (cached.children instanceof Array) for (var i = 0; i < cached.children.length; i++) unload(cached.children[i]) + if (type.call(cached.children) == "[object Array]") for (var i = 0; i < cached.children.length; i++) unload(cached.children[i]) else if (cached.children.tag) unload(cached.children) } } @@ -274,7 +274,7 @@ Mithril = m = new function app(window) { var flattened = [] for (var i = 0; i < data.length; i++) { var item = data[i] - if (item instanceof Array) flattened.push.apply(flattened, flatten(item)) + if (type.call(item) == "[object Array]") flattened.push.apply(flattened, flatten(item)) else flattened.push(item) } return flattened @@ -332,7 +332,7 @@ Mithril = m = new function app(window) { return value } - var roots = [], modules = [], controllers = [], lastRedrawId = 0, computePostRedrawHook = null + var roots = [], modules = [], controllers = [], lastRedrawId = 0, computePostRedrawHook = null, prevented = false m.module = function(root, module) { var index = roots.indexOf(root) if (index < 0) index = roots.length @@ -352,6 +352,11 @@ Mithril = m = new function app(window) { } } m.redraw = function() { + if (prevented) { + prevented = false + return + } + var cancel = window.cancelAnimationFrame || window.clearTimeout var defer = window.requestAnimationFrame || window.setTimeout if (lastRedrawId) { @@ -363,6 +368,7 @@ Mithril = m = new function app(window) { lastRedrawId = defer(function() {lastRedrawId = null}, 0) } } + m.preventRedraw = function() {prevented = true} function redraw() { for (var i = 0; i < roots.length; i++) { if (controllers[i]) m.render(roots[i], modules[i].view(controllers[i])) @@ -642,7 +648,7 @@ Mithril = m = new function app(window) { var unwrap = (e.type == "load" ? xhrOptions.unwrapSuccess : xhrOptions.unwrapError) || identity var response = unwrap(deserialize(extract(e.target, xhrOptions))) if (e.type == "load") { - if (response instanceof Array && xhrOptions.type) { + if (type.call(response) == "[object Array]" && xhrOptions.type) { for (var i = 0; i < response.length; i++) response[i] = new xhrOptions.type(response[i]) } else if (xhrOptions.type) response = new xhrOptions.type(response) diff --git a/package.json b/package.json index fd91cb67..b188a2fc 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,22 @@ "grunt-replace": "*", "grunt-contrib-qunit": "*", "grunt-contrib-connect": "*", - "grunt-zip": "*" + "grunt-zip": "*", + + "grunt-contrib-connect": "~0.7.1", + "grunt-contrib-jshint": "~0.10.0", + "grunt-contrib-watch": "~0.6.1", + "grunt-jscs-checker": "^0.4.4", + "grunt-sauce-tunnel": "^0.2.1", + "load-grunt-config": "^0.9.2", + "merge": "^1.1.3", + "publish": "~0.3.2", + "grunt-saucelabs": "*", + "request": "~2.35.0", + "q": "~1.0.0", + "saucelabs": "~0.1.1", + "sauce-tunnel": "~2.0.6", + "colors": "~0.6.2", + "lodash": "~2.4.1" } } diff --git a/tests/e2e/tests.js b/tests/e2e/tests.js index 1a1e4241..d80c1e33 100644 --- a/tests/e2e/tests.js +++ b/tests/e2e/tests.js @@ -1,3 +1,31 @@ +//saucelabs reporting; see https://github.com/axemclion/grunt-saucelabs#test-result-details-with-qunit +var log = []; +var testName; +QUnit.done(function (test_results) { + var tests = []; + for(var i = 0, len = log.length; i < len; i++) { + var details = log[i]; + tests.push({ + name: details.name, + result: details.result, + expected: details.expected, + actual: details.actual, + source: details.source + }); + } + test_results.tests = tests; + + window.global_test_results = test_results; +}); +QUnit.testStart(function(testDetails){ + QUnit.log(function(details){ + if (!details.result) { + details.name = testDetails.name; + log.push(details); + } + }); +}); + //qunit doesn't support Function.prototype.bind... if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { diff --git a/tests/mithril-tests.js b/tests/mithril-tests.js index c4fe3127..53323b88 100644 --- a/tests/mithril-tests.js +++ b/tests/mithril-tests.js @@ -1575,7 +1575,17 @@ function testMithril(mock) { } -//mocks -testMithril(mock.window) +//test reporting for saucelabs +if (typeof window != "undefined") { + window.global_test_results = { + tests: [], + duration: 0, + passed: 0, + failed: 0 + }; +} + +//mock +testMithril(mock.window); test.print(function(value) {console.log(value)}) diff --git a/tests/test.js b/tests/test.js index 16e45a21..025d8216 100644 --- a/tests/test.js +++ b/tests/test.js @@ -1,7 +1,37 @@ function test(condition) { - try {if (!condition()) throw new Error} - catch (e) {console.error(e);test.failures.push(condition)} + var duration = 0; + var start = 0; + var result = true; test.total++ + + if (typeof window != "undefined") { + if (typeof performance != "undefined") { + start = performance.now(); + } + try {if (!condition()) throw new Error} + catch (e) {result = false;console.error(e);test.failures.push(condition)} + if (typeof performance != "undefined") { + duration = performance.now() - start; + } + + + test_obj = { + name: "" + test.total, + result: result, + duration: duration + } + if (!result) { + message: "failed: " + condition, + window.global_test_results.tests.push(test_obj) + } + + window.global_test_results.duration += duration; + if (result) { + window.global_test_results.passed++; + } else { + window.global_test_results.failed++; + } + } } test.total = 0 test.failures = []