Skip to content

Commit 975477f

Browse files
committed
jquery plugin and tests, fixes #7
You need to call "grunt test:remote" now rather than "grunt intern:remote", and that will do the test build, run the intern tests, and then delete the test build.
1 parent d245b0b commit 975477f

19 files changed

+518
-5
lines changed

Gruntfile.js

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,19 @@ module.exports = function (grunt) {
5656
reporters: ["runner"]
5757
}
5858
}
59+
},
60+
61+
clean: {
62+
// Delete files created by the "testBuild" target.
63+
testBuild: [
64+
"tests/functional/jqueryApp/{bower_components,node_modules,build,tmp}",
65+
"tests/jquery.js" // work around grunt-amd-build bug where it puts files outside of tmp/ dir
66+
]
5967
}
6068
});
6169

6270
// These plugins provide necessary tasks.
71+
grunt.loadNpmTasks("grunt-contrib-clean");
6372
grunt.loadNpmTasks("grunt-contrib-jshint");
6473
grunt.loadNpmTasks("grunt-jsbeautifier");
6574
grunt.loadNpmTasks("grunt-lineending");
@@ -73,6 +82,90 @@ module.exports = function (grunt) {
7382
grunt.registerTask("lint", ["jsbeautifier", "lineending", "jshint"]);
7483

7584
// Travis build
76-
grunt.registerTask("travis", ["jshint", "intern:remote"]);
85+
grunt.registerTask("travis", ["jshint", "test:remote"]);
86+
87+
grunt.registerTask("testBuild", "Run the builds used by the functional tests", function () {
88+
var done = this.async();
89+
90+
var appRootDir = "tests/functional/jqueryApp";
91+
92+
function npmInstall(error, bowerResults) {
93+
if (error !== null) {
94+
grunt.log.writeln(bowerResults.stdout);
95+
done(error);
96+
return;
97+
}
98+
grunt.util.spawn({
99+
cmd: "npm",
100+
args: ["install"],
101+
opts: {
102+
cwd: appRootDir
103+
}
104+
}, startBuild);
105+
}
106+
107+
function startBuild(error, npmResults) {
108+
if (error !== null) {
109+
grunt.log.writeln(npmResults.stdout);
110+
done(error);
111+
return;
112+
}
113+
grunt.util.spawn({
114+
cmd: "grunt",
115+
args: ["build"],
116+
opts: {
117+
cwd: appRootDir
118+
}
119+
}, done.bind(null, true));
120+
}
121+
122+
grunt.util.spawn({
123+
cmd: "bower",
124+
args: ["install"],
125+
opts: {
126+
cwd: appRootDir
127+
}
128+
}, npmInstall);
129+
});
130+
131+
// Testing.
132+
// Always specify the target e.g. grunt test:remote, grunt test:remote
133+
// then add on any other flags afterwards e.g. console, lcovhtml.
134+
var testTaskDescription = "Run this task instead of the intern task directly! \n" +
135+
"Always specify the test target e.g. \n" +
136+
"grunt test:local\n" +
137+
"grunt test:remote\n\n" +
138+
"Add any optional reporters via a flag e.g. \n" +
139+
"grunt test:local:console\n" +
140+
"grunt test:local:lcovhtml\n" +
141+
"grunt test:local:console:lcovhtml";
142+
grunt.registerTask("test", testTaskDescription, function (target) {
143+
function addReporter(reporter) {
144+
var property = "intern." + target + ".options.reporters",
145+
value = grunt.config.get(property);
146+
if (value.indexOf(reporter) !== -1) {
147+
return;
148+
}
149+
value.push(reporter);
150+
grunt.config.set(property, value);
151+
}
152+
153+
if (this.flags.lcovhtml) {
154+
addReporter("lcovhtml");
155+
}
156+
157+
if (this.flags.console) {
158+
addReporter("console");
159+
}
160+
161+
// First create the test builds. These are referenced from the intern tests.
162+
grunt.task.run("testBuild");
163+
164+
// Then run the intern tests.
165+
grunt.task.run("intern:" + target);
166+
167+
// Finally, delete the test builds so that they don't show up in "git status" as "untracked files".
168+
grunt.task.run("clean:testBuild");
169+
});
77170

78171
};

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Set of AMD plugins for RequireJS. It contains the following plugins:
44

