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.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,231 @@
/*global OptionMenu, MockL10n, TransitionEvent */
'use strict';
require('/shared/test/unit/mocks/mock_l10n.js');
require('/shared/js/option_menu.js');
suite('OptionMenu', function() {
var options, menu, formHeader, formSection, realL10n;
suiteSetup(function() {
options = {
id: 'menu-fixture',
header: 'Text Header',
section: 'Text Section',
classes: ['class1', 'class2'],
items: [
{
name: 'test',
method: function(param) {
},
params: ['foo']
},
{
l10nId: 'cancel',
l10nArgs: { test: true }
}
]
};
realL10n = navigator.mozL10n;
navigator.mozL10n = MockL10n;
});
suiteTeardown(function() {
navigator.mozL10n = realL10n;
});
setup(function() {
this.sinon.spy(navigator.mozL10n, 'setAttributes');
menu = new OptionMenu(options);
formHeader = menu.form.querySelector('header');
formSection = menu.form.querySelector('section');
});
teardown(function() {
var fixture = document.getElementById('menu-fixture');
if (fixture) {
document.body.removeChild(fixture);
}
});
suite('Instance', function() {
test('OptionMenu', function() {
assert.ok(OptionMenu);
assert.ok(OptionMenu.prototype.show);
assert.ok(OptionMenu.prototype.hide);
});
suite('menu.show()', function() {
setup(function() {
this.sinon.stub(menu.form, 'focus');
this.sinon.stub(HTMLElement.prototype, 'blur');
menu.show();
});
test('appends element to body', function() {
assert.equal(
menu.form, document.body.lastElementChild
);
});
test('Redundant shows have no effect', function() {
sinon.spy(document.body, 'appendChild');
menu.show();
sinon.assert.notCalled(document.body.appendChild);
});
test('Prevent pointer events and focus', function() {
menu.show();
sinon.assert.called(HTMLElement.prototype.blur);
assert.isTrue(document.body.classList.contains('dialog-animating'));
var transitionend = new TransitionEvent('transitionend', {
bubbles: true,
propertyName: 'transform'
});
menu.form.dispatchEvent(transitionend);
assert.isFalse(document.body.classList.contains('dialog-animating'));
sinon.assert.called(menu.form.focus);
});
suite('menu.hide()', function() {
setup(function() {
menu.hide();
});
test('hiding is delayed by animation', function() {
assert.notEqual(menu.form.parentElement, null);
});
test('removes element from DOM after transitionend', function() {
var transitionend =
new CustomEvent('transitionend', { target: menu.form });
menu.form.dispatchEvent(transitionend);
assert.equal(menu.form.parentElement, null);
});
});
});
});
suite('Display', function() {
test('header: text', function() {
assert.equal(
formHeader.textContent, 'Text Header'
);
});
test('header: element', function() {
options.header = document.createElement('header');
options.header.textContent = 'Element Header';
menu = new OptionMenu(options);
formHeader = menu.form.firstElementChild;
assert.equal(
formHeader.textContent, 'Element Header'
);
});
test('header: none', function() {
options.header = null;
menu = new OptionMenu(options);
assert.isNull(menu.form.querySelector('header'));
});
test('section: text', function() {
assert.equal(
formSection.textContent, 'Text Section'
);
});
test('section: element', function() {
options.section = document.createElement('section');
options.section.textContent = 'Element Section';
menu = new OptionMenu(options);
formSection = menu.form.firstElementChild;
assert.equal(
formSection.textContent, 'Element Section'
);
});
test('section: none', function() {
options.section = null;
menu = new OptionMenu(options);
assert.isNull(menu.form.querySelector('section'));
});
test('style doesn\'t affect confirm dialogs', function(next) {
var style = document.createElement('style');
style.textContent = '@import "../../../../shared/style/option_menu.css"';
var loaded = setInterval(function() {
try {
// We're waiting for an @import stylesheet to load, so wait for the
// inner set of cssRules.
style.sheet.cssRules[0].styleSheet.cssRules;
clearInterval(loaded);
} catch (e) {
// Waiting for stylesheet to load
} finally {
// Clear the interval again just in case we threw before calling
// clearInterval() the first time. This is necessary so we don't call
// the done() function multiple times.
clearInterval(loaded);
var form = document.createElement('form');
form.setAttribute('role', 'dialog');
form.setAttribute('data-type', 'confirm');
document.body.appendChild(form);
var compStyle = window.getComputedStyle(form);
assert.notEqual(compStyle.visibility, 'hidden');
next();
}
}, 10);
document.body.appendChild(style);
});
});
suite('Options', function() {
var buttons;
setup(function() {
buttons = menu.form.querySelectorAll('button');
});
test('Buttons', function() {
Array.forEach(buttons, (button) => {
assert.equal(button.type, 'button');
});
assert.equal(buttons.length, 2);
});
test('Button Text', function() {
assert.equal(buttons[0].textContent, options.items[0].name);
});
test('Localized button', function() {
sinon.assert.calledWith(navigator.mozL10n.setAttributes, buttons[1],
options.items[1].l10nId, options.items[1].l10nArgs);
});
test('classes', function() {
assert.ok(menu.form.classList.contains('class1'));
assert.ok(menu.form.classList.contains('class2'));
});
});
suite('Behaviours', function() {
test('Fat fingering does not hide menu', function() {
menu.show();
menu.form.click();
assert.equal(
menu.form, document.body.lastElementChild
);
});
});
});