146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)# Copyright 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# found in the LICENSE file. 43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import logging 6116680a4aac90f2aa7413d9095a592090648e557Ben Murdochimport tempfile 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfrom telemetry import benchmark 946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)from telemetry.core import bitmap 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import exceptions 116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)from telemetry.core import util 126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)from telemetry.core import video 135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from telemetry.core.platform import tracing_category_filter 1403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)from telemetry.core.platform import tracing_options 15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)from telemetry.timeline import model 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)from telemetry.unittest import tab_test_case 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def _IsDocumentVisible(tab): 20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return not tab.EvaluateJavaScript('document.hidden || document.webkitHidden') 21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class FakePlatformBackend(object): 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def __init__(self): 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.platform = FakePlatform() 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def DidStartBrowser(self, _, _2): 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pass 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def WillCloseBrowser(self, _, _2): 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pass 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class FakePlatform(object): 35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def __init__(self): 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._is_video_capture_running = False 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) #pylint: disable=W0613 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def StartVideoCapture(self, min_bitrate_mbps): 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._is_video_capture_running = True 41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def StopVideoCapture(self): 43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._is_video_capture_running = False 44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return video.Video(tempfile.NamedTemporaryFile()) 45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @property 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def is_video_capture_running(self): 48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._is_video_capture_running 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class TabTest(tab_test_case.TabTestCase): 526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) def testNavigateAndWaitForCompleteState(self): 536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._tab.Navigate(self.UrlOfUnittestFile('blank.html')) 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._tab.WaitForDocumentReadyStateToBeComplete() 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) def testNavigateAndWaitForInteractiveState(self): 576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._tab.Navigate(self.UrlOfUnittestFile('blank.html')) 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def testTabBrowserIsRightBrowser(self): 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.assertEquals(self._tab.browser, self._browser) 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def testRendererCrash(self): 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.assertRaises(exceptions.TabCrashException, 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lambda: self._tab.Navigate('chrome://crash', 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) timeout=5)) 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch @benchmark.Enabled('has tabs') 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def testActivateTab(self): 70e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch util.WaitFor(lambda: _IsDocumentVisible(self._tab), timeout=5) 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new_tab = self._browser.tabs.New() 724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) new_tab.Navigate('about:blank') 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) util.WaitFor(lambda: _IsDocumentVisible(new_tab), timeout=5) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.assertFalse(_IsDocumentVisible(self._tab)) 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._tab.Activate() 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) util.WaitFor(lambda: _IsDocumentVisible(self._tab), timeout=5) 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.assertFalse(_IsDocumentVisible(new_tab)) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu def testTabUrl(self): 805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu self.assertEquals(self._tab.url, 'about:blank') 816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) url = self.UrlOfUnittestFile('blank.html') 826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._tab.Navigate(url) 836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self.assertEquals(self._tab.url, url) 845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testIsTimelineRecordingRunningTab(self): 86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.assertFalse(self._tab.is_timeline_recording_running) 87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._tab.StartTimelineRecording() 88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.assertTrue(self._tab.is_timeline_recording_running) 89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._tab.StopTimelineRecording() 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.assertFalse(self._tab.is_timeline_recording_running) 91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) #pylint: disable=W0212 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testIsVideoCaptureRunning(self): 945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) original_platform_backend = self._tab.browser._platform_backend 955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) try: 965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._tab.browser._platform_backend = FakePlatformBackend() 975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.assertFalse(self._tab.is_video_capture_running) 985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._tab.StartVideoCapture(min_bitrate_mbps=2) 995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.assertTrue(self._tab.is_video_capture_running) 1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.assertIsNotNone(self._tab.StopVideoCapture()) 1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.assertFalse(self._tab.is_video_capture_running) 1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) finally: 1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._tab.browser._platform_backend = original_platform_backend 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @benchmark.Disabled('chromeos') # crbug.com/412713. 10646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) def testHighlight(self): 10746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) self.assertEquals(self._tab.url, 'about:blank') 10803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) options = tracing_options.TracingOptions() 10903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) options.enable_chrome_trace = True 11003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) self._browser.platform.tracing_controller.Start( 11103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) options, tracing_category_filter.CreateNoOverheadFilter()) 11246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) self._tab.Highlight(bitmap.WEB_PAGE_TEST_ORANGE) 11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) self._tab.ClearHighlight(bitmap.WEB_PAGE_TEST_ORANGE) 11403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) trace_data = self._browser.platform.tracing_controller.Stop() 11546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) timeline_model = model.TimelineModel(trace_data) 116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) renderer_thread = timeline_model.GetRendererThreadFromTabId( 117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) self._tab.id) 11846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) found_video_start_event = False 11946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) for event in renderer_thread.async_slices: 12046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if event.name == '__ClearHighlight.video_capture_start': 12146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) found_video_start_event = True 12246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) break 12346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) self.assertTrue(found_video_start_event) 12446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch @benchmark.Enabled('has tabs') 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @benchmark.Disabled('chromeos') # crbug.com/412713. 127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) def testGetRendererThreadFromTabId(self): 128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) self.assertEquals(self._tab.url, 'about:blank') 12903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) # Create 3 tabs. The third tab is closed before we call 13003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) # tracing_controller.Start. 131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) first_tab = self._tab 132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) second_tab = self._browser.tabs.New() 133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) second_tab.Navigate('about:blank') 134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) second_tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() 135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) third_tab = self._browser.tabs.New() 136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) third_tab.Navigate('about:blank') 137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) third_tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() 138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) third_tab.Close() 13903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) options = tracing_options.TracingOptions() 14003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) options.enable_chrome_trace = True 14103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) self._browser.platform.tracing_controller.Start( 14203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) options, tracing_category_filter.CreateNoOverheadFilter()) 143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) first_tab.ExecuteJavaScript('console.time("first-tab-marker");') 144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) first_tab.ExecuteJavaScript('console.timeEnd("first-tab-marker");') 145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) second_tab.ExecuteJavaScript('console.time("second-tab-marker");') 146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) second_tab.ExecuteJavaScript('console.timeEnd("second-tab-marker");') 14703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) trace_data = self._browser.platform.tracing_controller.Stop() 148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) timeline_model = model.TimelineModel(trace_data) 149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) # Assert that the renderer_thread of the first tab contains 151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) # 'first-tab-marker'. 152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) renderer_thread = timeline_model.GetRendererThreadFromTabId( 153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) first_tab.id) 154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) first_tab_markers = [ 155f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) renderer_thread.IterAllSlicesOfName('first-tab-marker')] 156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) self.assertEquals(1, len(first_tab_markers)) 157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 158f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) # Close second tab and assert that the renderer_thread of the second tab 159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) # contains 'second-tab-marker'. 160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) second_tab.Close() 161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) renderer_thread = timeline_model.GetRendererThreadFromTabId( 162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) second_tab.id) 163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) second_tab_markers = [ 164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) renderer_thread.IterAllSlicesOfName('second-tab-marker')] 165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) self.assertEquals(1, len(second_tab_markers)) 166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) # Third tab wasn't available when we start tracing, so there is no 168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) # renderer_thread corresponding to it in the the trace. 169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) self.assertIs(None, timeline_model.GetRendererThreadFromTabId(third_tab.id)) 170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class GpuTabTest(tab_test_case.TabTestCase): 173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch @classmethod 1746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) def CustomizeBrowserOptions(cls, options): 1756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) options.AppendExtraBrowserArgs('--enable-gpu-benchmarking') 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 177c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch # Test flaky on mac: http://crbug.com/358664 178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch @benchmark.Disabled('android', 'mac') 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def testScreenshot(self): 180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if not self._tab.screenshot_supported: 181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) logging.warning('Browser does not support screenshots, skipping test.') 182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return 183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.Navigate('green_rect.html') 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) pixel_ratio = self._tab.EvaluateJavaScript('window.devicePixelRatio || 1') 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) screenshot = self._tab.Screenshot(5) 188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) assert screenshot 189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) screenshot.GetPixelColor(0 * pixel_ratio, 0 * pixel_ratio).AssertIsRGB( 190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 0, 255, 0, tolerance=2) 191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) screenshot.GetPixelColor(31 * pixel_ratio, 31 * pixel_ratio).AssertIsRGB( 192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 0, 255, 0, tolerance=2) 193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) screenshot.GetPixelColor(32 * pixel_ratio, 32 * pixel_ratio).AssertIsRGB( 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 255, 255, 255, tolerance=2) 195