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,19 @@
{
"extends": "../../../../../.jshintrc",
"nonew": false,
"predef": [
"__dirname",
"module",
"suite",
"test",
"setup",
"teardown",
"suiteSetup",
"suiteTeardown",
"marionette",
"marionetteScriptFinished",
"require",
"define",
"requireApp"
]
}

View file

@ -0,0 +1,253 @@
'use strict';
/* global MozActivity */
var Contacts = require('./lib/contacts');
var Dialer = require('../../../dialer/test/marionette/lib/dialer');
var Sms = require('./lib/sms');
var assert = require('assert');
var fs = require('fs');
marionette('Contacts > Activities', function() {
var client = marionette.client({
profile: Contacts.config,
desiredCapabilities: { raisesAccessibilityExceptions: false }
});
var dialerSubject;
var smsSubject;
var smsSelectors;
var subject;
var selectors;
setup(function() {
subject = new Contacts(client);
selectors = Contacts.Selectors;
dialerSubject = new Dialer(client);
smsSubject = new Sms(client);
smsSelectors = Sms.Selectors;
});
suite('open text/vcard activity', function() {
setup(function() {
smsSubject.launch(); // We open some app to start a Marionette session.
});
function getListItems() {
return client.executeScript(function() {
return document.querySelectorAll('#multiple-select-container li');
});
}
test('> with only one contact', function() {
client.executeScript(function(vCardFile) {
new MozActivity({
name: 'open',
data: {
type: 'text/vcard',
filename: 'vcard_4.vcf',
blob: new Blob([vCardFile], {type: 'text/vcard'})
}
});
}, [fs.readFileSync(__dirname + '/data/vcard_4.vcf', 'utf8')]);
var iframe = 'iframe[src="' + Contacts.URL +
'/contacts/views/vcard_load/vcard_load.html"]';
client.switchToFrame();
client.switchToFrame(client.findElement(iframe), {'focus': true});
client.helper.waitForElement(selectors.multipleSelectSave);
assert.ok(getListItems().length === 1); // vcard has one element
});
test('> with multiple contacts', function() {
client.executeScript(function(vCardFile) {
new MozActivity({
name: 'open',
data: {
type: 'text/vcard',
filename: 'vcard_21_multiple.vcf',
blob: new Blob([vCardFile], {type: 'text/vcard'})
}
});
}, [fs.readFileSync(__dirname + '/data/vcard_21_multiple.vcf', 'utf8')]);
var iframe = 'iframe[src="' + Contacts.URL +
'/contacts/views/vcard_load/vcard_load.html"]';
client.switchToFrame();
client.switchToFrame(client.findElement(iframe), {'focus': true});
client.helper.waitForElement(selectors.multipleSelectSave);
assert.ok(getListItems().length === 2); // vcard has one element
});
});
suite('webcontacts/contact activity', function() {
// Disabling these tests by now due to we need a way to switch to an
// activity instead of switching to an app, due to paths can differ.
// More info in [1].
// These test must be recovered once this bug will be landed.
// [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1140344#c9
test.skip('a contact with duplicate number shows merge page', function() {
subject.launch();
subject.addContact({
givenName: 'From Contacts App',
tel: 1111
});
client.apps.close(Contacts.URL, 'contacts');
dialerSubject.launch();
// Dialer keys don't work in b2g desktop for some reason yet,
// So just manually fire off the activity
client.executeScript(function() {
new MozActivity({
name: 'new',
data: {
type: 'webcontacts/contact',
params: {
'tel': 1111
}
}
});
});
client.switchToFrame();
client.apps.switchToApp(Contacts.URL, 'contacts');
subject.enterContactDetails({
givenName: 'From Dialer Activity'
});
this.waitForFormTransition();
client.switchToFrame(client.findElement(selectors.duplicateFrame));
var duplicateHeader = client.helper.
waitForElement(selectors.duplicateHeader);
var expectedResult = subject.l10n(
'/locales-obj/contacts.matching_contacts.en-US.json',
'duplicatesFoundTitle');
assert.equal(duplicateHeader.text(), expectedResult);
});
});
suite('webcontacts/tel activity', function() {
// Disabling these tests by now due to we need a way to switch to an
// activity instead of switching to an app, due to paths can differ.
// More info in [1].
// These test must be recovered once this bug will be landed.
// [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1140344#c9
test.skip('Error message when no contacts', function() {
smsSubject.launch();
// Launch the activity directly as mozSms has problems
// in b2g desktop.
client.executeScript(function() {
new MozActivity({
name: 'pick',
data: {
type: 'webcontacts/tel'
}
});
});
client.switchToFrame();
client.apps.switchToApp(Contacts.URL, 'contacts');
var confirmMsg = client.findElement(selectors.confirmBody);
var expectedResult = subject.l10n(
'/locales-obj/contacts.index.en-US.json',
'noContactsActivity2');
assert.equal(confirmMsg.text(), expectedResult);
});
test.skip('Error message selected contact has no number', function() {
subject.launch();
subject.addContact({
givenName: 'No Phone Number'
});
client.apps.close(Contacts.URL, 'contacts');
smsSubject.launch();
client.executeScript(function() {
new MozActivity({
name: 'pick',
data: {
type: 'webcontacts/tel'
}
});
});
client.switchToFrame();
client.apps.switchToApp(Contacts.URL, 'contacts');
client.helper.waitForElement(selectors.bodyReady);
client.helper.waitForElement(selectors.listContactFirst)
.click();
var confirmText = client.helper.waitForElement(selectors.confirmBody)
.text();
var expectedResult = subject.l10n(
'/locales-obj/contacts.index.en-US.json',
'no_contact_phones');
assert.equal(confirmText, expectedResult);
});
});
suite('webcontacts/email activity', function() {
test('Creates only one instance of action menu', function() {
subject.launch();
subject.addContactMultipleEmails({
givenName: 'From Contacts App',
emailFirst: 'first@personal.com',
emailSecond: 'second@personal.com'
});
client.apps.close(Contacts.URL, 'contacts');
smsSubject.launch();
client.executeScript(function() {
new MozActivity({
name: 'pick',
data: {
type: 'webcontacts/email'
}
});
});
client.switchToFrame();
client.apps.switchToApp(Contacts.URL, 'contacts');
client.helper.waitForElement(selectors.bodyReady);
var contact = client.helper.waitForElement(selectors.listContactFirst);
// Simulate two clicks
contact.click();
contact.click();
var emailList = client.helper.waitForElement(selectors.actionMenuList);
var emailChildren = emailList.findElements('button');
assert.equal(emailChildren.length, 3);
});
});
});

View file

@ -0,0 +1,82 @@
'use strict';
var Contacts = require('./lib/contacts');
var assert = require('assert');
marionette('Contacts shortcuts > touch', function() {
var client = marionette.client({ profile: Contacts.config });
var subject;
var selectors;
var actions;
var scrollbar;
var overlay;
function overlayOpacity() {
return subject.getElementStyle(selectors.overlay, 'opacity');
}
setup(function() {
actions = client.loader.getActions();
subject = new Contacts(client);
subject.launch();
selectors = Contacts.Selectors;
subject.addContact();
scrollbar = client.helper.waitForElement(selectors.scrollbar);
});
// Disabled bug 1023908
suite('touch on shortcuts', function() {
test('press/release on scrollbar should show/hide shortcut', function() {
var action = actions.press(scrollbar, 10, 100).perform();
overlay = client.helper.waitForElement(selectors.overlay);
assert.equal(overlay.text().length, 1);
assert.equal(overlayOpacity(), '1');
action.release().perform();
assert.equal(overlay.text().length, 0);
assert.equal(overlayOpacity(), '0');
});
// Disabled bug 1005708
test.skip('shortcut text should change after moving some distance',
function() {
var letter, nextLetter, lastLetter;
var action = actions.press(scrollbar, 10, 100).perform();
overlay = client.helper.waitForElement(selectors.overlay);
letter = overlay.text();
assert.equal(letter.length, 1);
action.moveByOffset(0, 1).perform();
nextLetter = overlay.text();
assert.equal(nextLetter.length, 1);
assert.equal(letter, nextLetter);
action.moveByOffset(0, 50).perform();
lastLetter = overlay.text();
assert.equal(nextLetter.length, 1);
assert.notEqual(lastLetter, nextLetter);
action.release().perform();
});
test('pressing near the last release position should show valid shortcut',
function() {
actions.press(scrollbar, 15, 100).release().perform();
var action = actions.press(scrollbar, 15, 100).perform();
overlay = client.helper.waitForElement(selectors.overlay);
assert.equal(overlay.text().length, 1);
action.release().perform();
});
test('pressing outside the scrollbar should not show shortcut',
function() {
var action = actions.press(scrollbar, -1, 200).perform();
assert.notEqual(overlayOpacity(), '1');
action.release().perform();
});
});
});

View file

@ -0,0 +1,43 @@
'use strict';
window.wrappedJSObject.data = window.wrappedJSObject.data || {};
window.wrappedJSObject.data.fbContactData = {
'uid': '100007887283166',
'name': 'Jander Klander',
'pic_big': 'https://fbcdn-profile-a.akamaihd.net/static-ak/' +
'fbrsrc.php/v2/yL/r/HsTZSDw4avx.gif',
'current_location': null,
'email': [{
'type': ['other'],
'value': 'gtorodelvalle@hotmail.com'
}],
'profile_update_time': 1393974966,
'work': [],
'hometown_location': null,
'_idxFriendsArray': 124,
'familyName': ['Klander'],
'additionalName': '',
'givenName': ['Jander'],
'tel': [{
'type': ['other'],
'value': '+34666666666'
}],
'email1': 'gtorodelvalle@hotmail.com',
'contactPictureUri': 'https://graph.facebook.com/100007887283166/' +
'picture?type=square&width=120&height=120',
'search': 'JanderKlandergtorodelvalle@hotmail.com',
'picwidth': 120,
'picheight': 120,
'_idx_': 0,
'fbInfo': {
'org': [''],
'adr': [],
'shortTelephone': ['666666666'],
'url': [{
'type': ['fb_profile_photo'],
'value': 'https://fbcdn-profile-a.akamaihd.net/static-ak/' +
'rsrc.php/v2/yL/r/HsTZSDw4avx.gif'
}]
}
};

View file

