示例#1
0
    def attach_file(self, attached_type):
        """
        This method is reponsible of attaching a certain file to an email.
        NOTE: It does not fill neither the message destinatary nor the message body
        """

        self.gallery = Gallery(self.parent)
        self.video = Video(self.parent)
        self.music = Music(self.parent)

        if attached_type == "image":
            self.UTILS.general.add_file_to_device(
                './tests/_resources/80x60.jpg')
            self.create_email_image()
            self.gallery.click_on_thumbnail_at_position_email(0)
        elif attached_type == "cameraImage":
            self.create_email_camera_image()
        elif attached_type == "video":
            self.UTILS.general.add_file_to_device(
                './tests/_resources/mpeg4.mp4')
            self.create_email_video()
            self.video.click_on_video_at_position_email(0)
        elif attached_type == "audio":
            self.UTILS.general.add_file_to_device('./tests/_resources/AMR.amr')
            self.create_email_music()
            self.music.click_on_song_email()
        else:
            msg = "FAILED: Incorrect parameter received in create_and_send_mms()"\
                ". attached_type must being image, video or audio."
            self.UTILS.test.test(False, msg)
示例#2
0
class test_main(GaiaTestCase):
    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.music = Music(self)

        self.test_msg = "Hello World"

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable(
            "phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " +
                                        self.phone_number)
        self.data_layer.delete_all_sms()

    def tearDown(self):
        self.music.tap_play()
        self.UTILS.reporting.reportResults()
        GaiaTestCase.tearDown(self)

    def test_run(self):
        # Create and Send an MMS with a audio attached.
        self.messages.create_and_send_mms("audio", [self.phone_number],
                                          self.test_msg)

        self.messages.wait_for_message()
        self.messages.verify_mms_received("audio", self.phone_number)
        self.messages.open_attached_file(DOM.Music.frame_locator)
        time.sleep(5)
        self.music.is_player_playing()
示例#3
0
class test_main(GaiaTestCase):

    test_msg = "Hello World {}".format(time.time())

    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.gallery = Gallery(self)
        self.music = Music(self)
        self.video = Video(self)

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable("phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " + self.phone_number)
        self.data_layer.delete_all_sms()
        self.UTILS.statusbar.clearAllStatusBarNotifs()
        self.expected_sizes = ["4.8", "62.3", "175.6"]
        self.expected_names = ["80x60.jpg", "30k_basic_AMR.amr", "mpeg4.3gp"]

        self.UTILS.general.add_file_to_device('./tests/_resources/80x60.jpg')
        self.UTILS.general.add_file_to_device('./tests/_resources/30k_basic_AMR.amr')
        self.UTILS.general.add_file_to_device('./tests/_resources/mpeg4.mp4')

    def tearDown(self):
        self.UTILS.general.remove_files()
        self.UTILS.reporting.reportResults()
        GaiaTestCase.tearDown(self)

    def test_run(self):

        self.messages.launch()

        self.messages.startNewSMS()
        self.messages.addNumbersInToField([self.phone_number])
        self.messages.enterSMSMsg(self.test_msg)

        self.messages.create_mms_image()
        self.gallery.click_on_thumbnail_at_position_mms(0)

        self.messages.create_mms_music()
        self.music.click_on_song_mms()

        self.messages.create_mms_video()
        self.video.click_on_video_at_position_mms(0)

        # Click send and wait for the message to be received
        self.messages.sendSMS()
        last_msg = self.messages.wait_for_message()
        attachments = self.messages.get_mms_attachments_info(last_msg)
        self.UTILS.reporting.debug("*** ATTACHMENTS: {}".format(attachments))

        # Check the names and sizes of all attachments are as expected
        for (i, att) in enumerate(attachments):
            self.UTILS.test.test(self.expected_names[i] == att["name"] and self.expected_sizes[i] == att["size"],
                                 "Attachment [{}] ({}kb)     Expected [{}] ({}kb)".\
                                 format(self.expected_names[i], self.expected_sizes[i],
                                        att["name"], att["size"]))
示例#4
0
class test_main(GaiaTestCase):

    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.music = Music(self)

        self.test_msg = "Hello World"

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable("phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " + self.phone_number)
        self.data_layer.delete_all_sms()

    def tearDown(self):
        self.music.tap_play()
        self.UTILS.reporting.reportResults()
        GaiaTestCase.tearDown(self)

    def test_run(self):
        # Create and Send an MMS with a audio attached.
        self.messages.create_and_send_mms("audio", [self.phone_number], self.test_msg)

        self.messages.wait_for_message()
        self.messages.verify_mms_received("audio", self.phone_number)
        self.messages.open_attached_file(DOM.Music.frame_locator)
        time.sleep(5)
        self.music.is_player_playing()
示例#5
0
class test_main(GaiaTestCase):

    test_msg = "Test."

    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.gallery = Gallery(self)
        self.music = Music(self)
        self.settings = Settings(self)

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable(
            "phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " +
                                        self.phone_number)

    def tearDown(self):
        self.UTILS.general.remove_files()
        self.UTILS.reporting.reportResults()
        GaiaTestCase.tearDown(self)

    def test_run(self):

        # Load files into the device.
        self.UTILS.general.add_file_to_device('./tests/_resources/imgd.jpg')
        self.UTILS.general.add_file_to_device('./tests/_resources/MP3.mp3')

        # Launch messages app.
        self.messages.launch()

        # Create a new SMS
        self.messages.startNewSMS()

        # Insert the phone number in the To field
        self.messages.addNumbersInToField([self.phone_number])

        # Create MMS.
        self.messages.enterSMSMsg(self.test_msg)

        self.messages.create_mms_image()
        self.gallery.click_on_thumbnail_at_position_mms(0)

        self.messages.create_mms_music()
        self.music.click_on_song_mms()

        # Click send and wait for the message to be received
        self.messages.sendSMS()
        self.messages.wait_for_message()
        self.messages.verify_mms_received('img', self.phone_number)
        self.messages.verify_mms_received('audio', self.phone_number)
示例#6
0
class test_main(GaiaTestCase):

    test_msg = "Test."

    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.gallery = Gallery(self)
        self.music = Music(self)
        self.settings = Settings(self)

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable("phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " + self.phone_number)

    def tearDown(self):
        self.UTILS.general.remove_files()
        self.UTILS.reporting.reportResults()
        GaiaTestCase.tearDown(self)

    def test_run(self):

        # Load files into the device.
        self.UTILS.general.add_file_to_device('./tests/_resources/imgd.jpg')
        self.UTILS.general.add_file_to_device('./tests/_resources/MP3.mp3')

        # Launch messages app.
        self.messages.launch()

        # Create a new SMS
        self.messages.startNewSMS()

        # Insert the phone number in the To field
        self.messages.addNumbersInToField([self.phone_number])

        # Create MMS.
        self.messages.enterSMSMsg(self.test_msg)

        self.messages.create_mms_image()
        self.gallery.click_on_thumbnail_at_position_mms(0)

        self.messages.create_mms_music()
        self.music.click_on_song_mms()

        # Click send and wait for the message to be received
        self.messages.sendSMS()
        self.messages.wait_for_message()
        self.messages.verify_mms_received('img', self.phone_number)
        self.messages.verify_mms_received('audio', self.phone_number)
示例#7
0
    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.gallery = Gallery(self)
        self.music = Music(self)
        self.settings = Settings(self)

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable(
            "phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " +
                                        self.phone_number)
示例#8
0
    def attach_file(self, attached_type):
        """
        This method is reponsible of attaching a certain file to an email.
        NOTE: It does not fill neither the message destinatary nor the message body
        """

        self.gallery = Gallery(self.parent)
        self.video = Video(self.parent)
        self.music = Music(self.parent)

        if attached_type == "image":
            self.UTILS.general.add_file_to_device('./tests/_resources/80x60.jpg')
            self.create_email_image()
            self.gallery.click_on_thumbnail_at_position_email(0)
        elif attached_type == "cameraImage":
            self.create_email_camera_image()
        elif attached_type == "video":
            self.UTILS.general.add_file_to_device('./tests/_resources/mpeg4.mp4')
            self.create_email_video()
            self.video.click_on_video_at_position_email(0)
        elif attached_type == "audio":
            self.UTILS.general.add_file_to_device('./tests/_resources/AMR.amr')
            self.create_email_music()
            self.music.click_on_song_email()
        else:
            msg = "FAILED: Incorrect parameter received in create_and_send_mms()"\
                ". attached_type must being image, video or audio."
            self.UTILS.test.test(False, msg)
示例#9
0
    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.music = Music(self)

        self.test_msg = "Hello World"

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable(
            "phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " +
                                        self.phone_number)
        self.data_layer.delete_all_sms()
示例#10
0
class test_main(GaiaTestCase):

    test_msg = "Hello World"

    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.gallery = Gallery(self)
        self.music = Music(self)

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable(
            "phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " +
                                        self.phone_number)

        # Load files into the device.
        self.UTILS.general.add_file_to_device('./tests/_resources/80x60.jpg')
        self.UTILS.general.add_file_to_device('./tests/_resources/AMR.amr')

    def tearDown(self):
        self.UTILS.general.remove_files()
        self.UTILS.reporting.reportResults()
        GaiaTestCase.tearDown(self)

    def test_run(self):
        self.messages.launch()

        self.messages.startNewSMS()
        self.messages.addNumbersInToField([self.phone_number])
        self.messages.enterSMSMsg(self.test_msg)
        self.messages.create_mms_image()
        self.gallery.click_on_thumbnail_at_position_mms(0)

        time.sleep(2)
        self.messages.create_mms_music()
        self.music.click_on_song_mms()

        self.messages.sendSMS()
        self.messages.wait_for_message()
        self.messages.verify_mms_received("img", self.phone_number)
        self.messages.verify_mms_received("audio", self.phone_number)
示例#11
0
class test_main(GaiaTestCase):
    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.music = Music(self)

        self.test_msg = "Hello World"

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable(
            "phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " +
                                        self.phone_number)
        self.UTILS.general.add_file_to_device('./tests/_resources/MP3.mp3')
        self.data_layer.delete_all_sms()
        self.UTILS.statusbar.clearAllStatusBarNotifs()

    def tearDown(self):
        self.UTILS.general.remove_files()
        self.UTILS.reporting.reportResults()
        GaiaTestCase.tearDown(self)

    def test_run(self):

        # Launch messages app.
        self.messages.launch()

        # Create a new SMS
        self.messages.startNewSMS()

        # Insert the phone number in the To field
        self.messages.addNumbersInToField([self.phone_number])

        # Create MMS.
        self.messages.enterSMSMsg(self.test_msg)
        self.messages.create_mms_music()
        self.music.click_on_song_mms()
        container = self.UTILS.element.getElement(
            DOM.Messages.attach_preview_video_audio_type, "Audio container")
        self.UTILS.test.test(
            container.get_attribute("data-attachment-type") == "audio",
            "Audio container found")
示例#12
0
    def setUp(self):

        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)

        self.browser = Browser(self)
        self.settings = Settings(self)
        self.download_manager = DownloadManager(self)
        self.music = Music(self)
        self.test_url = self.UTILS.general.get_config_variable(
            "download_url", "common")
        self.file_name = "GOSPEL.mp3"
        self.data_url = "{}/{}".format(self.test_url, self.file_name)

        self.connect_to_network()
        self.settings.launch()
        self.settings.downloads()
        self.download_manager.clean_downloads_list()
示例#13
0
    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.gallery = Gallery(self)
        self.music = Music(self)

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable(
            "phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " +
                                        self.phone_number)

        # Load files into the device.
        self.UTILS.general.add_file_to_device('./tests/_resources/80x60.jpg')
        self.UTILS.general.add_file_to_device('./tests/_resources/AMR.amr')
示例#14
0
    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.music = Music(self)

        self.test_msg = "Hello World"

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable(
            "phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " +
                                        self.phone_number)
        self.UTILS.general.add_file_to_device('./tests/_resources/MP3.mp3')
        self.data_layer.delete_all_sms()
        self.UTILS.statusbar.clearAllStatusBarNotifs()
示例#15
0
    def create_and_send_mms(self, attached_type, nums, m_text):

        self.gallery = Gallery(self.parent)
        self.video = Video(self.parent)
        self.music = Music(self.parent)

        self.launch()
        self.startNewSMS()
        self.addNumbersInToField(nums)
        self.enterSMSMsg(m_text)

        if attached_type == "image":
            # Add an image file
            self.UTILS.general.add_file_to_device(
                './tests/_resources/80x60.jpg')
            self.create_mms_image()
            self.gallery.click_on_thumbnail_at_position_mms(0)
        elif attached_type == "cameraImage":
            # Add an image file from camera
            self.create_mms_camera_image()
            time.sleep(3)
        elif attached_type == "video":
            # Load an video file into the device.
            self.UTILS.general.add_file_to_device(
                './tests/_resources/mpeg4.mp4')
            self.create_mms_video()
            self.video.click_on_video_at_position_mms(0)
        elif attached_type == "audio":
            # Load an video file into the device.
            self.UTILS.general.add_file_to_device('./tests/_resources/AMR.amr')
            self.create_mms_music()
            self.music.click_on_song_mms()
        else:
            # self.UTILS.reporting.logResult("info", "incorrect value received")
            msg = "FAILED: Incorrect parameter received in create_and_send_mms()"\
                ". attached_type must being image, video or audio."
            self.UTILS.test.test(False, msg)

        time.sleep(2)
        self.sendSMS()
        return self.last_sent_message_timestamp()
示例#16
0
    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.gallery = Gallery(self)
        self.music = Music(self)
        self.settings = Settings(self)

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable("phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " + self.phone_number)
示例#17
0
    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.music = Music(self)

        self.test_msg = "Hello World"

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable("phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " + self.phone_number)
        self.data_layer.delete_all_sms()
示例#18
0
class test_main(GaiaTestCase):
    def setUp(self):

        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)

        self.browser = Browser(self)
        self.settings = Settings(self)
        self.download_manager = DownloadManager(self)
        self.music = Music(self)
        self.test_url = self.UTILS.general.get_config_variable(
            "download_url", "common")
        self.file_name = "GOSPEL.mp3"
        self.data_url = "{}/{}".format(self.test_url, self.file_name)

        self.connect_to_network()
        self.settings.launch()
        self.settings.downloads()
        self.download_manager.clean_downloads_list()

    def tearDown(self):
        self.UTILS.reporting.reportResults()
        GaiaTestCase.tearDown(self)

    def test_run(self):
        self.browser.launch()
        self.browser.open_url(self.test_url)
        self.download_manager.download_file(self.file_name)
        self.UTILS.statusbar.wait_for_notification_toaster_title(
            "Download complete", timeout=60)
        time.sleep(5)

        self.apps.kill_all()
        time.sleep(2)

        self.settings.launch()
        self.settings.downloads()
        self.download_manager.open_download(self.data_url)
        self.download_manager.tap_on_open_option()

        self.UTILS.iframe.switchToFrame(*DOM.Music.frame_locator)
        time.sleep(5)

        title = self.UTILS.element.getElement(
            DOM.Music.title_song, "Getting song title in music player")
        self.UTILS.test.test(title.text in self.file_name, "Mp3 file title")

        self.UTILS.test.test(self.music.is_player_playing(),
                             "Mp3 file is being played")
示例#19
0
    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.gallery = Gallery(self)
        self.music = Music(self)
        self.video = Video(self)

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable(
            "phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " +
                                        self.phone_number)
        self.data_layer.delete_all_sms()
        self.UTILS.statusbar.clearAllStatusBarNotifs()
        self.expected_sizes = ["4.8", "62.3", "175.6"]
        self.expected_names = ["80x60.jpg", "30k_basic_AMR.amr", "mpeg4.3gp"]

        self.UTILS.general.add_file_to_device('./tests/_resources/80x60.jpg')
        self.UTILS.general.add_file_to_device(
            './tests/_resources/30k_basic_AMR.amr')
        self.UTILS.general.add_file_to_device('./tests/_resources/mpeg4.mp4')
示例#20
0
    def setUp(self):

        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)

        self.browser = Browser(self)
        self.settings = Settings(self)
        self.download_manager = DownloadManager(self)
        self.music = Music(self)
        self.test_url = self.UTILS.general.get_config_variable("download_url", "common")
        self.file_name = "GOSPEL.mp3"
        self.data_url = "{}/{}".format(self.test_url, self.file_name)

        self.connect_to_network()
        self.settings.launch()
        self.settings.downloads()
        self.download_manager.clean_downloads_list()
示例#21
0
class test_main(GaiaTestCase):

    def setUp(self):

        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)

        self.browser = Browser(self)
        self.settings = Settings(self)
        self.download_manager = DownloadManager(self)
        self.music = Music(self)
        self.test_url = self.UTILS.general.get_config_variable("download_url", "common")
        self.file_name = "GOSPEL.mp3"
        self.data_url = "{}/{}".format(self.test_url, self.file_name)

        self.connect_to_network()
        self.settings.launch()
        self.settings.downloads()
        self.download_manager.clean_downloads_list()

    def tearDown(self):
        self.UTILS.reporting.reportResults()
        GaiaTestCase.tearDown(self)

    def test_run(self):
        self.browser.launch()
        self.browser.open_url(self.test_url)
        self.download_manager.download_file(self.file_name)
        self.UTILS.statusbar.wait_for_notification_toaster_title("Download complete", timeout=60)
        time.sleep(5)

        self.apps.kill_all()
        time.sleep(2)

        self.settings.launch()
        self.settings.downloads()
        self.download_manager.open_download(self.data_url)
        self.download_manager.tap_on_open_option()

        self.UTILS.iframe.switchToFrame(*DOM.Music.frame_locator)
        time.sleep(5)

        title = self.UTILS.element.getElement(DOM.Music.title_song, "Getting song title in music player")
        self.UTILS.test.test(title.text in self.file_name, "Mp3 file title")

        self.UTILS.test.test(self.music.is_player_playing(), "Mp3 file is being played")
