VulpesOS/gaia/apps/system/test/unit/app_statusbar_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

291 lines
9.9 KiB
JavaScript
Executable file

/* global MockAppWindow, AppStatusbar, MocksHelper, MockTouchForwarder */
'use strict';
require('/shared/test/unit/mocks/mock_l10n.js');
requireApp('system/test/unit/mock_app_window.js');
require('/test/unit/mock_touch_forwarder.js');
requireApp('system/js/service.js');
requireApp('system/js/base_ui.js');
requireApp('system/js/app_statusbar.js');
var mocksForAppStatusbar = new MocksHelper([
'AppWindow',
'TouchForwarder'
]).init();
suite('system/AppStatusbar', function() {
mocksForAppStatusbar.attachTestHelpers();
var app;
var subject;
setup(function() {
this.sinon.useFakeTimers();
app = new MockAppWindow({ chrome: { navigation: false }});
subject = new AppStatusbar(app);
this.sinon.stub(app, 'isFullScreen').returns(true);
subject.screen = document.createElement('div');
subject.chromeBar = document.createElement('div');
subject.titleBar = document.createElement('div');
});
suite('Reset destination if browser is destroyed', function() {
test('Suspend', function() {
app.element.dispatchEvent(new CustomEvent('_suspended'));
assert.isNull(subject._touchForwarder.destination);
});
test('Resume', function() {
var newBrowserElement = document.createElement('iframe');
app.browser = {
element: newBrowserElement
};
app.element.dispatchEvent(new CustomEvent('_resumed'));
assert.deepEqual(subject._touchForwarder.destination, newBrowserElement);
});
});
suite('fullscreen mode >', function() {
function forgeTouchEvent(type, x, y) {
var touch = document.createTouch(window, null, 42, x, y,
x, y, x, y,
0, 0, 0, 0);
var touchList = document.createTouchList(touch);
var touches = (type == 'touchstart' || type == 'touchmove') ?
touchList : null;
var changed = (type == 'touchmove') ?
null : touchList;
var e = document.createEvent('TouchEvent');
e.initTouchEvent(type, true, true,
null, null, false, false, false, false,
touches, null, changed);
return e;
}
function forgeMouseEvent(type, x, y) {
var e = document.createEvent('MouseEvent');
e.initMouseEvent(type, true, true, window, 1, x, y, x, y,
false, false, false, false, 0, null);
return e;
}
function fakeDispatch(type, x, y) {
var e;
if (type.startsWith('mouse')) {
e = forgeMouseEvent(type, x, y);
} else {
e = forgeTouchEvent(type, x, y);
}
subject.handleStatusbarTouch(e, 24);
return e;
}
suite('Revealing the StatusBar >', function() {
var transitionEndSpy;
var element;
setup(function() {
element = subject.titleBar;
transitionEndSpy = this.sinon.spy(element, 'addEventListener');
});
function assertStatusBarReleased() {
assert.isFalse(element.classList.contains('dragged'));
}
function assertChromeBarDragging(isDragging) {
assert.equal(subject.chromeBar.classList.contains('dragging'),
isDragging);
}
teardown(function() {
this.sinon.clock.tick(10000);
});
test('it should prevent default on mouse events',
function() {
var mousedown = fakeDispatch('mousedown', 100, 0);
var mousemove = fakeDispatch('mousemove', 100, 2);
var mouseup = fakeDispatch('mouseup', 100, 2);
assert.isTrue(mousedown.defaultPrevented);
assert.isTrue(mousemove.defaultPrevented);
assert.isTrue(mouseup.defaultPrevented);
});
test('it should prevent default on all touch events to prevent reflows',
function() {
var touchstart = fakeDispatch('touchstart', 100, 0);
var touchmove = fakeDispatch('touchmove', 100, 2);
var touchend = fakeDispatch('touchend', 100, 2);
assert.isTrue(touchstart.defaultPrevented);
assert.isTrue(touchmove.defaultPrevented);
assert.isTrue(touchend.defaultPrevented);
});
test('chromeBar dragging, then dragged then released when above ' +
'threshold', function() {
assertChromeBarDragging(false);
fakeDispatch('touchstart', 100, 0);
assertChromeBarDragging(true);
fakeDispatch('touchmove', 100, 24);
assertChromeBarDragging(true);
fakeDispatch('touchend', 100, 25);
assertChromeBarDragging(false);
assert.isTrue(element.classList.contains('dragged'));
});
test('chromeBar dragging then released when below threshold', function() {
assertChromeBarDragging(false);
fakeDispatch('touchstart', 100, 0);
assertChromeBarDragging(true);
fakeDispatch('touchmove', 100, 2);
assertChromeBarDragging(true);
fakeDispatch('touchend', 100, 2);
assertChromeBarDragging(false);
assertStatusBarReleased();
});
test('it should stop the propagation of the events at first', function() {
var fakeEvt = {
stopImmediatePropagation: function() {},
preventDefault: function() {},
type: 'fake'
};
this.sinon.spy(fakeEvt, 'stopImmediatePropagation');
subject.handleStatusbarTouch(fakeEvt, 24);
sinon.assert.calledOnce(fakeEvt.stopImmediatePropagation);
});
test('it should translate the statusbar on touchmove', function() {
fakeDispatch('touchstart', 100, 0);
fakeDispatch('touchmove', 100, 5);
var transform = 'translateY(calc(5px - 100%))';
assert.equal(element.style.transform, transform);
fakeDispatch('touchend', 100, 5);
});
test('it should set the dragged class on touchstart', function() {
fakeDispatch('touchstart', 100, 0);
assert.isFalse(element.classList.contains('dragged'));
fakeDispatch('touchmove', 100, 24);
fakeDispatch('touchend', 100, 25);
assert.isTrue(element.classList.contains('dragged'));
});
test('it should not translate the statusbar more than its height',
function() {
fakeDispatch('touchstart', 100, 0);
fakeDispatch('touchmove', 100, 5);
fakeDispatch('touchmove', 100, 15);
var transform = 'translateY(calc(15px - 100%))';
assert.equal(element.style.transform, transform);
fakeDispatch('touchend', 100, 15);
});
suite('after the gesture', function() {
suite('when the StatusBar is not fully displayed', function() {
setup(function() {
fakeDispatch('touchstart', 100, 0);
fakeDispatch('touchmove', 100, 5);
fakeDispatch('touchend', 100, 5);
});
test('it should hide it right away', function() {
assertStatusBarReleased();
});
});
suite('when the StatusBar is fully displayed', function() {
setup(function() {
fakeDispatch('touchstart', 100, 0);
fakeDispatch('touchmove', 100, 5);
fakeDispatch('touchmove', 100, 24);
fakeDispatch('touchend', 100, 24);
});
test('it should not hide it right away', function() {
assert.equal(subject.titleBar.style.transform, '');
assert.equal(subject.titleBar.style.transition, '');
assert.ok(subject.titleBar.classList.contains('dragged'));
});
test('but after 5 seconds', function() {
this.sinon.clock.tick(5000);
assertStatusBarReleased();
});
test('or if the utility tray hides', function() {
window.dispatchEvent(new CustomEvent('utilitytraywillshow'));
assertStatusBarReleased();
});
test('or if the user interacts with the app', function() {
// We're faking a touchstart event on the app iframe
var iframe = app.browser.element;
subject._touchForwarder.destination = window;
var e = forgeTouchEvent('touchstart', 100, 100);
window.dispatchEvent(e);
assertStatusBarReleased();
subject._touchForwarder.destination = iframe;
});
});
});
});
suite('Touch forwarding in fullscreen >', function() {
var forwardSpy;
setup(function() {
forwardSpy = this.sinon.spy(MockTouchForwarder.prototype, 'forward');
});
test('it should forward taps to the app', function() {
var touchstart = fakeDispatch('touchstart', 100, 0);
fakeDispatch('touchmove', 100, 2);
var touchend = fakeDispatch('touchend', 100, 2);
assert.isTrue(forwardSpy.calledTwice);
var call = forwardSpy.firstCall;
assert.equal(call.args[0], touchstart);
call = forwardSpy.getCall(1);
assert.equal(call.args[0], touchend);
});
suite('if it\'s not a tap and the statusbar is not fully displayed',
function() {
test('it should not forward any events', function() {
fakeDispatch('touchstart', 100, 0);
fakeDispatch('touchmove', 100, 8);
fakeDispatch('touchend', 100, 8);
assert.isTrue(forwardSpy.notCalled);
});
});
test('it should forward touchmove once the statusbar is shown',
function() {
var touchstart = fakeDispatch('touchstart', 100, 0);
fakeDispatch('touchmove', 100, 6);
var secondMove = fakeDispatch('touchmove', 100, 26);
var thirdMove = fakeDispatch('touchmove', 100, 28);
var touchend = fakeDispatch('touchend', 100, 2);
assert.equal(forwardSpy.callCount, 4);
var call = forwardSpy.firstCall;
assert.equal(call.args[0], touchstart);
call = forwardSpy.getCall(1);
assert.equal(call.args[0], secondMove);
call = forwardSpy.getCall(2);
assert.equal(call.args[0], thirdMove);
call = forwardSpy.getCall(3);
assert.equal(call.args[0], touchend);
});
});
});
});