1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | var rewire = require('rewire');
|
21 | var prepare = rewire('../../template/cordova/lib/prepare');
|
22 | var AppxManifest = require('../../template/cordova/lib/AppxManifest');
|
23 | var ConfigParser = require('../../template/cordova/lib/ConfigParser');
|
24 | var fs = require('fs');
|
25 | var et = require('elementtree');
|
26 | var events = require('cordova-common').events;
|
27 | var path = require('path');
|
28 | var xml = require('cordova-common').xmlHelpers;
|
29 | var FileUpdater = require('cordova-common').FileUpdater;
|
30 | var updateManifestFile = prepare.__get__('updateManifestFile');
|
31 | var applyCoreProperties = prepare.__get__('applyCoreProperties');
|
32 | var applyAccessRules = prepare.__get__('applyAccessRules');
|
33 | var applyNavigationWhitelist = prepare.__get__('applyNavigationWhitelist');
|
34 | var applyStartPage = prepare.__get__('applyStartPage');
|
35 |
|
36 | var Win10ManifestPath = 'template/package.windows10.appxmanifest';
|
37 | var Win81ManifestPath = 'template/package.windows.appxmanifest';
|
38 | var WP81ManifestPath = 'template/package.phone.appxmanifest';
|
39 |
|
40 | var Win10ManifestName = path.basename(Win10ManifestPath);
|
41 | var Win81ManifestName = path.basename(Win81ManifestPath);
|
42 | var WP81ManifestName = path.basename(WP81ManifestPath);
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 | var PreferencesBaseline = {
|
50 | Orientation: null,
|
51 | WindowsDefaultUriPrefix: null,
|
52 | WindowsStoreDisplayName: null,
|
53 | WindowsStorePublisherName: null,
|
54 | WindowsStoreIdentityName: null
|
55 | };
|
56 |
|
57 | function createMockConfigAndManifestForApplyCoreProperties (startPage, preferences, win10, winPackageVersion) {
|
58 | if (!preferences) {
|
59 | preferences = { };
|
60 | }
|
61 |
|
62 | preferences.__proto__ = PreferencesBaseline;
|
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 |
|
88 | function 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 |
|
95 | describe('Windows 8.1 project', function () {
|
96 |
|
97 | it('should not have an HTTP or HTTPS scheme for its startup URI.', function () {
|
98 |
|
99 |
|
100 | var mockConfig = createMockConfigAndManifestForApplyCoreProperties('index.html', { 'WindowsDefaultUriPrefix': 'http://' }, false);
|
101 |
|
102 |
|
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 |
|
112 | var mockConfig = createMockConfigAndManifestForApplyCoreProperties('index.html', { 'WindowsDefaultUriPrefix': 'ms-appx://' }, false);
|
113 |
|
114 |
|
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 |
|
122 | describe('Windows 10 project', function () {
|
123 | it('should default to ms-appx-web for its startup URI.', function () {
|
124 |
|
125 |
|
126 | var mockConfig = createMockConfigAndManifestForApplyCoreProperties('index.html', { }, true);
|
127 |
|
128 |
|
129 | applyStartPage(mockConfig.config, mockConfig.manifest, true);
|
130 |
|
131 | var app = mockConfig.manifest.doc.find('.//Application');
|
132 |
|
133 |
|
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 |
|
142 | var mockConfig = createMockConfigAndManifestForApplyCoreProperties('index.html', { 'WindowsDefaultUriPrefix': 'ms-appx://' }, true);
|
143 |
|
144 |
|
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 |
|
154 | var mockConfig = createMockConfigAndManifestForApplyCoreProperties('www.contoso.com/', { 'WindowsDefaultUriPrefix': 'http://' }, true);
|
155 |
|
156 |
|
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 |
|
164 | describe('Windows Store preference', function () {
|
165 |
|
166 | it('"WindowsStoreDisplayName" should be reflected in the manifest.', function () {
|
167 |
|
168 |
|
169 | var mockConfig = createMockConfigAndManifestForApplyCoreProperties('www.contoso.com/', { 'WindowsDefaultUriPrefix': 'http://', 'WindowsStoreDisplayName': 'ContosoApp' }, true);
|
170 |
|
171 |
|
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 |
|
181 | var mockConfig = createMockConfigAndManifestForApplyCoreProperties('www.contoso.com/', { 'WindowsDefaultUriPrefix': 'http://', 'WindowsStorePublisherName': 'Contoso Inc' }, true);
|
182 |
|
183 |
|
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 |
|
191 | describe('A Windows 10 project should warn if it supports remote mode and restricted capabilities.', function () {
|
192 |
|
193 |
|
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 |
|
212 | updateManifestFile(mockConfig.config, '/manifest/path');
|
213 |
|
214 |
|
215 | expect(stringFound).toBe(true);
|
216 | });
|
217 | });
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 | function 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 |
|
286 | describe('Access rules management', function () {
|
287 |
|
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 |
|
363 | describe('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 |
|
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 |
|
390 | function 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, true);
|
403 | spyOn(fs, 'writeFileSync');
|
404 |
|
405 | return { config: config, manifest: manifest };
|
406 | }
|
407 |
|
408 | describe('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 |
|
461 | describe('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' },
|
555 | { src: 'res/Windows/splashscreen.scale-180.png', width: '1116', height: '540' },
|
556 | { src: 'res/Windows/splashscreen.scale-200.png', width: '1240', height: '600' },
|
557 | { src: 'res/Windows/splashscreen.scale-400.png', width: '2480', height: '1200' },
|
558 | { src: 'res/Windows/splashscreenphone.scale-240.png', width: '1152', height: '1920' },
|
559 | { src: 'res/Windows/splashscreenphone.png', target: 'SplashScreenPhone' }
|
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' },
|
590 | { src: 'res/Windows/splashscreen.scale-180.bmp', width: '1116', height: '540' },
|
591 | { src: 'res/Windows/splashscreenphone.tga', target: 'SplashScreenPhone' }
|
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' },
|
635 | { src: 'res/Windows/splashscreen.scale-180.jpg', width: '1116', height: '540' },
|
636 | { src: 'res/Windows/splashscreen.scale-200.png', width: '1240', height: '600' },
|
637 | { src: 'res/Windows/splashscreen.scale-400.jpg', width: '2480', height: '1200' },
|
638 | { src: 'res/Windows/splashscreenphone.scale-240.png', width: '1152', height: '1920' },
|
639 | { src: 'res/Windows/splashscreenphone.jpg', width: '480', height: '800' }
|
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 |
|
663 |
|
664 |
|
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' },
|
689 | { src: 'res/Windows/splashscreen.scale-180.jpg', width: '1116', height: '540' },
|
690 | { src: 'res/Windows/splashscreenphone.jpg', width: '480', height: '800' }
|
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 | });
|