示例#22
0
    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.gallery = Gallery(self)
        self.music = Music(self)
        self.video = Video(self)

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable("phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " + self.phone_number)
        self.data_layer.delete_all_sms()
        self.UTILS.statusbar.clearAllStatusBarNotifs()
        self.expected_sizes = ["4.8", "62.3", "175.6"]
        self.expected_names = ["80x60.jpg", "30k_basic_AMR.amr", "mpeg4.3gp"]

        self.UTILS.general.add_file_to_device('./tests/_resources/80x60.jpg')
        self.UTILS.general.add_file_to_device('./tests/_resources/30k_basic_AMR.amr')
        self.UTILS.general.add_file_to_device('./tests/_resources/mpeg4.mp4')
示例#23
0
    def create_and_send_mms(self, attached_type, nums, m_text):

        self.gallery = Gallery(self.parent)
        self.video = Video(self.parent)
        self.music = Music(self.parent)

        self.launch()
        self.startNewSMS()
        self.addNumbersInToField(nums)
        self.enterSMSMsg(m_text)

        if attached_type == "image":
            # Add an image file
            self.UTILS.general.add_file_to_device('./tests/_resources/80x60.jpg')
            self.create_mms_image()
            self.gallery.click_on_thumbnail_at_position_mms(0)
        elif attached_type == "cameraImage":
            # Add an image file from camera
            self.create_mms_camera_image()
            time.sleep(3)
        elif attached_type == "video":
            # Load an video file into the device.
            self.UTILS.general.add_file_to_device('./tests/_resources/mpeg4.mp4')
            self.create_mms_video()
            self.video.click_on_video_at_position_mms(0)
        elif attached_type == "audio":
            # Load an video file into the device.
            self.UTILS.general.add_file_to_device('./tests/_resources/AMR.amr')
            self.create_mms_music()
            self.music.click_on_song_mms()
        else:
            # self.UTILS.reporting.logResult("info", "incorrect value received")
            msg = "FAILED: Incorrect parameter received in create_and_send_mms()"\
                ". attached_type must being image, video or audio."
            self.UTILS.test.test(False, msg)

        time.sleep(2)
        self.sendSMS()
        return self.last_sent_message_timestamp()
示例#24
0
class Email(object):

    def __init__(self, parent):
        self.apps = parent.apps
        self.data_layer = parent.data_layer
        self.parent = parent
        self.marionette = parent.marionette
        self.UTILS = parent.UTILS

    def launch(self):
        self.app = self.apps.launch(self.__class__.__name__)
        self.UTILS.element.waitForNotElements(
            DOM.GLOBAL.loading_overlay, self.__class__.__name__ + " app - loading overlay")
        return self.app

    def refresh(self):
        self.parent.wait_for_element_displayed(*DOM.Email.folder_refresh_button)
        self.marionette.find_element(*DOM.Email.folder_refresh_button).tap()

    def mails(self):
        self.refresh()
        self.wait_for_sync_completed()
        self.wait_for_message_list()
        return self.marionette.find_elements(*DOM.Email.email_entry)

    def _email_exists(self, subject):
        if subject in [mail.find_element(*DOM.Email.folder_subject_list).text for mail in self.mails()]:
            return True
        else:
            self.refresh()
            self.wait_for_sync_completed()
            self.UTILS.element.scroll_into_view(self.mails()[0])
            return False

    def get_email(self, subject):
        return filter(lambda msg: msg.find_element(*DOM.Email.folder_subject_list).text == subject, self.mails())[0]

    def wait_for_sync_completed(self):
        element = self.marionette.find_element(*DOM.Email.folder_refresh_button)
        self.parent.wait_for_condition(lambda m: element.get_attribute('data-state') == 'synchronized')

    def wait_for_folder(self, folder_name):
        self.parent.wait_for_condition(lambda m: m.find_element(*DOM.Email.folder_name).text == folder_name)

    def wait_for_email_loaded(self, subject):
        Wait(self.marionette, timeout=20, interval=5).until(
            lambda m: m.find_element(*DOM.Email.open_email_subject).text == subject)

    def wait_for_message_list(self):
        element = self.marionette.find_element(*DOM.Email.message_list_locator)
        self.parent.wait_for_condition(lambda m: element.is_displayed() and element.location['x'] == 0)

    def _create_attachment(self, locator, msg, frame_to_change):
        attach = self.UTILS.element.getElement(DOM.Email.compose_attach_btn, "Attach button")
        attach.tap()

        self.marionette.switch_to_frame()
        attacth_type = self.UTILS.element.getElement(locator, msg)
        attacth_type.tap()
        self.UTILS.iframe.switchToFrame(*frame_to_change)

    def create_email_image(self):
        self._create_attachment(DOM.Email.attach_gallery_btn, "From Gallery", DOM.Gallery.frame_locator)

    def create_email_camera_image(self):
        self._create_attachment(DOM.Email.attach_camera_btn, "From Camera", DOM.Camera.frame_locator)
        # Take a picture.
        self.camera = Camera(self.parent)
        self.camera.take_and_select_picture()
        self.UTILS.iframe.switchToFrame(*DOM.Email.frame_locator)

    def create_email_music(self):
        self._create_attachment(DOM.Email.attach_music_btn, "From Music", DOM.Music.frame_locator)

    def create_email_video(self):
        self._create_attachment(DOM.Email.attach_video_btn, "From video", DOM.Video.frame_locator)

    def attach_file(self, attached_type):
        """
        This method is reponsible of attaching a certain file to an email.
        NOTE: It does not fill neither the message destinatary nor the message body
        """

        self.gallery = Gallery(self.parent)
        self.video = Video(self.parent)
        self.music = Music(self.parent)

        if attached_type == "image":
            self.UTILS.general.add_file_to_device('./tests/_resources/80x60.jpg')
            self.create_email_image()
            self.gallery.click_on_thumbnail_at_position_email(0)
        elif attached_type == "cameraImage":
            self.create_email_camera_image()
        elif attached_type == "video":
            self.UTILS.general.add_file_to_device('./tests/_resources/mpeg4.mp4')
            self.create_email_video()
            self.video.click_on_video_at_position_email(0)
        elif attached_type == "audio":
            self.UTILS.general.add_file_to_device('./tests/_resources/AMR.amr')
            self.create_email_music()
            self.music.click_on_song_email()
        else:
            msg = "FAILED: Incorrect parameter received in create_and_send_mms()"\
                ". attached_type must being image, video or audio."
            self.UTILS.test.test(False, msg)

    def delete_email(self, subject):
        """
        Deletes the first message in this folder with this subject line.
        """
        self.open_msg(subject)

        # Press the delete button and confirm deletion.
        delete_btn = self.UTILS.element.getElementByXpath(DOM.Email.delete_this_email_btn[1])
        delete_btn.tap()
        delete_confirm = self.UTILS.element.getElement(DOM.Email.confirmation_delete_ok, "Confirmation button")
        delete_confirm.tap()

        # Refresh and check that the message is no longer in the inbox.
        self.refresh()
        self.wait_for_sync_completed()

        self.UTILS.test.test(not self._email_exists(
            subject), "Email with subject [{}] is no longer in the folder".format(subject))

    def email_is_in_folder(self, subject, timeout=60):
        self.parent.wait_for_condition(lambda m: self._email_exists(subject), timeout=timeout)
        return True

    def goto_folder_from_list(self, name):
        """
        Goto a specific folder in the folder list screen.
        """
        name = _(name)
        elem = ('xpath', DOM.Email.folder_name_xpath.format(name))
        folder_link = self.UTILS.element.getElement(elem, "Link to folder '" + name + "'")
        self.UTILS.element.scroll_into_view(folder_link)
        folder_link.tap()
        self.wait_for_folder(name)

    def open_folder(self, folder_name):
        # Check whether we're already there
        try:
            self.wait_for_folder(folder_name)
        except:
            # Open a specific mail folder (must be called from "Inbox").
            settings_menu = self.UTILS.element.getElement(DOM.Email.settings_menu_btn, "Settings menu button")
            settings_menu.tap()

            # When we're looking at the folders screen ...
            self.UTILS.element.waitForElements(
                DOM.Email.folder_list_container, "Folder list container", True, 20, False)
            self.goto_folder_from_list(folder_name)

            # Wait a while for everything to finish populating.
            self.UTILS.element.waitForNotElements(DOM.Email.folder_sync_spinner,
                                                  "Loading messages spinner", True, 60, False)

    def open_msg(self, subject):
        """
        Opens a specific email in the current folder
        (assumes we're already in the folder we want).
        """

        if self.email_is_in_folder(subject):
            mail = self.get_email(subject)
            self.UTILS.element.scroll_into_view(mail)
            mail.tap()
            self.wait_for_email_loaded(subject)
            return True
        else:
            screenshot = self.UTILS.debug.screenShotOnErr()
            self.UTILS.reporting.logResult('info', "Mail not found", screenshot)
            return False

    def _send_and_wait(self):
        send_btn = self.UTILS.element.getElement(DOM.Email.compose_send_btn, "Send button")
        send_btn.tap()

        self.UTILS.element.waitForElements(DOM.Email.toaster_sending_mail, "Sending email toaster", True, 60)
        self.UTILS.element.waitForNotElements(DOM.Email.toaster_sending_mail, "Sending email toaster", True, 60, False)
        self.UTILS.element.waitForElements(DOM.Email.toaster_sent_mail, "Email sent toaster", True, 120, False)

    def send_new_email(self, p_target, p_subject, p_message, attach=False, attached_type=None):
        """
        Compose and send a new email.
        """
        self.UTILS.reporting.logResult("info", "Getting 'compose message button'")

        compose_new_msg_btn = self.UTILS.element.getElement(DOM.Email.compose_msg_btn, "Compose button")
        time.sleep(1)
        compose_new_msg_btn.tap()

        # Put items in the corresponsing fields.
        self.parent.wait_for_element_displayed(*DOM.Email.compose_to)
        to_field = self.marionette.find_element(*DOM.Email.compose_to)
        if type(p_target) is list:
            for addr in p_target:
                to_field.send_keys(addr)
                to_field.send_keys(" ")
        else:
            to_field.send_keys(p_target)

        time.sleep(1)
        self.marionette.find_element(*DOM.Email.compose_subject).send_keys(p_subject)
        time.sleep(1)
        self.marionette.find_element(*DOM.Email.compose_msg).send_keys(p_message)
        if attach:
            self.attach_file(attached_type)

        self.send_the_email()

    def reply_msg(self, reply_message):
        """
        This method replies to a previously received message
        It assumes we already are viewing that message
        """

        # Get who sent us the email
        from_field = self.UTILS.element.getElement(DOM.Email.open_email_from, "'From' field").text

        reply_btn = self.UTILS.element.getElement(DOM.Email.reply_btn, "Reply message button")
        reply_btn.tap()

        reply_opt = self.UTILS.element.getElement(DOM.Email.reply_menu_reply, "'Reply' option button")
        reply_opt.tap()

        # Get the guy we're replying to
        to_field = self.UTILS.element.getElement(DOM.Email.compose_to_from_contacts, "[Reply] 'To' field")
        to_field = to_field.text

        # Check we're actually replying to the guy who sent us the email
        self.UTILS.test.test(to_field in from_field, "Checking we are replying correctly")

        # Write some reply content
        self.marionette.find_element(*DOM.Email.compose_msg).send_keys(reply_message)
        self.reply_the_email(from_field.split("@")[0])

    def reply_all(self, sender, reply_message):
        """
        This method replies to all recipients of a previously received message
        It assumes we already are viewing that message
        """

        # Get who sent us the email
        from_field = self.UTILS.element.getElement(DOM.Email.open_email_from, "'From' field").text

        reply_btn = self.UTILS.element.getElement(DOM.Email.reply_btn, "Reply message button")
        reply_btn.tap()

        # Now choose the "Reply all" option
        reply_opt = self.UTILS.element.getElement(DOM.Email.reply_menu_reply_all, "'Reply all' option button")
        reply_opt.tap()

        # Wait for 'compose message' header.
        self.parent.wait_for_element_displayed(*DOM.Email.compose_header, timeout=30)

        # Check the sender is not included in the 'To' field
        bubbles = self.UTILS.element.getElements(('css selector', '.cmp-to-container.cmp-addr-container .cmp-bubble-container .cmp-peep-name'),
                                                 '"To" field bubbles')
        bubbles_text = [bubble.text for bubble in bubbles]

        if sender['username'] in bubbles_text:
            self.UTILS.test.test(
                False, "Sender ({}) must not appear in the 'To field' when replying".format(sender['username']), True)

        # Write some reply content
        self.marionette.find_element(*DOM.Email.compose_msg).send_keys(reply_message)
        self.reply_the_email(from_field.split("@")[0])

    def forward_msg(self, p_target, fwd_message, attach=False, attached_type=None):
        """
        This method forward a previously received message to somebody else
        It assumes we already are viewing that message
        """

        # Get who sent us the email
        from_field = self.UTILS.element.getElement(DOM.Email.open_email_from, "'From' field").text

        reply_btn = self.UTILS.element.getElement(DOM.Email.reply_btn, "Reply message button")
        reply_btn.tap()

        # Now choose the "Forward" option
        fw_opt = self.UTILS.element.getElement(DOM.Email.reply_menu_forward, "'Forward' option button")
        fw_opt.tap()

        # Wait for 'compose message' header.
        self.parent.wait_for_element_displayed(*DOM.Email.compose_header, timeout=30)

        # Put items in the corresponding fields.
        self.parent.wait_for_element_displayed(*DOM.Email.compose_to)
        to_field = self.marionette.find_element(*DOM.Email.compose_to)
        if type(p_target) is list:
            for addr in p_target:
                to_field.send_keys(addr)
                to_field.send_keys(" ")
        else:
            to_field.send_keys(p_target)

        # Write some reply content
        self.marionette.find_element(*DOM.Email.compose_msg).send_keys(fwd_message)
        if attach:
            self.attach_file(attached_type)
        self.reply_the_email(from_field.split("@")[0])

    def reply_the_email(self, sender_name):
        """
        Hits the 'Send' button to reply to the message (handles
        waiting for the correct elements etc...).
        """
        self._send_and_wait()
        sender_header = ('xpath', DOM.GLOBAL.app_head_specific.format(sender_name))
        self.UTILS.element.waitForElements(sender_header, "Previous received message", True, 120)

    def send_the_email(self):
        """
        Hits the 'Send' button to send the message (handles
        waiting for the correct elements etc...).
        """
        self._send_and_wait()
        self.wait_for_folder(_("Inbox"))

    def send_the_email_and_switch_frame(self, header, frame_locator):
        send_btn = self.UTILS.element.getElement(DOM.Email.compose_send_btn, "Send button")
        send_btn.tap()
        app_header = ('xpath', DOM.GLOBAL.app_head_specific.format(header))
        self.UTILS.iframe.switchToFrame(*frame_locator)
        self.UTILS.element.waitForElements(app_header, header, True, 120)

    def setup_account_active_sync(self, user, email, passwd, hostname):
        """
        Set up a new ActiveSync account manually
        """
        if not self.no_existing_account(email):
            return

        # (At this point we are now in the 'New account' screen by one path or another.)
        self.marionette.find_element(*DOM.Email.username).send_keys(user)
        self.marionette.find_element(*DOM.Email.email_addr).send_keys(email)

        # Now tap on Manual setUp
        manual_setup = self.UTILS.element.getElement(DOM.Email.manual_setup, "Manual setup button")
        manual_setup.tap()

        # Check that we are indeed setting up an account manually
        self.UTILS.element.waitForElements(DOM.Email.manual_setup_sup_header, "Manual setup header", True, 5)

        # Change the account type to ActiveSync
        account_type = self.UTILS.element.getElement(DOM.Email.manual_setup_account_type, "Account type select")
        account_type.tap()

        # Change to top frame is needed in order to be able of choosing an option
        self.marionette.switch_to_frame()
        self.UTILS.element.waitForElements(DOM.Email.manual_setup_account_options, "Account type options", True, 5)
        # Select active sync
        elem = (DOM.Email.manual_setup_account_option[0],
                DOM.Email.manual_setup_account_option[1].format("ActiveSync"))
        active_sync = self.UTILS.element.getElement(elem, "ActiveSync option")
        active_sync.tap()

        # Confirm
        ok_btn = self.UTILS.element.getElement(DOM.Email.manual_setup_account_type_ok, "Ok button")
        ok_btn.tap()

        # Going back to Email frame
        self.apps.switch_to_displayed_app()

        # Finish setting things up
        self.marionette.find_element(*DOM.Email.password).send_keys(passwd)
        time.sleep(1)
        self.marionette.find_element(*DOM.Email.manual_setup_activesync_host).send_keys(hostname)
        time.sleep(1)
        self.marionette.find_element(*DOM.Email.manual_setup_activesync_user).send_keys(user)
        time.sleep(1)

        manual_next_btn = self.UTILS.element.getElement(
            DOM.Email.manual_setup_next, "Manual Setup 'Next' button", True, 60)
        manual_next_btn.tap()

        manual_prefs_btn = self.UTILS.element.getElement(
            DOM.Email.login_account_prefs_next_btn, "Next button", True, 60)
        manual_prefs_btn.tap()

        # Click the 'continue to mail' button.
        manual_continue_btn = self.UTILS.element.getElement(
            DOM.Email.login_cont_to_email_btn, "'Continue to mail' button", True, 60)
        manual_continue_btn.tap()

        self.UTILS.element.waitForNotElements(DOM.Email.login_cont_to_email_btn, "'Continue to mail' button")
        self.wait_for_folder(_("Inbox"))

    def setup_account(self, user, email, passwd, via_activity=False):
        """
        Set up a new email account in the email app and login.
        """

        # TODO - There's some kind of malfunctioning here. It assumes that I've already set an account. If I close the
        # email app, wait 2 secs, an open it back again, in the beginning, it shows the setup menu, but after 2-3
        # seconds it takes us back to inbox of the registered account, which should be the default behavior.

        time.sleep(5)
        if not self.no_existing_account(email):
            return

        # At this point we are now in the 'New account' screen by one path or another
        username_field = self._get_field(DOM.Email.username)
        username_field.send_keys(user)

        email_field = self._get_field(DOM.Email.email_addr)
        email_field.send_keys(email)

        self.tap_next_account_info()

        domain = re.search('[a-zA-Z0-9+_\-\.]+@([0-9a-zA-Z][.-0-9a-zA-Z]*).[a-zA-Z]+', email).group(1)
        if 'gmail' in domain:
            self.switch_to_gmail_frame(email)
            self.gmail_login(passwd)
            self.wait_for_gmail_approve_access()
            self.tap_gmail_approve_access()
        elif 'hotmail' or 'msn' or 'outlook' in domain:
            self.setup_hotmail_account(email, passwd)

        self.apps.switch_to_displayed_app()
        self.tap_next_account_preferences()
        self.tap_continue_to_mail()

        if not via_activity:
            self.wait_for_folder(_("Inbox"))
            self.wait_for_sync_completed()
            self.wait_for_message_list()

    def setup_account_first_step(self, user, email):
        """
        Set up a new email account in the email app and login.
        If we've just started out, email will open directly to "New Account").
        """
        if not self.no_existing_account(email):
            return

        # (At this point we are now in the 'New account' screen by one path or another.)
        self.marionette.find_element(*DOM.Email.username).send_keys(user)
        self.marionette.find_element(*DOM.Email.email_addr).send_keys(email)
        self.tap_next_account_info()

    def no_existing_account(self, email):
        """
        Check if the new account header is present
        """
        try:
            self.parent.wait_for_element_displayed(*DOM.Email.setup_account_header)
            self.marionette.find_element(*DOM.Email.setup_account_header)
            return True
        except:

            #  If exception raised --> other account has been alread set up
            self.UTILS.reporting.logResult("info", "It is necessary to switch to another email account.")

            if self.switch_account(email):
                return False

            # It's not setup already, so prepare to set it up!
            set_settings = self.UTILS.element.getElement(DOM.Email.settings_set_btn, "Settings set button")
            set_settings.tap()

            add_account_btn = self.UTILS.element.getElement(DOM.Email.settings_add_account_btn, "Add account button")
            time.sleep(2)
            add_account_btn.tap()
            return True

    def switch_account(self, address):
        settings_menu = self.UTILS.element.getElement(DOM.Email.settings_menu_btn, "Settings menu button")
        settings_menu.tap()

        try:
            self.UTILS.reporting.logResult("info", "First, check whether we have one account configured or MORE")
            self.parent.wait_for_element_displayed(*DOM.Email.switch_account_panel_one_account)
            self.UTILS.reporting.logResult("info", "There's only a single account configured. Time to check if\
                                                        it's necessary to do the change")
            try:
                self.parent.wait_for_element_present(*DOM.Email.switch_account_current_account)
                current_account = self.marionette.find_element(*DOM.Email.switch_account_current_account)
                """
                Since the element is not displayed, sometimes we cannot access to the text using .text
                This way is more secure
                """
                current_account_text = self.marionette.execute_script(
                    "return arguments[0].innerHTML", script_args=[current_account])

                self.UTILS.reporting.logResult('info', "Current account: {}".format(current_account_text))
                self.UTILS.reporting.logResult('info', "Account to switch: {}".format(address))

                screenshot = self.UTILS.debug.screenShotOnErr()
                self.UTILS.reporting.logResult('info', "Screenshot", screenshot)

                if current_account_text == address:
                    self.UTILS.reporting.logResult("info", "Already in the account we want - switch back to inbox.")
                    self.goto_folder_from_list(_("Inbox"))
                    return True
                else:
                    self.UTILS.reporting.logResult(
                        "info", "It looks like the account we want to switch is not set up yet, so we cannot switch to it")
                    return False
            except:
                self.UTILS.reporting.logResult("info", "ONE ACCOUNT - something went wrong")

        except:
            self.UTILS.reporting.logResult("info", "Well, we have at least 2 accounts configured")

            self.UTILS.reporting.logResult("info", "Checking whether exists a scroll containing different accounts")
            self.parent.wait_for_element_displayed(*DOM.Email.switch_account_scroll_outer)

            self.UTILS.reporting.logResult("info", "Check if the current account is the one we we want to change")
            self.parent.wait_for_element_displayed(*DOM.Email.switch_account_current_account)
            current_account = self.marionette.find_element(*DOM.Email.switch_account_current_account)

            if current_account.text == address:
                self.UTILS.reporting.logResult("info", "Already in the account we want - switch back to inbox.")
                self.goto_folder_from_list(_("Inbox"))
                return True

            self.UTILS.reporting.logResult(
                "info", "We're not in the account we want to be, so open the scroll to see what's there")

            self.parent.wait_for_element_displayed(*DOM.Email.switch_account_scroll)
            scroll = self.marionette.find_element(*DOM.Email.switch_account_scroll)
            scroll.tap()

            self.UTILS.reporting.logResult(
                "info", "Now we have to iterate over all accounts displayed (but not already selected)")
            self.parent.wait_for_element_displayed(*DOM.Email.switch_account_accounts_to_change)
            accounts = self.marionette.find_elements(*DOM.Email.switch_account_accounts_to_change)

            for account in accounts:
                if account.text == address:
                    self.UTILS.reporting.logResult(
                        "info", "We got a winner. Switching to already configured account...")
                    account.tap()
                    self.wait_for_folder(_("Inbox"))
                    return True

            self.UTILS.reporting.logResult(
                "info", "It looks like the account we want to switch is not set up yet, so we cannot switch to it")
            return False

    def switch_to_gmail_frame(self, expected_email):
        """
        Switches to gmail login frame when trying to set up a gmail account
        """
        gmail_frame = self.parent.wait_for_element_present(*DOM.Email.gmail_iframe_locator)
        self.marionette.switch_to_frame(gmail_frame)

        # Make sure the page is loaded
        email = self.parent.wait_for_element_present(*DOM.Email.gmail_email_locator)
        self.parent.wait_for_condition(lambda m: email.get_attribute('value') == expected_email)

    def _get_field(self, locator):
        self.parent.wait_for_element_displayed(*locator)
        return self.marionette.find_element(*locator)

    def gmail_login(self, passwd):
        self.marionette.find_element(*DOM.Email.gmail_password_locator).send_keys(passwd)
        self.marionette.find_element(*DOM.Email.gmail_sign_in_locator).tap()

    def wait_for_gmail_approve_access(self):
        self.parent.wait_for_element_displayed(*DOM.Email.gmail_approve_access_locator)

    def tap_gmail_approve_access(self):
        self.parent.wait_for_condition(
            lambda m: self.marionette.find_element(*DOM.Email.gmail_approve_access_locator).is_enabled())
        self.marionette.find_element(*DOM.Email.gmail_approve_access_locator).tap()

    def tap_next_account_info(self):
        self.marionette.find_element(*DOM.Email.login_account_info_next_btn).tap()

    def tap_next_account_preferences(self):
        self.parent.wait_for_element_displayed(*DOM.Email.login_account_prefs_next_btn, timeout=120)
        self.marionette.find_element(*DOM.Email.login_account_prefs_next_btn).tap()

    def tap_continue_to_mail(self):
        self.parent.wait_for_element_displayed(*DOM.Email.login_cont_to_email_btn, timeout=20)
        continue_btn = self.marionette.find_element(*DOM.Email.login_cont_to_email_btn)
        time.sleep(1)
        continue_btn.tap()

    def setup_hotmail_account(self, expected_email, passwd):
        """
        Switches to hotmail login frame when trying to set up a gmail account
        """
        self.parent.wait_for_element_displayed(*DOM.Email.email_label_for_passwd)
        label = self.marionette.find_element(*DOM.Email.email_label_for_passwd)
        self.UTILS.test.test(label.text == expected_email, "The account remains the same: {}".format(expected_email))

        self.parent.wait_for_element_displayed(*DOM.Email.password)
        self.marionette.find_element(*DOM.Email.password).send_keys(passwd)

        self.parent.wait_for_condition(lambda m: m.find_element(*DOM.Email.login_account_passwd_next_btn).is_enabled())
        self.marionette.find_element(*DOM.Email.login_account_passwd_next_btn).tap()
