arnaucube
arnaucube/openEventsPlatformAppPublic Self-hosted repository
openEventsPlatformApp/plugins/cordova-plugin-camera/tests/tests.js
plugins/cordova-plugin-camera/tests/tests.jsRaw
  1/*
  2 *
  3 * Licensed to the Apache Software Foundation (ASF) under one
  4 * or more contributor license agreements.  See the NOTICE file
  5 * distributed with this work for additional information
  6 * regarding copyright ownership.  The ASF licenses this file
  7 * to you under the Apache License, Version 2.0 (the
  8 * "License"); you may not use this file except in compliance
  9 * with the License.  You may obtain a copy of the License at
 10 *
 11 *   http://www.apache.org/licenses/LICENSE-2.0
 12 *
 13 * Unless required by applicable law or agreed to in writing,
 14 * software distributed under the License is distributed on an
 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 16 * KIND, either express or implied.  See the License for the
 17 * specific language governing permissions and limitations
 18 * under the License.
 19 *
 20*/
 21
 22/* globals Camera, resolveLocalFileSystemURL, FileEntry, CameraPopoverOptions, FileTransfer, FileUploadOptions, LocalFileSystem, MSApp */
 23/* jshint jasmine: true */
 24
 25exports.defineAutoTests = function () {
 26    describe('Camera (navigator.camera)', function () {
 27        it("should exist", function () {
 28            expect(navigator.camera).toBeDefined();
 29        });
 30
 31        it("should contain a getPicture function", function () {
 32            expect(navigator.camera.getPicture).toBeDefined();
 33            expect(typeof navigator.camera.getPicture == 'function').toBe(true);
 34        });
 35    });
 36
 37    describe('Camera Constants (window.Camera + navigator.camera)', function () {
 38        it("camera.spec.1 window.Camera should exist", function () {
 39            expect(window.Camera).toBeDefined();
 40        });
 41
 42        it("camera.spec.2 should contain three DestinationType constants", function () {
 43            expect(Camera.DestinationType.DATA_URL).toBe(0);
 44            expect(Camera.DestinationType.FILE_URI).toBe(1);
 45            expect(Camera.DestinationType.NATIVE_URI).toBe(2);
 46            expect(navigator.camera.DestinationType.DATA_URL).toBe(0);
 47            expect(navigator.camera.DestinationType.FILE_URI).toBe(1);
 48            expect(navigator.camera.DestinationType.NATIVE_URI).toBe(2);
 49        });
 50
 51        it("camera.spec.3 should contain two EncodingType constants", function () {
 52            expect(Camera.EncodingType.JPEG).toBe(0);
 53            expect(Camera.EncodingType.PNG).toBe(1);
 54            expect(navigator.camera.EncodingType.JPEG).toBe(0);
 55            expect(navigator.camera.EncodingType.PNG).toBe(1);
 56        });
 57
 58        it("camera.spec.4 should contain three MediaType constants", function () {
 59            expect(Camera.MediaType.PICTURE).toBe(0);
 60            expect(Camera.MediaType.VIDEO).toBe(1);
 61            expect(Camera.MediaType.ALLMEDIA).toBe(2);
 62            expect(navigator.camera.MediaType.PICTURE).toBe(0);
 63            expect(navigator.camera.MediaType.VIDEO).toBe(1);
 64            expect(navigator.camera.MediaType.ALLMEDIA).toBe(2);
 65        });
 66
 67        it("camera.spec.5 should contain three PictureSourceType constants", function () {
 68            expect(Camera.PictureSourceType.PHOTOLIBRARY).toBe(0);
 69            expect(Camera.PictureSourceType.CAMERA).toBe(1);
 70            expect(Camera.PictureSourceType.SAVEDPHOTOALBUM).toBe(2);
 71            expect(navigator.camera.PictureSourceType.PHOTOLIBRARY).toBe(0);
 72            expect(navigator.camera.PictureSourceType.CAMERA).toBe(1);
 73            expect(navigator.camera.PictureSourceType.SAVEDPHOTOALBUM).toBe(2);
 74        });
 75    });
 76};
 77
 78
 79/******************************************************************************/
 80/******************************************************************************/
 81/******************************************************************************/
 82
 83exports.defineManualTests = function (contentEl, createActionButton) {
 84    var pictureUrl = null;
 85    var fileObj = null;
 86    var fileEntry = null;
 87    var pageStartTime = +new Date();
 88
 89    //default camera options
 90    var camQualityDefault = ['50', 50];
 91    var camDestinationTypeDefault = ['FILE_URI', 1];
 92    var camPictureSourceTypeDefault = ['CAMERA', 1];
 93    var camAllowEditDefault = ['allowEdit', false];
 94    var camEncodingTypeDefault = ['JPEG', 0];
 95    var camMediaTypeDefault = ['mediaType', 0];
 96    var camCorrectOrientationDefault = ['correctOrientation', false];
 97    var camSaveToPhotoAlbumDefault = ['saveToPhotoAlbum', true];
 98
 99    function log(value) {
100        console.log(value);
101        document.getElementById('camera_status').textContent += (new Date() - pageStartTime) / 1000 + ': ' + value + '\n';
102    }
103
104    function clearStatus() {
105        document.getElementById('camera_status').innerHTML = '';
106        document.getElementById('camera_image').src = 'about:blank';
107        var canvas = document.getElementById('canvas');
108        canvas.width = canvas.height = 1;
109        pictureUrl = null;
110        fileObj = null;
111        fileEntry = null;
112    }
113
114    function setPicture(url, callback) {
115        try {
116            window.atob(url);
117            // if we got here it is a base64 string (DATA_URL)
118            url = "data:image/jpeg;base64," + url;
119        } catch (e) {
120            // not DATA_URL
121        }
122        log('URL: "' + url.slice(0, 90) + '"');
123
124        pictureUrl = url;
125        var img = document.getElementById('camera_image');
126        var startTime = new Date();
127        img.src = url;
128        img.onload = function () {
129            log('Img size: ' + img.naturalWidth + 'x' + img.naturalHeight);
130            log('Image tag load time: ' + (new Date() - startTime));
131            if (callback) {
132                callback();
133            }
134        };
135    }
136
137    function onGetPictureError(e) {
138        log('Error getting picture: ' + (e.code || e));
139    }
140
141    function getPictureWin(data) {
142        setPicture(data);
143        // TODO: Fix resolveLocalFileSystemURI to work with native-uri.
144        if (pictureUrl.indexOf('file:') === 0 || pictureUrl.indexOf('content:') === 0 || pictureUrl.indexOf('ms-appdata:') === 0 || pictureUrl.indexOf('assets-library:') === 0) {
145            resolveLocalFileSystemURL(data, function (e) {
146                fileEntry = e;
147                logCallback('resolveLocalFileSystemURL()', true)(e.toURL());
148                readFile();
149            }, logCallback('resolveLocalFileSystemURL()', false));
150        } else if (pictureUrl.indexOf('data:image/jpeg;base64') === 0) {
151            // do nothing
152        } else {
153            var path = pictureUrl.replace(/^file:\/\/(localhost)?/, '').replace(/%20/g, ' ');
154            fileEntry = new FileEntry('image_name.png', path);
155        }
156    }
157
158    function getPicture() {
159        clearStatus();
160        var options = extractOptions();
161        log('Getting picture with options: ' + JSON.stringify(options));
162        var popoverHandle = navigator.camera.getPicture(getPictureWin, onGetPictureError, options);
163
164        // Reposition the popover if the orientation changes.
165        window.onorientationchange = function () {
166            var newPopoverOptions = new CameraPopoverOptions(0, 0, 100, 100, 0);
167            popoverHandle.setPosition(newPopoverOptions);
168        };
169    }
170
171    function uploadImage() {
172        var ft = new FileTransfer(),
173            options = new FileUploadOptions();
174        options.fileKey = "photo";
175        options.fileName = 'test.jpg';
176        options.mimeType = "image/jpeg";
177        ft.onprogress = function (progressEvent) {
178            console.log('progress: ' + progressEvent.loaded + ' of ' + progressEvent.total);
179        };
180        var server = "http://sheltered-retreat-43956.herokuapp.com";
181
182        ft.upload(pictureUrl, server + '/upload', win, fail, options);
183        function win(information_back) {
184            log('upload complete');
185        }
186        function fail(message) {
187            log('upload failed: ' + JSON.stringify(message));
188        }
189    }
190
191    function logCallback(apiName, success) {
192        return function () {
193            log('Call to ' + apiName + (success ? ' success: ' : ' failed: ') + JSON.stringify([].slice.call(arguments)));
194        };
195    }
196
197    /**
198     * Select image from library using a NATIVE_URI destination type
199     * This calls FileEntry.getMetadata, FileEntry.setMetadata, FileEntry.getParent, FileEntry.file, and FileReader.readAsDataURL.
200     */
201    function readFile() {
202        function onFileReadAsDataURL(evt) {
203            var img = document.getElementById('camera_image');
204            img.style.visibility = "visible";
205            img.style.display = "block";
206            img.src = evt.target.result;
207            log("FileReader.readAsDataURL success");
208        }
209
210        function onFileReceived(file) {
211            log('Got file: ' + JSON.stringify(file));
212            fileObj = file;
213
214            var reader = new FileReader();
215            reader.onload = function () {
216                log('FileReader.readAsDataURL() - length = ' + reader.result.length);
217            };
218            reader.onerror = logCallback('FileReader.readAsDataURL', false);
219            reader.onloadend = onFileReadAsDataURL;
220            reader.readAsDataURL(file);
221        }
222
223        // Test out onFileReceived when the file object was set via a native <input> elements.
224        if (fileObj) {
225            onFileReceived(fileObj);
226        } else {
227            fileEntry.file(onFileReceived, logCallback('FileEntry.file', false));
228        }
229    }
230
231    function getFileInfo() {
232        // Test FileEntry API here.
233        fileEntry.getMetadata(logCallback('FileEntry.getMetadata', true), logCallback('FileEntry.getMetadata', false));
234        fileEntry.setMetadata(logCallback('FileEntry.setMetadata', true), logCallback('FileEntry.setMetadata', false), { "com.apple.MobileBackup": 1 });
235        fileEntry.getParent(logCallback('FileEntry.getParent', true), logCallback('FileEntry.getParent', false));
236        fileEntry.getParent(logCallback('FileEntry.getParent', true), logCallback('FileEntry.getParent', false));
237    }
238
239    /**
240     * Copy image from library using a NATIVE_URI destination type
241     * This calls FileEntry.copyTo and FileEntry.moveTo.
242     */
243    function copyImage() {
244        var onFileSystemReceived = function (fileSystem) {
245            var destDirEntry = fileSystem.root;
246            var origName = fileEntry.name;
247
248            // Test FileEntry API here.
249            fileEntry.copyTo(destDirEntry, 'copied_file.png', logCallback('FileEntry.copyTo', true), logCallback('FileEntry.copyTo', false));
250            fileEntry.moveTo(destDirEntry, 'moved_file.png', logCallback('FileEntry.moveTo', true), logCallback('FileEntry.moveTo', false));
251
252            //cleanup
253            //rename moved file back to original name so other tests can reference image
254            resolveLocalFileSystemURL(destDirEntry.nativeURL+'moved_file.png', function(fileEntry) {
255                fileEntry.moveTo(destDirEntry, origName, logCallback('FileEntry.moveTo', true), logCallback('FileEntry.moveTo', false));
256                console.log('Cleanup: successfully renamed file back to original name');
257            }, function () {
258                console.log('Cleanup: failed to rename file back to original name');
259            });
260
261            //remove copied file
262            resolveLocalFileSystemURL(destDirEntry.nativeURL+'copied_file.png', function(fileEntry) {
263                fileEntry.remove(logCallback('FileEntry.remove', true), logCallback('FileEntry.remove', false));
264                console.log('Cleanup: successfully removed copied file');
265            }, function () {
266                console.log('Cleanup: failed to remove copied file');
267            });
268        };
269
270        window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, onFileSystemReceived, null);
271    }
272
273    /**
274     * Write image to library using a NATIVE_URI destination type
275     * This calls FileEntry.createWriter, FileWriter.write, and FileWriter.truncate.
276     */
277    function writeImage() {
278        var onFileWriterReceived = function (fileWriter) {
279            fileWriter.onwrite = logCallback('FileWriter.write', true);
280            fileWriter.onerror = logCallback('FileWriter.write', false);
281            fileWriter.write("some text!");
282        };
283
284        var onFileTruncateWriterReceived = function (fileWriter) {
285            fileWriter.onwrite = logCallback('FileWriter.truncate', true);
286            fileWriter.onerror = logCallback('FileWriter.truncate', false);
287            fileWriter.truncate(10);
288        };
289
290        fileEntry.createWriter(onFileWriterReceived, logCallback('FileEntry.createWriter', false));
291        fileEntry.createWriter(onFileTruncateWriterReceived, null);
292    }
293
294    function displayImageUsingCanvas() {
295        var canvas = document.getElementById('canvas');
296        var img = document.getElementById('camera_image');
297        var w = img.width;
298        var h = img.height;
299        h = 100 / w * h;
300        w = 100;
301        canvas.width = w;
302        canvas.height = h;
303        var context = canvas.getContext('2d');
304        context.drawImage(img, 0, 0, w, h);
305    }
306
307    /**
308     * Remove image from library using a NATIVE_URI destination type
309     * This calls FileEntry.remove.
310     */
311    function removeImage() {
312        fileEntry.remove(logCallback('FileEntry.remove', true), logCallback('FileEntry.remove', false));
313    }
314
315    function testInputTag(inputEl) {
316        clearStatus();
317        // iOS 6 likes to dead-lock in the onchange context if you
318        // do any alerts or try to remote-debug.
319        window.setTimeout(function () {
320            testNativeFile2(inputEl);
321        }, 0);
322    }
323
324    function testNativeFile2(inputEl) {
325        if (!inputEl.value) {
326            alert('No file selected.');
327            return;
328        }
329        fileObj = inputEl.files[0];
330        if (!fileObj) {
331            alert('Got value but no file.');
332            return;
333        }
334        var URLApi = window.URL || window.webkitURL;
335        if (URLApi) {
336            var blobURL = URLApi.createObjectURL(fileObj);
337            if (blobURL) {
338                setPicture(blobURL, function () {
339                    URLApi.revokeObjectURL(blobURL);
340                });
341            } else {
342                log('URL.createObjectURL returned null');
343            }
344        } else {
345            log('URL.createObjectURL() not supported.');
346        }
347    }
348
349    function extractOptions() {
350        var els = document.querySelectorAll('#image-options select');
351        var ret = {};
352        /*jshint -W084 */
353        for (var i = 0, el; el = els[i]; ++i) {
354            var value = el.value;
355            if (value === '') continue;
356            value = +value;
357
358            if (el.isBool) {
359                ret[el.getAttribute("name")] = !!value;
360            } else {
361                ret[el.getAttribute("name")] = value;
362            }
363        }
364        /*jshint +W084 */
365        return ret;
366    }
367
368    function createOptionsEl(name, values, selectionDefault) {
369        var openDiv = '<div style="display: inline-block">' + name + ': ';
370        var select = '<select name=' + name + ' id="' + name + '">';
371
372        var defaultOption = '';
373        if (selectionDefault === undefined) {
374            defaultOption = '<option value="">default</option>';
375        }
376
377        var options = '';
378        if (typeof values == 'boolean') {
379            values = { 'true': 1, 'false': 0 };
380        }
381        for (var k in values) {
382            var isSelected = '';
383            if (selectionDefault) {
384                if (selectionDefault[0] == k) {
385                    isSelected = 'selected';
386                }
387            }
388            options += '<option value="' + values[k] + '" ' + isSelected + '>' + k + '</option>';
389        }
390
391        var closeDiv = '</select></div>';
392
393        return openDiv + select + defaultOption + options + closeDiv;
394    }
395
396    /******************************************************************************/
397
398    var info_div = '<h1>Camera</h1>' +
399            '<div id="info">' +
400            '<b>Status:</b> <div id="camera_status"></div>' +
401            'img: <img width="100" id="camera_image">' +
402            'canvas: <canvas id="canvas" width="1" height="1"></canvas>' +
403            '</div>',
404        options_div = '<h2>Cordova Camera API Options</h2>' +
405            '<div id="image-options">' +
406            createOptionsEl('sourceType', Camera.PictureSourceType, camPictureSourceTypeDefault) +
407            createOptionsEl('destinationType', Camera.DestinationType, camDestinationTypeDefault) +
408            createOptionsEl('encodingType', Camera.EncodingType, camEncodingTypeDefault) +
409            createOptionsEl('mediaType', Camera.MediaType, camMediaTypeDefault) +
410            createOptionsEl('quality', { '0': 0, '50': 50, '80': 80, '100': 100 }, camQualityDefault) +
411            createOptionsEl('targetWidth', { '50': 50, '200': 200, '800': 800, '2048': 2048 }) +
412            createOptionsEl('targetHeight', { '50': 50, '200': 200, '800': 800, '2048': 2048 }) +
413            createOptionsEl('allowEdit', true, camAllowEditDefault) +
414            createOptionsEl('correctOrientation', true, camCorrectOrientationDefault) +
415            createOptionsEl('saveToPhotoAlbum', true, camSaveToPhotoAlbumDefault) +
416            createOptionsEl('cameraDirection', Camera.Direction) +
417            '</div>',
418        getpicture_div = '<div id="getpicture"></div>',
419        test_procedure = '<h4>Recommended Test Procedure</h4>' +
420            'Options not specified should be the default value' +
421            '<br>Status box should update with image and info whenever an image is taken or selected from library' +
422            '</p><div style="background:#B0C4DE;border:1px solid #FFA07A;margin:15px 6px 0px;min-width:295px;max-width:97%;padding:4px 0px 2px 10px;min-height:160px;max-height:200px;overflow:auto">' +
423            '<ol> <li>All default options. Should be able to edit once picture is taken and will be saved to library.</li>' +
424            '</p><li>sourceType=PHOTOLIBRARY<br>Should be able to see picture that was just taken in previous test and edit when selected</li>' +
425            '</p><li>sourceType=Camera<br>allowEdit=false<br>saveToPhotoAlbum=false<br>Should not be able to edit when taken and will not save to library</li>' +
426            '</p><li>encodingType=PNG<br>allowEdit=true<br>saveToPhotoAlbum=true<br>cameraDirection=FRONT<br>Should bring up front camera. Verify in status box info URL that image is encoded as PNG.</li>' +
427            '</p><li>sourceType=SAVEDPHOTOALBUM<br>mediaType=VIDEO<br>Should only be able to select a video</li>' +
428            '</p><li>sourceType=SAVEDPHOTOALBUM<br>mediaType=PICTURE<br>allowEdit=false<br>Should only be able to select a picture and not edit</li>' +
429            '</p><li>sourceType=PHOTOLIBRARY<br>mediaType=ALLMEDIA<br>allowEdit=true<br>Should be able to select pics and videos and edit picture if selected</li>' +
430            '</p><li>sourceType=CAMERA<br>targetWidth & targetHeight=50<br>allowEdit=false<br>Do Get File Metadata test below and take note of size<br>Repeat test but with width and height=800. Size should be significantly larger.</li>' +
431            '</p><li>quality=0<br>targetWidth & targetHeight=default<br>allowEdit=false<br>Do Get File Metadata test below and take note of size<br>Repeat test but with quality=80. Size should be significantly larger.</li>' +
432            '</ol></div>',
433        inputs_div = '<h2>Native File Inputs</h2>' +
434            'For the following tests, status box should update with file selected' +
435            '</p><div>input type=file <input type="file" class="testInputTag"></div>' +
436            '<div>capture=camera <input type="file" accept="image/*;capture=camera" class="testInputTag"></div>' +
437            '<div>capture=camcorder <input type="file" accept="video/*;capture=camcorder" class="testInputTag"></div>' +
438            '<div>capture=microphone <input type="file" accept="audio/*;capture=microphone" class="testInputTag"></div>',
439        actions_div = '<h2>Actions</h2>' +
440            'For the following tests, ensure that an image is set in status box' +
441            '</p><div id="metadata"></div>' +
442            'Expected result: Get metadata about file selected.<br>Status box will show, along with the metadata, "Call to FileEntry.getMetadata success, Call to FileEntry.setMetadata success, Call to FileEntry.getParent success"' +
443            '</p><div id="reader"></div>' +
444            'Expected result: Read contents of file.<br>Status box will show "Got file: {some metadata}, FileReader.readAsDataURL() - length = someNumber"' +
445            '</p><div id="copy"></div>' +
446            'Expected result: Copy image to new location and move file to different location.<br>Status box will show "Call to FileEntry.copyTo success:{some metadata}, Call to FileEntry.moveTo success:{some metadata}"' +
447            '</p><div id="write"></div>' +
448            'Expected result: Write image to library.<br>Status box will show "Call to FileWriter.write success:{some metadata}, Call to FileWriter.truncate success:{some metadata}"' +
449            '</p><div id="upload"></div>' +
450            'Expected result: Upload image to server.<br>Status box may print out progress. Once finished will show "upload complete"' +
451            '</p><div id="draw_canvas"></div>' +
452            'Expected result: Display image using canvas.<br>Image will be displayed in status box under "canvas:"' +
453            '</p><div id="remove"></div>' +
454            'Expected result: Remove image from library.<br>Status box will show "FileEntry.remove success:["OK"]';
455
456    // We need to wrap this code due to Windows security restrictions
457    // see http://msdn.microsoft.com/en-us/library/windows/apps/hh465380.aspx#differences for details
458    if (window.MSApp && window.MSApp.execUnsafeLocalFunction) {
459        MSApp.execUnsafeLocalFunction(function() {
460            contentEl.innerHTML = info_div + options_div + getpicture_div + test_procedure + inputs_div + actions_div;
461        });
462    } else {
463        contentEl.innerHTML = info_div + options_div + getpicture_div + test_procedure + inputs_div + actions_div;
464    }
465
466    var elements = document.getElementsByClassName("testInputTag");
467    var listener = function (e) {
468        testInputTag(e.target);
469    };
470    for (var i = 0; i < elements.length; ++i) {
471        var item = elements[i];
472        item.addEventListener("change", listener, false);
473    }
474
475    createActionButton('Get picture', function () {
476        getPicture();
477    }, 'getpicture');
478
479    createActionButton('Clear Status', function () {
480        clearStatus();
481    }, 'getpicture');
482
483    createActionButton('Get File Metadata', function () {
484        getFileInfo();
485    }, 'metadata');
486
487    createActionButton('Read with FileReader', function () {
488        readFile();
489    }, 'reader');
490
491    createActionButton('Copy Image', function () {
492        copyImage();
493    }, 'copy');
494
495    createActionButton('Write Image', function () {
496        writeImage();
497    }, 'write');
498
499    createActionButton('Upload Image', function () {
500        uploadImage();
501    }, 'upload');
502
503    createActionButton('Draw Using Canvas', function () {
504        displayImageUsingCanvas();
505    }, 'draw_canvas');
506
507    createActionButton('Remove Image', function () {
508        removeImage();
509    }, 'remove');
510};