arnaucube
arnaucube/openEventsPlatformAppPublic Self-hosted repository
openEventsPlatformApp/plugins/cordova-plugin-camera/appium-tests/helpers/cameraHelper.js
plugins/cordova-plugin-camera/appium-tests/helpers/cameraHelper.jsRaw
  1/*jshint node: true */
  2/* global Q, resolveLocalFileSystemURL, Camera, cordova */
  3/*
  4 *
  5 * Licensed to the Apache Software Foundation (ASF) under one
  6 * or more contributor license agreements.  See the NOTICE file
  7 * distributed with this work for additional information
  8 * regarding copyright ownership.  The ASF licenses this file
  9 * to you under the Apache License, Version 2.0 (the
 10 * "License"); you may not use this file except in compliance
 11 * with the License.  You may obtain a copy of the License at
 12 *
 13 *   http://www.apache.org/licenses/LICENSE-2.0
 14 *
 15 * Unless required by applicable law or agreed to in writing,
 16 * software distributed under the License is distributed on an
 17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 18 * KIND, either express or implied.  See the License for the
 19 * specific language governing permissions and limitations
 20 * under the License.
 21 *
 22*/
 23
 24'use strict';
 25
 26var cameraConstants = require('../../www/CameraConstants');
 27
 28function findKeyByValue(set, value) {
 29   for (var k in set) {
 30      if (set.hasOwnProperty(k)) {
 31         if (set[k] == value) {
 32            return k;
 33         }
 34      }
 35   }
 36   return undefined;
 37}
 38
 39function getDescription(spec) {
 40    var desc = '';
 41
 42    desc += 'sourceType: ' + findKeyByValue(cameraConstants.PictureSourceType, spec.options.sourceType);
 43    desc += ', destinationType: ' + findKeyByValue(cameraConstants.DestinationType, spec.options.destinationType);
 44    desc += ', encodingType: ' + findKeyByValue(cameraConstants.EncodingType, spec.options.encodingType);
 45    desc += ', allowEdit: ' + spec.options.allowEdit.toString();
 46    desc += ', correctOrientation: ' + spec.options.correctOrientation.toString();
 47
 48    return desc;
 49}
 50
 51module.exports.generateSpecs = function (sourceTypes, destinationTypes, encodingTypes, allowEditOptions, correctOrientationOptions) {
 52    var destinationType,
 53        sourceType,
 54        encodingType,
 55        allowEdit,
 56        correctOrientation,
 57        specs = [],
 58        id = 1;
 59    for (destinationType in destinationTypes) {
 60        if (destinationTypes.hasOwnProperty(destinationType)) {
 61            for (sourceType in sourceTypes) {
 62                if (sourceTypes.hasOwnProperty(sourceType)) {
 63                    for (encodingType in encodingTypes) {
 64                        if (encodingTypes.hasOwnProperty(encodingType)) {
 65                            for (allowEdit in allowEditOptions) {
 66                                if (allowEditOptions.hasOwnProperty(allowEdit)) {
 67                                    for (correctOrientation in correctOrientationOptions) {
 68                                        // if taking picture from photolibrary, don't vary 'correctOrientation' option
 69                                        if ((sourceTypes[sourceType] === cameraConstants.PictureSourceType.PHOTOLIBRARY ||
 70                                            sourceTypes[sourceType] === cameraConstants.PictureSourceType.SAVEDPHOTOALBUM) &&
 71                                            correctOrientation === true) { continue; }
 72                                        var spec = {
 73                                            'id': id++,
 74                                            'options': {
 75                                                'destinationType': destinationTypes[destinationType],
 76                                                'sourceType': sourceTypes[sourceType],
 77                                                'encodingType': encodingTypes[encodingType],
 78                                                'allowEdit': allowEditOptions[allowEdit],
 79                                                'saveToPhotoAlbum': false,
 80                                                'correctOrientation': correctOrientationOptions[correctOrientation]
 81                                            }
 82                                        };
 83                                        spec.description = getDescription(spec);
 84                                        specs.push(spec);
 85                                    }
 86                                }
 87                            }
 88                        }
 89                    }
 90                }
 91            }
 92        }
 93    }
 94    return specs;
 95};
 96
 97// calls getPicture() and saves the result in promise
 98// note that this function is executed in the context of tested app
 99// and not in the context of tests