示例#25
0
class test_main(GaiaTestCase):

    test_msg = "Hello World {}".format(time.time())

    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)
        self.gallery = Gallery(self)
        self.music = Music(self)
        self.video = Video(self)

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable(
            "phone_number", "custom")
        self.UTILS.reporting.logComment("Sending mms to telephone number " +
                                        self.phone_number)
        self.data_layer.delete_all_sms()
        self.UTILS.statusbar.clearAllStatusBarNotifs()
        self.expected_sizes = ["4.8", "62.3", "175.6"]
        self.expected_names = ["80x60.jpg", "30k_basic_AMR.amr", "mpeg4.3gp"]

        self.UTILS.general.add_file_to_device('./tests/_resources/80x60.jpg')
        self.UTILS.general.add_file_to_device(
            './tests/_resources/30k_basic_AMR.amr')
        self.UTILS.general.add_file_to_device('./tests/_resources/mpeg4.mp4')

    def tearDown(self):
        self.UTILS.general.remove_files()
        self.UTILS.reporting.reportResults()
        GaiaTestCase.tearDown(self)

    def test_run(self):

        self.messages.launch()

        self.messages.startNewSMS()
        self.messages.addNumbersInToField([self.phone_number])
        self.messages.enterSMSMsg(self.test_msg)

        self.messages.create_mms_image()
        self.gallery.click_on_thumbnail_at_position_mms(0)

        self.messages.create_mms_music()
        self.music.click_on_song_mms()

        self.messages.create_mms_video()
        self.video.click_on_video_at_position_mms(0)

        # Click send and wait for the message to be received
        self.messages.sendSMS()
        last_msg = self.messages.wait_for_message()
        attachments = self.messages.get_mms_attachments_info(last_msg)
        self.UTILS.reporting.debug("*** ATTACHMENTS: {}".format(attachments))

        # Check the names and sizes of all attachments are as expected
        for (i, att) in enumerate(attachments):
            self.UTILS.test.test(self.expected_names[i] == att["name"] and self.expected_sizes[i] == att["size"],
                                 "Attachment [{}] ({}kb)     Expected [{}] ({}kb)".\
                                 format(self.expected_names[i], self.expected_sizes[i],
                                        att["name"], att["size"]))
