Skip to content

Commit 3bef3e7

Browse files
committed
Added basic functional test + travis setup.
1 parent 6fa1088 commit 3bef3e7

File tree

8 files changed

+1466
-0
lines changed

8 files changed

+1466
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
.DS_Store
2+
npm-debug.log
3+
node_modules
24
.metadata
35
*.pyc
46
*~

.travis.yml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
language: node_js
2+
sudo: false
3+
node_js:
4+
- '0.10'

package.json

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "readability",
3+
"version": "0.0.1",
4+
"description": "A standalone version of the readability library used for Firefox Reader View.",
5+
"main": "Readability.js",
6+
"scripts": {
7+
"test": "mocha"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "https://github.com/mozilla/readability"
12+
},
13+
"author": "",
14+
"license": "ISC",
15+
"bugs": {
16+
"url": "https://github.com/mozilla/readability/issues"
17+
},
18+
"homepage": "https://github.com/mozilla/readability",
19+
"devDependencies": {
20+
"chai": "^2.1.*",
21+
"chai-as-promised": "^4.3.*",
22+
"html": "0.0.*",
23+
"mocha": "^2.2.*",
24+
"readable-proxy": "1.2.*"
25+
}
26+
}

test/index.js

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
var scrape = require("readable-proxy").scrape;
2+
var path = require("path");
3+
var fs = require("fs");
4+
var prettyPrint = require("html").prettyPrint;
5+
var chai = require("chai");
6+
var chaiAsPromised = require("chai-as-promised");
7+
chai.should();
8+
chai.use(chaiAsPromised);
9+
var expect = chai.expect;
10+
11+
var testPageRoot = path.join(__dirname, "test-pages");
12+
var testPages = fs.readdirSync(testPageRoot).map(function(dir) {
13+
return {
14+
dir: dir,
15+
source: path.join(testPageRoot, dir, "source.html"),
16+
expected: path.join(testPageRoot, dir, "expected.html"),
17+
};
18+
});
19+
20+
describe("Test page", function() {
21+
testPages.forEach(function(testPage) {
22+
describe(testPage.dir, function() {
23+
it("should render as expected", function() {
24+
// Allows up to 10 seconds for parsing to complete.
25+
// XXX: Scraping is damn slow. Investigate.
26+
this.timeout(10000);
27+
var expected = fs.readFileSync(testPage.expected, {encoding: "utf-8"});
28+
return scrape("file://" + testPage.source).catch(function(err) {
29+
throw err;
30+
}).then(function(result) {
31+
// normalize html
32+
return prettyPrint(result.content);
33+
}).should.eventually.become(prettyPrint(expected));
34+
});
35+
});
36+
})
37+
});

