blob: 98f9ee3e825104f229b3463b1cd30e39d3c97673 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
*/
const fs = require('fs-extra');
const path = require('path');
const rewire = require('rewire');
const templateDir = path.resolve(__dirname, '..', '..', '..', 'bin', 'templates');
const Api = rewire(path.join(templateDir, 'cordova', 'Api'));
const tmpDir = path.join(__dirname, '../../../temp');
const apiRequire = Api.__get__('require');
const FIXTURES = path.join(__dirname, '..', 'fixtures');
const pluginFixture = path.join(FIXTURES, 'testplugin');
const testProjectDir = path.join(tmpDir, 'testapp');
function dirExists (dir) {
return fs.existsSync(dir) && fs.statSync(dir).isDirectory();
}
function fileExists (file) {
return fs.existsSync(file) && fs.statSync(file).isFile();
}
function readJson (file) {
return JSON.parse(
fs.readFileSync(
file
)
);
}
function writeJson (file, json) {
fs.writeFileSync(
file,
JSON.stringify(json, null, ' '),
'utf-8'
);
}
describe('Api class', () => {
fs.ensureDirSync(tmpDir);
fs.copySync(path.resolve(FIXTURES, 'testapp'), path.resolve(tmpDir, 'testapp'));
const api = new Api(null, testProjectDir);
const apiEvents = Api.__get__('selfEvents');
apiEvents.removeAllListeners();
const rootDir = testProjectDir;
const mockExpectedLocations = {
platformRootDir: rootDir,
root: rootDir,
www: path.join(rootDir, 'www'),
res: path.join(rootDir, 'res'),
platformWww: path.join(rootDir, 'platform_www'),
configXml: path.join(rootDir, 'config.xml'),
defaultConfigXml: path.join(rootDir, 'cordova/defaults.xml'),
build: path.join(rootDir, 'build'),
buildRes: path.join(rootDir, 'build-res'),
cache: path.join(rootDir, 'cache'),
cordovaJs: 'bin/templates/project/assets/www/cordova.js',
cordovaJsSrc: 'cordova-js-src'
};
it('should exist', () => {
expect(Api).toBeDefined();
});
describe('Api constructor', () => {
it('should be ale to construct.', () => {
expect(api).toBeDefined();
});
it('should have set platform as electron.', () => {
expect(api.platform).toBe('electron');
});
it('should have set the root path.', () => {
/**
* In Unit Testing:
* The API file path is located in "cordova-electron/bin/templates/cordova".
* The expected path is the "cordova-electron/bin/templates" dir.
*
* In production:
* The API file path is actually located in "<project_dir>/platforms/electron/cordova".
* The expected path is "<project_dir>/platforms/electron" which is the electron's platform root dir
*/
expect(api.root).toBe(rootDir);
});
it('should configure proper locations.', () => {
expect(api.locations).toEqual(mockExpectedLocations);
});
});
describe('getPlatformInfo method', () => {
beforeEach(() => {
// Mocking require that is called to get version.
Api.__set__('require', () => {
return '1.0.0';
});
});
afterEach(() => {
Api.__set__('require', apiRequire);
});
it('should return object containing platform information', () => {
const actual = api.getPlatformInfo();
const expected = {
locations: mockExpectedLocations,
root: rootDir,
name: 'electron',
version: '1.0.0',
projectConfig: undefined
};
expect(actual).toEqual(expected);
});
});
describe('prepare method', () => {
const prepareSpy = jasmine.createSpy('prepare');
beforeEach(() => {
// Mocking require that is called to get version.
Api.__set__('require', () => {
return {
prepare: prepareSpy
};
});
});
afterEach(() => {
Api.__set__('require', apiRequire);
});
it('should return object containing platform information', () => {
api.prepare('', {});
expect(prepareSpy).toHaveBeenCalledWith(jasmine.any(String), jasmine.any(Object));
});
});
describe('addPlugin method', () => {
let logs = {};
beforeEach(() => {
fs.removeSync(path.resolve(testProjectDir, 'electron.json'));
fs.removeSync(path.resolve(testProjectDir, 'www'));
apiEvents.addListener('verbose', (data) => {
logs.verbose.push(data);
});
logs = {
verbose: []
};
});
afterEach(() => {
apiEvents.removeAllListeners();
});
it('should reject when missing plugin information', () => {
api.addPlugin().then(
() => {
fail('Unwanted code branch');
},
(error) => {
expect(error).toEqual(new Error('The parameter is incorrect. The first parameter should be valid PluginInfo instance'));
}
);
});
it('empty plugin', () => api.addPlugin({
id: 'empty_plugin',
getPlatformsArray: () => { return ['electron']; },
getFilesAndFrameworks: (platform) => { return []; },
getAssets: (platform) => { return []; },
getJsModules: (platform) => { return []; },
getConfigFiles: (platform) => { return []; }
}, { }).then(
(result) => {
expect(result).not.toBeDefined();
expect(dirExists(path.resolve(testProjectDir, 'www'))).toBeTruthy();
expect(fileExists(path.resolve(testProjectDir, 'electron.json'))).toBeTruthy();
expect(fileExists(path.resolve(testProjectDir, 'www', 'cordova_plugins.js'))).toBeTruthy();
},
(error) => {
fail('Unwanted code branch: ' + error);
}
));
it('asset plugin', () => api.addPlugin({
id: 'asset-plugin',
dir: pluginFixture,
getPlatformsArray: () => { return ['electron']; },
getFilesAndFrameworks: (platform) => { return []; },
getAssets: (platform) => {
return [{
itemType: 'asset',
src: 'src/electron/sample.json',
target: 'js/sample.json'
}];
},
getJsModules: (platform) => { return []; },
getConfigFiles: (platform) => { return []; }
}, { }).then(
(result) => {
expect(result).not.toBeDefined();
expect(fileExists(path.resolve(testProjectDir, 'www', 'js', 'sample.json'))).toBeTruthy();
expect(readJson(path.resolve(testProjectDir, 'www', 'js', 'sample.json')).title).toEqual('sample');
},
(error) => {
fail('Unwanted code branch: ' + error);
}
));
it('js-module plugin', () => api.addPlugin({
id: 'module-plugin',
dir: pluginFixture,
getPlatformsArray: () => { return ['electron']; },
getFilesAndFrameworks: (platform) => { return []; },
getAssets: (platform) => { return []; },
getJsModules: (platform) => {
return [{
itemType: 'js-module',
name: 'testmodule',
src: 'www/plugin.js',
clobbers: [ 'ModulePlugin.clobbers' ],
merges: [ 'ModulePlugin.merges' ],
runs: true
}];
},
getConfigFiles: (platform) => { return []; }
}, { }).then(
(result) => {
expect(result).not.toBeDefined();
expect(fileExists(path.resolve(testProjectDir, 'www', 'plugins', 'module-plugin', 'www', 'plugin.js'))).toBeTruthy();
},
(error) => {
fail('Unwanted code branch: ' + error);
}
));
it('unrecognized type plugin', () => {
const _events = api.events;
const emitSpy = jasmine.createSpy('emit');
api.events = {
emit: emitSpy
};
return api.addPlugin({
id: 'unrecognized-plugin',
dir: pluginFixture,
getPlatformsArray: () => { return ['electron']; },
getFilesAndFrameworks: (platform) => { return []; },
getAssets: (platform) => {
return [{
itemType: 'unrecognized'
}];
},
getJsModules: (platform) => { return []; },
getConfigFiles: (platform) => { return []; }
}, { }).then(
(result) => {
expect(emitSpy.calls.argsFor(0)[1]).toContain('unrecognized');
expect(result).not.toBeDefined();
api.events = _events;
},
(error) => {
fail('Unwanted code branch: ' + error);
api.events = _events;
}
);
});
it('source-file type plugin', () => api.addPlugin({
id: 'source-file-plugin',
dir: pluginFixture,
getPlatformsArray: () => { return ['electron']; },
getFilesAndFrameworks: (platform) => { return []; },
getAssets: (platform) => {
return [{
itemType: 'source-file'
}];
},
getJsModules: (platform) => { return []; },
getConfigFiles: (platform) => { return []; }
}, { }).then(
(result) => {
expect(result).not.toBeDefined();
expect(logs.verbose.some((message) => { return message === 'source-file.install is currently not supported for electron'; })).toBeTruthy();
},
(error) => {
fail('Unwanted code branch: ' + error);
}
));
it('empty plugin with browser platform', () => api.addPlugin({
id: 'empty_plugin',
getPlatformsArray: () => { return ['browser']; },
getFilesAndFrameworks: (platform) => { return []; },
getAssets: (platform) => { return []; },
getJsModules: (platform) => { return []; },
getConfigFiles: (platform) => { return []; }
}, { }).then(
(result) => {
expect(result).not.toBeDefined();
expect(dirExists(path.resolve(testProjectDir, 'www'))).toBeTruthy();
expect(fileExists(path.resolve(testProjectDir, 'electron.json'))).toBeTruthy();
expect(fileExists(path.resolve(testProjectDir, 'www', 'cordova_plugins.js'))).toBeTruthy();
},
(error) => {
fail('Unwanted code branch: ' + error);
}
));
});
/**
* @todo Add useful tests.
*/
describe('removePlugin method', () => {
let logs = {};
beforeEach(() => {
fs.removeSync(path.resolve(testProjectDir, 'electron.json'));
fs.removeSync(path.resolve(testProjectDir, 'www'));
apiEvents.addListener('verbose', (data) => {
logs.verbose.push(data);
});
logs = {
verbose: []
};
});
afterEach(() => {
apiEvents.removeAllListeners();
});
it('should exist', () => {
expect(api.removePlugin).toBeDefined();
expect(typeof api.removePlugin).toBe('function');
});
it('remove empty plugin', () => api.removePlugin({
id: 'empty_plugin',
getPlatformsArray: () => { return ['electron']; },
getFilesAndFrameworks: (platform) => { return []; },
getAssets: (platform) => { return []; },
getJsModules: (platform) => { return []; },
getConfigFiles: (platform) => { return []; }
}, { }).then(
(result) => {
expect(result).not.toBeDefined();
},
(error) => {
fail('Unwanted code branch: ' + error);
}
));
it('asset plugin', () => {
fs.ensureDirSync(path.resolve(testProjectDir, 'www', 'js'));
writeJson(path.resolve(testProjectDir, 'www', 'js', 'sample.json'), { 'title': 'sample' });
return api.removePlugin({
id: 'empty_plugin',
dir: pluginFixture,
getPlatformsArray: () => { return ['electron']; },
getFilesAndFrameworks: (platform) => { return []; },
getAssets: (platform) => {
return [{
itemType: 'asset',
src: 'src/electron/sample.json',
target: 'js/sample.json'
}];
},
getJsModules: (platform) => { return []; },
getConfigFiles: (platform) => { return []; }
}, { }).then(
(result) => {
expect(result).not.toBeDefined();
expect(fileExists(path.resolve(testProjectDir, 'www', 'js', 'sample.json'))).toBeFalsy();
},
(error) => {
fail('Unwanted code branch: ' + error);
}
);
});
it('js-module plugin', () => {
fs.ensureDirSync(path.resolve(testProjectDir, 'www', 'plugins', 'module-plugin', 'www'));
fs.copySync(path.resolve(pluginFixture, 'www', 'plugin.js'), path.resolve(testProjectDir, 'www', 'plugins', 'module-plugin', 'www', 'plugin.js'));
expect(fileExists(path.resolve(testProjectDir, 'www', 'plugins', 'module-plugin', 'www', 'plugin.js'))).toBeTruthy();
return api.removePlugin({
id: 'module-plugin',
dir: pluginFixture,
getPlatformsArray: () => { return ['electron']; },
getFilesAndFrameworks: (platform) => { return []; },
getAssets: (platform) => { return []; },
getJsModules: (platform) => {
return [{
itemType: 'js-module',
name: 'testmodule',
src: 'www/plugin.js',
clobbers: [ 'ModulePlugin.clobbers' ],
merges: [ 'ModulePlugin.merges' ],
runs: true
}];
},
getConfigFiles: (platform) => { return []; }
}, { }).then(
(result) => {
expect(result).not.toBeDefined();
expect(fileExists(path.resolve(testProjectDir, 'www', 'plugins', 'module-plugin', 'www', 'plugin.js'))).toBeFalsy();
},
(error) => {
fail('Unwanted code branch: ' + error);
}
);
});
it('unrecognized type plugin', () => api.removePlugin({
id: 'unrecognized-plugin',
dir: pluginFixture,
getPlatformsArray: () => { return ['electron']; },
getFilesAndFrameworks: (platform) => { return []; },
getAssets: (platform) => {
return [{
itemType: 'unrecognized'
}];
},
getJsModules: (platform) => { return []; },
getConfigFiles: (platform) => { return []; }
}, { }).then(
(result) => {
expect(result).not.toBeDefined();
},
(error) => {
fail('Unwanted code branch: ' + error);
}
));
it('source-file type plugin', () => api.removePlugin({
id: 'source-file-plugin',
dir: pluginFixture,
getPlatformsArray: () => { return ['electron']; },
getFilesAndFrameworks: (platform) => { return []; },
getAssets: (platform) => {
return [{
itemType: 'source-file'
}];
},
getJsModules: (platform) => { return []; },
getConfigFiles: (platform) => { return []; }
}, { }).then(
(result) => {
expect(result).not.toBeDefined();
expect(logs.verbose.some((message) => { return message === 'source-file.uninstall is currently not supported for electron'; })).toBeTruthy();
},
(error) => {
fail('Unwanted code branch: ' + error);
}
));
it('remove empty plugin with browser platform', () => api.removePlugin({
id: 'empty_plugin',
getPlatformsArray: () => { return ['browser']; },
getFilesAndFrameworks: (platform) => { return []; },
getAssets: (platform) => { return []; },
getJsModules: (platform) => { return []; },
getConfigFiles: (platform) => { return []; }
}, { }).then(
(result) => {
expect(result).not.toBeDefined();
},
(error) => {
fail('Unwanted code branch: ' + error);
}
));
});
describe('updatePlatform method', () => {
it('should return a resolved promise.', () => {
Api.updatePlatform().then(
(result) => {
// Currently updatePlatform only resolves with nothing.
expect(result).toBeUndefined();
}
);
});
});
describe('createPlatform method', () => {
beforeEach(() => {
fs.removeSync(tmpDir);
});
afterEach(() => {
fs.removeSync(tmpDir);
});
/**
* @todo improve createPlatform to test actual created platforms.
*/
it('should export static createPlatform function', () => {
return Api.createPlatform(tmpDir).then(
(results) => {
expect(results.constructor.name).toBe(api.constructor.name);
}
);
});
it('should emit createPlatform not callable when error occurs.', () => {
Api.__set__('require', () => {
return {
createProject: () => { throw 'Some Random Error'; }
};
});
expect(() => Api.createPlatform(tmpDir)).toThrowError(/createPlatform is not callable from the electron project API/);
Api.__set__('require', apiRequire);
});
});
describe('build method', () => {
const runSpy = jasmine.createSpy('run');
beforeEach(() => {
// Mocking require that is called to get version.
Api.__set__('require', () => {
return {
run: { call: runSpy }
};
});
});
afterEach(() => {
Api.__set__('require', apiRequire);
});
it('should execute build', () => {
const mockBuildOptions = { foo: 'bar' };
api.build(mockBuildOptions);
expect(runSpy).toHaveBeenCalledWith(api, mockBuildOptions, api);
});
});
describe('run method', () => {
const runSpy = jasmine.createSpy('run');
beforeEach(() => {
// Mocking require that is called to get version.
Api.__set__('require', () => {
return {
run: runSpy
};
});
});
afterEach(() => {
Api.__set__('require', apiRequire);
});
it('should execute run', () => {
const mockRunOptions = { foo: 'bar' };
api.run(mockRunOptions);
expect(runSpy).toHaveBeenCalledWith(mockRunOptions);
});
});
describe('clean method', () => {
const cleanSpy = jasmine.createSpy('clean');
beforeEach(() => {
// Mocking require that is called to get version.
Api.__set__('require', () => {
return {
run: cleanSpy
};
});
});
afterEach(() => {
Api.__set__('require', apiRequire);
});
it('should execute clean', () => {
const mockCleanOptions = { foo: 'bar' };
api.clean(mockCleanOptions);
expect(cleanSpy).toHaveBeenCalledWith(mockCleanOptions);
});
});
describe('requirements method', () => {
const requirementsSpy = jasmine.createSpy('requirements');
beforeEach(() => {
// Mocking require that is called to get version.
Api.__set__('require', () => {
return {
run: requirementsSpy
};
});
});
afterEach(() => {
Api.__set__('require', apiRequire);
});
it('should execute requirements', () => {
api.requirements();
expect(requirementsSpy).toHaveBeenCalled();
});
});
});