ModularPatternBasics
Overview
Learn the basics of how to use the modular pattern. It is likely that many of the projects we create this quarter will follow this basic pattern. So make a note of this project so you can find it again later as it lays out several patterns that we are likely to use over and over.
You are learning three things:
- How to set up the elf object
- How to use the modular pattern, which provides public, private and instance methods.
- How to test code of this type.
Step 01: Create Project
Make sure you have the latest from JsObjects:
cd $JSOBJECTS
git pull
Navigate to your repository and create a project with the scripts already setup in the Pristine Lubuntu ~/bin directory:
CreateAllExpress Week01-ModularPattern
Step 02: Check Setup
Run the following command in the root of your project directory:
check-karma-grunt-config > CheckSetup.txt
This pipes the output from check-karma-grunt-config into a text file. If you open the text file in an editor it will look odd, but you can view it properly with the following command:
cat CheckSetup
All the checks should be green. You should add this file to your repository so I can view it when I pull your work down.
Handle this command the same way you did CheckSetup:
karma start --single-run > TestResults.txt
Also run grunt check now, and once again before you turn in the project. Make sure it comes back clean.
Step03: Setup elf Object Failing Test
Add the following test to the Elvenware Simple Plain Suite in spec/test-basic:
it('expects the elf object to exist', function() {
expect(elf).toBeDefined();
});
Save the results of a single-run test to TestResults02.txt:
karma start --single-run > TestResults02.txt
I’m looking for the failed result. This test should fail. Our mantra is:
- Red, Green, Refactor
- Write a failing test
- Make the test pass
- Do any refactoring necessary to clean up our code
Step 04: Setup elf Object
Create a file called public/javascript/my-object.js. Put the following content in it:
var elf = {};
Run your test and place your results RestResult03:
karma start --single-run > TestResults03.txt
If you run cat TestResults03.txt you should see that two tests passed.
NOTE: You don’t have to pipe the output into a text file the first time you run a test. You can just send the output to standard out until you get the results you want, and then pipe them into a file. Before piping the content into a file you can treat single-run as an option that you can use or not use, as needed. In other words, any of these options would work, depending on your taste:
npm test
karma start
karma start --single-run
To see all the karma start options, type karma start –help,, like this:
$ karma start --help
Karma - Spectacular Test Runner for JavaScript.
START - Start the server / do a single run.
Usage:
/home/charlie/npm/bin/karma start [<configFile>] [<options>]
Options:
--port <integer> Port where the server is running.
--auto-watch Auto watch source files and run on change.
--no-auto-watch Do not watch source files.
--log-level <disable | error | warn | info | debug> Level of logging.
--colors Use colors when reporting and printing logs.
--no-colors Do not use colors when reporting or printing logs.
--reporters List of reporters (available: dots, progress, junit, growl, coverage).
--browsers List of browsers to start (eg. --browsers Chrome,ChromeCanary,Firefox).
--capture-timeout <integer> Kill browser if does not capture in given time [ms].
--single-run Run the test when browsers captured and exit.
--no-single-run Disable single-run.
--report-slower-than <integer> Report tests that are slower than given time [ms].
--help Print usage and options.
Step 05: Test for elf.initialize
Let’s write two tests this time:
it('expects to find an elf.initialize to be defined', function() {
expect(elf.initialize).toBeDefined();
});
it('expects to find an elf.initialize method', function() {
expect(typeof elf.initialize).toBe('function');
});
Show me the failing results:
karma start --single-run > TestResults04.txt
Step 06: Create the initialize method
Implement the method in my-object.js:
var elf = {
initialize: function() {}
};
And you guessed it:
karma start --single-run > TestResults05.txt
Step 07: Create MyObject Failing Test
Do this:
bower install jasmine-jquery --save
Make sure the Jasmine Jquery path is right in karma.conf.js:
files: [
'public/components/jquery/dist/jquery.min.js',
'public/components/jasmine-jquery/lib/*.js',
'public/javascripts/*.js',
'spec/**/*.html',
'spec/test*.js'
],
Then create your fixture:
grunt fixture
The test:
it('expects to elf.MyObject to be defined', function() {
expect(elf.MyObject).toBeDefined();
});
Show that it fails:
karma start --single-run > TestResults06.txt
Step 08: Create MyObject
The implementation:
In my-object.js:
var elf = {
initialize: function() {
new elf.MyObject();
}
};
elf.MyObject = (function() {
function MyObject() {}
return MyObject;
}());
In control.js:
$(document).ready(function() {
'use strict';
elf.initialize();
});
And now exclude control.js from the list of files loaded in karma.conf.js:
// list of files to exclude
exclude: ['public/javascripts/control.js'],
Show that the test works:
karma start --single-run > TestResults07.txt
Step09: Test Interface
Set up your fixture so we can test the interface:
grunt fixture
Open spec/fixtures/fixture.html to make sure it worked.
Load the fixture near the top of test-basic:
beforeEach(function() {
jasmine.getFixtures().fixturesPath = 'base/spec/fixtures/';
loadFixtures('fixture.html');
});
And put these near the bottom:
it('expects to elf.myObject to be defined', function() {
elf.initialize();
expect(elf.myObject).toBeDefined();
});
it('shows that clicking the button calls MyObject.runMyObject', function() {
spyOn(elf.MyObject.prototype, 'runMyObject');
elf.initialize();
$('#runMyObject').trigger('click');
expect(elf.MyObject.prototype.runMyObject).toHaveBeenCalled();
});
And then record the failing results:
karma start --single-run > TestResults08.txt
Step10: Create Interface
We want to create an interface like this, where the text shown near the bottom appears when we click the button:
In views/index.jade:
extends layout
block content
h1= title
p Welcome to #{title}
button#runMyObject Run My Object
pre#displayArea
In layout.jade, make sure you load my-object.js. In routes/index.js, set the title to include your last name.
In my-object.js setup the button click event handler:
var elf = {
initialize: function() {
elf.myObject = new elf.MyObject();
}
};
elf.MyObject = (function() {
function MyObject() {
$('#runMyObject').click(this.runMyObject);
}
MyObject.prototype.runMyObject = function() {
$('#displayArea').html('MyObject is running');
};
return MyObject;
}());
Then pipe the results into TestResults09.txt. It should look something like this:
$ karma start --single-run
08 01 2016 20:28:32.692:INFO [karma]: Karma v0.13.19 server started at http://localhost:9876/
08 01 2016 20:28:32.696:INFO [launcher]: Starting browser PhantomJS
08 01 2016 20:28:32.851:INFO [PhantomJS 1.9.8 (Linux 0.0.0)]: Connected on socket /#-yyI6MdjGv8s2LE4AAAA with id 73142100
Elvenware Simple Plain Suite
✓ expects true to be true
✓ expects the elf object to exist
✓ expects to find an elf.initialize to be defined
✓ expects to find an elf.initialize method
✓ expects to elf.MyObject to be defined
✓ expects to elf.myObject to be defined
✓ shows that clicking the button calls MyObject.runMyObject
PhantomJS 1.9.8 (Linux 0.0.0): Executed 7 of 7 SUCCESS (0.041 secs / 0.008 secs)
TOTAL: 7 SUCCESS
Turn it in
Submit your code in the appropriate folder of your repository. Make sure TestResults01.txt - TestResults09.txt are included. Also, make sure the code works when you run it.