UNPKG

26.3 kBJavaScriptView Raw
1/* jslint node: true */
2/* global describe, it, expect */
3
4"use strict";
5
6var testUtil = require("./test-util");
7
8describe("index.js", function () {
9
10 it("- test import/require and export timeout", function (done) {
11 testUtil.onJenkinsPage(function() {
12 var jenkins = require("../js/index");
13
14 try {
15 jenkins.require('pluginA:mathUtils');
16 } catch (e) {
17 expect(e).toBe("Unable to perform synchronous 'require' for module 'pluginA:mathUtils'. This module is not pre-loaded. The module needs to have been asynchronously pre-loaded via an outer call to 'import'.");
18 }
19
20 // should fail because a export never happens
21 jenkins.setRegisterTimeout(100);
22 jenkins.import('pluginA:mathUtils')
23 .onRejected(function(error) {
24 expect(error.reason).toBe('timeout');
25 expect(error.detail).toBe("Timed out waiting on module 'pluginA:mathUtils' to load.");
26 done();
27 });
28 });
29 });
30
31 it("- test import/require and export async successful", function (done) {
32 testUtil.onJenkinsPage(function() {
33 var jenkins = require("../js/index");
34
35 // Require before the module is registered.
36 // The require should "trigger" the loading of the module from the plugin.
37 // Should pass because export will happen before the timeout
38 jenkins.import('pluginA:mathUtils', 2000).onFulfilled(function(module) {
39 expect(module.add(2,2)).toBe(4);
40 done();
41 }); // timeout before Jasmine does
42
43 // Try requiring the module again immediately. Should be ignored i.e. a second
44 // <script> element should NOT be added to the dom. See the test at the end
45 // of this method.
46 jenkins.import('pluginA:mathUtils', 1000).onFulfilled(function(module) {
47 });
48
49 // Check that the <script> element was added to the <head>
50 var internal = require("../js/internal");
51 var document = require('window-handle').getWindow().document;
52 var moduleId = internal.toModuleId('pluginA', 'mathUtils') + ':js';
53
54 var scriptEl = document.getElementById(moduleId);
55
56 expect(scriptEl).toBeDefined();
57 expect(scriptEl.getAttribute('src')).toBe('/jenkins/adjuncts/xxx/org/jenkins/ui/jsmodules/pluginA/mathUtils.js');
58
59 // Now mimic registering of the plugin module. In real Jenkins land, this would happen
60 // async. The call to "require" would trigger the plugin js to be loaded
61 // via adding of a <script> element to the page DOM. That plugin module
62 // is then responsible for calling 'export', which should trigger
63 // the notify etc
64 jenkins.export('pluginA', 'mathUtils', {
65 add: function(lhs, rhs) {
66 return lhs + rhs;
67 }
68 });
69
70 // Verify that only one <script> element was added to the dom. Remove the one we found and
71 // attempt to find another with the same id - we should fail.
72 internal.getHeadElement().removeChild(scriptEl);
73 scriptEl = document.getElementById(moduleId);
74 expect(scriptEl).toBe(null);
75
76 // Make sure we can synchronously get the module.
77 var mathUtils = jenkins.require('pluginA:mathUtils');
78 expect(mathUtils).toBeDefined();
79 });
80 });
81
82 it("- test import and export sync successful", function (done) {
83 testUtil.onJenkinsPage(function() {
84 var jenkins = require("../js/index");
85
86 // Register the module before calling require. See above test too.
87 jenkins.export('pluginA', 'mathUtils', {
88 add: function(lhs, rhs) {
89 return lhs + rhs;
90 }
91 });
92
93 // Should pass immediately because export has already happened.
94 jenkins.import('pluginA:mathUtils', 0).onFulfilled(function(module) {
95 expect(module.add(2,2)).toBe(4);
96 done();
97 }); // disable async load mode
98
99 });
100 });
101
102 it("- test import and export async successful", function (done) {
103 testUtil.onJenkinsPage(function() {
104 var jenkins = require("../js/index");
105 var internal = require("../js/internal");
106
107 // Require before the modules are registered.
108 // The require should "trigger" the loading of the module from the plugin.
109 // Should pass because export will happen before the timeout
110 jenkins.setRegisterTimeout(2000);
111 jenkins.import('pluginA:mathUtils', 'pluginB:timeUtils')
112 .onFulfilled(function(mathUtils, timeUtils) {
113 // This function should only be called once both modules have been exported
114 expect(mathUtils.add(2,2)).toBe(4);
115 expect(timeUtils.now().getTime()).toBe(1000000000000);
116
117 // The mathUtils module should be in the 'global' namespace
118 var moduleNamespace = internal.getModuleNamespaceObj({namespace: 'pluginA', moduleName: 'mathUtils'});
119 expect(moduleNamespace.globalNS).toBe(false);
120
121 // Check the namespace provider from which the plugins were loaded.
122 // Should default to the 'plugin' namespace provider i.e. load from
123 // a plugin namespace.
124 var mathUtils = internal.getModuleSpec('pluginA:mathUtils');
125 expect(mathUtils.nsProvider).toBe('adjuncts');
126
127 done();
128 }); // timeout before Jasmine does
129
130 // Now mimic registering of the plugin modules.
131 jenkins.export('pluginA', 'mathUtils', {
132 add: function(lhs, rhs) {
133 return lhs + rhs;
134 }
135 });
136 jenkins.export('pluginB', 'timeUtils', {
137 now: function() {
138 return new Date(1000000000000);
139 }
140 });
141 });
142 });
143
144 it("- test import from parent namespace provider", function (done) {
145 testUtil.onJenkinsPage(function() {
146 var jenkins = require("../js/index");
147 var internal = require("../js/internal");
148 var document = require('window-handle').getWindow().document;
149 var head = internal.getHeadElement();
150 var script = document.createElement('script');
151
152 // Let's mimic the loading of a bundle like 'bootstrap3' from the 'bootstrap' namespace, which
153 // has a dependency on 'jquery3' from the 'jquery' namespace. We manually add the bootstrap
154 // <script> tags for the test, pretending that 'core-assets' is the namespace provider for the
155 // 'bootstrap' namespace. This should then result in js-modules loading 'jquery'
156 // namespace bundles from the 'core-assets' namespace provider.
157 script.setAttribute('data-jenkins-module-nsProvider', 'core-assets');
158 script.setAttribute('data-jenkins-module-namespace', 'bootstrap');
159 script.setAttribute('data-jenkins-module-moduleName', 'bootstrap3');
160 head.appendChild(script);
161
162 jenkins.whoami('bootstrap:bootstrap3');
163 expect(internal.whoami().nsProvider).toBe('core-assets');
164
165 jenkins.import('jquery:jquery2')
166 .onFulfilled(function() {
167 // 'jquery:jquery2' should have also been loaded from the 'core-assets' namespace
168 // provider because the parent bundle ('bootstrap3') was loaded from 'core-assets'.
169 var jquerySpec = internal.getModuleSpec('jquery:jquery2');
170 expect(jquerySpec.nsProvider).toBe('core-assets');
171
172 // Let's also do a check on the actual script URL.
173 var jqueryJsId = internal.toModuleId('jquery', 'jquery2') + ':js';
174 var jqueryScriptEl = document.getElementById(jqueryJsId);
175 expect(jqueryScriptEl).toBeDefined();
176 expect(jqueryScriptEl.getAttribute('src')).toBe('/jenkins/assets/jquery/jsmodules/jquery2.js');
177
178 // Let's also mimic the loading of the bootstrap3 CSS. It too should get loaded
179 // via the 'core-assets' namespace provider.
180 internal.addModuleCSSToPage('bootstrap', 'bootstrap3');
181 var bootstrapCSSId = internal.toModuleId('bootstrap', 'bootstrap3') + ':css';
182 var bootstrapCSSEl = document.getElementById(bootstrapCSSId);
183 expect(bootstrapCSSEl).toBeDefined();
184 expect(bootstrapCSSEl.getAttribute('href')).toBe('/jenkins/assets/bootstrap/jsmodules/bootstrap3/style.css');
185
186 // Test require ...
187 jenkins.require('jquery:jquery2');
188 // Specifying the namespace provider here should be irrelevant coz
189 // the bundle/module is already registered. That's the main point here i.e.
190 // the nsProvider is only of interest IF the module needs to be loaded i.e. it tells
191 // where to get the module from (the provider). If it's already loaded, then we don't
192 // care where it was loaded from.
193 jenkins.require('core-assets/jquery:jquery2');
194 jenkins.require('plugin/jquery:jquery2');
195
196 done();
197 });
198
199 // Now mimic registering of the plugin modules.
200 jenkins.export('jquery', 'jquery2', {});
201 });
202 });
203
204 it("- test import from import/QName provided namespace provider", function (done) {
205 testUtil.onJenkinsPage(function() {
206 var jenkins = require("../js/index");
207 var internal = require("../js/internal");
208 var document = require('window-handle').getWindow().document;
209
210 // Test import where the nsProvider is specified on the import. This is
211 // slightly different to using the parent's provider namespace
212 jenkins.import('core-assets/jquery:jquery2')
213 .onFulfilled(function() {
214 // 'jquery:jquery2' should have also been loaded from the 'core-assets' namespace
215 // provider because the parent bundle ('bootstrap3') was loaded from 'core-assets'.
216 var jquerySpec = internal.getModuleSpec('jquery:jquery2');
217 expect(jquerySpec.nsProvider).toBe('core-assets');
218
219 // Let's also do a check on the actual script URL.
220 var jqueryJsId = internal.toModuleId('jquery', 'jquery2') + ':js';
221 var jqueryScriptEl = document.getElementById(jqueryJsId);
222 expect(jqueryScriptEl).toBeDefined();
223 expect(jqueryScriptEl.getAttribute('src')).toBe('/jenkins/assets/jquery/jsmodules/jquery2.js');
224
225 // Test require ...
226 jenkins.require('jquery:jquery2');
227 // Specifying the namespace provider here should be irrelevant coz
228 // the bundle/module is already registered. That's the main point here i.e.
229 // the nsProvider is only of interest IF the module needs to be loaded i.e. it tells
230 // where to get the module from (the provider). If it's already loaded, then we don't
231 // care where it was loaded from.
232 jenkins.require('core-assets/jquery:jquery2');
233 jenkins.require('plugin/jquery:jquery2');
234
235 done();
236 });
237
238 // Now mimic registering of the plugin modules.
239 jenkins.export('jquery', 'jquery2', {});
240 });
241 });
242
243 it("- test import and export sync successful", function (done) {
244 testUtil.onJenkinsPage(function() {
245 var jenkins = require("../js/index");
246
247 // Register the plugin modules before requiring.
248 jenkins.export('pluginA', 'mathUtils', {
249 add: function(lhs, rhs) {
250 return lhs + rhs;
251 }
252 });
253 jenkins.export('pluginB', 'timeUtils', {
254 now: function() {
255 return new Date(1000000000000);
256 }
257 });
258
259 // Now require.
260 // Should pass immediately because export has already happened for each plugin.
261 jenkins.setRegisterTimeout(0);
262 jenkins.import('pluginA:mathUtils', 'pluginB:timeUtils') // disable async load mode
263 .onFulfilled(function(mathUtils, timeUtils) {
264 // This function should only be called once both modules have been exported
265 expect(mathUtils.add(2,2)).toBe(4);
266 expect(timeUtils.now().getTime()).toBe(1000000000000);
267 done();
268 }); // timeout before Jasmine does
269 });
270 });
271
272 it("- test import via global '_internal'", function (done) {
273 testUtil.onJenkinsPage(function() {
274 var jenkins = require("../js/index");
275 var internal = require("../js/internal");
276
277 // Require before the modules are registered.
278 // The require should "trigger" the loading of the module from the plugin.
279 // Should pass because export will happen before the timeout
280 jenkins.setRegisterTimeout(2000);
281 var _internal = internal.getJenkins()._internal;
282 _internal.import('pluginA:mathUtils')
283 .onFulfilled(function(mathUtils) {
284 // This function should only be called once both modules have been exported
285 expect(mathUtils.add(2,2)).toBe(4);
286 done();
287 }); // timeout before Jasmine does
288
289 // Now mimic registering of the plugin modules.
290 jenkins.export('pluginA', 'mathUtils', {
291 add: function(lhs, rhs) {
292 return lhs + rhs;
293 }
294 });
295 });
296 });
297
298 it("- test import and export global namespace async successful", function (done) {
299 testUtil.onJenkinsPage(function() {
300 var jenkins = require("../js/index");
301 var internal = require("../js/internal");
302
303 // Require before the modules are registered.
304 // The require should "trigger" the loading of the module.
305 // Should pass because export will happen before the timeout
306 jenkins.setRegisterTimeout(2000);
307 jenkins.import('mathUtils', 'timeUtils')
308 .onFulfilled(function(mathUtils, timeUtils) {
309 // This function should only be called once both modules have been exported
310 expect(mathUtils.add(2,2)).toBe(4);
311 expect(timeUtils.now().getTime()).toBe(1000000000000);
312
313 // The mathUtils module should be in the 'global' namespace
314 var moduleNamespace = internal.getModuleNamespaceObj({moduleName: 'mathUtils'});
315 expect(moduleNamespace.globalNS).toBe(true);
316
317 done();
318 }); // timeout before Jasmine does
319
320 // Now mimic registering of the global modules (plugin name undefined).
321 jenkins.export(undefined, 'mathUtils', {
322 add: function(lhs, rhs) {
323 return lhs + rhs;
324 }
325 });
326 jenkins.export(undefined, 'timeUtils', {
327 now: function() {
328 return new Date(1000000000000);
329 }
330 });
331 });
332 });
333
334 it("- test import and export global/plugin namespace async without module", function (done) {
335
336 // This test is simply testing that we can async wait for a module that doesn't export
337 // anything to load. Sounds strange, but we actually need something like this in Jenkins.
338 // E.g. to support backward compatibility, we want adjuncts to wait for the
339 // 'jenkins-backcompat' bundle to load before they execute. The 'jenkins-backcompat' bundle
340 // may or may not export functions (not always relevant), but it does register stuff in the
341 // global/window JS namespace that legacy adjuncts need, so we need to make sure it is done
342 // loading before we let the adjunct execute.
343
344 testUtil.onJenkinsPage(function() {
345 var jenkins = require("../js/index");
346 var internal = require("../js/internal");
347
348 // Require before the modules are registered.
349 // The require should "trigger" the loading of the module.
350 // Should pass because export will happen before the timeout
351 jenkins.setRegisterTimeout(2000);
352 // 2 modules, the first is in the global namespace and the second is in a
353 // plugin namespace ('pluginB')
354 jenkins.import('mathUtils', 'pluginB:timeUtils')
355 .onFulfilled(function(mathUtils, timeUtils) {
356 expect(mathUtils).toBeDefined();
357 expect(timeUtils).toBeDefined();
358 done();
359 }); // timeout before Jasmine does
360
361 // Now mimic registering of the modules, but without actual "modules" i.e. 3rd param not defined.
362 jenkins.export(undefined, 'mathUtils');
363 jenkins.export('pluginB', 'timeUtils');
364 });
365 });
366
367 it("- test addScript without 'data-replaceable' attribute", function (done) {
368 testUtil.onJenkinsPage(function() {
369 var internal = require("../js/internal");
370 var document = require('window-handle').getWindow().document;
371
372 var scriptId = 'adjunct:path/to/script.js';
373 var jsEl = document.getElementById(scriptId);
374
375 expect(jsEl).toBe(null);
376
377 jsEl = internal.addScript('path/to/script.js', scriptId);
378 expect(jsEl).toBeDefined();
379 expect(jsEl.getAttribute('src')).toBe('/jenkins/path/to/script.js');
380
381 // Trying to add another <script> of the same id should fail
382 // because the existing <script> doesn't have a 'data-replaceable="true"'
383 // attribute.
384
385 var jsEl2 = internal.addScript('path/to/script.js', scriptId);
386 expect(jsEl2).not.toBeDefined();
387
388 done();
389 });
390 });
391
392 it("- test addScript with 'data-replaceable' attribute", function (done) {
393 testUtil.onJenkinsPage(function() {
394 var internal = require("../js/internal");
395 var document = require('window-handle').getWindow().document;
396
397 var scriptId = 'adjunct:path/to/script.js';
398 var jsEl = document.getElementById(scriptId);
399
400 expect(jsEl).toBe(null);
401 jsEl = internal.addScript('path/to/script.js', {scriptId: scriptId}); // use an config object
402 expect(jsEl).toBeDefined();
403 expect(jsEl.parentNode).toBe(internal.getHeadElement());
404
405 // add the 'data-replaceable' attribute
406 jsEl.setAttribute('data-replaceable', 'true');
407
408 // Now when we try to add another <script> of the same id, it will
409 // work because the existing <script> has a 'data-replaceable="true"'
410 // attribute.
411
412 var jsEl2 = internal.addScript('path/to/script.js', {scriptId: scriptId}); // use an config object
413 expect(jsEl2).toBeDefined(); // addScript worked?
414 expect(jsEl2).not.toBe(jsEl); // and it's not the original of the same id?
415
416 // and the original jsEl should no longer be attached to the
417 // document head i.e. should have been deleted.
418 expect(jsEl.parentNode).not.toBe(internal.getHeadElement());
419
420 done();
421 });
422 });
423
424 it("- test addScript with URL mapping/transform", function (done) {
425 testUtil.onJenkinsPage(function() {
426 var internal = require("../js/internal");
427 var document = require('window-handle').getWindow().document;
428
429 var scriptId = 'adjunct:path/to/script.js';
430 var jsEl = document.getElementById(scriptId);
431
432 expect(jsEl).toBe(null);
433 jsEl = internal.addScript('path/to/script.js', {
434 scriptId: scriptId,
435 scriptSrcMap: [
436 {from: 'to/script.js', to: 'to/some/other/script.js'}
437 ]
438 });
439 expect(jsEl).toBeDefined();
440 expect(jsEl.getAttribute('src')).toBe('/jenkins/path/to/some/other/script.js');
441
442 done();
443 });
444 });
445
446 it("- test addScript (adjunct)", function (done) {
447 testUtil.onJenkinsPage(function() {
448 var internal = require("../js/internal");
449 var document = require('window-handle').getWindow().document;
450
451 var scriptId = 'adjunct:path/to/script.js';
452 var jsEl = document.getElementById(scriptId);
453
454 expect(jsEl).toBe(null);
455 jsEl = internal.addScript('path/to/script.js', {
456 scriptId: scriptId,
457 scriptSrcBase: '@adjunct'
458 });
459 expect(jsEl).toBeDefined();
460 expect(jsEl.getAttribute('src')).toBe('/jenkins/adjuncts/be297f05/path/to/script.js');
461
462 done();
463 }, '<html><head data-adjuncturl="/jenkins/adjuncts/be297f05"></head></html>');
464 });
465
466 it("- test addModuleCSSToPage", function (done) {
467 testUtil.onJenkinsPage(function() {
468 var jenkins = require("../js/index");
469 var internal = require("../js/internal");
470 var document = require('window-handle').getWindow().document;
471
472 var cssEl = document.getElementById(internal.toModuleId('pluginA', 'mathUtils') + ':css');
473 expect(cssEl).toBe(null);
474
475 jenkins.addModuleCSSToPage('pluginA', 'mathUtils');
476 cssEl = document.getElementById(internal.toModuleId('pluginA', 'mathUtils') + ':css');
477 expect(cssEl).toBeDefined();
478 expect(cssEl.getAttribute('href')).toBe('/jenkins/adjuncts/xxx/org/jenkins/ui/jsmodules/pluginA/mathUtils/style.css');
479
480 done();
481 });
482 });
483
484 it("- test addPluginCSSToPage", function (done) {
485 testUtil.onJenkinsPage(function() {
486 var jenkins = require("../js/index");
487 var internal = require("../js/internal");
488 var document = require('window-handle').getWindow().document;
489 var cssId = 'jenkins-js-module:pluginA:css:/jenkins/plugin/pluginA/css/mathUtils.css';
490
491 var cssEl = document.getElementById(cssId);
492 expect(cssEl).toBe(null);
493
494 jenkins.addPluginCSSToPage('pluginA', 'css/mathUtils.css');
495 cssEl = document.getElementById(cssId);
496 expect(cssEl).toBeDefined();
497 expect(cssEl.getAttribute('href')).toBe('/jenkins/plugin/pluginA/css/mathUtils.css');
498
499 done();
500 });
501 });
502
503 it("- test addCSSToPage", function (done) {
504 testUtil.onJenkinsPage(function() {
505 var jenkins = require("../js/index");
506 var document = require('window-handle').getWindow().document;
507 var cssId = 'jenkins-js-module:global:css:/jenkins/css/mathUtils.css';
508
509 var cssEl = document.getElementById(cssId);
510 expect(cssEl).toBe(null);
511
512 jenkins.addCSSToPage('css/mathUtils.css');
513 cssEl = document.getElementById(cssId);
514 expect(cssEl).toBeDefined();
515 expect(cssEl.getAttribute('href')).toBe('/jenkins/css/mathUtils.css');
516
517 done();
518 });
519 });
520
521 it("- test rootURL/resURL not defined", function (done) {
522 testUtil.onJenkinsPage(function() {
523 var jenkins = require("../js/index");
524 jenkins.export('pluginA', 'mathUtils', {
525 add: function(lhs, rhs) {
526 return lhs + rhs;
527 }
528 }, function (e) {
529 expect(e).toBe("Attribute 'data-rooturl' not defined on the document <head> element.");
530 done();
531 });
532 }, '<html><head></head></html>');
533 });
534
535 it("- test data-rooturl empty", function (done) {
536 testUtil.onJenkinsPage(function() {
537 var jenkins = require("../js/index");
538 expect(jenkins.getRootURL()).toBe("");
539 done();
540 }, '<html><head data-rooturl=""></head></html>');
541 });
542
543 it("- test data-adjuncturl empty", function (done) {
544 testUtil.onJenkinsPage(function() {
545 var jenkins = require("../js/index");
546 expect(jenkins.getAdjunctURL()).toBe("");
547 done();
548 }, '<html><head data-adjuncturl=""></head></html>');
549 });
550
551 it("- test rootURL/resURL defined", function (done) {
552 testUtil.onJenkinsPage(function() {
553 var jenkins = require("../js/index");
554 jenkins.setRootURL('/jenkins');
555 jenkins.export('pluginA', 'mathUtils', {
556 add: function(lhs, rhs) {
557 return lhs + rhs;
558 }
559 });
560 jenkins.require('pluginA:mathUtils');
561 done();
562 }, '<html><head></head></html>');
563 });
564});