@ -0,0 +1,19 @@
BEGIN:VCARD
VERSION:2.1
N;ENCODING=QUOTED-PRINTABLE;CHARSET=utf-8:Gump;F=C3=B3rrest
TEL;PREF;VOICE;WORK:(111) 555-1212
ADR;HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America
LABEL;HOME;ENCODING=QUOTED-PRINTABLE:42 Plantation St.=0D=0ABaytown, LA 30314=0D=0AUnited States of America
EMAIL;PREF;INTERNET:forrestgump@example.com
END:VCARD
BEGIN:VCARD
VERSION:2.1
N;ENCODING=QUOTED-PRINTABLE;CHARSET=utf-8:Gump2;F=C3=B3rrest2
TEL;PREF;VOICE;WORK:(111) 555-1213
TEL;HOME;VOICE:(404) 555-1213
ADR;WORK;ENCODING=QUOTED-PRINTABLE:;;100 W=C3=A1ters Edge;Baytown;LA;30314;United States of America
LABEL;WORK;ENCODING=QUOTED-PRINTABLE:100 Waters Edge=0D=0ABaytown, LA 30314=0D=0AUnited States of America
ADR;HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America
LABEL;HOME;ENCODING=QUOTED-PRINTABLE:42 Plantation St.=0D=0ABaytown, LA 30314=0D=0AUnited States of America
EMAIL;PREF;INTERNET:forrestgump@example2.com
END:VCARD

View file

@ -0,0 +1,20 @@
BEGIN:VCARD
VERSION:4.0
N:Gump;Forrest;;;
FN:Forrest Gump
ORG:Bubba Gump Shrimp Co.
TITLE:Shrimp Man
PHOTO:data:image/bmp;base64,Qk02BAAAAAAAADYAAAAoAAAAEAAAAPD///8BACAAAAAAAAAAAABiBwAAYgcAAAAAAAAAAAAA///////////////////////////////////////////////////+///////////////////////////////////////////////////////////////////////V0s3/b21l/1pbVf9ydHL/u8HB//D09f/29vb///////////////////////////////////////Lx8P9ycWv/EhEO/wAAAP8AAgD/Gh0Z/15mav+tt7z/6+zr/////////////v////////////////////////+IiYf/AgYF/wAAAP8AAAD/AAAA/x8iI/88Ojv/e3l6///+/v/////////////////////////////////p5+f/am5z/xoeI/8iKDH/HSIr/ztATP+wtL//sbfC/zI4P//Ky8r///////////////////////7+/f/s7O3/vcDH/2Fkbf8+Qk7/foSW/5Wcsv+5vtP/7ezz//////97g5P/j5Oh//f4+P//////+/v7//Py8v/z8vP/9/j5/8jL2/8zNkD/MDM4/3Nydf/X0+H/0cvZ/7Srrv/Hvrz/h4uX/2Vsf/+5vcP/5OXj//Tz8//5+fn///////7+/v+eoa3/NjxE/2Vnaf9vbGr/pqSt/+ro8v+xqrP/6ePi/4SLnP85QE//e4SQ/5CWmv////////////z8+//X1tf/kZWc/09UXP9hY2f/TEhL/62twP/o6vP/n5ij/9LM0f+WnbX/PkRS/4CFkv99gor//f39//j39//19PP/+Pj3//////+ysrj/cnqP/21viv/c2On/9PL3//Hv+v/l5/T/x8jd/7Cvv//Y0NX/5NzD//X19f/7+/v///////Py9v/W3uf/z9Xa/4WFm/9UVGn/tK3D/+/o8v/Y0uD/9fL8/+3q9f/w7fn/+/n+///////////////////////08/b/2eLo/8XT2P9zdYb/XFxy/8S80//68vz/urTE/9XU5//j4+//9vX6////////////7e/u/+Dk5v/a4OT/8vf5///////g5+n/kZKe/25of/9sa3D/ZGNn/2pndf/ExdP/0tTf/+nm4//+/Pr//////87V2v+KmKf/cYOV/3mMn/+NnK3/TVll/1dYZP9kYHn/ODBG/yAcMP9fXW//ubzK/9PW3/9JREX/OTIu/7OxsP//////y9HZ/4WSov9xfo//TVhx/x8nNP8ZGiH/Y2F//3Bphv9vZYj/mZm3/7C1yv/Ey9n/DREX/wYIDf9ZaYb//v7+/8vS2v+Hk6T/h4+c/2hxg/8iJi//AwQE/0pHYP9nX4f/kIuv/4WIo/+GjaT/doOb/wECBv8dIS3/VWWL/w==
TEL;TYPE=work,voice;VALUE=uri:tel:+1-111-555-1212
TEL;TYPE=home,voice;VALUE=uri:tel:+1-404-555-1212
ADR;TYPE=work;LABEL="100 Waters Edge
Baytown,LA 30314
United States of America"
:;;100 Waters Edge;Baytown;LA;30314;United States of America
ADR;TYPE=home;LABEL="42 Plantation St.
Baytown,LA 30314
United States of America"
:;;42 Plantation St.;Baytown;LA;30314;United States of America
EMAIL:forrestgump@example.com
REV:20080424T195243Z
END:VCARD

View file

@ -0,0 +1,109 @@
'use strict';
var assert = require('assert');
var Contacts = require('./lib/contacts');
marionette('Contacts > Delete', function() {
var client = marionette.client({
profile: Contacts.config,
desiredCapabilities: { raisesAccessibilityExceptions: false }
});
var subject;
var selectors;
setup(function() {
subject = new Contacts(client);
subject.launch();
selectors = Contacts.Selectors;
});
function goToSelectMode() {
// Click on settings button and wait for slide up animation
client.helper.waitForElement(selectors.settingsButton).click();
var settings = client.helper.waitForElement(selectors.settingsView);
subject.waitForSlideUp(settings);
// Click on delete button and wait for slide down animation
client.helper.waitForElement(selectors.bulkDelete).click();
subject.waitForSlideDown(settings);
}
function isDisabled(selector) {
return client.executeScript(function(selector) {
return document.querySelector(selector).disabled;
}, [selector]);
}
test(' > Edit menu is not visible on search mode', function() {
subject.addContact({
givenName: 'Hello',
tel: 1231231234
});
goToSelectMode();
var editForm = client.findElement(selectors.editForm);
editForm.displayed(function onDisplayed() {
// Enter in search mode
client.helper.waitForElement(selectors.searchLabel).click();
// Wait until the select-all view goes away
client.helper.waitForElementToDisappear(selectors.editMenu);
});
});
// Moztrap: https://moztrap.mozilla.org/manage/case/15181/
test(' > All contacts', function() {
subject.addContact({
givenName: 'Contact 1'
});
subject.addContact({
givenName: 'Contact 2'
});
goToSelectMode();
// Check that the action now is not available
assert.ok(isDisabled(selectors.selectAction));
// Click in select all
client.helper.waitForElement(selectors.selectAllButton).click();
// Click on delete
client.helper.waitForElement(selectors.selectAction).click();
// Click on the confirmation
client.helper.waitForElement(selectors.confirmDelete).click();
// Wait until the list appear and check it's empty
client.helper.waitForElement(selectors.noContacts);
// Wait for the status saying we removed contacts
var status = client.helper.waitForElement(selectors.multipleSelectStatus);
subject.waitForSlideDown(status);
client.executeScript(function() {
return !document.querySelector('#no-contacts').classList.contains('hide');
});
});
test('> Deleting last contact', function() {
subject.addContact({
givenName: 'Contact 1'
});
// Go to deatils
client.helper.waitForElement(selectors.listContactFirstText).click();
subject.waitSlideLeft('details');
// Get to the form
var edit = client.helper.waitForElement(selectors.detailsEditContact);
subject.clickOn(edit);
subject.waitForFadeIn(client.helper.waitForElement(selectors.form));
// Click on delete
client.helper.waitForElement(selectors.deleteContact).click();
client.helper.waitForElement(selectors.confirmDelete).click();
// Check the list has 0 contacts
subject.waitForFadeIn(client.helper.waitForElement(selectors.list));
assert.equal(subject.getNumberOfContacts(), 0);
});
});

View file

@ -0,0 +1,116 @@
'use strict';
var Contacts = require('./lib/contacts');
var ContactsData = require('./lib/contacts_data');
var assert = require('assert');
var ContactsListView = require('./lib/views/contact-list/view');
marionette('Contacts > Details', function() {
var client = marionette.client({
profile: Contacts.config,
desiredCapabilities: { raisesAccessibilityExceptions: false }
});
var subject, actions;
var selectors;
var contactsData = new ContactsData(client);
var testContact;
setup(function() {
subject = new Contacts(client);
actions = client.loader.getActions();
subject.actions = actions;
subject.launch();
selectors = Contacts.Selectors;
testContact = {
tel: [{value: '1231231234', type: ['home']}],
givenName: ['Hello'],
familyName: ['World'],
name: ['Hello World'],
email: [{value: 'hello@example.com', type: ['home']}],
adr: [{type: ['home'], pref: true, streetAddress: 'False Street 123'}],
org: ['Mozilla'],
note: ['This is a note about the contact.']
};
});
function assertContactData(mozContact) {
var telNode = client.helper.waitForElement(selectors.detailsTelButtonFirst);
assert.equal(telNode.text(), mozContact.tel[0].value);
var nameNode = client.helper.waitForElement(selectors.detailsContactName);
assert.equal(nameNode.text(), mozContact.name[0]);
var emailNode = client.helper.waitForElement(selectors.detailsEmail);
assert.equal(emailNode.text(), mozContact.email[0].value);
var addressNode = client.helper.waitForElement(selectors.detailsAddress);
assert.equal(addressNode.text(), mozContact.adr[0].streetAddress);
var orgNode = client.helper.waitForElement(selectors.detailsOrg);
assert.equal(orgNode.text(), mozContact.org[0]);
var noteNode = client.helper.waitForElement(selectors.detailsNote);
assert.equal(noteNode.text(), mozContact.note[0]);
}
test('Regular contact is displayed correctly', function() {
contactsData.createMozContact(testContact);
client.helper.waitForElement(selectors.listContactFirstText).click();
subject.waitSlideLeft('details');
assertContactData(testContact);
});
test('Show contact with picture', function() {
contactsData.createMozContact(testContact, true);
client.helper.waitForElement(selectors.listContactFirstText).click();
subject.waitSlideLeft('details');
assertContactData(testContact);
var coverImg = client.helper.waitForElement(selectors.detailsCoverImage);
assert.ok(coverImg, 'Element should exist.');
client.waitFor(function() {
return coverImg.getAttribute('style').indexOf('background-image') != -1;
});
});
test('Share Contact', function() {
contactsData.createMozContact(testContact);
client.helper.waitForElement(selectors.listContactFirstText).click();
subject.waitSlideLeft('details');
// Click on share button
client.helper.waitForElement(selectors.detailsShareButton).click();
var sysMenu = subject.systemMenu;
// In the sysMenu they should appear at least the Messages and email apps
var menuOptions = sysMenu.findElements('button');
assert.ok(menuOptions.length >= 2);
});
suite('Favorite contact', function() {
setup(function(){
contactsData.createMozContact(testContact);
});
test('Mark contact as favorite', function() {
var contactsListView = new ContactsListView(client);
var contactDetailsView = contactsListView.goToContact();
contactDetailsView.makeFavorited();
assertContactData(testContact);
});
test('Favorite contact should appear in' +
' favorite and regular lists', function() {
var contactsListView = new ContactsListView(client);
var contactDetailsView = contactsListView.goToContact();
contactDetailsView.makeFavorited();
contactsListView = contactDetailsView.backtoContactsList();
assert.ok(contactsListView.firstContact.displayed());
assert.ok(contactsListView.firstFavorite.displayed());
});
});
});