test/test-pages/001/expected.html

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<div id="readability-page-1" class="page"><section class="">
2+
<p><strong>So finally you're <a href="file:///code/2013/testing-frontend-javascript-code-using-mocha-chai-and-sinon/">testing your frontend JavaScript code</a>? Great! The more you
3+
write tests, the more confident you are with your code… but how much precisely?
4+
That's where <a href="http://en.wikipedia.org/wiki/Code_coverage">code coverage</a> might
5+
help.</strong></p>
6+
<p>The idea behind code coverage is to record which parts of your code (functions,
7+
statements, conditionals and so on) have been executed by your test suite, to
8+
compute metrics out of these data and usually to provide tools for navigating
9+
and inspecting them.</p>
10+
<p>Not a lot of frontend developers I know actually test their frontend code, and I
11+
can barely imagine how many of them have ever setup code coverage… Mostly
12+
because there are not many frontend-oriented tools in this area I guess.</p>
13+
<p>Actually I've only found one which provides an adapter for <a href="http://visionmedia.github.io/mocha/">Mocha</a> and actually
14+
works…</p>
15+
16+
17+
<p><strong><a href="http://blanketjs.org/">Blanket.js</a></strong> is an <em>easy to install, easy to configure,
18+
and easy to use JavaScript code coverage library that works both in-browser and
19+
with nodejs.</em></p>
20+
<p>Its use is dead easy, adding Blanket support to your Mocha test suite is just
21+
matter of adding this simple line to your HTML test file:</p>
22+
<pre><code>&lt;script src="vendor/blanket.js"
23+
data-cover-adapter="vendor/mocha-blanket.js"&gt;&lt;/script&gt;
24+
</code></pre>
25+
<p>Source files: <a href="https://raw.github.com/alex-seville/blanket/master/dist/qunit/blanket.min.js">blanket.js</a>,
26+
<a href="https://raw.github.com/alex-seville/blanket/master/src/adapters/mocha-blanket.js">mocha-blanket.js</a></p>
27+
<p>As an example, let's reuse the silly <code>Cow</code> example we used <a href="file:///code/2013/testing-frontend-javascript-code-using-mocha-chai-and-sinon/">in a previous episode</a>:</p>
28+
<pre><code>// cow.js
29+
(function(exports) {
30+
"use strict";
31+
32+
function Cow(name) {
33+
this.name = name || "Anon cow";
34+
}
35+
exports.Cow = Cow;
36+
37+
Cow.prototype = {
38+
greets: function(target) {
39+
if (!target)
40+
throw new Error("missing target");
41+
return this.name + " greets " + target;
42+
}
43+
};
44+
})(this);
45+
</code></pre>
46+
<p>And its test suite, powered by Mocha and <a href="http://chaijs.com/">Chai</a>:</p>
47+
<pre><code>var expect = chai.expect;
48+
49+
describe("Cow", function() {
50+
describe("constructor", function() {
51+
it("should have a default name", function() {
52+
var cow = new Cow();
53+
expect(cow.name).to.equal("Anon cow");
54+
});
55+
56+
it("should set cow's name if provided", function() {
57+
var cow = new Cow("Kate");
58+
expect(cow.name).to.equal("Kate");
59+
});
60+
});
61+
62+
describe("#greets", function() {
63+
it("should greet passed target", function() {
64+
var greetings = (new Cow("Kate")).greets("Baby");
65+
expect(greetings).to.equal("Kate greets Baby");
66+
});
67+
});
68+
});
69+
</code></pre>
70+
<p>Let's create the HTML test file for it, featuring Blanket and its adapter for
71+
Mocha:</p>
72+
<pre><code>&lt;!DOCTYPE html&gt;
73+
&lt;html&gt;
74+
&lt;head&gt;
75+
&lt;meta charset="utf-8"&gt;
76+
&lt;title&gt;Test&lt;/title&gt;
77+
&lt;link rel="stylesheet" media="all" href="vendor/mocha.css"&gt;
78+
&lt;/head&gt;
79+
&lt;body&gt;
80+
&lt;div id="mocha"&gt;&lt;/div&gt;
81+
&lt;div id="messages"&gt;&lt;/div&gt;
82+
&lt;div id="fixtures"&gt;&lt;/div&gt;
83+
&lt;script src="vendor/mocha.js"&gt;&lt;/script&gt;
84+
&lt;script src="vendor/chai.js"&gt;&lt;/script&gt;
85+
&lt;script src="vendor/blanket.js"
86+
data-cover-adapter="vendor/mocha-blanket.js"&gt;&lt;/script&gt;
87+
&lt;script&gt;mocha.setup('bdd');&lt;/script&gt;
88+
&lt;script src="cow.js" data-cover&gt;&lt;/script&gt;
89+
&lt;script src="cow_test.js"&gt;&lt;/script&gt;
90+
&lt;script&gt;mocha.run();&lt;/script&gt;
91+
&lt;/body&gt;
92+
&lt;/html&gt;
93+
</code></pre>
94+
<p><strong>Notes</strong>:</p>
95+
<ul>
96+
<li>Notice the <code>data-cover</code> attribute we added to the script tag loading the
97+
source of our library;</li>
98+
<li>The HTML test file <em>must</em> be served over HTTP for the adapter to be loaded.</li>
99+
</ul>
100+
<p>Running the tests now gives us something like this:</p>
101+
<p><img alt="screenshot" src="file:///static/code/2013/blanket-coverage.png"></p>
102+
<p>As you can see, the report at the bottom highlights that we haven't actually
103+
tested the case where an error is raised in case a target name is missing.
104+
We've been informed of that, nothing more, nothing less. We simply know we're
105+
missing a test here. Isn't this cool? I think so!</p>
106+
<p>Just remember that code coverage will only <a href="http://codebetter.com/karlseguin/2008/12/09/code-coverage-use-it-wisely/">bring you numbers</a> and raw
107+
information, not actual proofs that the whole of your <em>code logic</em> has been
108+
actually covered. If you ask me, the best inputs you can get about your code
109+
logic and implementation ever are the ones issued out of <a href="http://www.extremeprogramming.org/rules/pair.html">pair programming</a>
110+
sessions and <a href="http://alexgaynor.net/2013/sep/26/effective-code-review/">code reviews</a> — but that's another story.</p>
111+
<p><strong>So is code coverage silver bullet? No. Is it useful? Definitely. Happy testing!</strong></p>
112+
</section></div>

