diff --git a/Gruntfile.js b/Gruntfile.js index e3b4940e12153..dd04aa2d139cc 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -53,7 +53,9 @@ module.exports = function(grunt) { grunt.registerTask('build:min', ['jsx:release', 'browserify:min']); grunt.registerTask('build:test', [ 'jsx:debug', + 'jsx:jasmine', 'jsx:test', + 'browserify:jasmine', 'browserify:test' ]); diff --git a/grunt/config/browserify.js b/grunt/config/browserify.js index 35ffef9d807c2..7594e95544289 100644 --- a/grunt/config/browserify.js +++ b/grunt/config/browserify.js @@ -76,10 +76,23 @@ var transformer = { after: [simpleBannerify] }; +var jasmine = { + entries: [ + "./build/jasmine/all.js" + ], + requires: { + "jasmine": "./build/jasmine/all.js" + }, + outfile: "./build/jasmine.js", + debug: false +}; + var test = { entries: [ "./build/modules/test/all.js", - "./build/modules/**/__tests__/*-test.js" + ], + requires: [ + "**/__tests__/*-test.js" ], outfile: './build/react-test.js', debug: false, @@ -88,6 +101,7 @@ var test = { module.exports = { basic: basic, + jasmine: jasmine, test: test, min: min, transformer: transformer diff --git a/grunt/config/jsx/jsx.js b/grunt/config/jsx/jsx.js index c75c318aca845..34fe98c16630e 100644 --- a/grunt/config/jsx/jsx.js +++ b/grunt/config/jsx/jsx.js @@ -6,7 +6,18 @@ var rootIDs = [ var debug = { rootIDs: rootIDs, - configFile: "grunt/config/jsx/debug.json" + configFile: "grunt/config/jsx/debug.json", + sourceDir: "src", + outputDir: "build/modules" +}; + +var jasmine = { + rootIDs: [ + "all" + ], + configFile: debug.configFile, + sourceDir: "vendor/jasmine", + outputDir: "build/jasmine" }; var test = { @@ -14,16 +25,21 @@ var test = { "test/all.js", "**/__tests__/*.js" ]), - configFile: debug.configFile + configFile: debug.configFile, + sourceDir: "src", + outputDir: "build/modules" }; var release = { rootIDs: rootIDs, - configFile: "grunt/config/jsx/release.json" + configFile: "grunt/config/jsx/release.json", + sourceDir: "src", + outputDir: "build/modules" }; module.exports = { debug: debug, + jasmine: jasmine, test: test, release: release }; diff --git a/grunt/config/phantom.js b/grunt/config/phantom.js index c5bfc7717af1d..36cbc0f3ded11 100644 --- a/grunt/config/phantom.js +++ b/grunt/config/phantom.js @@ -4,5 +4,8 @@ exports.run = { port: 8080, harness: "test/phantom-harness.js", // Run `grunt test --debug` to enable in-browser testing. - debug: !!grunt.option("debug") + debug: !!grunt.option("debug"), + tests: [ + "**/__tests__/*-test.js" + ] }; diff --git a/grunt/tasks/browserify.js b/grunt/tasks/browserify.js index b73b67bd19f77..d43c0841f8619 100644 --- a/grunt/tasks/browserify.js +++ b/grunt/tasks/browserify.js @@ -12,7 +12,6 @@ module.exports = function() { // More/better assertions // grunt.config.requires('outfile'); // grunt.config.requires('entries'); - config.requires = config.requires || {}; config.transforms = config.transforms || []; config.after = config.after || []; if (typeof config.after === 'function') { @@ -24,9 +23,20 @@ module.exports = function() { var bundle = browserify(entries); // Make sure the things that need to be exposed are. - // TODO: support a blob pattern maybe? - for (var name in config.requires) { - bundle.require(config.requires[name], { expose: name }); + var requires = config.requires || {}; + if (requires instanceof Array) { + grunt.file.expand({ + nonull: true, // Keep IDs that don't expand to anything. + cwd: "src" + }, requires).forEach(function(name) { + bundle.require("./build/modules/" + name, { + expose: name.replace(/\.js$/i, "") + }); + }); + } else if (typeof requires === "object") { + Object.keys(requires).forEach(function(name) { + bundle.require(requires[name], { expose: name }); + }); } // Extract other options diff --git a/grunt/tasks/jsx.js b/grunt/tasks/jsx.js index 1ecee11fd7c98..6b2f4123d74d1 100644 --- a/grunt/tasks/jsx.js +++ b/grunt/tasks/jsx.js @@ -9,8 +9,8 @@ module.exports = function() { var args = [ "bin/jsx", - "src", - "build/modules" + config.sourceDir, + config.outputDir ]; var rootIDs = expand({ diff --git a/grunt/tasks/phantom.js b/grunt/tasks/phantom.js index 2134dcde63a7d..ff71f683c69a2 100644 --- a/grunt/tasks/phantom.js +++ b/grunt/tasks/phantom.js @@ -37,6 +37,14 @@ function run(config, done) { args.push("--debug"); } + args.push("--tests"); + var tests = grunt.file.expand({ + nonull: true, + cwd: "src" + }, config.tests || []).forEach(function(file) { + args.push(file.replace(/\.js$/i, "")); + }); + var child = spawn({ cmd: phantomjs, args: args diff --git a/src/test/all.js b/src/test/all.js index c6511b9f0a4ca..b370c31b629f8 100644 --- a/src/test/all.js +++ b/src/test/all.js @@ -2,17 +2,56 @@ // modules in src/test and to specify an ordering on those modules, since // some still have implicit dependencies on others. -require("./phantom"); -require("./console"); +var Ap = Array.prototype; +var slice = Ap.slice; +var Fp = Function.prototype; + +if (!Fp.bind) { + // PhantomJS doesn't support Function.prototype.bind natively, so + // polyfill it whenever this module is required. + Fp.bind = function(context) { + var func = this; + var args = slice.call(arguments, 1); + var bound; + + if (func.prototype) { + if (args.length > 0) { + bound = function() { + return func.apply( + !(this instanceof func) && context || this, + args.concat(slice.call(arguments)) + ); + }; + } else { + bound = function() { + return func.apply( + !(this instanceof func) && context || this, + arguments + ); + }; + } + + bound.prototype = Object.create(func.prototype); + + } else if (args.length > 0) { + bound = function() { + return func.apply( + context || this, + args.concat(slice.call(arguments)) + ); + }; + } else { + bound = function() { + return func.apply(context || this, arguments); + }; + } + + return bound; + }; +} + require("ReactTestUtils"); require("reactComponentExpect"); -require("./diff"); -require("./PrintReporter"); -require("./HtmlReporter"); -require("./ReporterView"); -require("./SpecView"); -require("./SuiteView"); -require("./jasmine-support"); require("mocks"); require("mock-modules"); require("./mock-timers"); diff --git a/src/utils/__tests__/ImmutableObject-test.js b/src/utils/__tests__/ImmutableObject-test.js index 6075f576619c3..fbcda924aee6d 100644 --- a/src/utils/__tests__/ImmutableObject-test.js +++ b/src/utils/__tests__/ImmutableObject-test.js @@ -100,6 +100,7 @@ describe('ImmutableObject', function() { }); testDev('should prevent shallow field addition when strict', function() { + if (window.callPhantom) return; expect(function() { var io = new ImmutableObject({oldField: 'asdf'}); io.newField = 'this will not work'; @@ -107,6 +108,7 @@ describe('ImmutableObject', function() { }); testDev('should prevent shallow field mutation when strict', function() { + if (window.callPhantom) return; expect(function() { var io = new ImmutableObject({oldField: 'asdf'}); io.oldField = 'this will not work!'; @@ -114,6 +116,7 @@ describe('ImmutableObject', function() { }); testDev('should prevent deep field addition when strict', function() { + if (window.callPhantom) return; expect(function() { var io = new ImmutableObject({shallowField: {deepField: {oldField: null}}}); @@ -122,6 +125,7 @@ describe('ImmutableObject', function() { }); testDev('should prevent deep field mutation when strict', function() { + if (window.callPhantom) return; expect(function() { var io = new ImmutableObject({shallowField: {deepField: {oldField: null}}}); diff --git a/test/frame.html b/test/frame.html new file mode 100644 index 0000000000000..34061d7ce1a5f --- /dev/null +++ b/test/frame.html @@ -0,0 +1,18 @@ + + +
+ + + + + + + diff --git a/test/index.html b/test/index.html index a609479571207..ee98b71067175 100644 --- a/test/index.html +++ b/test/index.html @@ -2,12 +2,18 @@ + - - diff --git a/test/phantom-harness.js b/test/phantom-harness.js index 0350e5c9cd80e..6dcfced557a91 100644 --- a/test/phantom-harness.js +++ b/test/phantom-harness.js @@ -19,36 +19,58 @@ fs.changeWorkingDirectory(cwd); // Hard to believe PhantomJS has no option parsing module. var port = 8080; var debug = false; -var lastArg; +var tests = []; +var rest = []; while (argv.length > 0) { var arg = argv.pop(); if (arg === "--port") { - port = +lastArg; + port = +rest.pop(); } else if (arg === "--debug") { debug = true; + } else if (arg === "--tests") { + while (rest.length > 0) + tests.push(rest.pop()); } - lastArg = arg; + rest.push(arg); } +// Dynamically interpolate the individual test