blob: 06fa97adaffb9642e959e55edd07e604b11b3dfe [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 rewire = require('rewire');
const path = require('path');
const requireFresh = require('import-fresh');
const create = require('..');
const { CordovaError, ConfigParser } = require('cordova-common');
const { tmpDir, createWith, createWithMockFetch, expectRejection } = require('./helpers');
const appName = 'TestBase';
const appId = 'org.testing';
const appVersion = '1.0.0';
const project = path.join(tmpDir, appName);
let opts;
beforeEach(() => {
fs.emptyDirSync(tmpDir);
opts = { name: appName, id: appId };
});
afterAll(() => {
process.chdir(path.join(__dirname, '..')); // Needed to rm the dir on Windows.
fs.removeSync(tmpDir);
});
describe('cordova create checks for valid-identifier', () => {
const error = new CordovaError('is not a valid identifier');
it('should reject reserved words from start of id', () => {
opts.id = 'int.bob';
return expectRejection(create(project, opts), error);
});
it('should reject reserved words from end of id', () => {
opts.id = 'bob.class';
return expectRejection(create(project, opts), error);
});
});
describe('create end-to-end', () => {
function checkCommonArtifacts () {
// Check that www dir exist
expect(path.join(project, 'www')).toExist();
// Check that index.html exists inside of www
expect(path.join(project, 'www', 'index.html')).toExist();
// Check that www files don't get copied to the top level
expect(path.join(project, 'index.html')).not.toExist();
// index.js and template subdir folder should not exist in top level
// (inner files should be copied to the project top level folder)
expect(path.join(project, 'index.js')).not.toExist();
expect(path.join(project, 'template')).not.toExist();
// Check that config.xml does not exist inside of www
expect(path.join(project, 'www', 'config.xml')).not.toExist();
// Check that config.xml was updated correctly
const configXml = new ConfigParser(path.join(project, 'config.xml'));
expect(configXml.packageName()).toEqual(appId);
expect(configXml.name()).toEqual(appName);
}
// Check that we got package.json and it was updated correctly
function checkPackageJson () {
const pkg = requireFresh(path.join(project, 'package.json'));
expect(pkg.name).toEqual(appId);
expect(pkg.displayName).toEqual(appName);
}
// Check that we got no package.json
function checkNoPackageJson () {
expect(path.join(project, 'package.json')).not.toExist();
}
// Check that we did use the default template
function checkDefaultTemplate () {
const pkg = requireFresh(path.join(project, 'package.json'));
expect(pkg.author).toEqual('Apache Cordova Team');
expect(pkg.version).toEqual(appVersion);
const configXml = new ConfigParser(path.join(project, 'config.xml'));
expect(configXml.author()).toEqual('Apache Cordova Team');
expect(configXml.version()).toEqual(appVersion);
}
// Check that we did not use the default template
function checkNotDefaultTemplate () {
const configXml = new ConfigParser(path.join(project, 'config.xml'));
expect(configXml.author()).not.toEqual('Apache Cordova Team');
expect(configXml.version()).toEqual('0.0.1');
}
function checkProjectCreatedWithDefaultTemplate () {
checkCommonArtifacts();
checkPackageJson();
checkDefaultTemplate();
}
it('should successfully run without template and use default hello-world app', () => {
// Create a real project with no template
// use default cordova-app-hello-world app
return create(project, opts)
.then(checkProjectCreatedWithDefaultTemplate);
});
it('should successfully run with Git URL', () => {
// Create a real project with git URL as template
opts.template = 'https://github.com/apache/cordova-app-hello-world';
return createWithMockFetch(project, opts)
.then(fetchSpy => {
expect(fetchSpy).toHaveBeenCalledTimes(1);
expect(fetchSpy.calls.argsFor(0)[0]).toBe(opts.template);
})
.then(checkProjectCreatedWithDefaultTemplate);
});
it('should successfully run with NPM package (specific version)', () => {
// Create a real project with npm module as template
opts.template = 'phonegap-template-vue-f7-tabs@1';
return createWithMockFetch(project, opts)
.then(fetchSpy => {
expect(fetchSpy).toHaveBeenCalledTimes(1);
expect(fetchSpy.calls.argsFor(0)[0]).toBe(opts.template);
})
.then(checkProjectCreatedWithDefaultTemplate);
});
it('should successfully run with NPM package (no specific version)', () => {
// Create a real project with npm module as template
opts.template = 'phonegap-template-vue-f7-tabs';
return createWithMockFetch(project, opts)
.then(fetchSpy => {
expect(fetchSpy).toHaveBeenCalledTimes(1);
expect(fetchSpy.calls.argsFor(0)[0]).toBe(opts.template);
})
.then(checkProjectCreatedWithDefaultTemplate);
});
it('should successfully run with local template having no package.json in template dir', () => {
opts.template = path.join(__dirname, 'templates/withsubdirectory');
return create(project, opts)
.then(checkCommonArtifacts)
.then(checkNoPackageJson)
.then(checkNotDefaultTemplate);
});
it('should successfully run with local template having package.json in template dir', () => {
opts.template = path.join(__dirname, 'templates/withsubdirectory_package_json');
return create(project, opts)
.then(checkCommonArtifacts)
.then(checkPackageJson)
.then(checkNotDefaultTemplate);
});
it('should successfully run with existing, empty destination', () => {
fs.ensureDirSync(project);
return create(project, opts)
.then(checkProjectCreatedWithDefaultTemplate);
});
it('should rename all gitignore files in template to .gitignore', () => {
const baseTemplatePkg = path.join(__dirname, 'templates/withsubdirectory');
const templatePkg = path.join(tmpDir, 'gitignore-template');
fs.copySync(baseTemplatePkg, templatePkg);
// Setup a few gitignore files that should be renamed (or not)
const templateDir = path.join(templatePkg, 'template');
fs.ensureFileSync(path.join(templateDir, 'gitignore'));
fs.ensureFileSync(path.join(templateDir, 'www/gitignore'));
fs.ensureDirSync(path.join(templateDir, 'foo/gitignore'));
opts.template = templatePkg;
return create(project, opts).then(() => {
// Renames gitignore at template root
expect(path.join(project, 'gitignore')).not.toExist();
expect(path.join(project, '.gitignore')).toExist();
// Renames gitignores in sub-directories
expect(path.join(project, 'www/gitignore')).not.toExist();
expect(path.join(project, 'www/.gitignore')).toExist();
// Does not rename directories with name gitignore
expect(path.join(project, 'foo/gitignore')).toExist();
expect(path.join(project, 'foo/.gitignore')).not.toExist();
});
});
});
describe('when shit happens', () => {
it('should fail when dir is missing', () => {
return expectRejection(
create(null, opts),
new CordovaError('Directory not specified')
);
});
it('should fail when dir already exists', () => {
return expectRejection(
create(__dirname, opts),
new CordovaError('Path already exists and is not empty')
);
});
it('should fail when destination is inside template', () => {
opts.template = path.join(tmpDir, 'template');
return expectRejection(
create(path.join(opts.template, 'destination'), opts),
new CordovaError('inside the template')
);
});
it('should fail when fetch fails', () => {
const fetchError = new Error('Fetch fail');
const failingFetch = jasmine.createSpy('failingFetch')
.and.callFake(() => Promise.reject(fetchError));
opts.template = 'http://localhost:123456789/cordova-create';
return expectRejection(
createWith({ fetch: failingFetch })(project, opts),
fetchError
);
});
// FIXME: we need to improve isRemote to make this different from the test above
xit('should fail when template does not exist', () => {
opts.template = path.join(__dirname, 'doesnotexist');
return expectRejection(
create(project, opts),
new CordovaError('not a valid template')
);
});
});
describe('cordova create needsToBeFetched', () => {
let needsToBeFetched;
beforeEach(() => {
needsToBeFetched = rewire('..').__get__('needsToBeFetched');
});
it('should recognize URLs as remote', () => {
expect(needsToBeFetched('https://example.com/pkg/foo')).toBe(true);
});
it('should recognize package@version as remote', () => {
expect(needsToBeFetched('foo@1')).toBe(true);
});
it('should not detect paths as remote only because they include an @', () => {
expect(needsToBeFetched('../foo@1')).toBe(false);
});
});