Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
27
gaia/apps/gallery/test/build/integration/gallery_test.js
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
'use strict';
|
||||
|
||||
/* jshint node: true, mocha: true */
|
||||
/* global suiteSetup */
|
||||
|
||||
var helper = require('helper');
|
||||
|
||||
suite('Gallery tests', function() {
|
||||
suiteSetup(helper.cleanupWorkspace);
|
||||
teardown(helper.cleanupWorkspace);
|
||||
|
||||
test('APP=gallery make', function(done) {
|
||||
helper.exec('APP=gallery make', function(error, stdout, stderr) {
|
||||
helper.checkError(error, stdout, stderr);
|
||||
|
||||
var zipPath = process.cwd() +
|
||||
'/profile/webapps/gallery.gaiamobile.org/application.zip';
|
||||
var checkList = ['manifest.webapp'];
|
||||
|
||||
checkList.forEach(function(filePath) {
|
||||
helper.checkFilePathInZip(zipPath, filePath);
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
BIN
gaia/apps/gallery/test/images/01.jpg
Executable file
|
After Width: | Height: | Size: 37 KiB |
BIN
gaia/apps/gallery/test/images/02.png
Executable file
|
After Width: | Height: | Size: 19 KiB |
BIN
gaia/apps/gallery/test/images/03.gif
Executable file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
gaia/apps/gallery/test/images/04.bmp
Executable file
|
After Width: | Height: | Size: 234 KiB |
BIN
gaia/apps/gallery/test/images/05.jpg
Executable file
|
After Width: | Height: | Size: 39 KiB |
BIN
gaia/apps/gallery/test/images/06.png
Executable file
|
After Width: | Height: | Size: 36 KiB |
BIN
gaia/apps/gallery/test/images/07.gif
Executable file
|
After Width: | Height: | Size: 18 KiB |
BIN
gaia/apps/gallery/test/images/08.png
Executable file
|
After Width: | Height: | Size: 29 KiB |
BIN
gaia/apps/gallery/test/images/09.png
Executable file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
gaia/apps/gallery/test/images/10.png
Executable file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
gaia/apps/gallery/test/images/11.png
Executable file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
gaia/apps/gallery/test/images/12.png
Executable file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
gaia/apps/gallery/test/images/13.png
Executable file
|
After Width: | Height: | Size: 11 KiB |
BIN
gaia/apps/gallery/test/images/14.jpg
Executable file
|
After Width: | Height: | Size: 26 KiB |
BIN
gaia/apps/gallery/test/images/15.jpg
Executable file
|
After Width: | Height: | Size: 40 KiB |
BIN
gaia/apps/gallery/test/images/16.jpg
Executable file
|
After Width: | Height: | Size: 54 KiB |
BIN
gaia/apps/gallery/test/images/17.jpg
Executable file
|
After Width: | Height: | Size: 62 KiB |
BIN
gaia/apps/gallery/test/images/18.jpg
Executable file
|
After Width: | Height: | Size: 75 KiB |
BIN
gaia/apps/gallery/test/images/19.jpg
Executable file
|
After Width: | Height: | Size: 85 KiB |
BIN
gaia/apps/gallery/test/images/20.jpg
Executable file
|
After Width: | Height: | Size: 95 KiB |
BIN
gaia/apps/gallery/test/images/21.jpg
Executable file
|
After Width: | Height: | Size: 104 KiB |
BIN
gaia/apps/gallery/test/images/22.jpg
Executable file
|
After Width: | Height: | Size: 116 KiB |
BIN
gaia/apps/gallery/test/images/23.jpg
Executable file
|
After Width: | Height: | Size: 127 KiB |
BIN
gaia/apps/gallery/test/images/24.jpg
Executable file
|
After Width: | Height: | Size: 131 KiB |
BIN
gaia/apps/gallery/test/images/25.jpg
Executable file
|
After Width: | Height: | Size: 274 KiB |
BIN
gaia/apps/gallery/test/images/26.jpg
Executable file
|
After Width: | Height: | Size: 155 KiB |
BIN
gaia/apps/gallery/test/images/27.jpg
Executable file
|
After Width: | Height: | Size: 159 KiB |
BIN
gaia/apps/gallery/test/images/28.jpg
Executable file
|
After Width: | Height: | Size: 205 KiB |
BIN
gaia/apps/gallery/test/images/29.jpg
Executable file
|
After Width: | Height: | Size: 232 KiB |
BIN
gaia/apps/gallery/test/images/30.jpg
Executable file
|
After Width: | Height: | Size: 252 KiB |
BIN
gaia/apps/gallery/test/images/31.jpg
Executable file
|
After Width: | Height: | Size: 299 KiB |
BIN
gaia/apps/gallery/test/images/32.jpg
Executable file
|
After Width: | Height: | Size: 492 KiB |
BIN
gaia/apps/gallery/test/images/33.jpg
Executable file
|
After Width: | Height: | Size: 590 KiB |
BIN
gaia/apps/gallery/test/images/34.png
Executable file
|
After Width: | Height: | Size: 31 KiB |
BIN
gaia/apps/gallery/test/images/35.png
Executable file
|
After Width: | Height: | Size: 30 KiB |
BIN
gaia/apps/gallery/test/images/36.png
Executable file
|
After Width: | Height: | Size: 30 KiB |
BIN
gaia/apps/gallery/test/images/37.png
Executable file
|
After Width: | Height: | Size: 33 KiB |
BIN
gaia/apps/gallery/test/images/38.png
Executable file
|
After Width: | Height: | Size: 48 KiB |
BIN
gaia/apps/gallery/test/images/39.jpg
Executable file
|
After Width: | Height: | Size: 67 KiB |
BIN
gaia/apps/gallery/test/images/40.jpg
Executable file
|
After Width: | Height: | Size: 67 KiB |
BIN
gaia/apps/gallery/test/images/41.jpg
Executable file
|
After Width: | Height: | Size: 65 KiB |
BIN
gaia/apps/gallery/test/images/42.jpg
Executable file
|
After Width: | Height: | Size: 66 KiB |
BIN
gaia/apps/gallery/test/images/43.jpg
Executable file
|
After Width: | Height: | Size: 67 KiB |
BIN
gaia/apps/gallery/test/images/44.jpg
Executable file
|
After Width: | Height: | Size: 66 KiB |
BIN
gaia/apps/gallery/test/images/45.jpg
Executable file
|
After Width: | Height: | Size: 65 KiB |
BIN
gaia/apps/gallery/test/images/46.jpg
Executable file
|
After Width: | Height: | Size: 68 KiB |
BIN
gaia/apps/gallery/test/images/47.jpg
Executable file
|
After Width: | Height: | Size: 53 KiB |
BIN
gaia/apps/gallery/test/images/48.jpg
Executable file
|
After Width: | Height: | Size: 56 KiB |
BIN
gaia/apps/gallery/test/images/49.jpg
Executable file
|
After Width: | Height: | Size: 56 KiB |
BIN
gaia/apps/gallery/test/images/50.jpg
Executable file
|
After Width: | Height: | Size: 56 KiB |
BIN
gaia/apps/gallery/test/images/51.jpg
Executable file
|
After Width: | Height: | Size: 55 KiB |
BIN
gaia/apps/gallery/test/images/52.jpg
Executable file
|
After Width: | Height: | Size: 57 KiB |
BIN
gaia/apps/gallery/test/images/53.jpg
Executable file
|
After Width: | Height: | Size: 56 KiB |
BIN
gaia/apps/gallery/test/images/54.jpg
Executable file
|
After Width: | Height: | Size: 57 KiB |
BIN
gaia/apps/gallery/test/images/55.jpg
Executable file
|
After Width: | Height: | Size: 499 KiB |
BIN
gaia/apps/gallery/test/images/56.jpg
Executable file
|
After Width: | Height: | Size: 527 KiB |
BIN
gaia/apps/gallery/test/images/57.jpg
Executable file
|
After Width: | Height: | Size: 535 KiB |
BIN
gaia/apps/gallery/test/images/58.jpg
Executable file
|
After Width: | Height: | Size: 551 KiB |
BIN
gaia/apps/gallery/test/images/59.jpg
Executable file
|
After Width: | Height: | Size: 169 KiB |
BIN
gaia/apps/gallery/test/images/60.jpg
Executable file
|
After Width: | Height: | Size: 169 KiB |
BIN
gaia/apps/gallery/test/images/61.jpg
Executable file
|
After Width: | Height: | Size: 198 KiB |
BIN
gaia/apps/gallery/test/images/62.jpg
Executable file
|
After Width: | Height: | Size: 164 KiB |
BIN
gaia/apps/gallery/test/images/63.jpg
Executable file
|
After Width: | Height: | Size: 146 KiB |
BIN
gaia/apps/gallery/test/images/64.png
Executable file
|
After Width: | Height: | Size: 3.6 MiB |
BIN
gaia/apps/gallery/test/images/65.jpg
Executable file
|
After Width: | Height: | Size: 687 KiB |
BIN
gaia/apps/gallery/test/images/66.jpg
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
154
gaia/apps/gallery/test/images/README
Executable file
|
|
@ -0,0 +1,154 @@
|
|||
This directory contains images for testing the FirefoxOS Gallery app.
|
||||
|
||||
It also contains:
|
||||
|
||||
README: this file
|
||||
|
||||
creator.html: a simple web page that helps create test images
|
||||
|
||||
push.sh: A shell script for pushing the test images to your phone
|
||||
in the right order and with different timestamps so that they
|
||||
appear in numerical order when scanned by the Gallery app. This
|
||||
script assumes that the sdcard is at /storage/sdcard0. It works
|
||||
for the Flame device but may not work for others.
|
||||
|
||||
To test the Gallery app manually with these images, follow these steps:
|
||||
|
||||
1) Push the images to your phone by typing ./push.sh
|
||||
|
||||
2) Launch the gallery app.
|
||||
|
||||
3) Ensure that:
|
||||
|
||||
- the Gallery app scans for the test photos
|
||||
- the app does not crash with an OOM
|
||||
- the scanning process stops
|
||||
- after the scan, there should be 66 new images in Gallery.
|
||||
The first 63 and 66 display the numbers 1 to 63, 66 respectively and the
|
||||
64, 65 are test patterns. For some images, the image number is not visible
|
||||
in the thumbnail and you have to tap on the thumbnail to verify.
|
||||
- If any of the 66 images is missing, that is a bug
|
||||
- If additional images appear that may also be a bug
|
||||
|
||||
4) Hold the phone in portrait orientation. Tap on the first thumbnail,
|
||||
and swipe through the full set of images. Ensure that:
|
||||
|
||||
- There is no OOM while swiping
|
||||
- Images 39 to 58 are all displayed with their text right-side up
|
||||
- The images are all centered on the screen
|
||||
|
||||
5) Turn the phone to landscape mode and swipe back in the other
|
||||
direction to ensure that all of the images display correctly in this
|
||||
orientation as well
|
||||
|
||||
6) Now swipe again from image 14 through image 33. For each one,
|
||||
double-tap to zoom in and then swipe (or double tap to zoom back out
|
||||
and swipe). This should not cause an OOM even if you do it as quickly
|
||||
as you can.
|
||||
|
||||
7) Check a few special-case images:
|
||||
|
||||
- Image 6 has a transparent background, but it should be readable
|
||||
- Images 7 and 8 should be animated (but their thumbnails won't be)
|
||||
- Image 59 should change when you zoom in to it. (It has an EXIF
|
||||
preview that does not match the actual image, and we use it to test
|
||||
that the EXIF preview is used when available. It is a bug if this
|
||||
image does not change when you zoom in.)
|
||||
|
||||
|
||||
Here are some more details about what the various images are and what
|
||||
they are intended to test.
|
||||
|
||||
The first batch of images tests various image types to be sure we can
|
||||
display them.
|
||||
|
||||
01.jpg: jpeg image
|
||||
02.png: png image
|
||||
03.gif: gif image
|
||||
04.bmp: bmp image
|
||||
05.jpg: progressive jpeg
|
||||
06.png: png with transparent bg
|
||||
07.gif: animated gif
|
||||
08.png: animated png
|
||||
|
||||
Next, we test that we can display PNG images of various sizes
|
||||
|
||||
09.png: icon 128x128
|
||||
10.png: hvga 320x480
|
||||
11.png: wvga 480x768
|
||||
12.png: fwvga: 480x854
|
||||
13.png: dvga: 640x960
|
||||
|
||||
The next batch of images are jpegs with sizes between 1 megapixel and
|
||||
64 megapixels. Gallery should be able to scan, create thumbnails, and
|
||||
display all of these images without OOMs. Of course, it is not
|
||||
expected to display the big images at full resolution. It should be
|
||||
possible to double-tap to zoom in on all of these images without an OOM.
|
||||
|
||||
14.jpg - 27.jpg: 1 to 14 mp jpeg files
|
||||
28.jpg: 16mp
|
||||
29.jpg: 20mp
|
||||
30.jpg: 24mp
|
||||
31.jpg: 32mp
|
||||
32.jpg: 48mp
|
||||
33.jpg: 64mp
|
||||
|
||||
Now we test that images of various aspect ratios can be displayed correctly
|
||||
|
||||
34.png: large portrait mode png
|
||||
35.png: large landscape mode png
|
||||
36.png: large square
|
||||
37.png: wide
|
||||
38.png: tall
|
||||
|
||||
Next we test that we can handle EXIF orientation in JPEG images
|
||||
correctly. First there is a set of 8 images that should all be
|
||||
displayed in portrait mode. Then 8 that should all be displayed in
|
||||
landscape mode. Then four actual photos from the Tarako device that
|
||||
use EXIF orientation. In all 20 of these images, the text should be
|
||||
right side up and legible.
|
||||
|
||||
39-46.jpg: EXIF orientations 1-8, portrait
|
||||
47-54.jpg: EXIF orientations 1-8, landscape
|
||||
55-58.jpg: pictures from Tarako
|
||||
|
||||
Next is a series of JPEG images that test our use of EXIF preview
|
||||
images. Image 59 has a preview image that is different than the real
|
||||
image. You should see it change if you double-tap to zoom in. This
|
||||
tests that we are using previews when they are valid. The remaining
|
||||
four images have invalid or corrupt EXIF previews and should not
|
||||
display a preview.
|
||||
|
||||
59.jpg: image with valid exif preview that changes when zoomed
|
||||
60.jpg: exif preview is too small, should never see it (thumbnail only?)
|
||||
61.jpg: exif preview has wrong aspect ratio should never see it
|
||||
62.jpg: exif preview is corrupt should not crash or hang the scan
|
||||
63.jpg: exif preview is corrupt and has no metadata
|
||||
|
||||
We end with two test patterns. These might be useful for looking at
|
||||
the quality of our image downsampling.
|
||||
|
||||
64.png: test pattern
|
||||
65.jpg: test pattern
|
||||
66.jpg: JPEG image with size 90 x 40 smaller than thumbnail container
|
||||
|
||||
Finally, there is a set of images that should not display in the
|
||||
gallery app. These will be rejected during scanning, and error
|
||||
messages will be printed in the logcat. The first four images don't
|
||||
display because they are too large. If they appear, it probably means
|
||||
you're running a high-end device with a different maximum image size
|
||||
configuration. The other images are actually corrupt and can not
|
||||
display. They are here to ensure that the metadata scanner does not
|
||||
choke on them.
|
||||
|
||||
x01.png: png that is > 5mp
|
||||
x02.gif: gif that is > 5mp
|
||||
x03.jpg: pjpeg that is > 3.33mp
|
||||
x04.bmp: bmp that has file size > 500kb
|
||||
x05.png: a zero length file
|
||||
x06.jpg: a text file that has an image extension
|
||||
x07.jpg: a corrupt jpeg file (a zero byte change. gecko can't display it)
|
||||
x08.jpg: truncated jpeg
|
||||
x09.png: truncated png
|
||||
x10.gif: truncated gif
|
||||
x11.bmp: truncated bmp
|
||||
60
gaia/apps/gallery/test/images/creator.html
Executable file
|
|
@ -0,0 +1,60 @@
|
|||
<style>
|
||||
body, textarea {
|
||||
font-size: 24px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function create() {
|
||||
var text = document.getElementById('text').value;
|
||||
var lines = text.split('\n');
|
||||
var width = parseInt(document.getElementById('width').value);
|
||||
var height = parseInt(document.getElementById('height').value);
|
||||
var background = document.getElementById('background').value
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
var context = canvas.getContext('2d');
|
||||
var fontSize = Math.round(height / (lines.length * 2));
|
||||
context.font = fontSize + 'px sans-serif';
|
||||
|
||||
if (background) {
|
||||
context.fillStyle = background;
|
||||
context.fillRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
context.fillStyle = '#000';
|
||||
// context.strokeStyle = '#fff';
|
||||
context.lineWidth = 2;
|
||||
|
||||
for(var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i];
|
||||
var lineWidth = context.measureText(line).width;
|
||||
context.fillText(line,
|
||||
(width - lineWidth)/2,
|
||||
height * .33 + i * 1.1 * fontSize);
|
||||
|
||||
/*
|
||||
context.strokeText(line,
|
||||
(width - lineWidth)/2,
|
||||
height * .33 + i * 1.1 * fontSize);
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
canvas.toBlob(function(blob) {
|
||||
var url = URL.createObjectURL(blob);
|
||||
document.getElementById('output').src = url;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<br><textarea id="text" rows=4 cols=40></textarea>
|
||||
<br>width: <input id="width">
|
||||
<br>height: <input id="height">
|
||||
<br>background: <input id="background">
|
||||
<br><button onclick="create()">Create</button>
|
||||
<br><img id="output">
|
||||
|
||||
13
gaia/apps/gallery/test/images/push.sh
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
# push the images to the sdcard of the attached device.
|
||||
# push them in reverse numerical order and give them timestamps that
|
||||
# are one second apart, so that when Gallery lists them from newest to
|
||||
# oldest, we'll see image 01 first and image 65 last.
|
||||
(( t = `date +%s` ))
|
||||
for i in `ls ??.{jpg,png,gif,bmp} x??.{jpg,png,gif,bmp} | sort -r`; do
|
||||
adb push $i /storage/sdcard0/TestImages/$i
|
||||
(( t += 1 ))
|
||||
adb shell touch -t $t /storage/sdcard0/TestImages/$i
|
||||
done
|
||||
|
||||
BIN
gaia/apps/gallery/test/images/x01.png
Executable file
|
After Width: | Height: | Size: 114 KiB |
BIN
gaia/apps/gallery/test/images/x02.gif
Executable file
|
After Width: | Height: | Size: 72 KiB |
BIN
gaia/apps/gallery/test/images/x03.jpg
Executable file
|
After Width: | Height: | Size: 201 KiB |
BIN
gaia/apps/gallery/test/images/x04.bmp
Executable file
|
After Width: | Height: | Size: 586 KiB |
0
gaia/apps/gallery/test/images/x05.png
Executable file
7
gaia/apps/gallery/test/images/x06.jpg
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
This is not actually a jpeg file
|
||||
It is just a text file that was
|
||||
saved with a .jpeg file extension.
|
||||
Oops!
|
||||
But we want to be sure that it
|
||||
just gets ignored and does not
|
||||
cause problems for the Gallery app.
|
||||
BIN
gaia/apps/gallery/test/images/x07.jpg
Executable file
|
After Width: | Height: | Size: 17 KiB |
BIN
gaia/apps/gallery/test/images/x08.jpg
Executable file
|
After Width: | Height: | Size: 204 B |
BIN
gaia/apps/gallery/test/images/x09.png
Executable file
|
After Width: | Height: | Size: 22 B |
1
gaia/apps/gallery/test/images/x10.gif
Executable file
|
|
@ -0,0 +1 @@
|
|||
GIF89a X
|
||||
|
After Width: | Height: | Size: 9 B |
BIN
gaia/apps/gallery/test/images/x11.bmp
Executable file
|
After Width: | Height: | Size: 42 B |
17
gaia/apps/gallery/test/marionette/.jshintrc
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../../../.jshintrc",
|
||||
"predef": [
|
||||
"suite",
|
||||
"test",
|
||||
"setup",
|
||||
"teardown",
|
||||
"suiteSetup",
|
||||
"suiteTeardown",
|
||||
"marionette",
|
||||
"marionetteScriptFinished",
|
||||
"require",
|
||||
"define",
|
||||
"requireApp",
|
||||
"sinon"
|
||||
]
|
||||
}
|
||||
204
gaia/apps/gallery/test/marionette/activity_test.js
Executable file
|
|
@ -0,0 +1,204 @@
|
|||
/* global require, marionette, setup, __dirname */
|
||||
'use strict';
|
||||
|
||||
var Gallery = require('./lib/gallery.js'),
|
||||
Fullscreen_View = require('./lib/fullscreen_view.js'),
|
||||
GalleryActivityTester = require('./lib/galleryactivitytester.js'),
|
||||
System = require('./lib/system.js'),
|
||||
assert = require('assert');
|
||||
|
||||
marionette('Gallery Activity Tests', function() {
|
||||
|
||||
var fullscreenView, client, apps = {};
|
||||
|
||||
apps[GalleryActivityTester.ORIGIN] =
|
||||
__dirname + '/apps/galleryactivitytester';
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
prefs: {
|
||||
'device.storage.enabled': true,
|
||||
'device.storage.testing': true,
|
||||
'device.storage.prompt.testing': true
|
||||
},
|
||||
apps: apps
|
||||
},
|
||||
desiredCapabilities: { raisesAccessibilityExceptions: false }
|
||||
});
|
||||
|
||||
var galleryApp, activityTesterApp, system;
|
||||
var imageInfo = {
|
||||
name: 'pictures/firefoxOS.png',
|
||||
type: 'image/png',
|
||||
size: '52458'
|
||||
};
|
||||
|
||||
setup(function() {
|
||||
// Remove all files in temp device storage.
|
||||
client.fileManager.removeAllFiles();
|
||||
// Add file into the pictures directory
|
||||
client.fileManager.add([
|
||||
{type: 'pictures',filePath: 'test_media/Pictures/firefoxOS.png'},
|
||||
{type: 'pictures',
|
||||
filePath: 'test_media/Pictures/firefoxOS.png',
|
||||
filename: 'firefoxOS_2.png'}
|
||||
]);
|
||||
galleryApp = new Gallery(client);
|
||||
fullscreenView = new Fullscreen_View(client);
|
||||
activityTesterApp = GalleryActivityTester.create(client);
|
||||
system = new System(client);
|
||||
});
|
||||
|
||||
test('pick and open image using gallery pick and open activity', function() {
|
||||
activityTesterApp.launch();
|
||||
// Initiate pick activity by clicking pick image button
|
||||
activityTesterApp.tapPickImageButton();
|
||||
|
||||
// Tap Gallery button from Systm app Action Menu
|
||||
system.menuOptionButton('Gallery').tap();
|
||||
|
||||
// We've switched to the system app, and we're calling
|
||||
// switchToApp that waits for gallery app and then switch to gallery app
|
||||
client.apps.switchToApp(Gallery.ORIGIN);
|
||||
|
||||
// Check number of images loaded in gallery App
|
||||
assert.ok(galleryApp.thumbnails.length == '2');
|
||||
// Get image name of first thumbnail
|
||||
var selectedImageName = galleryApp.getThumbnailFileName(0);
|
||||
// Select first image from thumbnail list in gallery app
|
||||
galleryApp.tapThumbnail(0);
|
||||
|
||||
client.waitFor(function(){
|
||||
return fullscreenView.editCropCanvas.displayed();
|
||||
});
|
||||
|
||||
fullscreenView.cropDoneButton.click();
|
||||
system.switchToApp(GalleryActivityTester.ORIGIN);
|
||||
|
||||
client.waitFor(function(){
|
||||
return activityTesterApp.pickedImageName.displayed();
|
||||
});
|
||||
|
||||
// Compare returned blob name, type and size with the
|
||||
// first image loaded in gallery app
|
||||
var pickedImageName = activityTesterApp.pickedImageName.text();
|
||||
assert.strictEqual(pickedImageName, selectedImageName);
|
||||
|
||||
var pickedImageType = activityTesterApp.pickedImageType.text();
|
||||
assert.strictEqual(pickedImageType, imageInfo.type);
|
||||
|
||||
var pickedImageSize = activityTesterApp.pickedImageSize.text();
|
||||
assert.strictEqual(pickedImageSize, imageInfo.size);
|
||||
|
||||
// Open the picked image using open activity
|
||||
// with allowSave option as true. Tap picked
|
||||
// image and invoke gallery open activity
|
||||
activityTesterApp.tapPickedImage();
|
||||
system.switchToApp(Gallery.ORIGIN);
|
||||
|
||||
// Check if the filename displayed in titlebar matches
|
||||
// data sent by the initiating app
|
||||
var title = fullscreenView.openActivityImageTitle.text();
|
||||
assert.strictEqual(title, 'firefoxOS.png');
|
||||
|
||||
// Check if save button is displayed
|
||||
client.helper.waitForElement(fullscreenView.openActivitySaveButton);
|
||||
assert.ok(fullscreenView.openActivitySaveButton.displayed());
|
||||
|
||||
client.waitFor(function(){
|
||||
return fullscreenView.openActivityImage.displayed();
|
||||
});
|
||||
|
||||
// Check if displayed image src is set with blob url
|
||||
assert.ok(fullscreenView.hasSrcImageBlobURL(Gallery.ORIGIN,
|
||||
fullscreenView.openActivityImage));
|
||||
});
|
||||
|
||||
test('FullScreenView > share image using share activity ', function() {
|
||||
galleryApp.launch();
|
||||
|
||||
// Check number of images loaded in gallery App
|
||||
assert.ok(galleryApp.thumbnails.length == '2');
|
||||
// Get image name of first thumbnail
|
||||
var selectedImageName = galleryApp.getThumbnailFileName(0);
|
||||
// Select first image from thumbnail list in gallery app
|
||||
galleryApp.tapThumbnail(0);
|
||||
fullscreenView.shareButton.tap();
|
||||
|
||||
system.menuOptionButton('Gallery Activity Tester').tap();
|
||||
system.switchToApp(GalleryActivityTester.ORIGIN);
|
||||
|
||||
client.waitFor(function(){
|
||||
return activityTesterApp.sharedImageName.displayed();
|
||||
});
|
||||
|
||||
// Compare shared blob name, type and size with the
|
||||
// first image loaded in gallery app
|
||||
var sharedImageName = activityTesterApp.sharedImageName.text();
|
||||
assert.strictEqual(sharedImageName, selectedImageName);
|
||||
|
||||
var sharedImageType = activityTesterApp.sharedImageType.text();
|
||||
assert.strictEqual(sharedImageType, imageInfo.type);
|
||||
|
||||
var sharedImageSize = activityTesterApp.sharedImageSize.text();
|
||||
assert.strictEqual(sharedImageSize, imageInfo.size);
|
||||
});
|
||||
|
||||
test('open memory backed blob using gallery open activity', function() {
|
||||
activityTesterApp.launch();
|
||||
// Initiate open activity by clicking open image button.
|
||||
// This will generate memory backed blob using canvas
|
||||
// and trigger open activity to view the blob
|
||||
activityTesterApp.tapOpenImageButton();
|
||||
|
||||
system.switchToApp(Gallery.ORIGIN);
|
||||
|
||||
// Check there is no filename in title bar
|
||||
var title = fullscreenView.openActivityImageTitle.text();
|
||||
assert.strictEqual(title, '');
|
||||
|
||||
// Check save button is not displayed
|
||||
assert.ok(!fullscreenView.openActivitySaveButton.displayed(),
|
||||
'Save button is not displayed');
|
||||
|
||||
client.waitFor(function(){
|
||||
return fullscreenView.openActivityImage.displayed();
|
||||
});
|
||||
|
||||
// Check if displayed image src is set with blob url
|
||||
assert.ok(fullscreenView.hasSrcImageBlobURL(Gallery.ORIGIN,
|
||||
fullscreenView.openActivityImage));
|
||||
});
|
||||
|
||||
test('SelectView > share image using share activity ', function() {
|
||||
galleryApp.launch();
|
||||
galleryApp.switchToSelectView();
|
||||
|
||||
// Check number of files that exist
|
||||
assert.ok(galleryApp.thumbnails.length == '2');
|
||||
galleryApp.tapThumbnail(0);
|
||||
// Get image name of selected thumbnail
|
||||
var selectedImageName = galleryApp.getThumbnailFileName(0);
|
||||
|
||||
galleryApp.thumbnailsShareButton.tap();
|
||||
system.menuOptionButton('Gallery Activity Tester').tap();
|
||||
system.switchToApp(GalleryActivityTester.ORIGIN);
|
||||
|
||||
// Check that image is shared and displayed in
|
||||
// Gallery Activity Tester App
|
||||
client.waitFor(function(){
|
||||
return activityTesterApp.sharedImage.displayed();
|
||||
});
|
||||
// Compare shared blob name, type and size with the
|
||||
// first image loaded in gallery app
|
||||
var sharedImageName = activityTesterApp.sharedImageName.text();
|
||||
assert.strictEqual(sharedImageName, selectedImageName);
|
||||
|
||||
var sharedImageType = activityTesterApp.sharedImageType.text();
|
||||
assert.strictEqual(sharedImageType, imageInfo.type);
|
||||
|
||||
var sharedImageSize = activityTesterApp.sharedImageSize.text();
|
||||
assert.strictEqual(sharedImageSize, imageInfo.size);
|
||||
});
|
||||
|
||||
});
|
||||
28
gaia/apps/gallery/test/marionette/apps/galleryactivitytester/index.html
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Gallery Activity Tester</title>
|
||||
<script defer src="/js/galleryactivitytester.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>Gallery Activity Tester</div>
|
||||
<button id="open-image">Generate Blob and Open Image</button>
|
||||
<button id="pick-image">Pick Image</button>
|
||||
<div id="pick-activity-data">
|
||||
<span class="name"></span>
|
||||
<span class="type"></span>
|
||||
<span class="size"></span>
|
||||
<img id="picked-image"></img>
|
||||
</div>
|
||||
|
||||
<div id="share-activity-data">
|
||||
<span class="name"></span>
|
||||
<span class="type"></span>
|
||||
<span class="size"></span>
|
||||
<img></img>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
/* global MozActivity */
|
||||
(function(window) {
|
||||
'use strict';
|
||||
|
||||
var image_blob;
|
||||
|
||||
function generateBlob(width, height, type) {
|
||||
var canvas = document.createElement('canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
context.fillStyle = 'orange';
|
||||
context.fillRect (0, 0, width, height);
|
||||
|
||||
return new Promise(function(resolve) {
|
||||
canvas.toBlob(function(blob) {
|
||||
canvas.width = canvas.height = 0;
|
||||
canvas = null;
|
||||
|
||||
resolve(blob);
|
||||
}, type);
|
||||
});
|
||||
}
|
||||
|
||||
function loadImageData(id, blob) {
|
||||
var imageUrl = window.URL.createObjectURL(blob);
|
||||
var img = document.querySelector(id + ' > img');
|
||||
img.src = imageUrl;
|
||||
|
||||
document.querySelector(id + ' > span.name').innerHTML = blob.name;
|
||||
document.querySelector(id + ' > span.type').innerHTML = blob.type;
|
||||
document.querySelector(id + ' > span.size').innerHTML = blob.size;
|
||||
}
|
||||
|
||||
window.addEventListener('load', function() {
|
||||
var pickImageButton = document.getElementById('pick-image');
|
||||
|
||||
pickImageButton.addEventListener('click', function() {
|
||||
var activity = new MozActivity({
|
||||
name: 'pick',
|
||||
data: {
|
||||
type: 'image/*',
|
||||
}
|
||||
});
|
||||
activity.onsuccess = function() {
|
||||
image_blob = activity.result.blob;
|
||||
// Populate test app elements with returned activity data
|
||||
loadImageData('#pick-activity-data', activity.result.blob);
|
||||
};
|
||||
activity.onerror = function() {
|
||||
console.warn('pick activity error:', activity.error.name);
|
||||
};
|
||||
});
|
||||
|
||||
var pickedImage = document.getElementById('picked-image');
|
||||
|
||||
// Add click event handler to received image to
|
||||
// trigger gallery app open activity
|
||||
pickedImage.addEventListener('click', function() {
|
||||
var activity = new MozActivity({
|
||||
name: 'open',
|
||||
data: {
|
||||
type: 'image/png',
|
||||
filename: 'pictures/firefoxOS.png',
|
||||
blob: image_blob,
|
||||
allowSave: true
|
||||
}
|
||||
});
|
||||
activity.onerror = function() {
|
||||
console.warn('open activity error:', activity.error.name);
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
var openImageButton = document.getElementById('open-image');
|
||||
|
||||
// Add click event handler to open image button to generate memory
|
||||
// backed blob and open it using gallery app open activity
|
||||
openImageButton.addEventListener('click', function() {
|
||||
generateBlob(100, 100, 'image/jpeg').then(function(blob) {
|
||||
var activity = new MozActivity({
|
||||
name: 'open',
|
||||
data: {
|
||||
type: blob.type,
|
||||
blob: blob
|
||||
}
|
||||
});
|
||||
activity.onerror = function() {
|
||||
console.warn('open activity error while opening memory backed blob:',
|
||||
activity.error.name);
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
window.navigator.mozSetMessageHandler('activity', function(activity) {
|
||||
// Populate test app elements with shared activity data
|
||||
loadImageData('#share-activity-data', activity.source.data.blobs[0]);
|
||||
});
|
||||
|
||||
})(window);
|
||||
20
gaia/apps/gallery/test/marionette/apps/galleryactivitytester/manifest.webapp
Executable file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "Gallery Activity Tester",
|
||||
"description": "Gallery Activity Tester app",
|
||||
"type": "privileged",
|
||||
"launch_path": "/index.html",
|
||||
"developer": {
|
||||
"name": "The Gaia Team",
|
||||
"url": "https://github.com/mozilla-b2g/gaia"
|
||||
},
|
||||
"activities": {
|
||||
"share": {
|
||||
"href": "/index.html#activity-share",
|
||||
"filters": {
|
||||
"type": ["image/*"]
|
||||
},
|
||||
"disposition": "window",
|
||||
"returnValue": true
|
||||
}
|
||||
}
|
||||
}
|
||||
137
gaia/apps/gallery/test/marionette/delete_image_test.js
Executable file
|
|
@ -0,0 +1,137 @@
|
|||
'use strict';
|
||||
|
||||
var Gallery = require('./lib/gallery.js'),
|
||||
assert = require('assert');
|
||||
|
||||
marionette('using the gallery menu', function() {
|
||||
|
||||
var app, client;
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
prefs: {
|
||||
'device.storage.enabled': true,
|
||||
'device.storage.testing': true,
|
||||
'device.storage.prompt.testing': true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
app = new Gallery(client);
|
||||
});
|
||||
|
||||
suite('Gallery app delete single image', function() {
|
||||
setup(function() {
|
||||
// Remove all files in temp device storage.
|
||||
client.fileManager.removeAllFiles();
|
||||
// Add file into the pictures directory
|
||||
client.fileManager.add([
|
||||
{type: 'pictures',filePath: 'apps/gallery/test/images/01.jpg'},
|
||||
{type: 'pictures',filePath: 'apps/gallery/test/images/02.png'},
|
||||
{type: 'pictures',filePath: 'apps/gallery/test/images/03.gif'}
|
||||
]);
|
||||
});
|
||||
|
||||
suite('Select and delete single image', function() {
|
||||
setup(function() {
|
||||
app.launch();
|
||||
});
|
||||
|
||||
test('should let you select images', function() {
|
||||
// Use the 'selection' button and select the test image.
|
||||
// Selected images should have an border/highlight.
|
||||
app.switchToSelectView();
|
||||
app.thumbnail.click();
|
||||
app.isThumbnailSelected(0);
|
||||
});
|
||||
|
||||
test('should let you delete single image', function() {
|
||||
app.switchToSelectView();
|
||||
app.thumbnail.click();
|
||||
|
||||
// Check number of selected images
|
||||
assert.ok(app.thumbnailsNumberSelected.text() == '1 selected');
|
||||
app.thumbnailsDeleteButton.click();
|
||||
app.confirmButton.click();
|
||||
|
||||
// Check select header text is reset to default text
|
||||
assert.ok(app.thumbnailsNumberSelected.text() == 'Select');
|
||||
// Check 2 files still exist
|
||||
assert.ok(app.thumbnails.length == '2');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('Gallery app delete multiple images', function() {
|
||||
setup(function() {
|
||||
// Remove all files in temp device storage.
|
||||
client.fileManager.removeAllFiles();
|
||||
// Add file into the pictures directory
|
||||
client.fileManager.add([
|
||||
{type: 'pictures',filePath: 'apps/gallery/test/images/01.jpg'},
|
||||
{type: 'pictures',filePath: 'apps/gallery/test/images/02.png'},
|
||||
{type: 'pictures',filePath: 'apps/gallery/test/images/03.gif'}
|
||||
]);
|
||||
});
|
||||
|
||||
suite('Select and delete multiple images', function() {
|
||||
setup(function() {
|
||||
app.launch();
|
||||
});
|
||||
|
||||
test('should let you select images', function() {
|
||||
// Use the 'selection' button and select the test images.
|
||||
// Selected images should have an border/highlight.
|
||||
app.switchToSelectView();
|
||||
app.tapThumbnail(0);
|
||||
app.tapThumbnail(1);
|
||||
app.tapThumbnail(2);
|
||||
|
||||
app.isThumbnailSelected(0);
|
||||
app.isThumbnailSelected(1);
|
||||
app.isThumbnailSelected(2);
|
||||
|
||||
assert.ok(app.thumbnailsNumberSelected.text() == '3 selected');
|
||||
|
||||
});
|
||||
|
||||
test('should let you cancel delete images', function() {
|
||||
// Use the 'selection' button and select the test images.
|
||||
// Selected images should have an border/highlight.
|
||||
app.switchToSelectView();
|
||||
app.tapThumbnail(0);
|
||||
app.tapThumbnail(1);
|
||||
app.tapThumbnail(2);
|
||||
// Check number of selected images
|
||||
assert.ok(app.thumbnailsNumberSelected.text() == '3 selected');
|
||||
app.thumbnailsDeleteButton.click();
|
||||
// Cancel delete of images
|
||||
app.confirmCancelButton.click();
|
||||
|
||||
// Check files still exist
|
||||
assert.ok(app.thumbnails.length == '3');
|
||||
assert.ok(app.thumbnailsNumberSelected.text() == '3 selected');
|
||||
});
|
||||
|
||||
test('should let you delete images', function() {
|
||||
// This test deletes the test image.
|
||||
app.switchToSelectView();
|
||||
app.tapThumbnail(0);
|
||||
app.tapThumbnail(1);
|
||||
app.tapThumbnail(2);
|
||||
|
||||
app.thumbnailsDeleteButton.click();
|
||||
app.confirmButton.click();
|
||||
|
||||
// Wait for the overlay with 'No photos or videos' message.
|
||||
var overlayView = app.overlayView;
|
||||
client.helper.waitForElement(overlayView);
|
||||
assert.ok(overlayView.displayed());
|
||||
|
||||
assert.ok(app.thumbnails.length == '0');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
124
gaia/apps/gallery/test/marionette/edit_image_test.js
Executable file
|
|
@ -0,0 +1,124 @@
|
|||
'use strict';
|
||||
|
||||
var Gallery = require('./lib/gallery.js'),
|
||||
Fullscreen_View = require('./lib/fullscreen_view.js'),
|
||||
Marionette = require('marionette-client'),
|
||||
assert = require('assert');
|
||||
|
||||
marionette('editing an image', function() {
|
||||
|
||||
var app, actions, fullscreen_view, client;
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
prefs: {
|
||||
'device.storage.enabled': true,
|
||||
'device.storage.testing': true,
|
||||
'device.storage.prompt.testing': true,
|
||||
'webgl.force-enabled': true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
// Remove all files in temp device storage.
|
||||
client.fileManager.removeAllFiles();
|
||||
// Add file into the pictures directory
|
||||
client.fileManager.add({
|
||||
type: 'pictures',
|
||||
filePath: 'test_media/Pictures/firefoxOS.png'
|
||||
});
|
||||
app = new Gallery(client);
|
||||
fullscreen_view = new Fullscreen_View(client);
|
||||
actions = new Marionette.Actions(client);
|
||||
app.launch();
|
||||
});
|
||||
|
||||
test('should have crop options', function() {
|
||||
app.tapFirstThumbnail();
|
||||
fullscreen_view.editButton.click();
|
||||
fullscreen_view.editCropButton.click();
|
||||
assert.ok(fullscreen_view.cropOptions.displayed());
|
||||
|
||||
});
|
||||
|
||||
test('should have exposure options', function() {
|
||||
app.tapFirstThumbnail();
|
||||
fullscreen_view.editButton.click();
|
||||
fullscreen_view.editExposureButton.click();
|
||||
assert.ok(fullscreen_view.exposureOptions.displayed());
|
||||
|
||||
});
|
||||
|
||||
test('should have effect options', function() {
|
||||
app.tapFirstThumbnail();
|
||||
fullscreen_view.editButton.click();
|
||||
fullscreen_view.editEffectButton.click();
|
||||
assert.ok(fullscreen_view.effectOptions.displayed());
|
||||
});
|
||||
|
||||
test('should change exposure', function() {
|
||||
// Changing the exposure of an image creates a new modified
|
||||
// version of original.
|
||||
app.tapFirstThumbnail();
|
||||
fullscreen_view.editButton.click();
|
||||
fullscreen_view.editExposureButton.click();
|
||||
|
||||
//Change Exposure and get the updated value
|
||||
actions.flick(fullscreen_view.exposureSlider, 0, 0, 50, 0).perform();
|
||||
var current = fullscreen_view.getExposureSliderPosition();
|
||||
assert.ok(
|
||||
current == 0.8125,
|
||||
'Exposure slider is at updated position'
|
||||
);
|
||||
});
|
||||
|
||||
test('should crop image', function() {
|
||||
// Croping an image creates a new modified version of original.
|
||||
app.tapFirstThumbnail();
|
||||
fullscreen_view.editButton.click();
|
||||
fullscreen_view.editCropButton.click();
|
||||
|
||||
//Choose crop aspect portrait crop option
|
||||
fullscreen_view.editCropAspectPortraitButton.click();
|
||||
fullscreen_view.applyEditToolOptions();
|
||||
|
||||
// Enter Crop edit tool to check selected crop option
|
||||
fullscreen_view.editCropButton.click();
|
||||
// Check crop aspect portrait is selected
|
||||
fullscreen_view.waitForCropAspectPortraitSelected();
|
||||
});
|
||||
|
||||
test('should apply effect', function() {
|
||||
app.tapFirstThumbnail();
|
||||
fullscreen_view.editButton.click();
|
||||
fullscreen_view.editEffectButton.click();
|
||||
|
||||
// Choose sepia effect edit option
|
||||
fullscreen_view.editEffectSepiaButton.click();
|
||||
fullscreen_view.applyEditToolOptions();
|
||||
|
||||
// Enter effect edit tool to check selected effect
|
||||
fullscreen_view.editEffectButton.click();
|
||||
// Check Sepia Effect is selected
|
||||
fullscreen_view.waitForSepiaEffectSelected();
|
||||
});
|
||||
|
||||
test('check default enhance', function() {
|
||||
app.tapFirstThumbnail();
|
||||
fullscreen_view.editButton.click();
|
||||
// Check auto enhance is turned off
|
||||
fullscreen_view.waitForAutoEnhanceButtonOff();
|
||||
});
|
||||
|
||||
test('Apply auto enhance and cancel to exit main edit screen', function() {
|
||||
app.tapFirstThumbnail();
|
||||
fullscreen_view.editButton.click();
|
||||
fullscreen_view.applyAutoEnhance();
|
||||
|
||||
// Click on cancel after applying auto enhance should take user
|
||||
// out of edit screen and display image in full screen view
|
||||
fullscreen_view.performEditHeaderCancelAction();
|
||||
assert.ok(fullscreen_view.displayed);
|
||||
});
|
||||
});
|
||||
45
gaia/apps/gallery/test/marionette/empty_image_test.js
Executable file
|
|
@ -0,0 +1,45 @@
|
|||
'use strict';
|
||||
|
||||
var Gallery = require('./lib/gallery.js'),
|
||||
assert = require('assert');
|
||||
|
||||
marionette('run gallery without any files', function() {
|
||||
|
||||
var app, client;
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
prefs: {
|
||||
'device.storage.enabled': true,
|
||||
'device.storage.testing': true,
|
||||
'device.storage.prompt.testing': true,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
// Remove all files in temp device storage.
|
||||
client.fileManager.removeAllFiles();
|
||||
|
||||
app = new Gallery(client);
|
||||
app.launch(true);
|
||||
});
|
||||
|
||||
test('should display empty media message', function() {
|
||||
|
||||
// Wait for the overlay with 'Use the Camera app to get started' message.
|
||||
var overlayView = app.overlayView;
|
||||
var overlayTitle = app.overlayTitle;
|
||||
var overlayText = app.overlayText;
|
||||
var cameraButton = app.cameraButton;
|
||||
client.helper.waitForElement(overlayView);
|
||||
assert.ok(overlayView.displayed());
|
||||
assert.ok(overlayTitle.displayed());
|
||||
assert.ok(overlayTitle.text() == 'No photos or videos');
|
||||
assert.ok(overlayText.displayed());
|
||||
assert.ok(overlayText.text() == 'Use the Camera app to get started.');
|
||||
assert.ok(cameraButton.displayed());
|
||||
assert.ok(cameraButton.text() == 'Go to Camera');
|
||||
});
|
||||
});
|
||||
|
||||
149
gaia/apps/gallery/test/marionette/fullscreen_image_test.js
Executable file
|
|
@ -0,0 +1,149 @@
|
|||
'use strict';
|
||||
|
||||
var Gallery = require('./lib/gallery.js'),
|
||||
Fullscreen_View = require('./lib/fullscreen_view.js'),
|
||||
Marionette = require('marionette-client'),
|
||||
assert = require('assert');
|
||||
|
||||
marionette('the gallery', function() {
|
||||
|
||||
var app, client, actions, fullscreen_view;
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
prefs: {
|
||||
'device.storage.enabled': true,
|
||||
'device.storage.testing': true,
|
||||
'device.storage.prompt.testing': true
|
||||
}
|
||||
},
|
||||
desiredCapabilities: { raisesAccessibilityExceptions: false }
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
// Remove all files in temp device storage.
|
||||
client.fileManager.removeAllFiles();
|
||||
// Add file into the pictures directory
|
||||
client.fileManager.add({
|
||||
type: 'pictures',
|
||||
filePath: 'test_media/Pictures/firefoxOS.png'
|
||||
});
|
||||
app = new Gallery(client);
|
||||
fullscreen_view = new Fullscreen_View(client);
|
||||
actions = new Marionette.Actions(client);
|
||||
app.launch();
|
||||
});
|
||||
|
||||
test('should only have one image present', function() {
|
||||
// There should only be a single test image in the gallery
|
||||
// after running the test suite setup.
|
||||
// This mainly tests if TestCommon runs smoothly.
|
||||
assert.strictEqual(app.thumbnails.length, 1);
|
||||
});
|
||||
|
||||
test('should display an image fullscreen and go back', function() {
|
||||
// You should be able to click on an image to view a fullscreen
|
||||
// preview and go back by pressing the 'back' button.
|
||||
app.tapFirstThumbnail();
|
||||
assert.ok(fullscreen_view.displayed);
|
||||
|
||||
fullscreen_view.fullscreenBackButton.click();
|
||||
assert.ok(app.thumbnailsView.displayed());
|
||||
});
|
||||
|
||||
test('should flick through images in fullscreen mode', function() {
|
||||
// Acquire a duplicate of an image by launching the editing
|
||||
// mode and saving it.
|
||||
app.tapFirstThumbnail();
|
||||
client.waitFor(function() {
|
||||
return fullscreen_view.displayed;
|
||||
});
|
||||
fullscreen_view.editButton.click();
|
||||
fullscreen_view.waitForImageEditor();
|
||||
fullscreen_view.waitForAutoEnhanceButtonOff();
|
||||
fullscreen_view.editEnhanceButton.click();
|
||||
fullscreen_view.waitForAutoEnhanceButtonOn();
|
||||
client.waitFor(function() {
|
||||
return fullscreen_view.editSaveButton.enabled();
|
||||
});
|
||||
fullscreen_view.editSaveButton.click();
|
||||
client.waitFor(function() {
|
||||
return app.thumbnails.length == 2;
|
||||
});
|
||||
assert.ok(fullscreen_view.displayed);
|
||||
|
||||
// go back to the thumbnail view, and click the first thumbnail
|
||||
fullscreen_view.fullscreenBackButton.click();
|
||||
client.waitFor(function() {
|
||||
return app.thumbnailsView.displayed();
|
||||
});
|
||||
app.tapFirstThumbnail();
|
||||
client.waitFor(function() {
|
||||
return fullscreen_view.displayed;
|
||||
});
|
||||
|
||||
// You should be able to swipe between the two in fullscreen mode.
|
||||
var translateX = fullscreen_view.getFrameTranslation(
|
||||
fullscreen_view.fullscreenFrame2);
|
||||
assert.strictEqual(translateX, 0);
|
||||
|
||||
var size = fullscreen_view.fullscreenView.size();
|
||||
var centerX = size.width / 2;
|
||||
var centerY = size.height / 2;
|
||||
|
||||
actions.flick(fullscreen_view.fullscreenFrame2, centerX + 100,
|
||||
centerY, centerX - 100, centerY).perform();
|
||||
|
||||
//Swiping centers the fullscreen view on the second frame.
|
||||
translateX = fullscreen_view.getFrameTranslation(
|
||||
fullscreen_view.fullscreenFrame3);
|
||||
assert.strictEqual(translateX, 0);
|
||||
});
|
||||
|
||||
test('Change orientation of displayed image in fullscreen', function() {
|
||||
app.tapFirstThumbnail();
|
||||
client.waitFor(function() {
|
||||
return fullscreen_view.displayed;
|
||||
});
|
||||
|
||||
var screen_width = fullscreen_view.screenWidth;
|
||||
var screen_height = fullscreen_view.screenHeight;
|
||||
|
||||
// Checks the image blob is currently being displayed
|
||||
assert.ok(fullscreen_view.hasSrcImageBlobURL(Gallery.ORIGIN,
|
||||
fullscreen_view.displayedImage));
|
||||
|
||||
// Check that there are 5 options displayed beneath the picture
|
||||
assert.equal(fullscreen_view.toolBarOptions.length, 5);
|
||||
|
||||
// Verify that the screen orientation is in portrait mode
|
||||
assert.equal(fullscreen_view.screenOrientation, 'portrait');
|
||||
assert.ok(fullscreen_view.fullScreenToolBar.displayed);
|
||||
assert.equal(fullscreen_view.toolBarWidth, screen_width);
|
||||
|
||||
// Change the screen orientation to landscape mode and verify that
|
||||
// the screen is in landscape mode
|
||||
fullscreen_view.changeOrientation('landscape');
|
||||
|
||||
// Wait for orientation changes to propagate
|
||||
client.helper.wait(300);
|
||||
assert.equal(fullscreen_view.screenOrientation, 'landscape');
|
||||
assert.ok(fullscreen_view.fullScreenToolBar.displayed);
|
||||
assert.equal(fullscreen_view.toolBarWidth, screen_height);
|
||||
|
||||
// Change the screen orientation back to portrait and verify the screen
|
||||
// is in portrait mode
|
||||
fullscreen_view.changeOrientation('portrait');
|
||||
|
||||
// Wait for orientation changes to propagate
|
||||
client.helper.wait(300);
|
||||
assert.equal(fullscreen_view.screenOrientation, 'portrait');
|
||||
assert.ok(fullscreen_view.fullScreenToolBar.displayed);
|
||||
assert.equal(fullscreen_view.toolBarWidth, screen_width);
|
||||
|
||||
// Unlock the screen before exiting test
|
||||
client.executeScript(function () {
|
||||
window.wrappedJSObject.screen.mozUnlockOrientation();
|
||||
});
|
||||
});
|
||||
});
|
||||
441
gaia/apps/gallery/test/marionette/lib/fullscreen_view.js
Executable file
|
|
@ -0,0 +1,441 @@
|
|||
/* global module */
|
||||
(function(module) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {Marionette.Client} client Marionette client to use.
|
||||
*/
|
||||
function Fullscreen_View(client) {
|
||||
this.client = client.scope({
|
||||
searchTimeout: 20000
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = Fullscreen_View;
|
||||
|
||||
/**
|
||||
* @const {Object}
|
||||
*/
|
||||
Fullscreen_View.Selector = Object.freeze({
|
||||
currentImage: '#frames .current > .image-view',
|
||||
fullscreenView: '#fullscreen-view',
|
||||
fullscreenBackButton: '#fullscreen-back-button-tiny',
|
||||
editButton: '#fullscreen-edit-button-tiny',
|
||||
shareButton: '#fullscreen-share-button-tiny',
|
||||
editView: '#edit-view',
|
||||
editExposureButton: '#edit-exposure-button',
|
||||
editCropButton: '#edit-crop-button',
|
||||
editEffectButton: '#edit-effect-button',
|
||||
editEnhanceButton: '#edit-enhance-button',
|
||||
exposureOptions: '#exposure-slider',
|
||||
cropOptions: '#edit-crop-options',
|
||||
effectOptions: '#edit-effect-options',
|
||||
exposureSlider: '#sliderthumb',
|
||||
editCropAspectPortraitButton: '#edit-crop-aspect-portrait',
|
||||
editEffectSepiaButton: '#edit-effect-sepia',
|
||||
editSaveButton: '#edit-save-button',
|
||||
editToolApplyButton: '#edit-tool-apply-button',
|
||||
editHeader: '#edit-view gaia-header',
|
||||
fullscreenFrame2: '#frame2',
|
||||
fullscreenFrame3: '#frame3',
|
||||
cropDoneButton: '#crop-done-button',
|
||||
editCropCanvas: '#edit-crop-canvas',
|
||||
openTitle: '#filename',
|
||||
openImage: '#frame > .image-view',
|
||||
openSaveButton: '#save',
|
||||
fullScreenToolBar: '#fullscreen-toolbar',
|
||||
fullScreenToolBarOptions: '#fullscreen-toolbar > a',
|
||||
|
||||
});
|
||||
|
||||
Fullscreen_View.prototype = {
|
||||
|
||||
client: null,
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Currently displayed image element.
|
||||
*/
|
||||
get displayedImage() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.currentImage);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {numeric} Currently displayed image width.
|
||||
*/
|
||||
get width() {
|
||||
return this.displayedImage.size().width;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {numeric} Currently displayed image height.
|
||||
*/
|
||||
get height() {
|
||||
return this.displayedImage.size().height;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Container for fullscreen view of an image.
|
||||
*/
|
||||
get fullscreenView() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.fullscreenView);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {boolean} display status of Fullscreen View.
|
||||
*/
|
||||
get displayed() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.fullscreenView).displayed();
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to click to get back
|
||||
* to thumbnail view.
|
||||
*/
|
||||
get fullscreenBackButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.fullscreenBackButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to click for image editing mode.
|
||||
*/
|
||||
get editButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.editButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to click for effects editing mode.
|
||||
*/
|
||||
get editEffectButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.editEffectButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to click for the auto-enhance
|
||||
* editing mode.
|
||||
*/
|
||||
get editEnhanceButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.editEnhanceButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to click for the exposure editing
|
||||
* mode.
|
||||
*/
|
||||
get editExposureButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.editExposureButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to click for crop editing mode.
|
||||
*/
|
||||
get editCropButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.editCropButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Container to host the exposure options.
|
||||
*/
|
||||
get exposureOptions() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.exposureOptions);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Container to host the crop options.
|
||||
*/
|
||||
get cropOptions() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.cropOptions);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Container to host the effect options.
|
||||
*/
|
||||
get effectOptions() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.effectOptions);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Container to host the enhance options.
|
||||
*/
|
||||
get enhanceOptions() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.enhanceOptions);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element}
|
||||
* Element to swipe to change exposure settings.
|
||||
*/
|
||||
get exposureSlider() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.exposureSlider);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element}
|
||||
* Element to click to save changes from editing.
|
||||
*/
|
||||
get editSaveButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.editSaveButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to apply edits in edit tool.
|
||||
*/
|
||||
get editToolApplyButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.editToolApplyButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to click to crop an image.
|
||||
*/
|
||||
get editCropAspectPortraitButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.editCropAspectPortraitButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to click to apply a sepia affect.
|
||||
*/
|
||||
get editEffectSepiaButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.editEffectSepiaButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Container element to host fullscreen images.
|
||||
*/
|
||||
get fullscreenFrame2() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.fullscreenFrame2);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Container element to host fullscreen images.
|
||||
*/
|
||||
get fullscreenFrame3() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.fullscreenFrame3);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Done Button to finish crop and pick image.
|
||||
*/
|
||||
get cropDoneButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.cropDoneButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} edit crop canvas showing crop overlay.
|
||||
*/
|
||||
get editCropCanvas() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.editCropCanvas);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to click for sharing image.
|
||||
*/
|
||||
get shareButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.shareButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element containing fullScreenView toolbar
|
||||
*/
|
||||
get fullScreenToolBar() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.fullScreenToolBar);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {numeric} fullScreenToolBar width.
|
||||
*/
|
||||
get toolBarWidth() {
|
||||
return this.fullScreenToolBar.size().width;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} List of elements of toolbar options.
|
||||
*/
|
||||
get toolBarOptions() {
|
||||
this.waitFor(Fullscreen_View.Selector.fullScreenToolBarOptions);
|
||||
return this.client.findElements(
|
||||
Fullscreen_View.Selector.fullScreenToolBarOptions);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {String} screen orientation
|
||||
*/
|
||||
get screenOrientation() {
|
||||
var orientation = this.client.executeScript(function () {
|
||||
return window.wrappedJSObject.screen.mozOrientation;
|
||||
});
|
||||
return orientation;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {numeric} screen width
|
||||
*/
|
||||
get screenWidth() {
|
||||
var width = this.client.executeScript(function () {
|
||||
return window.wrappedJSObject.screen.width;
|
||||
});
|
||||
return width;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {numeric} screen height
|
||||
*/
|
||||
get screenHeight() {
|
||||
var height = this.client.executeScript(function () {
|
||||
return window.wrappedJSObject.screen.height;
|
||||
});
|
||||
return height;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} element to display image opened using
|
||||
* gallery app open activity.
|
||||
*/
|
||||
get openActivityImage() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.openImage);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} header element
|
||||
* showing file name opened using gallery app open activity.
|
||||
*/
|
||||
get openActivityImageTitle() {
|
||||
return this.client.helper.waitForElement(
|
||||
Fullscreen_View.Selector.openTitle);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} save button that saves image opened using
|
||||
* gallery app open activity.
|
||||
*/
|
||||
get openActivitySaveButton() {
|
||||
return this.client.findElement(Fullscreen_View.Selector.openSaveButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* Check referenced image src
|
||||
* is set with the URL provided
|
||||
*/
|
||||
hasSrcImageBlobURL: function(appURL, image) {
|
||||
var url = 'blob:' + appURL;
|
||||
return image.getAttribute('src').indexOf(url) > -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Read the translateX style and return its integer value.
|
||||
*/
|
||||
getFrameTranslation: function(frame) {
|
||||
var style = frame.getAttribute('style');
|
||||
return parseInt(style.match(/.*:\s.*\((\d*).*/)[1]);
|
||||
},
|
||||
|
||||
waitFor: function(selector) {
|
||||
return this.client.helper.waitForElement(selector);
|
||||
},
|
||||
|
||||
/**
|
||||
* Wait for the image editor view to render before continuing with the tests.
|
||||
*/
|
||||
waitForImageEditor: function() {
|
||||
this.waitFor(Fullscreen_View.Selector.editCropButton);
|
||||
this.waitFor(Fullscreen_View.Selector.editEffectButton);
|
||||
this.waitFor(Fullscreen_View.Selector.editExposureButton);
|
||||
this.waitFor(Fullscreen_View.Selector.editEnhanceButton);
|
||||
},
|
||||
|
||||
getExposureSliderPosition: function() {
|
||||
return this.exposureSlider.text();
|
||||
},
|
||||
|
||||
applyEditToolOptions: function() {
|
||||
this.editToolApplyButton.click();
|
||||
},
|
||||
|
||||
saveEditedImage: function() {
|
||||
this.editSaveButton.click();
|
||||
},
|
||||
|
||||
performEditHeaderCancelAction: function() {
|
||||
this.waitFor(Fullscreen_View.Selector.editHeader).scriptWith(
|
||||
function(header) {
|
||||
var event = document.createEvent('HTMLEvents');
|
||||
event.initEvent('action', true, true);
|
||||
header.dispatchEvent(event);
|
||||
});
|
||||
},
|
||||
|
||||
performEditEnhanceButtonClick: function() {
|
||||
this.waitFor(Fullscreen_View.Selector.editEnhanceButton).scriptWith(
|
||||
function(button) {
|
||||
var event = document.createEvent('HTMLEvents');
|
||||
event.initEvent('click', true, true);
|
||||
button.dispatchEvent(event);
|
||||
});
|
||||
},
|
||||
|
||||
applyAutoEnhance: function() {
|
||||
this.client.waitFor(function() {
|
||||
return this.editEnhanceButton.enabled();
|
||||
}.bind(this));
|
||||
this.performEditEnhanceButtonClick();
|
||||
},
|
||||
|
||||
waitForCropAspectPortraitSelected: function() {
|
||||
this.client.waitFor(function() {
|
||||
return this.editCropAspectPortraitButton
|
||||
.getAttribute('class').indexOf('selected') > -1;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
waitForSepiaEffectSelected: function() {
|
||||
this.client.waitFor(function() {
|
||||
return this.editEffectSepiaButton
|
||||
.getAttribute('class').indexOf('selected') > -1;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
waitForAutoEnhanceButtonOn: function() {
|
||||
this.client.waitFor(function() {
|
||||
return this.editEnhanceButton
|
||||
.getAttribute('class').split(' ').indexOf('on') > -1;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
waitForAutoEnhanceButtonOff: function() {
|
||||
this.client.waitFor(function() {
|
||||
return this.editEnhanceButton
|
||||
.getAttribute('class').split(' ').indexOf('on') < 0;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
changeOrientation: function(orientation) {
|
||||
this.client.executeScript(function(orientation) {
|
||||
window.wrappedJSObject.screen.mozLockOrientation(orientation);
|
||||
}, [orientation]);
|
||||
}
|
||||
};
|
||||
})(module);
|
||||
202
gaia/apps/gallery/test/marionette/lib/gallery.js
Executable file
|
|
@ -0,0 +1,202 @@
|
|||
'use strict';
|
||||
/* jshint node:true */
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {Marionette.Client} client Marionette client to use.
|
||||
*/
|
||||
function Gallery(client) {
|
||||
this.client = client.scope({
|
||||
searchTimeout: 20000
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = Gallery;
|
||||
|
||||
/**
|
||||
* @const {string}
|
||||
*/
|
||||
Gallery.ORIGIN = 'app://gallery.gaiamobile.org';
|
||||
|
||||
/**
|
||||
* @const {Object}
|
||||
*/
|
||||
Gallery.Selector = Object.freeze({
|
||||
thumbnail: '.thumbnail',
|
||||
thumbnailImage: '.thumbnailImage',
|
||||
thumbnailsView: '#thumbnail-views > footer.thumbnails-list',
|
||||
thumbnailsSelectButton: '#thumbnails-select-button',
|
||||
thumbnailsDeleteButton: '#thumbnails-delete-button',
|
||||
thumbnailsShareButton: '#thumbnails-share-button',
|
||||
confirmButton: '#confirm-ok',
|
||||
confirmCancelButton: '#confirm-cancel',
|
||||
overlayView: '#overlay',
|
||||
overlayTitle: '#overlay-title',
|
||||
overlayText: '#overlay-text',
|
||||
overlayCameraButton: '#overlay-camera-button',
|
||||
thumbnailsNumberSelected: '#thumbnails-number-selected'
|
||||
});
|
||||
|
||||
Gallery.prototype = {
|
||||
/**
|
||||
* Marionette client to use.
|
||||
* @type {Marionette.Client}
|
||||
*/
|
||||
client: null,
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} First thumbnail containing element
|
||||
*/
|
||||
get thumbnail() {
|
||||
return this.client.helper.waitForElement(Gallery.Selector.thumbnail);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} List of thumbnail containing elements
|
||||
*/
|
||||
get thumbnails() {
|
||||
return this.client.findElements(Gallery.Selector.thumbnail);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} List of thumbnail images
|
||||
*/
|
||||
get thumbnailsImage() {
|
||||
return this.client.findElements(Gallery.Selector.thumbnailImage);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Container for thumbnails list view.
|
||||
*/
|
||||
get thumbnailsView() {
|
||||
return this.client.helper.waitForElement(Gallery.Selector.thumbnailsView);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {boolean} thumbnails view display status.
|
||||
*/
|
||||
get thumbnailsViewDisplayed() {
|
||||
return this.client.helper.waitForElement(
|
||||
Gallery.Selector.thumbnailsView).displayed();
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Container for different overlay messages.
|
||||
*/
|
||||
get overlayView() {
|
||||
return this.client.helper.waitForElement(Gallery.Selector.overlayView);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Container for overlay message title.
|
||||
*/
|
||||
get overlayTitle() {
|
||||
return this.client.helper.waitForElement(Gallery.Selector.overlayTitle);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Container for overlay message content.
|
||||
*/
|
||||
get overlayText() {
|
||||
return this.client.helper.waitForElement(Gallery.Selector.overlayText);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Container for the camera button
|
||||
* when no media is found.
|
||||
*/
|
||||
get cameraButton() {
|
||||
return this.client.helper.waitForElement(Gallery.Selector.
|
||||
overlayCameraButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to click to select thumbnails.
|
||||
*/
|
||||
get thumbnailsSelectButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Gallery.Selector.thumbnailsSelectButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to click to delete images.
|
||||
*/
|
||||
get thumbnailsDeleteButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Gallery.Selector.thumbnailsDeleteButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to click to share multiple images.
|
||||
*/
|
||||
get thumbnailsShareButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Gallery.Selector.thumbnailsShareButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to click to confirm the delete dialog.
|
||||
*/
|
||||
get confirmButton() {
|
||||
return this.client.helper.waitForElement(Gallery.Selector.confirmButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to click to cancel the delete dialog.
|
||||
*/
|
||||
get confirmCancelButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
Gallery.Selector.confirmCancelButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} Element to display number of selected items
|
||||
*/
|
||||
get thumbnailsNumberSelected() {
|
||||
return this.client.helper.waitForElement(
|
||||
Gallery.Selector.thumbnailsNumberSelected);
|
||||
},
|
||||
|
||||
switchToSelectView: function() {
|
||||
this.thumbnailsSelectButton.click();
|
||||
this.client.waitFor(function() {
|
||||
return this.thumbnailsNumberSelected.displayed();
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
tapFirstThumbnail: function() {
|
||||
this.thumbnail.click();
|
||||
},
|
||||
|
||||
tapThumbnail: function(n) {
|
||||
this.thumbnails[n].click();
|
||||
},
|
||||
|
||||
isThumbnailSelected: function(n) {
|
||||
this.client.waitFor(function() {
|
||||
return this.thumbnails[n].cssProperty('outline') != null;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
getThumbnailFileName: function(n) {
|
||||
return this.thumbnailsImage[n].getAttribute('data-filename');
|
||||
},
|
||||
|
||||
/**
|
||||
* Start the Gallery, save the client for future ops, and wait for the
|
||||
* Gallery to finish an initial render.
|
||||
*/
|
||||
launch: function(nomedia) {
|
||||
this.client.apps.launch(Gallery.ORIGIN);
|
||||
this.client.apps.switchToApp(Gallery.ORIGIN);
|
||||
// Wait for the document body to know we're really 'launched'.
|
||||
this.client.helper.waitForElement('body');
|
||||
// Make sure the gallery is done scanning for new content.
|
||||
this.client.setSearchTimeout(1000);
|
||||
|
||||
// Check for thumbnail when loaded with images
|
||||
if (!nomedia) {
|
||||
this.client.helper.waitForElement(Gallery.Selector.thumbnail);
|
||||
}
|
||||
}
|
||||
};
|
||||
77
gaia/apps/gallery/test/marionette/lib/galleryactivitytester.js
Executable file
|
|
@ -0,0 +1,77 @@
|
|||
/* global module */
|
||||
(function(module) {
|
||||
'use strict';
|
||||
|
||||
var SELECTORS = Object.freeze({
|
||||
pickImageButton: '#pick-image',
|
||||
openImageButton: '#open-image',
|
||||
pickedImage: '#pick-activity-data > img',
|
||||
pickedImageName: '#pick-activity-data > span.name',
|
||||
pickedImageType: '#pick-activity-data > span.type',
|
||||
pickedImageSize: '#pick-activity-data > span.size',
|
||||
sharedImage: '#share-activity-data > img',
|
||||
sharedImageName: '#share-activity-data > span.name',
|
||||
sharedImageType: '#share-activity-data > span.type',
|
||||
sharedImageSize: '#share-activity-data > span.size'
|
||||
});
|
||||
|
||||
var ORIGIN = 'app://gallery.activitytester.gaiamobile.org';
|
||||
|
||||
module.exports = {
|
||||
ORIGIN: ORIGIN,
|
||||
|
||||
create: function(client) {
|
||||
return {
|
||||
get pickedImage() {
|
||||
return client.helper.waitForElement(SELECTORS.pickedImage);
|
||||
},
|
||||
|
||||
get pickedImageName() {
|
||||
return client.helper.waitForElement(SELECTORS.pickedImageName);
|
||||
},
|
||||
|
||||
get pickedImageType() {
|
||||
return client.helper.waitForElement(SELECTORS.pickedImageType);
|
||||
},
|
||||
|
||||
get pickedImageSize() {
|
||||
return client.helper.waitForElement(SELECTORS.pickedImageSize);
|
||||
},
|
||||
|
||||
get sharedImage() {
|
||||
return client.helper.waitForElement(SELECTORS.sharedImage);
|
||||
},
|
||||
|
||||
get sharedImageName() {
|
||||
return client.helper.waitForElement(SELECTORS.sharedImageName);
|
||||
},
|
||||
|
||||
get sharedImageType() {
|
||||
return client.helper.waitForElement(SELECTORS.sharedImageType);
|
||||
},
|
||||
|
||||
get sharedImageSize() {
|
||||
return client.helper.waitForElement(SELECTORS.sharedImageSize);
|
||||
},
|
||||
|
||||
launch: function() {
|
||||
client.switchToFrame();
|
||||
client.apps.launch(ORIGIN);
|
||||
client.apps.switchToApp(ORIGIN);
|
||||
},
|
||||
|
||||
tapPickImageButton: function() {
|
||||
client.helper.waitForElement(SELECTORS.pickImageButton).tap();
|
||||
},
|
||||
|
||||
tapOpenImageButton: function() {
|
||||
client.helper.waitForElement(SELECTORS.openImageButton).tap();
|
||||
},
|
||||
|
||||
tapPickedImage: function() {
|
||||
client.helper.waitForElement(SELECTORS.pickedImage).tap();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
})(module);
|
||||
49
gaia/apps/gallery/test/marionette/lib/system.js
Executable file
|
|
@ -0,0 +1,49 @@
|
|||
/* global module */
|
||||
'use strict';
|
||||
|
||||
function System(client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
module.exports = System;
|
||||
|
||||
System.Selector = Object.freeze({
|
||||
actionMenu: 'form[data-z-index-level="action-menu"]',
|
||||
button: 'form[data-z-index-level="action-menu"] > menu > button'
|
||||
});
|
||||
|
||||
System.prototype = {
|
||||
client: null,
|
||||
|
||||
get actionMenu() {
|
||||
// Switch to the system app first.
|
||||
this.client.switchToFrame();
|
||||
this.waitForOptionsToDisplay();
|
||||
return this.client.findElement(System.Selector.actionMenu);
|
||||
},
|
||||
|
||||
switchToApp: function(appOrigin) {
|
||||
this.client.switchToFrame();
|
||||
this.client.apps.switchToApp(appOrigin);
|
||||
},
|
||||
|
||||
waitForOptionsToDisplay: function() {
|
||||
this.client.waitFor(function() {
|
||||
return this.client.helper.waitForElement(
|
||||
System.Selector.button).displayed();
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Marionette.Element} menu option that has same text as appName.
|
||||
*/
|
||||
menuOptionButton: function(appName) {
|
||||
var options = this.actionMenu.findElements(System.Selector.button);
|
||||
for (var i = 0; i < options.length; i++) {
|
||||
var menuOption = options[i];
|
||||
if (menuOption.text() === appName) {
|
||||
return menuOption;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
58
gaia/apps/gallery/test/marionette/load_invalid_image_test.js
Executable file
|
|
@ -0,0 +1,58 @@
|
|||
'use strict';
|
||||
|
||||
var Gallery = require('./lib/gallery.js'),
|
||||
assert = require('assert');
|
||||
|
||||
marionette('loading images', function() {
|
||||
|
||||
var app, client;
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
prefs: {
|
||||
'device.storage.enabled': true,
|
||||
'device.storage.testing': true,
|
||||
'device.storage.prompt.testing': true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
// Remove all files in temp device storage.
|
||||
client.fileManager.removeAllFiles();
|
||||
// Add invalid files into the pictures directory
|
||||
client.fileManager.add([
|
||||
{type: 'pictures', filePath: 'apps/gallery/test/images/x01.png'},
|
||||
{type: 'pictures', filePath: 'apps/gallery/test/images/x02.gif'},
|
||||
{type: 'pictures', filePath: 'apps/gallery/test/images/x03.jpg'},
|
||||
{type: 'pictures', filePath: 'apps/gallery/test/images/x05.png'},
|
||||
{type: 'pictures', filePath: 'apps/gallery/test/images/x06.jpg'},
|
||||
{type: 'pictures', filePath: 'apps/gallery/test/images/x08.jpg'},
|
||||
{type: 'pictures', filePath: 'apps/gallery/test/images/x09.png'},
|
||||
{type: 'pictures', filePath: 'apps/gallery/test/images/x10.gif'},
|
||||
{type: 'pictures', filePath: 'apps/gallery/test/images/x11.bmp'}
|
||||
]);
|
||||
app = new Gallery(client);
|
||||
app.launch(true);
|
||||
});
|
||||
|
||||
test('check invalid images are not shown in thumbnail view', function() {
|
||||
assert.strictEqual(app.thumbnails.length, 0);
|
||||
|
||||
var overlayView = app.overlayView;
|
||||
client.helper.waitForElement(overlayView);
|
||||
assert.ok(overlayView.displayed());
|
||||
|
||||
var overlayTitle = app.overlayTitle;
|
||||
assert.ok(overlayTitle.displayed());
|
||||
assert.ok(overlayTitle.text() == 'No photos or videos');
|
||||
|
||||
var overlayText = app.overlayText;
|
||||
assert.ok(overlayText.displayed());
|
||||
assert.ok(overlayText.text() == 'Use the Camera app to get started.');
|
||||
|
||||
var cameraButton = app.cameraButton;
|
||||
assert.ok(cameraButton.displayed());
|
||||
assert.ok(cameraButton.text() == 'Go to Camera');
|
||||
});
|
||||
});
|
||||
76
gaia/apps/gallery/test/marionette/load_valid_image_test.js
Executable file
|
|
@ -0,0 +1,76 @@
|
|||
'use strict';
|
||||
|
||||
var Gallery = require('./lib/gallery.js'),
|
||||
Fullscreen_View = require('./lib/fullscreen_view.js'),
|
||||
Marionette = require('marionette-client'),
|
||||
assert = require('assert');
|
||||
|
||||
marionette('loading images', function() {
|
||||
|
||||
var app, fullscreen_view, actions, client;
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
prefs: {
|
||||
'device.storage.enabled': true,
|
||||
'device.storage.testing': true,
|
||||
'device.storage.prompt.testing': true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
// Remove all files in temp device storage.
|
||||
client.fileManager.removeAllFiles();
|
||||
// Add file into the pictures directory
|
||||
client.fileManager.add([
|
||||
{type: 'pictures',filePath: 'apps/gallery/test/images/01.jpg'},
|
||||
{type: 'pictures',filePath: 'apps/gallery/test/images/02.png'},
|
||||
{type: 'pictures',filePath: 'apps/gallery/test/images/03.gif'},
|
||||
{type: 'pictures',filePath: 'apps/gallery/test/images/04.bmp'},
|
||||
// Progressive JPG
|
||||
{type: 'pictures',filePath: 'apps/gallery/test/images/05.jpg'},
|
||||
// Transparent background PNG
|
||||
{type: 'pictures',filePath: 'apps/gallery/test/images/06.png'},
|
||||
// Animated GIF
|
||||
{type: 'pictures',filePath: 'apps/gallery/test/images/07.gif'},
|
||||
// Animaged PNG
|
||||
{type: 'pictures',filePath: 'apps/gallery/test/images/08.png'}
|
||||
]);
|
||||
app = new Gallery(client);
|
||||
fullscreen_view = new Fullscreen_View(client);
|
||||
actions = new Marionette.Actions(client);
|
||||
app.launch();
|
||||
});
|
||||
|
||||
test('open valid images in fullscreen view', function() {
|
||||
|
||||
for (var i = 0; i < 8; i++) {
|
||||
app.tapThumbnail(i);
|
||||
assert.ok(fullscreen_view.displayed);
|
||||
|
||||
var initial_width = fullscreen_view.width;
|
||||
var initial_height = fullscreen_view.height;
|
||||
|
||||
// Checks the image blob is currently being displayed
|
||||
assert.ok(fullscreen_view.hasSrcImageBlobURL(Gallery.ORIGIN,
|
||||
fullscreen_view.displayedImage));
|
||||
|
||||
// Initially the image resolutions matches the frame size.
|
||||
// if the image's original res is
|
||||
// greater than the frame, it will zoom in when the user double taps.
|
||||
// double tap, if the image width got increased,
|
||||
// also check the displayed image height has increased (i.e. zoomed in)
|
||||
actions.doubleTap(fullscreen_view.displayedImage).perform();
|
||||
if (initial_width < fullscreen_view.width)
|
||||
{assert.ok(initial_height < fullscreen_view.height);}
|
||||
else
|
||||
{assert.ok(initial_height == fullscreen_view.height);}
|
||||
|
||||
// return to the main thumbnail view
|
||||
fullscreen_view.fullscreenBackButton.click();
|
||||
assert.ok(app.thumbnailsViewDisplayed);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
18
gaia/apps/gallery/test/unit/.jshintrc
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"extends": "../../../../.jshintrc",
|
||||
"predef": [
|
||||
"assert",
|
||||
"suite",
|
||||
"test",
|
||||
"setup",
|
||||
"teardown",
|
||||
"suiteSetup",
|
||||
"suiteTeardown",
|
||||
"require",
|
||||
"requireApp",
|
||||
"sinon",
|
||||
"mocha",
|
||||
"loadBodyHTML",
|
||||
"MocksHelper"
|
||||
]
|
||||
}
|
||||
311
gaia/apps/gallery/test/unit/image_processor_test.js
Executable file
|
|
@ -0,0 +1,311 @@
|
|||
'use strict';
|
||||
|
||||
requireApp('/gallery/js/image_processor.js');
|
||||
requireApp('/gallery/js/image_processor_thread.js');
|
||||
|
||||
function defineTestSuite(implementationName) {
|
||||
suite(implementationName, function() {
|
||||
var processor;
|
||||
|
||||
suiteSetup(function() {
|
||||
if (implementationName === 'ImageProcessorThread') {
|
||||
// The path to the worker code is different in this test case
|
||||
// so tweak the URL just for this test.
|
||||
window.ImageProcessorThread.WORKER_URL =
|
||||
'../../' + window.ImageProcessorThread.WORKER_URL;
|
||||
}
|
||||
processor = new window[implementationName](1024*1024);
|
||||
});
|
||||
|
||||
var imageProcessingTests = [
|
||||
{
|
||||
name: 'implicit noop test',
|
||||
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
|
||||
expected: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
|
||||
},
|
||||
|
||||
{
|
||||
name: 'explicit noop test',
|
||||
gamma: 1.0,
|
||||
levels: {
|
||||
red: {min: 0, max:255},
|
||||
green: {min: 0, max:255},
|
||||
blue: {min: 0, max:255}
|
||||
},
|
||||
matrix: [1,0,0,0,0,1,0,0,0,0,1,0],
|
||||
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
|
||||
expected: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
|
||||
},
|
||||
|
||||
{
|
||||
name: 'gamma=1.0',
|
||||
gamma: 1.0,
|
||||
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
|
||||
expected: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
|
||||
},
|
||||
|
||||
{
|
||||
name: 'gamma=0.5',
|
||||
gamma: 0.5,
|
||||
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
|
||||
expected: [0,0,0,0, 255,255,255,0,
|
||||
Math.round(255*Math.pow(50/255, 0.5)),
|
||||
Math.round(255*Math.pow(100/255, 0.5)),
|
||||
Math.round(255*Math.pow(150/255, 0.5)),
|
||||
0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'gamma=2.0',
|
||||
gamma: 2.0,
|
||||
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
|
||||
expected: [0,0,0,0, 255,255,255,0,
|
||||
Math.round(255*Math.pow(50/255, 2.0)),
|
||||
Math.round(255*Math.pow(100/255, 2.0)),
|
||||
Math.round(255*Math.pow(150/255, 2.0)),
|
||||
0],
|
||||
},
|
||||
|
||||
{ // should not modify the image because range too small
|
||||
name: 'narrow levels',
|
||||
levels: {
|
||||
red: {min: 100, max:105},
|
||||
green: {min: 60, max:65},
|
||||
blue: {min: 200, max:205}
|
||||
},
|
||||
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
|
||||
expected: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
|
||||
},
|
||||
|
||||
{
|
||||
name: 'no-op levels',
|
||||
levels: {
|
||||
red: {min: 0, max:255},
|
||||
green: {min: 0, max:255},
|
||||
blue: {min: 0, max:255}
|
||||
},
|
||||
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
|
||||
expected: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
|
||||
},
|
||||
|
||||
{
|
||||
name: 'levels',
|
||||
levels: {
|
||||
red: {min: 0, max: 255},
|
||||
green: { min: 50, max: 200},
|
||||
blue: {min: 100, max: 150 }
|
||||
},
|
||||
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
|
||||
expected: [0,0,0,0, 255,255,255,0,
|
||||
50, Math.round(255 * (100-50)/150), 255, 0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'levels plus gamma',
|
||||
levels: {
|
||||
red: {min: 0, max: 255},
|
||||
green: { min: 50, max: 200},
|
||||
blue: {min: 100, max: 150 }
|
||||
},
|
||||
gamma: 1.25,
|
||||
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
|
||||
expected: [0,0,0,0, 255,255,255,0,
|
||||
Math.round(255*Math.pow(50/255, 1.25)),
|
||||
Math.round(255*Math.pow(Math.round(255*(100-50)/150)/255,
|
||||
1.25)),
|
||||
255, 0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'identity matrix',
|
||||
matrix: [1,0,0,0,0,1,0,0,0,0,1,0],
|
||||
input: [1,2,3,0],
|
||||
expected: [1,2,3,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'matrix m0',
|
||||
matrix: [2,0,0,0, 0,0,0,0, 0,0,0,0],
|
||||
input: [1,2,3,0],
|
||||
expected: [2,0,0,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'matrix m1',
|
||||
matrix: [0,2,0,0, 0,0,0,0, 0,0,0,0],
|
||||
input: [1,2,3,0],
|
||||
expected: [4,0,0,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'matrix m2',
|
||||
matrix: [0,0,2,0, 0,0,0,0, 0,0,0,0],
|
||||
input: [1,2,3,0],
|
||||
expected: [6,0,0,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'matrix m3',
|
||||
matrix: [0,0,0,0.5, 0,0,0,0, 0,0,0,0],
|
||||
input: [1,2,3,0],
|
||||
expected: [128,0,0,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'matrix m4',
|
||||
matrix: [0,0,0,0, 2,0,0,0, 0,0,0,0],
|
||||
input: [1,2,3,0],
|
||||
expected: [0,2,0,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'matrix m5',
|
||||
matrix: [0,0,0,0, 0,2,0,0, 0,0,0,0],
|
||||
input: [1,2,3,0],
|
||||
expected: [0,4,0,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'matrix m6',
|
||||
matrix: [0,0,0,0, 0,0,2,0, 0,0,0,0],
|
||||
input: [1,2,3,0],
|
||||
expected: [0,6,0,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'matrix m7',
|
||||
matrix: [0,0,0,0, 0,0,0,0.5, 0,0,0,0],
|
||||
input: [1,2,3,0],
|
||||
expected: [0,128,0,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'matrix m8',
|
||||
matrix: [0,0,0,0, 0,0,0,0, 2,0,0,0],
|
||||
input: [1,2,3,0],
|
||||
expected: [0,0,2,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'matrix m9',
|
||||
matrix: [0,0,0,0, 0,0,0,0, 0,2,0,0],
|
||||
input: [1,2,3,0],
|
||||
expected: [0,0,4,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'matrix m10',
|
||||
matrix: [0,0,0,0, 0,0,0,0, 0,0,2,0],
|
||||
input: [1,2,3,0],
|
||||
expected: [0,0,6,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'matrix m11',
|
||||
matrix: [0,0,0,0, 0,0,0,0, 0,0,0,0.5],
|
||||
input: [1,2,3,0],
|
||||
expected: [0,0,128,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'full matrix',
|
||||
matrix: [1,2,3,0.1, 4,5,6,0.2, 7,8,9,0.4],
|
||||
input: [1,2,3,0],
|
||||
expected: [40,83,152,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'matrix overflow',
|
||||
matrix: [1,2,3,1, 4,5,6,1, 7,8,9,1],
|
||||
input: [1,2,3,0],
|
||||
expected: [255,255,255,0]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'everything',
|
||||
gamma: 0.75,
|
||||
levels: {
|
||||
red: {min: 20, max: 225},
|
||||
green: { min: 50, max: 200},
|
||||
blue: {min: 10, max: 180 }
|
||||
},
|
||||
matrix: [0.1,0.2,0.3,0, 0.4,0.5,0.6,0, 0.7,0.8,0.9,0],
|
||||
input: [50,100,150,0],
|
||||
expected: [94,212,255,0]
|
||||
}
|
||||
];
|
||||
|
||||
// Register all the tests defined in the array above
|
||||
imageProcessingTests.forEach(function(t) {
|
||||
test(t.name, function(done) {
|
||||
if (t.gamma) {
|
||||
processor.setGamma(t.gamma);
|
||||
}
|
||||
else {
|
||||
processor.setGamma(1.0);
|
||||
}
|
||||
if (t.levels) {
|
||||
processor.setLevels(t.levels);
|
||||
}
|
||||
else {
|
||||
processor.setLevels(null);
|
||||
}
|
||||
if (t.matrix) {
|
||||
processor.setMatrix(t.matrix);
|
||||
}
|
||||
else {
|
||||
processor.setMatrix(null);
|
||||
}
|
||||
|
||||
processor.processImage(new Uint8Array(t.input).buffer).then(
|
||||
function(result) {
|
||||
done(function() {
|
||||
assert.deepEqual(new Uint8Array(result),
|
||||
new Uint8Array(t.expected));
|
||||
});
|
||||
},
|
||||
function(error) {
|
||||
done(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('compute histogram', function(done) {
|
||||
// Generate some random input and keep track of the histogram
|
||||
// we expect from that input;
|
||||
var N = 16*1024;
|
||||
var input = new Uint8Array(N*4);
|
||||
var red = new Uint32Array(256);
|
||||
var green = new Uint32Array(256);
|
||||
var blue = new Uint32Array(256);
|
||||
for(var i = 0; i < N; i++) {
|
||||
var r = Math.floor(Math.random()*256);
|
||||
var g = Math.floor(Math.random()*256);
|
||||
var b = Math.floor(Math.random()*256);
|
||||
input[i*4] = r;
|
||||
input[i*4+1] = g;
|
||||
input[i*4+2] = b;
|
||||
red[r]++;
|
||||
green[g]++;
|
||||
blue[b]++;
|
||||
}
|
||||
|
||||
// Now compute a histogram on that input and compare to expected
|
||||
processor.computeHistogram(input.buffer).then(
|
||||
function(result) {
|
||||
done(function() {
|
||||
assert.deepEqual(new Uint32Array(result, 0, 256), red);
|
||||
assert.deepEqual(new Uint32Array(result, 256*4, 256), green);
|
||||
assert.deepEqual(new Uint32Array(result, 256*8, 256), blue);
|
||||
});
|
||||
},
|
||||
function(error) {
|
||||
done(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
defineTestSuite('ImageProcessor');
|
||||
defineTestSuite('ImageProcessorThread');
|
||||
|
||||
51
gaia/apps/gallery/test/unit/mock_image_editor.js
Executable file
|
|
@ -0,0 +1,51 @@
|
|||
'use strict';
|
||||
/* exported MockImageEditor */
|
||||
|
||||
var MockImageEditor = (function() {
|
||||
var MockImageEditor = function(imageBlob, container, edits, ready, croponly) {
|
||||
this.imageBlob = imageBlob;
|
||||
this.container = container;
|
||||
this.edits = edits;
|
||||
this.ready = ready;
|
||||
this.croponly = croponly;
|
||||
|
||||
this.dest = {};
|
||||
this.cropOverlayRegion = {};
|
||||
|
||||
setTimeout(ready);
|
||||
};
|
||||
|
||||
MockImageEditor.prototype.showCropOverlay = sinon.spy();
|
||||
MockImageEditor.prototype.setCropAspectRatio = sinon.spy();
|
||||
MockImageEditor.prototype.destroy = sinon.spy();
|
||||
|
||||
MockImageEditor.prototype.hasBeenCropped = function() {
|
||||
return (this.cropOverlayRegion.left !== 0 ||
|
||||
this.cropOverlayRegion.top !== 0 ||
|
||||
this.cropOverlayRegion.right !== this.dest.width ||
|
||||
this.cropOverlayRegion.bottom !== this.dest.height);
|
||||
};
|
||||
|
||||
MockImageEditor.prototype.getCropRegion = function() {
|
||||
var region = this.cropOverlayRegion;
|
||||
var previewRect = this.dest;
|
||||
|
||||
// Convert the preview crop region to fractions
|
||||
var left = region.left / previewRect.width;
|
||||
var right = region.right / previewRect.width;
|
||||
var top = region.top / previewRect.height;
|
||||
var bottom = region.bottom / previewRect.height;
|
||||
|
||||
return {
|
||||
left: left,
|
||||
top: top,
|
||||
width: right - left,
|
||||
height: bottom - top
|
||||
};
|
||||
};
|
||||
|
||||
sinon.spy(MockImageEditor.prototype, 'hasBeenCropped');
|
||||
sinon.spy(MockImageEditor.prototype, 'getCropRegion');
|
||||
|
||||
return MockImageEditor;
|
||||
})();
|
||||
7
gaia/apps/gallery/test/unit/mock_spinner.js
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
'use strict';
|
||||
/* exported MockSpinner */
|
||||
|
||||
var MockSpinner = {
|
||||
show: sinon.spy(),
|
||||
hide: sinon.spy()
|
||||
};
|
||||