\
230 | builder envs test-func-sauce \
231 | --setup=setup-sauce \
232 | --buffer \
233 | '[ { "TEST_FUNC_PORT": 3030, "ROWDY_SETTINGS":"sauceLabs.IE_8_Windows_2008_Desktop" },
234 | { "TEST_FUNC_PORT": 3040, "ROWDY_SETTINGS":"sauceLabs.IE_9_Windows_2008_Desktop" },
235 | { "TEST_FUNC_PORT": 3050, "ROWDY_SETTINGS":"sauceLabs.IE_10_Windows_2012_Desktop" }
236 | ]'
237 | ```
238 |
239 |
240 | ### Releases
241 |
242 | **IMPORTANT - NPM**: To correctly run `preversion` your first step is to make
243 | sure that you have a very modern `npm` binary:
244 |
245 | ```sh
246 | $ npm install -g npm
247 | ```
248 |
249 | First, you can optionally edit and commit the project history.
250 |
251 | ```sh
252 | $ vim HISTORY.md
253 | $ git add HISTORY.md
254 | $ git commit -m "Update history for VERSION"
255 | ```
256 |
257 | Now we're ready to publish. Choose a semantic update for the new version.
258 | If you're unsure, read about semantic versioning at http://semver.org/
259 |
260 | ```sh
261 | $ npm version VERSION|major|minor|patch -m "Version %s - INSERT_REASONS"
262 | ```
263 |
264 | Now `postversion` will push to git and publish to NPM.
265 |
266 | [trav_img]: https://api.travis-ci.org/walmartlabs/little-loader.svg
267 | [trav_site]: https://travis-ci.org/walmartlabs/little-loader
268 | [sauce]: https://saucelabs.com
269 | [sauce_img]: http://badges.herokuapp.com/sauce/wml-little-loader
270 |
271 | [sauce_site]: https://saucelabs.com/u/wml-little-loader
272 | [cov]: https://coveralls.io
273 | [cov_img]: https://img.shields.io/coveralls/walmartlabs/little-loader.svg
274 | [cov_site]: https://coveralls.io/r/walmartlabs/little-loader
275 |
--------------------------------------------------------------------------------
/lib/little-loader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Script loading is difficult thanks to IE. We need callbacks to fire
3 | * immediately following the script's execution, with no other scripts
4 | * running in between. If other scripts on the page are able to run
5 | * between our script and its callback, bad things can happen, such as
6 | * `jQuery.noConflict` not being called in time, resulting in plugins
7 | * latching onto our version of jQuery, etc.
8 | *
9 | * For IE<10 we use a relatively well-documented "preloading" strategy,
10 | * which ensures that the script is ready to execute *before* appending
11 | * it to the DOM. That way when it is finally appended, it is
12 | * executed immediately.
13 | *
14 | * References:
15 | * - http://www.html5rocks.com/en/tutorials/speed/script-loading/
16 | * - http://blog.getify.com/ie11-please-bring-real-script-preloading-back/
17 | * - https://github.com/jrburke/requirejs/issues/526
18 | * - https://connect.microsoft.com/IE/feedback/details/729164/
19 | * ie10-dynamic-script-element-fires-loaded-readystate-prematurely
20 | */
21 | (function () {
22 |
23 | // Global state.
24 | var pendingScripts = {};
25 | var scriptCounter = 0;
26 |
27 | /**
28 | * Insert script into the DOM
29 | *
30 | * @param {Object} script Script DOM object
31 | * @returns {void}
32 | */
33 | var _addScript = function (script) {
34 | // Get the first script element, we're just going to use it
35 | // as a reference for where to insert ours. Do NOT try to do
36 | // this just once at the top and then re-use the same script
37 | // as a reference later. Some weird loaders *remove* script
38 | // elements after the browser has executed their contents,
39 | // so the same reference might not have a parentNode later.
40 | var firstScript = document.getElementsByTagName("script")[0];
41 |
42 | // Append the script to the DOM, triggering execution.
43 | firstScript.parentNode.insertBefore(script, firstScript);
44 | };
45 |
46 | /**
47 | * Load Script.
48 | *
49 | * @param {String} src URI of script
50 | * @param {Function|Object} callback (Optional) Called on script load completion,
51 | * or options object
52 | * @param {Object} context (Optional) Callback context (`this`)
53 | * @returns {void}
54 | */
55 | var _lload = function (src, callback, context) {
56 | /*eslint max-statements: [2, 32]*/
57 | var setup;
58 |
59 | if (callback && typeof callback !== "function") {
60 | context = callback.context || context;
61 | setup = callback.setup;
62 | callback = callback.callback;
63 | }
64 |
65 | var script = document.createElement("script");
66 | var done = false;
67 | var err;
68 | var _cleanup; // _must_ be set below.
69 |
70 | /**
71 | * Final handler for error or completion.
72 | *
73 | * **Note**: Will only be called _once_.
74 | *
75 | * @returns {void}
76 | */
77 | var _finish = function () {
78 | // Only call once.
79 | if (done) { return; }
80 | done = true;
81 |
82 | // Internal cleanup.
83 | _cleanup();
84 |
85 | // Callback.
86 | if (callback) {
87 | callback.call(context, err);
88 | }
89 | };
90 |
91 | /**
92 | * Error handler
93 | *
94 | * @returns {void}
95 | */
96 | var _error = function () {
97 | err = new Error(src || "EMPTY");
98 | _finish();
99 | };
100 |
101 | if (script.readyState && !("async" in script)) {
102 | /*eslint-disable consistent-return*/
103 |
104 | // This section is only for IE<10. Some other old browsers may
105 | // satisfy the above condition and enter this branch, but we don't
106 | // support those browsers anyway.
107 |
108 | var id = scriptCounter++;
109 | var isReady = { loaded: true, complete: true };
110 | var inserted = false;
111 |
112 | // Clear out listeners, state.
113 | _cleanup = function () {
114 | script.onreadystatechange = script.onerror = null;
115 | pendingScripts[id] = void 0;
116 | };
117 |
118 | // Attach the handler before setting src, otherwise we might
119 | // miss events (consider that IE could fire them synchronously
120 | // upon setting src, for example).
121 | script.onreadystatechange = function () {
122 | var firstState = script.readyState;
123 |
124 | // Protect against any errors from state change randomness.
125 | if (err) { return; }
126 |
127 | if (!inserted && isReady[firstState]) {
128 | inserted = true;
129 |
130 | // Append to DOM.
131 | _addScript(script);
132 | }
133 |
134 | // --------------------------------------------------------------------
135 | // GLORIOUS IE8 HACKAGE!!!
136 | // --------------------------------------------------------------------
137 | //
138 | // Oh IE8, how you disappoint. IE8 won't call `script.onerror`, so
139 | // we have to resort to drastic measures.
140 | // See, e.g. http://www.quirksmode.org/dom/events/error.html#t02
141 | //
142 | // As with all things development, there's a Stack Overflow comment that
143 | // asserts the following combinations of state changes in IE8 indicate a
144 | // script load error. And crazily, it seems to work!
145 | //
146 | // http://stackoverflow.com/a/18840568/741892
147 | //
148 | // The `script.readyState` transitions we're interested are:
149 | //
150 | // * If state starts as `loaded`
151 | // * Call `script.children`, which _should_ change state to `complete`
152 | // * If state is now `loading`, then **we have a load error**
153 | //
154 | // For the reader's amusement, here is HeadJS's catalog of various
155 | // `readyState` transitions in normal operation for IE:
156 | // https://github.com/headjs/headjs/blob/master/src/2.0.0/load.js#L379-L419
157 | if (firstState === "loaded") {
158 | // The act of accessing the property should change the script's
159 | // `readyState`.
160 | //
161 | // And, oh yeah, this hack is so hacky-ish we need the following
162 | // eslint disable...
163 | /*eslint-disable no-unused-expressions*/
164 | script.children;
165 | /*eslint-enable no-unused-expressions*/
166 |
167 | if (script.readyState === "loading") {
168 | // State transitions indicate we've hit the load error.
169 | //
170 | // **Note**: We are not intending to _return_ a value, just have
171 | // a shorter short-circuit code path here.
172 | return _error();
173 | }
174 | }
175 |
176 | // It's possible for readyState to be "complete" immediately
177 | // after we insert (and execute) the script in the branch
178 | // above. So check readyState again here and react without
179 | // waiting for another onreadystatechange.
180 | if (script.readyState === "complete") {
181 | _finish();
182 | }
183 | };
184 |
185 | // Onerror handler _may_ work here.
186 | script.onerror = _error;
187 |
188 | // Since we're not appending the script to the DOM yet, the
189 | // reference to our script element might get garbage collected
190 | // when this function ends, without onreadystatechange ever being
191 | // fired. This has been witnessed to happen. Adding it to
192 | // `pendingScripts` ensures this can't happen.
193 | pendingScripts[id] = script;
194 |
195 | // call the setup callback to mutate the script tag
196 | if (setup) {
197 | setup.call(context, script);
198 | }
199 |
200 | // This triggers a request for the script, but its contents won't
201 | // be executed until we append it to the DOM.
202 | script.src = src;
203 |
204 | // In some cases, the readyState is already "loaded" immediately
205 | // after setting src. It's a lie! Don't append to the DOM until
206 | // the onreadystatechange event says so.
207 |
208 | } else {
209 | // This section is for modern browsers, including IE10+.
210 |
211 | // Clear out listeners.
212 | _cleanup = function () {
213 | script.onload = script.onerror = null;
214 | };
215 |
216 | script.onerror = _error;
217 | script.onload = _finish;
218 | script.async = true;
219 | script.charset = "utf-8";
220 |
221 | // call the setup callback to mutate the script tag
222 | if (setup) {
223 | setup.call(context, script);
224 | }
225 |
226 | script.src = src;
227 |
228 | // Append to DOM.
229 | _addScript(script);
230 | }
231 | };
232 |
233 | // UMD wrapper.
234 | /*global define:false*/
235 | if (typeof exports === "object" && typeof module === "object") {
236 | // CommonJS
237 | module.exports = _lload;
238 |
239 | } else if (typeof define === "function" && define.amd) {
240 | // AMD
241 | define([], function () { return _lload; });
242 |
243 | } else {
244 | // VanillaJS
245 | window._lload = _lload;
246 | }
247 | }());
248 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "little-loader",
3 | "version": "0.2.0",
4 | "description": "A lightweight, IE8+ JavaScript loader.",
5 | "main": "lib/little-loader.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "https://github.com/walmartlabs/little-loader.git"
9 | },
10 | "contributors": [
11 | {
12 | "name": "Brian Beck",
13 | "email": "brian.beck@formidable.com"
14 | },
15 | {
16 | "name": "Ryan Roemer",
17 | "email": "ryan.roemer@formidable.com"
18 | }
19 | ],
20 | "license": "MIT",
21 | "bugs": {
22 | "url": "https://github.com/walmartlabs/little-loader/issues"
23 | },
24 | "dependencies": {},
25 | "devDependencies": {
26 | "builder": "^2.3.1",
27 | "chai": "^3.4.1",
28 | "coveralls": "^2.11.4",
29 | "eslint": "^1.10.3",
30 | "eslint-config-defaults": "^9.0.0",
31 | "eslint-plugin-filenames": "^0.2.0",
32 | "guacamole": "^1.1.4",
33 | "http-server": "^0.8.5",
34 | "istanbul": "^0.4.0",
35 | "istanbul-instrumenter-loader": "^0.2.0",
36 | "karma": "^0.13.15",
37 | "karma-chrome-launcher": "^0.2.2",
38 | "karma-coverage": "^0.5.3",
39 | "karma-firefox-launcher": "^0.1.7",
40 | "karma-ie-launcher": "^0.2.0",
41 | "karma-mocha": "^0.2.1",
42 | "karma-phantomjs-launcher": "^1.0.0",
43 | "karma-phantomjs-shim": "^1.1.2",
44 | "karma-requirejs": "^0.2.2",
45 | "karma-safari-launcher": "^0.1.1",
46 | "karma-sauce-launcher": "^0.3.0",
47 | "karma-sinon": "^1.0.5",
48 | "karma-spec-reporter": "0.0.24",
49 | "karma-webpack": "^1.7.0",
50 | "mocha": "^2.3.4",
51 | "node-uuid": "^1.4.7",
52 | "phantomjs": "^2.1.3",
53 | "phantomjs-prebuilt": "^2.1.4",
54 | "requirejs": "^2.1.22",
55 | "rimraf": "^2.4.4",
56 | "rowdy": "^0.4.0",
57 | "sauce-connect-launcher": "^0.14.0",
58 | "saucelabs": "^1.0.1",
59 | "selenium-standalone": "^4.9.1",
60 | "server-destroy": "^1.0.1",
61 | "sinon": "^1.17.6",
62 | "sinon-chai": "^2.8.0",
63 | "uglify-js": "^2.6.1",
64 | "webdriverio": "^4.0.3",
65 | "webpack": "^1.12.9"
66 | },
67 | "scripts": {
68 | "lint-client": "eslint -c .eslintrc-client lib test/func/fixtures",
69 | "lint-client-test": "eslint -c .eslintrc-client-test test/client/*/spec test/client/*/main.js",
70 | "lint-server": "eslint -c .eslintrc-server *.js",
71 | "lint-server-test": "eslint -c .eslintrc-server-test test/func/*.js test/func/spec",
72 | "lint": "builder concurrent lint-client lint-client-test lint-server lint-server-test",
73 | "clean-cov": "rimraf coverage/func",
74 | "test-client-rjs": "karma start test/client/requirejs/karma.conf.js",
75 | "test-client-rjs-ci": "karma start --browsers PhantomJS,Firefox test/client/requirejs/karma.conf.coverage.js",
76 | "test-client-rjs-cov": "karma start test/client/requirejs/karma.conf.coverage.js",
77 | "test-client-wp": "karma start test/client/webpack/karma.conf.js",
78 | "test-client-wp-ci": "karma start --browsers PhantomJS,Firefox test/client/webpack/karma.conf.coverage.js",
79 | "test-client-wp-cov": "karma start test/client/webpack/karma.conf.coverage.js",
80 | "test-client": "builder concurrent --buffer test-client-rjs test-client-wp",
81 | "test-client-ci": "builder concurrent --buffer test-client-rjs-ci test-client-wp-ci",
82 | "test-client-cov": "builder concurrent --buffer test-client-rjs-cov test-client-wp-cov",
83 | "test-func": "mocha --colors --opts test/func/mocha.opts test/func/spec/",
84 | "test-func-cov": "mocha --colors --opts test/func/mocha-cov.opts test/func/spec/",
85 | "test-func-ci": "builder run test-func-cov",
86 | "test": "builder run test-client && builder run test-func",
87 | "test-ci": "builder concurrent --buffer test-client-ci test-func-ci",
88 | "setup-local-selenium": "selenium-standalone start >/dev/null 2>&1",
89 | "setup-local": "builder run setup-local-selenium",
90 | "test-func-local": "sleep 5 && echo \"Starting ${ROWDY_SETTINGS}\" && builder run test-func-cov",
91 | "setup-sauce-connect": "node_modules/sauce-connect-launcher/sc/*/bin/sc",
92 | "setup-sauce": "builder run setup-sauce-connect",
93 | "test-func-sauce": "sleep 20 && echo \"Starting ${ROWDY_SETTINGS}\" && builder run test-func-cov",
94 | "cov-report-func": "istanbul report --config .istanbul.func.yml --include 'coverage/func/data/coverage-*.json'",
95 | "check": "builder run lint && builder run test",
96 | "check-ci": "builder run lint && builder run test-ci",
97 | "server": "http-server -p 3001 .",
98 | "install-dev": "selenium-standalone install",
99 | "build": "rimraf dist && mkdir dist && uglifyjs lib/little-loader.js --stats --compress --mangle --output=dist/little-loader.min.js",
100 | "preversion": "builder run check",
101 | "version": "builder run build",
102 | "postversion": "git push && git push --tags && npm publish"
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/test/client/fixtures/advanced/four.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | var test = window._LLOAD_TEST = window._LLOAD_TEST || {};
3 | test.four = "four";
4 | }());
5 |
--------------------------------------------------------------------------------
/test/client/fixtures/advanced/one.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | window._LLOAD_TEST = window._LLOAD_TEST || {};
3 | window._LLOAD_TEST.one = "one";
4 | }());
5 |
--------------------------------------------------------------------------------
/test/client/fixtures/advanced/three.amd.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | var test = window._LLOAD_TEST = window._LLOAD_TEST || {};
3 | test.three = "three";
4 | test.getFour = function (callback) {
5 | require(["lib/little-loader"], function (load) {
6 | load("/base/test/client/fixtures/advanced/four.js", callback);
7 | });
8 | };
9 | }());
10 |
--------------------------------------------------------------------------------
/test/client/fixtures/advanced/three.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Basic script.
3 | */
4 | (function () {
5 | var test = window._LLOAD_TEST = window._LLOAD_TEST || {};
6 | test.three = "three";
7 | }());
8 |
--------------------------------------------------------------------------------
/test/client/fixtures/advanced/two.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Basic script.
3 | */
4 | (function () {
5 | window._LLOAD_TEST = window._LLOAD_TEST || {};
6 | window._LLOAD_TEST.two = "two";
7 | }());
8 |
--------------------------------------------------------------------------------
/test/client/fixtures/basic/basic.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Basic script.
3 | */
4 | (function () {
5 | window._LLOAD_TEST = window._LLOAD_TEST || {};
6 | window._LLOAD_TEST.basic = "basic";
7 | }());
8 |
--------------------------------------------------------------------------------
/test/client/requirejs/karma.conf.coverage.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /*
3 | * Karma Configuration: "coverage" version.
4 | *
5 | * This configuration is the same as basic one-shot version, just with coverage.
6 | */
7 | var path = require("path");
8 | var ROOT = path.join(__dirname, "../../..");
9 |
10 | module.exports = function (config) {
11 | /* eslint-disable global-require */
12 | require("./karma.conf")(config);
13 | config.set({
14 | reporters: ["spec", "coverage"],
15 | preprocessors: {
16 | "lib/little-loader.js": ["coverage"]
17 | },
18 | coverageReporter: {
19 | reporters: [
20 | { type: "json", file: "coverage.json" },
21 | { type: "lcov" },
22 | { type: "text-summary" }
23 | ],
24 | dir: path.join(ROOT, "coverage/client/requirejs")
25 | }
26 | });
27 | };
28 |
--------------------------------------------------------------------------------
/test/client/requirejs/karma.conf.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /*
3 | * Karma Configuration
4 | */
5 | var path = require("path");
6 | var ROOT = path.join(__dirname, "../../..");
7 |
8 | module.exports = function (config) {
9 | config.set({
10 | frameworks: ["mocha", "phantomjs-shim", "requirejs", "sinon"],
11 | reporters: ["spec"],
12 | browsers: ["PhantomJS"],
13 | basePath: ROOT,
14 | files: [
15 | { pattern: "node_modules/chai/chai.js", included: false },
16 | { pattern: "node_modules/sinon-chai/lib/sinon-chai.js", included: false },
17 | { pattern: "lib/**/*.js", included: false },
18 | { pattern: "test/client/fixtures/**/*.js", included: false },
19 | { pattern: "test/client/requirejs/**/*.spec.js", included: false },
20 |
21 | "test/client/requirejs/main.js"
22 | ],
23 | port: 9999,
24 | singleRun: true,
25 | client: {
26 | captureConsole: true,
27 | mocha: {
28 | ui: "bdd"
29 | }
30 | }
31 | });
32 | };
33 |
--------------------------------------------------------------------------------
/test/client/requirejs/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Test setup for client-side tests.
3 | */
4 | // TODO: Add expect.js + ie8 compat.
5 | // https://github.com/walmartlabs/little-loader/issues/17
6 |
7 | (function () {
8 | requirejs.config({
9 | // Karma serves files from '/base'
10 | baseUrl: "/base",
11 |
12 | paths: {
13 | "chai": "node_modules/chai/chai",
14 | "sinon-chai": "node_modules/sinon-chai/lib/sinon-chai"
15 | }
16 | });
17 |
18 | require(["chai", "sinon-chai"], function (chai, sinonChai) {
19 | /*globals window:false*/
20 |
21 | // ------------------------------------------------------------------------
22 | // Chai / Mocha configuration.
23 | // ------------------------------------------------------------------------
24 | // Integration
25 | chai.use(sinonChai);
26 |
27 | // Exports
28 | window.expect = chai.expect;
29 |
30 | // Mocha (part of static include).
31 | window.mocha.setup({
32 | ui: "bdd",
33 | bail: false
34 | });
35 |
36 | // ------------------------------------------------------------------------
37 | // Bootstrap
38 | // ------------------------------------------------------------------------
39 | var tests = [];
40 | for (var file in window.__karma__.files) {
41 | if (/\.spec\.js$/.test(file)) {
42 | tests.push(file);
43 | }
44 | }
45 |
46 | require(tests, function () {
47 | window.__karma__.start();
48 | });
49 | });
50 | }());
51 |
--------------------------------------------------------------------------------
/test/client/requirejs/spec/advanced.spec.js:
--------------------------------------------------------------------------------
1 | define(["lib/little-loader"], function (load) {
2 | describe("requirejs:advanced", function () {
3 |
4 | beforeEach(function () {
5 | window._LLOAD_TEST = {};
6 | });
7 |
8 | it("loads nested scripts", function (done) {
9 | load("/base/test/client/fixtures/advanced/one.js", function (err1) {
10 | expect(err1).to.not.be.ok;
11 | expect(window._LLOAD_TEST.one).to.equal("one");
12 |
13 | load("/base/test/client/fixtures/advanced/two.js", function (err2) {
14 | expect(err2).to.not.be.ok;
15 | expect(window._LLOAD_TEST.two).to.equal("two");
16 |
17 | load("/base/test/client/fixtures/advanced/three.js", function (err3) {
18 | expect(err3).to.not.be.ok;
19 | expect(window._LLOAD_TEST.three).to.equal("three");
20 |
21 | load("/base/test/client/fixtures/advanced/four.js", function (err4) {
22 | expect(err4).to.not.be.ok;
23 | expect(window._LLOAD_TEST.four).to.equal("four");
24 | done();
25 | });
26 | });
27 | });
28 | });
29 | });
30 |
31 | it("loads requirejs callback to load", function (done) {
32 | load("/base/test/client/fixtures/advanced/one.js", function (err1) {
33 | expect(err1).to.not.be.ok;
34 | expect(window._LLOAD_TEST.one).to.equal("one");
35 |
36 | load("/base/test/client/fixtures/advanced/two.js", function (err2) {
37 | expect(err2).to.not.be.ok;
38 | expect(window._LLOAD_TEST.two).to.equal("two");
39 |
40 | load("/base/test/client/fixtures/advanced/three.amd.js", function (err3) {
41 | expect(err3).to.not.be.ok;
42 | expect(window._LLOAD_TEST.three).to.equal("three");
43 |
44 | window._LLOAD_TEST.getFour(function () {
45 | expect(window._LLOAD_TEST.four).to.equal("four");
46 | done();
47 | });
48 | });
49 | });
50 | });
51 | });
52 | });
53 | });
54 |
--------------------------------------------------------------------------------
/test/client/requirejs/spec/basic.spec.js:
--------------------------------------------------------------------------------
1 | define(["lib/little-loader"], function (load) {
2 | describe("requirejs:basic", function () {
3 |
4 | it("load is a function", function () {
5 | expect(load).to.be.a("function");
6 | });
7 |
8 | it("loads basic", function (done) {
9 | load("/base/test/client/fixtures/basic/basic.js", function (err) {
10 | expect(err).to.not.be.ok;
11 | expect(window._LLOAD_TEST).to.be.ok;
12 | expect(window._LLOAD_TEST.basic).to.equal("basic");
13 | done();
14 | });
15 | });
16 |
17 | it("uses context", function (done) {
18 | var obj = { greeting: "hi" };
19 |
20 | load("/base/test/client/fixtures/basic/basic.js", function (err) {
21 | expect(err).to.not.be.ok;
22 | expect(this.greeting).to.equal("hi");
23 | done();
24 | }, obj);
25 | });
26 |
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/test/client/requirejs/spec/config.spec.js:
--------------------------------------------------------------------------------
1 | /*global sinon: false */
2 |
3 | define(["lib/little-loader"], function (load) {
4 | describe("requirejs:config", function () {
5 |
6 | it("loads basic", function (done) {
7 | var config = {
8 | callback: function (err) {
9 | expect(err).to.not.be.ok;
10 | expect(window._LLOAD_TEST).to.be.ok;
11 | expect(window._LLOAD_TEST.basic).to.equal("basic");
12 | done();
13 | }
14 | };
15 |
16 | load("/base/test/client/fixtures/basic/basic.js", config);
17 | });
18 |
19 | it("uses context", function (done) {
20 | var config = {
21 | callback: function (err) {
22 | expect(err).to.not.be.ok;
23 | expect(this.greeting).to.equal("hi");
24 | done();
25 | },
26 |
27 | context: { greeting: "hi" }
28 | };
29 |
30 | load("/base/test/client/fixtures/basic/basic.js", config);
31 | });
32 |
33 | it("calls setup", function (done) {
34 | var setup = sinon.spy();
35 | var context = {};
36 |
37 | var config = {
38 | callback: function (err) {
39 | expect(err).to.not.be.ok;
40 | expect(setup)
41 | .to.have.callCount(1).and
42 | .to.be.calledOn(context);
43 |
44 | done();
45 | },
46 |
47 | context: context,
48 | setup: setup
49 | };
50 |
51 | load("/base/test/client/fixtures/basic/basic.js", config);
52 | });
53 |
54 | });
55 | });
56 |
--------------------------------------------------------------------------------
/test/client/requirejs/spec/error.spec.js:
--------------------------------------------------------------------------------
1 | define(["lib/little-loader"], function (load) {
2 | describe("requirejs:error", function () {
3 |
4 | it("errs on 404", function (done) {
5 | load("DOESNT_EXIST.js", function (err) {
6 | expect(err).to.be.ok;
7 | expect(err.message || err.toString()).to.contain("DOESNT_EXIST.js");
8 | done();
9 | });
10 | });
11 |
12 | it("errs on undefined url", function (done) {
13 | load(undefined, function (err) {
14 | expect(err).to.be.ok;
15 | expect(err.message || err.toString()).to.contain("EMPTY");
16 | done();
17 | });
18 | });
19 |
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/test/client/webpack/karma.conf.coverage.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /*
3 | * Karma Configuration: "coverage" version.
4 | *
5 | * This configuration is the same as basic one-shot version, just with coverage.
6 | */
7 | var path = require("path");
8 | var ROOT = path.join(__dirname, "../../..");
9 |
10 | module.exports = function (config) {
11 | /* eslint-disable global-require */
12 | require("./karma.conf")(config);
13 |
14 | // Mutate and manually instrument.
15 | config.webpack.module = {
16 | preLoaders: [
17 | {
18 | test: /lib\/.*\.js$/,
19 | exclude: /(test|node_modules)\//,
20 | loader: "istanbul-instrumenter"
21 | }
22 | ]
23 | };
24 |
25 | config.set({
26 | reporters: ["spec", "coverage"],
27 | preprocessors: {
28 | "test/client/webpack/main.js": ["webpack"]
29 | },
30 | webpack: config.webpack,
31 | coverageReporter: {
32 | reporters: [
33 | { type: "json", file: "coverage.json" },
34 | { type: "lcov" },
35 | { type: "text-summary" }
36 | ],
37 | dir: path.join(ROOT, "coverage/client/webpack")
38 | }
39 | });
40 | };
41 |
--------------------------------------------------------------------------------
/test/client/webpack/karma.conf.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /*
3 | * Karma Configuration
4 | */
5 | var path = require("path");
6 | var ROOT = path.join(__dirname, "../../..");
7 |
8 | module.exports = function (config) {
9 | config.set({
10 | frameworks: ["mocha", "phantomjs-shim", "sinon"],
11 | reporters: ["spec"],
12 | browsers: ["PhantomJS"],
13 | basePath: ROOT,
14 | preprocessors: {
15 | "test/client/webpack/main.js": ["webpack"]
16 | },
17 | files: [
18 | { pattern: "test/client/fixtures/**/*.js", included: false },
19 |
20 | "test/client/webpack/main.js"
21 | ],
22 | port: 9999,
23 | singleRun: true,
24 | client: {
25 | captureConsole: true,
26 | mocha: {
27 | ui: "bdd"
28 | }
29 | },
30 | webpack: {
31 | cache: true,
32 | context: path.join(ROOT, "test/client/webpack"),
33 | entry: "./main",
34 | output: {
35 | filename: "main.js",
36 | publicPath: "/assets/"
37 | },
38 | resolve: {
39 | alias: {
40 | // Allow root import of `lib/FOO` from ROOT/lib.
41 | lib: path.join(ROOT, "lib")
42 | }
43 | },
44 | devtool: "source-map"
45 | },
46 | webpackServer: {
47 | port: 3002, // Choose a non-conflicting port (3001 static serve)
48 | quiet: true,
49 | noInfo: true
50 | }
51 | });
52 | };
53 |
--------------------------------------------------------------------------------
/test/client/webpack/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Test setup for client-side tests.
3 | */
4 | // TODO: Add expect.js + ie8 compat.
5 | // https://github.com/walmartlabs/little-loader/issues/17
6 |
7 | /*globals window:false*/
8 | var chai = require("chai");
9 | var sinonChai = require("sinon-chai");
10 |
11 | // --------------------------------------------------------------------------
12 | // Chai / Mocha configuration.
13 | // --------------------------------------------------------------------------
14 | // Integration
15 | chai.use(sinonChai);
16 |
17 | // Exports
18 | window.expect = chai.expect;
19 |
20 | // Mocha (part of static include).
21 | window.mocha.setup({
22 | ui: "bdd",
23 | bail: false
24 | });
25 |
26 | // --------------------------------------------------------------------------
27 | // Bootstrap
28 | // --------------------------------------------------------------------------
29 | // Use webpack to infer and `require` tests automatically.
30 | var testsReq = require.context(".", true, /\.spec\.js$/);
31 | testsReq.keys().map(testsReq);
32 |
--------------------------------------------------------------------------------
/test/client/webpack/spec/advanced.spec.js:
--------------------------------------------------------------------------------
1 | var load = require("lib/little-loader");
2 |
3 | describe("webpack:advanced", function () {
4 |
5 | beforeEach(function () {
6 | window._LLOAD_TEST = {};
7 | });
8 |
9 | it("loads nested scripts", function (done) {
10 | load("/base/test/client/fixtures/advanced/one.js", function (err1) {
11 | expect(err1).to.not.be.ok;
12 | expect(window._LLOAD_TEST.one).to.equal("one");
13 |
14 | load("/base/test/client/fixtures/advanced/two.js", function (err2) {
15 | expect(err2).to.not.be.ok;
16 | expect(window._LLOAD_TEST.two).to.equal("two");
17 |
18 | load("/base/test/client/fixtures/advanced/three.js", function (err3) {
19 | expect(err3).to.not.be.ok;
20 | expect(window._LLOAD_TEST.three).to.equal("three");
21 |
22 | load("/base/test/client/fixtures/advanced/four.js", function (err4) {
23 | expect(err4).to.not.be.ok;
24 | expect(window._LLOAD_TEST.four).to.equal("four");
25 | done();
26 | });
27 | });
28 | });
29 | });
30 | });
31 |
32 | });
33 |
--------------------------------------------------------------------------------
/test/client/webpack/spec/basic.spec.js:
--------------------------------------------------------------------------------
1 | var load = require("lib/little-loader");
2 |
3 | describe("webpack:basic", function () {
4 |
5 | it("load is a function", function () {
6 | expect(load).to.be.a("function");
7 | });
8 |
9 | it("loads basic", function (done) {
10 | load("/base/test/client/fixtures/basic/basic.js", function (err) {
11 | expect(err).to.not.be.ok;
12 | expect(window._LLOAD_TEST).to.be.ok;
13 | expect(window._LLOAD_TEST.basic).to.equal("basic");
14 | done();
15 | });
16 | });
17 |
18 | it("uses context", function (done) {
19 | var obj = { greeting: "hi" };
20 |
21 | load("/base/test/client/fixtures/basic/basic.js", function (err) {
22 | expect(err).to.not.be.ok;
23 | expect(this.greeting).to.equal("hi");
24 | done();
25 | }, obj);
26 | });
27 |
28 | });
29 |
--------------------------------------------------------------------------------
/test/client/webpack/spec/config.spec.js:
--------------------------------------------------------------------------------
1 | /*global sinon: false */
2 | var load = require("lib/little-loader");
3 |
4 | describe("webpack:config", function () {
5 |
6 | it("loads basic", function (done) {
7 | var config = {
8 | callback: function (err) {
9 | expect(err).to.not.be.ok;
10 | expect(window._LLOAD_TEST).to.be.ok;
11 | expect(window._LLOAD_TEST.basic).to.equal("basic");
12 | done();
13 | }
14 | };
15 |
16 | load("/base/test/client/fixtures/basic/basic.js", config);
17 | });
18 |
19 | it("uses context", function (done) {
20 | var config = {
21 | callback: function (err) {
22 | expect(err).to.not.be.ok;
23 | expect(this.greeting).to.equal("hi");
24 | done();
25 | },
26 |
27 | context: { greeting: "hi" }
28 | };
29 |
30 | load("/base/test/client/fixtures/basic/basic.js", config);
31 | });
32 |
33 | it("calls setup", function (done) {
34 | var setup = sinon.spy();
35 | var context = {};
36 |
37 | var config = {
38 | callback: function (err) {
39 | expect(err).to.not.be.ok;
40 | expect(setup)
41 | .to.have.callCount(1).and
42 | .to.be.calledOn(context);
43 |
44 | done();
45 | },
46 |
47 | context: context,
48 | setup: setup
49 | };
50 |
51 | load("/base/test/client/fixtures/basic/basic.js", config);
52 | });
53 |
54 | });
55 |
--------------------------------------------------------------------------------
/test/client/webpack/spec/error.spec.js:
--------------------------------------------------------------------------------
1 | var load = require("lib/little-loader");
2 |
3 | describe("webpack:error", function () {
4 |
5 | it("errs on 404", function (done) {
6 | load("DOESNT_EXIST.js", function (err) {
7 | expect(err).to.be.ok;
8 | expect(err.message || err.toString()).to.contain("DOESNT_EXIST.js");
9 | done();
10 | });
11 | });
12 |
13 | it("errs on undefined url", function (done) {
14 | load(undefined, function (err) {
15 | expect(err).to.be.ok;
16 | expect(err.message || err.toString()).to.contain("EMPTY");
17 | done();
18 | });
19 | });
20 |
21 | });
22 |
--------------------------------------------------------------------------------
/test/func/fixtures/advanced.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Fixture
5 |
6 |
7 |
8 |
9 |
10 |
11 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/test/func/fixtures/advanced/first.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | var content = document.querySelector(".e2e-content");
3 | content.innerHTML += "First Script
";
4 | }());
5 |
--------------------------------------------------------------------------------
/test/func/fixtures/advanced/fourth.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | var content = document.querySelector(".e2e-content");
3 | content.innerHTML += "Fourth Script
";
4 | }());
5 |
--------------------------------------------------------------------------------
/test/func/fixtures/advanced/second.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | var content = document.querySelector(".e2e-content");
3 | content.innerHTML += "Second Script
";
4 |
5 | window._lload("advanced/fourth.js", {
6 | callback: function () {
7 | content.innerHTML += "After Load Fourth
";
8 | },
9 | setup: function () {
10 | content.innerHTML += "After Setup Fourth
";
11 | }
12 | });
13 | }());
14 |
--------------------------------------------------------------------------------
/test/func/fixtures/advanced/third.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | var content = document.querySelector(".e2e-content");
3 | content.innerHTML += "Third Script
";
4 | }());
5 |
--------------------------------------------------------------------------------
/test/func/fixtures/basic.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Fixture
5 |
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/test/func/fixtures/basic/basic.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Basic script.
3 | */
4 | (function () {
5 | var content = document.querySelector(".e2e-content");
6 | content.innerHTML += "Basic Script
";
7 | }());
8 |
--------------------------------------------------------------------------------
/test/func/fixtures/error-handler.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Error handler for all tests.
3 | */
4 | (function () {
5 | /*eslint-disable max-params*/
6 | window.onerror = function (msg, file, line, col, error) {
7 | var content = document.querySelector(".e2e-error");
8 | content.innerHTML += ""
9 | + "msg: " + msg + "
\n"
10 | + "file: " + file + "
\n"
11 | + "line: " + line + "
\n"
12 | + "col: " + col + "
\n"
13 | + "error: " + error + "
\n"
14 | + "
";
15 | };
16 | }());
17 |
--------------------------------------------------------------------------------
/test/func/fixtures/error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Fixture
5 |
6 |
7 |
8 |
9 |
10 |
11 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/test/func/fixtures/jquery.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Fixture
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/test/func/fixtures/jquery/jquery.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | // These are "live" tests meaning you need an internet connection.
3 | var load = window._lload;
4 | var content = document.querySelector(".e2e-content");
5 |
6 | // DOM writing helper
7 | var output = function (name, err, result) {
8 | content.innerHTML +=
9 | "" +
10 | (err ? err.message || err.toString() : "") +
11 | "
" +
12 |
13 | "" +
14 | (result || "") +
15 | "
";
16 | };
17 |
18 | // Append status information of jQuery noConflict state to DOM content.
19 | var check = function (host, version, extra) {
20 | var name = [host, version.replace(/\./g, "-"), extra].join("-");
21 | var url = host === "google" ?
22 | "http://ajax.googleapis.com/ajax/libs/jquery/" + version + "/jquery.min.js" :
23 | "http://code.jquery.com/jquery-" + version + ".min.js";
24 |
25 | load(url, function (err) {
26 | var results = "";
27 |
28 | if (typeof window.jQuery !== "function") {
29 | results += "FAIL: jquery function, ";
30 | }
31 |
32 | // Remove the global.
33 | var jQuery = window.jQuery.noConflict(true);
34 |
35 | if (typeof jQuery._MARKED !== "undefined") {
36 | results += "FAIL: jquery marked, ";
37 | }
38 |
39 | if (jQuery.fn.jquery !== version) {
40 | results += "FAIL: jquery version ( " +
41 | jQuery.fn.jquery + " vs. " + version + "), ";
42 | }
43 |
44 | // Mark the instance with a flag.
45 | jQuery._MARKED = true;
46 |
47 | // Pass
48 | if (!results) {
49 | results = "PASS";
50 | }
51 |
52 | output(name, err, results);
53 | });
54 | };
55 |
56 | // Run a whole bunch of loads.
57 | check("google", "1.11.3", "1");
58 | check("jquery", "1.11.3", "1");
59 |
60 | check("google", "1.11.2", "1");
61 | check("jquery", "1.11.2", "1");
62 |
63 | check("jquery", "1.7.2", "1");
64 |
65 | check("google", "1.11.1", "1");
66 | check("jquery", "1.11.1", "1");
67 |
68 | check("google", "1.7.2", "1");
69 |
70 | check("google", "1.11.3", "2");
71 | check("jquery", "1.11.3", "2");
72 | }());
73 |
--------------------------------------------------------------------------------
/test/func/fixtures/origins.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Fixture
5 |
6 |
7 |
8 |
9 |
10 |
11 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/test/func/mocha-cov.opts:
--------------------------------------------------------------------------------
1 | --require test/func/setup-cov.js
2 | --reporter spec
3 | --ui bdd
4 | --timeout 60000
5 |
--------------------------------------------------------------------------------
/test/func/mocha.opts:
--------------------------------------------------------------------------------
1 | --require test/func/setup.js
2 | --reporter spec
3 | --ui bdd
4 | --timeout 60000
5 |
--------------------------------------------------------------------------------
/test/func/setup-cov.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /**
3 | * Test setup for functional tests with code coverage.
4 | */
5 | require("./setup.js");
6 |
7 | // Indicate coverage.
8 | global.USE_COVERAGE = true;
9 |
--------------------------------------------------------------------------------
/test/func/setup.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /**
3 | * Test setup for functional tests.
4 | */
5 | var chai = require("chai");
6 |
7 | // Add test lib globals.
8 | global.expect = chai.expect;
9 |
10 | // Set test environment
11 | process.env.NODE_ENV = "func";
12 |
--------------------------------------------------------------------------------
/test/func/spec/advanced.spec.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var base = require("./base.spec");
4 |
5 | describe("advanced", function () {
6 | it("loads advanced scenario", function () {
7 | var url = base.appUrl + "test/func/fixtures/advanced.html";
8 |
9 | return base.adapter.client
10 | .url(url)
11 |
12 | // Check errors
13 | .getText(".e2e-error").then(function (text) {
14 | expect(text).to.not.be.ok;
15 | })
16 |
17 | // Verify load
18 | .getText(".e2e-script-first").then(function (text) {
19 | expect(text).to.equal("First Script");
20 | })
21 | .getText(".e2e-after-load-first").then(function (text) {
22 | expect(text).to.equal("After Load First");
23 | })
24 | .getText(".e2e-script-second").then(function (text) {
25 | expect(text).to.equal("Second Script");
26 | })
27 | .getText(".e2e-after-load-second").then(function (text) {
28 | expect(text).to.equal("After Load Second");
29 | })
30 | .getText(".e2e-script-third").then(function (text) {
31 | expect(text).to.equal("Third Script");
32 | })
33 | .getText(".e2e-after-load-third").then(function (text) {
34 | expect(text).to.equal("After Load Third");
35 | })
36 | .getText(".e2e-script-fourth").then(function (text) {
37 | expect(text).to.equal("Fourth Script");
38 | })
39 | .getText(".e2e-after-load-fourth").then(function (text) {
40 | expect(text).to.equal("After Load Fourth");
41 | })
42 | .getText(".e2e-after-setup-fourth").then(function (text) {
43 | expect(text).to.equal("After Setup Fourth");
44 | });
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/test/func/spec/base.spec.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /**
3 | * Base setup, specs.
4 | *
5 | * This file _must_ be run in any spec file and thus must be manually
6 | * `require()`-ed in.
7 | */
8 | // --------------------------------------------------------------------------
9 | // Selenium (webdriverio/Rowdy) initialization
10 | // --------------------------------------------------------------------------
11 | // We use webdriverio to get a client to Selenium, and Rowdy to help configure
12 | // our client, start a local selenium server if specified and provide a Mocha
13 | // adapter.
14 | // Enable Rowdy with webdriverio.
15 | var rowdy = require("rowdy");
16 | var config = require("rowdy/config");
17 |
18 | // Only start selenium on single-run local.
19 | var startSelenium = process.env.TEST_PARALLEL !== "true" && process.env.CI !== "true";
20 |
21 | // Patch and re-configure.
22 | config.options.driverLib = "webdriverio";
23 | config.options.server.start = startSelenium;
24 | rowdy(config);
25 |
26 | // Patch rowdy to force not started.
27 | // https://github.com/FormidableLabs/rowdy/issues/40
28 | if ((rowdy.setting.server || {}).start) {
29 | rowdy.setting.server.start = startSelenium;
30 | }
31 |
32 | // Mocha adapter.
33 | var Adapter = rowdy.adapters.mocha;
34 | var adapter = new Adapter();
35 |
36 | adapter.before();
37 | adapter.beforeEach();
38 | adapter.afterEach();
39 | adapter.after();
40 |
41 | before(function () {
42 | var IMPLICIT_TIMEOUT = 200;
43 |
44 | // The `adapter.before();` call has the side effect of instantiating a
45 | // Selenium / webdriver client that we can extract here.
46 | // Set a global Selenium timeout that is _before_ our test timeout.
47 | return adapter.client
48 | .timeouts("implicit", IMPLICIT_TIMEOUT);
49 | });
50 |
51 | // --------------------------------------------------------------------------
52 | // Dev. Server
53 | // --------------------------------------------------------------------------
54 | var APP_PORT_DEFAULT = 3030;
55 | var APP_PORT = process.env.TEST_FUNC_PORT || APP_PORT_DEFAULT;
56 | APP_PORT = parseInt(APP_PORT, 10);
57 | var APP_HOST = process.env.TEST_FUNC_HOST || "127.0.0.1";
58 | var APP_URL = "http://" + APP_HOST + ":" + APP_PORT + "/";
59 |
60 | // Go for "other" port of +2 if not specified
61 | var APP_PORT_OTHER = process.env.TEST_FUNC_PORT_OTHER || APP_PORT + 2;
62 | APP_PORT_OTHER = parseInt(APP_PORT_OTHER, 10);
63 | var APP_URL_OTHER = "http://" + APP_HOST + ":" + APP_PORT_OTHER + "/";
64 |
65 | // Start up (and later stop) a single instance of the server so that we can
66 | // interact with the web application via our tests.
67 | //
68 | // An alternative to this approach is to hit a live running staging or
69 | // production server for "smoke" tests.
70 | //
71 | // For multi-file tests this setup should be extracted to a `base.spec.js`
72 | // file and executed **once** for the entire test suite.
73 | var httpServer = require("http-server");
74 | var enableDestroy = require("server-destroy");
75 |
76 | // To test multiple origins, we spawn two servers.
77 | var realServer1;
78 | var realServer2;
79 |
80 | // ----------------------------------------------------------------------------
81 | // Code Coverage
82 | // ----------------------------------------------------------------------------
83 | var path = require("path");
84 | var fs = require("fs");
85 | var uuid = require("node-uuid");
86 | var istanbul = require("istanbul");
87 | var collector = new istanbul.Collector();
88 |
89 | var PROJECT_ROOT = path.resolve(__dirname, "../../..");
90 | var middleware = [];
91 |
92 | // Instrument library for middleware insertion.
93 | var _covered = function (filePath) {
94 | var fileName = path.relative(PROJECT_ROOT, filePath);
95 | var code = fs.readFileSync(filePath);
96 | var instrumenter = new istanbul.Instrumenter();
97 | return instrumenter.instrumentSync(code.toString(), fileName);
98 | };
99 |
100 | if (global.USE_COVERAGE) {
101 | // Custom Instrumentation middleware.
102 | middleware.push(function (req, res) {
103 | var HTTP_OK = 200;
104 |
105 | if (/lib\/little-loader\.js/.test(req.url)) {
106 | var covered = _covered(path.resolve(PROJECT_ROOT, "lib/little-loader.js"));
107 |
108 | res.writeHead(HTTP_OK, { "Content-Type": "text/javascript" });
109 | res.end(covered);
110 | return;
111 | }
112 |
113 | res.emit("next");
114 | });
115 |
116 | afterEach(function () {
117 | return adapter.client
118 | // Coverage.
119 | .execute(function () {
120 | // Client / browser code.
121 | /*globals window:false */
122 | return JSON.stringify(window.__coverage__);
123 | }).then(function (ret) {
124 | // Gather data into collector.
125 | // Note: `JSON.parse` exception will get caught in `.finally()`
126 | var covObj = JSON.parse(ret.value);
127 | collector.add(covObj);
128 | });
129 | });
130 |
131 | after(function (done) {
132 | // Load configuration.
133 | // **Note**: We're tying to a known istanbul configuration file that in the
134 | // general should come from a shell flag.
135 | var cfg = istanbul.config.loadFile(".istanbul.func.yml");
136 |
137 | // Patch reporter to output our GUID-driven incremental coverage files.
138 | cfg.reporting.reportConfig = function () {
139 | return {
140 | json: {
141 | file: "coverage-" + uuid.v4() + ".json"
142 | }
143 | };
144 | };
145 |
146 | // Create a `coverage/func/data` directory for outputs.
147 | var dir = path.join(cfg.reporting.config.dir, "data");
148 |
149 | // Write out `data/coverage-GUID.json` object.
150 | var reporter = new istanbul.Reporter(cfg, dir);
151 | reporter.add("json");
152 | reporter.write(collector, false, done);
153 | });
154 | }
155 |
156 | // ----------------------------------------------------------------------------
157 | // App server
158 | // ----------------------------------------------------------------------------
159 | // Primary server
160 | before(function (done) {
161 | var server1 = httpServer.createServer({
162 | before: middleware
163 | });
164 | server1.listen(APP_PORT, APP_HOST, done);
165 |
166 | // `http-server` doesn't pass enough of the underlying server, so we capture it.
167 | realServer1 = server1.server;
168 |
169 | // Wrap the server with a "REALLY REALLY KILL IT!" `destroy` method.
170 | enableDestroy(realServer1);
171 | });
172 |
173 | after(function (done) {
174 | if (!realServer1) { return done(); }
175 |
176 | // Take that server!
177 | realServer1.destroy(done);
178 | });
179 |
180 | // Other server
181 | before(function (done) {
182 | var server2 = httpServer.createServer();
183 | server2.listen(APP_PORT_OTHER, APP_HOST, done);
184 | realServer2 = server2.server;
185 | enableDestroy(realServer2);
186 | });
187 |
188 | after(function (done) {
189 | if (!realServer2) { return done(); }
190 | realServer2.destroy(done);
191 | });
192 |
193 | module.exports = {
194 | adapter: adapter,
195 | appUrl: APP_URL,
196 | appUrlOther: APP_URL_OTHER
197 | };
198 |
--------------------------------------------------------------------------------
/test/func/spec/basic.spec.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var base = require("./base.spec");
4 |
5 | describe("basic", function () {
6 | it("loads basic script", function () {
7 | var url = base.appUrl + "test/func/fixtures/basic.html";
8 |
9 | return base.adapter.client
10 | .url(url)
11 |
12 | // Check errors
13 | .getText(".e2e-error").then(function (text) {
14 | expect(text).to.not.be.ok;
15 | })
16 |
17 | // Verify load
18 | .getText(".e2e-basic-script").then(function (text) {
19 | expect(text).to.equal("Basic Script");
20 | })
21 | .getText(".e2e-after-load").then(function (text) {
22 | expect(text).to.equal("After Load");
23 | });
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/test/func/spec/error.spec.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var base = require("./base.spec");
4 |
5 | describe("error", function () {
6 | it("capture script 404 error", function () {
7 | var url = base.appUrl + "test/func/fixtures/error.html";
8 |
9 | return base.adapter.client
10 | .url(url)
11 |
12 | // Check errors
13 | .getText(".e2e-error").then(function (text) {
14 | expect(text).to.not.be.ok;
15 | })
16 |
17 | // Verify error callback
18 | .getText(".e2e-after-load").then(function (text) {
19 | expect(text).to.equal("DOESNT_EXIST.js");
20 | });
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/test/func/spec/jquery.spec.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var base = require("./base.spec");
4 |
5 | describe("error", function () {
6 | it("handles multiple jqueries", function () {
7 | var url = base.appUrl + "test/func/fixtures/jquery.html";
8 |
9 | return base.adapter.client
10 | .url(url)
11 |
12 | // Check errors
13 | .getText(".e2e-error").then(function (text) {
14 | expect(text).to.not.be.ok;
15 | })
16 |
17 | // Verify error and result callbacks
18 | .getText(".e2e-google-1-11-3-1-error").then(function (text) {
19 | expect(text).to.equal("");
20 | })
21 | .getText(".e2e-google-1-11-3-1-result").then(function (text) {
22 | expect(text).to.equal("PASS");
23 | })
24 |
25 | .getText(".e2e-jquery-1-11-3-1-error").then(function (text) {
26 | expect(text).to.equal("");
27 | })
28 | .getText(".e2e-jquery-1-11-3-1-result").then(function (text) {
29 | expect(text).to.equal("PASS");
30 | })
31 |
32 | .getText(".e2e-google-1-11-2-1-error").then(function (text) {
33 | expect(text).to.equal("");
34 | })
35 | .getText(".e2e-google-1-11-2-1-result").then(function (text) {
36 | expect(text).to.equal("PASS");
37 | })
38 |
39 | .getText(".e2e-jquery-1-11-2-1-error").then(function (text) {
40 | expect(text).to.equal("");
41 | })
42 | .getText(".e2e-jquery-1-11-2-1-result").then(function (text) {
43 | expect(text).to.equal("PASS");
44 | })
45 |
46 | .getText(".e2e-google-1-7-2-1-error").then(function (text) {
47 | expect(text).to.equal("");
48 | })
49 | .getText(".e2e-google-1-7-2-1-result").then(function (text) {
50 | expect(text).to.equal("PASS");
51 | })
52 |
53 | .getText(".e2e-google-1-11-1-1-error").then(function (text) {
54 | expect(text).to.equal("");
55 | })
56 | .getText(".e2e-google-1-11-1-1-result").then(function (text) {
57 | expect(text).to.equal("PASS");
58 | })
59 |
60 | .getText(".e2e-jquery-1-11-1-1-error").then(function (text) {
61 | expect(text).to.equal("");
62 | })
63 | .getText(".e2e-jquery-1-11-1-1-result").then(function (text) {
64 | expect(text).to.equal("PASS");
65 | })
66 |
67 | .getText(".e2e-jquery-1-7-2-1-error").then(function (text) {
68 | expect(text).to.equal("");
69 | })
70 | .getText(".e2e-jquery-1-7-2-1-result").then(function (text) {
71 | expect(text).to.equal("PASS");
72 | })
73 |
74 | .getText(".e2e-google-1-11-3-2-error").then(function (text) {
75 | expect(text).to.equal("");
76 | })
77 | .getText(".e2e-google-1-11-3-2-result").then(function (text) {
78 | expect(text).to.equal("PASS");
79 | })
80 |
81 | .getText(".e2e-jquery-1-11-3-2-error").then(function (text) {
82 | expect(text).to.equal("");
83 | })
84 | .getText(".e2e-jquery-1-11-3-2-result").then(function (text) {
85 | expect(text).to.equal("PASS");
86 | });
87 | });
88 | });
89 |
--------------------------------------------------------------------------------
/test/func/spec/origins.spec.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /**
3 | * Origins
4 | *
5 | * Reuses the `advanced` scripts to test 3/4 from altnerate origin (different port).
6 | */
7 | var base = require("./base.spec");
8 |
9 | describe("origins", function () {
10 | it("loads origins scenario", function () {
11 | var url = base.appUrl + "test/func/fixtures/origins.html";
12 |
13 | return base.adapter.client
14 | .url(url)
15 |
16 | // Inject dynamic JS (easiest way to get `appUrlOther` information).
17 | .execute(function (appUrlOther) {
18 | // CLIENT CODE: This is stringified, sent to browser and executed.
19 | /*global window:false, document:false*/
20 | var content = document.querySelector(".e2e-content");
21 |
22 | // Load second (which loads fourth) and third from other orign.
23 | window._lload(appUrlOther + "test/func/fixtures/advanced/second.js", function () {
24 | content.innerHTML += "After Load Second
";
25 | });
26 | window._lload(appUrlOther + "test/func/fixtures/advanced/third.js", function () {
27 | content.innerHTML += "After Load Third
";
28 | });
29 | }, base.appUrlOther)
30 |
31 | // Check errors
32 | .getText(".e2e-error").then(function (text) {
33 | expect(text).to.not.be.ok;
34 | })
35 |
36 | // Verify load from same origin.
37 | .getText(".e2e-script-first").then(function (text) {
38 | expect(text).to.equal("First Script");
39 | })
40 | .getText(".e2e-after-load-first").then(function (text) {
41 | expect(text).to.equal("After Load First");
42 | })
43 |
44 | // Verify load from different origin.
45 | .getText(".e2e-script-second").then(function (text) {
46 | expect(text).to.equal("Second Script");
47 | })
48 | .getText(".e2e-after-load-second").then(function (text) {
49 | expect(text).to.equal("After Load Second");
50 | })
51 | .getText(".e2e-script-third").then(function (text) {
52 | expect(text).to.equal("Third Script");
53 | })
54 | .getText(".e2e-after-load-third").then(function (text) {
55 | expect(text).to.equal("After Load Third");
56 | })
57 | .getText(".e2e-script-fourth").then(function (text) {
58 | expect(text).to.equal("Fourth Script");
59 | })
60 | .getText(".e2e-after-load-fourth").then(function (text) {
61 | expect(text).to.equal("After Load Fourth");
62 | })
63 | .getText(".e2e-after-setup-fourth").then(function (text) {
64 | expect(text).to.equal("After Setup Fourth");
65 | });
66 | });
67 | });
68 |
--------------------------------------------------------------------------------