示例#26
0
class Messages(object):
    def __init__(self, parent):
        self.apps = parent.apps
        self.data_layer = parent.data_layer
        self.parent = parent
        self.marionette = parent.marionette
        self.UTILS = parent.UTILS
        self.actions = Actions(self.marionette)

    @retry(5)
    def launch(self):
        self.app = self.apps.launch(self.__class__.__name__)
        self.UTILS.element.waitForNotElements(
            DOM.GLOBAL.loading_overlay,
            self.__class__.__name__ + " app - loading overlay")
        return self.app

    def cancelSettings(self):
        self.UTILS.reporting.logResult("info",
                                       "Cliking on messages options button")
        options_btn = self.UTILS.element.getElement(
            DOM.Messages.messages_options_btn,
            "Messages option button is displayed")
        options_btn.tap()

        # Press cancel button
        cancelBtn = self.UTILS.element.getElement(DOM.Messages.cancel_btn_msg,
                                                  "Press Cancel button")
        cancelBtn.tap()

    def deleteSubject(self, subject):
        self.UTILS.reporting.logResult("info",
                                       "Cliking on messages options button")
        x = self.UTILS.element.getElement(
            DOM.Messages.messages_options_btn,
            "Messages option button is displayed")
        x.tap()

        # Press add subject button
        self.UTILS.reporting.logResult("info",
                                       "Cliking on delete subject button")
        x = self.UTILS.element.getElement(
            DOM.Messages.deletesubject_btn_msg_opt,
            "delete subject option button is displayed")
        x.tap()

    def addSubject(self, subject):
        self.UTILS.reporting.logResult("info",
                                       "Cliking on messages options button")
        x = self.UTILS.element.getElement(
            DOM.Messages.messages_options_btn,
            "Messages option button is displayed")
        x.tap()

        # Press add subject button
        screenshot = self.UTILS.debug.screenShotOnErr()
        self.UTILS.reporting.logResult('info', "Screenshot", screenshot)

        self.UTILS.reporting.logResult("info", "Cliking on add subject button")
        x = self.UTILS.element.getElement(
            DOM.Messages.addsubject_btn_msg_opt,
            "add subject option button is displayed")
        x.tap()

        self.UTILS.general.typeThis(DOM.Messages.target_subject,
                                    "Target Subject  field",
                                    subject,
                                    p_no_keyboard=True,
                                    p_validate=False,
                                    p_clear=False,
                                    p_enter=False)

    def checkAirplaneModeWarning(self):
        """
        Checks for the presence of the popup
        warning message if you just sent a message
        while in 'airplane mode' (also removes
        the message so you can continue).
        """
        x = self.UTILS.element.getElement(
            DOM.Messages.airplane_warning_message,
            "Airplane mode warning message", True, 5, False)
        if x:
            self.UTILS.reporting.logResult(
                "info", "Warning message title detected = '" + x.text + "'.")

            x = self.UTILS.element.getElement(DOM.Messages.airplane_warning_ok,
                                              "OK button")
            x.tap()

    def check_last_message_contents(self, expected, mms=False):
        """
        Get the last message text and check it against the expected value.
        """
        msg = self.last_message_in_this_thread()
        dom = DOM.Messages.last_message_mms_text if mms else DOM.Messages.last_message_text
        msg_text = self.marionette.find_element(*dom, id=msg.id)
        self.UTILS.test.test(
            (msg_text and msg_text.text == expected),
            u"Expected message text = '{}' ({}) (got '{}' ({})).".format(
                expected, len(expected), msg_text.text, len(msg_text.text)))

    def checkIsInToField(self, target, targetIsPresent=True):
        """
        Verifies if a number (or contact name) is
        displayed in the "To: " field of a compose message.<br>
        (Uses 'caseless' search for this.)
        """
        time.sleep(1)
        x = self.UTILS.element.getElements(DOM.Messages.target_numbers,
                                           "'To:' field contents", False)

        boolOK = False
        for i in x:
            if i.text.lower() == str(target).lower():
                boolOK = True
                break

        testMsg = "is" if targetIsPresent else "is not"
        testMsg = "\"" + str(target) + "\" " + testMsg + " in the 'To:' field."
        self.UTILS.test.test(boolOK == targetIsPresent, testMsg)
        return boolOK

    def checkMMSIcon(self, thread_name):

        # Get the thread for which we want to check the icon existence
        selector = ("xpath",
                    DOM.Messages.thread_selector_xpath.format(thread_name))
        elem = self.UTILS.element.getElement(
            selector, "Message thread for " + thread_name)
        """
        But, in order to make sure we're getting the specific frame, what we trully
        got above is an inner child of the thread element. So, we gotta get the father
        """
        thread = self.marionette.execute_script("""
            return arguments[0].parentNode;
        """,
                                                script_args=[elem])

        # Checks for the presence of the MMS icon
        icon = thread.find_element(*DOM.Messages.mms_icon)
        if icon:
            self.UTILS.test.test(
                icon is not None,
                "MMS icon detected for thread [{}]".format(thread_name))

    def checkNumberIsInToField(self, target):
        """
        Verifies if a number is contained in the
        "To: " field of a compose message (even if it's
        not displayed - i.e. a contact name is displayed,
        but this validates the <i>number</i> for that
        contact).
        """
        x = self.UTILS.element.getElements(DOM.Messages.target_numbers,
                                           "'To:' field contents")

        boolOK = False
        for i in x:
            if i.get_attribute("data-number") == target:
                boolOK = True
                break

        self.UTILS.test.test(
            boolOK, "\"" + str(target) +
            "\" is the number in one of the 'To:' field targets.")
        return boolOK

    def checkThreadHeader(self, header):
        """
        Verifies if a string is contained in the header
        """
        x = self.UTILS.element.getElement(DOM.Messages.message_header,
                                          "Header")

        boolOK = False
        if x.get_attribute("data-number") == header:
            boolOK = True

        self.UTILS.test.test(
            boolOK,
            "\"" + str(header) + "\" is the header in the SMS conversation.")
        return boolOK

    def checkThreadHeaderWithNameSurname(self, header):
        """
        Verifies if a string is contained in the header
        """
        x = self.UTILS.element.getElement(DOM.Messages.message_header,
                                          "Header")

        boolOK = False

        if x.text == header:
            boolOK = True

        self.UTILS.test.test(
            boolOK,
            "\"" + header + "\" is the header in the SMS conversation.")
        return boolOK

    def closeThread(self):
        """
        Closes the current thread (returns you to the
        'thread list' SMS screen).
        """
        self.go_back()
        self.UTILS.element.waitForElements(
            ("xpath", "//h1[text()='{}']".format(_("Messages"))),
            "Messages main header")

    def countMessagesInThisThread(self):
        """
        Returns the number of messages in this thread
        (assumes you're already in the thread).
        """
        try:
            return len(
                self.UTILS.element.getElements(DOM.Messages.message_list,
                                               "Messages"))
        except:
            return 0

    def countNumberOfThreads(self):
        """
        Count all threads (assumes the messagin app is already open).
        """
        try:
            return len(
                self.UTILS.element.getElements(DOM.Messages.threads_list,
                                               "Threads"))
        except:
            return 0

    def create_and_send_mms(self, attached_type, nums, m_text):

        self.gallery = Gallery(self.parent)
        self.video = Video(self.parent)
        self.music = Music(self.parent)

        self.launch()
        self.startNewSMS()
        self.addNumbersInToField(nums)
        self.enterSMSMsg(m_text)

        if attached_type == "image":
            # Add an image file
            self.UTILS.general.add_file_to_device(
                './tests/_resources/80x60.jpg')
            self.create_mms_image()
            self.gallery.click_on_thumbnail_at_position_mms(0)
        elif attached_type == "cameraImage":
            # Add an image file from camera
            self.create_mms_camera_image()
            time.sleep(3)
        elif attached_type == "video":
            # Load an video file into the device.
            self.UTILS.general.add_file_to_device(
                './tests/_resources/mpeg4.mp4')
            self.create_mms_video()
            self.video.click_on_video_at_position_mms(0)
        elif attached_type == "audio":
            # Load an video file into the device.
            self.UTILS.general.add_file_to_device('./tests/_resources/AMR.amr')
            self.create_mms_music()
            self.music.click_on_song_mms()
        else:
            # self.UTILS.reporting.logResult("info", "incorrect value received")
            msg = "FAILED: Incorrect parameter received in create_and_send_mms()"\
                ". attached_type must being image, video or audio."
            self.UTILS.test.test(False, msg)

        time.sleep(2)
        self.sendSMS()
        return self.last_sent_message_timestamp()

    def create_and_send_sms(self, nums, msg):
        """
        Create and send a new SMS.<br>
        <b>Note:</b> The nums field must be an array of numbers
        or contact names.
        """
        self.startNewSMS()
        self.addNumbersInToField(nums)
        self.enterSMSMsg(msg)

        # The header should now say how many recipients.
        time.sleep(2)  # give the header time to change.

        num_recs = len(nums)
        search_str = _(" recipient") if num_recs == 1 else _(" recipients")
        self.UTILS.element.headerCheck(str(num_recs) + search_str)

        # Send the message.
        self.sendSMS()

    def create_mms_image(self):
        attach = self.UTILS.element.getElement(DOM.Messages.attach_button,
                                               "Attach button")
        attach.tap()

        self.marionette.switch_to_frame()
        gallery = self.UTILS.element.getElement(DOM.Messages.mms_from_gallery,
                                                "From gallery")
        gallery.tap()

        self.UTILS.iframe.switchToFrame(*DOM.Gallery.frame_locator)

    def create_mms_camera_image(self):
        self.camera = Camera(self.parent)

        attach = self.UTILS.element.getElement(DOM.Messages.attach_button,
                                               "Attach button")
        attach.tap()

        self.marionette.switch_to_frame()
        camera = self.UTILS.element.getElement(DOM.Messages.mms_from_camera,
                                               "From Camera")
        camera.tap()

        self.UTILS.iframe.switchToFrame(*DOM.Camera.frame_locator)

        # Take a picture.
        self.camera.take_and_select_picture()

        self.UTILS.iframe.switchToFrame(*DOM.Messages.frame_locator)

    def create_mms_music(self):

        attach = self.UTILS.element.getElement(DOM.Messages.attach_button,
                                               "Attach button")
        attach.tap()

        self.marionette.switch_to_frame()
        music = self.UTILS.element.getElement(DOM.Messages.mms_from_music,
                                              "From music")
        music.tap()

        self.UTILS.iframe.switchToFrame(*DOM.Music.frame_locator)

    def go_back(self):
        """Press back button in messages thread
        """
        # TODO: remove tap with coordinates after Bug 1061698 is fixed
        self.UTILS.element.getElement(DOM.Messages.header_link_locator,
                                      "Back button").tap(25, 25)

    def create_mms_video(self):

        attach = self.UTILS.element.getElement(DOM.Messages.attach_button,
                                               "Attach button")
        attach.tap()

        self.marionette.switch_to_frame()

        video = self.UTILS.element.getElement(DOM.Messages.mms_from_video,
                                              "From video")
        video.tap()

        self.UTILS.iframe.switchToFrame(*DOM.Video.frame_locator)

    def delete_all_threads(self):
        """
        Deletes all threads (assumes the messagin app is already open).
        """
        try:
            self.parent.wait_for_element_displayed(
                *DOM.Messages.no_threads_message, timeout=3)
            no_threads_message = self.marionette.find_element(
                *DOM.Messages.no_threads_message)
            if no_threads_message.is_displayed():
                self.UTILS.reporting.logResult(
                    "info", "(No message threads to delete.)")
        except:
            self.UTILS.reporting.logResult("info",
                                           "Deleting message threads ...")
            self.threadEditModeON()

            select_threads = self.UTILS.element.getElement(
                DOM.Messages.edit_msgs_select_threads_btn,
                "Delete threads button")
            select_threads.tap()

            select_all_btn = self.UTILS.element.getElement(
                DOM.Messages.check_all_threads_btn, "Select all button")
            select_all_btn.tap()

            self.deleteSelectedThreads()
            self.UTILS.element.waitForElements(
                DOM.Messages.no_threads_message,
                "No message threads notification", True, 60)

    def deleteMessagesInThisThread(self, msg_array=False):
        """
        Enters edit mode, selects the required messages and
        deletes them.<br>
        msg_array is an array of numbers.
        If it's not specified then all messages in this
        thread will be deleted.
        """
        if msg_array:
            self.editAndSelectMessages(msg_array)
        else:

            # Go into messages Settings..
            edit_btn = self.UTILS.element.getElement(
                DOM.Messages.edit_messages_icon, "Edit button")
            edit_btn.tap()

            select_btn = self.UTILS.element.getElement(
                DOM.Messages.edit_msgs_select_btn, "Select button")
            select_btn.tap()

            # Press select all button.
            select_all_btn = self.UTILS.element.getElement(
                DOM.Messages.check_all_messages_btn, "'Select all' button")
            select_all_btn.tap()

        self.deleteSelectedMessages()

    def deleteSelectedMessages(self):
        self.UTILS.reporting.debug("*** Tapping top Delete button")
        delete_btn = self.UTILS.element.getElement(
            DOM.Messages.delete_messages_ok_btn, "Delete button")
        delete_btn.tap()
        time.sleep(2)

        self.UTILS.reporting.debug(
            "*** Tap Delete messages confirmation button")
        confirm_btn = self.UTILS.element.getElement(
            DOM.Messages.delete_threads_ok_btn,
            "Delete messages confirmation button")
        confirm_btn.tap()
        time.sleep(2)

    def deleteSelectedThreads(self):
        delete_btn = self.UTILS.element.getElement(
            DOM.Messages.threads_delete_button, "Delete threads button")
        delete_btn.tap()

        delete_confirm_btn = self.UTILS.element.getElement(
            DOM.Messages.delete_threads_ok_btn,
            "Delete threads confirmation button")
        delete_confirm_btn.tap()

    def deleteThreads(self, target_array=False):
        """
        Enters edit mode, selects the required messages and
        deletes them.<br>
        target_array is an array of target numbers
        or contacts which identify the threads to be selected.
        If it's not specified then all messages in this
        thread will be deleted.
        """
        try:
            self.parent.wait_for_element_displayed(
                *DOM.Messages.no_threads_message, timeout=2)
            x = self.marionette.find_element(*DOM.Messages.no_threads_message)
            if x.is_displayed():
                self.UTILS.reporting.logResult(
                    "info", "(No message threads to delete.)")
        except:
            self.UTILS.reporting.logResult("info",
                                           "Deleting message threads ...")
            if target_array:
                self.UTILS.reporting.debug(
                    "*** Selecting threads for deletion [{}]".format(
                        target_array))
                self.editAndSelectThreads(target_array)
                self.UTILS.reporting.debug("*** Threads selected")
                self.deleteSelectedThreads()
            else:
                self.delete_all_threads()

    def editAndSelectMessages(self, msg_array):
        """
        Puts this thread into Edit mode and selects
        the messages listed in msg_array.<br>
        msg_array is an array of numbers.
        """
        edit_btn = self.UTILS.element.getElement(
            DOM.Messages.edit_messages_icon, "Edit button")
        edit_btn.tap()
        time.sleep(2)

        # Go into message edit mode..
        select_btn = self.UTILS.element.getElement(
            DOM.Messages.edit_msgs_select_btn, "Select messages button")
        select_btn.tap()
        time.sleep(2)

        messages = self.UTILS.element.getElements(DOM.Messages.message_list,
                                                  "Messages")
        for msg in msg_array:
            messages[msg].tap()

    def editAndSelectThreads(self, target_array):
        """
        Puts this thread into Edit mode and selects
        the messages listed in p_msg_array.<br>
        target_array is an array of target numbers
        or contacts which identify the threads to be selected.
        """
        # Go into edit mode..
        self.threadEditModeON()

        select_btn = self.UTILS.element.getElement(
            DOM.Messages.edit_msgs_select_threads_btn, "Select threads button")
        select_btn.tap()

        if len(target_array) == 0:
            return

        for i in target_array:
            self.UTILS.reporting.debug("selecting thread for [{}]".format(i))
            thread = self.UTILS.element.getElement(
                ("xpath", DOM.Messages.thread_selector_xpath.format(i)),
                "Thread checkbox for '{}'".format(i))
            self.UTILS.reporting.debug(
                "Trying to tap in element {}".format(thread))
            thread.tap()

        # Finally check that all desired threads have been selected
        header = self.UTILS.element.getElement(
            DOM.Messages.edit_threads_header, "Edit threads header").text
        expected_title = str(
            len(target_array)) if len(target_array) else _("Delete messages")
        self.UTILS.test.test(
            expected_title in header,
            "Check that all desired threads have been selected")

    def enterSMSMsg(self, msg, not_keyboard=True):
        """
        Create and send a message (assumes we are in a new 'create new message'
        screen with the destination number filled in already).
        """
        self.parent.wait_for_element_displayed(
            *DOM.Messages.input_message_area)
        input_area = self.marionette.find_element(
            *DOM.Messages.input_message_area)
        input_area.tap()
        input_area.send_keys(msg)

        # Validate the field.
        # Get the element again in order to avoid StaleElementException
        input_area = self.marionette.find_element(
            *DOM.Messages.input_message_area)
        self.UTILS.test.test(
            input_area.text == msg,
            u'The text in the message area is "{}". Expected: "{}"'.format(
                input_area.text, msg))

    def addNumbersInToField(self, nums):
        """
        Add the phone numbers in the 'To' field of this sms message.
        Assumes you are in 'create sms' screen.
        """

        # This variable is used to keep track of the appearance of the keyboard frame
        n = 0

        for num in nums:
            """
            Even though we don't use the keyboard for putting the number in,
            we need it for the ENTER button (which allows us to put more than
            one number in).
            So check that the keyboard appears when we tap the "TO" field if we have
            more than one number.
            """
            if len(nums) > 1:
                self.UTILS.reporting.logResult(
                    "info",
                    "Checking the keyboard appears when I tap the 'To' field ..."
                )
                to_field = self.UTILS.element.getElement(
                    DOM.Messages.target_numbers_empty, "Target number field")
                to_field.tap()

                boolKBD = False
                self.marionette.switch_to_frame()

                if n < 1:

                    try:
                        # A 'silent' check to see if the keyboard iframe appears.
                        elDef = ("xpath",
                                 "//iframe[contains(@{}, '{}')]".format(
                                     DOM.Keyboard.frame_locator[0],
                                     DOM.Keyboard.frame_locator[1]))
                        self.parent.wait_for_element_displayed(*elDef,
                                                               timeout=2)
                        boolKBD = True
                    except:
                        boolKBD = False

                    self.UTILS.test.test(
                        boolKBD,
                        "Keyboard is displayed when 'To' field is clicked for the first time"
                    )

                self.UTILS.iframe.switchToFrame(*DOM.Messages.frame_locator)

            if n == 0:

                self.UTILS.general.typeThis(DOM.Messages.target_numbers_empty,
                                            "Target number field",
                                            num,
                                            p_no_keyboard=True,
                                            p_validate=False,
                                            p_clear=False,
                                            p_enter=True)

            else:
                self.UTILS.general.typeThis(DOM.Messages.target_numbers_empty,
                                            "Target number field",
                                            num,
                                            p_no_keyboard=True,
                                            p_validate=False,
                                            p_clear=False,
                                            p_enter=False)
                input_area = self.UTILS.element.getElement(
                    DOM.Messages.input_message_area, "Target number field")
                input_area.tap()

            n += 1

    def addContactToField(self, contact_name):
        self._search_for_contact(contact_name)
        # Now check the correct name is in the 'To' list.
        self.checkIsInToField(contact_name)

    def _select_forward_option_for(self, element):
        self.actions.long_press(element, 2).perform()
        self.UTILS.reporting.logResult("info", "Clicking on forward button")
        forward_option = self.UTILS.element.getElement(
            DOM.Messages.forward_btn_msg_opt, "Forward button is displayed")
        forward_option.tap()

    def _search_for_contact(self, contact_name):
        self.contacts = Contacts(self.parent)
        self.selectAddContactButton()
        self.UTILS.iframe.switchToFrame(*DOM.Contacts.frame_locator)

        self.contacts.search(contact_name)
        self.contacts.check_search_results(contact_name)

        results = self.UTILS.element.getElements(
            DOM.Contacts.search_results_list, "Contacts search results")
        for result in results:
            if result.text == contact_name:
                result.tap()
                break

        # Switch back to the sms iframe.
        self.apps.switch_to_displayed_app()

    def forwardMessage(self, msg_type, target_telNum):
        """
        Forwards the last message of the thread to a number
        """

        self.UTILS.reporting.logResult(
            'info', "The message type to forward is: {}".format(msg_type))

        if msg_type == "sms" or msg_type == "mms":
            self.UTILS.reporting.logResult(
                "info", "Open {} option with longtap on it".format(msg_type))
            last = self.last_message_in_this_thread()
            body = self.marionette.find_element(
                *DOM.Messages.last_message_body, id=last.id)
            self._select_forward_option_for(body)

        elif msg_type == "mmssub":
            self.UTILS.reporting.logResult(
                "info", "Open mms with subject options with longtap on it")
            mms_subject = self.UTILS.element.getElement(
                DOM.Messages.received_mms_subject, "Target MMS field")
            self._select_forward_option_for(mms_subject)

        else:
            self.UTILS.reporting.logResult("info", "incorrect value received")
            self.UTILS.test.test(False, "Incorrect value received")

        self.addNumbersInToField([target_telNum])

        self.UTILS.reporting.logResult("info", "Clicking on Send button")
        self.sendSMS()

    def forwardMessageToContact(self, msg_type, contact_name):
        """
        Forwards the last message of the thread to a contact, searching for it
        """
        self.UTILS.reporting.logResult(
            'info', "The message type to forward is: {}".format(msg_type))

        if msg_type == "sms" or msg_type == "mms":
            # Open sms option with longtap on it
            self.UTILS.reporting.logResult(
                "info", "Open sms option with longtap on it")
            sms = self.last_message_in_this_thread()
            body = self.marionette.find_element(
                *DOM.Messages.last_message_body, id=sms.id)
            self._select_forward_option_for(body)

        elif msg_type == "mmssub":
            # Open mms option with longtap on it
            self.UTILS.reporting.logResult(
                "info", "Open mms with subject options with longtap on it")
            mms_subject = self.UTILS.element.getElement(
                DOM.Messages.received_mms_subject, "Target MMS field")
            self._select_forward_option_for(mms_subject)

        else:
            self.UTILS.reporting.logResult("info", "incorrect value received")
            self.UTILS.test.test(False, "Incorrect value received")

        # Search for the contact and check it's been added
        self.addContactToField(contact_name)

        # Send the mms.
        self.UTILS.reporting.logResult("info", "Clicking on Send button")
        self.sendSMS()

    def forwardMessageToMultipleRecipients(self, msg_type, target_telNum,
                                           contact_name):
        self.UTILS.reporting.logResult(
            'info', "The message type to forward is: {}".format(msg_type))

        if msg_type == "sms" or msg_type == "mms":
            # Open sms option with longtap on it
            self.UTILS.reporting.logResult(
                "info", "Open sms option with longtap on it")
            sms = self.last_message_in_this_thread()
            body = self.marionette.find_element(
                *DOM.Messages.last_message_body, id=sms.id)
            self._select_forward_option_for(body)

        elif msg_type == "mmssub":
            # Open mms option with longtap on it
            self.UTILS.reporting.logResult(
                "info", "Open mms with subject options with longtap on it")
            mms_subject = self.UTILS.element.getElement(
                DOM.Messages.received_mms_subject, "Target MMS field")
            self._select_forward_option_for(mms_subject)

        else:
            self.UTILS.reporting.logResult("info", "incorrect value received")
            self.UTILS.test.test(False, "Incorrect value received")

        # Add phone numbers
        self.addNumbersInToField([target_telNum])
        # Search for the contact and check it's been added
        self.addContactToField(contact_name)

        # Send the mms.
        self.UTILS.reporting.logResult("info", "Clicking on Send button")
        self.sendSMS()

    def get_mms_attachments_info(self, mms):
        """Give name and file size for all attachments in an MMS.

        Given an MMS, return a list containing a dictionary for every attachment,
        with two keys, name and size.
        """
        attachment_names = self.marionette.find_elements(
            *DOM.Messages.mms_attachment_names, id=mms.id)
        attachment_sizes = self.marionette.find_elements(
            *DOM.Messages.mms_attachment_sizes, id=mms.id)
        result = []
        for (i, name) in enumerate(attachment_names):
            inner_text = self.marionette.execute_script(
                """return arguments[0].innerHTML;""", script_args=[name])
            att = {}
            att["name"] = inner_text
            size_elem = attachment_sizes[i].get_attribute("data-l10n-args")
            size = size_elem[size_elem.index(":") + 2:size_elem.rfind("\"")]
            i = i + 1
            att["size"] = size
            result.append(att)
        return result

    def getThreadText(self, num):
        """
        Returns the preview text for the thread for this number (if it exists),
        or False if either the thread doesn't exist or can't be found.
        """
        if self.threadExists(num):
            x = self.UTILS.element.getElements(DOM.Messages.threads_list,
                                               "Threads")

            for thread in x:
                try:
                    thread.find_element("xpath",
                                        ".//p[text()='{}']".format(num))
                    z = thread.find_element("xpath",
                                            ".//span[@class='body-text']")
                    return z.text
                except:
                    pass
        return False

    def header_addToContact(self):
        """
        Taps the header and tries to tap the 'Add to an existsing contact' button.
        - Assumes we are looking at a message thread already.
        - Leaves you in the correct iframe to continue (contacts).
        """
        x = self.UTILS.element.getElement(DOM.Messages.message_header,
                                          "Thread header")
        x.tap()

        x = self.UTILS.element.getElement(
            DOM.Messages.header_add_to_contact_btn,
            "'Add to an existing contact' button")
        x.tap()

        # Switch to correct iframe.
        self.UTILS.iframe.switchToFrame(*DOM.Contacts.frame_locator)

    def header_call(self):
        """Tap on the header of a messages thread and dial the number
        """
        x = self.UTILS.element.getElement(DOM.Messages.message_header,
                                          "Thread header")
        x.tap()

        # Select dialer option.
        x = self.UTILS.element.getElement(DOM.Messages.header_call_btn,
                                          "'Call' button")
        x.tap()

        # Switch to correct iframe.
        self.UTILS.iframe.switchToFrame(*DOM.Dialer.frame_locator)

    def header_createContact(self):
        """
        Taps the header and tries to tap the 'send message' button.
        - Assumes we are looking at a message thread already.
        - Leaves you in the correct iframe to continue.
        """
        x = self.UTILS.element.getElement(DOM.Messages.message_header,
                                          "Thread header")
        x.tap()

        x = self.UTILS.element.getElement(
            DOM.Messages.header_create_new_contact_btn,
            "'Create new contact' button")
        x.tap()

        # Switch to correct iframe.
        self.UTILS.iframe.switchToFrame(*DOM.Contacts.frame_locator)

    def header_sendMessage(self):
        """
        Taps the header and tries to tap the 'send message' button.
        - Assumes we are looking at a message thread already.
        - Leaves you in the correct iframe to continue.
        """
        x = self.UTILS.element.getElement(DOM.Messages.message_header,
                                          "Thread header")
        x.tap()

        x = self.UTILS.element.getElement(DOM.Messages.header_send_message_btn,
                                          "'Send message' button")
        x.tap()

    def last_message_in_this_thread(self):
        """
        Returns an object of the last message in the current thread.
        """
        self.parent.wait_for_element_present(*DOM.Messages.last_message,
                                             timeout=20)
        message = self.marionette.find_element(*DOM.Messages.last_message)
        self.UTILS.element.scroll_into_view(message)
        return message

    def last_sent_message_timestamp(self):
        """Returns the timestamp of the last sent message
        """
        send_time = self.marionette.find_element(
            *DOM.Messages.last_sent_message).get_attribute("data-timestamp")
        return float(send_time) / 1000

    def last_sent_message(self):
        """Returns the last sent message
        """
        return self.marionette.find_element(*DOM.Messages.last_sent_message)

    def open_attached_file(self, frame_to_change):
        elem = DOM.Messages.last_message_attachment_av
        last = self.UTILS.element.getElement(elem, "Last message attachment")
        self.UTILS.element.scroll_into_view(last)

        # Now get the thumbnail in order to open it
        thumb = last.find_element(*DOM.Messages.last_message_thumbnail)
        thumb.tap()
        self.UTILS.iframe.switchToFrame(*frame_to_change)

    def openThread(self, num):
        """
        Opens the thread for this number (assumes we're looking at the
        threads in the messaging screen).
        """
        try:
            thread_el = ("xpath",
                         DOM.Messages.thread_selector_xpath.format(num))
            x = self.UTILS.element.getElement(thread_el,
                                              "Message thread for " + num)
            x.tap()

            self.UTILS.element.waitForElements(
                DOM.Messages.send_message_button, "'Send' button")
        except Exception as e:
            x = self.UTILS.debug.screenShotOnErr()
            msg = "<b>NOTE:</b> The thread <i>may</i> have failed to open due to [{}].".format(
                e)
            self.UTILS.reporting.logResult("info", msg, x)

    def readLastSMSInThread(self):
        """
        Read last message in the current thread.
        """
        received_message = self.UTILS.element.getElements(
            DOM.Messages.received_messages, "Received messages")[-1]
        return str(received_message.text)

    def readNewSMS(self, fromNum):
        """
        Read and return the value of the new message received from number.
        """
        x = self.UTILS.element.getElement(
            ("xpath", DOM.Messages.messages_from_num.format(fromNum)),
            "Message from '" + fromNum + "'")
        x.tap()

        # (From gaiatest: "TODO Due to displayed bugs I cannot find a good wait
        # for switch btw views")
        time.sleep(5)

        # Return the last comment in this thread.
        return self.readLastSMSInThread()

    def removeContactFromToField(self, target):
        """
        Removes target from the "To" field of this SMS.<br>
        Returns True if it found the target, or False if not.
        """
        x = self.UTILS.element.getElements(DOM.Messages.target_numbers,
                                           "'To:' field contents")

        for i in range(len(x)):
            self.UTILS.reporting.logResult(
                "info",
                "Checking target '{}' to '{}' ...".format(x[i].text, target))

            if x[i].text.lower() == target.lower():
                self.UTILS.reporting.logResult(
                    "info", "Tapping contact '" + target + "' ...")
                x[i].tap()

                try:

                    # This contact was added via 'add contact' icon.
                    self.parent.wait_for_element_displayed(
                        "xpath",
                        "//button[text()='{}']".format(_("Remove")),
                        timeout=2)
                    y = self.marionette.find_element(
                        "xpath", "//button[text()='{}']".format(_("Remove")))
                    self.UTILS.reporting.logResult("info",
                                                   "Tapping 'Remove' button.")
                    y.tap()
                    return True
                except:

                    # This contact was manually entered.
                    z = self.UTILS.element.getElements(
                        DOM.Messages.target_numbers, "Target to be removed")[i]
                    z.clear()
                    return True
        return False

    def selectAddContactButton(self):
        """
        Taps the 'add contact' button
        """
        add_btn = self.UTILS.element.getElement(
            DOM.Messages.add_contact_button, "Add contact button")
        add_btn.tap()

    def sendSMS(self):
        """
        Just presses the 'send' button (assumes everything else is done).
        """
        self.parent.wait_for_condition(lambda m: m.find_element(
            *DOM.Messages.send_message_button).is_enabled())
        send_btn = self.marionette.find_element(
            *DOM.Messages.send_message_button)
        send_btn.tap()

        # (Give the spinner time to appear.)
        time.sleep(2)
        self.UTILS.element.waitForNotElements(
            DOM.Messages.message_sending_spinner, "'Sending' icon", True, 180)

        # Check if we received the 'service unavailable' message.
        try:
            self.parent.wait_for_element_displayed(
                *DOM.Messages.service_unavailable_msg, timeout=2)
            screenshot = self.UTILS.debug.screenShotOnErr()
            msg = "'Service unavailable' message detected - unable to send sms!"
            self.UTILS.reporting.logResult("info", msg, screenshot)
            return False
        except:
            pass

        return True

    def startNewSMS(self):
        """
        Starts a new sms (doesn't fill anything in).
        Assumes the Messaging app is already launched.
        """
        newMsgBtn = self.UTILS.element.getElement(
            DOM.Messages.create_new_message_btn, "Create new message button")
        newMsgBtn.tap()

    def threadCarrier(self):

        # Returns the 'carrier' being used by this thread.
        x = self.UTILS.element.getElement(DOM.Messages.type_and_carrier_field,
                                          "Type and carrier information")
        parts = x.text.split("|")
        if len(parts) > 1:
            return parts[1].strip()
        return parts[0].strip()

    def threadEditModeOFF(self):
        """
        Turns off Edit mode while in the SMS threads screen.
        """
        x = self.UTILS.element.getElement(DOM.Messages.cancel_edit_threads,
                                          "Cancel button")
        x.tap()
        self.UTILS.element.waitForElements(DOM.Messages.edit_threads_button,
                                           "Edit button")

    def threadEditModeON(self):
        """
        Turns on Edit mode while in the SMS threads screen.
        """
        edit_btn = self.UTILS.element.getElement(
            DOM.Messages.edit_threads_button, "Edit button")
        edit_btn.tap()
        self.UTILS.element.waitForElements(DOM.Messages.cancel_edit_threads,
                                           "Cancel button")

    def threadExists(self, num):
        """
        Verifies that a thread exists for this number (returns True or False).
        """
        boolOK = False
        try:
            self.parent.wait_for_element_present(
                "xpath", DOM.Messages.thread_selector_xpath.format(num), 1)
            boolOK = True
        except:
            boolOK = False

        return boolOK

    def threadType(self):
        """
        Returns the 'type' being used by this thread.
        """
        x = self.UTILS.element.getElement(DOM.Messages.type_and_carrier_field,
                                          "Type and carrier information")
        parts = x.text.split("|")
        typ = parts[0].strip()
        return typ if len(parts) > 1 else ''

    def time_of_last_message_in_thread(self):
        """
        Returns the time of the last message in the current thread.
        """
        t = self.UTILS.element.getElement(DOM.Messages.last_message_time,
                                          "Last message time")
        return t.text

    def time_of_thread(self, num):
        """
        Returns the time of a thread.
        """
        x = self.UTILS.element.getElement(
            ("xpath", DOM.Messages.thread_timestamp_xpath.format(num)),
            "Thread time", True, 5, False)
        return x.text

    def thread_timestamp(self, num):
        """
        Returns the timestamp of a thread
        """
        x = self.marionette.find_element(
            *DOM.Messages.last_message).get_attribute("data-timestamp")
        return float(x)

    def verify_mms_received(self, attached_type, sender_number):

        self.UTILS.iframe.switchToFrame(*DOM.Messages.frame_locator)
        self.openThread(sender_number)
        message = self.last_message_in_this_thread()
        self.UTILS.test.test(message,
                             "A received message appeared in the thread.",
                             True)

        self.UTILS.reporting.debug(
            "*** attached type: {}".format(attached_type))
        if attached_type == "img":
            elem = DOM.Messages.last_message_attachment_img
        elif attached_type == "video":
            elem = DOM.Messages.last_message_attachment_av
        elif attached_type == "audio":
            elem = DOM.Messages.last_message_attachment_av
        else:
            # self.UTILS.reporting.logResult("info", "incorrect value received")
            msg = "FAILED: Incorrect parameter received in verify_mms_received()"\
                ". Attached_type must be image, video or audio."
            self.UTILS.test.test(False, msg)

        self.UTILS.reporting.debug("*** searching for attachment type")
        # Look for all the attachments, since there can be more than one
        atts = self.UTILS.element.getElements(elem, "Last message attachments")
        self.UTILS.element.scroll_into_view(atts[0])
        found = False
        for att in atts:
            typ = att.get_attribute("data-attachment-type")
            self.UTILS.reporting.debug(
                "*** searching for attachment type Result: {}".format(typ))
            if typ == attached_type:
                found = True
        if not found:
            msg = "No attachment with type {} was found in the message".format(
                attached_type)
            self.UTILS.test.test(False, msg)

    def wait_for_message(self, send_time=None, timeout=120):
        """Wait for a received message in the current thread and return it.
        """
        if not send_time:
            send_time = self.last_sent_message_timestamp()

        poll_time = 2
        poll_reps = (timeout / poll_time)
        result = False

        for i in range(poll_reps):
            # Get last message in this thread.
            last_msg = self.last_message_in_this_thread()

            if not last_msg:
                time.sleep(poll_time)
                continue

            # If the send_time timestamp is greater than this message's timestamp,it means the message
            # we expect has not arrived yet, so we have to wait a bit more.
            message_data_time = float(
                last_msg.get_attribute("data-timestamp")) / 1000
            fmt = "data-timestamp of last message in thread: {:.3f} send_time: {:.3f} --> {}"
            self.UTILS.reporting.debug(
                fmt.format(message_data_time, send_time,
                           send_time > message_data_time))
            if send_time > message_data_time:
                continue

            # Is this a received message?
            if "incoming" in last_msg.get_attribute("class"):
                result = last_msg
                break

            # Nope - sleep then try again.
            time.sleep(poll_time)

        self.UTILS.test.test(
            result,
            "Last message in thread 'received' within {} seconds.".format(
                timeout))
        return result
示例#27
0
class Email(object):
    def __init__(self, parent):
        self.apps = parent.apps
        self.data_layer = parent.data_layer
        self.parent = parent
        self.marionette = parent.marionette
        self.UTILS = parent.UTILS

    def launch(self):
        self.app = self.apps.launch(self.__class__.__name__)
        self.UTILS.element.waitForNotElements(
            DOM.GLOBAL.loading_overlay,
            self.__class__.__name__ + " app - loading overlay")
        return self.app

    def refresh(self):
        self.parent.wait_for_element_displayed(
            *DOM.Email.folder_refresh_button)
        self.marionette.find_element(*DOM.Email.folder_refresh_button).tap()

    def mails(self):
        self.refresh()
        self.wait_for_sync_completed()
        self.wait_for_message_list()
        return self.marionette.find_elements(*DOM.Email.email_entry)

    def _email_exists(self, subject):
        if subject in [
                mail.find_element(*DOM.Email.folder_subject_list).text
                for mail in self.mails()
        ]:
            return True
        else:
            self.refresh()
            self.wait_for_sync_completed()
            self.UTILS.element.scroll_into_view(self.mails()[0])
            return False

    def get_email(self, subject):
        return filter(
            lambda msg: msg.find_element(*DOM.Email.folder_subject_list).text
            == subject, self.mails())[0]

    def wait_for_sync_completed(self):
        element = self.marionette.find_element(
            *DOM.Email.folder_refresh_button)
        self.parent.wait_for_condition(
            lambda m: element.get_attribute('data-state') == 'synchronized')

    def wait_for_folder(self, folder_name):
        self.parent.wait_for_condition(lambda m: m.find_element(
            *DOM.Email.folder_name).text == folder_name)

    def wait_for_email_loaded(self, subject):
        Wait(self.marionette, timeout=20,
             interval=5).until(lambda m: m.find_element(
                 *DOM.Email.open_email_subject).text == subject)

    def wait_for_message_list(self):
        element = self.marionette.find_element(*DOM.Email.message_list_locator)
        self.parent.wait_for_condition(
            lambda m: element.is_displayed() and element.location['x'] == 0)

    def _create_attachment(self, locator, msg, frame_to_change):
        attach = self.UTILS.element.getElement(DOM.Email.compose_attach_btn,
                                               "Attach button")
        attach.tap()

        self.marionette.switch_to_frame()
        attacth_type = self.UTILS.element.getElement(locator, msg)
        attacth_type.tap()
        self.UTILS.iframe.switchToFrame(*frame_to_change)

    def create_email_image(self):
        self._create_attachment(DOM.Email.attach_gallery_btn, "From Gallery",
                                DOM.Gallery.frame_locator)

    def create_email_camera_image(self):
        self._create_attachment(DOM.Email.attach_camera_btn, "From Camera",
                                DOM.Camera.frame_locator)
        # Take a picture.
        self.camera = Camera(self.parent)
        self.camera.take_and_select_picture()
        self.UTILS.iframe.switchToFrame(*DOM.Email.frame_locator)

    def create_email_music(self):
        self._create_attachment(DOM.Email.attach_music_btn, "From Music",
                                DOM.Music.frame_locator)

    def create_email_video(self):
        self._create_attachment(DOM.Email.attach_video_btn, "From video",
                                DOM.Video.frame_locator)

    def attach_file(self, attached_type):
        """
        This method is reponsible of attaching a certain file to an email.
        NOTE: It does not fill neither the message destinatary nor the message body
        """

        self.gallery = Gallery(self.parent)
        self.video = Video(self.parent)
        self.music = Music(self.parent)

        if attached_type == "image":
            self.UTILS.general.add_file_to_device(
                './tests/_resources/80x60.jpg')
            self.create_email_image()
            self.gallery.click_on_thumbnail_at_position_email(0)
        elif attached_type == "cameraImage":
            self.create_email_camera_image()
        elif attached_type == "video":
            self.UTILS.general.add_file_to_device(
                './tests/_resources/mpeg4.mp4')
            self.create_email_video()
            self.video.click_on_video_at_position_email(0)
        elif attached_type == "audio":
            self.UTILS.general.add_file_to_device('./tests/_resources/AMR.amr')
            self.create_email_music()
            self.music.click_on_song_email()
        else:
            msg = "FAILED: Incorrect parameter received in create_and_send_mms()"\
                ". attached_type must being image, video or audio."
            self.UTILS.test.test(False, msg)

    def delete_email(self, subject):
        """
        Deletes the first message in this folder with this subject line.
        """
        self.open_msg(subject)

        # Press the delete button and confirm deletion.
        delete_btn = self.UTILS.element.getElementByXpath(
            DOM.Email.delete_this_email_btn[1])
        delete_btn.tap()
        delete_confirm = self.UTILS.element.getElement(
            DOM.Email.confirmation_delete_ok, "Confirmation button")
        delete_confirm.tap()

        # Refresh and check that the message is no longer in the inbox.
        self.refresh()
        self.wait_for_sync_completed()

        self.UTILS.test.test(
            not self._email_exists(subject),
            "Email with subject [{}] is no longer in the folder".format(
                subject))

    def email_is_in_folder(self, subject, timeout=60):
        self.parent.wait_for_condition(lambda m: self._email_exists(subject),
                                       timeout=timeout)
        return True

    def goto_folder_from_list(self, name):
        """
        Goto a specific folder in the folder list screen.
        """
        name = _(name)
        elem = ('xpath', DOM.Email.folder_name_xpath.format(name))
        folder_link = self.UTILS.element.getElement(
            elem, "Link to folder '" + name + "'")
        self.UTILS.element.scroll_into_view(folder_link)
        folder_link.tap()
        self.wait_for_folder(name)

    def open_folder(self, folder_name):
        # Check whether we're already there
        try:
            self.wait_for_folder(folder_name)
        except:
            # Open a specific mail folder (must be called from "Inbox").
            settings_menu = self.UTILS.element.getElement(
                DOM.Email.settings_menu_btn, "Settings menu button")
            settings_menu.tap()

            # When we're looking at the folders screen ...
            self.UTILS.element.waitForElements(DOM.Email.folder_list_container,
                                               "Folder list container", True,
                                               20, False)
            self.goto_folder_from_list(folder_name)

            # Wait a while for everything to finish populating.
            self.UTILS.element.waitForNotElements(
                DOM.Email.folder_sync_spinner, "Loading messages spinner",
                True, 60, False)

    def open_msg(self, subject):
        """
        Opens a specific email in the current folder
        (assumes we're already in the folder we want).
        """

        if self.email_is_in_folder(subject):
            mail = self.get_email(subject)
            self.UTILS.element.scroll_into_view(mail)
            mail.tap()
            self.wait_for_email_loaded(subject)
            return True
        else:
            screenshot = self.UTILS.debug.screenShotOnErr()
            self.UTILS.reporting.logResult('info', "Mail not found",
                                           screenshot)
            return False

    def _send_and_wait(self):
        send_btn = self.UTILS.element.getElement(DOM.Email.compose_send_btn,
                                                 "Send button")
        send_btn.tap()

        self.UTILS.element.waitForElements(DOM.Email.toaster_sending_mail,
                                           "Sending email toaster", True, 60)
        self.UTILS.element.waitForNotElements(DOM.Email.toaster_sending_mail,
                                              "Sending email toaster", True,
                                              60, False)
        self.UTILS.element.waitForElements(DOM.Email.toaster_sent_mail,
                                           "Email sent toaster", True, 120,
                                           False)

    def send_new_email(self,
                       p_target,
                       p_subject,
                       p_message,
                       attach=False,
                       attached_type=None):
        """
        Compose and send a new email.
        """
        self.UTILS.reporting.logResult("info",
                                       "Getting 'compose message button'")

        compose_new_msg_btn = self.UTILS.element.getElement(
            DOM.Email.compose_msg_btn, "Compose button")
        time.sleep(1)
        compose_new_msg_btn.tap()

        # Put items in the corresponsing fields.
        self.parent.wait_for_element_displayed(*DOM.Email.compose_to)
        to_field = self.marionette.find_element(*DOM.Email.compose_to)
        if type(p_target) is list:
            for addr in p_target:
                to_field.send_keys(addr)
                to_field.send_keys(" ")
        else:
            to_field.send_keys(p_target)

        time.sleep(1)
        self.marionette.find_element(
            *DOM.Email.compose_subject).send_keys(p_subject)
        time.sleep(1)
        self.marionette.find_element(
            *DOM.Email.compose_msg).send_keys(p_message)
        if attach:
            self.attach_file(attached_type)

        self.send_the_email()

    def reply_msg(self, reply_message):
        """
        This method replies to a previously received message
        It assumes we already are viewing that message
        """

        # Get who sent us the email
        from_field = self.UTILS.element.getElement(DOM.Email.open_email_from,
                                                   "'From' field").text

        reply_btn = self.UTILS.element.getElement(DOM.Email.reply_btn,
                                                  "Reply message button")
        reply_btn.tap()

        reply_opt = self.UTILS.element.getElement(DOM.Email.reply_menu_reply,
                                                  "'Reply' option button")
        reply_opt.tap()

        # Get the guy we're replying to
        to_field = self.UTILS.element.getElement(
            DOM.Email.compose_to_from_contacts, "[Reply] 'To' field")
        to_field = to_field.text

        # Check we're actually replying to the guy who sent us the email
        self.UTILS.test.test(to_field in from_field,
                             "Checking we are replying correctly")

        # Write some reply content
        self.marionette.find_element(
            *DOM.Email.compose_msg).send_keys(reply_message)
        self.reply_the_email(from_field.split("@")[0])

    def reply_all(self, sender, reply_message):
        """
        This method replies to all recipients of a previously received message
        It assumes we already are viewing that message
        """

        # Get who sent us the email
        from_field = self.UTILS.element.getElement(DOM.Email.open_email_from,
                                                   "'From' field").text

        reply_btn = self.UTILS.element.getElement(DOM.Email.reply_btn,
                                                  "Reply message button")
        reply_btn.tap()

        # Now choose the "Reply all" option
        reply_opt = self.UTILS.element.getElement(
            DOM.Email.reply_menu_reply_all, "'Reply all' option button")
        reply_opt.tap()

        # Wait for 'compose message' header.
        self.parent.wait_for_element_displayed(*DOM.Email.compose_header,
                                               timeout=30)

        # Check the sender is not included in the 'To' field
        bubbles = self.UTILS.element.getElements((
            'css selector',
            '.cmp-to-container.cmp-addr-container .cmp-bubble-container .cmp-peep-name'
        ), '"To" field bubbles')
        bubbles_text = [bubble.text for bubble in bubbles]

        if sender['username'] in bubbles_text:
            self.UTILS.test.test(
                False,
                "Sender ({}) must not appear in the 'To field' when replying".
                format(sender['username']), True)

        # Write some reply content
        self.marionette.find_element(
            *DOM.Email.compose_msg).send_keys(reply_message)
        self.reply_the_email(from_field.split("@")[0])

    def forward_msg(self,
                    p_target,
                    fwd_message,
                    attach=False,
                    attached_type=None):
        """
        This method forward a previously received message to somebody else
        It assumes we already are viewing that message
        """

        # Get who sent us the email
        from_field = self.UTILS.element.getElement(DOM.Email.open_email_from,
                                                   "'From' field").text

        reply_btn = self.UTILS.element.getElement(DOM.Email.reply_btn,
                                                  "Reply message button")
        reply_btn.tap()

        # Now choose the "Forward" option
        fw_opt = self.UTILS.element.getElement(DOM.Email.reply_menu_forward,
                                               "'Forward' option button")
        fw_opt.tap()

        # Wait for 'compose message' header.
        self.parent.wait_for_element_displayed(*DOM.Email.compose_header,
                                               timeout=30)

        # Put items in the corresponding fields.
        self.parent.wait_for_element_displayed(*DOM.Email.compose_to)
        to_field = self.marionette.find_element(*DOM.Email.compose_to)
        if type(p_target) is list:
            for addr in p_target:
                to_field.send_keys(addr)
                to_field.send_keys(" ")
        else:
            to_field.send_keys(p_target)

        # Write some reply content
        self.marionette.find_element(
            *DOM.Email.compose_msg).send_keys(fwd_message)
        if attach:
            self.attach_file(attached_type)
        self.reply_the_email(from_field.split("@")[0])

    def reply_the_email(self, sender_name):
        """
        Hits the 'Send' button to reply to the message (handles
        waiting for the correct elements etc...).
        """
        self._send_and_wait()
        sender_header = ('xpath',
                         DOM.GLOBAL.app_head_specific.format(sender_name))
        self.UTILS.element.waitForElements(sender_header,
                                           "Previous received message", True,
                                           120)

    def send_the_email(self):
        """
        Hits the 'Send' button to send the message (handles
        waiting for the correct elements etc...).
        """
        self._send_and_wait()
        self.wait_for_folder(_("Inbox"))

    def send_the_email_and_switch_frame(self, header, frame_locator):
        send_btn = self.UTILS.element.getElement(DOM.Email.compose_send_btn,
                                                 "Send button")
        send_btn.tap()
        app_header = ('xpath', DOM.GLOBAL.app_head_specific.format(header))
        self.UTILS.iframe.switchToFrame(*frame_locator)
        self.UTILS.element.waitForElements(app_header, header, True, 120)

    def setup_account_active_sync(self, user, email, passwd, hostname):
        """
        Set up a new ActiveSync account manually
        """
        if not self.no_existing_account(email):
            return

        # (At this point we are now in the 'New account' screen by one path or another.)
        self.marionette.find_element(*DOM.Email.username).send_keys(user)
        self.marionette.find_element(*DOM.Email.email_addr).send_keys(email)

        # Now tap on Manual setUp
        manual_setup = self.UTILS.element.getElement(DOM.Email.manual_setup,
                                                     "Manual setup button")
        manual_setup.tap()

        # Check that we are indeed setting up an account manually
        self.UTILS.element.waitForElements(DOM.Email.manual_setup_sup_header,
                                           "Manual setup header", True, 5)

        # Change the account type to ActiveSync
        account_type = self.UTILS.element.getElement(
            DOM.Email.manual_setup_account_type, "Account type select")
        account_type.tap()

        # Change to top frame is needed in order to be able of choosing an option
        self.marionette.switch_to_frame()
        self.UTILS.element.waitForElements(
            DOM.Email.manual_setup_account_options, "Account type options",
            True, 5)
        # Select active sync
        elem = (DOM.Email.manual_setup_account_option[0],
                DOM.Email.manual_setup_account_option[1].format("ActiveSync"))
        active_sync = self.UTILS.element.getElement(elem, "ActiveSync option")
        active_sync.tap()

        # Confirm
        ok_btn = self.UTILS.element.getElement(
            DOM.Email.manual_setup_account_type_ok, "Ok button")
        ok_btn.tap()

        # Going back to Email frame
        self.apps.switch_to_displayed_app()

        # Finish setting things up
        self.marionette.find_element(*DOM.Email.password).send_keys(passwd)
        time.sleep(1)
        self.marionette.find_element(
            *DOM.Email.manual_setup_activesync_host).send_keys(hostname)
        time.sleep(1)
        self.marionette.find_element(
            *DOM.Email.manual_setup_activesync_user).send_keys(user)
        time.sleep(1)

        manual_next_btn = self.UTILS.element.getElement(
            DOM.Email.manual_setup_next, "Manual Setup 'Next' button", True,
            60)
        manual_next_btn.tap()

        manual_prefs_btn = self.UTILS.element.getElement(
            DOM.Email.login_account_prefs_next_btn, "Next button", True, 60)
        manual_prefs_btn.tap()

        # Click the 'continue to mail' button.
        manual_continue_btn = self.UTILS.element.getElement(
            DOM.Email.login_cont_to_email_btn, "'Continue to mail' button",
            True, 60)
        manual_continue_btn.tap()

        self.UTILS.element.waitForNotElements(
            DOM.Email.login_cont_to_email_btn, "'Continue to mail' button")
        self.wait_for_folder(_("Inbox"))

    def setup_account(self, user, email, passwd, via_activity=False):
        """
        Set up a new email account in the email app and login.
        """

        # TODO - There's some kind of malfunctioning here. It assumes that I've already set an account. If I close the
        # email app, wait 2 secs, an open it back again, in the beginning, it shows the setup menu, but after 2-3
        # seconds it takes us back to inbox of the registered account, which should be the default behavior.

        time.sleep(5)
        if not self.no_existing_account(email):
            return

        # At this point we are now in the 'New account' screen by one path or another
        username_field = self._get_field(DOM.Email.username)
        username_field.send_keys(user)

        email_field = self._get_field(DOM.Email.email_addr)
        email_field.send_keys(email)

        self.tap_next_account_info()

        domain = re.search(
            '[a-zA-Z0-9+_\-\.]+@([0-9a-zA-Z][.-0-9a-zA-Z]*).[a-zA-Z]+',
            email).group(1)
        if 'gmail' in domain:
            self.switch_to_gmail_frame(email)
            self.gmail_login(passwd)
            self.wait_for_gmail_approve_access()
            self.tap_gmail_approve_access()
        elif 'hotmail' or 'msn' or 'outlook' in domain:
            self.setup_hotmail_account(email, passwd)

        self.apps.switch_to_displayed_app()
        self.tap_next_account_preferences()
        self.tap_continue_to_mail()

        if not via_activity:
            self.wait_for_folder(_("Inbox"))
            self.wait_for_sync_completed()
            self.wait_for_message_list()

    def setup_account_first_step(self, user, email):
        """
        Set up a new email account in the email app and login.
        If we've just started out, email will open directly to "New Account").
        """
        if not self.no_existing_account(email):
            return

        # (At this point we are now in the 'New account' screen by one path or another.)
        self.marionette.find_element(*DOM.Email.username).send_keys(user)
        self.marionette.find_element(*DOM.Email.email_addr).send_keys(email)
        self.tap_next_account_info()

    def no_existing_account(self, email):
        """
        Check if the new account header is present
        """
        try:
            self.parent.wait_for_element_displayed(
                *DOM.Email.setup_account_header)
            self.marionette.find_element(*DOM.Email.setup_account_header)
            return True
        except:

            #  If exception raised --> other account has been alread set up
            self.UTILS.reporting.logResult(
                "info", "It is necessary to switch to another email account.")

            if self.switch_account(email):
                return False

            # It's not setup already, so prepare to set it up!
            set_settings = self.UTILS.element.getElement(
                DOM.Email.settings_set_btn, "Settings set button")
            set_settings.tap()

            add_account_btn = self.UTILS.element.getElement(
                DOM.Email.settings_add_account_btn, "Add account button")
            time.sleep(2)
            add_account_btn.tap()
            return True

    def switch_account(self, address):
        settings_menu = self.UTILS.element.getElement(
            DOM.Email.settings_menu_btn, "Settings menu button")
        settings_menu.tap()

        try:
            self.UTILS.reporting.logResult(
                "info",
                "First, check whether we have one account configured or MORE")
            self.parent.wait_for_element_displayed(
                *DOM.Email.switch_account_panel_one_account)
            self.UTILS.reporting.logResult(
                "info",
                "There's only a single account configured. Time to check if\
                                                        it's necessary to do the change"
            )
            try:
                self.parent.wait_for_element_present(
                    *DOM.Email.switch_account_current_account)
                current_account = self.marionette.find_element(
                    *DOM.Email.switch_account_current_account)
                """
                Since the element is not displayed, sometimes we cannot access to the text using .text
                This way is more secure
                """
                current_account_text = self.marionette.execute_script(
                    "return arguments[0].innerHTML",
                    script_args=[current_account])

                self.UTILS.reporting.logResult(
                    'info', "Current account: {}".format(current_account_text))
                self.UTILS.reporting.logResult(
                    'info', "Account to switch: {}".format(address))

                screenshot = self.UTILS.debug.screenShotOnErr()
                self.UTILS.reporting.logResult('info', "Screenshot",
                                               screenshot)

                if current_account_text == address:
                    self.UTILS.reporting.logResult(
                        "info",
                        "Already in the account we want - switch back to inbox."
                    )
                    self.goto_folder_from_list(_("Inbox"))
                    return True
                else:
                    self.UTILS.reporting.logResult(
                        "info",
                        "It looks like the account we want to switch is not set up yet, so we cannot switch to it"
                    )
                    return False
            except:
                self.UTILS.reporting.logResult(
                    "info", "ONE ACCOUNT - something went wrong")

        except:
            self.UTILS.reporting.logResult(
                "info", "Well, we have at least 2 accounts configured")

            self.UTILS.reporting.logResult(
                "info",
                "Checking whether exists a scroll containing different accounts"
            )
            self.parent.wait_for_element_displayed(
                *DOM.Email.switch_account_scroll_outer)

            self.UTILS.reporting.logResult(
                "info",
                "Check if the current account is the one we we want to change")
            self.parent.wait_for_element_displayed(
                *DOM.Email.switch_account_current_account)
            current_account = self.marionette.find_element(
                *DOM.Email.switch_account_current_account)

            if current_account.text == address:
                self.UTILS.reporting.logResult(
                    "info",
                    "Already in the account we want - switch back to inbox.")
                self.goto_folder_from_list(_("Inbox"))
                return True

            self.UTILS.reporting.logResult(
                "info",
                "We're not in the account we want to be, so open the scroll to see what's there"
            )

            self.parent.wait_for_element_displayed(
                *DOM.Email.switch_account_scroll)
            scroll = self.marionette.find_element(
                *DOM.Email.switch_account_scroll)
            scroll.tap()

            self.UTILS.reporting.logResult(
                "info",
                "Now we have to iterate over all accounts displayed (but not already selected)"
            )
            self.parent.wait_for_element_displayed(
                *DOM.Email.switch_account_accounts_to_change)
            accounts = self.marionette.find_elements(
                *DOM.Email.switch_account_accounts_to_change)

            for account in accounts:
                if account.text == address:
                    self.UTILS.reporting.logResult(
                        "info",
                        "We got a winner. Switching to already configured account..."
                    )
                    account.tap()
                    self.wait_for_folder(_("Inbox"))
                    return True

            self.UTILS.reporting.logResult(
                "info",
                "It looks like the account we want to switch is not set up yet, so we cannot switch to it"
            )
            return False

    def switch_to_gmail_frame(self, expected_email):
        """
        Switches to gmail login frame when trying to set up a gmail account
        """
        gmail_frame = self.parent.wait_for_element_present(
            *DOM.Email.gmail_iframe_locator)
        self.marionette.switch_to_frame(gmail_frame)

        # Make sure the page is loaded
        email = self.parent.wait_for_element_present(
            *DOM.Email.gmail_email_locator)
        self.parent.wait_for_condition(
            lambda m: email.get_attribute('value') == expected_email)

    def _get_field(self, locator):
        self.parent.wait_for_element_displayed(*locator)
        return self.marionette.find_element(*locator)

    def gmail_login(self, passwd):
        self.marionette.find_element(
            *DOM.Email.gmail_password_locator).send_keys(passwd)
        self.marionette.find_element(*DOM.Email.gmail_sign_in_locator).tap()

    def wait_for_gmail_approve_access(self):
        self.parent.wait_for_element_displayed(
            *DOM.Email.gmail_approve_access_locator)

    def tap_gmail_approve_access(self):
        self.parent.wait_for_condition(lambda m: self.marionette.find_element(
            *DOM.Email.gmail_approve_access_locator).is_enabled())
        self.marionette.find_element(
            *DOM.Email.gmail_approve_access_locator).tap()

    def tap_next_account_info(self):
        self.marionette.find_element(
            *DOM.Email.login_account_info_next_btn).tap()

    def tap_next_account_preferences(self):
        self.parent.wait_for_element_displayed(
            *DOM.Email.login_account_prefs_next_btn, timeout=120)
        self.marionette.find_element(
            *DOM.Email.login_account_prefs_next_btn).tap()

    def tap_continue_to_mail(self):
        self.parent.wait_for_element_displayed(
            *DOM.Email.login_cont_to_email_btn, timeout=20)
        continue_btn = self.marionette.find_element(
            *DOM.Email.login_cont_to_email_btn)
        time.sleep(1)
        continue_btn.tap()

    def setup_hotmail_account(self, expected_email, passwd):
        """
        Switches to hotmail login frame when trying to set up a gmail account
        """
        self.parent.wait_for_element_displayed(
            *DOM.Email.email_label_for_passwd)
        label = self.marionette.find_element(*DOM.Email.email_label_for_passwd)
        self.UTILS.test.test(
            label.text == expected_email,
            "The account remains the same: {}".format(expected_email))

        self.parent.wait_for_element_displayed(*DOM.Email.password)
        self.marionette.find_element(*DOM.Email.password).send_keys(passwd)

        self.parent.wait_for_condition(lambda m: m.find_element(
            *DOM.Email.login_account_passwd_next_btn).is_enabled())
        self.marionette.find_element(
            *DOM.Email.login_account_passwd_next_btn).tap()
