blob: 7dfb0aad40562c24e8dbcb6ede558096f7bfd803 [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.
*/
var platforms = require('../../platforms'),
util = require('../../src/util'),
path = require('path'),
shell = require('shelljs'),
plist = require('plist'),
xcode = require('xcode'),
ET = require('elementtree'),
fs = require('fs'),
config = require('../../src/config'),
config_parser = require('../../src/config_parser'),
cordova = require('../../cordova');
describe('ios project parser', function () {
var proj = '/some/path';
var exec, custom, readdir, cfg_parser;
beforeEach(function() {
exec = spyOn(shell, 'exec').andCallFake(function(cmd, opts, cb) {
cb(0, '');
});
custom = spyOn(config, 'has_custom_path').andReturn(false);
readdir = spyOn(fs, 'readdirSync').andReturn(['test.xcodeproj']);
cfg_parser = spyOn(util, 'config_parser');
});
describe('constructions', function() {
it('should throw if provided directory does not contain an xcodeproj file', function() {
readdir.andReturn(['noxcodehere']);
expect(function() {
new platforms.ios.parser(proj);
}).toThrow('The provided path is not a Cordova iOS project.');
});
it('should create an instance with path, pbxproj, xcodeproj, originalName and cordovaproj properties', function() {
expect(function() {
var p = new platforms.ios.parser(proj);
expect(p.path).toEqual(proj);
expect(p.pbxproj).toEqual(path.join(proj, 'test.xcodeproj', 'project.pbxproj'));
expect(p.xcodeproj).toEqual(path.join(proj, 'test.xcodeproj'));
expect(p.originalName).toEqual('/test');
}).not.toThrow();
});
});
describe('check_requirements', function() {
it('should fire a callback if there is an error during shelling out', function(done) {
exec.andCallFake(function(cmd, opts, cb) {
cb(50, 'there was an errorz!');
});
platforms.ios.parser.check_requirements(proj, function(err) {
expect(err).toContain('there was an errorz!');
done();
});
});
it('should fire a callback if the xcodebuild version is less than 4.5.x', function(done) {
exec.andCallFake(function(cmd, opts, cb) {
cb(0, 'version 4.4.9');
});
platforms.ios.parser.check_requirements(proj, function(err) {
expect(err).toEqual('Xcode version installed is too old. Minimum: >=4.5.x, yours: 4.4.9');
done();
});
});
it('should not return an error if the xcodebuild version 2 digits and not proper semver (eg: 5.0), but still satisfies the MIN_XCODE_VERSION', function(done) {
exec.andCallFake(function(cmd, opts, cb) {
cb(0, 'version 5.0');
});
platforms.ios.parser.check_requirements(proj, function(err) {
expect(err).toBe(false);
done();
});
});
});
describe('instance', function() {
var p, cp, rm, is_cordova, write, read;
var ios_proj = path.join(proj, 'platforms', 'ios');
beforeEach(function() {
p = new platforms.ios.parser(ios_proj);
cp = spyOn(shell, 'cp');
rm = spyOn(shell, 'rm');
is_cordova = spyOn(util, 'isCordova').andReturn(proj);
write = spyOn(fs, 'writeFileSync');
read = spyOn(fs, 'readFileSync');
});
describe('update_from_config method', function() {
var et, xml, find, write_xml, root;
var cfg, find_obj, root_obj, cfg_access_add, cfg_access_rm, cfg_pref_add, cfg_pref_rm;
var plist_parse, plist_build, xc;
var update_name, xc_write;
beforeEach(function() {
find_obj = {
text:'hi'
};
root_obj = {
attrib:{
package:'android_pkg'
}
};
find = jasmine.createSpy('ElementTree find').andReturn(find_obj);
write_xml = jasmine.createSpy('ElementTree write');
root = jasmine.createSpy('ElementTree getroot').andReturn(root_obj);
et = spyOn(ET, 'ElementTree').andReturn({
find:find,
write:write_xml,
getroot:root
});
xml = spyOn(ET, 'XML');
plist_parse = spyOn(plist, 'parseFileSync').andReturn({
});
plist_build = spyOn(plist, 'build').andReturn('');
update_name = jasmine.createSpy('update_name');
xc_write = jasmine.createSpy('xcode writeSync');
xc = spyOn(xcode, 'project').andReturn({
parse:function(cb) {cb();},
updateProductName:update_name,
writeSync:xc_write
});
cfg = new config_parser();
cfg.name = function() { return 'testname' };
cfg.packageName = function() { return 'testpkg' };
cfg.version = function() { return 'one point oh' };
cfg.access.get = function() { return [] };
cfg.preference.get = function() { return [] };
cfg_access_add = jasmine.createSpy('config_parser access add');
cfg_access_rm = jasmine.createSpy('config_parser access rm');
cfg_pref_rm = jasmine.createSpy('config_parser pref rm');
cfg_pref_add = jasmine.createSpy('config_parser pref add');
cfg_parser.andReturn({
access:{
remove:cfg_access_rm,
get:function(){},
add:cfg_access_add
},
preference:{
remove:cfg_pref_rm,
get:function(){},
add:cfg_pref_add
}
});
p = new platforms.ios.parser(ios_proj);
});
it('should write out the app name to pbxproj by calling xcode.updateProductName', function(done) {
p.update_from_config(cfg, function() {
expect(update_name).toHaveBeenCalledWith('testname');
done();
});
});
it('should write out the app id to info plist as CFBundleIdentifier', function(done) {
p.update_from_config(cfg, function() {
expect(plist_build.mostRecentCall.args[0].CFBundleIdentifier).toEqual('testpkg');
done();
});
});
it('should write out the app version to info plist as CFBundleVersion', function(done) {
p.update_from_config(cfg, function() {
expect(plist_build.mostRecentCall.args[0].CFBundleVersion).toEqual('one point oh');
done();
});
});
it('should wipe out the ios whitelist every time', function(done) {
p.update_from_config(cfg, function() {
expect(cfg_access_rm).toHaveBeenCalled();
done();
});
});
it('should update the whitelist', function(done) {
cfg.access.get = function() { return ['one'] };
p.update_from_config(cfg, function() {
expect(cfg_access_add).toHaveBeenCalledWith('one');
done();
});
});
it('should update preferences', function(done) {
var sample_pref = {name:'pref',value:'yes'};
cfg.preference.get = function() { return [sample_pref] };
p.update_from_config(cfg, function() {
expect(cfg_pref_add).toHaveBeenCalledWith(sample_pref);
done();
});
});
it('should wipe out the ios preferences every time', function(done) {
p.update_from_config(cfg, function() {
expect(cfg_pref_rm).toHaveBeenCalled();
done();
});
});
it('should write out default preferences every time', function(done) {
var sample_pref = {name:'preftwo',value:'false'};
cfg.preference.get = function() { return [sample_pref] };
p.update_from_config(cfg, function() {
expect(cfg_pref_add).toHaveBeenCalledWith({name:"KeyboardDisplayRequiresUserAction",value:"true"});
expect(cfg_pref_add).toHaveBeenCalledWith({name:"SuppressesIncrementalRendering",value:"false"});
expect(cfg_pref_add).toHaveBeenCalledWith({name:"UIWebViewBounce",value:"true"});
expect(cfg_pref_add).toHaveBeenCalledWith({name:"TopActivityIndicator",value:"gray"});
expect(cfg_pref_add).toHaveBeenCalledWith({name:"EnableLocation",value:"false"});
expect(cfg_pref_add).toHaveBeenCalledWith({name:"EnableViewportScale",value:"false"});
expect(cfg_pref_add).toHaveBeenCalledWith({name:"AutoHideSplashScreen",value:"true"});
expect(cfg_pref_add).toHaveBeenCalledWith({name:"ShowSplashScreenSpinner",value:"true"});
expect(cfg_pref_add).toHaveBeenCalledWith({name:"MediaPlaybackRequiresUserAction",value:"false"});
expect(cfg_pref_add).toHaveBeenCalledWith({name:"AllowInlineMediaPlayback",value:"false"});
expect(cfg_pref_add).toHaveBeenCalledWith({name:"OpenAllWhitelistURLsInWebView",value:"false"});
expect(cfg_pref_add).toHaveBeenCalledWith({name:"BackupWebStorage",value:"cloud"});
done();
});
});
});
describe('www_dir method', function() {
it('should return /www', function() {
expect(p.www_dir()).toEqual(path.join(ios_proj, 'www'));
});
});
describe('staging_dir method', function() {
it('should return .staging/www', function() {
expect(p.staging_dir()).toEqual(path.join(ios_proj, '.staging', 'www'));
});
});
describe('config_xml method', function() {
it('should return the location of the config.xml', function() {
expect(p.config_xml()).toEqual(path.join(ios_proj, 'test', 'config.xml'));
});
});
describe('update_www method', function() {
it('should rm project-level www and cp in platform agnostic www', function() {
p.update_www();
expect(rm).toHaveBeenCalled();
expect(cp).toHaveBeenCalled();
});
it('should copy in a fresh cordova.js from stock cordova lib if no custom lib is specified', function() {
p.update_www();
expect(cp.mostRecentCall.args[1]).toMatch(util.libDirectory);
});
it('should copy in a fresh cordova.js from custom cordova lib if custom lib is specified', function() {
var custom_path = '/custom/path';
custom.andReturn(custom_path);
p.update_www();
expect(cp.mostRecentCall.args[1]).toMatch(custom_path);
});
});
describe('update_overrides method', function() {
var exists;
beforeEach(function() {
exists = spyOn(fs, 'existsSync').andReturn(true);
});
it('should do nothing if merges directory does not exist', function() {
exists.andReturn(false);
p.update_overrides();
expect(cp).not.toHaveBeenCalled();
});
it('should copy merges path into www', function() {
p.update_overrides();
expect(cp).toHaveBeenCalled();
});
});
describe('update_staging method', function() {
var exists;
beforeEach(function() {
exists = spyOn(fs, 'existsSync').andReturn(true);
});
it('should do nothing if staging dir does not exist', function() {
exists.andReturn(false);
p.update_staging();
expect(cp).not.toHaveBeenCalled();
});
it('should copy the staging dir into www if staging dir exists', function() {
p.update_staging();
expect(cp).toHaveBeenCalled();
});
});
describe('update_project method', function() {
var config, www, overrides, staging, svn;
beforeEach(function() {
config = spyOn(p, 'update_from_config').andCallFake(function(cfg, cb) { cb() });
www = spyOn(p, 'update_www');
overrides = spyOn(p, 'update_overrides');
staging = spyOn(p, 'update_staging');
svn = spyOn(util, 'deleteSvnFolders');
});
it('should call update_from_config', function() {
p.update_project();
expect(config).toHaveBeenCalled();
});
it('should throw if update_from_config errors', function(done) {
var err = new Error('uh oh!');
config.andCallFake(function(cfg, cb) { cb(err); });
p.update_project({}, function(err) {
expect(err).toEqual(err);
done();
});
});
it('should call update_www', function(done) {
p.update_project({}, function() {
expect(www).toHaveBeenCalled();
done();
});
});
it('should call update_overrides', function() {
p.update_project();
expect(overrides).toHaveBeenCalled();
});
it('should call update_staging', function() {
p.update_project();
expect(staging).toHaveBeenCalled();
});
it('should call deleteSvnFolders', function() {
p.update_project();
expect(svn).toHaveBeenCalled();
});
});
});
});