UNPKG

30 kBJavaScriptView Raw
1/**
2 Licensed to the Apache Software Foundation (ASF) under one
3 or more contributor license agreements. See the NOTICE file
4 distributed with this work for additional information
5 regarding copyright ownership. The ASF licenses this file
6 to you under the Apache License, Version 2.0 (the
7 "License"); you may not use this file except in compliance
8 with the License. You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing,
13 software distributed under the License is distributed on an
14 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 KIND, either express or implied. See the License for the
16 specific language governing permissions and limitations
17 under the License.
18*/
19
20var rewire = require('rewire');
21var prepare = rewire('../../template/cordova/lib/prepare');
22var AppxManifest = require('../../template/cordova/lib/AppxManifest');
23var ConfigParser = require('../../template/cordova/lib/ConfigParser');
24var fs = require('fs');
25var et = require('elementtree');
26var events = require('cordova-common').events;
27var path = require('path');
28var xml = require('cordova-common').xmlHelpers;
29var FileUpdater = require('cordova-common').FileUpdater;
30var updateManifestFile = prepare.__get__('updateManifestFile');
31var applyCoreProperties = prepare.__get__('applyCoreProperties');
32var applyAccessRules = prepare.__get__('applyAccessRules');
33var applyNavigationWhitelist = prepare.__get__('applyNavigationWhitelist');
34var applyStartPage = prepare.__get__('applyStartPage');
35
36var Win10ManifestPath = 'template/package.windows10.appxmanifest';
37var Win81ManifestPath = 'template/package.windows.appxmanifest';
38var WP81ManifestPath = 'template/package.phone.appxmanifest';
39
40var Win10ManifestName = path.basename(Win10ManifestPath);
41var Win81ManifestName = path.basename(Win81ManifestPath);
42var WP81ManifestName = path.basename(WP81ManifestPath);
43
44/***
45 * Unit tests for validating default ms-appx-web:// URI scheme in Win10
46 * (for the function applyCoreProperties) from prepare.js.
47 **/
48
49var PreferencesBaseline = {
50 Orientation: null,
51 WindowsDefaultUriPrefix: null,
52 WindowsStoreDisplayName: null,
53 WindowsStorePublisherName: null,
54 WindowsStoreIdentityName: null
55};
56
57function createMockConfigAndManifestForApplyCoreProperties (startPage, preferences, win10, winPackageVersion) {
58 if (!preferences) {
59 preferences = { };
60 }
61
62 preferences.__proto__ = PreferencesBaseline; /* eslint no-proto: 0 */
63
64 var config = {
65 version: function () { return '1.0.0.0'; },
66 description: function () { return 'CordovaApp'; },
67 windows_packageVersion: function () { return winPackageVersion; },
68 name: function () { return 'HelloCordova'; },
69 packageName: function () { return 'org.apache.cordova.HelloCordova'; },
70 author: function () { return 'Apache'; },
71 startPage: function () { return startPage; },
72 getPreference: function (preferenceName) {
73 if (typeof preferences[preferenceName] !== 'undefined') {
74 return preferences[preferenceName];
75 } else {
76 throw new RangeError('Unexpected call to config.getPreference with "' + preferenceName + '" in unit test.');
77 }
78 }
79 };
80
81 var filePath = win10 ? Win10ManifestPath : Win81ManifestPath;
82 var manifest = AppxManifest.get(filePath);
83 spyOn(fs, 'writeFileSync');
84
85 return { config: config, manifest: manifest };
86}
87
88function addCapabilityDeclarationToMockManifest (manifest, capability) {
89 var capRoot = manifest.doc.find('.//Capabilities');
90 var cap = new et.Element('Capability');
91 cap.attrib.Name = capability;
92 capRoot.append(cap);
93}
94
95describe('Windows 8.1 project', function () {
96
97 it('should not have an HTTP or HTTPS scheme for its startup URI.', function () {
98
99 // arrange
100 var mockConfig = createMockConfigAndManifestForApplyCoreProperties('index.html', { 'WindowsDefaultUriPrefix': 'http://' }, false);
101
102 // act
103 applyCoreProperties(mockConfig.config, mockConfig.manifest, 'fake-path', 'm2:', false);
104
105 var app = mockConfig.manifest.doc.find('.//Application');
106 expect(app.attrib.StartPage).toBe('www/index.html');
107 });
108
109 it('should not have any scheme for its startup URI.', function () {
110
111 // arrange
112 var mockConfig = createMockConfigAndManifestForApplyCoreProperties('index.html', { 'WindowsDefaultUriPrefix': 'ms-appx://' }, false);
113
114 // act
115 applyCoreProperties(mockConfig.config, mockConfig.manifest, 'fake-path', 'm2:', false);
116
117 var app = mockConfig.manifest.doc.find('.//Application');
118 expect(app.attrib.StartPage).toBe('www/index.html');
119 });
120});
121
122describe('Windows 10 project', function () {
123 it('should default to ms-appx-web for its startup URI.', function () {
124
125 // arrange
126 var mockConfig = createMockConfigAndManifestForApplyCoreProperties('index.html', { }, true);
127
128 // act
129 applyStartPage(mockConfig.config, mockConfig.manifest, true);
130
131 var app = mockConfig.manifest.doc.find('.//Application');
132
133 // Workaround to avoid WWAHost.exe bug: https://issues.apache.org/jira/browse/CB-10446
134 var isAppxWebStartupUri = app.attrib.StartPage === 'ms-appx-web:///www/index.html' ||
135 app.attrib.StartPage === 'ms-appx-web://' + mockConfig.config.packageName().toLowerCase() + '/www/index.html';
136 expect(isAppxWebStartupUri).toBe(true);
137 });
138
139 it('should allow ms-appx as its startup URI, and it gets removed from the final output.', function () {
140
141 // arrange
142 var mockConfig = createMockConfigAndManifestForApplyCoreProperties('index.html', { 'WindowsDefaultUriPrefix': 'ms-appx://' }, true);
143
144 // act
145 applyStartPage(mockConfig.config, mockConfig.manifest, true);
146
147 var app = mockConfig.manifest.doc.find('.//Application');
148 expect(app.attrib.StartPage).toBe('www/index.html');
149 });
150
151 it('should allow an HTTP or HTTPS scheme for its startup URI.', function () {
152
153 // arrange
154 var mockConfig = createMockConfigAndManifestForApplyCoreProperties('www.contoso.com/', { 'WindowsDefaultUriPrefix': 'http://' }, true);
155
156 // act
157 applyStartPage(mockConfig.config, mockConfig.manifest, true);
158
159 var app = mockConfig.manifest.doc.find('.//Application');
160 expect(app.attrib.StartPage).toBe('http://www.contoso.com/');
161 });
162});
163
164describe('Windows Store preference', function () {
165
166 it('"WindowsStoreDisplayName" should be reflected in the manifest.', function () {
167
168 // arrange
169 var mockConfig = createMockConfigAndManifestForApplyCoreProperties('www.contoso.com/', { 'WindowsDefaultUriPrefix': 'http://', 'WindowsStoreDisplayName': 'ContosoApp' }, true);
170
171 // act
172 applyCoreProperties(mockConfig.config, mockConfig.manifest, 'fake-path', 'uap:', true);
173
174 var app = mockConfig.manifest.doc.find('.//Properties/DisplayName');
175 expect(app.text).toBe('ContosoApp');
176 });
177
178 it('"WindowsStorePublisherName" should be reflected in the manifest.', function () {
179
180 // arrange
181 var mockConfig = createMockConfigAndManifestForApplyCoreProperties('www.contoso.com/', { 'WindowsDefaultUriPrefix': 'http://', 'WindowsStorePublisherName': 'Contoso Inc' }, true);
182
183 // act
184 applyCoreProperties(mockConfig.config, mockConfig.manifest, 'fake-path', 'uap:', true);
185
186 var app = mockConfig.manifest.doc.find('.//Properties/PublisherDisplayName');
187 expect(app.text).toBe('Contoso Inc');
188 });
189});
190
191describe('A Windows 10 project should warn if it supports remote mode and restricted capabilities.', function () {
192
193 // arrange
194 var mockConfig;
195 var stringFound = false;
196 var searchStr = 'documentsLibrary';
197
198 beforeEach(function () {
199 mockConfig = createMockConfigAndManifestForApplyAccessRules(true, 'http://www.bing.com/*');
200 addCapabilityDeclarationToMockManifest(mockConfig.manifest, 'documentsLibrary');
201
202 spyOn(AppxManifest, 'get').and.returnValue(mockConfig.manifest);
203
204 stringFound = false;
205 events.on('warn', function (msg) {
206 if (msg.indexOf(searchStr) >= 0) { stringFound = true; }
207 });
208 });
209
210 it('asserts that the documentsLibrary capability is restricted', function () {
211 // act
212 updateManifestFile(mockConfig.config, '/manifest/path');
213
214 // assert
215 expect(stringFound).toBe(true);
216 });
217});
218
219/***
220 * Unit tests for validating that access rules get correctly applied
221 * (for the function applyAccessRules) from prepare.js.
222 **/
223
224function createMockConfigAndManifestForApplyAccessRules (isWin10) {
225 var rules = [];
226 for (var i = 1; i < arguments.length; i++) {
227 rules.push(arguments[i]);
228 }
229
230 var TEST_XML = '<?xml version="1.0" encoding="UTF-8"?>\n' +
231 '<widget xmlns = "http://www.w3.org/ns/widgets"\n' +
232 ' xmlns:cdv = "http://cordova.apache.org/ns/1.0"\n' +
233 ' id = "org.apache.cordova.HelloCordova"\n' +
234 ' version = "1.0.0.0">\n' +
235 ' <name>HelloCordova</name>\n' +
236 ' <author href="http://cordova.io" email="dev@cordova.apache.org">\n' +
237 ' Apache\n' +
238 ' </author>\n' +
239 ' <content src="index.html" />\n' +
240 '</widget>\n';
241
242 var origParseElementtreeSync = xml.parseElementtreeSync;
243 spyOn(xml, 'parseElementtreeSync').and.callFake(function (path) {
244 if (path === 'config.xml') return new et.ElementTree(et.XML(TEST_XML));
245 return origParseElementtreeSync(path);
246 });
247
248 var config = new ConfigParser('config.xml');
249
250 var origGetPreference = config.getPreference;
251 spyOn(config, 'getPreference').and.callFake(function (prefName) {
252 if (prefName === 'WindowsDefaultUriPrefix') {
253 return isWin10 ? 'ms-appx-web://' : 'ms-appx://';
254 }
255
256 return origGetPreference.call(config, prefName);
257 });
258
259 config.getAccesses = function () {
260 if (isWin10) {
261 return [];
262 }
263
264 return rules.map(function (rule) {
265 return { 'origin': rule };
266 });
267 };
268
269 config.getAllowNavigations = function () {
270 if (isWin10) {
271 return rules.map(function (rule) {
272 return { 'href': rule };
273 });
274 }
275
276 return [];
277 };
278
279 var filePath = isWin10 ? Win10ManifestPath : Win81ManifestPath;
280 var manifest = AppxManifest.get(filePath);
281 spyOn(fs, 'writeFileSync');
282
283 return { config: config, manifest: manifest };
284}
285
286describe('Access rules management', function () {
287 // body...
288 it('A Windows 8.1 project should not have WindowsRuntimeAccess attributes in access rules.', function () {
289
290 var mockConfig = createMockConfigAndManifestForApplyAccessRules(false, 'https://www.contoso.com');
291
292 applyAccessRules(mockConfig.config, mockConfig.manifest);
293
294 var app = mockConfig.manifest.doc.find('.//Application');
295 var accessRules = app.find('.//ApplicationContentUriRules');
296
297 expect(accessRules).toBeDefined();
298 expect(accessRules.len()).toBe(1);
299
300 var rule = accessRules.getItem(0);
301 expect(rule).toBeDefined();
302 expect(rule.attrib.WindowsRuntimeAccess).toBeUndefined();
303
304 });
305
306 it('A Windows 10 project should have WindowsRuntimeAccess attributes in access rules.', function () {
307
308 var mockConfig = createMockConfigAndManifestForApplyAccessRules(true, 'https://www.contoso.com');
309
310 applyNavigationWhitelist(mockConfig.config, mockConfig.manifest, true);
311
312 var app = mockConfig.manifest.doc.find('.//Application');
313 var accessRules = app.find('.//uap:ApplicationContentUriRules');
314
315 expect(accessRules).toBeDefined();
316 expect(accessRules.len()).toBe(2);
317
318 var rule = accessRules.getItem(0);
319 expect(rule).toBeDefined();
320 expect(rule.attrib.WindowsRuntimeAccess).toBeDefined();
321 expect(rule.attrib.WindowsRuntimeAccess).toBe('all');
322
323 });
324
325 describe('A Windows 8.1 project should reject http:// URI scheme rules.', function () {
326
327 var stringIndex = -1;
328 var searchStr = 'Access rules must begin with "https://", the following rule will be ignored: ';
329
330 beforeEach(function () {
331 require('cordova-common').events.on('warn', function (evt) {
332 stringIndex = evt.indexOf(searchStr);
333 });
334 });
335
336 it('applies access rules and verifies at least one was rejected', function () {
337 var mockConfig = createMockConfigAndManifestForApplyAccessRules(false, 'http://www.contoso.com');
338 applyAccessRules(mockConfig.config, mockConfig.manifest, false);
339
340 expect(stringIndex).toBe(0);
341 });
342 });
343
344 describe('A Windows 10 project should accept http:// URI access rules.', function () {
345
346 var stringIndex = -1;
347 var searchStr = 'The following navigation rule had an invalid URI scheme and is ignored:';
348 beforeEach(function () {
349 require('cordova-common').events.on('warn', function (evt) {
350 stringIndex = evt.indexOf(searchStr);
351 });
352 });
353
354 it('applies access rules and verifies they were accepted', function () {
355 var mockConfig = createMockConfigAndManifestForApplyAccessRules(true, 'http://www.contoso.com');
356 applyAccessRules(mockConfig.config, mockConfig.manifest, true);
357
358 expect(stringIndex).toBe(-1);
359 });
360 });
361});
362
363describe('A Windows 10 project should apply the uap: namespace prefix to certain capabilities.', function () {
364
365 var manifest;
366
367 beforeEach(function () {
368 manifest = createMockConfigAndManifestForApplyAccessRules(true, 'https://www.contoso.com').manifest;
369 var element = manifest.doc.find('.//Capabilities');
370 element.clear();
371 element.append(new et.Element('Capability', { Name: 'internetClient' }));
372 element.append(new et.Element('Capability', { Name: 'documentsLibrary' }));
373 element.append(new et.Element('DeviceCapability', { Name: 'location' }));
374 manifest.write();
375 });
376
377 it('Applies the uap: prefix to the documentsLibrary capability.', function () {
378 var testResults = {};
379 // map capabilities to tag
380 manifest.getCapabilities().forEach(function (child) {
381 testResults[child.name] = child.type;
382 });
383
384 expect(testResults.internetClient).toBe('Capability');
385 expect(testResults.documentsLibrary).toBe('uap:Capability');
386 expect(testResults.location).toBe('DeviceCapability');
387 });
388});
389
390function createMockConfigAndManifestForDescription (description) {
391 var config = {
392 version: function () { return '1.0.0.0'; },
393 name: function () { return 'HelloCordova'; },
394 description: function () { return description; },
395 packageName: function () { return 'org.apache.cordova.HelloCordova'; },
396 author: function () { return 'Apache'; },
397 startPage: function () { return 'index.html'; },
398 windows_packageVersion: function () { },
399 getPreference: function () { }
400 };
401
402 var manifest = AppxManifest.get(Win81ManifestPath, /* ignoreCache= */true);
403 spyOn(fs, 'writeFileSync');
404
405 return { config: config, manifest: manifest };
406}
407
408describe('Package description', function () {
409 it('should be applied to both Properties and VisualElements nodes', function () {
410 var mockConfig = createMockConfigAndManifestForDescription('My custom description');
411 applyCoreProperties(mockConfig.config, mockConfig.manifest, 'fake-path', 'uap:', true);
412
413 var desc = mockConfig.manifest.doc.find('.//Properties/Description');
414 expect(desc.text).toBe('My custom description');
415
416 desc = mockConfig.manifest.doc.find('.//Application/m2:VisualElements');
417 expect(desc.attrib.Description).toBe('My custom description');
418 });
419
420 it('should not be removed from VisualElements node', function () {
421 var mockConfig = createMockConfigAndManifestForDescription();
422 applyCoreProperties(mockConfig.config, mockConfig.manifest, 'fake-path', 'uap:', true);
423
424 var desc = mockConfig.manifest.doc.find('.//Properties/Description');
425 expect(desc).toBe(null);
426
427 desc = mockConfig.manifest.doc.find('.//Application/m2:VisualElements');
428 expect(desc.attrib.Description).toEqual(prepare.__get__('DEFAULT_DESCRIPTION'));
429 });
430
431 it('should be stripped to 2048 symbols before adding to manifest', function () {
432 var veryLongDescription = (new Array(3 * 1024)).join('x');
433 var mockConfig = createMockConfigAndManifestForDescription(veryLongDescription);
434
435 expect(function () {
436 applyCoreProperties(mockConfig.config, mockConfig.manifest, 'fake-path', 'uap:', true);
437 }).not.toThrow();
438
439 var desc = mockConfig.manifest.doc.find('.//Properties/Description');
440 expect(desc.text.length).toBe(2048);
441
442 desc = mockConfig.manifest.doc.find('.//Application/m2:VisualElements');
443 expect(desc.attrib.Description.length).toBe(2048);
444 });
445
446 it('should be validated before adding to manifest', function () {
447 var mockConfig = createMockConfigAndManifestForDescription('My description with \t and \n symbols');
448
449 expect(function () {
450 applyCoreProperties(mockConfig.config, mockConfig.manifest, 'fake-path', 'uap:', true);
451 }).not.toThrow();
452
453 var desc = mockConfig.manifest.doc.find('.//Properties/Description');
454 expect(desc).not.toMatch(/\n|\t/);
455
456 desc = mockConfig.manifest.doc.find('.//Application/m2:VisualElements');
457 expect(desc.attrib.Description).not.toMatch(/\n|\t/);
458 });
459});
460
461describe('copyIcons method', function () {
462 var copyImages = prepare.__get__('copyImages');
463 var logFileOp = prepare.__get__('logFileOp');
464
465 var PROJECT = '/some/path';
466
467 function createMockConfig (images, splashScreens) {
468 var result = jasmine.createSpyObj('config', ['getIcons', 'getSplashScreens']);
469 result.getIcons.and.returnValue(images);
470 result.getSplashScreens.and.returnValue(splashScreens || []);
471
472 return result;
473 }
474
475 beforeEach(function () {
476 spyOn(FileUpdater, 'updatePaths');
477 });
478
479 it('should guess target filename based on icon size', function () {
480 var images = [
481 { src: 'res/Windows/Square44x44Logo_100.png', width: '44', height: '44' },
482 { src: 'res/Windows/Square44x44Logo_240.png', width: '106', height: '106' }
483 ];
484
485 var project = { projectConfig: createMockConfig(images), root: PROJECT };
486 var locations = { root: PROJECT };
487
488 copyImages(project, locations);
489
490 var expectedPathMap = {};
491 expectedPathMap['images' + path.sep + 'Square44x44Logo.scale-100.png'] = 'res/Windows/Square44x44Logo_100.png';
492 expectedPathMap['images' + path.sep + 'Square44x44Logo.scale-240.png'] = 'res/Windows/Square44x44Logo_240.png';
493 expect(FileUpdater.updatePaths).toHaveBeenCalledWith(expectedPathMap, { rootDir: PROJECT }, logFileOp);
494 });
495
496 it('should ignore unknown icon sizes and emit a warning', function () {
497 var config = createMockConfig([
498 { src: 'res/Windows/UnknownImage.png', width: '999', height: '999' }
499 ]);
500 var project = { projectConfig: config, root: PROJECT };
501 var locations = { root: PROJECT };
502
503 var warnSpy = jasmine.createSpy('warn');
504 events.on('warn', warnSpy);
505 copyImages(project, locations);
506 expect(FileUpdater.updatePaths).toHaveBeenCalledWith({}, { rootDir: PROJECT }, logFileOp);
507 expect(warnSpy.calls.argsFor(0)[0]).toMatch('image was skipped');
508 });
509
510 describe('when "target" attribute is specified for the image', function () {
511 it('should copy all images with the same base name and extension to destination dir', function () {
512 var matchingFiles = [
513 'Square44x44.scale-100.png',
514 'Square44x44.targetsize-16.png',
515 'Square44x44.scale-150_targetsize-16.png',
516 'Square44x44.targetsize-16_scale-200.png',
517 'Square44x44.targetsize-16_altform-unplated_scale-200.png'
518 ];
519
520 var nonMatchingFiles = [
521 'Square55x55.scale-100.png',
522 'Square44x44.targetsize-16.jpg'
523 ];
524
525 spyOn(fs, 'readdirSync').and.returnValue(matchingFiles.concat(nonMatchingFiles));
526
527 var images = [{ src: 'res/Windows/Square44x44.png', target: 'SmallIcon' }];
528 var project = { projectConfig: createMockConfig(images), root: PROJECT };
529 var locations = { root: PROJECT };
530
531 copyImages(project, locations);
532
533 var expectedPathMap = {};
534 expectedPathMap[path.join('images', 'SmallIcon.scale-100.png')] =
535 path.join('res', 'Windows', 'Square44x44.scale-100.png');
536 expectedPathMap[path.join('images', 'SmallIcon.targetsize-16.png')] =
537 path.join('res', 'Windows', 'Square44x44.targetsize-16.png');
538 expectedPathMap[path.join('images', 'SmallIcon.scale-150_targetsize-16.png')] =
539 path.join('res', 'Windows', 'Square44x44.scale-150_targetsize-16.png');
540 expectedPathMap[path.join('images', 'SmallIcon.targetsize-16_scale-200.png')] =
541 path.join('res', 'Windows', 'Square44x44.targetsize-16_scale-200.png');
542 expectedPathMap[path.join('images', 'SmallIcon.targetsize-16_altform-unplated_scale-200.png')] =
543 path.join('res', 'Windows', 'Square44x44.targetsize-16_altform-unplated_scale-200.png');
544 expect(FileUpdater.updatePaths).toHaveBeenCalledWith(expectedPathMap, { rootDir: PROJECT }, logFileOp);
545 });
546 });
547
548 it('should ignore splashScreens for Windows 10 project with size >200K and emit a warning', function () {
549 var size300K = 300 * 1024;
550 var warnSpy = jasmine.createSpy('warn');
551 events.on('warn', warnSpy);
552
553 var splashScreens = [
554 { src: 'res/Windows/splashscreen.png', target: 'SplashScreen' }, // targetProject: 10
555 { src: 'res/Windows/splashscreen.scale-180.png', width: '1116', height: '540' }, // targetProject: 8.1
556 { src: 'res/Windows/splashscreen.scale-200.png', width: '1240', height: '600' }, // targetProject: 10
557 { src: 'res/Windows/splashscreen.scale-400.png', width: '2480', height: '1200' }, // targetProject: 10
558 { src: 'res/Windows/splashscreenphone.scale-240.png', width: '1152', height: '1920' }, // targetProject: WP 8.1
559 { src: 'res/Windows/splashscreenphone.png', target: 'SplashScreenPhone' } // targetProject: WP 8.1
560 ];
561
562 var splashScreensFiles = splashScreens.map(function (splash) {
563 return path.basename(splash.src);
564 });
565 spyOn(fs, 'readdirSync').and.returnValue(splashScreensFiles);
566
567 spyOn(fs, 'statSync').and.returnValue({
568 size: size300K
569 });
570
571 var project = { projectConfig: createMockConfig([], splashScreens), root: PROJECT };
572 var locations = { root: PROJECT };
573
574 copyImages(project, locations);
575
576 var expectedPathMap = {};
577 expectedPathMap['images' + path.sep + 'SplashScreen.scale-180.png'] = 'res/Windows/splashscreen.scale-180.png';
578 expectedPathMap['images' + path.sep + 'SplashScreenPhone.scale-240.png'] = path.join('res', 'Windows', 'splashscreenphone.scale-240.png');
579 expectedPathMap['images' + path.sep + 'SplashScreenPhone.scale-100.png'] = path.join('res', 'Windows', 'splashscreenphone.png');
580 expect(FileUpdater.updatePaths).toHaveBeenCalledWith(expectedPathMap, { rootDir: PROJECT }, logFileOp);
581 expect(warnSpy.calls.argsFor(0)[0]).toMatch('file size exceeds the limit');
582 });
583
584 it('should ignore splashScreens with unsupported extensions and emit a warning', function () {
585 var warnSpy = jasmine.createSpy('warn');
586 events.on('warn', warnSpy);
587
588 var splashScreens = [
589 { src: 'res/Windows/splashscreen.gif', target: 'SplashScreen' }, // targetProject: 10
590 { src: 'res/Windows/splashscreen.scale-180.bmp', width: '1116', height: '540' }, // targetProject: 8.1
591 { src: 'res/Windows/splashscreenphone.tga', target: 'SplashScreenPhone' } // targetProject: WP 8.1
592 ];
593
594 var splashScreensFiles = splashScreens.map(function (splash) {
595 return path.basename(splash.src);
596 });
597 spyOn(fs, 'readdirSync').and.returnValue(splashScreensFiles);
598
599 spyOn(fs, 'statSync').and.returnValue({
600 size: 0
601 });
602
603 var project = { projectConfig: createMockConfig([], splashScreens), root: PROJECT };
604 var locations = { root: PROJECT };
605
606 copyImages(project, locations);
607
608 var extensionNotSupportedMsg = 'extension is not supported';
609 var expectedPathMap = {};
610 expect(FileUpdater.updatePaths).toHaveBeenCalledWith(expectedPathMap, { rootDir: PROJECT }, logFileOp);
611 expect(warnSpy.calls.argsFor(0)[0]).toMatch(extensionNotSupportedMsg);
612 expect(warnSpy.calls.argsFor(1)[0]).toMatch(extensionNotSupportedMsg);
613 expect(warnSpy.calls.argsFor(2)[0]).toMatch(extensionNotSupportedMsg);
614 });
615
616 it('should warn about mixed splashscreen extensions used for non-MRT syntax', function () {
617 var updateSplashScreenImageExtensions = prepare.__get__('updateSplashScreenImageExtensions');
618 spyOn(fs, 'writeFileSync');
619 spyOn(AppxManifest, 'get').and.returnValue({
620 getVisualElements: function () {
621 return {
622 getSplashScreenExtension: function () {
623 return '.png';
624 },
625 setSplashScreenExtension: function () {}
626 };
627 },
628 write: function () {}
629 });
630 var warnSpy = jasmine.createSpy('warn');
631 events.on('warn', warnSpy);
632
633 var splashScreens = [
634 { src: 'res/Windows/splashscreen.png', width: '620', height: '300' }, // targetProject: 10
635 { src: 'res/Windows/splashscreen.scale-180.jpg', width: '1116', height: '540' }, // targetProject: 8.1
636 { src: 'res/Windows/splashscreen.scale-200.png', width: '1240', height: '600' }, // targetProject: 10
637 { src: 'res/Windows/splashscreen.scale-400.jpg', width: '2480', height: '1200' }, // targetProject: 10
638 { src: 'res/Windows/splashscreenphone.scale-240.png', width: '1152', height: '1920' }, // targetProject: WP 8.1
639 { src: 'res/Windows/splashscreenphone.jpg', width: '480', height: '800' } // targetProject: WP 8.1
640 ];
641
642 var splashScreensFiles = splashScreens.map(function (splash) {
643 return path.basename(splash.src);
644 });
645 spyOn(fs, 'readdirSync').and.returnValue(splashScreensFiles);
646
647 spyOn(fs, 'statSync').and.returnValue({
648 size: 0
649 });
650
651 var project = { projectConfig: createMockConfig([], splashScreens), root: PROJECT };
652 var locations = { root: PROJECT };
653
654 updateSplashScreenImageExtensions(project, locations);
655
656 var mixedExtensionsMsg = 'splash screens have mixed file extensions';
657 expect(warnSpy.calls.argsFor(0)[0]).toMatch(mixedExtensionsMsg);
658 expect(warnSpy.calls.argsFor(1)[0]).toMatch(mixedExtensionsMsg);
659 });
660
661 it('should update manifests with proper splashscreen image extension', function () {
662 // 1. Set manifest with SplashScreen.Image = "image.png" (this is default)
663 // 2. Set config.xml with splash src="image.jpg"
664 // 3. updateSplashScreenImageExtensions should call getSplashScreenExtension, setSplashScreenExtension('.jpg')
665
666 var updateSplashScreenImageExtensions = prepare.__get__('updateSplashScreenImageExtensions');
667 spyOn(fs, 'writeFileSync');
668
669 var win10Manifest = AppxManifest.get(Win10ManifestPath);
670 var win81Manifest = AppxManifest.get(Win81ManifestPath);
671 var wp81Manifest = AppxManifest.get(WP81ManifestPath);
672
673 spyOn(AppxManifest, 'get').and.callFake(function (manifestPath) {
674 if (manifestPath.indexOf(Win10ManifestName) !== -1) {
675 return win10Manifest;
676 }
677
678 if (manifestPath.indexOf(Win81ManifestName) !== -1) {
679 return win81Manifest;
680 }
681
682 if (manifestPath.indexOf(WP81ManifestName) !== -1) {
683 return wp81Manifest;
684 }
685 });
686
687 var splashScreens = [
688 { src: 'res/Windows/splashscreen.jpg', width: '620', height: '300' }, // targetProject: 10
689 { src: 'res/Windows/splashscreen.scale-180.jpg', width: '1116', height: '540' }, // targetProject: 8.1
690 { src: 'res/Windows/splashscreenphone.jpg', width: '480', height: '800' } // targetProject: WP 8.1
691 ];
692
693 var splashScreensFiles = splashScreens.map(function (splash) {
694 return path.basename(splash.src);
695 });
696 spyOn(fs, 'readdirSync').and.returnValue(splashScreensFiles);
697
698 spyOn(fs, 'statSync').and.returnValue({
699 size: 0
700 });
701
702 var project = { projectConfig: createMockConfig([], splashScreens), root: PROJECT };
703 var locations = { root: PROJECT };
704
705 updateSplashScreenImageExtensions(project, locations);
706
707 expect(win10Manifest.getVisualElements().getSplashScreenExtension()).toBe('.jpg');
708 expect(win81Manifest.getVisualElements().getSplashScreenExtension()).toBe('.jpg');
709 expect(wp81Manifest.getVisualElements().getSplashScreenExtension()).toBe('.jpg');
710 });
711});