(deprecated) Easy setup of grunt-based testing/optimization for requirejs-based client javascript.
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
logs
src/server
test
.gitignore
.npmignore
.travis.yml
Gruntfile.js
History.md
LICENSE.txt
README.md
package.json
thehelp-client-project.sublime-project

README.md

Build Status

thehelp-client-project (deprecated)

I don't expect to make any more updates to this project, but by all means continue to use it if it helps you out! Also, let's talk if you'd like to jump in and help maintain it! https://blog.scottnonnenberg.com/the-state-of-thehelp/#thehelp-client-project

Developing client-side javascript with requirejs and testing with mocha? This easy-to-set-up library will streamline your project automation.

Features

  • connect task to serve static files on localhost instead of file:/ URLs, which have different security settings
  • grunt-mocha to run your client-side mocha tests on the command-line via phantomjs
  • grunt-requirejs to concatenate and optimize your AMD-style modules into production javascript files.
  • grunt-saucelabs to run tests on multiple browsers via Sauce Labs
  • 'preamble-for-dist' task to add version number, author, and license information into final distribution files

Setup

First, install the project (and its friend, thehelp-project) as dev dependencies:

npm install thehelp-project thehelp-client-project --save-dev

If you're new to thehelp-project, it would be good to read its docs first. Then make sure you have the grunt command available:

npm install -g grunt-cli

Your Gruntfile

This is the place to start with your Gruntfile:

var GruntConfig = require('thehelp-project').GruntConfig;
require('thehelp-client-project').mixin(GruntConfig);

module.exports = function(grunt) {
  var config = new GruntConfig(grunt);

  config.standardSetup();
  config.standardDefault();
};

Usage

Optimize

These methods give you two easier methods to generate concatenated, optimized javascript files via requirejs:

  • registerOptimize() - Generates a concatenated, optimized file based on AMD modules.
  • registerOptimizeLibrary() - Generates both minified and non-minified concatenated javascript files. Best-suited for generating a library for consumption by others.

This will generate a single, optimized file named 'home.js' under 'dist/js' which does not need requirejs on the page to run, as well as source maps:

config.registerOptimize({
  source: 'src/client/home',
  target: 'dist/js/home_standalone.js',
  standalone: true,
  config: { // these are the options piped directly into requirejs
    baseUrl: './',
    paths: {
      backbone: 'lib/vendor/backbone',
      underscore: 'lib/vendor/underscore'
    }
  }
})

Or, you can generate a file which isn't standalone. Anything in the empty array will not be included in the final file. When your code runs it will still need those packages, so those components must be provided by other files on the page.

config.registerOptimize({
  source: 'src/client/home',
  target: 'dist/js/home.js',
  empty: ['util', 'winston'],
  config: {
    baseUrl: './',
    paths: {
      backbone: 'lib/vendor/backbone',
      underscore: 'lib/vendor/underscore'
    }
  }
})

registerOptimizeLibrary will generate four separate requirejs sub-tasks...

config.registerOptimizeLibrary({
  source: 'src/library',
  target: 'library-name',
  targetPath: 'dist/js',
  standalone: true,
  config: {
    baseUrl: './',
    paths: {
      backbone: 'lib/vendor/backbone',
      underscore: 'lib/vendor/underscore'
    }
  }
})

...resulting in four files:

  • dist/js/library-name.js
  • dist/js/library-name.min.js
  • dist/js/standalone/library-name.js
  • dist/js/standalone/library-name.min.js

The first two files require you to provide a module loader like almond.js or requirejs. The second two include almond.js and can therefore be used with nothing else on the page.

For more information on requirejs configuration see the integration test included in this project (under 'test/default'), and the requirejs documentation:

Add Preamble

Now that you've generated some concatenated and/or optimized files for distribution, you probably want to make sure that people know where the files came from:

config.registerPreambleForDist();
config.registerTask('dist', ['requirejs', 'preamble-for-dist']);

Elements from your package.json will be injected into javascript files under your dist subdirectory. It will also look for a file LICENSE.txt in your project's root directory to include. And you can add comments to various subsets of your dist files with options.comments. More options and details are available at the detailed documentation.

Test

Another two methods make it easy to automate your client-side testing.

  • registerConnect() - Sets up a static file server for testing things on the client (called by standardSetup() so most of the time you won't call this directly)
  • registerMocha() - Uses phantomjs to run mocha tests inside a headless browser.

This is how you might create a 'client-test' task which runs your tests against both your development (using requirejs) and fully optimized standalone files:

config.registerMocha({
  urls: [
    'http://localhost:3001/test/integration/dev.html',
    'http://localhost:3001/test/integration/dist.html'
  ]
});
grunt.registerTask('client-test', ['connect:test', 'mocha']);

The default configuration expects that your tests will start whenever they are ready, and will pipe all console output in the browser to the command line. Take a look at the grunt-mocha documentation to get into the details.

Note: the registered connect:test task runs the server on port 3001. The connect:keepalive task is useful for manual browser-based debugging, and runs on port 3000. This is so you can run grunt test runs while also keeping a server up for your browser-based testing.

Test on multiple browsers

To get your tests running on multiple browers via the Sauce Labs service, first set two environment variables with information about your account. thehelp-project prefers to put them in 'env.json' in your project's root directory:

{
  "SAUCE_USERNAME": "your_username",
  "SAUCE_ACCESS_KEY": "your_key"
}

It's likely that you don't want to deploy your files to a publically-accessible server every new build for Sauce Labs, so they've provided Sauce Labs Connect. It opens a secure tunnel to your machine, giving their services access to ports on your machine. Yes, they take security seriously - they get into the details on the download page.

Once you've got those two things in place, a lot of defaults have been provided for you. This will set things up to run on a minimum set of browsers with reasonable coverage:

config.registerSauce({
  urls: [
    'http://localhost:3001/test/integration/dist.html'
  ]
});
grunt.registerTask('cross-browser', ['connect:test', 'sauce']);

Various browser subsets are available via config.saucePlatforms: iOS, chrome, internetExplorer, etc. (complete list of browser subsets). Just set the browsers key of the options you pass to registerSauce(). Check out the additional configuration available at the...

Detailed Documentation

Detailed docs be found at this project's GitHub Pages, thanks to groc: http://thehelp.github.io/client-project/src/server/mixin.html

Contributing changes

The comprehensive integration test under 'test/default' will be your friend. ./run.sh and ./clean.sh will test most of it, but you'll want to visually inspect the dist/js files to ensure that the 'preamble-for-dist' task is doing what it should. The 'cross-browser' task will verify that Sauce Labs integration is still working - you'll need to put your Sauce Labs account information in an env.json file in that directory.

When you have some changes ready, please submit a pull request with:

  • Justification - why is this change worthwhile? Link to issues, use code samples, etc.
  • Documentation changes for your code updates. Be sure to check the groc-generated HTML with grunt doc
  • A description of how you tested the change. Don't forget about the very-useful npm link command :0)

I may ask you to use a git rebase to ensure that your commits are not interleaved with commits already in the history. And of course, make sure grunt completes successfully. :0)

License

(The MIT License)

Copyright (c) 2014 Scott Nonnenberg <scott@nonnenberg.com>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.