View file

@ -0,0 +1,65 @@
'use strict';
var Contacts = require('./lib/contacts');
var assert = require('assert');
var fs = require('fs');
marionette('Export to SDCARD', function() {
var profile = Contacts.config;
// Enable device storage
var prefs = ['device.storage.enabled',
'device.storage.testing',
'device.storage.prompt.testing'];
prefs.forEach(pref => {
profile[pref] = true;
});
var client = marionette.client({
profile: profile,
desiredCapabilities: { raisesAccessibilityExceptions: false }
});
var actions, subject, selectors;
setup(function() {
// Remove all files in temp device storage.
client.fileManager.removeAllFiles();
subject = new Contacts(client);
actions = client.loader.getActions();
subject.actions = actions;
subject.launch();
selectors = Contacts.Selectors;
});
test('> export one contact', function() {
// Create a contact first
subject.addContact({
givenName: 'John',
tel: 1231231234
});
// Go to settings
client.helper.waitForElement(selectors.settingsButton).click();
// Now click on import contacts button
client.helper.waitForElement(selectors.exportButton).click();
client.helper.waitForElement(selectors.exportSDCard).click();
// Select all and export
client.helper.waitForElement(selectors.selectAllButton).click();
client.helper.waitForElement(selectors.selectAction).click();
// Check the string on the status
var status = client.helper.waitForElement(selectors.multipleSelectStatus);
assert.equal('1/1 contacts exported', status.text());
// Check we have a file in the sdcard
var path = client.fileManager.deviceStorage.getDeviceStoragePath();
console.log('path is ' + path);
assert.ok(fs.existsSync(path));
var files = fs.readdirSync(path);
assert.equal(files.length, 1);
subject.waitForFadeIn(client.helper.waitForElement(selectors.list));
});
});

View file

@ -0,0 +1,390 @@
'use strict';
var Contacts = require('./lib/contacts'),
ContactsData = require('./lib/contacts_data'),
Dialer = require('../../../dialer/test/marionette/lib/dialer'),
assert = require('assert'),
/*jshint -W079 */
System = require('../../../../system/test/marionette/lib/system');
// XXX Bug 1139799 - Enable test for Bug 1116889
// Gallery = require('../../../../gallery/test/marionette/lib/gallery');
marionette('Contacts > Form', function() {
var client = marionette.client({
profile: Contacts.config,
desiredCapabilities: { raisesAccessibilityExceptions: false }
}),
subject,
contactsData,
dialerSubject,
dialerSelectors,
selectors,
system;
setup(function() {
subject = new Contacts(client);
contactsData = new ContactsData(client);
selectors = Contacts.Selectors;
dialerSubject = new Dialer(client);
dialerSelectors = Dialer.Selectors;
subject.launch();
system = new System(client);
});
teardown(function() {
subject = null;
contactsData = null;
selectors = null;
dialerSubject = null;
dialerSelectors = null;
system = null;
});
var contactData = {
givenName: ['Jose'],
familyName: ['Cantera'],
org: ['EDM'],
tel: [{
type: ['mobile'],
value: '637654321'
}]
};
function editFirstContact() {
var firstContact = client.helper.waitForElement(selectors.listContactFirst);
subject.clickOn(firstContact);
subject.waitSlideLeft('details');
var edit = client.helper.waitForElement(selectors.detailsEditContact);
subject.clickOn(edit);
subject.waitForFadeIn(client.helper.waitForElement(selectors.form));
}
function editContactPhoto() {
editFirstContact();
var photoChangeButton = client.helper.waitForElement(
selectors.formPhotoButton);
subject.clickOn(photoChangeButton);
}
suite('> Add Contact', function() {
test('Add a simple contact', function() {
var givenName = 'Hello';
var familyName = 'World';
subject.addContact({
givenName: givenName,
familyName: familyName
});
var listView = client.helper.waitForElement(selectors.list);
assert.ok(listView.displayed(), 'List view is shown.');
var listElementText = client.helper.waitForElement(
selectors.listContactFirst).text();
assert.notEqual(listElementText.indexOf(givenName), -1);
assert.notEqual(listElementText.indexOf(familyName), -1);
});
});
suite('> Edit Contact', function() {
test('Simple edition of contact details. ORG field', function() {
contactsData.createMozContact(contactData);
editFirstContact();
client.helper.waitForElement(selectors.formOrg).sendKeys('v2');
client.helper.waitForElement(selectors.formSave).click();
subject.waitForFadeIn(client.helper.waitForElement(selectors.details));
var edit = client.helper.waitForElement(selectors.detailsEditContact);
subject.clickOn(edit);
subject.waitForFadeIn(client.helper.waitForElement(selectors.form));
var orgField = client.helper.waitForElement(selectors.formOrg);
var orgFieldValue = orgField.getAttribute('value');
assert.ok(orgFieldValue.trim() === 'v2EDM');
});
test('Can create custom label', function() {
contactsData.createMozContact(contactData);
editFirstContact();
client.helper.waitForElement(selectors.formTelLabelFirst).click();
subject.waitSlideLeft('formCustomTagPage');
client.helper.waitForElement(selectors.formCustomTag).sendKeys('BFF');
client.helper.waitForElement(selectors.formCustomTagDone).click();
// Wait for the custom tag page to disappear
var bodyWidth = client.findElement(selectors.body).size().width;
client.waitFor(function waiting() {
var tagPage = client.findElement(selectors.formCustomTagPage);
var location = tagPage.location();
return location.x >= bodyWidth;
});
client.findElement(selectors.formSave).click();
subject.waitForFadeIn(client.helper.waitForElement(selectors.details));
client.helper.waitForElement(selectors.detailsTelLabelFirst);
client.waitFor(function waiting() {
var label = client.helper.
waitForElement(selectors.detailsTelLabelFirst);
return label.text() === 'BFF';
});
assert.ok(true, 'custom label is updated.');
});
suite('> Edit Contact Photo', function() {
setup(function() {
// We create a mozContact with a photo
contactsData.createMozContact(contactData, true);
});
function areRemoveAndChangePresent() {
return client.executeScript(function(selector) {
var buttons = document.querySelectorAll(selector);
var out = 0;
for(var j = 0; j < buttons.length; j++) {
if (buttons[j].textContent === 'Remove photo') {
out++;
}
if (buttons[j].textContent === 'Change photo') {
out++;
}
}
return out === 2;
}, ['#value-menu button']);
}
test('Edit regular Contact with image', function() {
editContactPhoto();
client.helper.waitForElement(selectors.actionMenu);
assert.ok(areRemoveAndChangePresent());
});
});
suite('> Adding and removing', function() {
test('Template ids unique', function() {
var data = {
givenName: ['John'],
familyName: ['Doe'],
tel: [{
type: ['mobile'],
value: '1111111'
}, {
type: ['mobile'],
value: '222222'
}]
};
contactsData.createMozContact(data);
editFirstContact();
// Delete the first phone and click on add a new phone
client.helper.waitForElement(selectors.formDelFirstTel).click();
client.helper.waitForElement(selectors.formAddNewTel).click();
client.helper.waitForElement(selectors.formSave).click();
subject.waitForFadeIn(client.helper.waitForElement(selectors.details));
var phoneList = client.findElements(selectors.formTel);
assert.equal(phoneList.length, 2);
assert.equal(phoneList[1].getAttribute('id'), 'number_2');
});
});
/* XXX Bug 1139799 - Enable test for Bug 1116889
suite('> Discard edited contact photo', function() {
setup(function() {
// Create a contact without photo
contactsData.createMozContact(contactData, false);
client.switchToFrame();
// This test makes use of gallery images, so we need to populate
// the pictures folder with test images and launch the gallery app
// to make sure that it scans the images properly.
client.fileManager.add({
type: 'pictures',
filePath: 'test_media/Pictures/firefoxOS.png'
});
var gallery = new Gallery(client);
gallery.launch();
client.apps.close(Gallery.ORIGIN);
client.switchToFrame();
subject.launch();
});
test('Select photo and discard it', function() {
// Select first contact and click on the edit button.
editFirstContact();
// Check that we have no photo for this contact.
var photoBeforeEdit =
client.helper.waitForElement(selectors.formPhotoImg);
assert.ok(photoBeforeEdit.getAttribute('style') === '');
// Click on the photo button to edit it. This triggers an activity
// selection menu.
var photoChangeButton =
client.helper.waitForElement(selectors.formPhotoButton);
subject.clickOn(photoChangeButton);
// Switch to system frame.
client.switchToFrame();
// Select gallery option on activity selector.
var gallery = system.getActivityOptionMatching('gallery');
subject.clickOn(gallery);
// Choose an image.
client.apps.switchToApp('app://gallery.gaiamobile.org');
var thumbnail = client.helper.waitForElement(selectors.galleryImage);
subject.clickOn(thumbnail);
var done =
client.helper.waitForElement(selectors.galleryDone);
subject.clickOn(done);
// Get back to contacts app.
client.switchToFrame();
client.apps.switchToApp(Contacts.URL, 'contacts');
// Discard changes.
var formHeader =
client.helper.waitForElement(selectors.formHeader);
formHeader.tap(10, 10);
subject.waitSlideLeft('details');
// Edit again.
var edit =
client.helper.waitForElement(selectors.detailsEditContact);
subject.clickOn(edit);
client.helper.waitForElement(selectors.form);
// Check that we have no photo after discarding the selection.
var photoAfterEdit =
client.helper.waitForElement(selectors.formPhotoImg);
assert.ok(photoAfterEdit.getAttribute('style') === '');
});
});
*/
});
suite('> Facebook contacts', function() {
var fbContactData;
setup(function() {
fbContactData = contactsData.createFbContact();
});
function isGalleryButtonPresent() {
return client.executeScript(function(selector) {
var buttons = document.querySelectorAll(selector);
var out = false;
for(var j = 0; j < buttons.length; j++) {
if (buttons[j].textContent === 'Gallery') {
out = true;
}
}
return out;
}, [selectors.buttonActivityChooser]);
}
test('Add phone number from Dialer to existing Facebook contact',
function() {
client.apps.close(Contacts.URL, 'contacts');
dialerSubject.launch();
var one = client.findElement(dialerSelectors.one),
two = client.findElement(dialerSelectors.two),
three = client.findElement(dialerSelectors.three);
for (var i = 0; i < 3; i++) {
one.tap();
two.tap();
three.tap();
}
var phoneNumber = dialerSubject.client.findElement(
dialerSelectors.phoneNumber);
client.waitFor(function() {
return (phoneNumber.getAttribute('value').length === 9);
});
var addContact = dialerSubject.client.findElement(
dialerSelectors.keypadCallBarAddContact);
addContact.tap();
var addToExistingContact = dialerSubject.client.helper.waitForElement(
dialerSelectors.addToExistingContactMenuItem);
addToExistingContact.tap();
client.switchToFrame();
client.apps.switchToApp(Contacts.URL, 'contacts');
client.findElement(selectors.listContactFirst).tap();
subject.waitForFormShown();
var formTelNumberSecond = client.helper.waitForElement(
selectors.formTelNumberSecond);
var formEmailFirst = client.helper.waitForElement(
selectors.formEmailFirst);
assert.equal(formTelNumberSecond.getAttribute('value'),
fbContactData.tel[0].value);
assert.equal(formEmailFirst.getAttribute('value'),
fbContactData.email[0].value);
});
test('Contact Photo cannot be removed', function() {
editContactPhoto();
// As it is a Facebook contact it should appear the activity window
// to choose the source for the image
client.switchToFrame();
client.helper.waitForElement(selectors.activityChooser);
assert.ok(isGalleryButtonPresent());
});
}); // Facebook Contacts
suite('> Input buttons', function() {
function assertClear(inputSelector) {
var input = client.helper.waitForElement(inputSelector);
input.tap();
input.sendKeys('1234');
client.findElement(inputSelector + ' + button[type="reset"]').tap();
assert.strictEqual(input.getAttribute('value'), '');
}
test('Clear buttons work as expected', function() {
contactsData.createMozContact(contactData);
editFirstContact();
var fieldSelectors = [
selectors.formGivenName,
selectors.formTelNumberFirst,
selectors.formFamilyName,
selectors.formOrg,
selectors.formEmailFirst
];
for (var i = 0, len = fieldSelectors.length; i < len; i++){
assertClear(fieldSelectors[i]);
}
});
});
});