示例#28
0
class Messages(object):

    def __init__(self, parent):
        self.apps = parent.apps
        self.data_layer = parent.data_layer
        self.parent = parent
        self.marionette = parent.marionette
        self.UTILS = parent.UTILS
        self.actions = Actions(self.marionette)

    @retry(5)
    def launch(self):
        self.app = self.apps.launch(self.__class__.__name__)
        self.UTILS.element.waitForNotElements(DOM.GLOBAL.loading_overlay,
                                              self.__class__.__name__ + " app - loading overlay")
        return self.app

    def cancelSettings(self):
        self.UTILS.reporting.logResult("info", "Cliking on messages options button")
        options_btn = self.UTILS.element.getElement(DOM.Messages.messages_options_btn,
                                                    "Messages option button is displayed")
        options_btn.tap()

        # Press cancel button
        cancelBtn = self.UTILS.element.getElement(DOM.Messages.cancel_btn_msg,
                                                  "Press Cancel button")
        cancelBtn.tap()

    def deleteSubject(self, subject):
        self.UTILS.reporting.logResult("info", "Cliking on messages options button")
        x = self.UTILS.element.getElement(DOM.Messages.messages_options_btn,
                                          "Messages option button is displayed")
        x.tap()

        # Press add subject button
        self.UTILS.reporting.logResult("info", "Cliking on delete subject button")
        x = self.UTILS.element.getElement(DOM.Messages.deletesubject_btn_msg_opt,
                                          "delete subject option button is displayed")
        x.tap()

    def addSubject(self, subject):
        self.UTILS.reporting.logResult("info", "Cliking on messages options button")
        x = self.UTILS.element.getElement(DOM.Messages.messages_options_btn,
                                          "Messages option button is displayed")
        x.tap()

        # Press add subject button
        screenshot = self.UTILS.debug.screenShotOnErr()
        self.UTILS.reporting.logResult('info', "Screenshot", screenshot)

        self.UTILS.reporting.logResult("info", "Cliking on add subject button")
        x = self.UTILS.element.getElement(DOM.Messages.addsubject_btn_msg_opt,
                                          "add subject option button is displayed")
        x.tap()

        self.UTILS.general.typeThis(DOM.Messages.target_subject,
                                    "Target Subject  field",
                                    subject,
                                    p_no_keyboard=True,
                                    p_validate=False,
                                    p_clear=False,
                                    p_enter=False)

    def checkAirplaneModeWarning(self):
        """
        Checks for the presence of the popup
        warning message if you just sent a message
        while in 'airplane mode' (also removes
        the message so you can continue).
        """
        x = self.UTILS.element.getElement(DOM.Messages.airplane_warning_message,
                                          "Airplane mode warning message",
                                          True, 5, False)
        if x:
            self.UTILS.reporting.logResult("info",
                                           "Warning message title detected = '" + x.text + "'.")

            x = self.UTILS.element.getElement(DOM.Messages.airplane_warning_ok, "OK button")
            x.tap()

    def check_last_message_contents(self, expected, mms=False):
        """
        Get the last message text and check it against the expected value.
        """
        msg = self.last_message_in_this_thread()
        dom = DOM.Messages.last_message_mms_text if mms else DOM.Messages.last_message_text
        msg_text = self.marionette.find_element(*dom, id=msg.id)
        self.UTILS.test.test((msg_text and msg_text.text == expected),
                             u"Expected message text = '{}' ({}) (got '{}' ({})).".
                             format(expected, len(expected), msg_text.text, len(msg_text.text)))

    def checkIsInToField(self, target, targetIsPresent=True):
        """
        Verifies if a number (or contact name) is
        displayed in the "To: " field of a compose message.<br>
        (Uses 'caseless' search for this.)
        """
        time.sleep(1)
        x = self.UTILS.element.getElements(DOM.Messages.target_numbers, "'To:' field contents", False)

        boolOK = False
        for i in x:
            if i.text.lower() == str(target).lower():
                boolOK = True
                break

        testMsg = "is" if targetIsPresent else "is not"
        testMsg = "\"" + str(target) + "\" " + testMsg + " in the 'To:' field."
        self.UTILS.test.test(boolOK == targetIsPresent, testMsg)
        return boolOK

    def checkMMSIcon(self, thread_name):

        # Get the thread for which we want to check the icon existence
        selector = ("xpath", DOM.Messages.thread_selector_xpath.format(thread_name))
        elem = self.UTILS.element.getElement(selector, "Message thread for " + thread_name)
        """
        But, in order to make sure we're getting the specific frame, what we trully
        got above is an inner child of the thread element. So, we gotta get the father
        """
        thread = self.marionette.execute_script("""
            return arguments[0].parentNode;
        """, script_args=[elem])

        # Checks for the presence of the MMS icon
        icon = thread.find_element(*DOM.Messages.mms_icon)
        if icon:
            self.UTILS.test.test(icon is not None, "MMS icon detected for thread [{}]".format(thread_name))

    def checkNumberIsInToField(self, target):
        """
        Verifies if a number is contained in the
        "To: " field of a compose message (even if it's
        not displayed - i.e. a contact name is displayed,
        but this validates the <i>number</i> for that
        contact).
        """
        x = self.UTILS.element.getElements(DOM.Messages.target_numbers, "'To:' field contents")

        boolOK = False
        for i in x:
            if i.get_attribute("data-number") == target:
                boolOK = True
                break

        self.UTILS.test.test(boolOK,
                             "\"" + str(target) + "\" is the number in one of the 'To:' field targets.")
        return boolOK

    def checkThreadHeader(self, header):
        """
        Verifies if a string is contained in the header
        """
        x = self.UTILS.element.getElement(DOM.Messages.message_header, "Header")

        boolOK = False
        if x.get_attribute("data-number") == header:
            boolOK = True

        self.UTILS.test.test(boolOK, "\"" + str(header) + "\" is the header in the SMS conversation.")
        return boolOK

    def checkThreadHeaderWithNameSurname(self, header):
        """
        Verifies if a string is contained in the header
        """
        x = self.UTILS.element.getElement(DOM.Messages.message_header, "Header")

        boolOK = False

        if x.text == header:
            boolOK = True

        self.UTILS.test.test(boolOK, "\"" + header + "\" is the header in the SMS conversation.")
        return boolOK

    def closeThread(self):
        """
        Closes the current thread (returns you to the
        'thread list' SMS screen).
        """
        self.go_back()
        self.UTILS.element.waitForElements(("xpath", "//h1[text()='{}']".format(_("Messages"))),
                                           "Messages main header")

    def countMessagesInThisThread(self):
        """
        Returns the number of messages in this thread
        (assumes you're already in the thread).
        """
        try:
            return len(self.UTILS.element.getElements(DOM.Messages.message_list, "Messages"))
        except:
            return 0

    def countNumberOfThreads(self):
        """
        Count all threads (assumes the messagin app is already open).
        """
        try:
            return len(self.UTILS.element.getElements(DOM.Messages.threads_list, "Threads"))
        except:
            return 0

    def create_and_send_mms(self, attached_type, nums, m_text):

        self.gallery = Gallery(self.parent)
        self.video = Video(self.parent)
        self.music = Music(self.parent)

        self.launch()
        self.startNewSMS()
        self.addNumbersInToField(nums)
        self.enterSMSMsg(m_text)

        if attached_type == "image":
            # Add an image file
            self.UTILS.general.add_file_to_device('./tests/_resources/80x60.jpg')
            self.create_mms_image()
            self.gallery.click_on_thumbnail_at_position_mms(0)
        elif attached_type == "cameraImage":
            # Add an image file from camera
            self.create_mms_camera_image()
            time.sleep(3)
        elif attached_type == "video":
            # Load an video file into the device.
            self.UTILS.general.add_file_to_device('./tests/_resources/mpeg4.mp4')
            self.create_mms_video()
            self.video.click_on_video_at_position_mms(0)
        elif attached_type == "audio":
            # Load an video file into the device.
            self.UTILS.general.add_file_to_device('./tests/_resources/AMR.amr')
            self.create_mms_music()
            self.music.click_on_song_mms()
        else:
            # self.UTILS.reporting.logResult("info", "incorrect value received")
            msg = "FAILED: Incorrect parameter received in create_and_send_mms()"\
                ". attached_type must being image, video or audio."
            self.UTILS.test.test(False, msg)

        time.sleep(2)
        self.sendSMS()
        return self.last_sent_message_timestamp()

    def create_and_send_sms(self, nums, msg):
        """
        Create and send a new SMS.<br>
        <b>Note:</b> The nums field must be an array of numbers
        or contact names.
        """
        self.startNewSMS()
        self.addNumbersInToField(nums)
        self.enterSMSMsg(msg)

        # The header should now say how many recipients.
        time.sleep(2)  # give the header time to change.

        num_recs = len(nums)
        search_str = _(" recipient") if num_recs == 1 else _(" recipients")
        self.UTILS.element.headerCheck(str(num_recs) + search_str)

        # Send the message.
        self.sendSMS()

    def create_mms_image(self):
        attach = self.UTILS.element.getElement(DOM.Messages.attach_button, "Attach button")
        attach.tap()

        self.marionette.switch_to_frame()
        gallery = self.UTILS.element.getElement(DOM.Messages.mms_from_gallery, "From gallery")
        gallery.tap()

        self.UTILS.iframe.switchToFrame(*DOM.Gallery.frame_locator)

    def create_mms_camera_image(self):
        self.camera = Camera(self.parent)

        attach = self.UTILS.element.getElement(DOM.Messages.attach_button, "Attach button")
        attach.tap()

        self.marionette.switch_to_frame()
        camera = self.UTILS.element.getElement(DOM.Messages.mms_from_camera, "From Camera")
        camera.tap()

        self.UTILS.iframe.switchToFrame(*DOM.Camera.frame_locator)

        # Take a picture.
        self.camera.take_and_select_picture()

        self.UTILS.iframe.switchToFrame(*DOM.Messages.frame_locator)

    def create_mms_music(self):

        attach = self.UTILS.element.getElement(DOM.Messages.attach_button, "Attach button")
        attach.tap()

        self.marionette.switch_to_frame()
        music = self.UTILS.element.getElement(DOM.Messages.mms_from_music, "From music")
        music.tap()

        self.UTILS.iframe.switchToFrame(*DOM.Music.frame_locator)

    def go_back(self):
        """Press back button in messages thread
        """
        # TODO: remove tap with coordinates after Bug 1061698 is fixed
        self.UTILS.element.getElement(DOM.Messages.header_link_locator, "Back button").tap(25, 25)

    def create_mms_video(self):

        attach = self.UTILS.element.getElement(DOM.Messages.attach_button, "Attach button")
        attach.tap()

        self.marionette.switch_to_frame()

        video = self.UTILS.element.getElement(DOM.Messages.mms_from_video, "From video")
        video.tap()

        self.UTILS.iframe.switchToFrame(*DOM.Video.frame_locator)

    def delete_all_threads(self):
        """
        Deletes all threads (assumes the messagin app is already open).
        """
        try:
            self.parent.wait_for_element_displayed(*DOM.Messages.no_threads_message, timeout=3)
            no_threads_message = self.marionette.find_element(*DOM.Messages.no_threads_message)
            if no_threads_message.is_displayed():
                self.UTILS.reporting.logResult("info", "(No message threads to delete.)")
        except:
            self.UTILS.reporting.logResult("info", "Deleting message threads ...")
            self.threadEditModeON()

            select_threads = self.UTILS.element.getElement(
                DOM.Messages.edit_msgs_select_threads_btn, "Delete threads button")
            select_threads.tap()

            select_all_btn = self.UTILS.element.getElement(DOM.Messages.check_all_threads_btn, "Select all button")
            select_all_btn.tap()

            self.deleteSelectedThreads()
            self.UTILS.element.waitForElements(DOM.Messages.no_threads_message,
                                               "No message threads notification", True, 60)

    def deleteMessagesInThisThread(self, msg_array=False):
        """
        Enters edit mode, selects the required messages and
        deletes them.<br>
        msg_array is an array of numbers.
        If it's not specified then all messages in this
        thread will be deleted.
        """
        if msg_array:
            self.editAndSelectMessages(msg_array)
        else:

            # Go into messages Settings..
            edit_btn = self.UTILS.element.getElement(DOM.Messages.edit_messages_icon, "Edit button")
            edit_btn.tap()

            select_btn = self.UTILS.element.getElement(DOM.Messages.edit_msgs_select_btn, "Select button")
            select_btn.tap()

            # Press select all button.
            select_all_btn = self.UTILS.element.getElement(DOM.Messages.check_all_messages_btn, "'Select all' button")
            select_all_btn.tap()

        self.deleteSelectedMessages()

    def deleteSelectedMessages(self):
        self.UTILS.reporting.debug("*** Tapping top Delete button")
        delete_btn = self.UTILS.element.getElement(DOM.Messages.delete_messages_ok_btn, "Delete button")
        delete_btn.tap()
        time.sleep(2)

        self.UTILS.reporting.debug("*** Tap Delete messages confirmation button")
        confirm_btn = self.UTILS.element.getElement(
            DOM.Messages.delete_threads_ok_btn, "Delete messages confirmation button")
        confirm_btn.tap()
        time.sleep(2)

    def deleteSelectedThreads(self):
        delete_btn = self.UTILS.element.getElement(DOM.Messages.threads_delete_button, "Delete threads button")
        delete_btn.tap()

        delete_confirm_btn = self.UTILS.element.getElement(
            DOM.Messages.delete_threads_ok_btn, "Delete threads confirmation button")
        delete_confirm_btn.tap()

    def deleteThreads(self, target_array=False):
        """
        Enters edit mode, selects the required messages and
        deletes them.<br>
        target_array is an array of target numbers
        or contacts which identify the threads to be selected.
        If it's not specified then all messages in this
        thread will be deleted.
        """
        try:
            self.parent.wait_for_element_displayed(*DOM.Messages.no_threads_message, timeout=2)
            x = self.marionette.find_element(*DOM.Messages.no_threads_message)
            if x.is_displayed():
                self.UTILS.reporting.logResult("info", "(No message threads to delete.)")
        except:
            self.UTILS.reporting.logResult("info", "Deleting message threads ...")
            if target_array:
                self.UTILS.reporting.debug("*** Selecting threads for deletion [{}]".format(target_array))
                self.editAndSelectThreads(target_array)
                self.UTILS.reporting.debug("*** Threads selected")
                self.deleteSelectedThreads()
            else:
                self.delete_all_threads()

    def editAndSelectMessages(self, msg_array):
        """
        Puts this thread into Edit mode and selects
        the messages listed in msg_array.<br>
        msg_array is an array of numbers.
        """
        edit_btn = self.UTILS.element.getElement(DOM.Messages.edit_messages_icon, "Edit button")
        edit_btn.tap()
        time.sleep(2)

        # Go into message edit mode..
        select_btn = self.UTILS.element.getElement(DOM.Messages.edit_msgs_select_btn, "Select messages button")
        select_btn.tap()
        time.sleep(2)

        messages = self.UTILS.element.getElements(DOM.Messages.message_list, "Messages")
        for msg in msg_array:
            messages[msg].tap()

    def editAndSelectThreads(self, target_array):
        """
        Puts this thread into Edit mode and selects
        the messages listed in p_msg_array.<br>
        target_array is an array of target numbers
        or contacts which identify the threads to be selected.
        """
        # Go into edit mode..
        self.threadEditModeON()

        select_btn = self.UTILS.element.getElement(DOM.Messages.edit_msgs_select_threads_btn, "Select threads button")
        select_btn.tap()

        if len(target_array) == 0:
            return

        for i in target_array:
            self.UTILS.reporting.debug("selecting thread for [{}]".format(i))
            thread = self.UTILS.element.getElement(("xpath", DOM.Messages.thread_selector_xpath.format(i)),
                                                   "Thread checkbox for '{}'".format(i))
            self.UTILS.reporting.debug("Trying to tap in element {}".format(thread))
            thread.tap()

        # Finally check that all desired threads have been selected
        header = self.UTILS.element.getElement(DOM.Messages.edit_threads_header, "Edit threads header").text
        expected_title = str(len(target_array)) if len(target_array) else _("Delete messages")
        self.UTILS.test.test(expected_title in header, "Check that all desired threads have been selected")

    def enterSMSMsg(self, msg, not_keyboard=True):
        """
        Create and send a message (assumes we are in a new 'create new message'
        screen with the destination number filled in already).
        """
        self.parent.wait_for_element_displayed(*DOM.Messages.input_message_area)
        input_area = self.marionette.find_element(*DOM.Messages.input_message_area)
        input_area.tap()
        input_area.send_keys(msg)

        # Validate the field.
        # Get the element again in order to avoid StaleElementException
        input_area = self.marionette.find_element(*DOM.Messages.input_message_area)
        self.UTILS.test.test(input_area.text == msg,
                             u'The text in the message area is "{}". Expected: "{}"'.format(input_area.text, msg))

    def addNumbersInToField(self, nums):
        """
        Add the phone numbers in the 'To' field of this sms message.
        Assumes you are in 'create sms' screen.
        """

        # This variable is used to keep track of the appearance of the keyboard frame
        n = 0

        for num in nums:
            """
            Even though we don't use the keyboard for putting the number in,
            we need it for the ENTER button (which allows us to put more than
            one number in).
            So check that the keyboard appears when we tap the "TO" field if we have
            more than one number.
            """
            if len(nums) > 1:
                self.UTILS.reporting.logResult("info", "Checking the keyboard appears when I tap the 'To' field ...")
                to_field = self.UTILS.element.getElement(DOM.Messages.target_numbers_empty, "Target number field")
                to_field.tap()

                boolKBD = False
                self.marionette.switch_to_frame()

                if n < 1:

                    try:
                        # A 'silent' check to see if the keyboard iframe appears.
                        elDef = ("xpath", "//iframe[contains(@{}, '{}')]".
                                 format(DOM.Keyboard.frame_locator[0], DOM.Keyboard.frame_locator[1]))
                        self.parent.wait_for_element_displayed(*elDef, timeout=2)
                        boolKBD = True
                    except:
                        boolKBD = False

                    self.UTILS.test.test(
                        boolKBD, "Keyboard is displayed when 'To' field is clicked for the first time")

                self.UTILS.iframe.switchToFrame(*DOM.Messages.frame_locator)

            if n == 0:

                self.UTILS.general.typeThis(DOM.Messages.target_numbers_empty,
                                            "Target number field",
                                            num,
                                            p_no_keyboard=True,
                                            p_validate=False,
                                            p_clear=False,
                                            p_enter=True)

            else:
                self.UTILS.general.typeThis(DOM.Messages.target_numbers_empty,
                                            "Target number field",
                                            num,
                                            p_no_keyboard=True,
                                            p_validate=False,
                                            p_clear=False,
                                            p_enter=False)
                input_area = self.UTILS.element.getElement(DOM.Messages.input_message_area, "Target number field")
                input_area.tap()

            n += 1

    def addContactToField(self, contact_name):
        self._search_for_contact(contact_name)
        # Now check the correct name is in the 'To' list.
        self.checkIsInToField(contact_name)

    def _select_forward_option_for(self, element):
        self.actions.long_press(element, 2).perform()
        self.UTILS.reporting.logResult("info", "Clicking on forward button")
        forward_option = self.UTILS.element.getElement(DOM.Messages.forward_btn_msg_opt, "Forward button is displayed")
        forward_option.tap()

    def _search_for_contact(self, contact_name):
        self.contacts = Contacts(self.parent)
        self.selectAddContactButton()
        self.UTILS.iframe.switchToFrame(*DOM.Contacts.frame_locator)

        self.contacts.search(contact_name)
        self.contacts.check_search_results(contact_name)

        results = self.UTILS.element.getElements(DOM.Contacts.search_results_list, "Contacts search results")
        for result in results:
            if result.text == contact_name:
                result.tap()
                break

        # Switch back to the sms iframe.
        self.apps.switch_to_displayed_app()

    def forwardMessage(self, msg_type, target_telNum):
        """
        Forwards the last message of the thread to a number
        """

        self.UTILS.reporting.logResult('info', "The message type to forward is: {}".format(msg_type))

        if msg_type == "sms" or msg_type == "mms":
            self.UTILS.reporting.logResult("info", "Open {} option with longtap on it".format(msg_type))
            last = self.last_message_in_this_thread()
            body = self.marionette.find_element(*DOM.Messages.last_message_body, id=last.id)
            self._select_forward_option_for(body)

        elif msg_type == "mmssub":
            self.UTILS.reporting.logResult("info", "Open mms with subject options with longtap on it")
            mms_subject = self.UTILS.element.getElement(DOM.Messages.received_mms_subject, "Target MMS field")
            self._select_forward_option_for(mms_subject)

        else:
            self.UTILS.reporting.logResult("info", "incorrect value received")
            self.UTILS.test.test(False, "Incorrect value received")

        self.addNumbersInToField([target_telNum])

        self.UTILS.reporting.logResult("info", "Clicking on Send button")
        self.sendSMS()

    def forwardMessageToContact(self, msg_type, contact_name):
        """
        Forwards the last message of the thread to a contact, searching for it
        """
        self.UTILS.reporting.logResult('info', "The message type to forward is: {}".format(msg_type))

        if msg_type == "sms" or msg_type == "mms":
            # Open sms option with longtap on it
            self.UTILS.reporting.logResult("info", "Open sms option with longtap on it")
            sms = self.last_message_in_this_thread()
            body = self.marionette.find_element(*DOM.Messages.last_message_body, id=sms.id)
            self._select_forward_option_for(body)

        elif msg_type == "mmssub":
            # Open mms option with longtap on it
            self.UTILS.reporting.logResult("info", "Open mms with subject options with longtap on it")
            mms_subject = self.UTILS.element.getElement(DOM.Messages.received_mms_subject,
                                                        "Target MMS field")
            self._select_forward_option_for(mms_subject)

        else:
            self.UTILS.reporting.logResult("info", "incorrect value received")
            self.UTILS.test.test(False, "Incorrect value received")

        # Search for the contact and check it's been added
        self.addContactToField(contact_name)

        # Send the mms.
        self.UTILS.reporting.logResult("info", "Clicking on Send button")
        self.sendSMS()

    def forwardMessageToMultipleRecipients(self, msg_type, target_telNum, contact_name):
        self.UTILS.reporting.logResult('info', "The message type to forward is: {}".format(msg_type))

        if msg_type == "sms" or msg_type == "mms":
            # Open sms option with longtap on it
            self.UTILS.reporting.logResult("info", "Open sms option with longtap on it")
            sms = self.last_message_in_this_thread()
            body = self.marionette.find_element(*DOM.Messages.last_message_body, id=sms.id)
            self._select_forward_option_for(body)

        elif msg_type == "mmssub":
            # Open mms option with longtap on it
            self.UTILS.reporting.logResult("info", "Open mms with subject options with longtap on it")
            mms_subject = self.UTILS.element.getElement(DOM.Messages.received_mms_subject,
                                                        "Target MMS field")
            self._select_forward_option_for(mms_subject)

        else:
            self.UTILS.reporting.logResult("info", "incorrect value received")
            self.UTILS.test.test(False, "Incorrect value received")

        # Add phone numbers
        self.addNumbersInToField([target_telNum])
        # Search for the contact and check it's been added
        self.addContactToField(contact_name)

        # Send the mms.
        self.UTILS.reporting.logResult("info", "Clicking on Send button")
        self.sendSMS()

    def get_mms_attachments_info(self, mms):
        """Give name and file size for all attachments in an MMS.

        Given an MMS, return a list containing a dictionary for every attachment,
        with two keys, name and size.
        """
        attachment_names = self.marionette.find_elements(*DOM.Messages.mms_attachment_names, id=mms.id)
        attachment_sizes = self.marionette.find_elements(*DOM.Messages.mms_attachment_sizes, id=mms.id)
        result = []
        for (i, name) in enumerate(attachment_names):
            inner_text = self.marionette.execute_script("""return arguments[0].innerHTML;""", script_args=[name])
            att = {}
            att["name"] = inner_text
            size_elem = attachment_sizes[i].get_attribute("data-l10n-args")
            size = size_elem[size_elem.index(":") + 2:size_elem.rfind("\"")]
            i = i + 1
            att["size"] = size
            result.append(att)
        return result

    def getThreadText(self, num):
        """
        Returns the preview text for the thread for this number (if it exists),
        or False if either the thread doesn't exist or can't be found.
        """
        if self.threadExists(num):
            x = self.UTILS.element.getElements(DOM.Messages.threads_list, "Threads")

            for thread in x:
                try:
                    thread.find_element("xpath", ".//p[text()='{}']".format(num))
                    z = thread.find_element("xpath", ".//span[@class='body-text']")
                    return z.text
                except:
                    pass
        return False

    def header_addToContact(self):
        """
        Taps the header and tries to tap the 'Add to an existsing contact' button.
        - Assumes we are looking at a message thread already.
        - Leaves you in the correct iframe to continue (contacts).
        """
        x = self.UTILS.element.getElement(DOM.Messages.message_header, "Thread header")
        x.tap()

        x = self.UTILS.element.getElement(DOM.Messages.header_add_to_contact_btn,
                                          "'Add to an existing contact' button")
        x.tap()

        # Switch to correct iframe.
        self.UTILS.iframe.switchToFrame(*DOM.Contacts.frame_locator)

    def header_call(self):
        """Tap on the header of a messages thread and dial the number
        """
        x = self.UTILS.element.getElement(DOM.Messages.message_header, "Thread header")
        x.tap()

        # Select dialer option.
        x = self.UTILS.element.getElement(DOM.Messages.header_call_btn, "'Call' button")
        x.tap()

        # Switch to correct iframe.
        self.UTILS.iframe.switchToFrame(*DOM.Dialer.frame_locator)

    def header_createContact(self):
        """
        Taps the header and tries to tap the 'send message' button.
        - Assumes we are looking at a message thread already.
        - Leaves you in the correct iframe to continue.
        """
        x = self.UTILS.element.getElement(DOM.Messages.message_header, "Thread header")
        x.tap()

        x = self.UTILS.element.getElement(DOM.Messages.header_create_new_contact_btn,
                                          "'Create new contact' button")
        x.tap()

        # Switch to correct iframe.
        self.UTILS.iframe.switchToFrame(*DOM.Contacts.frame_locator)

    def header_sendMessage(self):
        """
        Taps the header and tries to tap the 'send message' button.
        - Assumes we are looking at a message thread already.
        - Leaves you in the correct iframe to continue.
        """
        x = self.UTILS.element.getElement(DOM.Messages.message_header, "Thread header")
        x.tap()

        x = self.UTILS.element.getElement(DOM.Messages.header_send_message_btn, "'Send message' button")
        x.tap()

    def last_message_in_this_thread(self):
        """
        Returns an object of the last message in the current thread.
        """
        self.parent.wait_for_element_present(*DOM.Messages.last_message, timeout=20)
        message = self.marionette.find_element(*DOM.Messages.last_message)
        self.UTILS.element.scroll_into_view(message)
        return message

    def last_sent_message_timestamp(self):
        """Returns the timestamp of the last sent message
        """
        send_time = self.marionette.find_element(*DOM.Messages.last_sent_message).get_attribute("data-timestamp")
        return float(send_time) / 1000

    def last_sent_message(self):
        """Returns the last sent message
        """
        return self.marionette.find_element(*DOM.Messages.last_sent_message)

    def open_attached_file(self, frame_to_change):
        elem = DOM.Messages.last_message_attachment_av
        last = self.UTILS.element.getElement(elem, "Last message attachment")
        self.UTILS.element.scroll_into_view(last)

        # Now get the thumbnail in order to open it
        thumb = last.find_element(*DOM.Messages.last_message_thumbnail)
        thumb.tap()
        self.UTILS.iframe.switchToFrame(*frame_to_change)

    def openThread(self, num):
        """
        Opens the thread for this number (assumes we're looking at the
        threads in the messaging screen).
        """
        try:
            thread_el = ("xpath", DOM.Messages.thread_selector_xpath.format(num))
            x = self.UTILS.element.getElement(thread_el, "Message thread for " + num)
            x.tap()

            self.UTILS.element.waitForElements(DOM.Messages.send_message_button, "'Send' button")
        except Exception as e:
            x = self.UTILS.debug.screenShotOnErr()
            msg = "<b>NOTE:</b> The thread <i>may</i> have failed to open due to [{}].".format(e)
            self.UTILS.reporting.logResult("info", msg, x)

    def readLastSMSInThread(self):
        """
        Read last message in the current thread.
        """
        received_message = self.UTILS.element.getElements(DOM.Messages.received_messages,
                                                          "Received messages")[-1]
        return str(received_message.text)

    def readNewSMS(self, fromNum):
        """
        Read and return the value of the new message received from number.
        """
        x = self.UTILS.element.getElement(("xpath", DOM.Messages.messages_from_num.format(fromNum)),
                                          "Message from '" + fromNum + "'")
        x.tap()

        # (From gaiatest: "TODO Due to displayed bugs I cannot find a good wait
        # for switch btw views")
        time.sleep(5)

        # Return the last comment in this thread.
        return self.readLastSMSInThread()

    def removeContactFromToField(self, target):
        """
        Removes target from the "To" field of this SMS.<br>
        Returns True if it found the target, or False if not.
        """
        x = self.UTILS.element.getElements(DOM.Messages.target_numbers, "'To:' field contents")

        for i in range(len(x)):
            self.UTILS.reporting.logResult("info",
                                           "Checking target '{}' to '{}' ...".format(x[i].text, target))

            if x[i].text.lower() == target.lower():
                self.UTILS.reporting.logResult("info", "Tapping contact '" + target + "' ...")
                x[i].tap()

                try:

                    # This contact was added via 'add contact' icon.
                    self.parent.wait_for_element_displayed("xpath", "//button[text()='{}']".format(_("Remove")),
                                                           timeout=2)
                    y = self.marionette.find_element("xpath", "//button[text()='{}']".format(_("Remove")))
                    self.UTILS.reporting.logResult("info", "Tapping 'Remove' button.")
                    y.tap()
                    return True
                except:

                    # This contact was manually entered.
                    z = self.UTILS.element.getElements(DOM.Messages.target_numbers,
                                                       "Target to be removed")[i]
                    z.clear()
                    return True
        return False

    def selectAddContactButton(self):
        """
        Taps the 'add contact' button
        """
        add_btn = self.UTILS.element.getElement(DOM.Messages.add_contact_button, "Add contact button")
        add_btn.tap()

    def sendSMS(self):
        """
        Just presses the 'send' button (assumes everything else is done).
        """
        self.parent.wait_for_condition(lambda m: m.find_element(*DOM.Messages.send_message_button).is_enabled())
        send_btn = self.marionette.find_element(*DOM.Messages.send_message_button)
        send_btn.tap()

        # (Give the spinner time to appear.)
        time.sleep(2)
        self.UTILS.element.waitForNotElements(DOM.Messages.message_sending_spinner, "'Sending' icon", True, 180)

        # Check if we received the 'service unavailable' message.
        try:
            self.parent.wait_for_element_displayed(*DOM.Messages.service_unavailable_msg, timeout=2)
            screenshot = self.UTILS.debug.screenShotOnErr()
            msg = "'Service unavailable' message detected - unable to send sms!"
            self.UTILS.reporting.logResult("info", msg, screenshot)
            return False
        except:
            pass

        return True

    def startNewSMS(self):
        """
        Starts a new sms (doesn't fill anything in).
        Assumes the Messaging app is already launched.
        """
        newMsgBtn = self.UTILS.element.getElement(DOM.Messages.create_new_message_btn, "Create new message button")
        newMsgBtn.tap()

    def threadCarrier(self):

        # Returns the 'carrier' being used by this thread.
        x = self.UTILS.element.getElement(DOM.Messages.type_and_carrier_field, "Type and carrier information")
        parts = x.text.split("|")
        if len(parts) > 1:
            return parts[1].strip()
        return parts[0].strip()

    def threadEditModeOFF(self):
        """
        Turns off Edit mode while in the SMS threads screen.
        """
        x = self.UTILS.element.getElement(DOM.Messages.cancel_edit_threads, "Cancel button")
        x.tap()
        self.UTILS.element.waitForElements(DOM.Messages.edit_threads_button, "Edit button")

    def threadEditModeON(self):
        """
        Turns on Edit mode while in the SMS threads screen.
        """
        edit_btn = self.UTILS.element.getElement(DOM.Messages.edit_threads_button, "Edit button")
        edit_btn.tap()
        self.UTILS.element.waitForElements(DOM.Messages.cancel_edit_threads, "Cancel button")

    def threadExists(self, num):
        """
        Verifies that a thread exists for this number (returns True or False).
        """
        boolOK = False
        try:
            self.parent.wait_for_element_present("xpath", DOM.Messages.thread_selector_xpath.format(num), 1)
            boolOK = True
        except:
            boolOK = False

        return boolOK

    def threadType(self):
        """
        Returns the 'type' being used by this thread.
        """
        x = self.UTILS.element.getElement(DOM.Messages.type_and_carrier_field, "Type and carrier information")
        parts = x.text.split("|")
        typ = parts[0].strip()
        return typ if len(parts) > 1 else ''

    def time_of_last_message_in_thread(self):
        """
        Returns the time of the last message in the current thread.
        """
        t = self.UTILS.element.getElement(DOM.Messages.last_message_time, "Last message time")
        return t.text

    def time_of_thread(self, num):
        """
        Returns the time of a thread.
        """
        x = self.UTILS.element.getElement(("xpath", DOM.Messages.thread_timestamp_xpath.format(num)),
                                          "Thread time", True, 5, False)
        return x.text

    def thread_timestamp(self, num):
        """
        Returns the timestamp of a thread
        """
        x = self.marionette.find_element(*DOM.Messages.last_message).get_attribute("data-timestamp")
        return float(x)

    def verify_mms_received(self, attached_type, sender_number):

        self.UTILS.iframe.switchToFrame(*DOM.Messages.frame_locator)
        self.openThread(sender_number)
        message = self.last_message_in_this_thread()
        self.UTILS.test.test(message, "A received message appeared in the thread.", True)

        self.UTILS.reporting.debug("*** attached type: {}".format(attached_type))
        if attached_type == "img":
            elem = DOM.Messages.last_message_attachment_img
        elif attached_type == "video":
            elem = DOM.Messages.last_message_attachment_av
        elif attached_type == "audio":
            elem = DOM.Messages.last_message_attachment_av
        else:
            # self.UTILS.reporting.logResult("info", "incorrect value received")
            msg = "FAILED: Incorrect parameter received in verify_mms_received()"\
                ". Attached_type must be image, video or audio."
            self.UTILS.test.test(False, msg)

        self.UTILS.reporting.debug("*** searching for attachment type")
        # Look for all the attachments, since there can be more than one
        atts = self.UTILS.element.getElements(elem, "Last message attachments")
        self.UTILS.element.scroll_into_view(atts[0])
        found = False
        for att in atts:
            typ = att.get_attribute("data-attachment-type")
            self.UTILS.reporting.debug("*** searching for attachment type Result: {}".format(typ))
            if typ == attached_type:
                found = True
        if not found:
            msg = "No attachment with type {} was found in the message".format(attached_type)
            self.UTILS.test.test(False, msg)

    def wait_for_message(self, send_time=None, timeout=120):
        """Wait for a received message in the current thread and return it.
        """
        if not send_time:
            send_time = self.last_sent_message_timestamp()

        poll_time = 2
        poll_reps = (timeout / poll_time)
        result = False

        for i in range(poll_reps):
            # Get last message in this thread.
            last_msg = self.last_message_in_this_thread()

            if not last_msg:
                time.sleep(poll_time)
                continue

            # If the send_time timestamp is greater than this message's timestamp,it means the message
            # we expect has not arrived yet, so we have to wait a bit more.
            message_data_time = float(last_msg.get_attribute("data-timestamp")) / 1000
            fmt = "data-timestamp of last message in thread: {:.3f} send_time: {:.3f} --> {}"
            self.UTILS.reporting.debug(fmt.format(message_data_time, send_time, send_time > message_data_time))
            if send_time > message_data_time:
                continue

            # Is this a received message?
            if "incoming" in last_msg.get_attribute("class"):
                result = last_msg
                break

            # Nope - sleep then try again.
            time.sleep(poll_time)

        self.UTILS.test.test(result, "Last message in thread 'received' within {} seconds.".
                             format(timeout))
        return result