100module.exports.getPicture = function (opts, pid) {
101    if (navigator._appiumPromises[pid - 1]) {
102        navigator._appiumPromises[pid - 1] = null;
103    }
104    navigator._appiumPromises[pid] = Q.defer();
105    navigator.camera.getPicture(function (result) {
106        navigator._appiumPromises[pid].resolve(result);
107    }, function (err) {
108        navigator._appiumPromises[pid].reject(err);
109    }, opts);
110};
111
112// verifies taken picture when the promise is resolved,
113// calls a callback with 'OK' if everything is good,
114// calls a callback with 'ERROR: <error message>' if something is wrong
115// note that this function is executed in the context of tested app
116// and not in the context of tests
117module.exports.checkPicture = function (pid, options, cb) {
118    var isIos = cordova.platformId === "ios";
119    var isAndroid = cordova.platformId === "android";
120    // skip image type check if it's unmodified on Android:
121    // https://github.com/apache/cordova-plugin-camera/#android-quirks-1
122    var skipFileTypeCheckAndroid = isAndroid && options.quality === 100 &&
123        !options.targetWidth && !options.targetHeight &&
124        !options.correctOrientation;
125
126    // Skip image type check if destination is NATIVE_URI and source - device's photoalbum
127    // https://github.com/apache/cordova-plugin-camera/#ios-quirks-1
128    var skipFileTypeCheckiOS = isIos && options.destinationType === Camera.DestinationType.NATIVE_URI &&
129        (options.sourceType === Camera.PictureSourceType.PHOTOLIBRARY ||
130         options.sourceType === Camera.PictureSourceType.SAVEDPHOTOALBUM);
131
132    var skipFileTypeCheck = skipFileTypeCheckAndroid || skipFileTypeCheckiOS;
133
134    var desiredType = 'JPEG';
135    var mimeType = 'image/jpeg';
136    if (options.encodingType === Camera.EncodingType.PNG) {
137        desiredType = 'PNG';
138        mimeType = 'image/png';
139    }
140
141    function errorCallback(msg) {
142        if (msg.hasOwnProperty('message')) {
143            msg = msg.message;
144        }
145        cb('ERROR: ' + msg);
146    }
147
148    // verifies the image we get from plugin
149    function verifyResult(result) {
150        if (result.length === 0) {
151            errorCallback('The result is empty.');
152            return;
153        } else if (isIos && options.destinationType === Camera.DestinationType.NATIVE_URI && result.indexOf('assets-library:') !== 0) {
154            errorCallback('Expected "' + result.substring(0, 150) + '"to start with "assets-library:"');
155            return;
156        } else if (isIos && options.destinationType === Camera.DestinationType.FILE_URI && result.indexOf('file:') !== 0) {
157            errorCallback('Expected "' + result.substring(0, 150) + '"to start with "file:"');
158            return;
159        }
160
161        try {
162            window.atob(result);
163            // if we got here it is a base64 string (DATA_URL)
164            result = "data:" + mimeType + ";base64," + result;
165        } catch (e) {
166            // not DATA_URL
167            if (options.destinationType === Camera.DestinationType.DATA_URL) {
168                errorCallback('Expected ' + result.substring(0, 150) + 'not to be DATA_URL');
169                return;
170            }
171        }
172
173        try {
174            if (result.indexOf('file:') === 0 ||
175                result.indexOf('content:') === 0 ||
176                result.indexOf('assets-library:') === 0) {
177
178                if (!window.resolveLocalFileSystemURL) {
179                    errorCallback('Cannot read file. Please install cordova-plugin-file to fix this.');
180                    return;
181                }
182                resolveLocalFileSystemURL(result, function (entry) {
183                    if (skipFileTypeCheck) {
184                        displayFile(entry);
185                    } else {
186                        verifyFile(entry);
187                    }
188                }, function (err) {
189                    errorCallback(err);
190                });
191            } else {
192                displayImage(result);
193            }
194        } catch (e) {
195            errorCallback(e);
196        }
197    }
198
199    // verifies that the file type matches the requested type
200    function verifyFile(entry) {
201        try {
202            var reader = new FileReader();
203            reader.onloadend = function(e) {
204                var arr = (new Uint8Array(e.target.result)).subarray(0, 4);
205                var header = '';
206                for(var i = 0; i < arr.length; i++) {
207                    header += arr[i].toString(16);
208                }
209                var actualType = 'unknown';
210
211                switch (header) {
212                    case "89504e47":
213                        actualType = 'PNG';
214                        break;
215                    case 'ffd8ffe0':
216                    case 'ffd8ffe1':
217                    case 'ffd8ffe2':
218                        actualType = 'JPEG';
219                        break;
220                }
221
222                if (actualType === desiredType) {
223                    displayFile(entry);
224                } else {
225                    errorCallback('File type mismatch. Expected ' + desiredType + ', got ' + actualType);
226                }
227            };
228            reader.onerror = function (e) {
229                errorCallback(e);
230            };
231            entry.file(function (file) {
232                reader.readAsArrayBuffer(file);
233            }, function (e) {
234                errorCallback(e);
235            });
236        } catch (e) {
237            errorCallback(e);
238        }
239    }
240
241    // reads the file, then displays the image
242    function displayFile(entry) {
243        function onFileReceived(file) {
244            var reader = new FileReader();
245            reader.onerror = function (e) {
246                errorCallback(e);
247            };
248            reader.onloadend = function (evt) {
249                displayImage(evt.target.result);
250            };
251            reader.readAsDataURL(file);
252        }
253
254        entry.file(onFileReceived, function (e) {
255            errorCallback(e);
256        });
257    }
258
259    function displayImage(image) {
260        try {
261            var imgEl = document.getElementById('camera_test_image');
262            if (!imgEl) {
263                imgEl = document.createElement('img');
264                imgEl.id = 'camera_test_image';
265                document.body.appendChild(imgEl);
266            }
267            var timedOut = false;
268            var loadTimeout = setTimeout(function () {
269                timedOut = true;
270                imgEl.src = '';
271                errorCallback('The image did not load: ' + image.substring(0, 150));
272            }, 10000);
273            var done = function (status) {
274                if (!timedOut) {
275                    clearTimeout(loadTimeout);
276                    imgEl.src = '';
277                    cb(status);
278                }
279            };
280            imgEl.onload = function () {
281                try {
282                    // aspect ratio is preserved so only one dimension should match
283                    if ((typeof options.targetWidth === 'number' && imgEl.naturalWidth !== options.targetWidth) &&
284                        (typeof options.targetHeight === 'number' && imgEl.naturalHeight !== options.targetHeight))
285                    {
286                        done('ERROR: Wrong image size: ' + imgEl.naturalWidth + 'x' + imgEl.naturalHeight +
287                            '. Requested size: ' + options.targetWidth + 'x' + options.targetHeight);
288                    } else {
289                        done('OK');
290                    }
291                } catch (e) {
292                    errorCallback(e);
293                }
294            };
295            imgEl.src = image;
296        } catch (e) {
297            errorCallback(e);
298        }
299    }
300
301    navigator._appiumPromises[pid].promise
302        .then(function (result) {
303            verifyResult(result);
304        })
305        .fail(function (e) {
306            errorCallback(e);
307        });
308};