blob: 401d752ed62f0cdddd9b5c4685dc30eed9749175 [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('node:fs');
const path = require('node:path');
const { tmpDir: getTmpDir, testPlatform } = require('../helpers');
const projectTestHelpers = require('../project-test-helpers');
/**
* Checks if "cordova/restore-util" is restoring platforms and plugins as
* expected given different configurations of package.json and/or config.xml.
*/
describe('cordova/restore-util', () => {
let tmpDir, project, pkgJsonPath, configXmlPath;
let restore, cordovaPlatform, cordovaPlugin;
const {
getPkgJsonPath, getConfigXmlPath, setupBaseProject, getCfg, getPkgJson, setPkgJson
} = projectTestHelpers(() => project);
beforeEach(() => {
tmpDir = getTmpDir('pkgJson');
project = path.join(tmpDir, 'project');
pkgJsonPath = getPkgJsonPath();
configXmlPath = getConfigXmlPath();
delete process.env.PWD;
restore = require('../../src/cordova/restore-util');
cordovaPlugin = require('../../src/cordova/plugin');
spyOn(cordovaPlugin, 'add')
.and.returnValue(Promise.resolve());
cordovaPlatform = require('../../src/cordova/platform');
spyOn(cordovaPlatform, 'add')
.and.returnValue(Promise.resolve());
setupBaseProject();
});
afterEach(() => {
process.chdir(__dirname); // Needed to rm the dir on Windows.
fs.rmSync(tmpDir, { recursive: true, force: true });
});
function getCfgEngineNames (cfg = getCfg()) {
return cfg.getEngines().map(({ name }) => name);
}
function platformPkgName (platformName) {
return platformName.replace(/^(?:cordova-)?/, 'cordova-');
}
function expectPluginsInPkgJson (plugins) {
const pkgJson = getPkgJson();
expect(pkgJson).toBeDefined();
// Check that cordova.plugins key in package.json contains the expected
// variables and ONLY them
const variables = plugins.reduce((o, { name, variables }) => {
o[name] = variables;
return o;
}, {});
expect(pkgJson.cordova).toBeDefined();
expect(pkgJson.cordova.plugins).toEqual(variables);
// Check that dependencies key in package.json contains the expected specs
// We only check the specs for plugins where an expected spec was given
const expectedSpecs = plugins.reduce((o, { name, spec }) => {
if (spec) o[name] = spec;
return o;
}, {});
if (Object.keys(expectedSpecs).length > 0) {
const specs = Object.assign({}, pkgJson.dependencies, pkgJson.devDependencies);
expect(specs).toEqual(jasmine.objectContaining(expectedSpecs));
}
}
function expectPlatformAdded (platform) {
const expectedOpts = {
platforms: jasmine.arrayContaining([
jasmine.stringMatching(platform)
])
};
expect(cordovaPlatform.add).toHaveBeenCalledWith(
jasmine.anything(), jasmine.any(String),
jasmine.arrayContaining([platform]),
jasmine.objectContaining(expectedOpts)
);
}
function expectPluginAdded (plugin) {
const expectedOpts = {
plugins: jasmine.arrayContaining([
jasmine.stringMatching(plugin.name)
])
};
if ('variables' in plugin) {
expectedOpts.cli_variables = plugin.variables;
}
expect(cordovaPlugin.add).toHaveBeenCalledWith(
jasmine.any(String), jasmine.anything(),
jasmine.objectContaining(expectedOpts)
);
}
function expectPluginsAddedAndSavedToPkgJson (plugins) {
expectPluginsInPkgJson(plugins);
plugins.forEach(expectPluginAdded);
}
describe('installPlatformsFromConfigXML', () => {
it('Test#001 : should restore saved platform from package.json', () => {
setPkgJson('cordova.platforms', [testPlatform]);
return restore.installPlatformsFromConfigXML().then(() => {
// Check that the platform was properly restored
expectPlatformAdded(testPlatform);
});
});
it('Test#017 : should restore saved platform from package.json using an URL spec', () => {
const PLATFORM = 'browser';
const PLATFORM_URL = 'https://github.com/apache/cordova-browser';
setPkgJson('dependencies', {
[platformPkgName(PLATFORM)]: `git+${PLATFORM_URL}.git`
});
setPkgJson('cordova.platforms', [PLATFORM]);
return restore.installPlatformsFromConfigXML().then(() => {
// Check config.xml for spec modification.
expect(getCfg().getEngines()).not.toEqual([{
name: PLATFORM,
spec: `git+${PLATFORM_URL}.git`
}]);
// No change to pkg.json.
const pkgJson = getPkgJson();
expect(pkgJson.cordova.platforms).toEqual([PLATFORM]);
const specs = Object.assign({}, pkgJson.dependencies, pkgJson.devDependencies);
expect(specs[platformPkgName(PLATFORM)]).toEqual(`git+${PLATFORM_URL}.git`);
});
});
it('Test#004 : should not modify either file if both have the same platforms', () => {
getCfg()
.addEngine(testPlatform)
.write();
setPkgJson('cordova.platforms', [testPlatform]);
const getModTimes = _ => ({
cfg: fs.statSync(configXmlPath).mtime,
pkg: fs.statSync(pkgJsonPath).mtime
});
const modTimes = getModTimes();
return restore.installPlatformsFromConfigXML().then(() => {
expect(getModTimes()).toEqual(modTimes);
});
});
it('Test#005 : should update package.json to include platforms from config.xml', () => {
const PLATFORM_1 = 'android';
const PLATFORM_2 = 'browser';
getCfg()
.addEngine(PLATFORM_1, '7.0.0')
.addEngine(PLATFORM_2, '^5.0.3')
.write();
setPkgJson('cordova.platforms', [testPlatform]);
return restore.installPlatformsFromConfigXML().then(() => {
const pkgJson = getPkgJson();
// Expect both pkg.json and config.xml to each have both platforms in their arrays.
expect(getCfgEngineNames()).toEqual([PLATFORM_1, PLATFORM_2]);
expect(pkgJson.cordova.platforms).toEqual([PLATFORM_1, PLATFORM_2]);
// Platform specs from config.xml have been added to pkg.json.
const specs = Object.assign({}, pkgJson.dependencies, pkgJson.devDependencies);
expect(specs).toEqual({
[platformPkgName(PLATFORM_1)]: '7.0.0',
[platformPkgName(PLATFORM_2)]: '^5.0.3'
});
});
});
it('Test#006 : should update a package.json without `cordova` key to match platforms from config.xml', () => {
getCfg()
.addEngine('android')
.write();
return restore.installPlatformsFromConfigXML().then(() => {
// Expect no change to config.xml.
expect(getCfgEngineNames()).toEqual(['android']);
// Expect cordova key and 'android' platform to be added to pkg.json.
expect(getPkgJson('cordova.platforms')).toEqual(['android']);
});
});
it('Test#007 : should find platform spec', () => {
setPkgJson('cordova.platforms', ['android']);
setPkgJson('devDependencies', {
'cordova-android': '1.0.0'
});
return restore.installPlatformsFromConfigXML(['android'], {}).then(() => {
expect(cordovaPlatform.add).toHaveBeenCalledWith(
jasmine.anything(),
jasmine.anything(),
['android@1.0.0'],
jasmine.anything()
);
});
});
it('Test#016 : should restore platforms & plugins and create a missing package.json', () => {
getCfg()
.addEngine(testPlatform)
.write();
fs.rmSync(pkgJsonPath, { recursive: true, force: true });
return restore.installPlatformsFromConfigXML().then(() => {
// Package.json should be auto-created using values from config.xml
const cfg = getCfg();
expect(getPkgJson()).toEqual(jasmine.objectContaining({
name: cfg.packageName().toLowerCase(),
version: cfg.version(),
displayName: cfg.name()
}));
});
});
});
// These tests will check the plugin/variable list in package.json and config.xml.
describe('installPluginsFromConfigXML', () => {
beforeEach(() => {
// Add some platform to test the plugins with
setPkgJson('cordova.platforms', [testPlatform]);
});
it('Test#011 : restores saved plugin', () => {
setPkgJson('dependencies', {
'cordova-plugin-camera': '^2.3.0'
});
setPkgJson('cordova.plugins', {
'cordova-plugin-camera': { variable_1: 'value_1' }
});
return restore.installPluginsFromConfigXML({ save: true }).then(() => {
expectPluginAdded({
name: 'cordova-plugin-camera',
spec: '^2.3.0',
variables: { variable_1: 'value_1' }
});
});
});
it('Test#012 : restores saved plugin using an URL spec', () => {
const PLUGIN_ID = 'cordova-plugin-splashscreen';
const PLUGIN_URL = 'https://github.com/apache/cordova-plugin-splashscreen';
setPkgJson('dependencies', {
[PLUGIN_ID]: `git+${PLUGIN_URL}.git`
});
setPkgJson('cordova.plugins', { [PLUGIN_ID]: {} });
return restore.installPluginsFromConfigXML({ save: true }).then(() => {
expectPluginAdded({
name: PLUGIN_ID,
spec: `git+${PLUGIN_URL}.git`,
variables: {}
});
});
});
it('Test#013 : does NOT detect plugins from dependencies ', () => {
setPkgJson('dependencies', { 'cordova-plugin-device': '~1.0.0' });
setPkgJson('devDependencies', { 'cordova-plugin-camera': '~1.0.0' });
return restore.installPluginsFromConfigXML({ save: true }).then(() => {
expect(cordovaPlugin.add).not.toHaveBeenCalled();
});
});
it('Test#014 : adds any plugins only present in config.xml to pkg.json', () => {
getCfg()
.addPlugin({
name: 'cordova-plugin-device',
spec: '~1.0.0',
variables: {}
})
.write();
setPkgJson('cordova.plugins', { 'cordova-plugin-camera': {} });
setPkgJson('devDependencies', { 'cordova-plugin-camera': '^2.3.0' });
return restore.installPluginsFromConfigXML({ save: true }).then(() => {
expectPluginsAddedAndSavedToPkgJson([{
name: 'cordova-plugin-camera',
spec: '^2.3.0',
variables: {}
}, {
name: 'cordova-plugin-device',
spec: '~1.0.0',
variables: {}
}]);
});
});
it('Test#015 : prefers pkg.json plugins over those from config.xml', () => {
getCfg()
.addPlugin({
name: 'cordova-plugin-camera',
spec: '~2.2.0',
variables: { common_var: 'xml', xml_var: 'foo' }
})
.write();
setPkgJson('cordova.plugins', {
'cordova-plugin-camera': { common_var: 'json', json_var: 'foo' }
});
setPkgJson('devDependencies', { 'cordova-plugin-camera': '^2.3.0' });
return restore.installPluginsFromConfigXML({ save: true }).then(() => {
expectPluginsAddedAndSavedToPkgJson([{
name: 'cordova-plugin-camera',
spec: '^2.3.0',
variables: { common_var: 'json', json_var: 'foo' }
}]);
});
});
it('Test#018 : does NOT produce conflicting dependencies', () => {
getCfg()
.addPlugin({
name: 'cordova-plugin-camera',
spec: '~2.2.0',
variables: { common_var: 'xml', xml_var: 'foo' }
})
.write();
setPkgJson('dependencies', { 'cordova-plugin-camera': '^2.3.0' });
return restore.installPluginsFromConfigXML({ save: true }).then(() => {
expectPluginsAddedAndSavedToPkgJson([{
name: 'cordova-plugin-camera',
spec: '^2.3.0',
variables: { common_var: 'xml', xml_var: 'foo' }
}]);
const pluginOccurences = !!getPkgJson('dependencies.cordova-plugin-camera') +
!!getPkgJson('devDependencies.cordova-plugin-camera');
expect(pluginOccurences).toBe(1);
});
});
});
});