From 503e36d41cb6a2abc39248a3f9a9b06c89251ccc Mon Sep 17 00:00:00 2001 From: Kevin Grandon Date: Fri, 11 Oct 2013 15:14:47 -0700 Subject: [PATCH] Bug 924274 - [Contacts] Add initial marionette tests --- apps/communications/contacts/js/contacts.js | 1 + .../test/marionette/activities_test.js | 137 ++++++++++++++++ .../contacts/test/marionette/details_test.js | 43 +++++ .../contacts/test/marionette/form_test.js | 81 ++++++++++ .../contacts/test/marionette/lib/contacts.js | 153 ++++++++++++++++++ .../contacts/test/marionette/lib/dialer.js | 45 ++++++ .../contacts/test/marionette/lib/sms.js | 47 ++++++ .../contacts/test/marionette/search_test.js | 35 ++++ package.json | 2 +- 9 files changed, 543 insertions(+), 1 deletion(-) create mode 100644 apps/communications/contacts/test/marionette/activities_test.js create mode 100644 apps/communications/contacts/test/marionette/details_test.js create mode 100644 apps/communications/contacts/test/marionette/form_test.js create mode 100644 apps/communications/contacts/test/marionette/lib/contacts.js create mode 100644 apps/communications/contacts/test/marionette/lib/dialer.js create mode 100644 apps/communications/contacts/test/marionette/lib/sms.js create mode 100644 apps/communications/contacts/test/marionette/search_test.js diff --git a/apps/communications/contacts/js/contacts.js b/apps/communications/contacts/js/contacts.js index c6e9383e23eb..a50b1917a14f 100644 --- a/apps/communications/contacts/js/contacts.js +++ b/apps/communications/contacts/js/contacts.js @@ -338,6 +338,7 @@ var Contacts = (function() { if (!customTag) { customTag = document.querySelector('#custom-tag'); + customTag.addEventListener('keydown', handleCustomTag); customTag.addEventListener('touchend', handleCustomTag); } if (!customTagReset) { diff --git a/apps/communications/contacts/test/marionette/activities_test.js b/apps/communications/contacts/test/marionette/activities_test.js new file mode 100644 index 000000000000..e32a1a9d2001 --- /dev/null +++ b/apps/communications/contacts/test/marionette/activities_test.js @@ -0,0 +1,137 @@ +var Contacts = require('./lib/contacts'); +var Dialer = require('./lib/dialer'); +var Sms = require('./lib/sms'); +var assert = require('assert'); + +marionette('Contacts > Activities', function() { + var client = marionette.client(Contacts.config); + + 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('webcontacts/contact activity', function() { + test('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() { + var activity = 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' + }, true); + + client.switchToFrame(client.findElement(selectors.duplicateFrame)); + + var duplicateHeader = client.helper. + waitForElement(selectors.duplicateHeader); + var expectedResult = subject.l10n( + '/contacts/locales/matcher/matcher.en-US.properties', + 'duplicatesFoundTitle'); + + assert.equal(duplicateHeader.text(), expectedResult); + }); + }); + + suite('webcontacts/tel activity', function() { + test('Error message when no contacts', function() { + + smsSubject.launch(); + + // Launch the activity directly as mozSms has problems + // in b2g desktop. + client.executeScript(function() { + var activity = 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( + '/contacts/locales/contacts.en-US.properties', + 'noContactsActivity'); + assert.equal(confirmMsg.text(), expectedResult); + }); + + test('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() { + var activity = 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( + '/contacts/locales/contacts.en-US.properties', + 'no_contact_phones'); + assert.equal(confirmText, expectedResult); + }); + }); +}); diff --git a/apps/communications/contacts/test/marionette/details_test.js b/apps/communications/contacts/test/marionette/details_test.js new file mode 100644 index 000000000000..cc0b6bc732f1 --- /dev/null +++ b/apps/communications/contacts/test/marionette/details_test.js @@ -0,0 +1,43 @@ +var Contacts = require('./lib/contacts'); +var assert = require('assert'); + +marionette('Contacts > Details', function() { + var client = marionette.client(Contacts.config); + var subject; + var selectors; + + setup(function() { + subject = new Contacts(client); + subject.launch(); + + selectors = Contacts.Selectors; + }); + + suite('Click phone number', function() { + test('Shows error /w no sim', function() { + var tel = 1231231234; + + subject.addContact({ + givenName: 'Hello', + tel: 1231231234 + }); + + client.helper.waitForElement(selectors.listContactFirstText) + .click(); + + client.helper.waitForElement(selectors.details); + + client.helper.waitForElement(selectors.detailsTelButtonFirst) + .click(); + + var header = client.helper.waitForElement(selectors.confirmHeader); + + var expectedHeaderText = subject.l10n( + '/dialer/locales/shared.en-US.properties', + 'emergencyDialogTitle'); + + assert.equal(header.text(), expectedHeaderText); + }); + }); + +}); diff --git a/apps/communications/contacts/test/marionette/form_test.js b/apps/communications/contacts/test/marionette/form_test.js new file mode 100644 index 000000000000..e08d731de8a2 --- /dev/null +++ b/apps/communications/contacts/test/marionette/form_test.js @@ -0,0 +1,81 @@ +var Contacts = require('./lib/contacts'); +var assert = require('assert'); + +marionette('Contacts > Form', function() { + var client = marionette.client(Contacts.config); + var subject; + var selectors; + + setup(function() { + subject = new Contacts(client); + subject.launch(); + + selectors = Contacts.Selectors; + }); + + suite('Click phone number', 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); + }); + + test('Can create custom label', function() { + subject.addContact({ + givenName: 'Custom Label Test', + tel: 1231231234 + }); + + client.helper.waitForElement(selectors.listContactFirstText) + .click(); + + client.helper.waitForElement(selectors.details); + client.helper.waitForElement(selectors.detailsEditContact) + .click(); + + subject.waitForFormShown(); + + client.helper.waitForElement(selectors.formTelLabelFirst) + .click(); + + client.helper.waitForElement(selectors.formCustomTag) + .sendKeys('BFF'); + + client.helper.waitForElement(selectors.formCustomTagDone) + .click(); + + // Wait for the custom tag page to disappear + client.waitFor(function waiting() { + var tagPage = client.findElement(selectors.formCustomTagPage); + var className = tagPage.getAttribute('className'); + return className.indexOf('app-go-left-in') === -1; + }); + + client.findElement(selectors.formSave) + .click(); + + client.helper.waitForElement(selectors.detailsTelLabelFirst); + client.waitFor(function waiting() { + var label = client.findElement(selectors.detailsTelLabelFirst).text(); + return label === 'BFF'; + }); + assert.ok(true, 'custom label is updated.'); + }); + }); + +}); diff --git a/apps/communications/contacts/test/marionette/lib/contacts.js b/apps/communications/contacts/test/marionette/lib/contacts.js new file mode 100644 index 000000000000..0ba7303d98f7 --- /dev/null +++ b/apps/communications/contacts/test/marionette/lib/contacts.js @@ -0,0 +1,153 @@ +var assert = require('assert'); + +/** + * Abstraction around contacts app. + * @constructor + * @param {Marionette.Client} client for operations. + */ +function Contacts(client) { + this.client = client; + this.client.setSearchTimeout(10000); +} + +/** + * @type String Origin of contacts app + */ +Contacts.URL = 'app://communications.gaiamobile.org'; + +Contacts.config = { + settings: { + // disable keyboard ftu because it blocks our display + 'keyboard.ftu.enabled': false + } +}; + +Contacts.Selectors = { + bodyReady: 'body .view-body', + + confirmHeader: '#confirmation-message h1', + confirmBody: '#confirmation-message p', + + details: '#view-contact-details', + detailsEditContact: '#edit-contact-button', + detailsTelLabelFirst: '#phone-details-template-0 h2', + detailsTelButtonFirst: 'button.icon-call[data-tel]', + + duplicateFrame: 'iframe[src*="matching_contacts.html"]', + duplicateHeader: '#title', + + form: '#view-contact-form', + formCustomTag: '#custom-tag', + formCustomTagPage: '#view-select-tag', + formCustomTagDone: '#view-select-tag #settings-done', + formNew: '#add-contact-button', + formGivenName: '#givenName', + formFamilyName: '#familyName', + formSave: '#save-button', + formTel: '#contacts-form-phones input[type="tel"]', + formTelLabelFirst: '#tel_type_0', + + list: '#view-contacts-list', + listContactFirst: '.contact-item', + listContactFirstText: '.contact-item .contact-text', + + searchLabel: '#search-start', + searchInput: '#search-contact', + searchCancel: '#cancel-search', + searchResultFirst: '#search-list .contact-item' +}; + +/** + * @private + * @param {Marionette.Client} client for selector. + * @param {String} name of selector [its a key in Contacts.Selectors]. + */ +function findElement(client, name) { + return client.findElement(Contacts.Selectors[name]); +} + +Contacts.prototype = { + /** + * Launches contacts app and focuses on frame. + */ + launch: function() { + this.client.apps.launch(Contacts.URL, 'contacts'); + this.client.apps.switchToApp(Contacts.URL, 'contacts'); + this.client.helper.waitForElement(Contacts.Selectors.bodyReady); + }, + + relaunch: function() { + this.client.apps.close(Contacts.URL, 'contacts'); + this.launch(); + }, + + /** + * 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 string = this.client.executeScript(function(file, key) { + var xhr = new XMLHttpRequest(); + var data; + xhr.open('GET', file, false); // Intentional sync + xhr.onload = function(o) { + data = xhr.response; + }; + xhr.send(null); + return data; + }, [file, key]); + + var re = new RegExp(key + '\\s*=\\s*(.*)'); + var result = re.exec(string)[1]; + return result; + }, + + waitForFormShown: function() { + this.client.waitFor(function() { + var location = this.client.findElement(Contacts.Selectors.form) + .location(); + return location.y === 0; + }); + }, + + enterContactDetails: function(details) { + + var selectors = Contacts.Selectors; + + details = details || { + givenName: 'Hello', + familyName: 'Contact' + }; + + 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.helper.waitForElement(selectors.formSave).click(); + + this.client.waitFor(function() { + var location = client.findElement(selectors.form).location(); + return location.y >= 460; + }); + }, + + addContact: function(details) { + var selectors = Contacts.Selectors; + + var addContact = this.client.findElement(selectors.formNew); + addContact.click(); + + this.enterContactDetails(details); + + this.client.helper.waitForElement(selectors.list); + } +}; + +module.exports = Contacts; diff --git a/apps/communications/contacts/test/marionette/lib/dialer.js b/apps/communications/contacts/test/marionette/lib/dialer.js new file mode 100644 index 000000000000..2f219c946357 --- /dev/null +++ b/apps/communications/contacts/test/marionette/lib/dialer.js @@ -0,0 +1,45 @@ +/** + * Abstraction around dialer app. + * This file can be moved to the dialer app once we + * implement dialer marionette tests. + * @constructor + * @param {Marionette.Client} client for operations. + */ +function Dialer(client) { + this.client = client; +} + +/** + * @type String Origin of dialer app + */ +Dialer.URL = 'app://communications.gaiamobile.org'; + +Dialer.Selectors = { +}; + +/** + * @private + * @param {Marionette.Client} client for selector. + * @param {String} name of selector [its a key in Dialer.Selectors]. + */ +function findElement(client, name) { + return client.findElement(Dialer.Selectors[name]); +} + +Dialer.prototype = { + /** + * Launches dialer app and focuses on frame. + */ + launch: function() { + this.client.apps.launch(Dialer.URL, 'dialer'); + this.client.apps.switchToApp(Dialer.URL, 'dialer'); + this.client.helper.waitForElement('body'); + }, + + relaunch: function() { + this.client.apps.close(Dialer.URL, 'dialer'); + this.launch(); + } +}; + +module.exports = Dialer; diff --git a/apps/communications/contacts/test/marionette/lib/sms.js b/apps/communications/contacts/test/marionette/lib/sms.js new file mode 100644 index 000000000000..a6d442aeec4d --- /dev/null +++ b/apps/communications/contacts/test/marionette/lib/sms.js @@ -0,0 +1,47 @@ +/** + * 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' +}; + +/** + * @private + * @param {Marionette.Client} client for selector. + * @param {String} name of selector [its a key in Sms.Selectors]. + */ +function findElement(client, name) { + return client.findElement(Sms.Selectors[name]); +} + +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; diff --git a/apps/communications/contacts/test/marionette/search_test.js b/apps/communications/contacts/test/marionette/search_test.js new file mode 100644 index 000000000000..df2d2580b557 --- /dev/null +++ b/apps/communications/contacts/test/marionette/search_test.js @@ -0,0 +1,35 @@ +var Contacts = require('./lib/contacts'); +var assert = require('assert'); + +marionette('Contacts > Search', function() { + var client = marionette.client(Contacts.config); + var subject; + var selectors; + + setup(function() { + subject = new Contacts(client); + subject.launch(); + + selectors = Contacts.Selectors; + }); + + suite('Search Mode', function() { + test('Can enter and exit search mode', function() { + + subject.addContact(); + + client.helper.waitForElement(selectors.searchLabel) + .click(); + + client.helper.waitForElement(selectors.searchInput) + .sendKeys('testme'); + + client.helper.waitForElement(selectors.searchCancel) + .click(); + + var listView = client.helper.waitForElement(selectors.list); + assert.ok(listView.displayed(), 'List view is shown.'); + }); + }); + +}); diff --git a/package.json b/package.json index 639c15d2e0f4..4a51fa156b60 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "empty-port": "~0.0.1", "jshint": "2.1.11", "mail-fakeservers": "~0.0.3", - "marionette-apps": "~0.3.1", + "marionette-apps": "~0.3.3", "marionette-client": "~1.0.1", "marionette-content-script": "0.0.0", "marionette-helper": "0.0.9",