opensphere-build-index
Version:
Generates index HTML files for Google Closure projects.
383 lines (328 loc) • 11.8 kB
JavaScript
const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));
const rimraf = Promise.promisify(require('rimraf'));
const mkdirp = Promise.promisifyAll(require('mkdirp'));
const path = require('path');
const osIndex = require('../buildindex.js');
const chai = require('chai');
const spies = require('chai-spies');
chai.use(spies);
const expect = chai.expect;
const mockDir = path.resolve(__dirname, 'mock');
const modulesDir = path.join(mockDir, 'node_modules', 'test');
const buildDir = path.join(mockDir, '.build');
const distDir = path.join(mockDir, 'dist');
const numResources = 5;
/**
* The gcc args file generated by opensphere-build-resolver.
* @type {string}
*/
const gccArgsFile = 'gcc-args.json';
const baseTemplate = '<!DOCTYPE html>\n' +
'<title>Test Template</title>\n' +
'<!--VENDOR_CSS-->\n' +
'<!--APP_CSS-->\n' +
'<div id="ng-app" ng-init="version=\'@appVersion@\';versionPath=\'@version@\'">\n' +
'<test-app></test-app>\n' +
'</div>\n' +
'<!--VENDOR_JS-->\n' +
'<!--APP_JS-->';
const noVendorTemplate = '<!DOCTYPE html>\n' +
'<title>Test Template</title>\n' +
'<!--APP_CSS-->\n' +
'<div id="ng-app" ng-init="version=\'@appVersion@\';versionPath=\'@version@\'">\n' +
'<test-app></test-app>\n' +
'</div>\n' +
'<!--APP_JS-->';
const noAppTemplate = '<!DOCTYPE html>\n' +
'<title>Test Template</title>\n' +
'<!--VENDOR_CSS-->\n' +
'<div id="ng-app" ng-init="version=\'@appVersion@\';versionPath=\'@version@\'">\n' +
'<test-app></test-app>\n' +
'</div>\n' +
'<!--VENDOR_JS-->';
/**
* The resource files generated by the opensphere-build-resolver resource plugin.
* @type {!Array<string>}
*/
const resourceFiles = [
'resources-css-debug-index1',
'resources-css-debug-index2',
'resources-css-debug-noapp',
'resources-css-debug-novendor',
'resources-css-dist-index1',
'resources-css-dist-index2',
'resources-css-dist-noapp',
'resources-css-dist-novendor',
'resources-js-debug-index1',
'resources-js-debug-index2',
'resources-js-debug-noapp',
'resources-js-debug-novendor',
'resources-js-dist-index1',
'resources-js-dist-index2',
'resources-js-dist-noapp',
'resources-js-dist-novendor'
];
/**
* Recreate the build directory.
* @return {Promise} A promise that resolves when the directory is ready.
*/
const cleanMockDirectory = function() {
return rimraf(mockDir)
.then(function() {
return Promise.map([buildDir, distDir, modulesDir], function(dir) {
return mkdirp.mkdirpAsync(dir);
});
});
};
/**
* If an index has APP tags.
* @param {string} key The index key.
* @return {boolean}
*/
const hasAppTag = function(key) {
return key.indexOf('noapp') === -1;
};
/**
* If an index has APP tags.
* @param {string} key The index key.
* @return {boolean}
*/
const hasVendorTag = function(key) {
return key.indexOf('novendor') === -1;
};
/**
* Generate HTML templates.
* @return {Promise} A promise that resolves when the templates are ready.
*/
const generateTemplates = function() {
return Promise.map([
path.join(mockDir, 'index1-template.html'),
path.join(modulesDir, 'index2-template.html'),
path.join(mockDir, 'noapp-template.html'),
path.join(mockDir, 'novendor-template.html')
], function(file) {
const template = !hasAppTag(file) ? noAppTemplate : !hasVendorTag(file) ? noVendorTemplate : baseTemplate;
return fs.writeFileAsync(file, template);
});
};
/**
* Generate a test file.
* @return {Promise} A promise that resolves when the files have been created.
*/
const generateResourceFiles = function() {
return Promise.map(resourceFiles, function(fileName) {
const filePath = path.join(buildDir, fileName);
const fileParts = fileName.split('-');
const ext = '.' + fileParts[1];
const resourcePath = fileParts.join(path.sep);
const resources = [];
for (let i = 0; i < numResources; i++) {
resources.push(path.join(resourcePath, i + ext));
}
const content = resources.join('\n');
return fs.writeFileAsync(filePath, content);
});
};
/**
* Generate the gcc manifest file.
* @return {Promise} A promise that resolves when the manifest has been created.
*/
const generateGccArgs = function() {
const filePath = path.join(buildDir, gccArgsFile);
const args = {
js: [
'!/not/included',
'/also/not/from/google-closure-library/sources',
'/included/src',
'/also/included/src'
],
entry_point: [
'goog:test_entry'
]
};
return fs.writeFileAsync(filePath, JSON.stringify(args));
};
/**
* Generate the index files.
* @return {Promise} A promise that resolves when generation completes.
*/
const generateIndex = function() {
return osIndex.buildIndex({
appVersion: 'test-version',
basePath: mockDir,
distPath: path.join('test', 'mock', 'dist'),
templates: [
{
id: 'index1'
},
{
id: 'index2',
file: path.join(modulesDir, 'index2-template.html')
},
{
id: 'noapp'
},
{
id: 'novendor'
}
],
debugCss: path.join('styles', 'debug.css'),
compiledCss: path.join('styles', 'test.min.css'),
debugJs: path.join(buildDir, 'test.js'),
compiledJs: 'test.min.js'
});
};
before(function() {
return cleanMockDirectory()
.then(generateTemplates)
.then(generateResourceFiles)
.then(generateGccArgs)
.then(generateIndex);
});
describe('opensphere-build-index', function() {
describe('debug index', function() {
const indexFiles = {};
it('generates debug index files from the templates', function() {
expect(fs.existsSync(path.join(mockDir, 'index1.html')))
.to.equal(true, 'first debug template missing');
expect(fs.existsSync(path.join(mockDir, 'index2.html')))
.to.equal(true, 'second debug template missing');
});
it('reads the debug index', function() {
return Promise.map(['index1.html', 'index2.html', 'noapp.html', 'novendor.html'], function(fileName) {
const key = fileName.replace(/\..*/, '');
return fs.readFileAsync(path.join(mockDir, fileName), 'utf8').then(function(file) {
indexFiles[key] = file;
return Promise.resolve();
});
})
.catch(function(e) {
expect(e).to.equal(null, 'encountered an error reading index', e);
});
});
it('replaces the version strings', function() {
for (const key in indexFiles) {
const index = indexFiles[key];
const lines = index.split('\n');
const versionLine = lines.find(function(line) {
return /ng-init="version='dev';versionPath=''"/.test(line);
});
expect(versionLine).not.to.equal(null);
}
});
it('adds link tags to the index', function() {
for (const key in indexFiles) {
const index = indexFiles[key];
const lines = index.split('\n');
const links = lines.filter(function(line) {
return /^<link /.test(line);
});
let inspectedLinks = 0;
if (hasVendorTag(key)) {
for (let i = 0; i < numResources; i++) {
const linkUrl = 'resources/css/debug/' + key + '/' + i + '.css';
const linkTag = '<link rel="stylesheet" href="' + linkUrl + '">';
expect(links[i]).to.equal(linkTag, key + ' missing css file from gcc resources');
inspectedLinks++;
}
}
if (hasAppTag(key)) {
expect(links[inspectedLinks]).to.equal('<link rel="stylesheet" href="styles/debug.css">');
inspectedLinks++;
}
expect(links.length).to.equal(inspectedLinks, key + ' has incorrect number of link elements');
}
});
it('adds script tags to the index', function() {
for (const key in indexFiles) {
const index = indexFiles[key];
const lines = index.split('\n');
const scripts = lines.filter(function(line) {
return /^<script( src|>)/.test(line);
});
let inspectedScripts = 0;
if (hasVendorTag(key)) {
for (let i = 0; i < numResources; i++) {
const scriptUrl = 'resources/js/debug/' + key + '/' + i + '.js';
expect(scripts[i]).to.have.string(scriptUrl, key + ' missing/incorrect js file from gcc resources');
inspectedScripts++;
}
}
if (hasAppTag(key)) {
expect(scripts[inspectedScripts]).to.have.string('.build/gcc-defines-debug.js',
key + ' missing gcc debug defines');
inspectedScripts++;
expect(scripts[inspectedScripts]).to.have.string('.build/test.js', key + ' missing app index');
inspectedScripts++;
}
expect(scripts.length).to.equal(inspectedScripts, key + ' has incorrect number of debug scripts');
}
});
});
describe('distribution index', function() {
const indexFiles = {};
it('generates distribution index files from the templates', function() {
expect(fs.existsSync(path.join(distDir, 'index1.html')))
.to.equal(true, 'first dist template missing');
expect(fs.existsSync(path.join(distDir, 'index2.html')))
.to.equal(true, 'first second template missing');
});
it('reads the distribution index', function() {
return Promise.map(['index1.html', 'index2.html'], function(fileName) {
return fs.readFileAsync(path.join(distDir, fileName), 'utf8').then(function(file) {
const key = fileName.replace(/\.html/, '');
indexFiles[key] = file;
return Promise.resolve();
});
})
.catch(function(e) {
expect(e).to.equal(null, 'encountered an error reading index', e);
});
});
it('replaces the version strings', function() {
for (const key in indexFiles) {
const index = indexFiles[key];
const lines = index.split('\n');
const versionLine = lines.find(function(line) {
return /ng-init="version='test-version';versionPath='test-version\/'"/.test(line);
});
expect(versionLine).not.to.equal(null);
}
});
it('adds link tags to the index', function() {
for (const key in indexFiles) {
const index = indexFiles[key];
const lines = index.split('\n');
const links = lines.filter(function(line) {
return /^<link /.test(line);
});
expect(links.length).to.equal(numResources + 1, key + ' has incorrect number of link elements');
for (let i = 0; i < numResources; i++) {
const linkUrl = 'resources/css/dist/' + key + '/' + i + '.css';
const linkTag = '<link rel="stylesheet" href="' + linkUrl + '">';
expect(links[i]).to.equal(linkTag, key + ' missing css file from gcc resources');
}
expect(links[numResources]).to.equal('<link rel="stylesheet" href="styles/test.min.css">',
key + ' missing compiled css file');
}
});
it('adds script tags to the index', function() {
for (const key in indexFiles) {
const index = indexFiles[key];
const lines = index.split('\n');
const scripts = lines.filter(function(line) {
return /^<script src=/.test(line);
});
expect(scripts.length).to.equal(numResources + 1, key + ' has incorrect number of script elements');
for (let i = 0; i < numResources; i++) {
const scriptUrl = 'resources/js/dist/' + key + '/' + i + '.js';
const scriptTag = '<script src="' + scriptUrl + '"></script>';
expect(scripts[i]).to.equal(scriptTag, key + ' missing/incorrect js file from gcc resources');
}
expect(scripts[numResources]).to.equal('<script src="test.min.js"></script>',
key + ' missing compiled js file');
}
});
});
});