View file

@ -0,0 +1,563 @@
'use strict';
var Contacts = require('./lib/contacts');
var ContactsData = require('./lib/contacts_data');
var assert = require('assert');
marionette('Contacts > ICE contacts', function() {
var client = marionette.client({
profile: Contacts.config,
desiredCapabilities: { raisesAccessibilityExceptions: false }
});
var contactsData = new ContactsData(client);
var actions, subject, selectors;
var testContactTelNumber = '655555555';
var testContact = {
givenName: ['Hello'],
tel: [{
type: ['mobile'],
value: testContactTelNumber
}]
};
setup(function() {
subject = new Contacts(client);
actions = client.loader.getActions();
subject.actions = actions;
subject.launch();
selectors = Contacts.Selectors;
});
function setFirstContactAsICE() {
openICESettings();
clickICESwitch(1);
var listContactFirstText =
client.helper.waitForElement(selectors.listContactFirstText);
subject.clickOn(listContactFirstText);
}
function clickICESwitch(switchNumber){
var iceSwitch =
client.helper.waitForElement(selectors['iceSwitch' + switchNumber]);
subject.clickOn(iceSwitch);
var iceButton =
client.helper.waitForElement(selectors['iceButton' + switchNumber]);
subject.clickOn(iceButton);
}
function openICESettings() {
var settingsBtn = client.helper.waitForElement(selectors.settingsButton);
subject.clickOn(settingsBtn);
var settings = client.helper.waitForElement(selectors.settingsView);
subject.waitForFadeIn(settings);
client.helper.waitForElement(selectors.setIceButton).click();
}
function addTestContact(addTelephone) {
var tel = addTelephone ? testContactTelNumber : undefined;
subject.addContact({
givenName: 'Hello',
tel: tel
});
}
function clickBackArrow() {
var contactsHeader =
client.helper.waitForElement(selectors.iceSettingsHeader);
actions.wait(0.5).tap(contactsHeader, 10, 10).perform();
}
function isIceContactsGroupHidden() {
return client.executeScript(function(selector) {
return document.querySelector(selector).classList.contains('hide');
}, [selectors.iceGroupOpen]);
}
function assertICEContact(position, name) {
var iceContact = client.helper.waitForElement(
selectors['iceButton' + position]);
assert.equal(iceContact.text(), name);
var checked = client.executeScript(function(selector) {
return document.querySelector(selector).checked;
}, [selectors['iceInputSwitch' + position]]);
assert.ok(checked);
}
function assertICEContactNotSet(position) {
var checked = client.executeScript(function(selector) {
return document.querySelector(selector).checked;
}, [selectors['iceInputSwitch' + position]]);
assert.ok(!checked);
}
// Creates a mozContact by calling the mozContacts API
function createMozContact(contactData) {
return contactsData.createMozContact(contactData);
}
function setICEContacts(iceContactsList) {
var doSetICEContacts = function(iceContactsList) {
var LazyLoader = window.wrappedJSObject.LazyLoader;
LazyLoader.load([
'/shared/js/contacts/utilities/ice_store.js',
'/contacts/js/utilities/ice_data.js',
'/shared/js/async_storage.js'
], function() {
var ICEData = window.wrappedJSObject.ICEData;
ICEData.setICEContacts(iceContactsList).then(function() {
marionetteScriptFinished(true);
}, function(error) {
console.error('Error while setting ICE ', error);
marionetteScriptFinished(false);
});
});
};
var iceContactsSet = false;
client.executeAsyncScript(doSetICEContacts, [iceContactsList],
function(err, val) {
iceContactsSet = val;
});
client.waitFor(function() {
return iceContactsSet;
});
}
function setICEContact(position, contact) {
var contactId = createMozContact(contact || testContact);
var iceContacts = [null, null];
iceContacts[position - 1] = contactId;
setICEContacts(iceContacts);
}
function createAndSetICEContacts(contactList) {
var iceList = [];
contactList.forEach(function(aContact) {
var contactId = createMozContact(aContact);
iceList.push(contactId);
});
setICEContacts(iceList);
}
suite('ICE settings', function() {
test('Check ICE settings transition', function() {
addTestContact();
openICESettings();
clickICESwitch(1);
clickBackArrow();
clickICESwitch(2);
clickBackArrow();
});
test('Clicking on ICE button does not toggle the switch', function() {
addTestContact();
openICESettings();
var iceButton1 = client.helper.waitForElement(selectors.iceButton1);
subject.clickOn(iceButton1);
var checked = client.executeScript(function(selector) {
return document.querySelector(selector).checked;
}, [selectors.iceInputSwitch1]);
assert.ok(!checked);
});
test('Select ICE contact from search, go back to ICE settings', function() {
addTestContact(true);
openICESettings();
clickICESwitch(1);
var searchLabel = client.helper.waitForElement(selectors.searchLabel);
subject.clickOn(searchLabel);
// We search for the first letter of givenName in addTestContact()
client.helper.waitForElement(selectors.searchInput).sendKeys('H');
client.helper.waitForElement(selectors.searchResultFirst).click();
clickBackArrow();
var settingsClose = client.helper.waitForElement(selectors.settingsClose);
subject.clickOn(settingsClose);
var openIce = client.helper.waitForElement(selectors.iceGroupOpen);
subject.clickOn(openIce);
var iceContact = client.helper.waitForElement(selectors.iceContact);
// 'Hello' is givenName in addTestContact()
assert.ok(iceContact.text().indexOf('Hello') >= 0,
'The name of the contact should appear as ICE contact');
});
test('ICE contacts can\'t be repeated', function() {
addTestContact(true);
setFirstContactAsICE();
clickICESwitch(2);
var listContactFirstText =
client.helper.waitForElement(selectors.listContactFirstText);
subject.clickOn(listContactFirstText);
var confirmText = client.helper.waitForElement(selectors.confirmBody)
.text();
var expectedResult = subject.l10n(
'/locales-obj/contacts.index.en-US.json',
'ICERepeatedContact');
assert.equal(confirmText, expectedResult);
});
test('Contact must have a phone number', function() {
addTestContact(false); // Added contact without phone
setFirstContactAsICE();
var confirmText = client.helper.waitForElement(selectors.confirmBody)
.text();
var expectedResult = subject.l10n(
'/locales-obj/contacts.index.en-US.json',
'ICEContactNoNumber');
assert.equal(confirmText, expectedResult);
});
});
suite('ICE contacts edition', function() {
function dismissAndGoBack() {
client.helper.waitForElement(selectors.confirmDismiss).click();
var header = client.helper.waitForElement(selectors.detailsHeader);
actions.wait(0.5).tap(header, 10, 10).perform();
}
function deleteFirstContactFirstTel() {
var firstContact =
client.helper.waitForElement(selectors.listContactFirst);
subject.clickOn(firstContact);
var edit = client.helper.waitForElement(selectors.detailsEditContact);
subject.clickOn(edit);
subject.waitForFadeIn(client.helper.waitForElement(selectors.form));
client.findElement(selectors.formDelFirstTel).click();
var save = client.findElement(selectors.formSave);
save.enabled();
save.click();
}
function closeSettings() {
var close = client.helper.waitForElement(selectors.settingsClose);
subject.clickOn(close);
}
suite('With one phone number', function() {
setup(function() {
addTestContact(true);
setFirstContactAsICE();
clickBackArrow();
closeSettings();
deleteFirstContactFirstTel();
});
test('Confirm window appears with correct message', function() {
var confirmBody = client.helper.waitForElement(selectors.confirmBody);
var expectedResult = subject.l10n(
'/locales-obj/contacts.index.en-US.json',
'ICEContactDelTelAll');
assert.equal(confirmBody.text(), expectedResult);
});
test('Contact is deleted from ICE when no numbers left', function() {
dismissAndGoBack();
openICESettings();
var iceButton1 = client.helper.waitForElement(selectors.iceButton1);
assert.ok(!iceButton1.enabled());
});
test('ICE list empty after removing phone', function() {
dismissAndGoBack();
client.helper.waitForElement(selectors.contactListHeader);
assert.ok(isIceContactsGroupHidden());
});
});
suite('With more than one phone number', function() {
test('Deleting the first number keeps the contact as ICE', function() {
var mozContact = {
tel: [
{
value: '01234',
type: ['home']
},
{
value: '56789',
type:['home']
}
],
givenName: ['Hello'],
familyName: ['World'],
name: ['Hello World']
};
createMozContact(mozContact);
setFirstContactAsICE();
clickBackArrow();
closeSettings();
deleteFirstContactFirstTel();
dismissAndGoBack();
subject.waitForFadeIn(client.helper.waitForElement(selectors.list));
openICESettings();
assertICEContact(1, mozContact.name[0]);
});
});
});
suite('ICE contacts and Merge', function() {
// Merges a duplicate contact and closes the duplicates iframe
function mergeDuplicate() {
var duplicateFrame = client.findElement(selectors.duplicateFrame);
subject.waitForSlideUp(duplicateFrame);
client.switchToFrame(duplicateFrame);
var mergeAction = client.helper.waitForElement(selectors.duplicateMerge);
subject.clickOn(mergeAction);
client.switchToFrame();
client.apps.switchToApp(Contacts.URL, 'contacts');
subject.waitForSlideDown(duplicateFrame);
}
function setTwoICEDuplicates() {
var duplicateContact = testContact;
var contactId1 = createMozContact(duplicateContact);
var contactId2 = createMozContact(duplicateContact);
setICEContacts([contactId1, contactId2]);
}
function addNewAndMatchTest(position) {
addTestContact(true);
mergeDuplicate();
// Now we go back to the ICE settings and check that our ICE remains
subject.waitForFadeIn(client.helper.waitForElement(selectors.list));
openICESettings();
assertICEContact(position, 'Hello');
}
function findDuplicatesAndMatchTest(position) {
var secondContactID = createMozContact({
givenName: ['Hello'],
tel: [{
type: ['mobile'],
value: testContactTelNumber
}]
});
var selectorForSecondContact = 'li[data-uuid="' + secondContactID + '"]';
// Going to the recently created contact
var listContactElement =
client.helper.waitForElement(selectorForSecondContact);
subject.clickOn(listContactElement);
subject.waitSlideLeft('details');
var findDups = client.helper.waitForElement(selectors.findDupsButton);
subject.clickOn(findDups);
mergeDuplicate();
subject.backToList();
openICESettings();
assertICEContact(position, 'Hello');
}
function editAndMatchTest(position) {
subject.addContact({
givenName: 'Good Bye',
tel: '+34638883074'
});
var selectorForSecondContact = 'li[data-group="G"].contact-item';
// Going to the recently created contact
var listContactElement =
client.helper.waitForElement(selectorForSecondContact);
subject.clickOn(listContactElement);
// Editing contact
subject.editContact();
// Adding a tel number equal to the tel number of 'Hello'
client.findElement(selectors.formAddNewTel).click();
client.helper.waitForElement(selectors.formTelNumberSecond).
sendKeys(testContactTelNumber);
// Saving the contact
var save = client.findElement(selectors.formSave);
save.enabled();
save.click();
mergeDuplicate();
subject.backToList();
openICESettings();
assertICEContact(position, 'Good Bye');
}
suite('> 1 ICE Contact. Position 1', function() {
setup(function() {
setICEContact(1);
});
test('> Add a new Contact that matches ICE Contact', function() {
addNewAndMatchTest(1);
assertICEContactNotSet(2);
});
test('> Find duplicates. ICE Contact Matches', function() {
findDuplicatesAndMatchTest(1);
assertICEContactNotSet(2);
});
test('> Edit existing, change data. ICE Matches. ICE changed',
function() {
editAndMatchTest(1);
assertICEContactNotSet(2);
});
});
suite('> 1 ICE Contact. Position 2', function() {
setup(function() {
setICEContact(2);
});
test('> Add a new Contact that matches ICE Contact', function() {
addNewAndMatchTest(2);
assertICEContactNotSet(1);
});
test('> Find duplicates. ICE Contact Matches', function() {
findDuplicatesAndMatchTest(2);
assertICEContactNotSet(1);
});
test('> Edit existing, change data. ICE Matches. ICE changed',
function() {
editAndMatchTest(2);
assertICEContactNotSet(1);
});
});
suite('> 2 ICE Contacts. Change position 1. Keep Position 2', function() {
setup(function() {
createAndSetICEContacts([testContact, {
givenName: ['Aufwiedersehen'],
tel: [{
type: ['mobile'],
value: '9999999'
}]
}]);
});
test('> Add a new Contact that matches ICE Contact', function() {
addNewAndMatchTest(1);
assertICEContact(2, 'Aufwiedersehen');
});
test('> Find duplicates. ICE Contact Matches', function() {
findDuplicatesAndMatchTest(1);
assertICEContact(2, 'Aufwiedersehen');
});
test('> Edit existing, change data. ICE Matches. ICE changed',
function() {
editAndMatchTest(1);
assertICEContact(2, 'Aufwiedersehen');
});
});
suite('> 2 ICE Contacts. Change position 2. Keep Position 1', function() {
setup(function() {
createAndSetICEContacts([{
givenName: ['Aufwiedersehen'],
tel: [{
type: ['mobile'],
value: '9999999'
}]
}, testContact]);
});
test('> Add a new Contact that matches ICE Contact', function() {
addNewAndMatchTest(2);
assertICEContact(1, 'Aufwiedersehen');
});
test('> Find duplicates. ICE Contact Matches', function() {
findDuplicatesAndMatchTest(2);
assertICEContact(1, 'Aufwiedersehen');
});
test('> Edit existing, change data. ICE Matches. ICE changed',
function() {
editAndMatchTest(2);
assertICEContact(1, 'Aufwiedersehen');
});
});
suite('> 2 ICE Contacts which are merged', function() {
setup(function() {
setTwoICEDuplicates();
});
test('> Two ICE Contacts are merged into 1', function() {
// Going to the recently created contact
var listContactElement =
client.helper.waitForElement(selectors.listContactFirst);
subject.clickOn(listContactElement);
subject.waitSlideLeft('details');
var findDups = client.helper.waitForElement(selectors.findDupsButton);
subject.clickOn(findDups);
mergeDuplicate();
subject.backToList();
openICESettings();
assertICEContact(1, 'Hello');
assertICEContactNotSet(2);
});
test('> A third incoming Contact merges two ICE contacts', function() {
addTestContact(true);
mergeDuplicate();
// Now we go back to the ICE settings and check that our ICE remains
subject.waitForFadeIn(client.helper.waitForElement(selectors.list));
openICESettings();
assertICEContact(1, 'Hello');
assertICEContactNotSet(2);
});
});
});
});

