45 changed files with 33657 additions and 0 deletions
Split View
Diff Options
-
21d3-ex1/LICENSE.txt
-
11d3-ex1/README.md
-
73d3-ex1/karma.conf.js
-
10253d3-ex1/lib/jquery-3.2.1.js
-
270d3-ex1/mocha.css
-
1571d3-ex1/package-lock.json
-
26d3-ex1/package.json
-
5332d3-ex1/test-lib/chai.js
-
6472d3-ex1/test-lib/mocha.js
-
30d3-ex1/test.html
-
109d3-ex1/tests.js
-
54d3-ex1/utils.js
-
3d3-ex2/.bowerrc
-
43d3-ex2/.gitignore
-
28d3-ex2/Chrome_86.0.4240_(Linux_0.0.0)/test/results/unit/test-results.xml
-
33d3-ex2/Gruntfile.js
-
202d3-ex2/LICENSE
-
88d3-ex2/README.md
-
24d3-ex2/app/index.html
-
43d3-ex2/app/scripts/controllers/math.js
-
5d3-ex2/app/scripts/main.js
-
52d3-ex2/app/scripts/services/math.js
-
38d3-ex2/app/scripts/services/tools.js
-
20d3-ex2/bower.json
-
21d3-ex2/build/grunt-tasks/connect.js
-
30d3-ex2/build/grunt-tasks/test.js
-
4703d3-ex2/package-lock.json
-
60d3-ex2/package.json
-
64d3-ex2/test/config/karma.conf.js
-
29d3-ex2/test/config/karma.coverage.conf.js
-
15d3-ex2/test/config/karma.unit.conf.js
-
18d3-ex2/test/config/mocha-globals.js
-
1d3-ex2/test/specs/unit/main.js
-
104d3-ex2/test/specs/unit/services/math.spec.js
-
76d3-ex2/test/specs/unit/services/tools.spec.js
-
3d3-ex3/.gitignore
-
23d3-ex3/README.md
-
31d3-ex3/bin/postinstall.js
-
18d3-ex3/bin/preinstall.js
-
77d3-ex3/karma.conf.js
-
3275d3-ex3/package-lock.json
-
45d3-ex3/package.json
-
26d3-ex3/packagejson.old
-
68d3-ex3/src/main/webapp/app/sample.js
-
169d3-ex3/src/test/sampleTest.js
@ -0,0 +1,21 @@ |
|||
The MIT License (MIT) |
|||
|
|||
Copyright (c) 2015 Ludovico Fischer |
|||
|
|||
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. |
|||
@ -0,0 +1,11 @@ |
|||
A demo setup for unit testing client-side JavaScript code with [Mocha.js](http://mochajs.org/) and [Chai.js](http://chaijs.com/). |
|||
|
|||
Since mocha 1.2, you can install mocha via npm and run `mocha init <path>` to generate a client side testing skeleton. |
|||
|
|||
## Automated in-browser tests with Karma |
|||
|
|||
This sample also includes a [Karma](http://karma-runner.github.io/) configuration to run the tests automatically. |
|||
|
|||
To use Karma, you need to have [node.js](http://nodejs.org) and [npm](https://npmjs.org/) installed. In the project directory, type `npm install karma-mocha`. After the Karma install finishes, type `node_modules/karma/bin/karma start` and navigate to `http://localhost:9876` to let Karma capture the web browser and run the tests automatically. |
|||
|
|||
If you are familiar with `npm`, you can look at the `package.json`. That configuration allows you to just type `npm install` and then `npm test` to start the Karma server. Since the karma NPM package does not define a `bin` field, we must make use of the `karma-cli` package to be able to use the karma executable inside our `test` script. |
|||
@ -0,0 +1,73 @@ |
|||
// Karma configuration
|
|||
// Generated on Tue Sep 02 2014 23:03:20 GMT+0200 (CEST)
|
|||
|
|||
module.exports = function(config) { |
|||
config.set({ |
|||
|
|||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
|||
basePath: '', |
|||
|
|||
|
|||
// frameworks to use
|
|||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
|||
frameworks: ['mocha'], |
|||
|
|||
|
|||
// list of files / patterns to load in the browser
|
|||
files: [ |
|||
'lib/*.js', |
|||
'test-lib/*.js', |
|||
'utils.js', |
|||
'tests.js' |
|||
], |
|||
|
|||
plugins: [ |
|||
'karma-chrome-launcher', |
|||
'karma-mocha' |
|||
], |
|||
|
|||
|
|||
// list of files to exclude
|
|||
exclude: [ |
|||
], |
|||
|
|||
|
|||
// preprocess matching files before serving them to the browser
|
|||
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
|||
preprocessors: { |
|||
}, |
|||
|
|||
|
|||
// test results reporter to use
|
|||
// possible values: 'dots', 'progress'
|
|||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
|||
reporters: ['progress'], |
|||
|
|||
|
|||
// web server port
|
|||
port: 9876, |
|||
|
|||
|
|||
// enable / disable colors in the output (reporters and logs)
|
|||
colors: true, |
|||
|
|||
|
|||
// level of logging
|
|||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
|||
logLevel: config.LOG_INFO, |
|||
|
|||
|
|||
// enable / disable watching file and executing tests whenever any file changes
|
|||
autoWatch: true, |
|||
|
|||
|
|||
// start these browsers
|
|||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
|||
browsers: ['Chrome'], |
|||
|
|||
|
|||
// Continuous Integration mode
|
|||
// if true, Karma captures browsers, runs the tests and exits
|
|||
singleRun: false |
|||
}); |
|||
}; |
|||
10253
d3-ex1/lib/jquery-3.2.1.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,270 @@ |
|||
@charset "utf-8"; |
|||
|
|||
body { |
|||
margin:0; |
|||
} |
|||
|
|||
#mocha { |
|||
font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; |
|||
margin: 60px 50px; |
|||
} |
|||
|
|||
#mocha ul, |
|||
#mocha li { |
|||
margin: 0; |
|||
padding: 0; |
|||
} |
|||
|
|||
#mocha ul { |
|||
list-style: none; |
|||
} |
|||
|
|||
#mocha h1, |
|||
#mocha h2 { |
|||
margin: 0; |
|||
} |
|||
|
|||
#mocha h1 { |
|||
margin-top: 15px; |
|||
font-size: 1em; |
|||
font-weight: 200; |
|||
} |
|||
|
|||
#mocha h1 a { |
|||
text-decoration: none; |
|||
color: inherit; |
|||
} |
|||
|
|||
#mocha h1 a:hover { |
|||
text-decoration: underline; |
|||
} |
|||
|
|||
#mocha .suite .suite h1 { |
|||
margin-top: 0; |
|||
font-size: .8em; |
|||
} |
|||
|
|||
#mocha .hidden { |
|||
display: none; |
|||
} |
|||
|
|||
#mocha h2 { |
|||
font-size: 12px; |
|||
font-weight: normal; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
#mocha .suite { |
|||
margin-left: 15px; |
|||
} |
|||
|
|||
#mocha .test { |
|||
margin-left: 15px; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
#mocha .test.pending:hover h2::after { |
|||
content: '(pending)'; |
|||
font-family: arial, sans-serif; |
|||
} |
|||
|
|||
#mocha .test.pass.medium .duration { |
|||
background: #c09853; |
|||
} |
|||
|
|||
#mocha .test.pass.slow .duration { |
|||
background: #b94a48; |
|||
} |
|||
|
|||
#mocha .test.pass::before { |
|||
content: '✓'; |
|||
font-size: 12px; |
|||
display: block; |
|||
float: left; |
|||
margin-right: 5px; |
|||
color: #00d6b2; |
|||
} |
|||
|
|||
#mocha .test.pass .duration { |
|||
font-size: 9px; |
|||
margin-left: 5px; |
|||
padding: 2px 5px; |
|||
color: #fff; |
|||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); |
|||
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); |
|||
box-shadow: inset 0 1px 1px rgba(0,0,0,.2); |
|||
-webkit-border-radius: 5px; |
|||
-moz-border-radius: 5px; |
|||
-ms-border-radius: 5px; |
|||
-o-border-radius: 5px; |
|||
border-radius: 5px; |
|||
} |
|||
|
|||
#mocha .test.pass.fast .duration { |
|||
display: none; |
|||
} |
|||
|
|||
#mocha .test.pending { |
|||
color: #0b97c4; |
|||
} |
|||
|
|||
#mocha .test.pending::before { |
|||
content: '◦'; |
|||
color: #0b97c4; |
|||
} |
|||
|
|||
#mocha .test.fail { |
|||
color: #c00; |
|||
} |
|||
|
|||
#mocha .test.fail pre { |
|||
color: black; |
|||
} |
|||
|
|||
#mocha .test.fail::before { |
|||
content: '✖'; |
|||
font-size: 12px; |
|||
display: block; |
|||
float: left; |
|||
margin-right: 5px; |
|||
color: #c00; |
|||
} |
|||
|
|||
#mocha .test pre.error { |
|||
color: #c00; |
|||
max-height: 300px; |
|||
overflow: auto; |
|||
} |
|||
|
|||
/** |
|||
* (1): approximate for browsers not supporting calc |
|||
* (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border) |
|||
* ^^ seriously |
|||
*/ |
|||
#mocha .test pre { |
|||
display: block; |
|||
float: left; |
|||
clear: left; |
|||
font: 12px/1.5 monaco, monospace; |
|||
margin: 5px; |
|||
padding: 15px; |
|||
border: 1px solid #eee; |
|||
max-width: 85%; /*(1)*/ |
|||
max-width: calc(100% - 42px); /*(2)*/ |
|||
word-wrap: break-word; |
|||
border-bottom-color: #ddd; |
|||
-webkit-border-radius: 3px; |
|||
-webkit-box-shadow: 0 1px 3px #eee; |
|||
-moz-border-radius: 3px; |
|||
-moz-box-shadow: 0 1px 3px #eee; |
|||
border-radius: 3px; |
|||
} |
|||
|
|||
#mocha .test h2 { |
|||
position: relative; |
|||
} |
|||
|
|||
#mocha .test a.replay { |
|||
position: absolute; |
|||
top: 3px; |
|||
right: 0; |
|||
text-decoration: none; |
|||
vertical-align: middle; |
|||
display: block; |
|||
width: 15px; |
|||
height: 15px; |
|||
line-height: 15px; |
|||
text-align: center; |
|||
background: #eee; |
|||
font-size: 15px; |
|||
-moz-border-radius: 15px; |
|||
border-radius: 15px; |
|||
-webkit-transition: opacity 200ms; |
|||
-moz-transition: opacity 200ms; |
|||
transition: opacity 200ms; |
|||
opacity: 0.3; |
|||
color: #888; |
|||
} |
|||
|
|||
#mocha .test:hover a.replay { |
|||
opacity: 1; |
|||
} |
|||
|
|||
#mocha-report.pass .test.fail { |
|||
display: none; |
|||
} |
|||
|
|||
#mocha-report.fail .test.pass { |
|||
display: none; |
|||
} |
|||
|
|||
#mocha-report.pending .test.pass, |
|||
#mocha-report.pending .test.fail { |
|||
display: none; |
|||
} |
|||
#mocha-report.pending .test.pass.pending { |
|||
display: block; |
|||
} |
|||
|
|||
#mocha-error { |
|||
color: #c00; |
|||
font-size: 1.5em; |
|||
font-weight: 100; |
|||
letter-spacing: 1px; |
|||
} |
|||
|
|||
#mocha-stats { |
|||
position: fixed; |
|||
top: 15px; |
|||
right: 10px; |
|||
font-size: 12px; |
|||
margin: 0; |
|||
color: #888; |
|||
z-index: 1; |
|||
} |
|||
|
|||
#mocha-stats .progress { |
|||
float: right; |
|||
padding-top: 0; |
|||
} |
|||
|
|||
#mocha-stats em { |
|||
color: black; |
|||
} |
|||
|
|||
#mocha-stats a { |
|||
text-decoration: none; |
|||
color: inherit; |
|||
} |
|||
|
|||
#mocha-stats a:hover { |
|||
border-bottom: 1px solid #eee; |
|||
} |
|||
|
|||
#mocha-stats li { |
|||
display: inline-block; |
|||
margin: 0 5px; |
|||
list-style: none; |
|||
padding-top: 11px; |
|||
} |
|||
|
|||
#mocha-stats canvas { |
|||
width: 40px; |
|||
height: 40px; |
|||
} |
|||
|
|||
#mocha code .comment { color: #ddd; } |
|||
#mocha code .init { color: #2f6fad; } |
|||
#mocha code .string { color: #5890ad; } |
|||
#mocha code .keyword { color: #8a6343; } |
|||
#mocha code .number { color: #2f6fad; } |
|||
|
|||
@media screen and (max-device-width: 480px) { |
|||
#mocha { |
|||
margin: 60px 0px; |
|||
} |
|||
|
|||
#mocha #stats { |
|||
position: absolute; |
|||
} |
|||
} |
|||
1571
d3-ex1/package-lock.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,26 @@ |
|||
{ |
|||
"name": "mocha-chai-browser-demo", |
|||
"version": "1.0.0", |
|||
"description": "An example setup for JavaScript unit testing", |
|||
"scripts": { |
|||
"test": "karma start" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "https://github.com/ludovicofischer/mocha-chai-browser-demo.git" |
|||
}, |
|||
"author": "Ludovico Fischer", |
|||
"license": "MIT", |
|||
"bugs": { |
|||
"url": "https://github.com/ludovicofischer/mocha-chai-browser-demo/issues" |
|||
}, |
|||
"homepage": "https://github.com/ludovicofischer/mocha-chai-browser-demo", |
|||
"devDependencies": { |
|||
"karma": "^4.4.1", |
|||
"karma-chrome-launcher": "^3.1.0", |
|||
"karma-cli": "^2.0.0", |
|||
"karma-mocha": "^2.0.1", |
|||
"karma-mocha-reporter": "^0.3.1", |
|||
"mocha": "^3.4.2" |
|||
} |
|||
} |
|||
5332
d3-ex1/test-lib/chai.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
6472
d3-ex1/test-lib/mocha.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,30 @@ |
|||
<!DOCTYPE html> |
|||
|
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<title>Mocha Tests</title> |
|||
<link rel="stylesheet" href="mocha.css" /> |
|||
<style> |
|||
#fixture { |
|||
position: absolute; |
|||
top: -9999; |
|||
left: -9999; |
|||
}; |
|||
</style> |
|||
<script src="lib/jquery-3.2.1.js"></script> |
|||
<script src="test-lib/chai.js"></script> |
|||
<script src="test-lib/mocha.js"></script> |
|||
<script> mocha.setup('bdd');</script> |
|||
<script src="utils.js"></script> |
|||
<script src="tests.js"></script> |
|||
<script> |
|||
window.onload = function() { |
|||
mocha.run() |
|||
}; |
|||
</script> |
|||
</head> |
|||
<body> |
|||
<div id="mocha"></div> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,109 @@ |
|||
var expect = chai.expect; |
|||
var formMarkup = '<div id="fixture"><form id="testForm"> <select id="testSelect">' + |
|||
'<option> Hello </option> </select>' + |
|||
'<input type="hidden" name="contest.question1" value="some bad question"/>' + |
|||
'<input type="text" id="contestInput" name="contest.answer1"/>' + |
|||
'<input type="hidden" name="contest.question2" value="some bad question"/>' + |
|||
'<select name="contest.answer2"> <option>Good</option>' + |
|||
'<option id="contestOption">Great</option> </select>' + |
|||
'<input type="hidden" name="contest.question3" value="some bad question"/>' + |
|||
'<input type="text" id="badQuizAnswer" name="contest.answer3"/></form></div>'; |
|||
|
|||
describe('Utilities', function() { |
|||
'use strict'; |
|||
var ourQuiz; |
|||
var contestData = { |
|||
question1: 'How Are you?', |
|||
answer1: 'Fine, thanks.', |
|||
question2: 'Status', |
|||
answer2: 'Great', |
|||
question3: 'Who is the greatest painter?', |
|||
answer3: 'Raphael' |
|||
}; |
|||
|
|||
before(function() { |
|||
ourQuiz = new Quiz(contestData); |
|||
jQuery('body').append(formMarkup); |
|||
}); |
|||
|
|||
after(function() { |
|||
jQuery('#fixture').remove(); |
|||
}); |
|||
|
|||
it('should correctly list data', function() { |
|||
expect(ourQuiz.isSelect('select')).to.be.true; |
|||
expect(ourQuiz.isSelect('input')).to.be.false; |
|||
expect(ourQuiz.isInput('input')).to.be.true; |
|||
expect(ourQuiz.isSelect('input')).to.be.false; |
|||
}); |
|||
|
|||
it('should select the correct option', function() { |
|||
var select = document.getElementById('testSelect'); |
|||
ourQuiz.prefillSelect(select, 'Hello'); |
|||
expect(select.children[0].selected).to.be.true; |
|||
}); |
|||
|
|||
it('should identify matching questions', function() { |
|||
expect(ourQuiz.questionMatches(1, contestData.question1)).to.be.true; |
|||
}); |
|||
|
|||
it('should identify non-matching questions', function() { |
|||
expect(ourQuiz.questionMatches(1, contestData.question1 + 'blah')).to.be.false; |
|||
}); |
|||
}); |
|||
|
|||
describe('Main function', function() { |
|||
'use strict'; |
|||
var ourQuiz, form; |
|||
var contestData = { |
|||
question1: 'How Are you?', |
|||
answer1: 'Fine, thanks.', |
|||
question2: 'Status', |
|||
answer2: 'Great', |
|||
question3: 'Who is the greatest painter?', |
|||
answer3: 'Raphael' |
|||
}; |
|||
|
|||
before(function() { |
|||
ourQuiz = new Quiz(contestData); |
|||
form = jQuery('body').append(formMarkup); |
|||
}); |
|||
|
|||
after(function() { |
|||
jQuery('#fixture').remove(); |
|||
}); |
|||
|
|||
beforeEach(function() { |
|||
document.getElementById('contestOption').value = contestData.answer2; |
|||
jQuery('input[name="contest.question1"]').val(contestData.question1); |
|||
jQuery('input[name="contest.question2"]').val(contestData.question2); |
|||
ourQuiz.prefillQuizForm(form); |
|||
}); |
|||
|
|||
it('should fill the text fields that correspond to an answer', function() { |
|||
expect(document.getElementById('contestInput').value).to.equal(contestData.answer1); |
|||
}); |
|||
|
|||
it('should select the options that correspond to an answer', function() { |
|||
expect(document.getElementById('contestOption').selected).to.be.true; |
|||
}); |
|||
|
|||
it('should skip fields where the question has changed', function() { |
|||
expect(document.getElementById('badQuizAnswer').value).to.be.empty; |
|||
}); |
|||
}); |
|||
|
|||
describe('Initialization', function() { |
|||
'use strict'; |
|||
it('should initialize the main object', function() { |
|||
var contestData = { |
|||
question1: 'How Are you?', |
|||
answer1: 'Fine, thanks.', |
|||
question2: 'Status', |
|||
answer2: 'Great', |
|||
question3: 'Who is the greatest painter?', |
|||
answer3: 'Raphael' |
|||
}; |
|||
var contest = new Quiz(contestData); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,54 @@ |
|||
(function() { |
|||
"use strict"; |
|||
var root = this; |
|||
var Quiz = function(contestData) { |
|||
this.contest = contestData; |
|||
}; |
|||
|
|||
Quiz.prototype.isSelect = function(tagName) { |
|||
return tagName.toUpperCase() === 'SELECT'; |
|||
}; |
|||
Quiz.prototype.isInput = function(tagName) { |
|||
return tagName.toUpperCase() === 'INPUT'; |
|||
}; |
|||
Quiz.prototype.prefillInput = function(input, text) { |
|||
input.value = text; |
|||
}; |
|||
|
|||
Quiz.prototype.prefillSelect = function(select, text) { |
|||
jQuery('option', select).each(function() { |
|||
if (this.innerHTML === text) { |
|||
this.selected = true; |
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
Quiz.prototype.prefillField = function(field, text) { |
|||
if (this.isInput(field.tagName)) { |
|||
this.prefillInput(field, text); |
|||
} else if (this.isSelect(field.tagName)) { |
|||
this.prefillSelect(field, text); |
|||
} |
|||
}; |
|||
|
|||
Quiz.prototype.questionMatches = function(questionIndex, text) { |
|||
var questionProperty = "question" + questionIndex; |
|||
return this.contest[questionProperty] === text; |
|||
}; |
|||
|
|||
Quiz.prototype.prefillQuizForm = function(form) { |
|||
var numberOfQuestions = 5; |
|||
for (var i = 1; i <= numberOfQuestions; i++) { |
|||
var answerName = 'contest.answer' + i; |
|||
var questionName = 'contest.question' + i; |
|||
var contestProperty = "answer" + i; |
|||
var _this = this; |
|||
jQuery('[name="' + answerName + '"]', form).each(function() { |
|||
if (_this.questionMatches(i, jQuery('input[name="'+ questionName + '"]', form).val())) { |
|||
_this.prefillField(this, _this.contest[contestProperty]); |
|||
} |
|||
}); |
|||
} |
|||
}; |
|||
root.Quiz = Quiz; |
|||
}).call(this); |
|||
@ -0,0 +1,3 @@ |
|||
{ |
|||
"directory": "app/bower-components" |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
# ---------------------------- |
|||
# --- GIT ignore --- |
|||
# ---------------------------- |
|||
|
|||
# Untracked general purpose files: |
|||
.project |
|||
.sass-cache |
|||
.settings |
|||
.jscsrc |
|||
*.sublime-* |
|||
*.seed |
|||
*.log |
|||
*.csv |
|||
*.dat |
|||
*.out |
|||
*.pid |
|||
*.gz |
|||
*.bck |
|||
*.tmp |
|||
*.orig |
|||
/npm-debug.log |
|||
|
|||
# Untracked tmp files |
|||
# For Mac |
|||
.DS_Store |
|||
|
|||
# Untracked general purpose directories: |
|||
.idea |
|||
lib-cov |
|||
pids |
|||
logs |
|||
doc |
|||
jsdoc |
|||
publish |
|||
dist |
|||
target |
|||
tmp |
|||
temp |
|||
/node_modules |
|||
|
|||
# Untracked application files and directories: |
|||
/app/bower-components |
|||
test/results |
|||
@ -0,0 +1,28 @@ |
|||
<?xml version="1.0"?> |
|||
<testsuite name="Chrome 86.0.4240 (Linux 0.0.0)" package="" timestamp="2020-10-26T06:08:41" id="0" hostname="osboxes" tests="17" errors="0" failures="0" time="0.045"> |
|||
<properties> |
|||
<property name="browser.fullName" value="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36"/> |
|||
</properties> |
|||
<testcase name="services:math should be defined an be an object" time="0.004" classname="Chrome_86_0_4240_(Linux_0_0_0).services:math"/> |
|||
<testcase name="services:math should have the next methods and properties" time="0.002" classname="Chrome_86_0_4240_(Linux_0_0_0).services:math"/> |
|||
<testcase name="services:math method div should return a number" time="0.009" classname="Chrome_86_0_4240_(Linux_0_0_0).services:math method div"/> |
|||
<testcase name="services:math method div should return the result of the division" time="0" classname="Chrome_86_0_4240_(Linux_0_0_0).services:math method div"/> |
|||
<testcase name="services:math method div should throw an exception if the second parameter is '0'" time="0" classname="Chrome_86_0_4240_(Linux_0_0_0).services:math method div"/> |
|||
<testcase name="services:math method add should return nothing" time="0.001" classname="Chrome_86_0_4240_(Linux_0_0_0).services:math method add"/> |
|||
<testcase name="services:math method add should add the current value to the total one" time="0.001" classname="Chrome_86_0_4240_(Linux_0_0_0).services:math method add"/> |
|||
<testcase name="services:math method addRandom should add the current value to the total one using promise" time="0.004" classname="Chrome_86_0_4240_(Linux_0_0_0).services:math method addRandom"/> |
|||
<testcase name="services:tools should be defined an be an object" time="0.001" classname="Chrome_86_0_4240_(Linux_0_0_0).services:tools"/> |
|||
<testcase name="services:tools should have the next methods and properties" time="0.001" classname="Chrome_86_0_4240_(Linux_0_0_0).services:tools"/> |
|||
<testcase name="services:tools method sum(*, *) should return a number" time="0" classname="Chrome_86_0_4240_(Linux_0_0_0).services:tools method sum(*, *)"/> |
|||
<testcase name="services:tools method sum(*, *) should return the addition of integer and float numbers" time="0.001" classname="Chrome_86_0_4240_(Linux_0_0_0).services:tools method sum(*, *)"/> |
|||
<testcase name="services:tools method sum(*, *) should return the addition of numbers in string format" time="0" classname="Chrome_86_0_4240_(Linux_0_0_0).services:tools method sum(*, *)"/> |
|||
<testcase name="services:tools method sum(*, *) should return '0' if the parameters are missing" time="0" classname="Chrome_86_0_4240_(Linux_0_0_0).services:tools method sum(*, *)"/> |
|||
<testcase name="services:tools method sum(*, *) should use '0' as default value if the parameter is missing" time="0" classname="Chrome_86_0_4240_(Linux_0_0_0).services:tools method sum(*, *)"/> |
|||
<testcase name="services:tools method sum(*, *) should use '0' as default value if the parameter is not a number nor a string-number" time="0" classname="Chrome_86_0_4240_(Linux_0_0_0).services:tools method sum(*, *)"/> |
|||
<testcase name="services:tools method getRandomNumbers should return a random number" time="0.021" classname="Chrome_86_0_4240_(Linux_0_0_0).services:tools method getRandomNumbers"/> |
|||
<system-out> |
|||
<![CDATA[ |
|||
]]> |
|||
</system-out> |
|||
<system-err/> |
|||
</testsuite> |
|||
@ -0,0 +1,33 @@ |
|||
/** |
|||
* Register Grunt tasks to automate workflow. |
|||
* |
|||
* Exposes the following tasks: |
|||
* grunt |
|||
* |
|||
* @param {Object} grunt Grunt configuration. |
|||
*/ |
|||
module.exports = function(grunt) { |
|||
var timer = require('grunt-timer'); |
|||
|
|||
// Timer init to show execute time of grunt task.
|
|||
timer.init(grunt); |
|||
|
|||
grunt.initConfig({ |
|||
pkg: grunt.file.readJSON('package.json'), |
|||
source: { |
|||
app: 'app', |
|||
build: 'build', |
|||
doc: 'doc', |
|||
test: 'test', |
|||
grunt: 'Gruntfile.js' |
|||
}, |
|||
server: { |
|||
host: 'localhost', |
|||
port: '9000' |
|||
} |
|||
}); |
|||
|
|||
grunt.loadTasks('build/grunt-tasks'); |
|||
|
|||
grunt.registerTask('default', ['connect:dev']); |
|||
}; |
|||
@ -0,0 +1,202 @@ |
|||
Apache License |
|||
Version 2.0, January 2004 |
|||
http://www.apache.org/licenses/ |
|||
|
|||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
|||
|
|||
1. Definitions. |
|||
|
|||
"License" shall mean the terms and conditions for use, reproduction, |
|||
and distribution as defined by Sections 1 through 9 of this document. |
|||
|
|||
"Licensor" shall mean the copyright owner or entity authorized by |
|||
the copyright owner that is granting the License. |
|||
|
|||
"Legal Entity" shall mean the union of the acting entity and all |
|||
other entities that control, are controlled by, or are under common |
|||
control with that entity. For the purposes of this definition, |
|||
"control" means (i) the power, direct or indirect, to cause the |
|||
direction or management of such entity, whether by contract or |
|||
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
|||
outstanding shares, or (iii) beneficial ownership of such entity. |
|||
|
|||
"You" (or "Your") shall mean an individual or Legal Entity |
|||
exercising permissions granted by this License. |
|||
|
|||
"Source" form shall mean the preferred form for making modifications, |
|||
including but not limited to software source code, documentation |
|||
source, and configuration files. |
|||
|
|||
"Object" form shall mean any form resulting from mechanical |
|||
transformation or translation of a Source form, including but |
|||
not limited to compiled object code, generated documentation, |
|||
and conversions to other media types. |
|||
|
|||
"Work" shall mean the work of authorship, whether in Source or |
|||
Object form, made available under the License, as indicated by a |
|||
copyright notice that is included in or attached to the work |
|||
(an example is provided in the Appendix below). |
|||
|
|||
"Derivative Works" shall mean any work, whether in Source or Object |
|||
form, that is based on (or derived from) the Work and for which the |
|||
editorial revisions, annotations, elaborations, or other modifications |
|||
represent, as a whole, an original work of authorship. For the purposes |
|||
of this License, Derivative Works shall not include works that remain |
|||
separable from, or merely link (or bind by name) to the interfaces of, |
|||
the Work and Derivative Works thereof. |
|||
|
|||
"Contribution" shall mean any work of authorship, including |
|||
the original version of the Work and any modifications or additions |
|||
to that Work or Derivative Works thereof, that is intentionally |
|||
submitted to Licensor for inclusion in the Work by the copyright owner |
|||
or by an individual or Legal Entity authorized to submit on behalf of |
|||
the copyright owner. For the purposes of this definition, "submitted" |
|||
means any form of electronic, verbal, or written communication sent |
|||
to the Licensor or its representatives, including but not limited to |
|||
communication on electronic mailing lists, source code control systems, |
|||
and issue tracking systems that are managed by, or on behalf of, the |
|||
Licensor for the purpose of discussing and improving the Work, but |
|||
excluding communication that is conspicuously marked or otherwise |
|||
designated in writing by the copyright owner as "Not a Contribution." |
|||
|
|||
"Contributor" shall mean Licensor and any individual or Legal Entity |
|||
on behalf of whom a Contribution has been received by Licensor and |
|||
subsequently incorporated within the Work. |
|||
|
|||
2. Grant of Copyright License. Subject to the terms and conditions of |
|||
this License, each Contributor hereby grants to You a perpetual, |
|||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|||
copyright license to reproduce, prepare Derivative Works of, |
|||
publicly display, publicly perform, sublicense, and distribute the |
|||
Work and such Derivative Works in Source or Object form. |
|||
|
|||
3. Grant of Patent License. Subject to the terms and conditions of |
|||
this License, each Contributor hereby grants to You a perpetual, |
|||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|||
(except as stated in this section) patent license to make, have made, |
|||
use, offer to sell, sell, import, and otherwise transfer the Work, |
|||
where such license applies only to those patent claims licensable |
|||
by such Contributor that are necessarily infringed by their |
|||
Contribution(s) alone or by combination of their Contribution(s) |
|||
with the Work to which such Contribution(s) was submitted. If You |
|||
institute patent litigation against any entity (including a |
|||
cross-claim or counterclaim in a lawsuit) alleging that the Work |
|||
or a Contribution incorporated within the Work constitutes direct |
|||
or contributory patent infringement, then any patent licenses |
|||
granted to You under this License for that Work shall terminate |
|||
as of the date such litigation is filed. |
|||
|
|||
4. Redistribution. You may reproduce and distribute copies of the |
|||
Work or Derivative Works thereof in any medium, with or without |
|||
modifications, and in Source or Object form, provided that You |
|||
meet the following conditions: |
|||
|
|||
(a) You must give any other recipients of the Work or |
|||
Derivative Works a copy of this License; and |
|||
|
|||
(b) You must cause any modified files to carry prominent notices |
|||
stating that You changed the files; and |
|||
|
|||
(c) You must retain, in the Source form of any Derivative Works |
|||
that You distribute, all copyright, patent, trademark, and |
|||
attribution notices from the Source form of the Work, |
|||
excluding those notices that do not pertain to any part of |
|||
the Derivative Works; and |
|||
|
|||
(d) If the Work includes a "NOTICE" text file as part of its |
|||
distribution, then any Derivative Works that You distribute must |
|||
include a readable copy of the attribution notices contained |
|||
within such NOTICE file, excluding those notices that do not |
|||
pertain to any part of the Derivative Works, in at least one |
|||
of the following places: within a NOTICE text file distributed |
|||
as part of the Derivative Works; within the Source form or |
|||
documentation, if provided along with the Derivative Works; or, |
|||
within a display generated by the Derivative Works, if and |
|||
wherever such third-party notices normally appear. The contents |
|||
of the NOTICE file are for informational purposes only and |
|||
do not modify the License. You may add Your own attribution |
|||
notices within Derivative Works that You distribute, alongside |
|||
or as an addendum to the NOTICE text from the Work, provided |
|||
that such additional attribution notices cannot be construed |
|||
as modifying the License. |
|||
|
|||
You may add Your own copyright statement to Your modifications and |
|||
may provide additional or different license terms and conditions |
|||
for use, reproduction, or distribution of Your modifications, or |
|||
for any such Derivative Works as a whole, provided Your use, |
|||
reproduction, and distribution of the Work otherwise complies with |
|||
the conditions stated in this License. |
|||
|
|||
5. Submission of Contributions. Unless You explicitly state otherwise, |
|||
any Contribution intentionally submitted for inclusion in the Work |
|||
by You to the Licensor shall be under the terms and conditions of |
|||
this License, without any additional terms or conditions. |
|||
Notwithstanding the above, nothing herein shall supersede or modify |
|||
the terms of any separate license agreement you may have executed |
|||
with Licensor regarding such Contributions. |
|||
|
|||
6. Trademarks. This License does not grant permission to use the trade |
|||
names, trademarks, service marks, or product names of the Licensor, |
|||
except as required for reasonable and customary use in describing the |
|||
origin of the Work and reproducing the content of the NOTICE file. |
|||
|
|||
7. Disclaimer of Warranty. Unless required by applicable law or |
|||
agreed to in writing, Licensor provides the Work (and each |
|||
Contributor provides its Contributions) on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|||
implied, including, without limitation, any warranties or conditions |
|||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
|||
PARTICULAR PURPOSE. You are solely responsible for determining the |
|||
appropriateness of using or redistributing the Work and assume any |
|||
risks associated with Your exercise of permissions under this License. |
|||
|
|||
8. Limitation of Liability. In no event and under no legal theory, |
|||
whether in tort (including negligence), contract, or otherwise, |
|||
unless required by applicable law (such as deliberate and grossly |
|||
negligent acts) or agreed to in writing, shall any Contributor be |
|||
liable to You for damages, including any direct, indirect, special, |
|||
incidental, or consequential damages of any character arising as a |
|||
result of this License or out of the use or inability to use the |
|||
Work (including but not limited to damages for loss of goodwill, |
|||
work stoppage, computer failure or malfunction, or any and all |
|||
other commercial damages or losses), even if such Contributor |
|||
has been advised of the possibility of such damages. |
|||
|
|||
9. Accepting Warranty or Additional Liability. While redistributing |
|||
the Work or Derivative Works thereof, You may choose to offer, |
|||
and charge a fee for, acceptance of support, warranty, indemnity, |
|||
or other liability obligations and/or rights consistent with this |
|||
License. However, in accepting such obligations, You may act only |
|||
on Your own behalf and on Your sole responsibility, not on behalf |
|||
of any other Contributor, and only if You agree to indemnify, |
|||
defend, and hold each Contributor harmless for any liability |
|||
incurred by, or claims asserted against, such Contributor by reason |
|||
of your accepting any such warranty or additional liability. |
|||
|
|||
END OF TERMS AND CONDITIONS |
|||
|
|||
APPENDIX: How to apply the Apache License to your work. |
|||
|
|||
To apply the Apache License to your work, attach the following |
|||
boilerplate notice, with the fields enclosed by brackets "{}" |
|||
replaced with your own identifying information. (Don't include |
|||
the brackets!) The text should be enclosed in the appropriate |
|||
comment syntax for the file format. We also recommend that a |
|||
file or class name and description of purpose be included on the |
|||
same "printed page" as the copyright notice for easier |
|||
identification within third-party archives. |
|||
|
|||
Copyright {yyyy} {name of copyright owner} |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
@ -0,0 +1,88 @@ |
|||
# JavaScript testing |
|||
|
|||
The goal of this example is to know how to write tests for Javascript projects. |
|||
- Configure the tools. |
|||
- Run the tests in a non-UI browser: [PhantomJS](http://phantomjs.org/). |
|||
- Mocking the dependencies. |
|||
- Replace server requests using _Sinon_. |
|||
- Debugging the tests and its source-code using _Chrome dev tools_. |
|||
|
|||
## Tools |
|||
|
|||
- [Karma](https://karma-runner.github.io/0.13/index.html): this test-runner can be different configurations for the different types of tests. |
|||
- The runner is configured to use the Mocha framework, a preferred browser, the test output format -junit- and other features such as coverage results. |
|||
- The preferred browser is PhantomJS because is a non-UI browser which can be used with the continuous-integration tool. |
|||
Other browsers: almost any commercial browser can be used as executor: Firefox, Chrome, Safari, etc. |
|||
- [Mocha](http://mochajs.org/): test framework running on NodeJS and the browser that allows to make asynchronous testing easily. |
|||
- [Chai](http://chaijs.com/): the assertion library, is compatible with Mocha and allows to choose a TDD/BDD assert types. |
|||
- [Expect](http://chaijs.com/api/bdd/): assertion methods for BDD expectations. Expect has also been choosed because it does not modify the object prototype. |
|||
- [Sinon](http://sinonjs.org/docs/): used for spying, creating stubs and mocking the tests, is very powerful and with Sinon-Chai library is fully compatible with Chai expectations. |
|||
- [Sinon-Chai](http://chaijs.com/plugins/sinon-chai): extension of Chai expectations to be used with Sinon. |
|||
|
|||
## Installation |
|||
|
|||
Make sure this is installed first: |
|||
- [Node.js](https://nodejs.org/en/) |
|||
|
|||
The next step is install the Grunt and Bower globally if they are not installed yet: |
|||
> npm install -g grunt bower |
|||
|
|||
Install dependencies: |
|||
> npm install |
|||
> bower install |
|||
|
|||
## Running tests |
|||
|
|||
[Grunt](http://gruntjs.com/) is the tool used to run the tests, it will launch _karma_ with its different configurations. |
|||
|
|||
Available grunt task: |
|||
> grunt test:unit |
|||
> grunt test:coverage |
|||
|
|||
### Debugging |
|||
|
|||
In order to debug in _Chrome_ for example, the _karma_ base configuration has to be updated, ``karma.conf.js``: |
|||
|
|||
- ``browsers``: browsers which will be opened to run the tests, more than one could be choosen at a time. |
|||
- ``singleRun``: if ``true`` the browser will be stopped after the first execution, else the browser will keep alive and listening for file modifications to run the tests automatically. |
|||
- For continuous integration the value should be: ``true``. |
|||
|
|||
```js |
|||
// Start these browsers, currently available: |
|||
// - Chrome |
|||
// - ChromeCanary |
|||
// - Firefox |
|||
// - Opera |
|||
// - Safari (only Mac) |
|||
// - PhantomJS |
|||
// - IE (only Windows) |
|||
browsers: [ |
|||
'Chrome' |
|||
], |
|||
|
|||
// Continuous Integration mode |
|||
// if true, it capture browsers, run tests and exit |
|||
singleRun: false |
|||
``` |
|||
|
|||
## Coverage |
|||
|
|||
The coverage analysis is written directly in the console, however a more detailed one can be found in the folder: ``test/results/coverage``. |
|||
|
|||
Example: |
|||
|
|||
``` |
|||
----------------------|----------|----------|----------|----------|----------------| |
|||
File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines | |
|||
----------------------|----------|----------|----------|----------|----------------| |
|||
scripts\ | 100 | 100 | 100 | 100 | | |
|||
main.js | 100 | 100 | 100 | 100 | | |
|||
scripts\controllers\ | 50 | 100 | 33.33 | 50 | | |
|||
math.js | 50 | 100 | 33.33 | 50 |... 30,32,37,38 | |
|||
scripts\services\ | 100 | 100 | 100 | 100 | | |
|||
math.js | 100 | 100 | 100 | 100 | | |
|||
tools.js | 100 | 100 | 100 | 100 | | |
|||
----------------------|----------|----------|----------|----------|----------------| |
|||
All files | 78.57 | 100 | 73.33 | 78.57 | | |
|||
----------------------|----------|----------|----------|----------|----------------| |
|||
``` |
|||
@ -0,0 +1,24 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<title>Math</title> |
|||
</head> |
|||
<body> |
|||
<h1>Math application</h1> |
|||
<h2>Total: <span id="total"></span></h2> |
|||
<form id="addFrom"> |
|||
<input id="numberField" type="text" size="3" /> |
|||
<button id="addButton" type="submit" disabled>Add</button> |
|||
</form> |
|||
<p> |
|||
<button id="addRandomButton" type="button">Add Random Number</button> |
|||
</p> |
|||
<script src="bower-components/jquery/dist/jquery.js"></script> |
|||
<script src="bower-components/loglevel/dist/loglevel.js"></script> |
|||
|
|||
<script src="scripts/services/tools.js"></script> |
|||
<script src="scripts/services/math.js"></script> |
|||
<script src="scripts/controllers/math.js"></script> |
|||
<script src="scripts/main.js"></script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,43 @@ |
|||
(function(jQuery, math, log) { |
|||
var addButton = jQuery('#addButton'), |
|||
numberInput = jQuery('#numberField'), |
|||
randomButton = jQuery('#addRandomButton'), |
|||
total = jQuery('#total'), |
|||
logger = log.getLogger('indexController'); |
|||
|
|||
logger.info('Controller math started'); |
|||
|
|||
/** |
|||
* Render value as total. |
|||
* @param {string|number} value - value to render. |
|||
*/ |
|||
function renderTotal(value) { |
|||
total.html(value); |
|||
} |
|||
|
|||
// Enable add button if the input is a number.
|
|||
numberInput.on('keyup change', function(event) { |
|||
numberInput.val(event.target.value.replace(/[^0-9]/g, '')); |
|||
addButton.prop('disabled', !parseFloat(event.target.value)); |
|||
}); |
|||
|
|||
// Add the number to the total.
|
|||
addButton.click(function(event) { |
|||
math.add(numberInput.val()); |
|||
renderTotal(math.total); |
|||
|
|||
numberInput.val(''); |
|||
addButton.prop('disabled', true); |
|||
|
|||
event.preventDefault(); |
|||
}); |
|||
|
|||
// Generate a random number and update the total.
|
|||
randomButton.click(function() { |
|||
math.addRandom().then(function() { |
|||
renderTotal(math.total); |
|||
}); |
|||
}); |
|||
|
|||
renderTotal(this.math.total); |
|||
}(window.jQuery, window.math, window.log)); |
|||
@ -0,0 +1,5 @@ |
|||
(function(log) { |
|||
var logger = log.getLogger('main'); |
|||
|
|||
logger.info('Application started!'); |
|||
}(window.log)); |
|||
@ -0,0 +1,52 @@ |
|||
(function(window, log) { |
|||
var logger = log.getLogger('mathService'); |
|||
|
|||
logger.info('Service math started'); |
|||
|
|||
this.math = { |
|||
|
|||
/** |
|||
* @prop {number} total - the total value |
|||
*/ |
|||
total: 0, |
|||
|
|||
/** |
|||
* Divide number a on b and return result |
|||
* @param {number} a - divider |
|||
* @param {number} b - divisor |
|||
* @return {number} - result |
|||
*/ |
|||
div: function(a, b) { |
|||
var result = 0; |
|||
|
|||
if (b) { |
|||
result = a / b; |
|||
} else { |
|||
throw Error('divisor-zero'); |
|||
} |
|||
|
|||
return result; |
|||
}, |
|||
|
|||
/** |
|||
* Add a number to the total |
|||
* @param {number} n - a number add to |
|||
*/ |
|||
add: function(n) { |
|||
this.total = window.tools.sum(this.total, n); |
|||
}, |
|||
|
|||
/** |
|||
* Add random number to the total |
|||
* @return {Promise} - jQuery promise |
|||
*/ |
|||
addRandom: function() { |
|||
var _this = this; |
|||
|
|||
return window.tools.getRandomNumbers().then(function(random) { |
|||
logger.debug('Generated randon value: ', random); |
|||
_this.add(random); |
|||
}); |
|||
} |
|||
}; |
|||
}(window, window.log)); |
|||
@ -0,0 +1,38 @@ |
|||
(function(jQuery, log) { |
|||
var logger = log.getLogger('toolsService'); |
|||
|
|||
logger.info('Service tools started'); |
|||
|
|||
this.tools = { |
|||
|
|||
/** |
|||
* Make sum of two numbers. |
|||
* @param {*} a - first number to sum. |
|||
* @param {*} b - second number to sum. |
|||
* @return {number} - result of sum. |
|||
*/ |
|||
sum: function(a, b) { |
|||
return (parseFloat(a) || 0) + (parseFloat(b) || 0); |
|||
}, |
|||
|
|||
/** |
|||
* Get random number by using service random.org. |
|||
* @param {number} [quantity=1] - count of numbers to get. |
|||
* @return {Promise} - jQuery promise. |
|||
*/ |
|||
getRandomNumbers: function() { |
|||
var url = 'https://www.random.org/integers/?num=10&min=1&max=6&col=1' + |
|||
'&base=10&format=plain&rnd=new'; |
|||
|
|||
return jQuery.getJSON(url, { |
|||
num: 1, |
|||
min: 1, |
|||
max: 100, |
|||
col: 1, |
|||
base: 10, |
|||
format: 'plain', |
|||
rnd: 'new' |
|||
}); |
|||
} |
|||
}; |
|||
}(window.jQuery, window.log)); |
|||
@ -0,0 +1,20 @@ |
|||
{ |
|||
"name": "javascript-testing", |
|||
"version": "1.0.0", |
|||
"authors": [ |
|||
"jpastorp" |
|||
], |
|||
"ignore": [ |
|||
"**/.*", |
|||
"node_modules", |
|||
"app/bower-components", |
|||
"test" |
|||
], |
|||
"devDependencies": { |
|||
"sinon": "1.17.2" |
|||
}, |
|||
"dependencies": { |
|||
"jquery": "2.1.4", |
|||
"loglevel": "1.4.0" |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
/** |
|||
* Start the server. Registered tasks: |
|||
* - connect |
|||
* - run |
|||
* |
|||
* @param {Object} grunt Reference to the current Grunt process. |
|||
*/ |
|||
module.exports = function(grunt) { |
|||
grunt.loadNpmTasks('grunt-contrib-connect'); |
|||
|
|||
grunt.config.set('connect', { |
|||
dev: { |
|||
options: { |
|||
base: '<%= source.app %>', |
|||
port: '<%= server.port %>', |
|||
open: false, |
|||
keepalive: true |
|||
} |
|||
} |
|||
}); |
|||
}; |
|||
@ -0,0 +1,30 @@ |
|||
/** |
|||
* Run the tests. Registered tasks: |
|||
* - test |
|||
* - test:unit |
|||
* - test:functional |
|||
* - test:coverage |
|||
* |
|||
* @param {Object} grunt Reference to the current Grunt process. |
|||
*/ |
|||
module.exports = function(grunt) { |
|||
grunt.loadNpmTasks('grunt-karma'); |
|||
|
|||
grunt.config.set('karma', { |
|||
unit: { |
|||
options: { |
|||
configFile: './<%= source.test %>/config/karma.unit.conf.js' |
|||
} |
|||
}, |
|||
coverage: { |
|||
options: { |
|||
configFile: './<%= source.test %>/config/karma.coverage.conf.js' |
|||
} |
|||
} |
|||
}); |
|||
|
|||
// Register the test tasks.
|
|||
grunt.registerTask('test:unit', ['karma:unit']); |
|||
grunt.registerTask('test:coverage', ['karma:coverage']); |
|||
grunt.registerTask('test', ['test:unit']); |
|||
}; |
|||
4703
d3-ex2/package-lock.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,60 @@ |
|||
{ |
|||
"name": "javascript-testing", |
|||
"version": "1.0.0", |
|||
"description": "Basic testing example for Javascript projects with karma, mocha, chai, sinon and phantomjs", |
|||
"homepage": "https://github.com/moelders/javascript-testing/", |
|||
"main": "grunt", |
|||
"scripts": { |
|||
"test": "grunt test" |
|||
}, |
|||
"author": { |
|||
"name": "Jaime Pastor Pueyo", |
|||
"email": "moelders@gmail.com" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "https://github.com/moelders/javascript-testing.git" |
|||
}, |
|||
"devDependencies": { |
|||
"sinon-chai": "^3.5.0", |
|||
"sinon": "^9.2.0", |
|||
"grunt": "^1.3.0", |
|||
"karma": "^4.4.1", |
|||
"mocha": "^8.2.0", |
|||
"chai": "^4.2.0", |
|||
"karma-chai": "0.1.0", |
|||
"grunt-contrib-connect": "3.0.0", |
|||
"grunt-karma": "4.0.0", |
|||
"grunt-run": "0.8.1", |
|||
"grunt-timer": "0.6.0", |
|||
"karma-chai-sinon": "0.1.5", |
|||
"karma-chrome-launcher": "3.1.0", |
|||
"karma-mocha": "2.0.1", |
|||
"karma-junit-reporter": "2.0.1", |
|||
"karma-sinon": "1.0.5", |
|||
"karma-coverage": "^2.0.3" |
|||
}, |
|||
"engines": { |
|||
"node": ">=0.10.0" |
|||
}, |
|||
"license": { |
|||
"type": "Apache-2.0", |
|||
"description": "Apache License Version 2.0, January 2004", |
|||
"url": "http://www.apache.org/licenses/LICENSE-2.0" |
|||
}, |
|||
"keywords": [ |
|||
"test", |
|||
"testing", |
|||
"unit", |
|||
"coverage", |
|||
"karma", |
|||
"mocha", |
|||
"chai", |
|||
"sinon", |
|||
"phantomjs" |
|||
], |
|||
"dependencies": { |
|||
"bower": "^1.8.8", |
|||
"install": "^0.13.0" |
|||
} |
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
// Karma shared configuration
|
|||
|
|||
module.exports = function(config) { |
|||
config.set({ |
|||
|
|||
// base path, that will be used to resolve files and exclude
|
|||
basePath: '../../', |
|||
|
|||
// list of files / patterns to load in the browser
|
|||
files: [ |
|||
'app/bower-components/jquery/dist/jquery.js', |
|||
'app/bower-components/loglevel/dist/loglevel.js', |
|||
|
|||
'app/scripts/services/**/*.js', |
|||
'app/scripts/controllers/**/*.js', |
|||
'app/scripts/main.js', |
|||
|
|||
'test/specs/unit/**/*.spec.js', |
|||
|
|||
'test/config/mocha-globals.js', |
|||
], |
|||
|
|||
// list of files / patterns to exclude
|
|||
exclude: [], |
|||
|
|||
/* Enable / disable watching file and executing tests |
|||
* whenever any file changes |
|||
*/ |
|||
autoWatch: true, |
|||
|
|||
// testing framework to use (jasmine/mocha/qunit/...)
|
|||
// as well as any additional frameworks (requirejs/chai/sinon/...)
|
|||
frameworks: [ |
|||
'mocha', |
|||
'chai', |
|||
'sinon', |
|||
'chai-sinon' |
|||
], |
|||
|
|||
// Shared plugins (default is 'karma-*'):
|
|||
plugins: [ |
|||
'karma-*' |
|||
], |
|||
|
|||
// web server port
|
|||
port: 8080, |
|||
|
|||
// Start these browsers, currently available:
|
|||
// - Chrome
|
|||
// - ChromeCanary
|
|||
// - Firefox
|
|||
// - Opera
|
|||
// - Safari (only Mac)
|
|||
// - PhantomJS
|
|||
// - IE (only Windows)
|
|||
browsers: [ |
|||
'Chrome' |
|||
], |
|||
|
|||
// Continuous Integration mode
|
|||
// if true, it capture browsers, run tests and exit
|
|||
singleRun: true |
|||
}); |
|||
}; |
|||
@ -0,0 +1,29 @@ |
|||
// Karma coverage configuration
|
|||
|
|||
module.exports = function(config) { |
|||
var baseConfig = require('../config/karma.conf'); |
|||
|
|||
baseConfig(config); |
|||
|
|||
config.set({ |
|||
preprocessors: { |
|||
'app/scripts/**/*.js': ['coverage'] |
|||
}, |
|||
|
|||
reporters: ['coverage'], |
|||
|
|||
coverageReporter: { |
|||
reporters: [ |
|||
{ |
|||
type: 'text' |
|||
}, { |
|||
type: 'lcov', |
|||
dir: 'test/results/coverage', |
|||
subdir: function(browserName) { |
|||
return browserName.toLowerCase().split(/[\s/-]/)[0]; |
|||
} |
|||
} |
|||
] |
|||
} |
|||
}); |
|||
}; |
|||
@ -0,0 +1,15 @@ |
|||
// Karma configuration for unit-test
|
|||
|
|||
module.exports = function(config) { |
|||
var baseConfig = require('../config/karma.conf'); |
|||
|
|||
baseConfig(config); |
|||
|
|||
config.set({ |
|||
reporters: ['dots', 'junit'], |
|||
|
|||
junitReporter: { |
|||
outputFile: 'test/results/unit/test-results.xml' |
|||
} |
|||
}); |
|||
}; |
|||
@ -0,0 +1,18 @@ |
|||
// Executes once before the first describe.
|
|||
before(function() { |
|||
logLevel = log.getLevel(); |
|||
|
|||
// Set minimum log level
|
|||
log.setLevel(log.levels.SILENT); |
|||
}); |
|||
|
|||
// Executes once after all the describes.
|
|||
after(function() { |
|||
log.setLevel(logLevel); |
|||
}); |
|||
|
|||
// Executed before every test.
|
|||
beforeEach(function() {}); |
|||
|
|||
// Executed after every test.
|
|||
afterEach(function() {}); |
|||
@ -0,0 +1 @@ |
|||
describe('app:main', function() {}); |
|||
@ -0,0 +1,104 @@ |
|||
describe('services:math', function() { |
|||
var math = window.math; |
|||
|
|||
it('should be defined an be an object', function() { |
|||
expect(math).not.to.be.undefined; |
|||
expect(math).to.be.an('object'); |
|||
}); |
|||
|
|||
it('should have the next methods and properties', function() { |
|||
expect(math).to.have.property('total').which.is.a('number'); |
|||
expect(math).to.have.property('div').which.is.a('function'); |
|||
expect(math).to.have.property('add').which.is.a('function'); |
|||
expect(math).to.have.property('addRandom').which.is.a('function'); |
|||
}); |
|||
|
|||
describe('method', function() { |
|||
describe('div', function() { |
|||
it('should return a number', function() { |
|||
expect(math.div(10, 2)).to.be.a('number'); |
|||
}); |
|||
|
|||
it('should return the result of the division', function() { |
|||
expect(math.div(10, 2)).to.be.equal(5); |
|||
expect(math.div(21, 3)).to.be.equal(7); |
|||
}); |
|||
|
|||
it('should throw an exception if the second parameter is \'0\'', |
|||
function() { |
|||
expect(function() { |
|||
math.div(10, 0); |
|||
}).to.throw('divisor-zero'); |
|||
} |
|||
); |
|||
}); |
|||
|
|||
describe('add', function() { |
|||
beforeEach(function() { |
|||
math.total = 0; |
|||
|
|||
sinon.stub(window.tools, 'sum') |
|||
.withArgs(0, 5).returns(5) |
|||
.withArgs(5, 10).returns(15); |
|||
}); |
|||
|
|||
afterEach(function() { |
|||
window.tools.sum.restore(); |
|||
}); |
|||
|
|||
it('should return nothing', function() { |
|||
expect(math.add(1)).to.be.undefined; |
|||
|
|||
expect(window.tools.sum).to.have.been.calledOnce; |
|||
expect(window.tools.sum).to.have.been.calledWith(0, 1); |
|||
}); |
|||
|
|||
it('should add the current value to the total one', function() { |
|||
math.add(5); |
|||
|
|||
expect(window.tools.sum).to.have.been.calledOnce; |
|||
expect(window.tools.sum).to.have.been.calledWith(0, 5); |
|||
expect(math.total).to.be.equal(5); |
|||
|
|||
math.add(10); |
|||
|
|||
expect(window.tools.sum).to.have.been.calledTwice; |
|||
expect(window.tools.sum).to.have.been.calledWith(5, 10); |
|||
expect(math.total).to.be.equal(15); |
|||
}); |
|||
}); |
|||
|
|||
describe('addRandom', function() { |
|||
var randomValue, |
|||
defer; |
|||
|
|||
beforeEach(function() { |
|||
math.total = 0; |
|||
randomValue = 999; |
|||
|
|||
defer = new jQuery.Deferred(); |
|||
defer.resolve(randomValue); |
|||
|
|||
sinon.stub(window.tools, 'getRandomNumbers').returns(defer.promise()); |
|||
}); |
|||
|
|||
afterEach(function() { |
|||
tools.getRandomNumbers.restore(); |
|||
}); |
|||
|
|||
it('should add the current value to the total one using promise', |
|||
function(done) { |
|||
math.addRandom().then( |
|||
function() { |
|||
expect(window.tools.getRandomNumbers).to.have.been.calledOnce; |
|||
expect(math.total).to.be.equal(parseInt(randomValue, 10)); |
|||
|
|||
done(); |
|||
}, |
|||
done |
|||
); |
|||
} |
|||
); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,76 @@ |
|||
describe('services:tools', function() { |
|||
it('should be defined an be an object', function() { |
|||
expect(tools).not.to.be.undefined; |
|||
expect(tools).to.be.an('object'); |
|||
}); |
|||
|
|||
it('should have the next methods and properties', function() { |
|||
expect(tools).to.have.property('sum').which.is.a('function'); |
|||
expect(tools).to.have.property('getRandomNumbers').which.is.a('function'); |
|||
}); |
|||
|
|||
describe('method', function() { |
|||
describe('sum(*, *)', function() { |
|||
it('should return a number', function() { |
|||
expect(tools.sum(10, 2)).to.be.a('number'); |
|||
}); |
|||
|
|||
it('should return the addition of integer and float numbers', function() { |
|||
expect(tools.sum(10, 2)).to.be.equal(12); |
|||
expect(tools.sum(21, 1.9)).to.be.equal(22.9); |
|||
}); |
|||
|
|||
it('should return the addition of numbers in string format', function() { |
|||
expect(tools.sum('21', 3)).to.be.equal(24); |
|||
expect(tools.sum(.5, '1.2')).to.be.equal(1.7); |
|||
}); |
|||
|
|||
it('should return \'0\' if the parameters are missing', function() { |
|||
expect(tools.sum()).to.be.equal(0); |
|||
}); |
|||
|
|||
it('should use \'0\' as default value if the parameter is missing', |
|||
function() { |
|||
expect(tools.sum(null, 5)).to.be.equal(5); |
|||
expect(tools.sum(5)).to.be.equal(5); |
|||
} |
|||
); |
|||
|
|||
it('should use \'0\' as default value if the parameter is not a number ' + |
|||
'nor a string-number', |
|||
function() { |
|||
expect(tools.sum({}, 5)).to.be.equal(5); |
|||
expect(tools.sum(5, function() {})).to.be.equal(5); |
|||
} |
|||
); |
|||
}); |
|||
|
|||
describe('getRandomNumbers', function() { |
|||
var randomValue = '999', |
|||
server; |
|||
|
|||
before(function() { |
|||
server = sinon.fakeServer.create(); |
|||
|
|||
server.respondWith(randomValue); |
|||
}); |
|||
|
|||
after(function() { |
|||
server.restore(); |
|||
}); |
|||
|
|||
it('should return a random number', function(done) { |
|||
tools.getRandomNumbers().then( |
|||
function(value) { |
|||
expect(value).to.be.equal(parseInt(randomValue)); |
|||
|
|||
done(); |
|||
}, |
|||
done |
|||
); |
|||
|
|||
server.respond(); |
|||
}); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,3 @@ |
|||
coverage |
|||
node_modules |
|||
src/main/webapp/lib/**/*.* |
|||
@ -0,0 +1,23 @@ |
|||
A simple and concise demonstration on how to use Mocha, Chai, and Karma to unit and integration test the frontend. |
|||
|
|||
# Prereqs # |
|||
|
|||
You must have Node.js installed. |
|||
|
|||
# Get it running # |
|||
|
|||
In the root directory, execute: |
|||
|
|||
```bash |
|||
npm install |
|||
``` |
|||
|
|||
To start/run the tests, execute the following in the root directory: |
|||
|
|||
```bash |
|||
node_modules/karma/bin/karma start |
|||
``` |
|||
|
|||
# Watch # |
|||
|
|||
By default, Karma is configured to watch for changes, so any changes you make to the sample.js or the sampleTest.js will automatically be picked up and tests will be rerun. |
|||
@ -0,0 +1,31 @@ |
|||
var fs = require('fs'), |
|||
path = require('path'), |
|||
libDirPath, |
|||
jqueryFilePath, |
|||
jqueryFileName; |
|||
|
|||
libDirPath = path.join(__dirname, '../src/main/webapp/lib'); |
|||
jqueryFileName = 'jquery.min.js'; |
|||
jqueryFilePath = path.join(libDirPath, jqueryFileName); |
|||
|
|||
fs.exists(libDirPath, function(exists) { |
|||
if(!exists) { |
|||
console.log('Creating lib directory') |
|||
fs.mkdir(libDirPath, function(err) { |
|||
if(err) { |
|||
throw err; |
|||
} |
|||
|
|||
addFiles(); |
|||
}); |
|||
} else { |
|||
addFiles(); |
|||
} |
|||
}); |
|||
|
|||
function addFiles() { |
|||
console.log('Trying to add files to lib directory!'); |
|||
fs.createReadStream(path.join(__dirname, '../node_modules/jquery/dist', jqueryFileName)) |
|||
.pipe(fs.createWriteStream(jqueryFilePath)); |
|||
console.log('Added files to lib directory.'); |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
var fs = require('fs'), |
|||
path = require('path'), |
|||
libDirPath, |
|||
jqueryFilePath; |
|||
|
|||
libDirPath = path.join(__dirname, '../src/main/webapp/lib'); |
|||
jqueryFilePath = path.join(libDirPath, 'jquery.min.js'); |
|||
|
|||
fs.exists(jqueryFilePath, function (exists) { |
|||
if(exists) { |
|||
fs.unlink(jqueryFilePath, function(err) { |
|||
if(err) { |
|||
throw err; |
|||
} |
|||
console.log('Successfully deleted jquery.min.js!'); |
|||
}); |
|||
} |
|||
}); |
|||
@ -0,0 +1,77 @@ |
|||
// Karma configuration
|
|||
// Generated on Mon Mar 23 2015 10:59:44 GMT-0700 (PDT)
|
|||
|
|||
module.exports = function(config) { |
|||
config.set({ |
|||
|
|||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
|||
basePath: '', |
|||
|
|||
|
|||
// frameworks to use
|
|||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
|||
frameworks: ['mocha', 'chai', 'sinon'], |
|||
|
|||
plugins: [ |
|||
'karma-mocha', |
|||
'karma-coverage', |
|||
'karma-chrome-launcher', |
|||
'karma-chai', |
|||
'karma-sinon' |
|||
], |
|||
|
|||
|
|||
// list of files / patterns to load in the browser
|
|||
files: [ |
|||
'src/main/webapp/app/**/*.js', |
|||
'src/main/webapp/lib/**/*.js', |
|||
'src/test/**/*.js' |
|||
], |
|||
|
|||
|
|||
|
|||
// list of files to exclude
|
|||
exclude: [], |
|||
|
|||
|
|||
// preprocess matching files before serving them to the browser
|
|||
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
|||
preprocessors: { |
|||
'src/main/webapp/app/**/*.js': ['coverage'] |
|||
}, |
|||
|
|||
|
|||
// test results reporter to use
|
|||
// possible values: 'dots', 'progress'
|
|||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
|||
reporters: ['progress','coverage'], |
|||
|
|||
|
|||
// web server port
|
|||
port: 9876, |
|||
|
|||
|
|||
// enable / disable colors in the output (reporters and logs)
|
|||
colors: true, |
|||
|
|||
|
|||
// level of logging
|
|||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
|||
logLevel: config.LOG_INFO, |
|||
|
|||
|
|||
// enable / disable watching file and executing tests whenever any file changes
|
|||
autoWatch: true, |
|||
|
|||
|
|||
// start these browsers
|
|||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
|||
browsers: ['Chrome'], |
|||
|
|||
|
|||
// Continuous Integration mode
|
|||
// if true, Karma captures browsers, runs the tests and exits
|
|||
singleRun: false |
|||
|
|||
}); |
|||
}; |
|||
3275
d3-ex3/package-lock.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,45 @@ |
|||
{ |
|||
"name": "clientside-testing-example", |
|||
"version": "0.0.0", |
|||
"scripts": { |
|||
"preinstall": "node bin/preinstall", |
|||
"postinstall": "node bin/postinstall" |
|||
}, |
|||
"dependencies": { |
|||
"jquery": "1.11.3" |
|||
}, |
|||
"devDependencies": { |
|||
"chai": "^4.2.0", |
|||
"coverage": "^0.4.1", |
|||
"karma": "^4.4.1", |
|||
"karma-chai": "0.1.0", |
|||
"karma-chai-sinon": "0.1.5", |
|||
"karma-chrome-launcher": "3.1.0", |
|||
"karma-coverage": "^2.0.3", |
|||
"karma-junit-reporter": "2.0.1", |
|||
"karma-mocha": "^2.0.1", |
|||
"karma-sinon": "1.0.5", |
|||
"mocha": "^8.2.0", |
|||
"requirejs": "^2.3.6", |
|||
"sinon": "^9.2.0", |
|||
"sinon-chai": "^3.5.0" |
|||
}, |
|||
"engines": { |
|||
"node": ">=0.10.0" |
|||
}, |
|||
"license": { |
|||
"type": "Apache-2.0", |
|||
"description": "Apache License Version 2.0, January 2004", |
|||
"url": "http://www.apache.org/licenses/LICENSE-2.0" |
|||
}, |
|||
"keywords": [ |
|||
"test", |
|||
"testing", |
|||
"unit", |
|||
"coverage", |
|||
"karma", |
|||
"mocha", |
|||
"chai", |
|||
"sinon" |
|||
] |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
{ |
|||
"name": "clientside-testing-example", |
|||
"version": "0.0.0", |
|||
"scripts": { |
|||
"preinstall": "node bin/preinstall", |
|||
"postinstall": "node bin/postinstall" |
|||
}, |
|||
"dependencies": { |
|||
"jquery": "*" |
|||
}, |
|||
"devDependencies": { |
|||
"chai": "*", |
|||
"karma": "*", |
|||
"mocha": "*", |
|||
"karma-mocha": "*", |
|||
"karma-chai": "*", |
|||
"karma-js-coverage": "*", |
|||
"karma-sinon": "*", |
|||
"karma-chrome-launcher": "*", |
|||
"sinon": "*", |
|||
"karma-coverage": "*" |
|||
}, |
|||
"engines": { |
|||
"node": ">=0.12.0" |
|||
} |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
|
|||
var AWESOME_CLASS = 'awesome', |
|||
VIEWPORT_ID = 'viewport', |
|||
ERROR_MESSAGE = 'error!', |
|||
DATA_SERVICE_URL = '/services/data', |
|||
doEverything; |
|||
|
|||
function makeAwesome(el) { |
|||
if(el) { |
|||
el.className += ' ' + AWESOME_CLASS; |
|||
} |
|||
} |
|||
|
|||
function isAwesome(el) { |
|||
return (el && el.className.indexOf(AWESOME_CLASS) > -1) === true; |
|||
} |
|||
|
|||
function isArray(arr) { |
|||
if(Array.isArray(arr)) { |
|||
return true; |
|||
} |
|||
|
|||
throw new Error(ERROR_MESSAGE); |
|||
} |
|||
|
|||
function getDataFromServer(onSuccess, onError) { |
|||
return $.ajax({ |
|||
url: DATA_SERVICE_URL |
|||
}).error(onError).done(onSuccess); |
|||
} |
|||
|
|||
doEverything = (function() { |
|||
var obj = {}; |
|||
|
|||
privateFunction = function(obj) { |
|||
// var obj = {};
|
|||
obj.stuff = true |
|||
}; |
|||
|
|||
asyncFunction = function(obj) { |
|||
setTimeout(function(){ |
|||
obj.async = true; |
|||
}, 3000); |
|||
}; |
|||
|
|||
return { |
|||
|
|||
wow: function() { |
|||
console.log('wow'); |
|||
}, |
|||
|
|||
omg: function() { |
|||
console.log('omg'); |
|||
}, |
|||
|
|||
addStuff: function (obj) { |
|||
if(obj) { |
|||
obj.hello = 'hello'; |
|||
} |
|||
privateFunction(obj); |
|||
}, |
|||
|
|||
asyncStuff: function(obj) { |
|||
asyncFunction(obj); |
|||
} |
|||
}; |
|||
|
|||
})(); |
|||
@ -0,0 +1,169 @@ |
|||
describe('sampleTest', function() { |
|||
|
|||
var div, |
|||
clock, |
|||
server; |
|||
|
|||
/** |
|||
* Setup function called before each test. |
|||
*/ |
|||
beforeEach(function() { |
|||
div = document.createElement('div'); |
|||
|
|||
div.id = VIEWPORT_ID; |
|||
document.body.appendChild(div); |
|||
|
|||
// Fake the clock before every test
|
|||
clock = sinon.useFakeTimers(); |
|||
// Creates a new fake server before every test
|
|||
server = sinon.fakeServer.create(); |
|||
}); |
|||
|
|||
/** |
|||
* Tear down function called after each test. |
|||
*/ |
|||
afterEach(function() { |
|||
document.body.removeChild(div); |
|||
|
|||
// Tears down the faked clock after every test
|
|||
clock.restore(); |
|||
// Tears down the fake server after every test
|
|||
server.restore(); |
|||
}); |
|||
|
|||
/** |
|||
* Demonstrates the expectation that the div added to the body contains |
|||
* the AWESOME_CLASS after calling #makeAwesome(). |
|||
*/ |
|||
it('#makeAwesome(): should add class AWESOME_CLASS to a div', function() { |
|||
expect(div.className).to.not.contain(AWESOME_CLASS); |
|||
|
|||
makeAwesome(div); |
|||
|
|||
expect(div.className).to.contain(AWESOME_CLASS); |
|||
}); |
|||
|
|||
it('#isAwesome(): should return true when el contains class AWESOME_CLASS', function() { |
|||
expect(isAwesome(div)).to.be.false; |
|||
|
|||
makeAwesome(div); |
|||
|
|||
expect(isAwesome(div)).to.be.true; |
|||
}); |
|||
|
|||
it('#isAwesome(): should return false when el is null', function() { |
|||
expect(isAwesome(null)).to.be.false; |
|||
}); |
|||
|
|||
it('#isAwesome(): should return false when el doesn\'t contain class "awesome"', function() { |
|||
expect(isAwesome(document.createElement('div'))).to.be.false; |
|||
}); |
|||
|
|||
it('#isArray(): should return true when arr is an Array', function() { |
|||
expect(isArray([])).to.be.true; |
|||
}); |
|||
|
|||
it('#isArray(): should throw an exception when arr is not an Array', function() { |
|||
assert.throws(function() { |
|||
isArray(null); |
|||
}, ERROR_MESSAGE); |
|||
}); |
|||
|
|||
it('doEverything#addStuff(): should add keys "hello" and "stuff" to obj', function() { |
|||
var obj = {}; |
|||
|
|||
doEverything.addStuff(obj) |
|||
|
|||
expect(obj).to.include.keys(['hello', 'stuff']); |
|||
}); |
|||
|
|||
/** |
|||
* Demonstrates that the #asyncStuff() function sets the "async" property |
|||
* on the parameter obj once the timeout has lapsed. |
|||
*/ |
|||
it('doEverything#asyncStuff(): should set obj.async to "true"', function() { |
|||
var obj = {}; |
|||
|
|||
doEverything.asyncStuff(obj); |
|||
// Fast-forward 4 seconds to trip the setTimeout() in myAsnycFn()
|
|||
clock.tick(4000); |
|||
|
|||
expect(obj).to.include.keys(['async']); |
|||
expect(obj.async).to.be.true; |
|||
}); |
|||
|
|||
/** |
|||
* Demonstrates the #getDataFromServer() function properly calls the success function |
|||
* passed to #getDataFromServer() when the server returns a HTTP 200. |
|||
*/ |
|||
it('#getDataFromServer(): should get object with "name" property from my service when a HTTP 200 is returned', function() { |
|||
var serverResponse, |
|||
ajaxResponseData; |
|||
|
|||
serverResponse = { |
|||
name: 'Jim Smith' |
|||
}; |
|||
|
|||
// Configure the fake server to respond with the configuration
|
|||
server.respondWith('GET', |
|||
DATA_SERVICE_URL, [ |
|||
200, { |
|||
'Content-Type': 'application/json', |
|||
}, |
|||
JSON.stringify(serverResponse) |
|||
] |
|||
); |
|||
|
|||
getDataFromServer(function(data) { |
|||
ajaxResponseData = data; |
|||
}); |
|||
// Tell the server to respond with the GET 200 response
|
|||
server.respond(); |
|||
|
|||
expect(ajaxResponseData).to.include.keys(['name']); |
|||
expect(ajaxResponseData.name).to.equal(serverResponse.name); |
|||
}); |
|||
|
|||
/** |
|||
* Demonstrates the #getDataFromServer() function properly calls the error function |
|||
* passed to #getDataFromServer() when the server returns a HTTP 500. |
|||
*/ |
|||
it('#getDataFromServer(): should get an error object from my service when an HTTP 500 is returned', function() { |
|||
var serverErrorResponse, |
|||
ajaxResponseData, |
|||
ajaxErrorData, |
|||
onError, |
|||
onSuccess; |
|||
|
|||
serverErrorResponse = { |
|||
error: 'Internal error!' |
|||
}; |
|||
|
|||
// Configure the fake server to respond with the configuration
|
|||
server.respondWith('GET', |
|||
DATA_SERVICE_URL, [ |
|||
500, { |
|||
'Content-Type': 'application/json', |
|||
}, |
|||
JSON.stringify(serverErrorResponse) |
|||
] |
|||
); |
|||
|
|||
onSuccess = function(data) { |
|||
ajaxResponseData = data; |
|||
}; |
|||
onError = function(jqXhr, errorString, exception) { |
|||
ajaxErrorData = jqXhr.responseJSON.error; |
|||
}; |
|||
|
|||
getDataFromServer(onSuccess, onError); |
|||
// Tell the server to respond with the GET 500 response
|
|||
server.respond(); |
|||
|
|||
// AJAX response failed, the response data should be empty
|
|||
expect(ajaxResponseData).to.be.not.ok; |
|||
// Make sure the AJAX response returned the server error
|
|||
expect(ajaxErrorData).to.equal(serverErrorResponse.error); |
|||
}); |
|||
|
|||
}); |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue