VulpesOS/gaia/apps/clock/test/unit/picker/spinner_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

396 lines
11 KiB
JavaScript
Executable file

suite('Spinner', function() {
'use strict';
/* global MockIntlHelper, IntlHelper */
var Spinner, GestureDetector;
var _clientHeight;
var VALUE_ELEMENT_HEIGHT = 20;
suiteSetup(function(done) {
window.IntlHelper = MockIntlHelper;
IntlHelper.define('digit-nopadding', 'number', {
style: 'decimal',
useGrouping: false
});
// override native clientHeight
_clientHeight = Object.getOwnPropertyDescriptor(
Element.prototype, 'clientHeight');
Object.defineProperty(Element.prototype, 'clientHeight', {
configurable: true,
enumerable: true,
get: function clockTestClientHeightStub() {
if (this.classList.contains('picker-unit')) {
return VALUE_ELEMENT_HEIGHT;
}
return _clientHeight.get.call(this);
}
});
require([
'picker/spinner',
'shared/js/gesture_detector'
], function(spinner, GD) {
Spinner = spinner;
GestureDetector = GD;
done();
});
});
suiteTeardown(function() {
Object.defineProperty(Element.prototype, 'clientHeight', _clientHeight);
});
setup(function() {
VALUE_ELEMENT_HEIGHT = 20;
this.container = document.createElement('div');
this.container.classList.add('test-spinner-container');
this.element = document.createElement('div');
this.element.classList.add('test-spinner-element');
this.container.appendChild(this.element);
document.body.appendChild(this.container);
this.clock = this.sinon.useFakeTimers();
});
function checkTranslate(value) {
test('Checking translate is ' + value, function() {
assert.equal(this.element.style.transform,
'translateY(' + value + 'px)');
assert.equal(this.spinner.top, value);
});
}
function checkIndex(index) {
test('Checking index is ' + index, function() {
assert.equal(this.spinner.index, index);
assert.equal(this.spinner.value, this.spinner.values[index]);
});
}
function checkCreation() {
checkTranslate(0);
checkIndex(0);
}
suite('values: [0, 1, 2]', function() {
setup(function() {
this.spinner = new Spinner({
element: this.element,
values: [0, 1, 2]
});
});
checkCreation();
suite('select option 2', function() {
setup(function() {
this.spinner.select(2);
});
checkTranslate(-40);
checkIndex(2);
});
suite('select option 3 (out of range)', function() {
setup(function() {
this.spinner.select(3);
});
checkTranslate(-40);
checkIndex(2);
});
suite('set value 2', function() {
setup(function() {
this.spinner.value = 2;
});
checkTranslate(-40);
checkIndex(2);
});
suite('set value out of range', function() {
setup(function() {
this.spinner.value = 'nope';
});
checkTranslate(0);
checkIndex(0);
});
suite('touchstart', function() {
setup(function() {
this.event = new CustomEvent('touchstart', {
cancelable: true,
bubbles: true
});
this.event.changedTouches = [];
this.element.dispatchEvent(this.event);
});
test('default is prevented', function() {
assert.ok(this.event.defaultPrevented);
});
});
suite('pan down by 15px over 1 second', function() {
setup(function() {
var event;
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 0,
timeStamp: 0
}
},
bubbles: true
});
this.container.dispatchEvent(event);
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 15,
timeStamp: 1000
}
},
bubbles: true
});
this.container.dispatchEvent(event);
});
// top should still be at zero, can't go "down" in the spinner
checkTranslate(0);
});
suite('pan up by 15px over 1 second', function() {
setup(function() {
var event;
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 15,
timeStamp: 0
}
},
bubbles: true
});
this.container.dispatchEvent(event);
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 0,
timeStamp: 1000
}
},
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-15);
checkIndex(1);
suite('pan finished w/ low (therefore zero) momentum', function() {
setup(function() {
var event = new CustomEvent('swipe', {
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-20);
checkIndex(1);
test('animation-on', function() {
assert.ok(this.element.classList.contains('animation-on'));
});
});
});
});
suite('values: [0...30]', function() {
setup(function() {
this.spinner = new Spinner({
element: this.element,
values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
});
});
checkCreation();
suite('pan up by 35px over 70ms', function() {
setup(function() {
var event;
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 35,
timeStamp: 0
}
},
bubbles: true
});
this.container.dispatchEvent(event);
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 0,
timeStamp: 70
}
},
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-35);
checkIndex(2);
suite('pan finished w/ momentum', function() {
setup(function() {
var event = new CustomEvent('swipe', {
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-200);
checkIndex(10);
test('animation-on', function() {
assert.ok(this.element.classList.contains('animation-on'));
});
});
suite('pan times out', function() {
setup(function() {
this.clock.tick(201);
});
checkTranslate(-40);
checkIndex(2);
test('animation-on', function() {
assert.ok(this.element.classList.contains('animation-on'));
});
});
});
suite('pan up by 100px over 1ms', function() {
setup(function() {
var event;
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 100,
timeStamp: 0
}
},
bubbles: true
});
this.container.dispatchEvent(event);
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 0,
timeStamp: 1
}
},
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-100);
checkIndex(5);
suite('pan finished w/ insane momentum', function() {
setup(function() {
var event = new CustomEvent('swipe', {
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-400);
checkIndex(20);
test('animation-on', function() {
assert.ok(this.element.classList.contains('animation-on'));
});
suite('start pan', function() {
setup(function() {
var event = new CustomEvent('pan', {
detail: {
position: {
clientY: 0,
timeStamp: 0
}
},
bubbles: true
});
this.container.dispatchEvent(event);
});
test('animation-on removed', function() {
assert.isFalse(
this.element.classList.contains('animation-on'));
});
suite('finish pan down 20px over 100ms', function() {
// this is a smaller scale pan, moving one unit per 100ms
setup(function() {
var event = new CustomEvent('pan', {
detail: {
position: {
clientY: 20,
timeStamp: 100
}
},
bubbles: true
});
this.container.dispatchEvent(event);
event = new CustomEvent('swipe', {
bubbles: true
});
this.container.dispatchEvent(event);
});
// total difference = 4, 1 moved + 3 inertia
checkTranslate(-320);
checkIndex(16);
});
});
});
suite('pan times out', function() {
setup(function() {
this.clock.tick(201);
});
checkTranslate(-100);
checkIndex(5);
test('animation-on', function() {
assert.ok(this.element.classList.contains('animation-on'));
});
});
});
});
suite('values: [0...30] - big elements', function() {
// results should have same index, as previous test,
// but double the px values for translates and motion because of bigger
// elements
setup(function() {
VALUE_ELEMENT_HEIGHT = 40;
this.spinner = new Spinner({
element: this.element,
values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
});
});
checkCreation();
suite('pan up by 70px over 70ms', function() {
setup(function() {
var event;
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 70,
timeStamp: 0
}
},
bubbles: true
});
this.container.dispatchEvent(event);
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 0,
timeStamp: 70
}
},
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-70);
checkIndex(2);
suite('pan finished w/ momentum', function() {
setup(function() {
var event = new CustomEvent('swipe', {
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-400);
checkIndex(10);
test('animation-on', function() {
assert.ok(this.element.classList.contains('animation-on'));
});
});
});
});
});