View file

@ -0,0 +1,55 @@
'use strict';
var Contacts = require('./lib/contacts');
var assert = require('assert');
marionette('Import from SDCARD', function() {
var profile = Contacts.config;
// Enable device storage
var prefs = ['device.storage.enabled',
'device.storage.testing',
'device.storage.prompt.testing'];
prefs.forEach(pref => {
profile[pref] = true;
});
var client = marionette.client({
profile: profile,
desiredCapabilities: { raisesAccessibilityExceptions: false }
});
var contactsApp, selectors;
setup(function() {
client.fileManager.removeAllFiles();
client.fileManager.add({
type: 'text',
filePath: 'apps/communications/contacts/test/marionette/data/vcard_4.vcf'
});
contactsApp = new Contacts(client);
contactsApp.launch();
selectors = Contacts.Selectors;
});
test('> one contact in one file', function() {
// Go to settings
client.helper.waitForElement(selectors.settingsButton).tap();
// Now click on import contacts button
client.helper.waitForElement(selectors.importContacts).tap();
client.helper.waitForElement(selectors.importSDCard).tap();
// Get back to the list
client.switchToShadowRoot(client.helper
.waitForElement(selectors.importHeader));
contactsApp.clickOn(client.helper.waitForElement(selectors.actionButton));
client.switchToShadowRoot();
contactsApp.waitForFadeIn(client.helper
.waitForElement(selectors.settingsView));
client.helper.waitForElement(selectors.settingsClose).tap();
contactsApp.waitForFadeIn(client.helper.waitForElement(selectors.list));
// Check that we have 1 contact and is the one from the SD,
var firstContact = client.findElement(selectors.listContactFirstText);
assert.equal(firstContact.text(), 'Forrest Gump');
});
});

View file

@ -0,0 +1,477 @@
'use strict';
/**
* Abstraction around contacts app.
* @constructor
* @param {Marionette.Client} client for operations.
*/
function Contacts(client) {
this.client = client;
this.client.setSearchTimeout(10000);
this.actions = this.client.loader.getActions();
}
/**
* @type String Origin of contacts app
*/
Contacts.URL = 'app://communications.gaiamobile.org';
Contacts.config = {
prefs: {
'device.storage.enabled': true,
'device.storage.testing': true,
'device.storage.prompt.testing': true
}
};
Contacts.Selectors = {
body: 'body',
bodyReady: 'body .view-body',
settingsButton: '#settings-button',
confirmHeader: '#confirmation-message h1',
confirmBody: '#confirmation-message p',
confirmDismiss: '#confirmation-message menu button',
confirmDelete: '#confirmation-message .danger',
details: '#view-contact-details',
detailsEditContact: '#edit-contact-button',
detailsTelLabelFirst: '#phone-details-template-0 h2',
detailsTelButtonFirst: '.button.icon-call[data-tel]',
detailsEmail: '#contact-detail-inner #email-details-template-0 div.item',
detailsAddress: '#contact-detail-inner #address-details-template-0 div.item',
detailsOrg: '#contact-detail-inner #org-title',
detailsNote: '#contact-detail-inner #note-details-template-0',
detailsFindDuplicate: '#contact-detail-inner #find-merge-button',
detailsFavoriteButton: '#toggle-favorite',
detailsContactName: '#contact-name-title',
detailsHeader: '#details-view-header',
detailsSocialLabel: '#contact-detail-inner #details-list #social-label',
detailsSocialTemplate: '#contact-detail-inner #details-list .social-actions',
detailsCoverImage: '#cover-img',
detailsShareButton: '#contact-detail-inner #share_button',
findDupsButton: '#details-list #find-merge-button',
duplicateFrame: 'iframe[src*="matching_contacts.html"]',
duplicateHeader: '#title',
duplicateClose: '#merge-close',
duplicateMerge: '#merge-action',
exportButton: '#exportContacts button',
exportSDCard: '#export-sd-option button',
form: '#view-contact-form',
formTitle: '#contact-form-title',
formCustomTag: '#custom-tag',
formCustomTagPage: '#view-select-tag',
formCustomTagDone: '#view-select-tag #settings-done',
formNew: '#add-contact-button',
formGivenName: '#givenName',
formOrg: '#org',
formFamilyName: '#familyName',
formSave: '#save-button',
formTel: '#contacts-form-phones input[type="tel"]',
formDelFirstTel: '#add-phone-0 .img-delete-button',
formTelLabelFirst: '#tel_type_0',
formTelNumberFirst: '#number_0',
formTelNumberSecond: '#number_1',
formEmailFirst: '#email_0',
formEmailSecond: '#email_1',
formPhotoButton: '#photo-button',
formAddNewTel: '#add-new-phone',
formAddNewEmail: '#add-new-email',
formHeader: '#contact-form-header',
formPhotoImg: '#thumbnail-photo',
deleteContact: '#delete-contact',
groupList: ' #groups-list',
contacts: '#groups-list .contact-item',
list: '#view-contacts-list',
listContactFirst: 'li:not([data-group="ice"]).contact-item',
listContactFirstText: 'li:not([data-group="ice"]).contact-item p',
contactsItems: 'li:not([data-group="ice"]).contact-item p',
contactListHeader: '#contacts-list-header',
contactsIframe: '#iframe-contacts',
searchLabel: '#search-start',
searchInput: '#search-contact',
searchCancel: '#cancel-search',
searchResultFirst: '#search-list .contact-item',
scrollbar: 'nav[data-type="scrollbar"]',
overlay: 'nav[data-type="scrollbar"] p',
settingsView: '#view-settings',
settingsClose: '#settings-close',
bulkDelete: '#bulkDelete',
orderSwitch: '#settingsOrder gaia-switch',
changeOrder: '#switch',
editForm: '#selectable-form',
editMenu: '#select-all-wrapper',
selectAction: '#select-action',
selectAllButton: '#select-all',
clearOrgButton: '#clear-org',
setIceButton: '#set-ice',
iceHeader: '#ice-header',
iceSettingsHeader: '#ice-settings-header',
iceSettings: '#ice-settings',
iceSwitch1: '#ice-contacts-1-switch',
iceInputSwitch1: '#ice-contacts-1-switch input[type="checkbox"]',
iceSwitch2: '#ice-contacts-2-switch',
iceInputSwitch2: '#ice-contacts-2-switch input[type="checkbox"]',
iceButton1: '#select-ice-contact-1',
iceButton2: '#select-ice-contact-2',
iceGroupOpen: '#section-group-ice',
iceContact: '#ice-group .contact-item',
importContacts: '#importContacts',
importSDCard: '#import-sd-option button',
importHeader: '#import-settings-header',
activityChooser: 'form[data-type="action"]',
buttonActivityChooser: 'form[data-type="action"] button',
actionMenu: '#action-menu',
actionMenuList: '#value-menu',
actionButton: '.action-button',
multipleSelectSave: '#save-button',
multipleSelectStatus: '#statusMsg p',
multipleSelectList: '#multiple-select-container',
systemMenu: 'form[data-z-index-level="action-menu"]',
galleryImage: '.thumbnail img',
galleryDone: '#crop-done-button',
header: '#edit-title',
noContacts: '#no-contacts'
};
Contacts.prototype = {
/**
* Launches contacts app and focuses on frame.
*/
launch: function() {
this.client.apps.launch(Contacts.URL, 'contacts');
this.switchToApp();
this.client.helper.waitForElement(Contacts.Selectors.bodyReady);
},
relaunch: function() {
this.close();
this.launch();
},
close: function() {
this.client.apps.close(Contacts.URL, 'contacts');
},
switchToApp: function() {
this.client.switchToFrame();
// switchToApp already waits for the app to be displayed
this.client.apps.switchToApp(Contacts.URL, 'contacts');
},
switchToCreateNewContactActivity: function() {
this._switchToActivity('views/form/form.html');
},
switchToMergeInterface: function() {
this._switchToActivity('views/matching/matching_contacts.html');
},
_switchToActivity: function(href) {
this.client.switchToFrame();
// switchToActivity already waits for the app to be displayed
this.client.apps.switchToActivity(Contacts.URL, '/contacts/' + href);
},
/**
* Returns a localized string from a properties file.
* @param {String} file to open.
* @param {String} key of the string to lookup.
*/
l10n: function(file, key) {
var ast = this.client.executeScript(function(file, key) {
var xhr = new XMLHttpRequest();
var data;
xhr.open('GET', file, false); // Intentional sync
xhr.onload = function(o) {
data = JSON.parse(xhr.response);
};
xhr.send(null);
return data;
}, [file, key]);
for (var i = 0; i < ast.length; i++) {
if (ast[i].$i === key) {
return ast[i].$v;
}
}
},
waitSlideLeft: function(elementKey) {
var element = this.client.findElement(Contacts.Selectors[elementKey]),
location;
var test = function() {
location = element.location();
return location.x <= 0;
};
this.client.waitFor(test);
},
waitForSlideDown: function(element) {
var bodyHeight = this.client.findElement(Contacts.Selectors.body).
size().height;
var test = function() {
return element.location().y >= bodyHeight;
};
this.client.waitFor(test);
},
waitForSlideUp: function(element) {
var test = function() {
return element.location().y <= 0;
};
this.client.waitFor(test);
},
waitForFadeIn: function(element) {
var test = function() {
var opacity = element.cssProperty('opacity');
var pointerEvents = element.cssProperty('pointer-events');
return opacity == 1 && pointerEvents == 'auto';
};
this.client.waitFor(test);
},
waitForFormShown: function() {
var form = this.client.helper.waitForElement(Contacts.Selectors.form),
location;
var test = function() {
location = form.location();
return location.y <= 0;
};
this.client.waitFor(test);
},
waitForFormTransition: function() {
var selectors = Contacts.Selectors;
var form = this.client.findElement(selectors.form);
try {
this.client.helper.waitForElementToDisappear(form);
} catch (e) {
// When the contact details pages was created in an activity and we close
// it, we might encounter errors like "GenericError: can't access dead
// object" or 'JavaScriptError: unload was called'. So we drop them as it
// makes the tests crash.
var isKnownError = e.message.indexOf(
'GenericError: can\'t access dead object') > -1 ||
e.message.indexOf('JavaScriptError: unload was called') > -1;
if (!isKnownError) {
throw e;
}
}
},
editContact: function() {
var selectors = Contacts.Selectors;
var edit = this.client.helper.waitForElement(selectors.detailsEditContact);
this.clickOn(edit);
this.waitForFadeIn(this.client.helper.waitForElement(selectors.form));
},
// Goes back to the Contact List view from a Details view
backToList: function() {
var selectors = Contacts.Selectors;
// Now we go back to the ICE settings and check that our ICE remains
this.waitForFadeIn(this.client.helper.waitForElement(selectors.details));
var header = this.client.helper.waitForElement(selectors.detailsHeader);
this.actions.wait(0.5).tap(header, 10, 10).perform();
this.waitSlideLeft('list');
},
enterContactDetails: function(details) {
var selectors = Contacts.Selectors;
details = details || {
givenName: 'Hello',
familyName: 'Contact',
org: 'Enterprise'
};
this.waitForFormShown();
for (var i in details) {
// Camelcase details to match form.* selectors.
var key = 'form' + i.charAt(0).toUpperCase() + i.slice(1);
this.client.findElement(selectors[key])
.sendKeys(details[i]);
}
this.client.findElement(selectors.formSave).click();
},
addContact: function(details) {
var selectors = Contacts.Selectors;
var addContact = this.client.findElement(selectors.formNew);
addContact.click();
this.enterContactDetails(details);
this.waitForFormTransition();
this.client.helper.waitForElement(selectors.list);
},
mergeContact: function(details) {
var selectors = Contacts.Selectors;
var addContact = this.client.findElement(selectors.formNew);
addContact.click();
this.enterContactDetails(details);
this.switchToMergeInterface();
var duplicateFrame = this.client.findElement(selectors.duplicateFrame);
var mergeAction =
this.client.helper.waitForElement(selectors.duplicateMerge);
this.clickOn(mergeAction);
this.switchTo();
this.waitForSlideDown(duplicateFrame);
},
addContactMultipleEmails: function(details) {
var selectors = Contacts.Selectors;
var addContact = this.client.findElement(selectors.formNew);
addContact.click();
this.client.helper.waitForElement(selectors.formAddNewEmail).click();
this.enterContactDetails(details);
this.waitForFormTransition();
this.client.helper.waitForElement(selectors.list);
},
tapContact: function(contactName) {
// There are currently no way to search on the text of an HTML Element
// That's why this function do the filter and check that no more than 1
// contact has the name we look up.
var elements = this.client.findElements(Contacts.Selectors.contacts);
var contactsWithName = elements.filter(function(el) {
var data = el.text();
return data && data.indexOf(contactName) > -1;
});
if (contactsWithName.length === 1) {
contactsWithName[0].tap();
} else if (contactsWithName.length > 1) {
throw new Error('There are more than 1 contact that contains "' +
contactName + '"');
} else {
throw new Error('"' + contactName + '" was not found');
}
},
getContactFirstName: function() {
var ci = this.client.findElement(Contacts.Selectors.contactsIframe);
this.client.switchToFrame(ci);
var contactInContactList = this.client.findElement(
Contacts.Selectors.listContactFirst
);
var contactName = contactInContactList.text();
return contactName;
},
tapSave: function() {
this.client.helper.waitForElement(Contacts.Selectors.formSave).click();
},
createNewContactAndReturnToDialer: function(contactName) {
this.client.helper.waitForElement(Contacts.Selectors.formGivenName);
this.client.helper.fillInputField(
Contacts.Selectors.formGivenName, contactName
);
this.client.helper.waitForElement(Contacts.Selectors.formSave).click();
var dialer = this.client.loader.getAppClass('dialer');
dialer.switchTo();
return dialer;
},
tapUpdate: function() {
this.tapSave();
},
get systemMenu() {
var selectors = Contacts.Selectors;
// Switch to the system app first.
this.client.switchToFrame();
return this.client.helper.waitForElement(selectors.systemMenu);
},
/**
* Helper method to simulate clicks on iFrames which is not currently
* working in the Marionette JS Runner.
* @param {Marionette.Element} element The element to simulate the click on.
**/
clickOn: function(element) {
element.scriptWith(function(elementEl) {
var event = new MouseEvent('click', {
'view': window,
'bubbles': true,
'cancelable': true
});
elementEl.dispatchEvent(event);
});
},
goToSettings: function() {
this.client.helper.waitForElement(
Contacts.Selectors.settingsButton).tap();
var settings = this.client.helper.waitForElement(
Contacts.Selectors.settingsView);
this.waitForFadeIn(settings);
},
getElementStyle: function(selector, type) {
return this.client.executeScript(function(selector, type) {
return document.querySelector(selector).style[type];
}, [selector, type]);
},
getNumberOfContacts: function() {
return this.contactsNames.length;
},
get contactsNames() {
try {
var contactElements = this.client.findElements(
Contacts.Selectors.contactsItems);
return contactElements.map((element) => {
return element.text();
});
} catch(e) {
return [];
}
}
};
module.exports = Contacts;

