Commit 661b7ac5 authored by Romain Courteaud's avatar Romain Courteaud

Add more tests and make them pass on firefox.

parent 03e6d909
...@@ -2,4 +2,4 @@ handle relative url #parseGadgetHTML TODO ...@@ -2,4 +2,4 @@ handle relative url #parseGadgetHTML TODO
how to manage local script tag #parseGadgetHTML TODO how to manage local script tag #parseGadgetHTML TODO
check that gadget/dom context is kept in promise TODO check that gadget/dom context is kept in promise TODO
keep css file media query #declareCSS TODO keep css file media query #declareCSS TODO
handle double loading of renderjs js file TODO test selector TODO
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
(function (document, window, $, DOMParser) { (function (document, window, $, DOMParser) {
var gadget_model_dict = {}, var gadget_model_dict = {},
gadget_scope_dict = {},
javascript_registration_dict = {}, javascript_registration_dict = {},
stylesheet_registration_dict = {}, stylesheet_registration_dict = {},
gadget_loading_klass, gadget_loading_klass,
...@@ -97,59 +96,71 @@ ...@@ -97,59 +96,71 @@
RenderJSGadget.prototype.declareGadget = function (url, jquery_context) { RenderJSGadget.prototype.declareGadget = function (url, jquery_context) {
var loaded = false, var loaded = false,
previous_loading_gadget_promise = loading_gadget_promise, previous_loading_gadget_promise = loading_gadget_promise,
next_loading_gadget_deferred = $.Deferred(), next_loading_gadget_deferred = $.Deferred();
dfr = $.Deferred(),
dfr_promise = dfr.promise();
dfr_promise.done(function (created_gadget) {
created_gadget.context.html(created_gadget.constructor.prototype.html);
$.each(created_gadget.constructor.ready_list, function (i, callback) {
callback.apply(created_gadget);
});
});
// Change the global variable to update the loading queue
loading_gadget_promise = next_loading_gadget_deferred.promise(); loading_gadget_promise = next_loading_gadget_deferred.promise();
if (gadget_model_dict.hasOwnProperty(url)) {
loaded = true; // Wait for previous gadget loading to finish first
} previous_loading_gadget_promise.always(function () {
// Get the gadget class and instanciate it
renderJS.declareGadgetKlass(url).done(function (Klass) { renderJS.declareGadgetKlass(url).done(function (Klass) {
var gadget = new Klass(); var gadget = new Klass();
gadget.context = jquery_context; gadget.context = jquery_context;
if (loaded === false) {
// Load dependencies if needed
$.when(gadget.getRequiredJSList(), gadget.getRequiredCSSList()) $.when(gadget.getRequiredJSList(), gadget.getRequiredCSSList())
.done(function (js_list, css_list) { .done(function (js_list, css_list) {
previous_loading_gadget_promise.done(function () {
var result_list = []; var result_list = [];
gadget_loading_klass = Klass; gadget_loading_klass = Klass;
// Load all JS and CSS
$.each(js_list, function (i, required_url) { $.each(js_list, function (i, required_url) {
result_list.push(renderJS.declareJS(required_url)); result_list.push(renderJS.declareJS(required_url));
}); });
$.each(css_list, function (i, required_url) { $.each(css_list, function (i, required_url) {
result_list.push(renderJS.declareCSS(required_url)); result_list.push(renderJS.declareCSS(required_url));
}); });
$.when.apply(this, result_list).done(function () { $.when.apply(this, result_list)
dfr.resolve(gadget); .done(function () {
// Dependency correctly loaded. Fire instanciation success.
next_loading_gadget_deferred.resolve(gadget);
}).fail(function () { }).fail(function () {
dfr.reject(gadget); // One error during css/js loading
}); next_loading_gadget_deferred.reject();
}); });
}).fail(function () { }).fail(function () {
dfr.reject(gadget); // Failed to fetch dependencies information.
next_loading_gadget_deferred.reject();
}); });
} else {
dfr.resolve(gadget);
}
}).fail(function () { }).fail(function () {
dfr.reject(); // Klass not correctly loaded. Reject instanciation
next_loading_gadget_deferred.reject();
}); });
dfr_promise.then(function () { });
loading_gadget_promise
// Drop the current loading klass info used by selector
.done(function () {
gadget_loading_klass = undefined; gadget_loading_klass = undefined;
next_loading_gadget_deferred.resolve(); })
.fail(function () {
gadget_loading_klass = undefined;
})
.done(function (created_gadget) {
// Set the content html and call the ready list if instance is
// correctly loaded
if (created_gadget.context !== undefined) {
$(created_gadget.context).html(
created_gadget.constructor.prototype.html
);
}
$.each(created_gadget.constructor.ready_list, function (i, callback) {
callback.apply(created_gadget);
}); });
return dfr_promise; });
return loading_gadget_promise;
}; };
methods = { methods = {
...@@ -282,9 +293,10 @@ ...@@ -282,9 +293,10 @@
// headID.appendChild(newScript); // headID.appendChild(newScript);
// } // }
var dfr, var dfr,
origin_dfr; origin_dfr = $.Deferred(),
head_element,
script_element;
if (javascript_registration_dict.hasOwnProperty(url)) { if (javascript_registration_dict.hasOwnProperty(url)) {
origin_dfr = $.Deferred();
setTimeout(function () { setTimeout(function () {
origin_dfr.resolve(); origin_dfr.resolve();
}); });
...@@ -297,13 +309,18 @@ ...@@ -297,13 +309,18 @@
}).done(function (script, textStatus) { }).done(function (script, textStatus) {
javascript_registration_dict[url] = null; javascript_registration_dict[url] = null;
}); });
} }
return dfr; return dfr;
}; };
renderJS.declareCSS = function (url) { renderJS.declareCSS = function (url) {
// https://github.com/furf/jquery-getCSS/blob/master/jquery.getCSS.js // https://github.com/furf/jquery-getCSS/blob/master/jquery.getCSS.js
// No way to cleanly check if a css has been loaded
// So, always resolve the promise...
// http://requirejs.org/docs/faq-advanced.html#css
var origin_dfr = $.Deferred(), var origin_dfr = $.Deferred(),
origin_promise = origin_dfr.promise(),
head, head,
link; link;
if (stylesheet_registration_dict.hasOwnProperty(url)) { if (stylesheet_registration_dict.hasOwnProperty(url)) {
...@@ -318,7 +335,7 @@ ...@@ -318,7 +335,7 @@
link.type = 'text/css'; link.type = 'text/css';
link.href = url; link.href = url;
origin_dfr.done(function () { origin_promise.done(function () {
stylesheet_registration_dict[url] = null; stylesheet_registration_dict[url] = null;
}); });
...@@ -329,7 +346,7 @@ ...@@ -329,7 +346,7 @@
}); });
} }
return origin_dfr.promise(); return origin_promise;
}; };
renderJS.declareGadgetKlass = function (url) { renderJS.declareGadgetKlass = function (url) {
...@@ -386,6 +403,8 @@ ...@@ -386,6 +403,8 @@
// For test purpose only // For test purpose only
renderJS.clearGadgetKlassList = function () { renderJS.clearGadgetKlassList = function () {
gadget_model_dict = {}; gadget_model_dict = {};
javascript_registration_dict = {};
stylesheet_registration_dict = {};
}; };
renderJS.parseGadgetHTML = function (html) { renderJS.parseGadgetHTML = function (html) {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
<script src="../lib/jquery/jquery.js" type="text/javascript"></script> <script src="../lib/jquery/jquery.js" type="text/javascript"></script>
<script src="../lib/qunit/qunit.js" type="text/javascript"></script> <script src="../lib/qunit/qunit.js" type="text/javascript"></script>
<script src="../lib/sinon/sinon.js" type="text/javascript"></script> <script src="../lib/sinon/sinon.js" type="text/javascript"></script>
<script src="../sinon-qunit.js" type="text/javascript"></script>
<script src="../renderjs.js" type="text/javascript"></script> <script src="../renderjs.js" type="text/javascript"></script>
<script src="renderjs_test2.js" type="text/javascript"></script> <script src="renderjs_test2.js" type="text/javascript"></script>
</head> </head>
......
/*global window, document, QUnit, jQuery, renderJS, RenderJSGadget, sinon */ /*global window, document, QUnit, jQuery, renderJS, RenderJSGadget */
/*jslint indent: 2, maxerr: 3, maxlen: 79 */ /*jslint indent: 2, maxerr: 3, maxlen: 79 */
"use strict"; "use strict";
(function (document, $, renderJS, QUnit, sinon) { (function (document, $, renderJS, QUnit) {
var test = QUnit.test, var test = QUnit.test,
stop = QUnit.stop, stop = QUnit.stop,
start = QUnit.start, start = QUnit.start,
...@@ -15,12 +15,20 @@ ...@@ -15,12 +15,20 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// parseGadgetHTML // parseGadgetHTML
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
module("renderJS.parseGadgetHTML"); module("renderJS.parseGadgetHTML", {
setup: function () {
renderJS.clearGadgetKlassList();
}
});
test('Not valid HTML string', function () { test('Not valid HTML string', function () {
// Check that parseGadgetHTML throws an error if the string is // Check that parseGadgetHTML returns the default value if the string is
// not a valid xml // not a valid xml
throws(function () { deepEqual(renderJS.parseGadgetHTML(""), {
renderJS.parseGadgetHTML("<ht"); title: "",
interface_list: [],
required_css_list: [],
required_js_list: [],
html: "",
}); });
}); });
...@@ -92,8 +100,8 @@ ...@@ -92,8 +100,8 @@
equal(settings.html, "<p>Foo</p>", "HTML extracted"); equal(settings.html, "<p>Foo</p>", "HTML extracted");
}); });
test('Extract only one body', function () { test('Extract all body', function () {
// Check that parseGadgetHTML correctly extract the first title // Check that parseGadgetHTML correctly extracts all bodies
var settings, var settings,
html = "<html>" + html = "<html>" +
"<body>" + "<body>" +
...@@ -103,18 +111,18 @@ ...@@ -103,18 +111,18 @@
"</body></html>"; "</body></html>";
settings = renderJS.parseGadgetHTML(html); settings = renderJS.parseGadgetHTML(html);
equal(settings.html, '<p>Foo</p>', 'First body extracted'); equal(settings.html, '<p>Foo</p><p>Bar</p>', 'All bodies extracted');
}); });
test('Extract body only from html', function () { test('Extract body only from html', function () {
// Check that parseGadgetHTML only extract title from html // Check that parseGadgetHTML also extract body from head
var settings, var settings,
html = "<html>" + html = "<html>" +
"<head><body><p>Bar</p></body></head>" + "<head><body><p>Bar</p></body></head>" +
"</html>"; "</html>";
settings = renderJS.parseGadgetHTML(html); settings = renderJS.parseGadgetHTML(html);
equal(settings.html, "", "Body not found"); equal(settings.html, "<p>Bar</p>", "Body not found");
}); });
test('Extract CSS', function () { test('Extract CSS', function () {
...@@ -270,15 +278,15 @@ ...@@ -270,15 +278,15 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// declareGadgetKlass // declareGadgetKlass
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
module("renderJS.declareGadgetKlass"); module("renderJS.declareGadgetKlass", {
setup: function () {
renderJS.clearGadgetKlassList();
}
});
test('Ajax error reject the promise', function () { test('Ajax error reject the promise', function () {
// Check that declareGadgetKlass fails if ajax fails // Check that declareGadgetKlass fails if ajax fails
renderJS.clearGadgetKlassList(); var server = this.sandbox.useFakeServer(),
var server = sinon.fakeServer.create(),
url = 'https://example.org/files/qunittest/test'; url = 'https://example.org/files/qunittest/test';
server.autoRespond = true;
server.autoRespondAfter = 1;
server.respondWith("GET", url, [404, { server.respondWith("GET", url, [404, {
"Content-Type": "text/html", "Content-Type": "text/html",
...@@ -295,16 +303,13 @@ ...@@ -295,16 +303,13 @@
.always(function () { .always(function () {
start(); start();
}); });
server.respond();
}); });
test('Non HTML reject the promise', function () { test('Non HTML reject the promise', function () {
// Check that declareGadgetKlass fails if non html is retrieved // Check that declareGadgetKlass fails if non html is retrieved
renderJS.clearGadgetKlassList(); var server = this.sandbox.useFakeServer(),
var server = sinon.fakeServer.create(),
url = 'https://example.org/files/qunittest/test'; url = 'https://example.org/files/qunittest/test';
server.autoRespond = true;
server.autoRespondAfter = 1;
server.respondWith("GET", url, [200, { server.respondWith("GET", url, [200, {
"Content-Type": "text/plain", "Content-Type": "text/plain",
...@@ -321,23 +326,20 @@ ...@@ -321,23 +326,20 @@
.always(function () { .always(function () {
start(); start();
}); });
server.respond();
}); });
test('HTML parsing failure reject the promise', function () { test('HTML parsing failure reject the promise', function () {
// Check that declareGadgetKlass fails if the html can not be parsed // Check that declareGadgetKlass fails if the html can not be parsed
renderJS.clearGadgetKlassList(); var server = this.sandbox.useFakeServer(),
var server = sinon.fakeServer.create(),
url = 'https://example.org/files/qunittest/test', url = 'https://example.org/files/qunittest/test',
mock; mock;
server.autoRespond = true;
server.autoRespondAfter = 1;
server.respondWith("GET", url, [200, { server.respondWith("GET", url, [200, {
"Content-Type": "text/html", "Content-Type": "text/html",
}, ""]); }, ""]);
mock = sinon.mock(renderJS, "parseGadgetHTML", function () { mock = this.mock(renderJS, "parseGadgetHTML", function () {
throw new Error(); throw new Error();
}); });
mock.expects("parseGadgetHTML").once().throws(); mock.expects("parseGadgetHTML").once().throws();
...@@ -353,26 +355,22 @@ ...@@ -353,26 +355,22 @@
.always(function () { .always(function () {
mock.verify(); mock.verify();
start(); start();
mock.restore();
}); });
server.respond();
}); });
test('Klass creation', function () { test('Klass creation', function () {
// Check that declareGadgetKlass returns a subclass of RenderJSGadget // Check that declareGadgetKlass returns a subclass of RenderJSGadget
// and contains all extracted properties on the prototype // and contains all extracted properties on the prototype
renderJS.clearGadgetKlassList(); var server = this.sandbox.useFakeServer(),
var server = sinon.fakeServer.create(),
url = 'https://example.org/files/qunittest/test', url = 'https://example.org/files/qunittest/test',
mock; mock;
server.autoRespond = true;
server.autoRespondAfter = 1;
server.respondWith("GET", url, [200, { server.respondWith("GET", url, [200, {
"Content-Type": "text/html", "Content-Type": "text/html",
}, "foo"]); }, "foo"]);
mock = sinon.mock(renderJS, "parseGadgetHTML"); mock = this.mock(renderJS, "parseGadgetHTML");
mock.expects("parseGadgetHTML").once().withArgs("foo").returns( mock.expects("parseGadgetHTML").once().withArgs("foo").returns(
{foo: 'bar'} {foo: 'bar'}
); );
...@@ -396,26 +394,22 @@ ...@@ -396,26 +394,22 @@
.always(function () { .always(function () {
mock.verify(); mock.verify();
start(); start();
mock.restore();
}); });
server.respond();
}); });
test('Klass is not reloaded if called twice', function () { test('Klass is not reloaded if called twice', function () {
// Check that declareGadgetKlass does not reload the gadget // Check that declareGadgetKlass does not reload the gadget
// if it has already been loaded // if it has already been loaded
renderJS.clearGadgetKlassList(); var server = this.sandbox.useFakeServer(),
var server = sinon.fakeServer.create(),
url = 'https://example.org/files/qunittest/test', url = 'https://example.org/files/qunittest/test',
mock; mock;
server.autoRespond = true;
server.autoRespondAfter = 1;
server.respondWith("GET", url, [200, { server.respondWith("GET", url, [200, {
"Content-Type": "text/html", "Content-Type": "text/html",
}, "foo"]); }, "foo"]);
mock = sinon.mock(renderJS, "parseGadgetHTML"); mock = this.mock(renderJS, "parseGadgetHTML");
mock.expects("parseGadgetHTML").once().withArgs("foo").returns( mock.expects("parseGadgetHTML").once().withArgs("foo").returns(
{foo: 'bar'} {foo: 'bar'}
); );
...@@ -423,24 +417,16 @@ ...@@ -423,24 +417,16 @@
stop(); stop();
renderJS.declareGadgetKlass(url) renderJS.declareGadgetKlass(url)
.done(function (Klass1) { .done(function (Klass1) {
var spy;
mock.restore();
server.restore();
spy = sinon.spy($, "ajax");
renderJS.declareGadgetKlass(url) renderJS.declareGadgetKlass(url)
.done(function (Klass2) { .done(function (Klass2) {
equal(Klass1, Klass2); equal(Klass1, Klass2);
ok(!spy.called);
}) })
.fail(function (jqXHR, textStatus) { .fail(function (jqXHR, textStatus) {
ok(false, "Failed to load " + textStatus + " " + jqXHR.status); ok(false, "Failed to load " + textStatus + " " + jqXHR.status);
}) })
.always(function () { .always(function () {
start(); start();
spy.restore(); mock.verify();
}); });
}) })
...@@ -448,19 +434,41 @@ ...@@ -448,19 +434,41 @@
ok(false, "Failed to load " + textStatus + " " + jqXHR.status); ok(false, "Failed to load " + textStatus + " " + jqXHR.status);
start(); start();
}); });
server.respond();
}); });
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// declareJS // declareJS
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
module("renderJS.declareJS"); module("renderJS.declareJS", {
test('Ajax error reject the promise', function () { setup: function () {
// Check that declareJS fails if ajax fails
renderJS.clearGadgetKlassList(); renderJS.clearGadgetKlassList();
}
});
test('Download error reject the promise', function () {
// Check that declareJS fails if ajax fails
var url = 'foo://bar';
stop();
renderJS.declareJS(url)
.done(function () {
ok(false, "404 should fail");
})
.fail(function (jqXHR, textStatus) {
equal("404", jqXHR.status);
})
.always(function () {
start();
});
});
test('Ajax error reject the promise twice', function () {
// Check that failed declareJS is not cached
var url = 'foo://bar'; var url = 'foo://bar';
stop(); stop();
renderJS.declareJS(url)
.always(function () {
renderJS.declareJS(url) renderJS.declareJS(url)
.done(function () { .done(function () {
ok(false, "404 should fail"); ok(false, "404 should fail");
...@@ -472,31 +480,31 @@ ...@@ -472,31 +480,31 @@
start(); start();
}); });
}); });
});
test('Non JS reject the promise', function () { test('Non JS reject the promise', function () {
// Check that declareJS fails if mime type is wrong // Check that declareJS fails if mime type is wrong
renderJS.clearGadgetKlassList();
var url = "data:image/png;base64," + var url = "data:image/png;base64," +
window.btoa("= = ="); window.btoa("= = ="),
previousonerror = window.onerror;
stop(); stop();
window.onerror = undefined;
renderJS.declareJS(url) renderJS.declareJS(url)
.done(function (value, textStatus, jqXHR) { .done(function (value, textStatus, jqXHR) {
ok(true, "Non JS mime type should load"); ok(ok, "Non JS mime type should load");
}) })
.fail(function (jqXHR, textStatus) { .fail(function (jqXHR, textStatus) {
ok(false, "Failed to load " + textStatus + " " + jqXHR.status); ok(false, "Failed to load " + textStatus + " " + jqXHR.status);
}) })
.always(function () { .always(function () {
window.onerror = previousonerror;
start(); start();
}); });
}); });
test('JS cleanly loaded', function () { test('JS cleanly loaded', function () {
// Check that declareJS is fetched and loaded // Check that declareJS is fetched and loaded
renderJS.clearGadgetKlassList();
var url = "data:application/javascript;base64," + var url = "data:application/javascript;base64," +
window.btoa("$('#qunit-fixture').text('JS fetched and loaded');"); window.btoa("$('#qunit-fixture').text('JS fetched and loaded');");
...@@ -515,28 +523,27 @@ ...@@ -515,28 +523,27 @@
test('JS with errors cleanly loaded', function () { test('JS with errors cleanly loaded', function () {
// Check that declareJS is fetched and loaded even if JS contains an error // Check that declareJS is fetched and loaded even if JS contains an error
renderJS.clearGadgetKlassList();
var url = "data:application/javascript;base64," + var url = "data:application/javascript;base64," +
window.btoa("throw new Error('foo');"); window.btoa("= var var var a a a"),
previousonerror = window.onerror;
stop(); stop();
window.onerror = undefined;
renderJS.declareJS(url) renderJS.declareJS(url)
.done(function () { .done(function (aaa) {
ok(true, "JS with error cleanly loaded"); ok(true, "JS with error cleanly loaded");
}) })
.fail(function (jqXHR, textStatus) { .fail(function (jqXHR, textStatus) {
ok(false, "Failed to load " + textStatus + " " + jqXHR.status); ok(false, "Failed to load " + textStatus + " " + jqXHR.status);
}) })
.always(function () { .always(function () {
window.onerror = previousonerror;
start(); start();
}); });
}); });
test('JS is not fetched twice', function () { test('JS is not fetched twice', function () {
// Check that declareJS does not load the JS twice // Check that declareJS does not load the JS twice
renderJS.clearGadgetKlassList();
var url = "data:application/javascript;base64," + var url = "data:application/javascript;base64," +
window.btoa("$('#qunit-fixture').text('JS not fetched twice');"); window.btoa("$('#qunit-fixture').text('JS not fetched twice');");
...@@ -565,30 +572,32 @@ ...@@ -565,30 +572,32 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// declareCSS // declareCSS
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
module("renderJS.declareCSS"); module("renderJS.declareCSS", {
test('Ajax error reject the promise', function () { setup: function () {
// Check that declareCSS fails if ajax fails
renderJS.clearGadgetKlassList(); renderJS.clearGadgetKlassList();
}
});
test('Ajax error resolve the promise', function () {
// Check that declareCSS is resolved if ajax fails
var url = 'foo://bar'; var url = 'foo://bar';
expect(1);
stop(); stop();
renderJS.declareCSS(url) renderJS.declareCSS(url)
.done(function () { .done(function () {
ok(false, "404 should fail"); ok(true, "404 should fail");
}) })
.fail(function (jqXHR, textStatus) { .fail(function (jqXHR, textStatus) {
equal("404", jqXHR.status); ok(false);
}) })
.always(function () { .always(function () {
start(); start();
}); });
}); });
test('Non CSS reject the promise', function () { test('Non CSS resolve the promise', function () {
// Check that declareCSS fails if mime type is wrong // Check that declareCSS is resolved if mime type is wrong
renderJS.clearGadgetKlassList();
var url = "data:image/png;base64," + var url = "data:image/png;base64," +
window.btoa("= = ="); window.btoa("= = =");
...@@ -598,7 +607,7 @@ ...@@ -598,7 +607,7 @@
ok(true, "Non CSS mime type should load"); ok(true, "Non CSS mime type should load");
}) })
.fail(function (jqXHR, textStatus) { .fail(function (jqXHR, textStatus) {
ok(false, "Failed to load " + textStatus + " " + jqXHR.status); ok(false);
}) })
.always(function () { .always(function () {
start(); start();
...@@ -607,8 +616,6 @@ ...@@ -607,8 +616,6 @@
test('CSS cleanly loaded', function () { test('CSS cleanly loaded', function () {
// Check that declareCSS is fetched and loaded // Check that declareCSS is fetched and loaded
renderJS.clearGadgetKlassList();
var url = "data:text/css;base64," + var url = "data:text/css;base64," +
window.btoa("#qunit-fixture {background-color: red;}"); window.btoa("#qunit-fixture {background-color: red;}");
...@@ -635,8 +642,6 @@ ...@@ -635,8 +642,6 @@
test('CSS with errors cleanly loaded', function () { test('CSS with errors cleanly loaded', function () {
// Check that declareCSS is fetched and // Check that declareCSS is fetched and
// loaded even if CSS contains an error // loaded even if CSS contains an error
renderJS.clearGadgetKlassList();
var url = "data:application/javascript;base64," + var url = "data:application/javascript;base64," +
window.btoa("throw new Error('foo');"); window.btoa("throw new Error('foo');");
...@@ -655,8 +660,6 @@ ...@@ -655,8 +660,6 @@
test('CSS is not fetched twice', function () { test('CSS is not fetched twice', function () {
// Check that declareCSS does not load the CSS twice // Check that declareCSS does not load the CSS twice
renderJS.clearGadgetKlassList();
var url = "data:text/css;base64," + var url = "data:text/css;base64," +
window.btoa("#qunit-fixture {background-color: blue;}"); window.btoa("#qunit-fixture {background-color: blue;}");
...@@ -699,24 +702,25 @@ ...@@ -699,24 +702,25 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// clearGadgetKlassList // clearGadgetKlassList
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
module("renderJS.clearGadgetKlassList"); module("renderJS.clearGadgetKlassList", {
setup: function () {
renderJS.clearGadgetKlassList();
}
});
test('clearGadgetKlassList leads to gadget reload', function () { test('clearGadgetKlassList leads to gadget reload', function () {
// Check that declareGadgetKlass reload the gadget // Check that declareGadgetKlass reload the gadget
// after clearGadgetKlassList is called // after clearGadgetKlassList is called
renderJS.clearGadgetKlassList(); var server = this.sandbox.useFakeServer(),
var server = sinon.fakeServer.create(),
url = 'https://example.org/files/qunittest/test', url = 'https://example.org/files/qunittest/test',
mock; mock;
server.autoRespond = true;
server.autoRespondAfter = 1;
server.respondWith("GET", url, [200, { server.respondWith("GET", url, [200, {
"Content-Type": "text/html", "Content-Type": "text/html",
}, "foo"]); }, "foo"]);
mock = sinon.mock(renderJS, "parseGadgetHTML"); mock = this.mock(renderJS, "parseGadgetHTML");
mock.expects("parseGadgetHTML").once().withArgs("foo").returns( mock.expects("parseGadgetHTML").twice().withArgs("foo").returns(
{foo: 'bar'} {foo: 'bar'}
); );
...@@ -724,12 +728,7 @@ ...@@ -724,12 +728,7 @@
renderJS.declareGadgetKlass(url) renderJS.declareGadgetKlass(url)
.done(function (Klass1) { .done(function (Klass1) {
mock.restore();
renderJS.clearGadgetKlassList(); renderJS.clearGadgetKlassList();
mock = sinon.mock(renderJS, "parseGadgetHTML");
mock.expects("parseGadgetHTML").once().withArgs("foo").returns(
{foo: 'bar'}
);
renderJS.declareGadgetKlass(url) renderJS.declareGadgetKlass(url)
.done(function (Klass2) { .done(function (Klass2) {
...@@ -741,7 +740,6 @@ ...@@ -741,7 +740,6 @@
}) })
.always(function () { .always(function () {
start(); start();
server.restore();
}); });
}) })
...@@ -749,12 +747,52 @@ ...@@ -749,12 +747,52 @@
ok(false, "Failed to load " + textStatus + " " + jqXHR.status); ok(false, "Failed to load " + textStatus + " " + jqXHR.status);
start(); start();
}); });
server.respond();
}); });
test('clearGadgetKlassList leads to JS reload', function () {
// Check that declareJS reload the JS
// after clearGadgetKlassList is called
var url = "data:application/javascript;base64," +
window.btoa("$('#qunit-fixture').text('JS not fetched twice');");
stop();
renderJS.declareJS(url)
.done(function () {
renderJS.clearGadgetKlassList();
equal($("#qunit-fixture").text(), "JS not fetched twice");
$("#qunit-fixture").text("");
renderJS.declareJS(url)
.done(function () {
equal($("#qunit-fixture").text(), "JS not fetched twice");
})
.fail(function (jqXHR, textStatus) {
ok(false, "Failed to load " + textStatus + " " + jqXHR.status);
})
.always(function () {
start();
});
})
.fail(function (jqXHR, textStatus) {
ok(false, "Failed to load " + textStatus + " " + jqXHR.status);
start();
});
});
// test('clearGadgetKlassList leads to CSS reload', function () {
// // Check that declareCSS reload the CSS
// // after clearGadgetKlassList is called
// ok(false, "not implemented");
// });
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSGadget.getInterfaceList // RenderJSGadget.getInterfaceList
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
module("RenderJSGadget.getInterfaceList"); module("RenderJSGadget.getInterfaceList", {
setup: function () {
renderJS.clearGadgetKlassList();
}
});
test('returns interface_list', function () { test('returns interface_list', function () {
// Check that getInterfaceList return a Promise // Check that getInterfaceList return a Promise
var gadget = new RenderJSGadget(); var gadget = new RenderJSGadget();
...@@ -785,7 +823,11 @@ ...@@ -785,7 +823,11 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSGadget.getRequiredCSSList // RenderJSGadget.getRequiredCSSList
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
module("RenderJSGadget.getRequiredCSSList"); module("RenderJSGadget.getRequiredCSSList", {
setup: function () {
renderJS.clearGadgetKlassList();
}
});
test('returns interface_list', function () { test('returns interface_list', function () {
// Check that getRequiredCSSList return a Promise // Check that getRequiredCSSList return a Promise
var gadget = new RenderJSGadget(); var gadget = new RenderJSGadget();
...@@ -816,7 +858,11 @@ ...@@ -816,7 +858,11 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSGadget.getRequiredJSList // RenderJSGadget.getRequiredJSList
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
module("RenderJSGadget.getRequiredJSList"); module("RenderJSGadget.getRequiredJSList", {
setup: function () {
renderJS.clearGadgetKlassList();
}
});
test('returns interface_list', function () { test('returns interface_list', function () {
// Check that getRequiredJSList return a Promise // Check that getRequiredJSList return a Promise
var gadget = new RenderJSGadget(); var gadget = new RenderJSGadget();
...@@ -847,7 +893,11 @@ ...@@ -847,7 +893,11 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSGadget.getPath // RenderJSGadget.getPath
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
module("RenderJSGadget.getPath"); module("RenderJSGadget.getPath", {
setup: function () {
renderJS.clearGadgetKlassList();
}
});
test('returns path', function () { test('returns path', function () {
// Check that getPath return a Promise // Check that getPath return a Promise
var gadget = new RenderJSGadget(); var gadget = new RenderJSGadget();
...@@ -878,7 +928,11 @@ ...@@ -878,7 +928,11 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSGadget.getTitle // RenderJSGadget.getTitle
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
module("RenderJSGadget.getTitle"); module("RenderJSGadget.getTitle", {
setup: function () {
renderJS.clearGadgetKlassList();
}
});
test('returns title', function () { test('returns title', function () {
// Check that getTitle return a Promise // Check that getTitle return a Promise
var gadget = new RenderJSGadget(); var gadget = new RenderJSGadget();
...@@ -909,7 +963,11 @@ ...@@ -909,7 +963,11 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSGadget.getHTML // RenderJSGadget.getHTML
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
module("RenderJSGadget.getHTML"); module("RenderJSGadget.getHTML", {
setup: function () {
renderJS.clearGadgetKlassList();
}
});
test('returns html', function () { test('returns html', function () {
// Check that getHTML return a Promise // Check that getHTML return a Promise
var gadget = new RenderJSGadget(); var gadget = new RenderJSGadget();
...@@ -940,7 +998,11 @@ ...@@ -940,7 +998,11 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSGadgetKlass.declareMethod // RenderJSGadgetKlass.declareMethod
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
module("RenderJSGadgetKlass.declareMethod"); module("RenderJSGadgetKlass.declareMethod", {
setup: function () {
renderJS.clearGadgetKlassList();
}
});
test('is chainable', function () { test('is chainable', function () {
// Check that declareMethod is chainable // Check that declareMethod is chainable
...@@ -1056,7 +1118,11 @@ ...@@ -1056,7 +1118,11 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSGadgetKlass.ready // RenderJSGadgetKlass.ready
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
module("RenderJSGadgetKlass.ready"); module("RenderJSGadgetKlass.ready", {
setup: function () {
renderJS.clearGadgetKlassList();
}
});
test('is chainable', function () { test('is chainable', function () {
// Check that ready is chainable // Check that ready is chainable
...@@ -1096,4 +1162,272 @@ ...@@ -1096,4 +1162,272 @@
deepEqual(Klass.ready_list, [callback]); deepEqual(Klass.ready_list, [callback]);
}); });
}(document, jQuery, renderJS, QUnit, sinon)); /////////////////////////////////////////////////////////////////
// RenderJSGadget.declareGadget
/////////////////////////////////////////////////////////////////
module("RenderJSGadget.declareGadget", {
setup: function () {
renderJS.clearGadgetKlassList();
}
});
test('returns a Promise', function () {
// Check that declareGadget return a Promise
var gadget = new RenderJSGadget(),
server = this.sandbox.useFakeServer(),
url = 'https://example.org/files/qunittest/test',
html = "<html>" +
"<body>" +
"<script src='../lib/qunit/qunit.js' " +
"type='text/javascript'></script>" +
"</body></html>";
server.respondWith("GET", url, [200, {
"Content-Type": "text/html",
}, html]);
stop();
gadget.declareGadget(url, $('#qunit-fixture'))
.always(function () {
ok(true);
start();
});
server.respond();
});
test('provide a gadget instance as callback parameter', function () {
// Check that declare gadget returns the gadget
var gadget = new RenderJSGadget(),
server = this.sandbox.useFakeServer(),
url = 'https://example.org/files/qunittest/test',
html = "<html>" +
"<body>" +
"<script src='../lib/qunit/qunit.js' " +
"type='text/javascript'></script>" +
"</body></html>";
server.respondWith("GET", url, [200, {
"Content-Type": "text/html",
}, html]);
stop();
gadget.declareGadget(url, $('#qunit-fixture'))
.done(function (new_gadget) {
equal(new_gadget.path, url);
})
.always(function () {
start();
});
server.respond();
});
// test('no parameter', function () {
// // Check that missing url reject the declaration
// var gadget = new RenderJSGadget();
// stop();
// gadget.declareGadget()
// .fail(function () {
// ok(true);
// })
// .always(function () {
// start();
// });
// });
test('load dependency before returning gadget', function () {
// Check that dependencies are loaded before gadget creation
var gadget = new RenderJSGadget(),
server = this.sandbox.useFakeServer(),
html_url = 'https://example.org/files/qunittest/test2.html',
js1_url = "data:application/javascript;base64," +
window.btoa(
"$('#qunit-fixture').find('div').first().text('youhou');"
),
js2_url = js1_url,
css1_url = "data:text/plain;base64," +
window.btoa(""),
css2_url = css1_url,
html = "<html>" +
"<head>" +
"<title>Foo title</title>" +
"<script src='" + js1_url + "' type='text/javascript'></script>" +
"<script src='" + js2_url + "' type='text/javascript'></script>" +
"<link rel='stylesheet' href='" + css1_url + "' type='text/css'/>" +
"<link rel='stylesheet' href='" + css2_url + "' type='text/css'/>" +
"</head><body><p>Bar content</p></body></html>",
mock,
spy_js,
spy_css;
server.respondWith("GET", html_url, [200, {
"Content-Type": "text/html",
}, html]);
spy_js = this.spy(renderJS, "declareJS");
spy_css = this.spy(renderJS, "declareCSS");
mock = this.mock(renderJS, "parseGadgetHTML");
mock.expects("parseGadgetHTML").once().withArgs(html).returns({
required_js_list: [js1_url, js2_url],
required_css_list: [css1_url, css2_url],
html: "<p>Bar content</p>",
});
$('#qunit-fixture').html("<div></div><div></div>");
stop();
gadget.declareGadget(html_url, $('#qunit-fixture').find("div").last())
.done(function (new_gadget) {
equal($('#qunit-fixture').html(),
"<div>youhou</div><div><p>Bar content</p></div>");
ok(spy_js.calledTwice, "JS count " + spy_js.callCount);
equal(spy_js.firstCall.args[0], js1_url, "First JS call");
equal(spy_js.secondCall.args[0], js2_url, "Second JS call");
ok(spy_css.calledTwice, "CSS count " + spy_css.callCount);
equal(spy_css.firstCall.args[0], css1_url, "First CSS call");
equal(spy_css.secondCall.args[0], css2_url, "Second CSS call");
})
.fail(function () {
ok(false);
})
.always(function () {
start();
});
server.respond();
});
test('Fail if klass can not be loaded', function () {
// Check that gadget is not created if klass is can not be loaded
var gadget = new RenderJSGadget(),
server = this.sandbox.useFakeServer(),
html_url = 'https://example.org/files/qunittest/test3.html';
server.respondWith("GET", html_url, [404, {
"Content-Type": "text/html",
}, ""]);
stop();
gadget.declareGadget(html_url, $('#qunit-fixture').find("div").last())
.done(function (new_gadget) {
ok(false);
})
.fail(function () {
ok(true);
})
.always(function () {
start();
});
server.respond();
});
test('Fail if js can not be loaded', function () {
// Check that dependencies are loaded before gadget creation
var gadget = new RenderJSGadget(),
server = this.sandbox.useFakeServer(),
html_url = 'https://example.org/files/qunittest/test2.html',
js1_url = 'foo://bar2',
mock;
server.respondWith("GET", html_url, [200, {
"Content-Type": "text/html",
}, "raw html"]);
mock = this.mock(renderJS, "parseGadgetHTML");
mock.expects("parseGadgetHTML").once().withArgs("raw html").returns({
required_js_list: [js1_url]
});
stop();
gadget.declareGadget(html_url, $('#qunit-fixture'))
.done(function (new_gadget) {
ok(false);
})
.fail(function () {
ok(true);
})
.always(function () {
start();
});
server.respond();
});
test('Do not load gadget dependency twice', function () {
// Check that dependencies are not reloaded if 2 gadgets are created
var gadget = new RenderJSGadget(),
server = this.sandbox.useFakeServer(),
html_url = 'https://example.org/files/qunittest/test2.html',
js1_url = "data:application/javascript;base64," +
window.btoa(
"$('#qunit-fixture').find('div').first().append('youhou');"
),
mock,
spy;
server.respondWith("GET", html_url, [200, {
"Content-Type": "text/html",
}, "raw html"]);
spy = this.spy($, "ajax");
mock = this.mock(renderJS, "parseGadgetHTML");
mock.expects("parseGadgetHTML").once().withArgs("raw html").returns({
required_js_list: [js1_url]
});
stop();
$('#qunit-fixture').html("<div></div><div></div>");
gadget.declareGadget(html_url, $('#qunit-fixture').find("div").last())
.always(function () {
equal($('#qunit-fixture').html(),
"<div>youhou</div><div></div>");
gadget.declareGadget(html_url, $('#qunit-fixture').find("div").last())
.done(function (new_gadget) {
equal($('#qunit-fixture').html(),
"<div>youhou</div><div></div>");
ok(spy.calledTwice, "Ajax count " + spy.callCount);
equal(spy.firstCall.args[0], html_url, "First ajax call");
deepEqual(spy.secondCall.args[0], {
"cache": true,
"dataType": "script",
"url": js1_url,
}, "Second ajax call");
})
.fail(function () {
ok(false);
})
.always(function () {
start();
});
});
server.respond();
});
test('Load 2 concurrent gadgets in parallel', function () {
// Check that dependencies are loaded once if 2 gadgets are created
var gadget = new RenderJSGadget(),
server = this.sandbox.useFakeServer(),
html_url = 'https://example.org/files/qunittest/test2.html',
mock,
spy;
server.respondWith("GET", html_url, [200, {
"Content-Type": "text/html",
}, "raw html"]);
spy = this.spy($, "ajax");
mock = this.mock(renderJS, "parseGadgetHTML");
mock.expects("parseGadgetHTML").once().withArgs("raw html").returns({});
stop();
$.when(
gadget.declareGadget(html_url, $('#qunit-fixture')),
gadget.declareGadget(html_url, $('#qunit-fixture'))
).always(function () {
// Check that only one request has been done.
ok(spy.calledOnce, "Ajax count " + spy.callCount);
equal(spy.firstCall.args[0], html_url, "First ajax call");
start();
});
server.respond();
});
}(document, jQuery, renderJS, QUnit));
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment