VulpesOS/gaia/apps/ringtones/test/marionette/lib/ringtones.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

463 lines
12 KiB
JavaScript
Executable file

/* jshint node: true*/
/* global marionetteScriptFinished */
/* exported findElement */
'use strict';
function createElementGetters(object, parentName, elementNames) {
elementNames.forEach(function(name) {
Object.defineProperty(object.prototype, name, {
get: function() {
return this[parentName].findElement(object.Selectors[name]);
}
});
});
}
/***** Popup windows *****/
function CustomDialog(client) {
this.client = client;
}
CustomDialog.Selectors = Object.freeze({
element: 'form#dialog-screen',
cancelButton: 'button#dialog-no',
confirmButton: 'button#dialog-yes'
});
CustomDialog.prototype = {
waitUntilCreated: function() {
this.client.helper.waitForElement(CustomDialog.Selectors.element);
}
};
createElementGetters(
CustomDialog, 'client', ['cancelButton', 'confirmButton']
);
function ActionsMenu(client) {
this.client = client;
this.element = this.client.findElement(ActionsMenu.Selectors.menu);
}
ActionsMenu.Selectors = Object.freeze({
menu: 'gaia-menu#ringtone-actions',
shareButton: 'button[data-action="share"]',
deleteButton: 'button[data-action="delete"]',
cancelButton: 'button[data-action="cancel"]',
shareMenu: 'form[data-z-index-level="action-menu"]'
});
ActionsMenu.prototype = {
waitUntilOpened: function() {
this.client.waitFor(function() {
return this.element.displayed();
}.bind(this));
},
waitForDialog: function() {
var dialog = new CustomDialog(this.client);
dialog.waitUntilCreated();
return dialog;
},
// TODO(gareth): Move this shareMenu stuff into the helper.
get shareMenu() {
// Switch to the system app first.
this.client.switchToFrame();
return this.client.helper.waitForElement(ActionsMenu.Selectors.shareMenu);
},
shareWith: function(appName) {
var shareMenu = this.shareMenu;
var list = shareMenu.findElements('button');
for (var i = 0; i < list.length; i++) {
if (list[i].text() === appName) {
return list[i];
}
}
return null;
}
};
createElementGetters(
ActionsMenu, 'element', ['shareButton', 'deleteButton', 'cancelButton']
);
// ***** Sounds *****
function BaseSound(client, element) {
this.client = client;
this.element = element;
}
BaseSound.Selectors = Object.freeze({
name: '.name',
subtitle: 'p.subtitle'
});
BaseSound.prototype = {
get name() {
return this.element.findElement(BaseSound.Selectors.name).text();
},
get subtitle() {
var subtitle = this.element.findElement(BaseSound.Selectors.subtitle);
return subtitle ? subtitle.text() : undefined;
}
};
function ManageSound(client, element) {
BaseSound.call(this, client, element);
}
ManageSound.prototype = Object.create(BaseSound.prototype);
ManageSound.prototype.constructor = ManageSound;
ManageSound.Selectors = Object.freeze({
description: 'div.desc',
actionsButton: 'a.actions-button'
});
ManageSound.prototype.tap = function() {
this.element.findElement(ManageSound.Selectors.description).tap(20, 20);
};
ManageSound.prototype.openActions = function() {
this.element.findElement(ManageSound.Selectors.actionsButton).tap();
var actionsMenu = new ActionsMenu(this.client);
actionsMenu.waitUntilOpened();
return actionsMenu;
};
Object.defineProperty(ManageSound.prototype, 'playing', {
get: function() {
return this.element.getAttribute('data-playing') === 'true';
}
});
function PickSound(client, element) {
BaseSound.call(this, client, element);
}
PickSound.prototype = Object.create(BaseSound.prototype);
PickSound.prototype.constructor = PickSound;
PickSound.Selectors = Object.freeze({
input: 'gaia-radio',
subtitle: 'gaia-radio details'
});
Object.defineProperty(PickSound.prototype, 'selected', {
get: function() {
return Boolean(this.element.findElement(PickSound.Selectors.input)
.scriptWith(function(el) {
return el.wrappedJSObject.checked;
}));
}
});
Object.defineProperty(PickSound.prototype, 'subtitle', {
get: function() {
var subtitle = this.element.findElement(PickSound.Selectors.subtitle);
return subtitle ? subtitle.text() : undefined;
}
});
PickSound.prototype.select = function() {
this.element.tap();
this.client.waitFor(function() {
return this.selected;
}.bind(this));
};
// ***** Sound Lists *****
function BaseSoundList(client, element, Sound) {
this.client = client;
this.element = element;
this.Sound = Sound;
}
BaseSoundList.Selectors = Object.freeze({
header: 'gaia-subheader > span',
sound: 'li'
});
BaseSoundList.prototype = {
client: null,
displayed: function(callback) {
return this.element.displayed(callback);
},
get sounds() {
// hack to find quicker that we have no elements
var quickly = this.client.scope({ searchTimeout: 50 });
this.element.client = quickly;
var elts = this.element.findElements(
BaseSoundList.Selectors.sound
);
this.element.client = this.client;
return elts.map(function(element) {
return new this.Sound(this.client, element);
}.bind(this));
}
};
createElementGetters(BaseSoundList, 'element', ['header']);
function ManageSoundList(client, element) {
BaseSoundList.call(this, client, element, ManageSound);
}
ManageSoundList.prototype = Object.create(BaseSoundList.prototype);
ManageSoundList.prototype.constructor = ManageSoundList;
function PickSoundList(client, element) {
BaseSoundList.call(this, client, element, PickSound);
}
PickSoundList.prototype = Object.create(BaseSoundList.prototype);
PickSoundList.prototype.constructor = PickSoundList;
Object.defineProperty(PickSoundList.prototype, 'selectedSound', {
get: function() {
var sounds = this.sounds;
for (var i = 0; i < sounds.length; i++) {
if (sounds[i].selected) {
return sounds[i];
}
}
}
});
// ***** Ringtones Containers *****
function BaseRingtonesContainer(client, SoundList) {
this.client = client;
this.SoundList = SoundList;
this.client.helper.waitForElement(
BaseRingtonesContainer.Selectors.readyBody
);
}
BaseRingtonesContainer.Selectors = Object.freeze({
readyBody: 'body[data-ready]',
soundLists: 'article#list-parent > section'
});
BaseRingtonesContainer.prototype = {
client: null,
get soundLists() {
return this.client.findElements(
BaseRingtonesContainer.Selectors.soundLists
).map(function(element) {
return new this.SoundList(this.client, element);
}.bind(this));
},
};
function ManageRingtonesContainer(client) {
BaseRingtonesContainer.call(this, client, ManageSoundList);
}
ManageRingtonesContainer.prototype = Object.create(
BaseRingtonesContainer.prototype
);
ManageRingtonesContainer.prototype.constructor = ManageRingtonesContainer;
ManageRingtonesContainer.Selectors = Object.freeze({
backButton: '#header',
addButton: 'button#add',
shareFrame: 'iframe[data-url$="share.html"]'
});
createElementGetters(
ManageRingtonesContainer, 'client', ['backButton', 'addButton']
);
ManageRingtonesContainer.prototype.addCustomRingtone = function(info) {
return this.client.executeAsyncScript(function(info) {
var customRingtones = window.wrappedJSObject.customRingtones;
customRingtones.add(JSON.parse(info)).then(function(tone) {
marionetteScriptFinished({
// Use the private members of tone, since the getters are getting Xrayed
// into oblivion. See bug 987111.
name: tone._name, subtitle: tone._subtitle, id: tone._id
});
}, function(error) {
marionetteScriptFinished(null);
});
}, [JSON.stringify(info)]);
};
ManageRingtonesContainer.prototype.waitUntilLoaded = function() {
this.client.waitFor(function() {
return this.soundLists.length === 2;
}.bind(this));
};
ManageRingtonesContainer.prototype.waitForNewRingtoneWindow =
function(callback) {
this.client.switchToFrame();
var win = this.client.helper.waitForElement(
ManageRingtonesContainer.Selectors.shareFrame
);
this.client.switchToFrame(win);
callback(new NewRingtoneContainer(this.client));
this.client.switchToFrame();
this.client.apps.switchToApp(Ringtones.URL);
};
function PickRingtoneContainer(client) {
BaseRingtonesContainer.call(this, client, PickSoundList);
}
PickRingtoneContainer.prototype = Object.create(
BaseRingtonesContainer.prototype
);
PickRingtoneContainer.prototype.constructor = PickRingtoneContainer;
PickRingtoneContainer.Selectors = Object.freeze({
cancelButton: '#header',
setButton: 'button#set'
});
PickRingtoneContainer.prototype.waitUntilLoaded = function() {
this.client.waitFor(function() {
return this.soundLists.length === 3;
}.bind(this));
};
createElementGetters(
PickRingtoneContainer, 'client', ['cancelButton', 'setButton']
);
Object.defineProperty(PickRingtoneContainer.prototype, 'selectedSound', {
get: function() {
var lists = this.soundLists;
for (var i = 0; i < lists.length; i++) {
if (lists[i].selectedSound) {
return lists[i].selectedSound;
}
}
}
});
function NewRingtoneContainer(client) {
this.client = client;
// For some reason, we can't add blobs to indexedDB in Marionette
// tests, so just null out our blob.
this.client.executeScript(function() {
var customRingtones = window.wrappedJSObject.customRingtones;
var oldAdd = customRingtones.add;
customRingtones.add = function(info) {
return oldAdd.call(
customRingtones, {name: info.name, subtitle: info.subtitle}
);
};
});
}
NewRingtoneContainer.Selectors = Object.freeze({
cancelButton: '#header',
saveButton: 'button#save',
songTitle: '#songtitle',
artist: '#artist'
});
NewRingtoneContainer.prototype = {
get songTitle() {
return this.client.findElement(
NewRingtoneContainer.Selectors.songTitle
).text();
},
get artist() {
return this.client.findElement(
NewRingtoneContainer.Selectors.artist
).text();
},
waitForSongInfo: function(expectedTitle, expectedArtist) {
this.client.waitFor(function() {
return this.songTitle === expectedTitle && this.artist === expectedArtist;
}.bind(this));
}
};
createElementGetters(
NewRingtoneContainer, 'client', ['cancelButton', 'saveButton']
);
var SETTINGS_URL = 'app://settings.gaiamobile.org';
// XXX: This is a workaround for changes in the system app; see bug 950673.
// I neither know (nor care) why this works, but we should probably fix it
// up when a better way comes along.
function switchToAppFixed(client, url) {
client.switchToFrame();
var frame = client.findElement('iframe[src*="' + url + '"]');
client.switchToFrame(frame, {focus: true});
client.helper.wait(500);
}
/**
* Abstraction around Ringtones app.
* @constructor
* @param {Marionette.Client} client for operations.
*/
function Ringtones(client) {
this.client = client;
}
/**
* @type String Origin of Ringtones app
*/
Ringtones.URL = 'app://ringtones.gaiamobile.org';
module.exports = Ringtones;
Ringtones.prototype = {
client: null,
switchToMe: function() {
this.client.switchToFrame();
this.client.apps.switchToApp(Ringtones.URL);
},
inAlertTones: function(soundPanel, callback) {
soundPanel.clickAlertToneSelect();
this.switchToMe();
callback(new PickRingtoneContainer(this.client));
switchToAppFixed(this.client, SETTINGS_URL);
},
inRingTones: function(soundPanel, callback) {
soundPanel.clickRingToneSelect();
this.switchToMe();
callback(new PickRingtoneContainer(this.client));
switchToAppFixed(this.client, SETTINGS_URL);
},
inManager: function(soundPanel, callback) {
soundPanel.clickManageTones();
this.switchToMe();
callback(new ManageRingtonesContainer(this.client));
switchToAppFixed(this.client, SETTINGS_URL);
},
inShare: function(callback) {
this.switchToMe();
callback(new NewRingtoneContainer(this.client));
}
};