View file

@ -0,0 +1,126 @@
'use strict';
/* globals mozContact */
var fs = require('fs');
/* This module contains Contacts Data Layer functions */
function ContactsData(client) {
this.client = client;
}
ContactsData.prototype = {
// Creates a new FB Contact
createFbContact: function() {
this.client.importScript(fs.readFileSync(__dirname +
'/../data/facebook_contact_data.js',
'utf8'));
var saveFBContact = function() {
var LazyLoader = window.wrappedJSObject.LazyLoader;
var data = window.wrappedJSObject.data;
var fb = window.wrappedJSObject.fb;
var Contacts = window.wrappedJSObject.Contacts;
var DEPS = [
'/shared/js/contacts/utilities/image_square.js'
];
Contacts.loadFacebook(function() {
LazyLoader.load(DEPS, function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/contacts/style/images/f_logo.png');
xhr.responseType = 'blob';
xhr.onload = function() {
var fbContact = new fb.Contact();
data.fbContactData.fbInfo.photo = [xhr.response];
fbContact.setData(data.fbContactData);
var savingFBContact = fbContact.save();
savingFBContact.onsuccess = function() {
marionetteScriptFinished(data.fbContactData);
};
savingFBContact.onerror = function() {
marionetteScriptFinished();
};
};
xhr.onerror = marionetteScriptFinished;
xhr.send(null);
});
});
};
var fbContactData;
this.client.executeAsyncScript(saveFBContact, function(err, val) {
if (err) {
console.error(err);
}
fbContactData = val;
});
this.client.waitFor(function() {
return fbContactData;
});
return fbContactData;
},
createMozContact: function(contactData, withPhoto) {
var saveMozContact = function(contactData, withPhoto) {
var doSave = function doSave(contactData) {
var mozContacts = navigator.mozContacts;
var handler = function handler(event) {
mozContacts.removeEventListener('contactchange', handler);
marionetteScriptFinished(event.contactID);
};
mozContacts.addEventListener('contactchange', handler);
var contact = new mozContact(contactData);
var req = mozContacts.save(contact);
req.onerror = function() {
mozContacts.removeEventListener('contactchange', handler);
marionetteScriptFinished();
};
};
if (withPhoto) {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/contacts/style/images/f_logo.png');
xhr.responseType = 'blob';
xhr.onload = function() {
contactData.photo = [xhr.response];
doSave(contactData);
};
xhr.onerror = marionetteScriptFinished;
xhr.send(null);
}
else {
doSave(contactData);
}
};
var contactID;
this.client.executeAsyncScript(saveMozContact, [contactData, withPhoto],
function(err, val) {
if (err) {
console.error(err);
}
contactID = val;
});
this.client.waitFor(function() {
return contactID;
});
return contactID;
}
};
module.exports = ContactsData;

View file

@ -0,0 +1,40 @@
'use strict';
/**
* Abstraction around sms app.
* This file can be moved to the sms app once we
* implement sms marionette tests.
* @constructor
* @param {Marionette.Client} client for operations.
*/
function Sms(client) {
this.client = client;
}
/**
* @type String Origin of sms app
*/
Sms.URL = 'app://sms.gaiamobile.org';
Sms.Selectors = {
listCompose: '#icon-add',
threadAddContact: '#messages-contact-pick-button'
};
Sms.prototype = {
/**
* Launches sms app and focuses on frame.
*/
launch: function() {
this.client.apps.launch(Sms.URL);
this.client.apps.switchToApp(Sms.URL);
this.client.helper.waitForElement('body');
},
relaunch: function() {
this.client.apps.close(Sms.URL);
this.launch();
}
};
module.exports = Sms;

View file

@ -0,0 +1,39 @@
'use strict';
/* global module */
var SELECTORS = Object.freeze({
detailsFavoriteButton: '#toggle-favorite',
detailsHeader: '#details-view-header',
details: '#view-contact-details',
list: '#view-contacts-list'
});
function ContactsDetailsAccessor(client) {
this.client = client;
}
ContactsDetailsAccessor.prototype = {
get favoritesButton() {
return this.client.helper.waitForElement(
SELECTORS.detailsFavoriteButton);
},
get detailsHeader() {
return this.client.helper.waitForElement(
SELECTORS.detailsHeader);
},
get listSelector () {
return SELECTORS.list;
},
get detailsSelector () {
return SELECTORS.details;
},
get detailsHeaderSelector () {
return SELECTORS.detailsHeader;
}
};
module.exports = ContactsDetailsAccessor;

View file

@ -0,0 +1,66 @@
'use strict';
/* global module */
var ContactsDetailsAccessor = require('./accessors');
function ContactsDetailsView(client) {
this.client = client;
this.accessors = new ContactsDetailsAccessor(client);
}
ContactsDetailsView.prototype = {
makeFavorited: function() {
this.accessors.favoritesButton.tap();
this.waitForFavorited;
},
waitForFavorited: function() {
var self = this;
this.client.waitFor(
'waitForHeaderToContainFavoriteClass', function() {
return self.accessors.detailsHeader.getAttribute(
'class').indexOf('favorite') != -1;
});
},
//TO-DO: ADD THIS TO A CONTACT VIEW BASE CLASS
backToList: function() {
this.waitForFadeIn(this.client.helper.waitForElement(
this.accessors.detailsSelector));
var header = this.client.helper.waitForElement(
this.accessors.detailsHeaderSelector);
this.client.loader.getActions().wait(0.5).tap(header, 10, 10).perform();
this.waitSlideLeftList();
},
waitSlideLeftList: function() {
var element = this.client.findElement(
this.accessors.listSelector),
location;
var test = function() {
location = element.location();
return location.x <= 0;
};
this.client.waitFor(test);
},
waitForFadeIn: function(element) {
var test = function() {
var opacity = element.cssProperty('opacity');
var pointerEvents = element.cssProperty('pointer-events');
return opacity == 1 && pointerEvents == 'auto';
};
this.client.waitFor(test);
},
backtoContactsList: function() {
this.backToList();
var ContactsListView = require('../contact-list/view');
var contactsListView = new ContactsListView(this.client);
contactsListView.accessors.firstFavorite;
return contactsListView;
}
};
module.exports = ContactsDetailsView;

View file

@ -0,0 +1,31 @@
'use strict';
/* global module */
var SELECTORS = Object.freeze({
listContactFirstText: 'li:not([data-group="ice"]).contact-item p',
listFavoritesFirstText: '#contacts-list-favorites .contact-item p',
details: '#view-contact-details'
});
function ContactsListAccessor(client) {
this.client = client;
}
ContactsListAccessor.prototype = {
get firstContact() {
return this.client.helper.waitForElement(
SELECTORS.listContactFirstText);
},
get firstFavorite() {
return this.client.helper.waitForElement(
SELECTORS.listFavoritesFirstText);
},
get detailsSelector() {
return SELECTORS.details;
}
};
module.exports = ContactsListAccessor;

View file

@ -0,0 +1,47 @@
'use strict';
/* global module */
var ContactsListAccessor = require('./accessors');
function ContactsListView(client) {
this.client = client;
this.accessors = new ContactsListAccessor(client);
}
ContactsListView.prototype = {
get firstContact() {
return this.accessors.firstContact;
},
get firstFavorite() {
return this.accessors.firstFavorite;
},
waitSlideLeftDetails: function() {
var element = this.client.findElement(
this.accessors.detailsSelector),
location;
var waitUntilPanelReachedLeftBorder = function() {
location = element.location();
return location.x <= 0;
};
this.client.waitFor(waitUntilPanelReachedLeftBorder);
},
goToContact: function() {
this.firstContact.tap();
this.waitSlideLeftDetails();
return this._createContactsDetailsView();
},
_createContactsDetailsView: function() {
var ContactsDetailsView = require('../contact-details/view');
var contactsDetailsView = new ContactsDetailsView(
this.client, this.subject);
return contactsDetailsView;
}
};
module.exports = ContactsListView;

View file

