3 | The samples do no longer comply with the standards and requirements in Jenkins.
4 | If you are looking for up-to-date samples and documentation how to use JS in plugins, please consult the Jenkins documentation.
5 |
6 |
7 | # jenkins-js Sample Plugins
8 |
9 | This repository provides some sample Jenkins Plugins, showing how to use [jenkins-js-builder] to build
10 | Jenkins plugins that support a richer UI through the use of Modularized JavaScript.
11 |
12 |
13 | ## Step-by-step Plugins
14 |
15 | The repository contains step-by-step example plugins, starting with step-01-basic,
16 | which is just a simple Jenkins plugin that contains no JavaScript at all, working up through steps 02 and 03 etc,
17 | incrementally adding more JavaScript "features".
18 |
19 | | Name | Description |
20 | | :-----| :------------|
21 | | step-01-basic | A very basic Jenkins plugin with no JavaScript.
22 | | step-02-nodeify | Update step-01-basic to add a very simple jQuery based JavaScript App bundle (jQuery bundled).|
23 | | step-03-more-npm-packs | Update step-02-nodeify to use Twitter Bootstrap instead of jQuery and to also use Moment.js (Bootstrap and Moment.js bundled). |
24 | | step-04-externalize-libs | Update step-03-more-npm-packs to slim down the the App bundle by externalizing Bootstrap and Moment.js (Bootstrap and Moment.js NOT bundled). |
25 | | step-05-namespaced-css | Update step-04-externalize-libs to use bootstrap's default namespaced CSS. |
26 | | step-06-handlebars-templates | Update step-04-externalize-libs to use Handlebars Templates. |
27 | | step-07-jsdom-tests | How to add unit tests using [jsdom] and [Jasmine]. |
28 | | step-08-zombie-tests | How to add integration tests using [Zombie] and [Jasmine]. |
29 |
30 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules
31 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder
32 | [jenkins-js-libs]: https://github.com/jenkinsci/js-libs
33 | [jenkins-js-test]: https://github.com/jenkinsci/js-test
34 | [Jasmine]: http://jasmine.github.io/
35 | [jsdom]: https://github.com/tmpvar/jsdom
36 | [Zombie]: http://zombie.js.org/
37 |
--------------------------------------------------------------------------------
/img/how-it-works.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkinsci/js-samples/a641067df2da59ff3f210c266d1a0c3c1127bdc1/img/how-it-works.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 |
7 | org.jenkins-ci.plugins
8 | plugin
9 | 2.6
10 |
11 |
12 |
13 | org.jenkins-ci.ui.samples
14 | jenkins-js-samples
15 | 1.0-SNAPSHOT
16 | pom
17 |
18 | JS Lib Samples: Parent POM
19 |
20 |
21 | 1.639
22 | 1.106
23 |
27 | 6.8.1
28 | 3.10.9
29 |
30 |
31 |
32 | step-01-basic
33 | step-02-nodeify
34 | step-03-more-npm-packs
35 | step-04-externalize-libs
36 | step-05-namespaced-css
37 | step-06-handlebars-templates
38 | step-07-jsdom-tests
39 | step-08-zombie-tests
40 |
41 |
42 |
43 |
44 | MIT License
45 | http://opensource.org/licenses/MIT
46 |
47 |
48 |
49 |
50 |
51 | repo.jenkins-ci.org
52 | http://repo.jenkins-ci.org/public/
53 |
54 |
55 |
56 |
57 | repo.jenkins-ci.org
58 | http://repo.jenkins-ci.org/public/
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/step-01-basic/HOW-IT-WORKS.md:
--------------------------------------------------------------------------------
1 | # Step 01 - A "basic" Plugin - How it Works
2 | Creating a basic Jenkins plugin is already well covered in the [Plugin Tutorial] on the wiki.
3 |
4 | There's really nothing much to this first Jenkins plugin in this repo. It's just a standard Jenkins plugin with
5 | nothing extra. It acts as the foundation for the other sample plugins in this repository.
6 |
7 | This plugin ("step-01-basic") just adds a standard Jenkins "root action" page that contains
8 | a simple form.
9 |
10 | On running the plugin (`mvn hpi:run`), you will see the following screens.
11 |
12 | 
13 | 
14 |
15 | At this point, we are ready to "nodeify" the plugin by adding some [CommonJS] JavaScript modules.
16 |
17 |
18 |
21 |
22 | [Plugin Tutorial]: https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial
23 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder
24 | [CommonJS]: http://www.commonjs.org/
25 |
--------------------------------------------------------------------------------
/step-01-basic/README.md:
--------------------------------------------------------------------------------
1 | # Step 01 - A "basic" Plugin
2 | A basic Jenkins plugin with just a standard Jenkins "root action" page that contains
3 | a simple form. This plugin is the foundation for all other sample plugins in this repo.
4 |
5 |
10 |
11 |
12 | ## How to run
13 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin).
14 |
15 | ```sh
16 | $ mvn hpi:run
17 | ```
18 |
19 | On running the plugin, you will see the following screens.
20 |
21 | 
22 | 
23 |
24 | ## How it works
25 |
26 |
27 |
28 |
29 |
32 |
33 | [Plugin Tutorial]: https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial
34 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder
35 | [CommonJS]: http://www.commonjs.org/
36 |
--------------------------------------------------------------------------------
/step-01-basic/img/root-action-page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkinsci/js-samples/a641067df2da59ff3f210c266d1a0c3c1127bdc1/step-01-basic/img/root-action-page.png
--------------------------------------------------------------------------------
/step-01-basic/img/root-action.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkinsci/js-samples/a641067df2da59ff3f210c266d1a0c3c1127bdc1/step-01-basic/img/root-action.png
--------------------------------------------------------------------------------
/step-01-basic/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 |
7 | org.jenkins-ci.ui.samples
8 | jenkins-js-samples
9 | 1.0-SNAPSHOT
10 | ../
11 |
12 | step-01-basic
13 | 1.0
14 | hpi
15 |
16 | JS Lib Samples: Step 1 - Basic
17 |
18 |
19 |
--------------------------------------------------------------------------------
/step-01-basic/src/main/java/org/jenkinsci/ui/samples/JSLibSample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2015, CloudBees, Inc.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package org.jenkinsci.ui.samples;
25 |
26 | import hudson.Extension;
27 | import hudson.model.RootAction;
28 |
29 | /**
30 | * @author tom.fennelly@gmail.com
31 | */
32 | @Extension
33 | public class JSLibSample implements RootAction {
34 |
35 | public String getIconFileName() {
36 | return "green.png";
37 | }
38 |
39 | public String getDisplayName() {
40 | return "JSLib Sample";
41 | }
42 |
43 | public String getUrlName() {
44 | return "/js-sample";
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/step-01-basic/src/main/resources/index.jelly:
--------------------------------------------------------------------------------
1 |
2 |
30 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/step-02-nodeify/HOW-IT-WORKS.md:
--------------------------------------------------------------------------------
1 | # Step 02 - Add CommonJS modules ("nodeify") - How it works
2 | The plugin in this step (`step-02-nodeify`) builds on top of step-01-basic,
3 | adding some [CommonJS] modules. We use [jenkins-js-builder] and some other [Node.js]
4 | tools to build a self contained browser-ready JavaScript "[bundle]" that can be loaded through your Jenkins `.jelly` files
5 | (or whatever mechanism works for your plugin).
6 |
7 | There are a few simple steps to adding [CommonJS] modules to your plugin.
8 |
9 |
21 |
22 |
23 | ## Install Node.js and Gulp
24 | On your dev machine, install [Node.js] v4.0.0+.
25 |
26 | You'll also need to globally install [Gulp].
27 |
28 | ```sh
29 | $ npm install --global gulp
30 | ```
31 |
32 | > __NOTE__ that [Node.js] and [Gulp] only needs to be installed on Dev machines so as to allow the running of node/npm/gulp etc commands while developing the plugin. A simple check out and build of your plugin (using maven) will NOT require [Node.js] to be installed on the build machine. The maven build will take care of everything.
33 |
34 | ## Add `package.json`
35 | Add a `package.json` file to the root of your plugin using the [`npm init`](https://docs.npmjs.com/cli/init) command.
36 |
37 | ```sh
38 | $ npm init
39 | This utility will walk you through creating a package.json file.
40 | It only covers the most common items, and tries to guess sensible defaults.
41 |
42 | See 'npm help json' for definitive documentation on these fields
43 | and exactly what they do.
44 |
45 | Use 'npm install --save' afterwards to install a package and
46 | save it as a dependency in the package.json file.
47 |
48 | Press ^C at any time to quit.
49 | name: (step-02-nodeify)
50 | ```
51 |
52 | ## Add initial NPM packages
53 | Install the minimum set of NPM packages required for your plugin to build ([gulp](https://github.com/gulpjs/gulp), [jenkins-js-builder] and [jenkins-js-modules]).
54 |
55 | ```sh
56 | $ npm install --save-dev gulp @jenkins-cd/js-builder
57 | $ npm install --save @jenkins-cd/js-modules
58 | ```
59 |
60 | Let's also install the jquery package.
61 |
62 | ```sh
63 | $ npm install --save jquery
64 | ```
65 |
66 | ## Add first CommonJS module
67 | Create `src/main/js/jslib-samples.js` and add the following JavaScript code:
68 |
69 | ```javascript
70 | var $ = require('jquery');
71 |
72 | $(document).ready(function () {
73 | $('#side-panel').remove();
74 | $('#main-panel').css('margin-left', '0px');
75 | });
76 | ```
77 |
78 | This silly little [CommonJS] module will just use jQuery to remove the left side-panel. Of
79 | course we could add more [CommonJS] modules in `src/main/js` and use them in our App.
80 |
81 | ## Add `gulpfile.js`
82 | Add a `gulpfile.js` file to the root of your plugin.
83 |
84 | `gulpfile.js` will not contain a lot of code. Most of the work is done by [jenkins-js-builder].
85 |
86 | ```javascript
87 | var builder = require('@jenkins-cd/js-builder');
88 |
89 | //
90 | // Bundle the modules.
91 | // See https://github.com/jenkinsci/js-builder
92 | //
93 | builder.bundle('src/main/js/jslib-samples.js');
94 | ```
95 |
96 | The `builder.bundle` command is asking [jenkins-js-builder] to create a [bundle] (using [Browserify]) starting from
97 | `src/main/js/jslib-samples.js`, and to output the generated [bundle] file to the `target/classes` folder, allowing the
98 | `.js` bundle to be loaded as an adjunct. The generated [bundle] file will be totally self contained (containing a private
99 | copy of jQuery and anything else used by the App) and loadable in a browser.
100 |
101 | ## Build the JavaScript bundle for the Browser
102 | To build the [bundle], simple run:
103 |
104 | ```sh
105 | $ gulp
106 | ```
107 |
108 | You should see output like the following:
109 |
110 | ```sh
111 | $ gulp
112 | [11:07:27] **********************************************************************
113 | [11:07:27] This build is using Jenkins JS Builder.
114 | [11:07:27] For command line options and other help, go to
115 | [11:07:27] https://www.npmjs.com/package/@jenkins-cd/js-builder
116 | [11:07:27] **********************************************************************
117 | [11:07:27] Maven project.
118 | [11:07:27] - Jenkins plugin (HPI): step-02-nodeify
119 | [11:07:27] Language level set to ECMA v5. Call builder.lang([number]) to change.
120 | [11:07:27] Defining default tasks...
121 | [11:07:27] Using gulpfile ~/projects/jenkins-plugins/jenkins-js-samples/step-02-nodeify/gulpfile.js
122 | [11:07:27] Starting 'lint'...
123 | [11:07:28] - Using the "es5" eslint configuration from eslint-config-jenkins. Override by defining a .eslintrc in this folder (if you really must).
124 | [11:07:28] Finished 'lint' after 549 ms
125 | [11:07:28] Starting 'log-env'...
126 | [11:07:28] Source Dirs:
127 | [11:07:28] - src: src/main/js,src/main/less
128 | [11:07:28] - test: src/test/js
129 | [11:07:28] Finished 'log-env' after 599 μs
130 | [11:07:28] Starting 'bundle_jslib-samples'...
131 | [11:07:28] Javascript bundle "jslib-samples" will be available in Jenkins as adjunct "org.jenkins.ui.jsmodules.step_02_nodeify.jslib-samples".
132 | [11:07:29] Finished 'bundle_jslib-samples' after 1.53 s
133 | [11:07:29] Starting 'bundle'...
134 | [11:07:29] bundling: done
135 | [11:07:29] Finished 'bundle' after 207 μs
136 | [11:07:29] Starting 'test'...
137 | [11:07:29] Test specs: src/test/js/**/*-spec.js
138 | [11:07:29] Testing web server started on port 18999 (http://localhost:18999). Content root: /Users/tfennelly/projects/jenkins-plugins/jenkins-js-samples/step-02-nodeify
139 | [11:07:29] Finished 'test' after 54 ms
140 | [11:07:29] Starting 'default'...
141 | [11:07:29] Finished 'default' after 3.77 μs
142 | SUCCESS: 0 specs, 0 failures, 0 skipped, 0 disabled in 0.001s.
143 | [11:07:30] Testing web server stopped.
144 | ```
145 |
146 | The part of the build output that's of most interest to us here is:
147 |
148 | ```sh
149 | [11:07:28] Javascript bundle "jslib-samples" will be available
150 | in Jenkins as adjunct "org.jenkins.ui.jsmodules.step_02_nodeify.jslib-samples".
151 | ```
152 |
153 | This tells us where the generated `.js` [bundle] can be loaded from as a Jenkins adjunct i.e. `org.jenkins.ui.jsmodules.step_02_nodeify.jslib-samples`.
154 | We will use this information in the next section.
155 |
156 | ## Add the JavaScript bundle to the .jelly page
157 | Using the information from the previous section, it's easy to determine how to load the [bundle] in Jenkins via the
158 | `.jelly` file. In this example we will use a Jenkins adjunt, adding it to
159 | [JSLibSample/index.jelly](src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly).
160 |
161 | ```html
162 |
163 | ```
164 |
165 | > Note: The `org.jenkins.ui.jsmodules.step_02_nodeify.jslib-samples` adjunct identifier translates to an adjunct URL of the form `http://localhost:8080//org/jenkins/ui/jsmodules/step_02_nodeify/jslib-samples.js`.
166 | > The `` prefix is typically something like `jenkins/adjuncts/1cc49125`. In JavaScript code, it can typically be accessed using the `getAdjunctURL()` method of the `@jenkins-cd/js-modules` package.
167 |
168 | ## Test run
169 | At this stage, you should be able to take `step-02-nodeify` for a test run and see how the Modularized JavaScript
170 | behaves. You can do this by simply [running the plugin using the HPI plugin](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin).
171 |
172 | 
173 |
174 | As you can see, the [bundle] ran fine and used jQuery (contained in the [bundle]) to remove the left side-panel.
175 |
176 | ## Integrate Gulp and Maven builds
177 | You will want to run the `gulp` build (to generate the [bundle]) as part of your plugin's Maven build. For that reason,
178 | the `gulp` build needs to be integrated into the `mvn` build lifecycle.
179 |
180 | If your plugin's parent POM is `org.jenkins-ci.plugins:plugins:1.639` or newer, no action is required. If your
181 | plugin depends on an older parent POM, then you will need to add the maven ``s referred to in the
182 | [sample_extract_pom.xml](https://github.com/jenkinsci/js-builder/blob/master/res/sample_extract_pom.xml) in
183 | [Maven Integration](https://github.com/jenkinsci/js-builder#maven-integration) section of the [jenkins-js-builder] docs.
184 |
185 |
186 |
10 |
11 |
12 | ## How to run
13 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin).
14 |
15 | ```sh
16 | $ mvn hpi:run
17 | ```
18 |
19 | On running the plugin, you will see the following screen. Nothing much has visually changed from
20 | step-01-basic, apart from the fact that some Modularized
21 | JavaScript has run (see how it works) which removed the left side-panel.
22 |
23 | 
24 |
25 | ## How it works
26 |
27 |
28 |
29 |
30 |
30 |
46 |
47 |
48 |
49 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/step-03-more-npm-packs/.gitignore:
--------------------------------------------------------------------------------
1 | target
--------------------------------------------------------------------------------
/step-03-more-npm-packs/HOW-IT-WORKS.md:
--------------------------------------------------------------------------------
1 | # Step 03 - Use more NPM packages i.e. Twitter Bootstrap and Moment.js - How it works
2 | `step-03-more-npm-packs` builds on step-02-nodeify, adding a few more
3 | NPM packages to the mix, namely Twitter Bootstrap (via [bootstrap-detached])
4 | and Moment.js. This is one of the major benefits of using [CommonJS] style packages; it means we can easily utilise
5 | the huge number of JavaScript packages available in the NPM registry.
6 |
7 | ## Install/Uninstall NPM packages
8 | Install [bootstrap-detached] and Moment.js:
9 |
10 | ```sh
11 | $ npm install --save bootstrap-detached moment
12 | ```
13 |
14 | Since we are using [bootstrap-detached], we can uninstall jquery because [bootstrap-detached]
15 | is `jquery + bootstrap`:
16 |
17 | ```sh
18 | $ npm uninstall --save jquery
19 | ```
20 |
21 | > Note: [bootstrap-detached] is easier to use because it contains it's own "detached" instance of jquery ([jquery-detached]).
22 |
23 | ## Update `.js`
24 | The changes to the `src/main/js/jslib-samples.js` are very trivial.
25 |
26 | ```diff
27 | -var $ = require('jquery');
28 | +// Change from 'jquery' to 'bootstrap-detached'
29 | +var $ = require('bootstrap-detached').getBootstrap();
30 |
31 | $(document).ready(function () {
32 | $('#side-panel').remove();
33 | $('#main-panel').css('margin-left', '0px');
34 | +
35 | + // Add some code to use momentjs, adding formatted time text to the page.
36 | + // See src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly.
37 | + var moment = require('moment');
38 | + $('#main-panel .time').text(moment().format("MMM Do YY"));
39 | });
40 | ```
41 |
42 | ## Bundle Bootstrap CSS
43 |
44 | The fact that we're using Bootstrap means that we need to add bootstrap's CSS to the plugin. After [downloading the
45 | bootstrap distro](http://getbootstrap.com/getting-started/), the CSS was added in
46 | [src/main/css/bootstrap336](src/main/css/bootstrap336). We want to bundle this CSS (and all related
47 | resources - fonts etc) in our plugin and to do that, we simply add another `bundle`
48 | command to the [gulpfile.js](gulpfile.js) as follows:
49 |
50 | ```javascript
51 | builder.bundle('src/main/css/bootstrap336/bootstrap.css');
52 | ```
53 |
54 | This bundling command will bundle everything under `src/main/css/bootstrap336` into the plugin as adjuncts. The
55 | adjunct identifier is output to the console by the build (just as described with the `.js` bundle adjunct
56 | in step-02-nodeify).
57 |
58 | ```sh
59 | [12:33:57] CSS resource "src/main/css/bootstrap336/bootstrap.css" will be available
60 | in Jenkins as adjunct "org.jenkins.ui.jsmodules.bootstrap336.bootstrap".
61 | ```
62 |
63 | > Note: You can also specify a [LESS](http://lesscss.org/) file here and it will be pre-processed and bundled into the Jenkins plugin.
64 |
65 | The changes to [JSLibSample/index.jelly](src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly) were trivial
66 | i.e. just add the adjunct:
67 |
68 | ```html
69 |
70 | ```
71 |
72 | > Note: Of course you can also just place the CSS resources somewhere in `src/main/resources` and they will get bundled
73 | > in the plugin classpath. The benefit of doing it as outlined above is that it makes dealing with [LESS](http://lesscss.org/) a bit easier.
74 | > It also auto-adds `.adjunct` marker files to all the resource sub-directories, making it possible to load fonts etc as adjuncts.
75 |
76 | ## Test run
77 | Now take `step-03-more-npm-packs` for a test run and see the effect of these changes.
78 | Again, you can do this by simply [running the plugin using the HPI plugin](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin).
79 |
80 | 
81 |
82 |
83 |
86 |
87 | [Node.js]: https://nodejs.org
88 | [Gulp]: https://github.com/gulpjs/gulp
89 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder
90 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules
91 | [CommonJS]: http://www.commonjs.org/
92 | [jquery-detached]: https://github.com/tfennelly/jquery-detached
93 | [bootstrap-detached]: https://github.com/tfennelly/bootstrap-detached
94 | [Browserify]: http://browserify.org/
95 | [bundle]: https://github.com/jenkinsci/js-modules/blob/master/FAQs.md#what-is-the-difference-between-a-module-and-a-bundle
96 |
97 |
--------------------------------------------------------------------------------
/step-03-more-npm-packs/README.md:
--------------------------------------------------------------------------------
1 | # Step 03 - Use more NPM packages i.e. Twitter Bootstrap and Moment.js
2 | `step-03-more-npm-packs` builds on step-02-nodeify, adding a few more
3 | NPM packages to the mix, namely Twitter Bootstrap (via [bootstrap-detached])
4 | and Moment.js. This is one of the major benefits of using [CommonJS] style packages; it means we can easily utilise
5 | the huge number of JavaScript packages available in the NPM registry.
6 |
7 |
12 |
13 |
14 | ## How to run
15 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin).
16 |
17 | ```sh
18 | $ mvn hpi:run
19 | ```
20 |
21 | On running the plugin, you will see the following screen. The main change from
22 | step-02-nodeify is the fact that the sample is utilizing
23 | bootstrap and moment.js (see how it works).
24 |
25 | 
26 |
27 | ## How it works
28 |
29 |
30 |
31 |
32 |
30 |
31 |
47 |
48 |
49 |
50 |
54 |
55 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/step-04-externalize-libs/HOW-IT-WORKS.md:
--------------------------------------------------------------------------------
1 | # Step 04 - Externalize Dependency Libraries (slim down) - How it Works
2 | With `step-03-more-npm-packs`, we have a plugin using Modularized [CommonJS] style JavaScript, which is good. Using
3 | [CommonJS] means we can easily use any of the huge number of JavaScript packages available in the NPM registry.
4 |
5 | This is great, but one of the issues with `step-03-more-npm-packs` is that its [bundle] contains everything it needs,
6 | including jQuery, Bootstrap, Moment.js and anything else we might add. This results in a quite bloated `.js` [bundle]
7 | for `step-03-more-npm-packs` - roughly 100Kb. If a given Jenkins page loads multiple `.js` bundles like this, it will
8 | potentially result in multiple jQuery instances (and Bootstrap, Moment.js etc) being loaded. What we really want in
9 | this kind of situations is to have slimmer/lighter "App" bundles, all sharing the same jQuery etc.
10 |
11 | In `step-04-externalize-libs`, we build on top of step-03-more-npm-packs,
12 | changing the bundling process by telling [jenkins-js-builder] to "externalize" some of the NPM dependencies. This means
13 | that `step-04-externalize-libs`s `.js` [bundle] will no longer include these dependencies and it's size will reduce to
14 | ~10Kb gzipped (as opposed to ~100Kb). Note that this change should not require app `.js`
15 | code changes. The only change is in the `package.json`.
16 |
17 | ## Configure Node build to externalize dependencies
18 | Externalizing NPM dependencies is a simple process. Just add an `import` entry in the `package.json`.
19 | In the case of this plugin externalizing [bootstrap-detached] and Moment.js:
20 |
21 | ```javascript
22 | "jenkinscd" : {
23 | "import": ["bootstrap-detached", "moment"]
24 | }
25 | ```
26 |
27 | The above instruction tells [jenkins-js-builder] to create seperate adjunct based bundles for these dependencies
28 | and to add them to the plugin archive. [jenkins-js-builder] does some magic (with [jenkins-js-modules]) that results in
29 | these dependency bundles being created in a way that if (e.g.) another plugin has also externalized the same dependency
30 | (version compatibility info below) then it will only be loaded once at runtime e.g. if a "compatible" version of the
31 | same NPM dependency was already loaded by [jenkins-js-modules] then it will not be loaded again.
32 |
33 | An important aspect of this externalization of NPM dependencies is the rules around how version compatibility works.
34 | In this regard, the above mentioned [jenkins-js-builder]/[jenkins-js-modules] magic honours the semantic versioning
35 | rules i.e. if a dependency bundle for Moment.js version `2.12.0` is already loaded, [jenkins-js-modules] will
36 | serve that version to anything that has a `moment` NPM dependency specification of version `^2.12.x` or `^2.x` i.e.
37 | they are considered as being compatible. If a compatible version of `moment` has not yet been loaded,
38 | [jenkins-js-modules] will trigger the async loading of that adjunct bundle.
39 |
40 | So putting it another way, every plugin will have `.js` bundle adjuncts for all of their external dependencies.
41 | If JavaScript for plugin "A" requires an externalized dependency to be loaded (e.g. `moment` v2.12.0),
42 | [jenkins-js-modules] will load that dependency for plugin "A". If plugin "B" then (some time later) also needs `moment`
43 | and it's version dependency is compatible with the already loaded version (e.g. `^2.x`), then [jenkins-js-modules]
44 | will not trigger another loading of `moment` i.e. it will provide the already loaded `moment` to plugin "B".
45 |
46 | ## Test run
47 | Now take `step-04-externalize-libs` for a test run and see the effect of these changes. What you'll see is that
48 | nothing has changed visually i.e. still works the same from a user perspective. The difference is in HOW it works.
49 |
50 | The `jslib-samples.js` [bundle] no longer contains [bootstrap-detached] or Moment.js.
51 |
52 | The easiest way to see this is through the Browsers Developer Tools.
53 |
54 | 
55 |
56 |
57 |
60 |
61 | [Node.js]: https://nodejs.org
62 | [Gulp]: https://github.com/gulpjs/gulp
63 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder
64 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules
65 | [jenkins-js-libs]: https://github.com/jenkinsci/js-libs
66 | [CommonJS]: http://www.commonjs.org/
67 | [jquery-detached]: https://github.com/tfennelly/jquery-detached
68 | [bootstrap-detached]: https://github.com/tfennelly/bootstrap-detached
69 | [Browserify]: http://browserify.org/
70 | [bundle]: https://github.com/jenkinsci/js-modules/blob/master/FAQs.md#what-is-the-difference-between-a-module-and-a-bundle
71 |
72 |
--------------------------------------------------------------------------------
/step-04-externalize-libs/README.md:
--------------------------------------------------------------------------------
1 | # Step 04 - Externalize Dependency Libraries (slim down)
2 | In this plugin (`step-04-externalize-libs`), we build on top of step-03-more-npm-packs,
3 | changing it to "externalize" it's bulky dependencies i.e. [bootstrap-detached] and Moment.js. This means that `step-04-externalize-libs`s `.js`
4 | [bundle] will no longer include these dependencies and it's size will reduce to ~10Kb (as opposed to ~100Kb).
5 |
6 | This is important if you have multiple bundles loaded in Jenkins at once (e.g. from different plugins). You don't want each
7 | bundle to have their own copies of [bootstrap-detached], Moment.js etc, making them heavier to load etc. Instead, you want
8 | those common dependencies to be loaded separately and only once i.e. shared between all "app" bundles.
9 |
10 |
15 |
16 |
17 | ## How to run
18 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin).
19 |
20 | ```sh
21 | $ mvn hpi:run
22 | ```
23 |
24 | Nothing visual changes from step-03-more-npm-packs to this plugin.
25 | The only difference is in how it works, specifically in how it loads JavaScript dependency
26 | libraries.
27 |
28 | The easiest way to see this is through the Browsers Developer Tools.
29 |
30 | 
31 |
32 | `jslib-samples.js` triggers the loading of `bootstrap3.js` and `momentjs2.js`.
33 |
34 | The main point here is that if you have a Jenkins page that loads multiple [bundle]s, many of which are loading common
35 | dependencies such as jQuery, Bootstrap etc, then you only need to load those dependencies once and share then between the
36 | different [bundle]s. And of course, the [bundle]s themselves are considerably lighter because they no longer contain
37 | these dependencies.
38 |
39 | ## How it works
40 |
41 |
42 |
43 |
44 |
30 |
31 |
47 |
48 |
49 |
50 |
54 |
55 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/step-05-namespaced-css/HOW-IT-WORKS.md:
--------------------------------------------------------------------------------
1 | # Step 05 - "Namespaced" CSS - How it works
2 | In this plugin (`step-05-namespaced-css`), we modify step-04-externalize-libs
3 | a little so as to demonstrate how to "namespace" a set of CSS rules.
4 |
5 | Namespacing the CSS rules makes it safer to use multiple versions of the same CSS lib on the same page. So if, for example, you are
6 | using bootstrap on a widget that gets added to a page on which other plugins are contributing content (e.g. the Job index page),
7 | then it makes sense to use a namespaced CSS for bootstrap in case another widget also uses bootstrap, but is using a different version.
8 |
9 | ## CSS/LESS and `index.jelly` changes
10 | The easiest way to namespace the CSS rules is to pre-process the ruleset using [LESS]. In this sample, we will namespace the
11 | bootstrap rules by introducing a `bootstrap-3` namespace. To do this, we added a [bootstrap-ns3.less](src/main/css/bootstrap336/bootstrap-ns3.less)
12 | in `src/main/css/bootstrap336`. It simply does a [LESS] `@import` of the [bootstrap.css](src/main/css/bootstrap336/bootstrap.css) rules,
13 | adding the `.bootstrap-3` class on all of them.
14 |
15 | ```less
16 | .bootstrap-3 {
17 | @import (less) "bootstrap.css";
18 | }
19 | ```
20 |
21 | Of course we also had to modify the `gulpfile.js`, telling it to bundle the new [LESS] file:
22 |
23 | ```javascript
24 | builder.bundle('src/main/css/bootstrap336/bootstrap-ns3.less');
25 | ```
26 |
27 | We also had to modify [JSLibSample/index.jelly](src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly) to "namespace" the content
28 | using `
`, as well as updating the CSS adjunct in accordance with the name of the adjunct specified in the build output
29 | i.e. `org.jenkins.ui.jsmodules.bootstrap336.bootstrap-ns3`:
30 |
31 | ```diff
32 |
33 |
34 |
35 | +
72 |
73 | [Node.js]: https://nodejs.org
74 | [Gulp]: https://github.com/gulpjs/gulp
75 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder
76 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules
77 | [jenkins-js-libs]: https://github.com/jenkinsci/js-libs
78 | [CommonJS]: http://www.commonjs.org/
79 | [jquery-detached]: https://github.com/tfennelly/jquery-detached
80 | [bootstrap-detached]: https://github.com/tfennelly/bootstrap-detached
81 | [Browserify]: http://browserify.org/
82 | [bundle]: https://github.com/jenkinsci/js-modules/blob/master/FAQs.md#what-is-the-difference-between-a-module-and-a-bundle
83 | [LESS]: http://lesscss.org/
84 |
85 |
--------------------------------------------------------------------------------
/step-05-namespaced-css/README.md:
--------------------------------------------------------------------------------
1 | # Step 05 - "Namespaced" CSS
2 | In this plugin (`step-05-namespaced-css`), we modify step-04-externalize-libs
3 | a little so as to demonstrate how to "namespace" a set of CSS rules.
4 |
5 | Namespacing the CSS rules makes it safer to use multiple versions of the same CSS lib on the same page. So if, for example, you are
6 | using bootstrap on a widget that gets added to a page on which other plugins are contributing content (e.g. the Job index page),
7 | then it makes sense to use a namespaced CSS for bootstrap in case another widget also uses bootstrap, but is using a different version.
8 |
9 |
14 |
15 |
16 | ## How to run
17 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin).
18 |
19 | ```sh
20 | $ mvn hpi:run
21 | ```
22 |
23 | Again, nothing visual changes from step-04-externalize-libs to this plugin.
24 | The only difference is in how it works, specifically in how the default namespaced CSS is auto-loaded and used.
25 |
26 | ## How it works
27 |
28 |
29 |
30 |
31 |
49 |
50 |
51 |
52 |
56 |
57 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/step-06-handlebars-templates/HOW-IT-WORKS.md:
--------------------------------------------------------------------------------
1 | # Step 06 - Handlebars Templates - How it works
2 | In this plugin (`step-06-handlebars-templates`), we build on step-04-externalize-libs,
3 | changing it to apply client-side templates using the [Handlebars] templating engine.
4 |
5 | With this model, we change from the "traditional" pure server-side content rendering approach of Jenkins (in `.jelly` files),
6 | to an approach where just the bare minimum content is rendered server-side, and the reset of the content is rendered on
7 | the client-side e.g. the client-side makes a REST API call to get some data from the server and then applies a template
8 | to that data to produce the view content. This approach is fundamental to creating a more dynamic/slick user experience
9 | (Vs full page reloading etc).
10 |
11 | [Handlebars] is actually quite a tricky package to use with Browserify, especially if registering [Handlebars] helpers
12 | (which most apps need to do). The following sections outline the changes that were made to
13 | step-04-externalize-libs in order for it to use [Handlebars] templates.
14 |
15 | ## Install Handlebars NPM package
16 |
17 | ```sh
18 | $ npm install --save handlebars@3
19 | ```
20 |
21 | Note that we are not goig to be pre-compiling the [Handlebars] templates (see [Handlebarsify]) as doing so would
22 | mean that we would not be able to externalize the [Handlebars] NPM package (due to how [Handlebarsify] references
23 | the [Handlebars] runtime, as well as how helpers work etc).
24 |
25 | ## Externalize the [Handlebars] NPM package
26 | Simply add `handlebars` to the `extDependencies` list in the `package.json` file:
27 |
28 | ```diff
29 | "jenkinscd" : {
30 | - "extDependencies": ["bootstrap-detached", "moment"]
31 | + "extDependencies": ["bootstrap-detached", "handlebars", "moment"]
32 | }
33 | ```
34 |
35 | See step-04-externalize-libs for more on externalizing
36 | NPM dependencies.
37 |
38 | ## Move the form to `form.hbs` (from `JSLibSample/index.jelly`)
39 | Add the [Handlebars] template in [src/main/js/templates/form.hbs](src/main/js/templates/form.hbs). Note the `{{time}}`
40 | token; this will make more sense when we get to the `.js` changes below.
41 |
42 | ```html
43 |
{{time}}
44 |
60 | ```
61 |
62 | Delete the same form content from [JSLibSample/index.jelly](src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly)
63 | and replace with a simple `` holder element; again, this will make more sense when we get to the
64 | `.js` changes below.
65 |
66 | ```diff
67 |
68 |
69 |
Jenkins JS Samples
70 | -
71 | -
87 | +
88 |
89 |
90 | ```
91 |
92 | ## Modify `jslib-samples.js` to use Handlerbars
93 | We modified [jslib-samples.js](src/main/js/jslib-samples.js) to use the `form.hbs` [Handlebars] template, injecting the
94 | Moment.js generated `time` value into the template (remember the `{{time}}` tokens in `form.hbs`).
95 |
96 | ```diff
97 | $('#side-panel').remove();
98 | $('#main-panel').css('margin-left', '0px');
99 |
100 | - // Add some code to use momentjs, adding formatted time text to the page.
101 | - // See src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly.
102 | var moment = require('moment');
103 | - $('#main-panel .time').text(moment().format("MMM Do YY"));
104 | + var handlebars = require('handlebars');
105 | + var formTemplate = handlebars.compile(require('fs')
106 | + .readFileSync(__dirname + '/./templates/form.hbs', 'utf8'));
107 | +
108 | + // Apply the 'form' template, appending the resulting content to
109 | + // the 'form-container' element. We could also define a Handlers helper
110 | + // to handle the formatted time.
111 | + $('#form-container').append(formTemplate({
112 | + time: moment().format("MMM Do YY")
113 | + }));
114 | });
115 | ```
116 |
117 | Note how we use the `fs` (filesystem) package to load the `form.hbs` template. [jenkins-js-builder] handles
118 | this at build time.
119 |
120 |
121 |
124 |
125 | [Handlebars]: http://handlebarsjs.com/
126 | [Handlebarsify]: https://www.npmjs.com/package/handlebarsify
127 | [Node.js]: https://nodejs.org
128 | [Gulp]: https://github.com/gulpjs/gulp
129 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder
130 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules
131 | [jenkins-js-libs]: https://github.com/jenkinsci/js-libs
132 | [CommonJS]: http://www.commonjs.org/
133 | [jquery-detached]: https://github.com/tfennelly/jquery-detached
134 | [bootstrap-detached]: https://github.com/tfennelly/bootstrap-detached
135 | [Browserify]: http://browserify.org/
136 | [bundle]: https://github.com/jenkinsci/js-modules/blob/master/FAQs.md#what-is-the-difference-between-a-module-and-a-bundle
137 |
138 |
--------------------------------------------------------------------------------
/step-06-handlebars-templates/README.md:
--------------------------------------------------------------------------------
1 | # Step 06 - Handlebars Templates
2 | In this plugin (`step-06-handlebars-templates`), we build on step-04-externalize-libs,
3 | changing it to apply client-side templates using the [Handlebars] templating engine.
4 |
5 | With this model, we change from the "traditional" pure server-side content rendering approach of Jenkins (in `.jelly` files),
6 | to an approach where just the bare minimum content is rendered server-side, and the reset of the content is rendered on
7 | the client-side e.g. the client-side makes a REST API call to get some data from the server and then applies a template
8 | to that data to produce the view content. This approach is fundamental to creating a more dynamic/slick user experience
9 | (Vs full page reloading etc).
10 |
11 |
16 |
17 |
18 | ## How to run
19 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin).
20 |
21 | ```sh
22 | $ mvn hpi:run
23 | ```
24 |
25 | Again, nothing visual changes from step-04-externalize-libs to this plugin.
26 | The only difference is in how it works, specifically in how the form content is rendered on the client-side
27 | using [Handlebars] templates.
28 |
29 | ## How it works
30 |
31 |
32 |
33 |
34 |
30 |
31 |
32 |
33 |
34 |
38 |
39 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/step-07-jsdom-tests/README.md:
--------------------------------------------------------------------------------
1 | # Step 07 - jsdom tests
2 | [jsdom] is a JavaScript implementation of the [WHATWG](https://whatwg.org/), DOM and HTML standards. It's quite
3 | useful for writing unit tests.
4 |
5 | In this sample plugin, we modified step-06-handlebars-templates
6 | a little so as the make it a small bit more interactive. We then added a simple unit test that used [jsdom] via [jenkins-js-test].
7 |
8 | > Also see step-08-zombie-tests as an example of how to do Integration Testing.
9 |
10 | ## How to run
11 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin).
12 |
13 | ```sh
14 | $ mvn hpi:run
15 | ```
16 |
17 | After running the plugin you'll see that the form (that was in step-06-handlebars-templates)
18 | has now moved into a Twitter Bootstrap popover.
19 |
20 | 
21 |
22 | ## The test
23 | In this plugin, we want to add a JavaScript unit test to test this page i.e.:
24 |
25 | 1. That the big red button is displayed
26 | 1. That the popover form appears when we click on that button
27 | 1. That the popover form disappears when we click the form "Submit" button
28 |
29 | To install `jenkins-js-test`:
30 |
31 | ```sh
32 | $ npm install --save-dev @jenkins-cd/js-test
33 | ```
34 |
35 | Since this is a maven project, [jenkins-js-builder] looks for the tests in `src/test/js` so that is where we
36 | added the test "spec" file i.e. `src/test/js/jslib-samples-spec.js`. [jenkins-js-builder] uses [Jasmine] to
37 | run all tests ("**/*-spec.js") it finds under the `src/test/js` sub directory.
38 |
39 | [See the test code in jslib-samples-spec.js and read the comments therein](src/test/js/jslib-samples-spec.js).
40 |
41 | ## Running the test
42 | Running the tests from the commandline is easy. Just run `gulp` and that will run the tests too:
43 |
44 | ```sh
45 | $ gulp
46 | ```
47 |
48 | > The `gulp` process also runs as part of the `mvn` build, generating the JavaScript bundle(s) into the generated HPI artifact.
49 |
50 | Running `gulp` should produce an output something like the following:
51 |
52 | ```sh
53 | $ gulp
54 | [16:19:09] Maven project
55 | [16:19:09] - src: src/main/js,src/main/less
56 | [16:19:09] - test: src/test/js
57 | [16:19:09] Setting defaults
58 | [16:19:09] Bundle will be generated in directory 'src/main/webapp/jsbundles' as 'jslib-samples.js'.
59 | [16:19:09] Using gulpfile ~/projects/jenkins-plugins/jenkins-js-samples/step-07-jsdom-tests/gulpfile.js
60 | [16:19:09] Starting 'jshint'...
61 | [16:19:09] - Using default JSHint configuration (in jenkins-js-builder). Override by defining a .jshintrc in this folder.
62 | [16:19:09] Finished 'jshint' after 155 ms
63 | [16:19:09] Starting 'bundle_jslib-samples'...
64 | [16:19:09] Finished 'bundle_jslib-samples' after 391 ms
65 | [16:19:09] Starting 'bundle'...
66 | [16:19:09] Finished 'bundle' after 8.02 μs
67 | [16:19:09] Starting 'test'...
68 | [16:19:09] Testing web server started on port 18999 (http://localhost:18999). Content root: /Users/tfennelly/projects/jenkins-plugins/jenkins-js-samples/step-07-jsdom-tests
69 | [16:19:09] Test execution completed.
70 | [16:19:09] Finished 'test' after 26 ms
71 | [16:19:09] Starting 'default'...
72 | [16:19:09] Finished 'default' after 17 μs
73 | jslib-samples.js
74 | - test ...
75 | Passed
76 | 1 of 1 passed (0 skipped, 0 disabled).
77 | SUCCESS: 1 spec, 0 failures, 0 skipped, 0 disabled in 0.256s.
78 | [16:19:10] Testing web server stopped.
79 | ```
80 |
81 |
82 |
30 |
31 |
32 |
33 |
34 |
38 |
39 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/step-07-jsdom-tests/src/test/js/jslib-samples-spec.js:
--------------------------------------------------------------------------------
1 | var jsTest = require("@jenkins-cd/js-test");
2 |
3 | // This is a Jasmine test that uses the jsdom lib via @jenkins-cd/js-test. @jenkins-cd/js-test
4 | // just wraps up some things and makes jsdom a bit easier to use.
5 |
6 | describe("jslib-samples.js", function () {
7 |
8 | it("- test", function (done) {
9 |
10 | // Create a "fake" page with the same button as is on the real page when the plugin
11 | // is run in Jenkins.
12 | var PAGE = '';
13 |
14 | // "Load" the fake page using @jenkins-cd/js-test. @jenkins-cd/js-test wraps jsdom, but also makes sure
15 | // the environment is reset properly for this test.
16 | jsTest.onPage(function() {
17 | // Load the CommonJS module under test
18 | jsTest.requireSrcModule('jslib-samples.js');
19 |
20 | // Get bootstrap and manually fire events, mimicing user interactions
21 | var bootstrap = require("bootstrap-detached");
22 | var $ = bootstrap.getBootstrap();
23 |
24 | // Make sure the submit-details-go button is not visible
25 | expect($('#submit-details-go').length).toBe(0);
26 |
27 | // Click the submit
28 | $('#submit-details').click();
29 |
30 | // Make sure that the popover with the submit-details-go button
31 | // is visible now
32 | expect($('#submit-details-go').length).toBe(1);
33 |
34 | // Click the submit go button on the popover. It should disappear then.
35 | $('#submit-details-go').click();
36 |
37 | // Make sure the submit-details-go button is no longer visible
38 | expect($('#submit-details-go').length).toBe(0);
39 |
40 | // Calling done tells Jasmine that the test is complete.
41 | done();
42 | }, PAGE);
43 | });
44 | });
--------------------------------------------------------------------------------
/step-08-zombie-tests/README.md:
--------------------------------------------------------------------------------
1 | # Step 08 - Zombie tests
2 | [Zombie] is an "Insanely fast, full-stack, headless browser testing using node.js", making it useful
3 | for integration testing.
4 |
5 | In this sample plugin, we modified step-06-handlebars-templates
6 | a little so as the make it a small bit more interactive. We then added a simple integration test using [Zombie].
7 |
8 | > Also see step-07-jsdom-tests as an example of how to do Unit Testing.
9 |
10 | ## How to run
11 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin).
12 |
13 | ```sh
14 | $ mvn hpi:run
15 | ```
16 |
17 | After running the plugin you'll see that the form (that was in step-06-handlebars-templates)
18 | has now moved into a Twitter Bootstrap popover.
19 |
20 | 
21 |
22 | ## The test
23 | In this plugin, we want to add a JavaScript unit test to test this page i.e.:
24 |
25 | 1. That the big red button is displayed
26 | 1. That the popover form appears when we click on that button
27 | 1. That the popover form disappears when we click the form "Submit" button
28 |
29 | To install `zombie`:
30 |
31 | ```sh
32 | $ npm install --save-dev zombie
33 | ```
34 |
35 | Since this is a maven project, [jenkins-js-builder] looks for the tests in `src/test/js` so that is where we
36 | added the test "spec" file i.e. `src/test/js/jslib-samples-spec.js`. [jenkins-js-builder] uses [Jasmine] to
37 | run all tests ("**/*-spec.js") it finds under the `src/test/js` sub directory.
38 |
39 | [See the test code in jslib-samples-spec.js and read the comments therein](src/test/js/jslib-samples-spec.js).
40 |
41 | ## Running the test
42 | Running the tests from the commandline is easy. Just run `gulp` and that will run the tests too:
43 |
44 | ```sh
45 | $ gulp
46 | ```
47 |
48 | > The `gulp` process also runs as part of the `mvn` build, generating the JavaScript bundle(s) into the generated HPI artifact.
49 |
50 | Running `gulp` should produce an output something like the following:
51 |
52 | ```sh
53 | $ gulp
54 | [13:57:00] Maven project
55 | [13:57:00] - src: src/main/js,src/main/less
56 | [13:57:00] - test: src/test/js
57 | [13:57:00] Setting defaults
58 | [13:57:00] Bundle will be generated in directory 'src/main/webapp/jsbundles' as 'jslib-samples.js'.
59 | [13:57:00] Using gulpfile ~/projects/jenkins-plugins/jenkins-js-samples/step-08-zombie-tests/gulpfile.js
60 | [13:57:00] Starting 'jshint'...
61 | [13:57:00] - Using default JSHint configuration (in jenkins-js-builder). Override by defining a .jshintrc in this folder.
62 | [13:57:00] Finished 'jshint' after 169 ms
63 | [13:57:00] Starting 'bundle_jslib-samples'...
64 | [13:57:00] Starting 'bundle_jslib-samples_no_imports'...
65 | [13:57:01] Finished 'bundle_jslib-samples' after 1.19 s
66 | [13:57:01] Finished 'bundle_jslib-samples_no_imports' after 1.11 s
67 | [13:57:01] Starting 'bundle'...
68 | [13:57:01] Finished 'bundle' after 7.94 μs
69 | [13:57:01] Starting 'test'...
70 | [13:57:01] Testing web server started on port 18999 (http://localhost:18999). Content root: /Users/tfennelly/projects/jenkins-plugins/jenkins-js-samples/step-08-zombie-tests
71 | [13:57:01] Test execution completed.
72 | [13:57:01] Finished 'test' after 61 ms
73 | [13:57:01] Starting 'default'...
74 | [13:57:01] Finished 'default' after 7.36 μs
75 | step 08 - zombie headless browser test
76 | - basic test ...
77 | zombie Opened window http://localhost:18999/src/test/js/testpage.html +0ms
78 | zombie GET http://localhost:18999/src/test/js/testpage.html => 200 +34ms
79 | zombie Loaded document http://localhost:18999/src/test/js/testpage.html +24ms
80 | zombie GET http://localhost:18999/src/main/webapp/jsbundles/no_imports/jslib-samples.js => 200 +11ms
81 | zombie Event loop is empty +100ms
82 | zombie Event loop is empty +33ms
83 | zombie Event loop is empty +6ms
84 | Passed
85 | 1 of 1 passed (0 skipped, 0 disabled).
86 | SUCCESS: 1 spec, 0 failures, 0 skipped, 0 disabled in 0.25s.
87 | [13:57:02] Testing web server stopped.
88 | ```
89 |
90 | ## So what happened?
91 | The test relies on the fact that [jenkins-js-builder] automatically runs a test web server on port `18999`, with its
92 | content root being the `cwd` of the build run i.e. the root of the maven project. See the console output above i.e.
93 |
94 | ```sh
95 | [13:57:01] Testing web server started on port 18999 (http://localhost:18999). Content root: /Users/tfennelly/projects/jenkins-plugins/jenkins-js-samples/step-08-zombie-tests
96 | ```
97 |
98 | The test spec file ([jslib-samples-spec.js](src/test/js/jslib-samples-spec.js)) uses this and [Zombie] to load a test HTML
99 | page ([testpage.html](src/test/js/testpage.html)). This test page contains the same `