55
* [has](#has)
66
* [i18n](#i18n)
7+
* [jquery](#jquery)
78
* [maybe](#maybe)
89

910
## Status
@@ -28,6 +29,7 @@ This project requires the following other project to run:
2829
_Bower_ release installation:
2930

3031
$ bower install requirejs-dplugins
32+
$ bower install jquery (if you are using the jquery plugin)
3133

3234
_Manual_ master installation:
3335

@@ -49,6 +51,11 @@ This plugin provides provides an API to handle string translation.
4951

5052
See [docs/i18n.md](./docs/i18n.md) and [samples/i18n.html](./samples/i18n.html) for documentation and sample.
5153

54+
## jquery
55+
This plugin loads the specified jquery modules if they are not loaded already.
56+
57+
See [docs/jquery.md](./docs/jquery.md) for documentation.
58+
5259
## maybe
5360
This plugin allows to require modules that may or may not exist.
5461

bower.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
"dojo": ">=1.9.1",
77
"requirejs": "2.1.x"
88
},
9+
"devDependencies": {
10+
"jquery": ">=2.1"
11+
},
912
"keywords": [
1013
"requirejs",
1114
"amd",
@@ -22,4 +25,4 @@
2225
"Gruntfile.js",
2326
"package.json"
2427
]
25-
}
28+
}

docs/jquery.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
layout: default
3+
title: requirejs-dplugins/jquery
4+
---
5+
6+
# requirejs-dplugins/jquery!
7+
8+
9+
This plugin will load load the specified jQuery module(s), unless the application has loaded the whole jQuery
10+
library via a `<script>` tag, in which case it just returns a pointer to the already loaded jQuery.
11+
12+
It's useful to avoid loading jQuery twice.
13+
14+
When using this plugin, you must manually include jquery into your app via `bower install jquery` or via
15+
a script tag (ex: `<script src="https://code.jquery.com/jquery-2.1.1.min.js">`).
16+
17+
## Example
18+
19+
To get a jQuery object that can modify classes and do animations:
20+
21+
```js
22+
require(["requirejs-dplugins/jquery!attributes/classes,effects"], function ($) {
23+
...
24+
$(myNode).addClass("selected");
25+
$(myNode).animate(...);
26+
});
27+
```

jquery.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Plugin to load specified jQuery module(s), unless the application has loaded the whole jQuery
3+
* library via a `<script>` tag, in which case it just returns a pointer to the already loaded jQuery.
4+
* Useful to avoid loading jQuery twice.
5+
*
6+
* @example:
7+
* To get a jQuery object that can modify classes and do animations:
8+
* ```
9+
* require(["requirejs-dplugins/jquery!attributes/classes,effects"], function ($){
10+
* ...
11+
* $(myNode).addClass("selected");
12+
* $(myNode).animate(...);
13+
* });
14+
* ```
15+
*
16+
* @module requirejs-dplugins/jquery
17+
*/
18+
19+
define([], function () {
20+
21+
// This is modifying and using the global require() configuration. Is there a better way?
22+
// I tried using a local require but it doesn't have a config() method.
23+
require.config({
24+
map: {
25+
jquery: {
26+
"jquery/src/selector": "jquery/src/selector-native" // don't pull in sizzle
27+
}
28+
}
29+
});
30+
31+
// Convert abbreviated list of jQuery modules to real list of jQuery modules
32+
// 1. Always include jquery/core since some modules like jquery/attributes/classes don't return
33+
// anything.
34+
// 2. Fix paths to modules by prefixing each module name with jQuery/src. The "src" directoy
35+
// is to match the directory structure in the jQuery installed via bower.
36+
//
37+
// Ex: "attributes/classes,effects" --> ["jquery/src/core", "jquery/src/attributes/classes", "jquery/src/effects"]
38+
function getModules(str) {
39+
return ["core"].concat(str.split(/, */)).map(function (amid) {
40+
return "jquery/src/" + amid;
41+
});
42+
}
43+
44+
return {
45+
normalize: function (resource) {
46+
// Don't do any normalization here; it's done when getModules() is called.
47+
return resource;
48+
},
49+
50+
load: function (resource, req, onLoad, config) {
51+
/* global jQuery */
52+
/* global $ */
53+
if (config.isBuild) {
54+
onLoad();
55+
} else if (typeof jQuery !== "undefined") {
56+
onLoad(jQuery);
57+
} else if (typeof $ !== "undefined") {
58+
onLoad($);
59+
} else {
60+
require(getModules(resource), function ($) {
61+
onLoad($);
62+
});
63+
}
64+
},
65+
66+
// Interface for grunt-amd-build. If the application doesn't want jQuery in the layer it should exclude
67+
// it through directives to grunt-amd-build.
68+
addModules: function (pluginName, resource, addModules) {
69+
addModules(getModules(resource));
70+
}
71+
};
72+
});

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"description": "AMD plugins for RequireJS",
55
"devDependencies": {
66
"grunt": "~0.4.1",
7+
"grunt-contrib-clean": "0.6.x",
78
"grunt-contrib-jshint": "~0.6.0",
89
"grunt-jsbeautifier": "~0.2.2",
910
"requirejs": "~2.1.10",

tests/functional/all.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Listing of all the plugin functional tests
2+
define([
3+
"./jqueryBuild",
4+
"./jqueryScript"
5+
]);

tests/functional/jqueryApp/.bowerrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"directory": "bower_components"
3+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Gruntfile for building layer including src.js and the jquery modules it references
2+
module.exports = function (grunt) {
3+
"use strict";
4+
5+
grunt.loadNpmTasks("grunt-contrib-clean");
6+
grunt.loadNpmTasks("grunt-contrib-copy");
7+
grunt.loadNpmTasks("grunt-contrib-concat");
8+
grunt.loadNpmTasks("grunt-amd-build");
9+
10+
var outprop = "amdoutput";
11+
var outdir = "./build/";
12+
var tmpdir = "./tmp/";
13+
14+
var common = {
15+
options: { banner: "<%= " + outprop + ".header%>" },
16+
src: "<%= " + outprop + ".modules.abs %>",
17+
dest: outdir + "<%= " + outprop + ".layerPath %>"
18+
};
19+
20+
grunt.initConfig({
21+
amdloader: {
22+
baseUrl: ".",
23+
24+
paths: {
25+
jquery: "bower_components/jquery",
26+
"requirejs-dplugins": "../../.."
27+
},
28+
29+
// Unfortunately this is needed for the jquery plugin.
30+
// It's automatically handled by the plugin itself at runtime, but not during builds.
31+
map: {
32+
"*": {
33+
"jquery/src/selector": "jquery/src/selector-native"
34+
}
35+
}
36+
},
37+
38+
amdbuild: {
39+
dir: tmpdir,
40+
41+
// List of layers to build.
42+
layers: [
43+
// Test build for jquery plugin. Should contain main test js file and a few jquery modules.
44+
{
45+
name: "app",
46+
include: [
47+
// Modules and layers listed here, and their dependencies, will be added to the layer.
48+
"src"
49+
]
50+
}
51+
]
52+
},
53+
54+
// Config to allow to concatenate files to generate the layer.
55+
concat: {
56+
options: {
57+
banner: "<%= " + outprop + ".header%>",
58+
sourceMap: true
59+
},
60+
dist: {
61+
src: "<%= " + outprop + ".modules.abs %>",
62+
dest: outdir + "<%= " + outprop + ".layerPath %>"
63+
}
64+
},
65+
66+
copy: {
67+
plugins: {
68+
expand: true,
69+
cwd: tmpdir,
70+
src: "<%= " + outprop + ".plugins.rel %>",
71+
dest: outdir
72+
}
73+
},
74+
75+
clean: {
76+
out: [outdir],
77+
temp: [tmpdir]
78+
}
79+
});
80+
81+
grunt.registerTask("amdbuild", function (amdloader) {
82+
var name = this.name, layers = grunt.config(name).layers;
83+
layers.forEach(function (layer) {
84+
grunt.task.run("amddepsscan:" + layer.name + ":" + name + ":" + amdloader);
85+
grunt.task.run("amdserialize:" + layer.name + ":" + name + ":" + outprop);
86+
grunt.task.run("concat");
87+
grunt.task.run("copy:plugins");
88+
});
89+
});
90+
grunt.registerTask("build", [
91+
"clean:out",
92+
"clean:temp",
93+
"amdbuild:amdloader"
94+
]);
95+
};

0 commit comments

Comments
 (0)