test/test-pages/001/source.html

+209
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
<!doctype html>
2+
<html class="no-js" lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
6+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
7+
<title>Get your Frontend JavaScript Code Covered | Code | Nicolas Perriault</title>
8+
<meta name="description" content="Nicolas Perriault's homepage.">
9+
<meta name="viewport" content="width=device-width">
10+
<link href="//fonts.googleapis.com/css?family=Asap:400,400italic,700,700italic&amp;subset=latin,latin-ext" rel="stylesheet" type="text/css">
11+
<link rel="stylesheet" type="text/css" href="/static/packed.css?1412806084">
12+
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
13+
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
14+
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
15+
<link rel="alternate" type="application/rss+xml" href="/carnet/feed/" title="Carnet (RSS)">
16+
<link rel="alternate" type="application/rss+xml" href="/feed/" title="Everything (RSS)">
17+
<!--[if lt IE 9]>
18+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
19+
<![endif]-->
20+
</head>
21+
<body class="code " onload="prettyPrint()">
22+
<!--[if lt IE 7]>
23+
<p class="chromeframe">Your browser is <em>ancient!</em> Please <a href="http://www.quirksmode.org/upgrade.html">upgrade</a>.</p>
24+
<![endif]-->
25+
<div class="container">
26+
<header class="main-title">
27+
<h1><a href="/">Hi, I'm <strong>Nicolas.</strong></a></h1>
28+
<small>I code stuff. I take photos. I write rants.</small>
29+
</header>
30+
<main class="contents" role="main">
31+
32+
33+
<article lang="en" class="code" itemscope itemtype="http://schema.org/BlogPosting">
34+
<link itemprop="url" href="/code/2013/get-your-frontend-javascript-code-covered/">
35+
<header>
36+
<h2><a itemprop="name" href="/code/2013/get-your-frontend-javascript-code-covered/">Get your Frontend JavaScript Code Covered</a></h2></header>
37+
38+
<section>
39+
<p><strong>So finally you're <a href="/code/2013/testing-frontend-javascript-code-using-mocha-chai-and-sinon/">testing your frontend JavaScript code</a>? Great! The more you
40+
write tests, the more confident you are with your code… but how much precisely?
41+
That's where <a href="http://en.wikipedia.org/wiki/Code_coverage">code coverage</a> might
42+
help.</strong></p>
43+
<p>The idea behind code coverage is to record which parts of your code (functions,
44+
statements, conditionals and so on) have been executed by your test suite, to
45+
compute metrics out of these data and usually to provide tools for navigating
46+
and inspecting them.</p>
47+
<p>Not a lot of frontend developers I know actually test their frontend code, and I
48+
can barely imagine how many of them have ever setup code coverage… Mostly
49+
because there are not many frontend-oriented tools in this area I guess.</p>
50+
<p>Actually I've only found one which provides an adapter for <a href="http://visionmedia.github.io/mocha/">Mocha</a> and actually
51+
works…</p>
52+
<blockquote class="twitter-tweet tw-align-center">
53+
<p>
54+
Drinking game for web devs: <br>
55+
(1) Think of a noun<br>
56+
(2) Google &quot;&lt;noun&gt;.js&quot;<br>
57+
(3) If a library with that name exists - drink
58+
</p>
59+
&mdash; Shay Friedman (@ironshay)
60+
<a href="https://twitter.com/ironshay/statuses/370525864523743232">August 22, 2013</a>
61+
</blockquote>
62+
63+
<p><strong><a href="http://blanketjs.org/">Blanket.js</a></strong> is an <em>easy to install, easy to configure,
64+
and easy to use JavaScript code coverage library that works both in-browser and
65+
with nodejs.</em></p>
66+
<p>Its use is dead easy, adding Blanket support to your Mocha test suite is just
67+
matter of adding this simple line to your HTML test file:</p>
68+
<pre><code>&lt;script src="vendor/blanket.js"
69+
data-cover-adapter="vendor/mocha-blanket.js"&gt;&lt;/script&gt;
70+
</code></pre>
71+
<p>Source files: <a href="https://raw.github.com/alex-seville/blanket/master/dist/qunit/blanket.min.js">blanket.js</a>,
72+
<a href="https://raw.github.com/alex-seville/blanket/master/src/adapters/mocha-blanket.js">mocha-blanket.js</a></p>
73+
<p>As an example, let's reuse the silly <code>Cow</code> example we used <a href="/code/2013/testing-frontend-javascript-code-using-mocha-chai-and-sinon/">in a previous episode</a>:</p>
74+
<pre><code>// cow.js
75+
(function(exports) {
76+
"use strict";
77+
78+
function Cow(name) {
79+
this.name = name || "Anon cow";
80+
}
81+
exports.Cow = Cow;
82+
83+
Cow.prototype = {
84+
greets: function(target) {
85+
if (!target)
86+
throw new Error("missing target");
87+
return this.name + " greets " + target;
88+
}
89+
};
90+
})(this);
91+
</code></pre>
92+
<p>And its test suite, powered by Mocha and <a href="http://chaijs.com/">Chai</a>:</p>
93+
<pre><code>var expect = chai.expect;
94+
95+
describe("Cow", function() {
96+
describe("constructor", function() {
97+
it("should have a default name", function() {
98+
var cow = new Cow();
99+
expect(cow.name).to.equal("Anon cow");
100+
});
101+
102+
it("should set cow's name if provided", function() {
103+
var cow = new Cow("Kate");
104+
expect(cow.name).to.equal("Kate");
105+
});
106+
});
107+
108+
describe("#greets", function() {
109+
it("should greet passed target", function() {
110+
var greetings = (new Cow("Kate")).greets("Baby");
111+
expect(greetings).to.equal("Kate greets Baby");
112+
});
113+
});
114+
});
115+
</code></pre>
116+
<p>Let's create the HTML test file for it, featuring Blanket and its adapter for
117+
Mocha:</p>
118+
<pre><code>&lt;!DOCTYPE html&gt;
119+
&lt;html&gt;
120+
&lt;head&gt;
121+
&lt;meta charset="utf-8"&gt;
122+
&lt;title&gt;Test&lt;/title&gt;
123+
&lt;link rel="stylesheet" media="all" href="vendor/mocha.css"&gt;
124+
&lt;/head&gt;
125+
&lt;body&gt;
126+
&lt;div id="mocha"&gt;&lt;/div&gt;
127+
&lt;div id="messages"&gt;&lt;/div&gt;
128+
&lt;div id="fixtures"&gt;&lt;/div&gt;
129+
&lt;script src="vendor/mocha.js"&gt;&lt;/script&gt;
130+
&lt;script src="vendor/chai.js"&gt;&lt;/script&gt;
131+
&lt;script src="vendor/blanket.js"
132+
data-cover-adapter="vendor/mocha-blanket.js"&gt;&lt;/script&gt;
133+
&lt;script&gt;mocha.setup('bdd');&lt;/script&gt;
134+
&lt;script src="cow.js" data-cover&gt;&lt;/script&gt;
135+
&lt;script src="cow_test.js"&gt;&lt;/script&gt;
136+
&lt;script&gt;mocha.run();&lt;/script&gt;
137+
&lt;/body&gt;
138+
&lt;/html&gt;
139+
</code></pre>
140+
<p><strong>Notes</strong>:</p>
141+
<ul>
142+
<li>Notice the <code>data-cover</code> attribute we added to the script tag loading the
143+
source of our library;</li>
144+
<li>The HTML test file <em>must</em> be served over HTTP for the adapter to be loaded.</li>
145+
</ul>
146+
<p>Running the tests now gives us something like this:</p>
147+
<p><img alt="screenshot" src="/static/code/2013/blanket-coverage.png" /></p>
148+
<p>As you can see, the report at the bottom highlights that we haven't actually
149+
tested the case where an error is raised in case a target name is missing.
150+
We've been informed of that, nothing more, nothing less. We simply know we're
151+
missing a test here. Isn't this cool? I think so!</p>
152+
<p>Just remember that code coverage will only <a href="http://codebetter.com/karlseguin/2008/12/09/code-coverage-use-it-wisely/">bring you numbers</a> and raw
153+
information, not actual proofs that the whole of your <em>code logic</em> has been
154+
actually covered. If you ask me, the best inputs you can get about your code
155+
logic and implementation ever are the ones issued out of <a href="http://www.extremeprogramming.org/rules/pair.html">pair programming</a>
156+
sessions and <a href="http://alexgaynor.net/2013/sep/26/effective-code-review/">code reviews</a> — but that's another story.</p>
157+
<p><strong>So is code coverage silver bullet? No. Is it useful? Definitely. Happy testing!</strong></p>
158+
</section>
159+
<aside>
160+
<p>
161+
<span class="article-author" itemprop="author" itemscope itemtype="http://schema.org/Person">
162+
<span itemprop="name">Nicolas Perriault</span>
163+
</span>
164+
<time datetime="2013-09-29" itemprop="datePublished">2013-09-29</time>
165+
— in <a href="/code/" itemprop="genre">Code</a>
166+
<a href="/code/2013/get-your-frontend-javascript-code-covered/">Permalink</a>
167+
<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/">License</a>
168+
169+
<a href="http://flattr.com/submit/auto?url=https://nicolas.perriault.net/code/2013/get-your-frontend-javascript-code-covered/&amp;title=Get your Frontend JavaScript Code Covered&amp;user_id=n1k0&amp;category=software&amp;language=en">flattr this</a>
170+
</p>
171+
</aside>
172+
<hr>
173+
<nav>
174+
<a class="prev" href="/code/2013/functional-javascript-for-crawling-the-web/">Functional JavaScript for crawling the Web</a>
175+
|
176+
<a class="next" href="/code/2013/testing-frontend-javascript-code-using-mocha-chai-and-sinon/">Testing your frontend JavaScript code using mocha, chai, and sinon</a>
177+
</nav>
178+
</article>
179+
180+
181+
</main>
182+
<nav class="sidebar">
183+
<ul>
184+
<li class="home"><a href="/" hreflang="en">Home</a></li>
185+
<li class="code"><a href="/code/" hreflang="en">Code</a></li>
186+
<li class="photography"><a href="/photography/" hreflang="en">Photography</a></li>
187+
<li class="talks"><a href="/talks/" hreflang="en">Talks</a></li>
188+
<li class="carnet"><a href="/carnet/" hreflang="fr">Carnet <span>fr</span></a></li>
189+
<li class="contact"><a href="/contact/" hreflang="en">Contact</a></li>
190+
</ul>
191+
</nav>
192+
<footer class="site-footer">
193+
<p>
194+
&copy; 2012 Nicolas Perriault
195+
<a href="https://twitter.com/n1k0">Tweet at me</a>
196+
<a href="https://github.com/n1k0">Get my code</a>
197+
<a href="http://500px.com/n1k0">Enjoy my pics</a>
198+
<a href="/contact/">Contact me</a>
199+
</p>
200+
</footer>
201+
</div>
202+
<!-- /container -->
203+
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
204+
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.7.1.min.js"><\/script>')</script>
205+
<script type="text/javascript" src="/static/js/libs/prettify/prettify.js"></script>
206+
<script type="text/javascript" src="/static/js/app.js"></script>
207+
<script src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
208+
</body>
209+
</html>

0 commit comments

Comments
 (0)