def test_ndt_result_increments_time_correctly(self):
        # Create a list of times every minute starting at 2016-1-1 8:00:00 and
        # ending at 2016-1-1 8:04:00. These will be the values that our mock
        # datetime.now() function returns.
        base_date = datetime.datetime(2016, 1, 1, 8, 0, 0, tzinfo=pytz.utc)
        dates = [base_date + datetime.timedelta(0, 60) * x for x in range(6)]

        with mock.patch.object(html5_driver.datetime,
                               'datetime',
                               autospec=True) as mocked_datetime:
            mocked_datetime.now.side_effect = dates

            result = html5_driver.NdtHtml5SeleniumDriver(
                browser='firefox',
                url='http://ndt.mock-server.com:7123/',
                timeout=1).perform_test()

        # And the sequence of returned values follows the expected timeline
        # that the readings are taken in.

        # yapf: disable
        self.assertEqual(
            result.start_time,
            datetime.datetime(2016, 1, 1, 8, 0, 0, tzinfo=pytz.utc))
        self.assertEqual(
            result.c2s_result.start_time,
            datetime.datetime(2016, 1, 1, 8, 1, 0, tzinfo=pytz.utc))
        self.assertEqual(
            result.s2c_result.start_time,
            datetime.datetime(2016, 1, 1, 8, 3, 0, tzinfo=pytz.utc))
        self.assertEqual(
            result.end_time,
            datetime.datetime(2016, 1, 1, 8, 5, 0, tzinfo=pytz.utc))
    def test_invalid_throughput_unit_raises_error(self):
        class NewDriver(object):
            def get(self, url):
                pass

            def close(self):
                pass

            def find_element_by_id(self, id):
                if id == 'download-speed-units':
                    return mock.Mock(text='Gb/s', autospec=True)
                elif id == 'download-speed':
                    return mock.Mock(text='72', autospec=True)
                elif id == 'upload-speed-units':
                    return mock.Mock(text='not a unit', autospec=True)
                else:
                    return mock.Mock(text='34', autospec=True)

            def find_elements_by_xpath(self, xpath):
                return [mock.Mock(autospec=True)]

        with mock.patch.object(html5_driver.webdriver,
                               'Firefox',
                               autospec=True,
                               return_value=NewDriver()):

            # And a value error is raised because the c2s throughput
            # unit was invalid.
            with self.assertRaises(ValueError):
                html5_driver.NdtHtml5SeleniumDriver(
                    browser='firefox',
                    url='http://ndt.mock-server.com:7123/',
                    timeout=1000).perform_test()
    def test_results_page_displays_non_numeric_latency(self):
        class NewDriver(object):
            def get(self, url):
                pass

            def close(self):
                pass

            def find_element_by_id(self, id):
                if id == 'upload-speed-units':
                    return mock.Mock(text='kb/s', autospec=True)
                elif id == 'download-speed-units':
                    return mock.Mock(text='Mb/s', autospec=True)
                elif id == 'latency':
                    return mock.Mock(text='Non-numeric value', autospec=True)
                else:
                    return mock.Mock(text='34', autospec=True)

            def find_elements_by_xpath(self, xpath):
                return [mock.Mock(autospec=True)]

        with mock.patch.object(html5_driver.webdriver,
                               'Firefox',
                               autospec=True,
                               return_value=NewDriver()):

            test_results = html5_driver.NdtHtml5SeleniumDriver(
                browser='firefox',
                url='http://ndt.mock-server.com:7123/',
                timeout=1000).perform_test()

        # And the appropriate error object is contained in the list
        self.assertEqual(len(test_results.errors), 1)
        self.assertEqual(test_results.errors[0].message,
                         'illegal value shown for latency: Non-numeric value')
 def test_unrecognized_browser_raises_error(self):
     selenium_driver = html5_driver.NdtHtml5SeleniumDriver(
         browser='not_a_browser',
         url='http://ndt.mock-server.com:7123',
         timeout=1)
     with self.assertRaises(ValueError):
         selenium_driver.perform_test()
    def test_results_page_displays_non_numeric_metrics(self):
        """A results page with non-numeric metrics results in error list errors.

        When latency, c2s_throughput, and s2c_throughput are all non-numeric values,
        corresponding error objects are added to the errors list that indicate
        that each of these values is invalid.
        """
        self.mock_page_elements['upload-speed'] = mock.Mock(
            text='Non-numeric value')
        self.mock_page_elements['download-speed'] = mock.Mock(
            text='Non-numeric value')
        self.mock_page_elements['latency'] = mock.Mock(
            text='Non-numeric value')

        result = html5_driver.NdtHtml5SeleniumDriver(
            browser='firefox',
            url='http://ndt.mock-server.com:7123/',
            timeout=1000).perform_test()

        self.assertIsNone(result.c2s_result.throughput)
        self.assertIsNone(result.s2c_result.throughput)
        self.assertIsNone(result.latency)
        self.assertErrorMessagesEqual([
            'illegal value shown for c2s throughput: Non-numeric value',
            'illegal value shown for s2c throughput: Non-numeric value',
            'illegal value shown for latency: Non-numeric value'
        ], result.errors)
    def test_results_page_displays_numeric_latency(self):
        """A valid (numeric) latency results in an empty errors list."""

        # Mock so always returns a numeric value for a WebElement.text attribute

        class NewDriver(object):
            def get(self, url):
                pass

            def close(self):
                pass

            def find_element_by_id(self, id):
                if id == 'download-speed-units':
                    return mock.Mock(text='Mb/s', autospec=True)
                elif id == 'upload-speed-units':
                    return mock.Mock(text='Mb/s', autospec=True)
                return mock.Mock(text='72', autospec=True)

            def find_elements_by_xpath(self, xpath):
                return [mock.Mock(autospec=True)]

        with mock.patch.object(html5_driver.webdriver,
                               'Firefox',
                               autospec=True,
                               return_value=NewDriver()):

            test_results = html5_driver.NdtHtml5SeleniumDriver(
                browser='firefox',
                url='http://ndt.mock-server.com:7123/',
                timeout=1000).perform_test()

        self.assertEqual(test_results.latency, 72.0)
        # And an error object is not contained in the list
        self.assertEqual(len(test_results.errors), 0)
    def test_reading_in_result_page_timeout_throws_error(self):

        # If a timeout exception occurs when the driver attempts to
        # read the metric page
        class NewDriver(object):
            def get(self, url):
                pass

            def close(self):
                pass

            def find_element_by_id(self, id):
                if id == 'upload-speed':
                    raise exceptions.TimeoutException
                else:
                    return mock.Mock(text='34', autospec=True)

            def find_elements_by_xpath(self, xpath):
                return [mock.Mock(autospec=True)]

        with mock.patch.object(html5_driver.webdriver,
                               'Firefox',
                               autospec=True,
                               return_value=NewDriver()):

            test_results = html5_driver.NdtHtml5SeleniumDriver(
                browser='firefox',
                url='http://ndt.mock-server.com:7123/',
                timeout=1000).perform_test()

        # The appropriate error object is contained in the list.
        self.assertEqual(test_results.errors[0].message,
                         'Test did not complete within timeout period.')
    def test_invalid_URL_throws_error(self):
        self.mock_driver.get.side_effect = (
            exceptions.WebDriverException('Failed to load test UI.'))
        result = html5_driver.NdtHtml5SeleniumDriver(browser='firefox',
                                                     url='invalid_url',
                                                     timeout=1).perform_test()

        self.assertErrorMessagesEqual(['Failed to load test UI.'],
                                      result.errors)
    def test_ndt_test_results_increments_time_correctly(self):
        # Create a list of times every minute starting at 2016-1-1 8:00:00
        # and ending at 2016-1-1 8:04:00. These will be the values that our
        # mock datetime.now() function returns.
        base_date = datetime.datetime(2016, 1, 1, 8, 0, 0, tzinfo=pytz.utc)
        dates = [base_date + datetime.timedelta(0, 60) * x for x in range(6)]

        class NewDriver(object):
            def get(self, url):
                pass

            def close(self):
                pass

            def find_element_by_id(self, id):
                if id == 'upload-speed-units':
                    return mock.Mock(text='kb/s', autospec=True)
                elif id == 'upload-speed':
                    return mock.Mock(text='72', autospec=True)
                elif id == 'download-speed-units':
                    return mock.Mock(text='Mb/s', autospec=True)
                else:
                    return mock.Mock(text='34', autospec=True)

            def find_elements_by_xpath(self, xpath):
                return [mock.Mock(autospec=True)]

        mock_driver = mock.patch.object(html5_driver.webdriver,
                                        'Firefox',
                                        autospec=True,
                                        return_value=NewDriver())
        mock_driver.start()
        with mock.patch.object(html5_driver.datetime,
                               'datetime',
                               autospec=True) as mocked_datetime:
            mocked_datetime.now.side_effect = dates

            test_results = html5_driver.NdtHtml5SeleniumDriver(
                browser='firefox',
                url='http://ndt.mock-server.com:7123/',
                timeout=1).perform_test()
        mock_driver.stop()

        # And the sequence of returned values follows the expected timeline
        # that the readings are taken in.
        self.assertEqual(
            test_results.start_time,
            datetime.datetime(2016, 1, 1, 8, 0, 0, tzinfo=pytz.utc))
        self.assertEqual(
            test_results.c2s_result.start_time,
            datetime.datetime(2016, 1, 1, 8, 1, 0, tzinfo=pytz.utc))
        self.assertEqual(
            test_results.s2c_result.start_time,
            datetime.datetime(2016, 1, 1, 8, 3, 0, tzinfo=pytz.utc))
        self.assertEqual(
            test_results.end_time,
            datetime.datetime(2016, 1, 1, 8, 5, 0, tzinfo=pytz.utc))
    def test_test_yields_valid_results_when_all_page_elements_are_expected_values(
            self):
        result = html5_driver.NdtHtml5SeleniumDriver(
            browser='firefox',
            url='http://ndt.mock-server.com:7123/').perform_test()

        self.assertEqual(1.0, result.c2s_result.throughput)
        self.assertEqual(2.0, result.s2c_result.throughput)
        self.assertEqual(3.0, result.latency)
        self.assertErrorMessagesEqual([], result.errors)
    def test_invalid_throughput_unit_raises_error(self):
        self.mock_page_elements['upload-speed-units'] = mock.Mock(
            text='not a unit')

        # And a value error is raised because the c2s throughput unit was
        # invalid.
        with self.assertRaises(ValueError):
            html5_driver.NdtHtml5SeleniumDriver(
                browser='firefox',
                url='http://ndt.mock-server.com:7123/',
                timeout=1000).perform_test()
    def test_safari_driver_can_be_used_for_test(self, mock_safari):
        mock_safari.return_value = self.mock_driver
        result = html5_driver.NdtHtml5SeleniumDriver(
            browser='safari',
            url='http://ndt.mock-server.com:7123/',
            timeout=1000).perform_test()

        self.assertEqual(1.0, result.c2s_result.throughput)
        self.assertEqual(2.0, result.s2c_result.throughput)
        self.assertEqual(3.0, result.latency)
        self.assertErrorMessagesEqual([], result.errors)
    def test_results_page_displays_non_numeric_latency(self):
        self.mock_page_elements['latency'] = mock.Mock(text='Non-numeric value')
        result = html5_driver.NdtHtml5SeleniumDriver(
            browser='firefox',
            url='http://ndt.mock-server.com:7123/').perform_test()

        self.assertEqual(1.0, result.c2s_result.throughput)
        self.assertEqual(2.0, result.s2c_result.throughput)
        self.assertIsNone(result.latency)
        self.assertErrorMessagesEqual(
            ['illegal value shown for latency: Non-numeric value'],
            result.errors)
    def test_invalid_throughput_unit_yields_error(self):
        self.mock_page_elements['upload-speed-units'] = mock.Mock(text='banana')

        result = html5_driver.NdtHtml5SeleniumDriver(
            browser='firefox',
            url='http://ndt.mock-server.com:7123/').perform_test()

        self.assertIsNone(result.c2s_result.throughput)
        self.assertEqual(2.0, result.s2c_result.throughput)
        self.assertEqual(3.0, result.latency)
        self.assertErrorMessagesEqual(
            ['Invalid throughput unit specified: banana'], result.errors)
    def test_fails_gracefully_when_start_button_not_in_dom(self):
        self.mock_elements_by_text['Start Test'] = None

        result = html5_driver.NdtHtml5SeleniumDriver(
            browser='firefox',
            url='http://ndt.mock-server.com:7123/').perform_test()

        self.assertIsNone(result.c2s_result.throughput)
        self.assertIsNone(result.s2c_result.throughput)
        self.assertIsNone(result.latency)
        self.assertErrorMessagesEqual(
            [html5_driver.ERROR_START_BUTTON_NOT_IN_DOM], result.errors)
    def test_test_in_progress_timeout_throws_error(self):
        # Call to webdriverwait throws timeout exception
        with mock.patch.object(html5_driver.ui,
                               'WebDriverWait',
                               side_effect=exceptions.TimeoutException,
                               autospec=True):
            result = html5_driver.NdtHtml5SeleniumDriver(
                browser='firefox',
                url='http://ndt.mock-server.com:7123/',
                timeout=1).perform_test()

        self.assertErrorMessagesEqual(
            ['Test did not complete within timeout period.'], result.errors)
    def test_invalid_URL_throws_error(self):
        self.mock_browser.get.side_effect = exceptions.WebDriverException(
            u'Failed to load test UI.')

        test_results = html5_driver.NdtHtml5SeleniumDriver(
            browser='firefox', url='invalid_url', timeout=1).perform_test()

        # We have one error
        self.assertEqual(len(test_results.errors), 1)

        # And that error is about test UI loading failure
        self.assertEqual(test_results.errors[0].message,
                         'Failed to load test UI.')
    def test_ndt_result_increments_time_correctly(self):
        # Create a list of mock times to be returned by datetime.now().
        times = []
        for i in range(11):
            times.append(datetime.datetime(2016, 1, 1, 0, 0, i))

        with mock.patch.object(html5_driver.datetime,
                               'datetime',
                               autospec=True) as mocked_datetime:
            # Patch datetime.now to return the next mock time on every call to
            # now().
            mocked_datetime.now.side_effect = times

            # Modify the create_browser mock to increment the clock forward one
            # call.
            @contextlib.contextmanager
            def mock_create_browser(unused_browser_name):
                datetime.datetime.now(pytz.utc)
                yield self.mock_driver

            browser_client_common.create_browser.side_effect = (
                mock_create_browser)

            # Modify the wait_until_element_is_visible mock to increment the
            # clock forward one call.
            def mock_visibility_of(unused_driver, unused_element,
                                   unused_timeout):
                datetime.datetime.now(pytz.utc)
                return True

            html5_driver.browser_client_common.wait_until_element_is_visible.side_effect = (
                mock_visibility_of)

            result = html5_driver.NdtHtml5SeleniumDriver(
                browser='firefox',
                url='http://ndt.mock-server.com:7123/').perform_test()

        # Verify the recorded times matches the expected sequence.
        self.assertEqual(times[0], result.start_time)
        # times[1] is the call from mock_firefox
        # times[2] is the check for visibility of "Start Test" button
        # times[3] is the check for visibility of c2s test start
        self.assertEqual(times[4], result.c2s_result.start_time)
        # times[5] is the check for visibility of s2c test start (start of s2c
        #   marks the end of c2s)
        self.assertEqual(times[6], result.c2s_result.end_time)
        self.assertEqual(times[7], result.s2c_result.start_time)
        # times[8] is the check for visibility of results page
        self.assertEqual(times[9], result.s2c_result.end_time)
        self.assertEqual(times[10], result.end_time)
    def test_c2s_start_timeout_yields_errors(self):
        """If waiting for just c2s start times out, expect just one error."""
        html5_driver.browser_client_common.wait_until_element_is_visible.side_effect = [
            True,  # "Start Test" button
            False,  # Upload speed label
            True,  # Download speed label
            True,  # Results div
        ]
        result = html5_driver.NdtHtml5SeleniumDriver(
            browser='firefox',
            url='http://ndt.mock-server.com:7123/').perform_test()

        self.assertErrorMessagesEqual(
            [browser_client_common.ERROR_C2S_NEVER_STARTED], result.errors)
    def test_results_page_displays_non_numeric_metrics(self):
        """A results page with non-numeric metrics results in error list errors.

        When latency, c2s_throughput, and s2c_throughput are all non-numeric values,
        corresponding error objects are added to the errors list that indicate
        that each of these values is invalid.
        """

        # We patch selenium's web driver so it always has a non numeric
        # value as a WebElement.text attribute
        class NewWebElement(object):
            def __init__(self):
                self.text = 'Non numeric value'

            def click(self):
                pass

        class NewDriver(object):
            def get(self, url):
                pass

            def close(self):
                pass

            def find_element_by_id(self, id):
                return NewWebElement()

            def find_elements_by_xpath(self, xpath):
                return [NewWebElement()]

        with mock.patch.object(html5_driver.webdriver,
                               'Firefox',
                               autospec=True,
                               return_value=NewDriver()):

            test_results = html5_driver.NdtHtml5SeleniumDriver(
                browser='firefox',
                url='http://ndt.mock-server.com:7123/',
                timeout=1000).perform_test()

        # And the appropriate error objects are contained in
        # the list
        self.assertEqual(
            test_results.errors[0].message,
            'illegal value shown for c2s throughput: Non numeric value')
        self.assertEqual(
            test_results.errors[1].message,
            'illegal value shown for s2c throughput: Non numeric value')
        self.assertEqual(test_results.errors[2].message,
                         'illegal value shown for latency: Non numeric value')
    def test_ndt_result_records_todays_times(self):
        # When we patch datetime so it shows our current date as 2016-01-01
        self.assertEqual(datetime.datetime.now(),
                         datetime.datetime(2016, 1, 1))
        result = html5_driver.NdtHtml5SeleniumDriver(
            browser='firefox',
            url='http://ndt.mock-server.com:7123/',
            timeout=1000).perform_test()

        # Then the readings for our test start and end times occur within
        # today's date
        self.assertEqual(result.start_time,
                         datetime.datetime(2016, 1, 1, tzinfo=pytz.utc))
        self.assertEqual(result.end_time,
                         datetime.datetime(2016, 1, 1, tzinfo=pytz.utc))
    def test_fails_gracefully_if_wait_for_start_button_times_out(self):
        # Simulate a webdriver timeout when waiting for any element to appear,
        # including the "Start Test" button.
        html5_driver.browser_client_common.wait_until_element_is_visible.return_value = (
            False)

        result = html5_driver.NdtHtml5SeleniumDriver(
            browser='firefox',
            url='http://ndt.mock-server.com:7123/').perform_test()

        self.assertIsNone(result.c2s_result.throughput)
        self.assertIsNone(result.s2c_result.throughput)
        self.assertIsNone(result.latency)
        self.assertErrorMessagesEqual(
            [html5_driver.ERROR_TIMED_OUT_WAITING_FOR_START_BUTTON],
            result.errors)
    def test_c2s_kbps_speed_conversion(self):
        """Test c2s speed converts from kb/s to Mb/s correctly."""
        # If c2s speed is 72 kb/s and s2c speed is 34 in the browser
        self.mock_page_elements['upload-speed'] = mock.Mock(text='72')
        self.mock_page_elements['upload-speed-units'] = mock.Mock(text='kb/s')
        self.mock_page_elements['download-speed'] = mock.Mock(text='34')
        self.mock_page_elements['download-speed-units'] = mock.Mock(text='Mb/s')
        result = html5_driver.NdtHtml5SeleniumDriver(
            browser='firefox',
            url='http://ndt.mock-server.com:7123/').perform_test()

        # Then c2s is converted from kb/s to Mb/s
        self.assertEqual(0.072, result.c2s_result.throughput)
        # And s2c is not
        self.assertEqual(34.0, result.s2c_result.throughput)
        self.assertEqual(3.0, result.latency)
        self.assertErrorMessagesEqual([], result.errors)
    def test_test_in_progress_timeout_throws_error(self):
        # Call to webdriverwait throws timeout exception
        with mock.patch.object(html5_driver.ui,
                               'WebDriverWait',
                               side_effect=exceptions.TimeoutException,
                               autospec=True):
            test_results = html5_driver.NdtHtml5SeleniumDriver(
                browser='firefox',
                url='http://ndt.mock-server.com:7123/',
                timeout=1).perform_test()

        # We have one error
        self.assertEqual(len(test_results.errors), 1)

        # And that is a timout error
        self.assertEqual(test_results.errors[0].message,
                         'Test did not complete within timeout period.')
    def test_test_in_progress_timeout_yields_timeout_errors(self):
        """If each test times out, expect an error for each timeout."""
        # Make the "Start Test" button visible, but others time out.
        html5_driver.browser_client_common.wait_until_element_is_visible.side_effect = [
            True,  # "Start Test" button
            False,  # Upload speed label
            False,  # Download speed label
            False,  # Results div
        ]
        result = html5_driver.NdtHtml5SeleniumDriver(
            browser='firefox',
            url='http://ndt.mock-server.com:7123/').perform_test()

        self.assertErrorMessagesEqual(
            [browser_client_common.ERROR_C2S_NEVER_STARTED,
             browser_client_common.ERROR_S2C_NEVER_STARTED,
             browser_client_common.ERROR_S2C_NEVER_ENDED], result.errors)
    def test_reading_in_result_page_timeout_throws_error(self):
        # Simulate a timeout exception when the driver attempts to read the
        # metric page.
        def mock_find_element_by_id(id):
            if id == 'upload-speed':
                raise exceptions.TimeoutException
            return self.mock_page_elements[id]

        self.mock_driver.find_element_by_id.side_effect = (
            mock_find_element_by_id)
        result = html5_driver.NdtHtml5SeleniumDriver(
            browser='firefox',
            url='http://ndt.mock-server.com:7123/',
            timeout=1000).perform_test()

        self.assertIsNone(result.c2s_result.throughput)
        self.assertIsNone(result.s2c_result.throughput)
        self.assertIsNone(result.latency)
        self.assertErrorMessagesEqual(
            ['Test did not complete within timeout period.'], result.errors)
    def test_c2s_kbps_speed_conversion(self):
        """Test c2s speed converts from kb/s to Mb/s correctly."""

        # If c2s speed is 72 kb/s and s2c speed is 34 in the browser

        class NewDriver(object):
            def get(self, url):
                pass

            def close(self):
                pass

            def find_element_by_id(self, id):
                if id == 'upload-speed-units':
                    return mock.Mock(text='kb/s', autospec=True)
                elif id == 'upload-speed':
                    return mock.Mock(text='72', autospec=True)
                elif id == 'download-speed-units':
                    return mock.Mock(text='Mb/s', autospec=True)
                else:
                    return mock.Mock(text='34', autospec=True)

            def find_elements_by_xpath(self, xpath):
                return [mock.Mock(autospec=True)]

        with mock.patch.object(html5_driver.webdriver,
                               'Firefox',
                               autospec=True,
                               return_value=NewDriver()):

            test_results = html5_driver.NdtHtml5SeleniumDriver(
                browser='firefox',
                url='http://ndt.mock-server.com:7123/',
                timeout=1000).perform_test()

        # Then c2s is converted from kb/s to Mb/s
        self.assertEqual(test_results.c2s_result.throughput, 0.072)
        # And s2c is not
        self.assertEqual(test_results.s2c_result.throughput, 34)
        # And an error object is not contained in the list
        self.assertEqual(len(test_results.errors), 0)
    def test_ndt_test_results_records_todays_times(self):
        class NewDriver(object):
            def get(self, url):
                pass

            def close(self):
                pass

            def find_element_by_id(self, id):
                if id == 'upload-speed-units':
                    return mock.Mock(text='kb/s', autospec=True)
                elif id == 'download-speed-units':
                    return mock.Mock(text='Mb/s', autospec=True)
                elif id == 'upload-speed' or 'download-speed':
                    return mock.Mock(text='72', autospec=True)
                else:
                    return mock.Mock(autospec=True)

            def find_elements_by_xpath(self, xpath):
                return [mock.Mock(autospec=True)]

        # When we patch datetime so it shows our current date as 2016-01-01
        self.assertEqual(datetime.datetime.now(),
                         datetime.datetime(2016, 1, 1))

        with mock.patch.object(html5_driver.webdriver,
                               'Firefox',
                               autospec=True,
                               return_value=NewDriver()):

            test_results = html5_driver.NdtHtml5SeleniumDriver(
                browser='firefox',
                url='http://ndt.mock-server.com:7123/',
                timeout=1000).perform_test()

        # Then the readings for our test start and end times occur within
        # today's date
        self.assertEqual(test_results.start_time,
                         datetime.datetime(2016, 1, 1, tzinfo=pytz.utc))
        self.assertEqual(test_results.end_time,
                         datetime.datetime(2016, 1, 1, tzinfo=pytz.utc))
    def test_safari_driver_can_be_used_for_test(self):
        class NewDriver(object):
            def get(self, url):
                pass

            def close(self):
                pass

            def find_elements_by_xpath(self, xpath):
                return [mock.Mock(autospec=True)]

            def find_element_by_id(self, id):
                if id == 'download-speed-units':
                    return mock.Mock(text='Gb/s', autospec=True)
                elif id == 'download-speed':
                    return mock.Mock(text='72', autospec=True)
                elif id == 'upload-speed-units':
                    return mock.Mock(text='Mb/s', autospec=True)
                else:
                    return mock.Mock(text='34', autospec=True)

        with mock.patch.object(html5_driver.webdriver,
                               'Safari',
                               autospec=True,
                               return_value=NewDriver()):

            test_results = html5_driver.NdtHtml5SeleniumDriver(
                browser='safari',
                url='http://ndt.mock-server.com:7123/',
                timeout=1000).perform_test()

        # Then s2c is converted from Gb/s to Mb/s
        self.assertEqual(test_results.s2c_result.throughput, 72000)
        # And c2s is not
        self.assertEqual(test_results.c2s_result.throughput, 34)
        # And an error object is not contained in the list
        self.assertEqual(len(test_results.errors), 0)