@ -0,0 +1,192 @@
'use strict';
var Contacts = require('./lib/contacts');
var ContactsData = require('./lib/contacts_data');
var assert = require('assert');
marionette('Contacts > List', function() {
var client = marionette.client({
profile: Contacts.config,
desiredCapabilities: { raisesAccessibilityExceptions: false }
});
var subject;
var selectors;
var contactsData;
var actions;
var agenda = [{ givenName: 'a' }, { givenName: 'b' }, { givenName: 'c' },
{ givenName: 'd' }, { givenName: 'e' }, { givenName: 'f' },
{ givenName: 'g' }, { givenName: 'h' }, { givenName: 'i' }];
function getNumberOfItemsVisited() {
return client.executeScript(function() {
return document.querySelectorAll('li[data-visited="true"]').length;
});
}
setup(function() {
contactsData = new ContactsData(client);
actions = client.loader.getActions();
subject = new Contacts(client);
subject.launch();
selectors = Contacts.Selectors;
});
suite('Visited contacts > ', function() {
setup(function() {
agenda.forEach(function(contact) {
subject.addContact(contact);
});
});
test('at least one has been visited by the imageLoader', function() {
assert.ok(getNumberOfItemsVisited() > 0);
});
test('number of visited is the same after leaving search view', function() {
var numItemsVisited = getNumberOfItemsVisited();
client.findElement(selectors.searchLabel).click();
client.helper.waitForElement(selectors.searchCancel).click();
assert.ok(getNumberOfItemsVisited() === numItemsVisited);
});
});
suite('List Order > ', function() {
var data = [['GG', 'E'], ['AA', 'Z'],
['XX', 'C'], ['CC', 'X'], ['EE', 'G'], ['FF', 'F'], ['HH', 'D'],
['BB', 'Y'], ['YY', 'B'], ['ZZ', 'A'], ['DD', 'H']];
setup(function() {
data.forEach(contactData => {
contactsData.createMozContact({
givenName: [contactData[0]],
familyName: [contactData[1]]
}, false);
});
});
function givenNameOrder(a, b) {
return a[0].localeCompare(b[0]);
}
function familyNameOrder(a, b) {
return a[1].localeCompare(b[1]);
}
test('Default to: given name > ', function() {
var names = subject.contactsNames;
var targetOrder = data.sort(givenNameOrder);
names.forEach((name, index) => {
assert.equal(name, targetOrder[index][0] + ' ' + targetOrder[index][1]);
});
});
test('Order by family name > ', function() {
subject.goToSettings();
// Change order
client.switchToShadowRoot(
client.helper.waitForElement(selectors.orderSwitch));
subject.clickOn(client.findElement(selectors.changeOrder));
client.switchToShadowRoot();
subject.clickOn(client.findElement(selectors.settingsClose));
subject.waitForFadeIn(client.helper.waitForElement(selectors.list));
var names = subject.contactsNames;
var targetOrder = data.sort(familyNameOrder);
names.forEach((name, index) => {
assert.equal(name, targetOrder[index][0] + ' ' + targetOrder[index][1]);
});
});
});
suite('Images in list > ', function() {
// Generates 3 contacts for each letter with image
function generateContactsWithImage() {
for(var i = 0; i < 25; i++) {
var name = '';
var character = 97 + i;
for (var j = 0; j < 3; j++) {
name += String.fromCharCode(character);
var contactData = {
givenName: [name]
};
contactsData.createMozContact(contactData, true);
}
}
}
function firstContactHasImage() {
return client.executeScript(function() {
var span = document.querySelector(
'#contacts-list-A .contact-item span');
if (!span) {
return false;
}
return span.dataset.src && span.style.backgroundImage !== null;
});
}
function firstContactHasDefaultImage() {
try {
var span = client.findElement(
'#contacts-list-A .contact-item span');
return span.cssProperty('background-image') === 'url(' +
'"app://communications.gaiamobile.org/contacts/' +
'style/images/Imagery.png")';
} catch (e) {
return false;
}
}
function checkLetterForElement(selector, letter) {
try {
var elem = client.findElement(selector);
return elem.getAttribute('data-group') === letter;
} catch (e) {
return e.toString();
}
}
suite('Default Images > ', function() {
// Moztrap: https://moztrap.mozilla.org/manage/case/14399/
test('contact with no picture show the default one', function() {
subject.addContact({givenName: 'Anthony'});
assert.ok(firstContactHasDefaultImage());
assert.ok(checkLetterForElement('span[data-type="img"]', 'A'));
});
});
suite('Contacts with images > ', function() {
setup(function() {
generateContactsWithImage();
});
test('after scrolling we keep the images', function() {
// Scroll to different sections in the list
var scrollbar = client.helper.waitForElement(
Contacts.Selectors.scrollbar);
//F
actions.press(scrollbar, 15, 100).release().perform();
client.helper.waitForElement(Contacts.Selectors.overlay);
client.helper.waitForElementToDisappear(Contacts.Selectors.overlay);
//T
actions.press(scrollbar, 15, 300).release().perform();
client.helper.waitForElement(Contacts.Selectors.overlay);
client.helper.waitForElementToDisappear(Contacts.Selectors.overlay);
//X
actions.press(scrollbar, 15, 350).release().perform();
client.helper.waitForElement(Contacts.Selectors.overlay);
client.helper.waitForElementToDisappear(Contacts.Selectors.overlay);
//A
actions.press(scrollbar, 15, 40).release().perform();
client.helper.waitForElement(Contacts.Selectors.overlay);
client.helper.waitForElementToDisappear(Contacts.Selectors.overlay);
assert.ok(firstContactHasImage());
});
});
});
});

View file

@ -0,0 +1,7 @@
[form_test.js]
[search_test.js]
[activities_test.js]
[details_test.js]
[contacts_shortcuts_test.js]
[delete_contacts_test.js]
[ice_test.js]

View file

@ -0,0 +1,77 @@
'use strict';
var Contacts = require('./lib/contacts');
var assert = require('assert');
marionette('Contacts > Merge contacts', function() {
var client = marionette.client({
profile: Contacts.config,
desiredCapabilities: { raisesAccessibilityExceptions: false }
});
var subject;
var selectors;
var aTelNumber = '655555555';
var anotherTelNumber = '655555556';
function addTestContact(name, telephone) {
subject.addContact({
givenName: name,
tel: telephone
});
}
function mergeContact(name, telephone) {
subject.mergeContact({
givenName: name,
tel: telephone
});
}
function selectAll(callback) {
// Click on settings button and wait for slide up animation
client.helper.waitForElement(selectors.settingsButton).click();
var settings = client.helper.waitForElement(selectors.settingsView);
subject.waitForSlideUp(settings);
// Click on delete button and wait for slide down animation
client.helper.waitForElement(selectors.bulkDelete).click();
subject.waitForSlideDown(settings);
var editForm = client.findElement(selectors.editForm);
editForm.displayed(callback);
}
function checkHeaderCount(expectedCount) {
client.helper.waitForElement(selectors.selectAllButton).click();
var header = client.helper.waitForElement(selectors.header);
return assert.equal(header.getAttribute('data-l10n-args'),
'{"n":' + expectedCount + '}');
}
setup(function() {
subject = new Contacts(client);
subject.launch();
selectors = Contacts.Selectors;
});
// Disabling these tests by now due to we need a way to switch to a
// different window instead of switching to an app, due to paths can
// differ.
// More info in [1].
// These test must be recovered once this bug will be landed.
// [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1140344#c9
test.skip(
'Selection count should be correct after merging contacts',
function() {
addTestContact('Contact1', aTelNumber);
addTestContact('Contact2', anotherTelNumber);
mergeContact('Contact3', anotherTelNumber);
selectAll(function() {
checkHeaderCount(2);
});
}
);
});

View file

@ -0,0 +1,60 @@
'use strict';
/* global MozActivity */
var Contacts = require('./lib/contacts');
var Sms = require('./lib/sms');
var assert = require('assert');
var fs = require('fs');
marionette('Contacts > MultipleSelect', function() {
var client = marionette.client({ profile: Contacts.config });
var subject;
var smsSubject;
var selectors;
setup(function() {
subject = new Contacts(client);
smsSubject = new Sms(client);
selectors = Contacts.Selectors;
});
suite('Import', function() {
function getNumberOfContacts(callback) {
client.executeAsyncScript(function() {
var request = navigator.mozContacts.getCount();
request.onsuccess = function() {
marionetteScriptFinished(request.result);
};
}, callback);
}
setup(function() {
smsSubject.launch();
client.executeScript(function(vCardFile) {
new MozActivity({
name: 'open',
data: {
type: 'text/vcard',
filename: 'vcard_21_multiple.vcf',
blob: new Blob([vCardFile], {type: 'text/vcard'}),
allowSave: true
}
});
}, [fs.readFileSync(__dirname + '/data/vcard_21_multiple.vcf', 'utf8')]);
var iframe = 'iframe[src="' + Contacts.URL +
'/contacts/views/vcard_load/vcard_load.html"]';
client.switchToFrame();
client.switchToFrame(client.findElement(iframe), {'focus': true});
});
test('Importing all contacts', function() {
client.helper.waitForElement(selectors.multipleSelectSave).click();
var status = client.helper.waitForElement(selectors.multipleSelectStatus);
assert.ok(status.text().indexOf('2') >= 0);
getNumberOfContacts(function(err, value) {
assert.equal(value, 2);
});
});
});
});

View file

@ -0,0 +1,76 @@
'use strict';
var Contacts = require('./lib/contacts');
var ContactsData = require('./lib/contacts_data');
var assert = require('assert');
marionette('Contacts > Search', function() {
var client = marionette.client({
profile: Contacts.config,
desiredCapabilities: { raisesAccessibilityExceptions: false }
});
var contactsData = new ContactsData(client);
var subject;
var selectors;
var testContact;
setup(function() {
subject = new Contacts(client);
subject.launch();
testContact = {
tel: [{value: '1231231234', type: ['home']}],
givenName: ['Hello'],
familyName: ['World'],
name: ['Hello World'],
email: [{value: 'hello@example.com', type: ['home']}],
adr: [{type: ['home'], pref: true, streetAddress: 'False Street 123'}],
org: ['Mozilla'],
note: ['This is a note about the contact.']
};
selectors = Contacts.Selectors;
});
suite('Search Mode', function() {
test('Can enter and exit search mode', function() {
contactsData.createMozContact(testContact);
client.helper.waitForElement(selectors.searchLabel).click();
var result = client.helper.waitForElement(selectors.searchResultFirst);
assert.ok(result.displayed(), 'Search view was not opened');
client.helper.waitForElement(selectors.searchCancel).click();
var listView = client.helper.waitForElement(selectors.list);
assert.ok(listView.displayed(), 'List view was not shown');
});
test('Search text is displayed correctly', function() {
var details = details || {
givenName: ['A%%&']
};
contactsData.createMozContact(details);
client.helper.waitForElement(selectors.searchLabel).click();
client.helper.waitForElement(selectors.searchInput).sendKeys('a');
client.helper.waitForElement(selectors.searchResultFirst).text(
function(error, textContent) {
assert.equal('A%%&', textContent);
});
});
test('Search gets updated if contact changes', function() {
contactsData.createMozContact(testContact);
client.helper.waitForElement(selectors.searchLabel).click();
client.helper.waitForElement(selectors.searchResultFirst).click();
client.helper.waitForElement(selectors.detailsEditContact).click();
subject.waitForFormShown();
client.helper.waitForElement(selectors.formGivenName).sendKeys('zzz');
client.findElement(selectors.formSave).click();
client.helper.waitForElement(selectors.detailsContactName).text(
function(error, textContent) {
assert.ok(textContent.indexOf('zzz') > -1);
});
});
});
});

View file

@ -0,0 +1,49 @@
'use strict';
var Contacts = require('./lib/contacts');
var assert = require('assert');
marionette('Contacts > Settings', function() {
var client = marionette.client({ profile: Contacts.config });
var subject;
var selectors;
var buttonSelectors;
setup(function() {
subject = new Contacts(client);
subject.launch();
selectors = Contacts.Selectors;
buttonSelectors = [selectors.exportButton, selectors.bulkDelete,
selectors.setIceButton];
});
function isDisabled(selector) {
return client.executeScript(function(selector) {
return document.querySelector(selector).disabled;
}, [selector]);
}
suite('Export, delete and ice buttons disabled', function() {
test('No contacts -> Disabled', function() {
client.findElement(selectors.settingsButton).click();
var settings = client.helper.waitForElement(selectors.settingsView);
subject.waitForSlideUp(settings);
buttonSelectors.forEach(function(selector) {
assert.ok(isDisabled(selector));
});
});
test('List not empty -> Active', function() {
subject.addContact({
givenName: 'Cristian'
});
client.helper.waitForElement(selectors.settingsButton).click();
var settings = client.helper.waitForElement(selectors.settingsView);
subject.waitForSlideUp(settings);
buttonSelectors.forEach(function(selector) {
assert.ok(!isDisabled(selector));
});
});
});
});