Skip to content

Commit fc641fa

Browse files
bndnsmthdevongovett
authored andcommitted
Improve Code Coverage (#562)
1 parent 74d70f8 commit fc641fa

17 files changed

Lines changed: 625 additions & 21 deletions

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
"posthtml-include": "^1.1.0",
7474
"prettier": "^1.9.1",
7575
"rimraf": "^2.6.1",
76+
"sinon": "^4.2.2",
7677
"sourcemap-validator": "^1.0.6",
7778
"stylus": "^0.54.5",
7879
"typescript": "^2.6.2"

src/Logger.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class Logger {
2525
this.lines += message.split('\n').length;
2626
}
2727

28-
console.log(message);
28+
this._log(message);
2929
}
3030

3131
log(message) {
@@ -119,6 +119,10 @@ class Logger {
119119
handleMessage(options) {
120120
this[options.method](...options.args);
121121
}
122+
123+
_log(message) {
124+
console.log(message);
125+
}
122126
}
123127

124128
// If we are in a worker, make a proxy class which will

src/assets/WebManifestAsset.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ class WebManifestAsset extends Asset {
1616
icon.src = this.addURLDependency(icon.src);
1717
}
1818
}
19-
19+
2020
if (Array.isArray(this.ast.screenshots)) {
2121
for (let shot of this.ast.screenshots) {
2222
shot.src = this.addURLDependency(shot.src);
2323
}
2424
}
25-
25+
2626
if (this.ast.serviceworker && this.ast.serviceworker.src) {
2727
this.ast.serviceworker.src = this.addURLDependency(
2828
this.ast.serviceworker.src

src/utils/customErrors.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
let serverErrorList = {
1+
const serverErrorList = {
22
EACCES: "You don't have access to bind the server to port {port}.",
33
EADDRINUSE: 'There is already a process listening on port {port}.'
44
};
55

66
function serverErrors(err, port) {
7-
let desc = serverErrorList[err.code].replace(/{port}/g, port);
8-
if (!desc) {
9-
desc = `Error: ${
10-
err.code
11-
} occurred while setting up server on port ${port}.`;
7+
let desc = `Error: ${
8+
err.code
9+
} occurred while setting up server on port ${port}.`;
10+
11+
if (serverErrorList[err.code]) {
12+
desc = serverErrorList[err.code].replace(/{port}/g, port);
1213
}
14+
1315
return desc;
1416
}
1517

src/utils/fs.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ exports.readFile = promisify(fs.readFile);
66
exports.writeFile = promisify(fs.writeFile);
77
exports.stat = promisify(fs.stat);
88
exports.readdir = promisify(fs.readdir);
9+
exports.unlink = promisify(fs.unlink);
910

1011
exports.exists = function(filename) {
1112
return new Promise(resolve => {

test/asset.js

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,24 @@
1-
const {strictEqual} = require('assert');
1+
const assert = require('assert');
22
const Asset = require('../src/Asset');
33

44
describe('Asset', () => {
5+
it('should include default implementations', async () => {
6+
const a = new Asset(__filename, undefined, {rootDir: '/root/dir'});
7+
Object.assign(a, {
8+
type: 'type',
9+
contents: 'contents'
10+
});
11+
12+
const err = new Error();
13+
14+
assert(a.shouldInvalidate() === false);
15+
assert(a.mightHaveDependencies());
16+
assert.deepEqual(await a.generate(), {
17+
type: 'contents'
18+
});
19+
assert.equal(a.generateErrorMessage(err), err);
20+
});
21+
522
describe('addURLDependency', () => {
623
const bundleName = 'xyz';
724
const options = {
@@ -18,21 +35,27 @@ describe('Asset', () => {
1835

1936
it('should ignore urls', () => {
2037
const url = 'https://parceljs.org/assets.html';
21-
strictEqual(asset.addURLDependency(url), url);
38+
assert.strictEqual(asset.addURLDependency(url), url);
2239
});
2340

2441
it('should ignore empty string', () => {
25-
strictEqual(asset.addURLDependency(''), '');
42+
assert.strictEqual(asset.addURLDependency(''), '');
2643
});
2744

2845
it('should generate bundle name', () => {
29-
strictEqual(asset.addURLDependency('foo'), bundleName);
46+
assert.strictEqual(asset.addURLDependency('foo'), bundleName);
3047
});
3148

3249
it('should preserve query and hash', () => {
33-
strictEqual(asset.addURLDependency('foo#bar'), `${bundleName}#bar`);
34-
strictEqual(asset.addURLDependency('foo?bar'), `${bundleName}?bar`);
35-
strictEqual(
50+
assert.strictEqual(
51+
asset.addURLDependency('foo#bar'),
52+
`${bundleName}#bar`
53+
);
54+
assert.strictEqual(
55+
asset.addURLDependency('foo?bar'),
56+
`${bundleName}?bar`
57+
);
58+
assert.strictEqual(
3659
asset.addURLDependency('foo?bar#baz'),
3760
`${bundleName}?bar#baz`
3861
);

test/bundler.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const assert = require('assert');
2+
const sinon = require('sinon');
23
const {bundler, nextBundle} = require('./utils');
34

45
describe('bundler', function() {
@@ -9,4 +10,43 @@ describe('bundler', function() {
910
await nextBundle(b);
1011
assert(b.mainAsset);
1112
});
13+
14+
it('should defer bundling if a bundle is pending', async () => {
15+
const b = bundler(__dirname + '/integration/html/index.html');
16+
b.pending = true; // bundle in progress
17+
const spy = sinon.spy(b, 'bundle');
18+
19+
// first bundle, with existing bundle pending
20+
const bundlePromise = b.bundle();
21+
22+
// simulate bundle finished
23+
b.pending = false;
24+
b.emit('buildEnd');
25+
26+
// wait for bundle to complete
27+
await bundlePromise;
28+
29+
assert(spy.calledTwice);
30+
});
31+
32+
it('should enforce asset type path to be a string', () => {
33+
const b = bundler(__dirname + '/integration/html/index.html');
34+
35+
assert.throws(() => {
36+
b.addAssetType('.ext', {});
37+
}, 'should be a module path');
38+
});
39+
40+
it('should enforce setup before bundling', () => {
41+
const b = bundler(__dirname + '/integration/html/index.html');
42+
b.farm = true; // truthy
43+
44+
assert.throws(() => {
45+
b.addAssetType('.ext', __filename);
46+
}, 'before bundling');
47+
48+
assert.throws(() => {
49+
b.addPackager('type', 'packager');
50+
}, 'before bundling');
51+
});
1252
});

test/customErrors.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const assert = require('assert');
2+
const customErrors = require('../src/utils/customErrors');
3+
4+
const port = 1234;
5+
6+
const EACCES = new Error();
7+
EACCES.code = 'EACCES';
8+
const EADDRINUSE = new Error();
9+
EADDRINUSE.code = 'EADDRINUSE';
10+
11+
describe('customErrors', () => {
12+
it('should include port in server errors', () => {
13+
const msg = customErrors.serverErrors(EACCES, port);
14+
assert(msg.includes(port));
15+
});
16+
17+
it('should handle known server errors', () => {
18+
let msg = customErrors.serverErrors(EACCES, port);
19+
assert(msg.includes(`don't have access`));
20+
21+
msg = customErrors.serverErrors(EADDRINUSE, port);
22+
assert(msg.includes('already'));
23+
});
24+
25+
it('should handled unknown server errors', () => {
26+
let msg = customErrors.serverErrors(new Error(), port);
27+
assert(msg.includes(port));
28+
});
29+
});

test/fs-cache.js

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
const assert = require('assert');
2+
const path = require('path');
3+
const rimraf = require('rimraf');
4+
const fs = require('../src/utils/fs');
5+
const promisify = require('../src/utils/promisify');
6+
const {sleep} = require('./utils');
7+
const ncp = promisify(require('ncp'));
8+
const FSCache = require('../src/FSCache');
9+
10+
const cachePath = path.join(__dirname, '.cache');
11+
const inputPath = path.join(__dirname, '/input');
12+
13+
const getMTime = async file => {
14+
const stat = await fs.stat(file);
15+
const mtime = stat.mtime.getTime();
16+
return mtime;
17+
};
18+
19+
describe('FSCache', () => {
20+
beforeEach(() => {
21+
rimraf.sync(cachePath);
22+
rimraf.sync(inputPath);
23+
});
24+
25+
it('should create directory on ensureDirExists', async () => {
26+
let exists = await fs.exists(cachePath);
27+
assert(!exists);
28+
29+
const cache = new FSCache({cacheDir: cachePath});
30+
await cache.ensureDirExists();
31+
32+
exists = await fs.exists(cachePath);
33+
assert(exists);
34+
});
35+
36+
it('should cache resources', async () => {
37+
const cache = new FSCache({cacheDir: cachePath});
38+
await cache.write(__filename, {a: 'test', b: 1, dependencies: []});
39+
40+
let cached = await cache.read(__filename);
41+
assert.equal(cached.a, 'test');
42+
assert.equal(cached.b, 1);
43+
});
44+
45+
it('should return null for invalidated resources', async () => {
46+
const cache = new FSCache({cacheDir: cachePath});
47+
cache.invalidate(__filename);
48+
49+
let cached = await cache.read(__filename);
50+
assert.equal(cached, null);
51+
});
52+
53+
it('should remove file on delete', async () => {
54+
let cache = new FSCache({cacheDir: cachePath});
55+
await cache.write(__filename, {a: 'test', b: 1, dependencies: []});
56+
await cache.delete(__filename);
57+
58+
let cached = await cache.read(__filename);
59+
assert.equal(cached, null);
60+
});
61+
62+
it('should remove from invalidated on write', async () => {
63+
const cache = new FSCache({cacheDir: cachePath});
64+
cache.invalidate(__filename);
65+
66+
assert(cache.invalidated.has(__filename));
67+
68+
await cache.write(__filename, {a: 'test', b: 1, dependencies: []});
69+
70+
assert(!cache.invalidated.has(__filename));
71+
});
72+
73+
it('should include mtime for dependencies included in parent', async () => {
74+
const cache = new FSCache({cacheDir: cachePath});
75+
const mtime = await getMTime(__filename);
76+
77+
await cache.write(__filename, {
78+
a: 'test',
79+
b: 1,
80+
dependencies: [
81+
{
82+
includedInParent: true,
83+
name: __filename
84+
},
85+
{
86+
name: __filename
87+
}
88+
]
89+
});
90+
91+
const cached = await cache.read(__filename);
92+
assert.equal(cached.dependencies[0].mtime, mtime);
93+
assert.equal(cached.dependencies[1].mtime, undefined);
94+
});
95+
96+
it('should invalidate when dependency included in parent changes', async () => {
97+
const cache = new FSCache({cacheDir: cachePath});
98+
await ncp(__dirname + '/integration/fs', inputPath);
99+
const filePath = path.join(inputPath, 'test.txt');
100+
101+
await cache.write(__filename, {
102+
dependencies: [
103+
{
104+
includedInParent: true,
105+
name: filePath
106+
}
107+
]
108+
});
109+
110+
// delay and update dependency
111+
await sleep(50);
112+
await fs.writeFile(filePath, 'world');
113+
114+
const cached = await cache.read(__filename);
115+
assert.equal(cached, null);
116+
});
117+
118+
it('should return null on read error', async () => {
119+
const cache = new FSCache({cacheDir: cachePath});
120+
const cached = await cache.read(
121+
path.join(__dirname, '/does/not/exist.txt')
122+
);
123+
124+
assert.equal(cached, null);
125+
});
126+
127+
it('should continue without throwing on write error', async () => {
128+
const cache = new FSCache({cacheDir: cachePath});
129+
const filePath = path.join(__dirname, '/does/not/exist.txt');
130+
131+
assert.doesNotThrow(async () => {
132+
await cache.write(__filename, {
133+
dependencies: [
134+
{
135+
includedInParent: true,
136+
name: filePath
137+
}
138+
]
139+
});
140+
});
141+
});
142+
});

0 commit comments

Comments
 (0)