VulpesOS/gaia/apps/sms/test/marionette/conversation_test.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

683 lines
22 KiB
JavaScript
Executable file

/* global require, marionette, setup, suite, test, __dirname */
'use strict';
var assert = require('chai').assert;
var _ = require('SMS/node_modules/lodash');
var ThreadGenerator = require('./generators/thread');
var Messages = require('./lib/messages.js');
var InboxView = require('./lib/views/inbox/view');
var Storage = require('./lib/storage.js');
var Tools = require('./lib/views/shared/tools.js');
var MessagesActivityCaller = require('./lib/messages_activity_caller.js');
var Keyboard = require('../../../keyboard/test/marionette/lib/keyboard.js');
marionette('Conversation Panel Tests', function() {
var apps = {};
apps[MessagesActivityCaller.ORIGIN] = __dirname + '/apps/activitycaller';
var client = marionette.client({
desiredCapabilities: { raisesAccessibilityExceptions: false },
profile: {
prefs: {
'focusmanager.testmode': true
},
apps: apps
}
});
var messagesApp, storage, activityCallerApp, keyboardApp;
function assertIsDisplayed(element) {
assert.isTrue(element.displayed(), 'Element should be displayed');
}
setup(function() {
messagesApp = Messages.create(client);
keyboardApp = new Keyboard(client);
storage = Storage.create(client);
activityCallerApp = MessagesActivityCaller.create(client);
client.loader.getMockManager('sms').inject([
'test_storages',
'test_blobs',
'navigator_moz_icc_manager',
'navigator_moz_mobile_message',
'navigator_moz_contacts'
]);
});
suite('General use cases', function() {
suite('Long SMS thread', function() {
var thread;
setup(function() {
thread = ThreadGenerator.generate({
numberOfMessages: 150
});
storage.setMessagesStorage([thread], ThreadGenerator.uniqueMessageId);
messagesApp.launch();
});
test('User can see all messages when scrolls up', function() {
messagesApp.Inbox.firstConversation.tap();
// Composer panel should always be visible
assertIsDisplayed(messagesApp.Composer.sendButton);
assertIsDisplayed(messagesApp.Composer.messageInput);
thread.messages.forEach(function(message) {
var messageNode = messagesApp.Conversation.findMessage(message.id);
// If node is not visible, let's just scroll up and wait until it
// becomes visible.
if (!messageNode.displayed()) {
client.waitFor(function() {
messagesApp.Conversation.scrollUp();
return messageNode.displayed();
});
}
});
assertIsDisplayed(messagesApp.Composer.sendButton);
assertIsDisplayed(messagesApp.Composer.messageInput);
});
});
suite('Long MMS thread', function() {
var thread;
var inboxView;
var attachmentScreenshot;
suiteSetup(function() {
attachmentScreenshot = Tools.loadAsset('mms-attachment.png');
});
suiteTeardown(function() {
attachmentScreenshot = null;
});
setup(function() {
thread = ThreadGenerator.generate({
numberOfMessages: 150,
baseTimestamp: Date.UTC(2015, 8, 1, 13, 40),
messageType: 'mms',
attachments: [
{ type: 'image/png', width: 10, height: 10 }
]
});
storage.setMessagesStorage([thread], ThreadGenerator.uniqueMessageId);
messagesApp.launch();
inboxView = new InboxView(client);
});
test('MMS are properly displayed after going to a subview', function() {
var conversationView = inboxView.goToConversation(thread.id);
conversationView.waitForFullRendering(thread);
var recentId = thread.messages[0].id;
var reportView = conversationView.openReport(recentId);
reportView.back();
var message = conversationView.findMessage(recentId);
var screenshot = message.attachments[0].screenshot();
assert.equal(screenshot, attachmentScreenshot);
conversationView.fakeScrollUpTo(0);
// Find the first displayed message. Displayed does not especially mean
// that we see it in the viewport, it merely means it's not "hidden"
// using CSS (eg: "display: none" here).
// I want to find the topmost already displayed message, and then scroll
// to it so that Gecko tries to load the attachment's background image.
var displayedMessage = _.find(
conversationView.messages(),
function(message) { return message.isDisplayed; }
);
conversationView.fakeScrollUpTo(0);
screenshot = displayedMessage.attachments[0].screenshot();
assert.equal(screenshot, attachmentScreenshot);
});
});
});
suite('Forward message', function() {
var smsBody = 'this is a sms body';
var mmsBody = 'this is a mms body';
var smsThread, mmsThread;
setup(function() {
smsThread = ThreadGenerator.generate({
body: smsBody
});
mmsThread = ThreadGenerator.generate({
numberOfMessages: 1,
messageType: 'mms',
participants: ['a@b.c'],
attachments: [
{ type: 'image/png', width: 10, height: 10 },
{ type: 'text/plain', content: mmsBody }
]
});
storage.setMessagesStorage(
[smsThread, mmsThread],
ThreadGenerator.uniqueMessageId
);
messagesApp.launch();
});
test('Forward a SMS', function() {
messagesApp.Inbox.findConversation(smsThread.id).tap();
// Forward message
messagesApp.contextMenu(messagesApp.Conversation.message);
messagesApp.Menu.selectAppMenuOption('Forward');
// Wait for message to be forwarded to fill out composer fields
client.waitFor(function() {
return messagesApp.Composer.messageInput.text() !== '';
});
assert.equal(
messagesApp.Composer.messageInput.text(),
smsThread.messages[0].body,
'Forwarded body is the initial body'
);
assert.equal(
messagesApp.Conversation.headerTitle.text(),
'New message',
'Header title should indicate that we are composing new message'
);
Tools.assertElementFocused(
messagesApp.NewMessage.recipientsInput,
'Recipients input should be focused'
);
});
test('Forwarding a MMS', function() {
messagesApp.Inbox.findConversation(mmsThread.id).tap();
// Forward message
messagesApp.contextMenu(messagesApp.Conversation.message);
messagesApp.Menu.selectAppMenuOption('Forward');
// Wait for message to be forwarded to fill out composer fields
client.waitFor(function() {
return messagesApp.Composer.messageInput.text() !== '';
});
assert.equal(
messagesApp.Composer.messageInput.text(),
mmsBody,
'Forwarded body is the initial body'
);
var composerAttachments = messagesApp.Composer.attachments;
assert.equal(composerAttachments.length, 1);
assert.equal(
composerAttachments[0].getAttribute('data-attachment-type'), 'img'
);
assert.equal(
messagesApp.Conversation.headerTitle.text(),
'New message',
'Header title should indicate that we are composing new message'
);
Tools.assertElementFocused(
messagesApp.NewMessage.recipientsInput,
'Recipients input should be focused'
);
});
});
suite('Action links in messages', function() {
var threads;
setup(function() {
threads = [
ThreadGenerator.generate({
participants: ['+400000'],
body: 'Call +400000 or send message to mozilla@mozilla.org'
}),
ThreadGenerator.generate({
participants: ['+100000'],
body: 'Use these numbers: +200000, +300000 or +400000'
})
];
storage.setMessagesStorage(threads, ThreadGenerator.uniqueMessageId);
storage.setContactsStorage([{
name: ['Alan Turing'],
tel: [{
value: '+300000',
type: 'Mobile'
}]
}]);
messagesApp.launch();
messagesApp.Inbox.findConversation(threads[1].id).tap();
});
test('Send message to unknown number', function() {
// Try to send message to the unknown number
var unknownNumberLink = messagesApp.Conversation.message.findElement(
'[data-dial="+200000"]'
);
unknownNumberLink.tap();
messagesApp.Menu.selectContactPromptMenuOption('Send message');
// Wait for the recipient input to be filled
var recipients = messagesApp.NewMessage.recipients;
client.waitFor(function() {
return recipients.length === 1;
});
assert.equal(recipients[0].text(), '+200000');
assert.equal(recipients[0].getAttribute('data-source'), 'manual');
Tools.assertElementFocused(
messagesApp.Composer.messageInput, 'Message input should be focused'
);
});
test('Send message to contact number', function() {
// Try to send message to number that has contact associated with it
var unknownNumberLink = messagesApp.Conversation.message.findElement(
'[data-dial="+300000"]'
);
unknownNumberLink.tap();
messagesApp.Menu.selectContactPromptMenuOption('Send message');
// Wait for the recipient input to be filled
var recipients = messagesApp.NewMessage.recipients;
client.waitFor(function() {
return recipients.length === 1;
});
assert.equal(recipients[0].text(), 'Alan Turing');
assert.equal(recipients[0].getAttribute('data-source'), 'contacts');
Tools.assertElementFocused(
messagesApp.Composer.messageInput, 'Message input should be focused'
);
});
test('Send message to thread number', function() {
// Try to send message to number that has thread associated with it
var threadNumberLink = messagesApp.Conversation.message.findElement(
'[data-dial="+400000"]'
);
threadNumberLink.tap();
messagesApp.Menu.selectContactPromptMenuOption('Send message');
// Verify that we entered the right thread
var message = messagesApp.Conversation.message;
assert.equal(
messagesApp.Conversation.getMessageContent(message).text(),
threads[0].messages[0].body
);
Tools.assertElementFocused(
messagesApp.Composer.messageInput, 'Message input should be focused'
);
});
});
suite('Retrieve MMS', function() {
var conversationView;
setup(function() {
var thread = ThreadGenerator.generate({
messageType: 'mms',
delivery: 'not-downloaded',
attachments: [
{ type: 'image/png', width: 10, height: 10 },
{ type: 'text/plain', content: 'Attachment' }
],
expiryDate: Date.now() + 100000
});
storage.setMessagesStorage([thread], ThreadGenerator.uniqueMessageId);
messagesApp.launch();
var inboxView = new InboxView(client);
conversationView = inboxView.goToConversation(thread.id);
});
test('MMS should be retrieved successfully', function() {
var notDownloadedMessage = conversationView.messages()[0];
assert.isFalse(notDownloadedMessage.isDownloaded);
assert.isFalse(notDownloadedMessage.isPending);
assert.equal(notDownloadedMessage.attachments.length, 0);
conversationView.downloadMessage(notDownloadedMessage.id);
// Now old message should be removed and new message is received.
var downloadedMessage;
client.waitFor(function() {
downloadedMessage = conversationView.findMessage(
notDownloadedMessage.id
);
return downloadedMessage && downloadedMessage.isDownloaded;
});
assert.equal(downloadedMessage.attachments.length, 1);
assert.equal(downloadedMessage.attachments[0].type, 'img');
assert.equal(downloadedMessage.content.trim(), 'Attachment');
});
});
suite('Edit Mode', function() {
var thread, conversationView;
setup(function() {
thread = ThreadGenerator.generate({
numberOfMessages: 4
});
storage.setMessagesStorage([thread], ThreadGenerator.uniqueMessageId);
messagesApp.launch();
var inboxView = new InboxView(client);
conversationView = inboxView.goToConversation(thread.id);
});
test('User can enter and exit edit mode', function () {
conversationView.enterEditMode();
conversationView.messages().forEach(function(message) {
assert.isTrue(message.isInEditMode);
});
conversationView.exitEditMode();
conversationView.messages().forEach(function(message) {
assert.isFalse(message.isInEditMode);
});
});
suite('Toggle selection button behavior', function() {
setup(function() {
conversationView.enterEditMode();
});
test('User can select/deselect all messages at once', function () {
// Selecting all messages
conversationView.toggleMessagesSelection();
conversationView.messages().forEach(function(message) {
assert.isTrue(message.isSelected);
});
assert.equal(
conversationView.toggleSelectionButtonTitle,
'Deselect all',
'Select / Deselect all button should display correct text'
);
assert.equal(
conversationView.editHeaderTitle,
'4 selected',
'Edit mode header should show correct number of messages'
);
// Deselecting all messages
conversationView.toggleMessagesSelection();
conversationView.messages().forEach(function(message) {
assert.isFalse(message.isSelected);
});
assert.equal(
conversationView.toggleSelectionButtonTitle,
'Select all',
'Select / Deselect all button should display correct text'
);
assert.equal(
conversationView.editHeaderTitle,
'Delete messages',
'Edit mode header should not indicate that any message is selected'
);
});
test('User selects a few and then selects/deselects all', function() {
// Selecting the 1st and 3rd message
var messageIndicesToSelect = [2, 0];
var messages = conversationView.messages();
messageIndicesToSelect.forEach(function(messageIndex) {
conversationView.tapOnMessage(messages[messageIndex].id);
});
conversationView.messages().forEach(function(message, index) {
if (messageIndicesToSelect.indexOf(index) >= 0) {
assert.isTrue(message.isSelected);
} else {
assert.isFalse(message.isSelected);
}
});
assert.equal(
conversationView.editHeaderTitle,
'2 selected',
'Edit mode header should show correct number of messages'
);
// Selecting all messages
conversationView.toggleMessagesSelection();
conversationView.messages().forEach(function(message) {
assert.isTrue(message.isSelected);
});
assert.equal(
conversationView.toggleSelectionButtonTitle,
'Deselect all',
'Select / Deselect all button should display correct text'
);
assert.equal(
conversationView.editHeaderTitle,
'4 selected',
'Edit mode header should show correct number of messages'
);
// Deselecting all messages
conversationView.toggleMessagesSelection();
conversationView.messages().forEach(function(message) {
assert.isFalse(message.isSelected);
});
assert.equal(
conversationView.toggleSelectionButtonTitle,
'Select all',
'Select / Deselect all button should display correct text'
);
assert.equal(
conversationView.editHeaderTitle,
'Delete messages',
'Edit mode header should not indicate that any message is selected'
);
});
test('User selects all, deselects some, selects all', function() {
// Selecting all messages
conversationView.toggleMessagesSelection();
conversationView.messages().forEach(function(message) {
assert.isTrue(message.isSelected);
});
assert.equal(
conversationView.toggleSelectionButtonTitle,
'Deselect all',
'Select / Deselect all button should display correct text'
);
assert.equal(
conversationView.editHeaderTitle,
'4 selected',
'Edit mode header should show correct number of messages'
);
// Deselecting 1st and 3rd message
var messageIndicesToDeselect = [2, 0];
var messages = conversationView.messages();
messageIndicesToDeselect.forEach(function(messageIndex) {
conversationView.tapOnMessage(messages[messageIndex].id);
});
conversationView.messages().forEach(function(message, index) {
if (messageIndicesToDeselect.indexOf(index) >= 0) {
assert.isFalse(message.isSelected);
} else {
assert.isTrue(message.isSelected);
}
});
assert.equal(
conversationView.editHeaderTitle,
'2 selected',
'Edit mode header should show correct number of messages'
);
// Selecting all messages
conversationView.toggleMessagesSelection();
conversationView.messages().forEach(function(message) {
assert.isTrue(message.isSelected);
});
assert.equal(
conversationView.toggleSelectionButtonTitle,
'Deselect all',
'Select / Deselect all button should display correct text'
);
assert.equal(
conversationView.editHeaderTitle,
'4 selected',
'Edit mode header should show correct number of messages'
);
});
});
});
suite('Add recipients from thread', function() {
var conversationView;
setup(function() {
var thread = ThreadGenerator.generate({
numberOfMessages: 1
});
storage.setMessagesStorage([thread], ThreadGenerator.uniqueMessageId);
messagesApp.launch();
var inboxView = new InboxView(client);
conversationView = inboxView.goToConversation(thread.id);
});
test('With empty composer: recipients should be kept',
function() {
var newMessageView = conversationView.includeSomeoneElse();
// this also ensure we are on Composer view
assert.equal(newMessageView.recipients, '+123',
'Recipients should be kept');
assert.equal(newMessageView.messageText, '', 'SMS text should be empty');
// add a recipient, a subject and send a mms to create a thread with
// several recipients
newMessageView.typeMessage('message2');
newMessageView.addNewRecipient('+234');
newMessageView.showSubject();
newMessageView.typeSubject('subject1');
conversationView = newMessageView.send();
newMessageView = conversationView.includeSomeoneElse();
var recipients = newMessageView.recipients;
assert.lengthOf(recipients, 2, 'There should be 2 recipients');
assert.include(recipients, '+123', '+123 should be in the recipients');
assert.include(recipients, '+234', '+234 should be in the recipients');
assert.equal(newMessageView.messageText, '', 'MMS text should be empty');
});
test('Sms being written: message and recipients should be kept',
function() {
conversationView.typeMessage('message2');
var newMessageView = conversationView.includeSomeoneElse();
assert.equal(newMessageView.recipients, '+123',
'Recipient should be +123');
assert.equal(newMessageView.messageText, 'message2',
'message text should be kept');
});
test('Mms being written: all info must be kept', function() {
conversationView.typeMessage('message2');
// add a subject
conversationView.showSubject();
conversationView.typeSubject('subject1');
var newMessageView = conversationView.includeSomeoneElse();
// assert that we kept all the infos
assert.equal(newMessageView.recipients, '+123',
'Recipient should be +123');
assert.equal(newMessageView.messageText, 'message2',
'Message text should be kept');
assert.equal(newMessageView.subject, 'subject1',
'Subject should be kept');
// let's add a recipients and send the message.
// we will have a thread with several recipients
newMessageView.addNewRecipient('+234');
conversationView = newMessageView.send();
// write another MMS
conversationView.typeMessage('message3');
conversationView.showSubject();
conversationView.typeSubject('subject2');
// add a blob
conversationView.addAttachment().choose('Messages Activity Caller')
.pickImage();
messagesApp.switchTo();
// take screenshot of current attachment to compare it later
var beforeScreenshot = conversationView
.takeComposerAttachmentScreenshot(0);
// redirect to new message to add recipients
newMessageView = conversationView.includeSomeoneElse();
// assert the content
var recipients = newMessageView.recipients;
assert.lengthOf(recipients, 2, 'There should be 2 recipients');
assert.include(recipients, '+123', '+123 should be in the recipients');
assert.include(recipients, '+234', '+234 should be in the recipients');
assert.equal(newMessageView.messageText, 'message3',
'Message text should be kept');
assert.equal(newMessageView.subject, 'subject2',
'Subject should be kept');
// hide the keyboard: when it is displayed, the attachment is hidden,
// which prevents the screenshot to be taken
client.switchToFrame();
var systemInputMgmt = client.loader.getAppClass(
'system', 'input_management'
);
systemInputMgmt.waitForKeyboardFrameDisplayed();
keyboardApp.switchTo();
keyboardApp.longPressSpaceBar(0.7);
client.switchToFrame();
// wait for the keyboard to be hidden
systemInputMgmt.waitForKeyboardFrameHidden();
messagesApp.switchTo();
assert.equal(
beforeScreenshot,
newMessageView.takeComposerAttachmentScreenshot(0)
);
});
});
});