test/file-change-cache.js
import './support.js';
import FileChangeCache from '../lib/file-change-cache';
import path from 'path';
import fs from 'fs';
import pify from 'pify';
const pfs = pify(fs);
describe('The file changed cache', function() {
beforeEach(function() {
this.fixture = new FileChangeCache(null);
});
it("Correctly computes a file hash for a canned file", async function() {
const expectedInfo = {
hash: '4a92e95074156e8b46869519c43ddf10b59299a4',
hasSourceMap: false,
isInNodeModules: false,
isMinified: false,
isFileBinary: false
};
let input = path.resolve(__dirname, '..', 'test', 'fixtures', 'valid.js');
let result = await this.fixture.getHashForPath(input);
expect(result.sourceCode).to.be.ok;
delete result.sourceCode;
expect(result).to.deep.equal(expectedInfo);
});
it("Correctly handles binary files", async function() {
const expectedInfo = {
hash: '83af4f2b5a3e2dda1a322ac75799eee337d569a5',
hasSourceMap: false,
isInNodeModules: false,
isMinified: false,
isFileBinary: true
};
let input = path.resolve(__dirname, '..', 'test', 'fixtures', 'binaryfile.zip');
let result = await this.fixture.getHashForPath(input);
expect(result.binaryData).to.be.ok;
expect(result.binaryData.length > 16).to.be.ok;
delete result.binaryData;
expect(result).to.deep.equal(expectedInfo);
});
it("Correctly computes a file hash for a canned file syncronously", function() {
const expectedInfo = {
hash: '4a92e95074156e8b46869519c43ddf10b59299a4',
hasSourceMap: false,
isInNodeModules: false,
isMinified: false,
isFileBinary: false
};
let input = path.resolve(__dirname, '..', 'test', 'fixtures', 'valid.js');
let result = this.fixture.getHashForPathSync(input);
expect(result.sourceCode).to.be.ok;
delete result.sourceCode;
expect(result).to.deep.equal(expectedInfo);
});
it("Doesn't rerun the file hash if you ask for it twice", async function() {
const expectedInfo = {
hash: '4a92e95074156e8b46869519c43ddf10b59299a4',
hasSourceMap: false,
isInNodeModules: false,
isMinified: false,
isFileBinary: false
};
let input = path.join(__dirname, '..', 'test', 'fixtures', 'valid.js');
let result = await this.fixture.getHashForPath(input);
expect(result.sourceCode).to.be.ok;
delete result.sourceCode;
expect(result).to.deep.equal(expectedInfo);
this.fixture.calculateHashForFile = () => Promise.reject(new Error("Didn't work"));
result = await this.fixture.getHashForPath(input);
// NB: The file hash cache itself shouldn't hold onto file contents, it should
// only opportunistically return it if it had to read the contents anyways
expect(result.sourceCode).to.be.not.ok;
expect(result).to.deep.equal(expectedInfo);
});
it("Throws on cache misses in production mode", function() {
this.fixture = new FileChangeCache(true);
let input = path.join(__dirname, '..', 'test', 'fixtures', 'valid.js');
expect(this.fixture.getHashForPath(input)).to.eventually.throw(Error);
});
it("Successfully saves and loads its cache information", async function() {
let input = path.join(__dirname, '..', 'test', 'fixtures', 'valid.js');
await this.fixture.getHashForPath(input);
let targetCache = path.join(__dirname, 'fileChangeCache1.json.gz');
try {
await this.fixture.save(targetCache);
this.fixture = await FileChangeCache.loadFromFile(targetCache, null);
this.fixture.calculateHashForFile = () => Promise.reject(new Error("Didn't work"));
await this.fixture.getHashForPath(input);
} finally {
fs.unlinkSync(targetCache);
}
});
it("Detects changes to files and reruns hash", async function() {
const expectedInfo = {
hash: '4a92e95074156e8b46869519c43ddf10b59299a4',
hasSourceMap: false,
isInNodeModules: false,
isMinified: false,
isFileBinary: false
};
let realInput = path.join(__dirname, '..', 'test', 'fixtures', 'valid.js');
let input = path.join(__dirname, 'tempfile.tmp');
let contents = await pfs.readFile(realInput);
await pfs.writeFile(input, contents);
let stat1 = await pfs.stat(realInput);
let stat2 = await pfs.stat(input);
expect(stat1.size).to.equal(stat2.size);
try {
let result = await this.fixture.getHashForPath(input);
expect(result.sourceCode).to.be.ok;
delete result.sourceCode;
expect(result).to.deep.equal(expectedInfo);
let fd = await pfs.open(input, 'a');
await pfs.write(fd, '\n\n\n\n');
await pfs.close(fd);
// NB: Declaring these as 'var' works around a BabelJS compilation bug
// where it can't deal with let + closure scoping
var realCalc = this.fixture.calculateHashForFile;
var hasCalledCalc = false;
this.fixture.calculateHashForFile = function(...args) {
hasCalledCalc = true;
return realCalc(...args);
};
result = await this.fixture.getHashForPath(input);
expect(result.sourceCode).to.be.ok;
delete result.sourceCode;
expect(result).not.to.deep.equal(expectedInfo);
expect(hasCalledCalc).to.be.ok;
} finally {
fs.unlinkSync(input);
}
});
it("Successfully finds if a file has a source map", async function() {
let input = path.join(__dirname, '..', 'test', 'fixtures', 'source_map.js');
let result = await this.fixture.getHashForPath(input);
expect(result.hasSourceMap).to.be.ok;
});
it("Successfully finds if a file has a source map synchronously", function() {
let input = path.join(__dirname, '..', 'test', 'fixtures', 'source_map.js');
let result = this.fixture.getHashForPathSync(input);
expect(result.hasSourceMap).to.be.ok;
});
it("Successfully finds if a file is minified", async function() {
let input = path.join(__dirname, '..', 'test', 'fixtures', 'minified.js');
let result = await this.fixture.getHashForPath(input);
expect(result.isMinified).to.be.ok;
});
it("Successfully finds if a file is in node_modules", async function() {
let input = path.join(__dirname, '..', 'node_modules', 'electron-compilers', 'package.json');
let result = await this.fixture.getHashForPath(input);
expect(result.isInNodeModules).to.be.ok;
});
});