VulpesOS/gaia/apps/camera/test/unit/controllers/viewfinder_test.js
OverSu b38dea0597 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.
2026-09-30 23:13:03 +02:00

360 lines
12 KiB
JavaScript
Executable file

'use strict';
suite('controllers/viewfinder', function() {
suiteSetup(function(done) {
var self = this;
requirejs([
'app',
'lib/camera/camera',
'controllers/viewfinder',
'views/viewfinder',
'views/focus',
'views/faces',
'lib/settings',
'lib/setting'
], function(
App, Camera, ViewfinderController, ViewfinderView,
FocusView, FacesView, Settings, Setting) {
self.ViewfinderController = ViewfinderController.ViewfinderController;
self.ViewfinderView = ViewfinderView;
self.FocusView = FocusView;
self.FacesView = FacesView;
self.Settings = Settings;
self.Setting = Setting;
self.Camera = Camera;
self.App = App;
done();
});
});
setup(function() {
this.sandbox = sinon.sandbox.create();
// App
this.app = sinon.createStubInstance(this.App);
this.app.camera = sinon.createStubInstance(this.Camera);
this.app.activity = {};
this.app.settings = sinon.createStubInstance(this.Settings);
this.app.settings.grid = sinon.createStubInstance(this.Setting);
this.app.views = {
viewfinder: sinon.createStubInstance(this.ViewfinderView),
focus: sinon.createStubInstance(this.FocusView),
faces: sinon.createStubInstance(this.FacesView)
};
this.app.Pinch = sinon.stub();
this.app.Pinch.prototype.on = sinon.stub();
// Fake elements
this.app.views.viewfinder.els = { video: {} };
// Settings
this.app.settings = sinon.createStubInstance(this.Settings);
this.app.settings.grid = sinon.createStubInstance(this.Setting);
this.app.settings.viewfinder = sinon.createStubInstance(this.Setting);
this.app.settings.cameras = sinon.createStubInstance(this.Setting);
this.app.settings.zoom = sinon.createStubInstance(this.Setting);
// Default return values
this.app.settings.viewfinder.get.withArgs('scaleType').returns('fill');
this.app.settings.grid.selected.withArgs('key').returns('off');
// Test instance
this.controller = new this.ViewfinderController(this.app);
// Shortcuts
this.viewfinder = this.controller.views.viewfinder;
this.focusRing = this.controller.views.focus;
this.faces = this.controller.views.faces;
this.focus = this.controller.views.focus;
this.settings = this.app.settings;
this.camera = this.app.camera;
});
teardown(function() {
this.sandbox.restore();
});
suite('ViewfinderController()', function() {
test('Should stop the stream when the PreviewGallery is opened', function() {
assert.isTrue(this.app.on.calledWith('previewgallery:opened',
this.controller.onGalleryOpened));
});
test('Should start the stream when the PreviewGallery is closed', function() {
assert.isTrue(this.app.on.calledWith('previewgallery:closed',
this.controller.onGalleryClosed));
});
test('Should stop the stream preview is false', function() {
assert.isTrue(this.app.on.calledWith('camera:previewactive', this.controller.onPreviewActive));
});
test('Should hide the grid when the settings menu opened', function() {
assert.isTrue(this.app.on.calledWith('settings:opened',
this.controller.onSettingsOpened));
});
test('Should show the grid again when the settings menu is closed', function() {
assert.isTrue(this.app.on.calledWith('settings:closed',
this.controller.onSettingsClosed));
});
test('Should flash viewfinder shutter when camera shutter fires', function() {
assert.isTrue(this.app.on.calledWith('camera:shutter', this.viewfinder.shutter));
});
test('Should respond to `zoomchanged` event', function() {
assert.isTrue(this.camera.on.calledWith('zoomchanged'));
});
test('Should should set the foucsRing state when focus changes', function() {
assert.isTrue(this.app.on.calledWith('camera:focusstatechanged', this.focusRing.setFocusState));
});
test('Should set the scaleType on the view', function() {
assert.equal(this.viewfinder.scaleType, 'fill');
});
test('Should set grid on/off', function() {
assert.isTrue(this.viewfinder.set.calledWith('grid', 'off'));
this.app.settings.grid.selected.withArgs('key').returns('on');
this.viewfinder.set.reset();
this.controller = new this.ViewfinderController(this.app);
assert.isTrue(this.viewfinder.set.calledWith('grid', 'on'));
});
});
suite('ViewfinderController#createViews()', function() {
setup(function() {
this.controller.createViews();
});
test('It appends views to the viewfinder views', function() {
assert.isTrue(this.focus.appendTo.calledWith(this.viewfinder.el));
assert.isTrue(this.faces.appendTo.calledWith(this.viewfinder.el));
assert.isTrue(this.viewfinder.appendTo.calledWith(this.app.el));
});
});
suite('ViewfinderController#show()', function() {
setup(function() {
this.sandbox.stub(window, 'clearTimeout');
this.sandbox.stub(window, 'setTimeout').returns('<timeout-id>');
this.app.criticalPathDone = true;
});
test('It fades the viewfinder in straight away if the critical path is incomplete', function() {
this.app.criticalPathDone = false;
this.controller.show();
sinon.assert.called(this.viewfinder.fadeIn);
sinon.assert.notCalled(window.setTimeout);
});
test('It fades the viewfinder in after 280ms timeout to avoid flicker', function() {
this.controller.show();
sinon.assert.calledWith(window.setTimeout, this.viewfinder.fadeIn, 280);
});
test('It clears any existing timeouts to avoid multiple scheduled timeouts', function() {
this.controller.show();
this.controller.show();
sinon.assert.calledWith(window.clearTimeout, '<timeout-id>');
});
});
suite('ViewfinderController#hide()', function() {
setup(function() {
this.sandbox.stub(window, 'setTimeout').returns('<timeout-id>');
this.sandbox.stub(window, 'clearTimeout');
});
test('It fades out the viewfinder', function() {
this.controller.hide();
sinon.assert.called(this.viewfinder.fadeOut);
});
test('It clears any fadeTimeout hanging around', function() {
this.controller.show();
this.controller.hide();
sinon.assert.called(window.clearTimeout, '<timeout-id>');
});
});
suite('ViewfinderController#loadStream()', function() {
test('Should load preview stream into viewfinder video element', function() {
var video = this.viewfinder.els.video;
this.controller.loadStream();
assert.isTrue(this.camera.loadStreamInto.calledWith(video));
});
});
suite('ViewfinderController#configurePreview()', function() {
setup(function() {
this.settings.cameras.selected.withArgs('key').returns('back');
this.camera.getSensorAngle.returns(90);
this.camera.previewSize.returns({ width: 400, height: 300 });
});
test('Should pass current previewSize', function() {
this.controller.configurePreview();
var previewSize = this.viewfinder.updatePreview.args[0][0];
assert.deepEqual(previewSize, { width: 400, height: 300 });
});
test('Should pass the sensor angle', function() {
this.controller.configurePreview();
var arg = this.viewfinder.updatePreview.args[0][1];
assert.equal(arg, 90);
});
test('Should indicate if selected camera is front', function() {
var arg;
// Back
this.controller.configurePreview();
arg = this.viewfinder.updatePreview.args[0][2];
assert.equal(arg, false);
this.viewfinder.updatePreview.reset();
// Front
this.settings.cameras.selected.withArgs('key').returns('front');
this.controller.configurePreview();
arg = this.viewfinder.updatePreview.args[0][2];
assert.equal(arg, true);
});
});
suite('ViewfinderController#onZoomConfigured()', function() {
setup(function() {
this.camera.isZoomSupported.returns(true);
this.settings.zoom.enabled.returns(true);
this.camera.getMinimumZoom.returns(0);
this.camera.getMaximumZoom.returns(3);
});
test('Should call enableZoom on the viewfinder', function() {
this.controller.onZoomConfigured();
assert.isTrue(this.viewfinder.enableZoom.calledWith(0, 3));
});
test('Should disable zoom if camera doesn\'t support zoom', function() {
this.camera.isZoomSupported.returns(false);
this.controller.onZoomConfigured();
assert.isTrue(this.viewfinder.disableZoom.called);
});
test('Should disable zoom if zoom disabled in settings', function() {
this.settings.zoom.enabled.returns(false);
this.controller.onZoomConfigured();
assert.isTrue(this.viewfinder.disableZoom.called);
});
});
suite('ViewfinderController#onSettingsOpened()', function() {
setup(function() {
sinon.spy(this.controller, 'hideGrid');
this.controller.onSettingsOpened();
});
test('Hide grid and hide viewfinder view from the screen reader',
function() {
sinon.assert.called(this.controller.hideGrid);
assert.isTrue(this.viewfinder.set.calledWith('ariaHidden', true));
});
});
suite('ViewfinderController#onSettingsClosed()', function() {
setup(function() {
sinon.spy(this.controller, 'configureGrid');
this.controller.onSettingsClosed();
});
test('Configure grid and show viewfinder view to the screen reader',
function() {
sinon.assert.called(this.controller.configureGrid);
assert.isTrue(this.viewfinder.set.calledWith('ariaHidden', false));
});
});
suite('ViewfinderController#onGalleryOpened()', function() {
setup(function() {
this.controller.onGalleryOpened();
});
test('When gallery is open, the viewfinder view should be disabled and ' +
'hidden from screen reader', function() {
sinon.assert.called(this.viewfinder.disable);
assert.isTrue(this.viewfinder.set.calledWith('ariaHidden', true));
});
});
suite('ViewfinderController#onGalleryClosed()', function() {
setup(function() {
this.controller.onGalleryClosed();
});
test('When gallery is closed, the viewfinder view should be enabled and ' +
'visible to screen reader', function() {
sinon.assert.called(this.viewfinder.enable);
assert.isTrue(this.viewfinder.set.calledWith('ariaHidden', false));
});
});
suite('ViewfinderController#onPowerSave', function() {
test('When power save enabled, the viewfinder should disable screen ' +
'wakelocks', function() {
this.controller.onPowerSave(false);
assert.isTrue(this.viewfinder.els.video.mozUseScreenWakeLock);
});
test('When power save disabled, the viewfinder should enable screen ' +
'wakelocks', function() {
this.controller.onPowerSave(true);
assert.isFalse(this.viewfinder.els.video.mozUseScreenWakeLock);
});
});
suite('click:viewfinder', function() {
test('Should set the grid depending on the setting', function() {
this.app.settings.grid.selected.withArgs('key').returns('on');
this.controller = new this.ViewfinderController(this.app);
assert.isTrue(this.viewfinder.set.calledWith('grid', 'on'));
this.app.settings.grid.selected.withArgs('key').returns('off');
this.controller = new this.ViewfinderController(this.app);
assert.isTrue(this.viewfinder.set.calledWith('grid', 'off'));
});
test('Should set viewfinder fill depending on the setting', function() {
this.app.settings.viewfinder.get.withArgs('scaleType').returns('fill');
this.controller = new this.ViewfinderController(this.app);
assert.equal(this.viewfinder.scaleType, 'fill');
this.app.settings.viewfinder.get.withArgs('scaleType').returns('fit');
this.controller = new this.ViewfinderController(this.app);
assert.equal(this.viewfinder.scaleType, 'fit');
});
});
suite('ViewfinderController#calculateFaceCircle()', function() {
test('Draw circle from a square', function() {
var circle = this.controller.calculateFaceCircle({top: 50, left: 50, width: 10, height: 10});
assert.deepEqual(circle, {x: 50, y: 50, diameter: 10});
});
test('Draw circle from a 2:1 rectangle', function() {
var circle = this.controller.calculateFaceCircle({top: 100, left: 50, width: 20, height: 10});
assert.deepEqual(circle, {x: 50, y: 95, diameter: 20});
});
test('Draw circle from a 1:2 rectangle', function() {
var circle = this.controller.calculateFaceCircle({top: 100, left: 50, width: 10, height: 20});
assert.deepEqual(circle, {x: 45, y: 100, diameter: 20});
});
});
});