Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[RU] ChromeDriver Jailbreak

[RU] ChromeDriver Jailbreak

Alexander Bayandin

December 10, 2016
Tweet

More Decks by Alexander Bayandin

Other Decks in Programming

Transcript

  1. 400K Регистраций в день 5 Платформ 330M Пользователей 1.8ч Использование

    в день 350M Сообщений в день 21M DAU 54M MAU 10M Фотозагрузок в день О нас
  2. 400K Регистраций в день 5 Платформ 330M Пользователей 1.8ч Использование

    в день 350M Сообщений в день 21M DAU 54M MAU 10M Фотозагрузок в день О нас
  3. Mobile Test Automation Team ✦ Ruby & Cucumber ✦ Calabash,

    Selenium & Winium.Mobile ✦ TeamCity 6
  4. Mobile Test Automation Team ✦ Ruby & Cucumber ✦ Calabash,

    Selenium & Winium.Mobile ✦ TeamCity ✦ Кросс-платформенная автоматизация 6
  5. 8 Step Definition iOS PO Android Page Objects MW PO

    WP PO Scenario Step Кросс-платформенная автоматизация
  6. 8 Step Definition iOS PO Android Page Objects MW PO

    WP PO Scenario Step Calabash Кросс-платформенная автоматизация
  7. 8 Step Definition iOS PO Android Page Objects MW PO

    WP PO Scenario Step Calabash Selenium Кросс-платформенная автоматизация
  8. 8 Step Definition iOS PO Android Page Objects MW PO

    WP PO Scenario Step Calabash Selenium Winium.Mobile Кросс-платформенная автоматизация
  9. Mobile Test Automation Team ✦ Ruby & Cucumber ✦ Calabash,

    Selenium & Winium.Mobile ✦ TeamCity ✦ Кросс-платформенная автоматизация 9
  10. Mobile Test Automation Team ✦ Ruby & Cucumber ✦ Calabash,

    Selenium & Winium.Mobile ✦ TeamCity ✦ Кросс-платформенная автоматизация ✦ Мы клёвые ! 9
  11. Варианты ответа ✦ Остановить тест за шаг до падения, последний

    шаг проделать вручную (с открытыми DevTools) 16
  12. Варианты ответа ✦ Остановить тест за шаг до падения, последний

    шаг проделать вручную (с открытыми DevTools) ✦ Поставить прокси 16
  13. Варианты ответа ✦ Остановить тест за шаг до падения, последний

    шаг проделать вручную (с открытыми DevTools) ✦ Поставить прокси ✦ ??? 16
  14. У нас же Chrome! 20 ✦ ChromeDriver умеет Performance log

    ✦ Нужно конвертировать Performance log в HAR
  15. Chrome Debugging Protocol ✦ Реализован поверх WebSocket ✦ Используется в

    Chrome DevTools https://developer.chrome.com/devtools/docs/debugger-protocol
  16. Тело ответа в DevTools Network.getResponseBody Returns content served for the

    given request. PARAMETERS requestId: RequestId RETURN OBJECT body: string base64Encoded: boolean https://chromedevtools.github.io/debugger-protocol-viewer/1-2/Network/#method-getResponseBody
  17. Решение ✦ Включить Performance log в тестах ✦ Получить тело

    ответа для всех запросов ✦ Конвертировать Performance log в HAR 37
  18. Решение ✦ Включить Performance log в тестах ✦ Получить тело

    ответа для всех запросов ✦ Конвертировать Performance log в HAR ✦ Добавить ответы в HAR 37
  19. +-+ +-+ +--------+ +------------+ |C| |T|<---->|Selenium|<---->|ChromeDriver|<------->|h| |e| +--------+ +------------+ |r|

    |s| |o| |t|<------------------------------------------->|m| +-+ |e| +-+ WebSocket Connection 38
  20. +-+ +-+ +--------+ +------------+ |C| |T|<---->|Selenium|<---->|ChromeDriver|<------->|h| |e| +--------+ +------------+ |r|

    |s| |o| |t|<------------------------------------------->|m| +-+ |e| +-+ WebSocket Connection 41
  21. +-+ +-+ +--------+ +------------+ |C| |T|<---->|Selenium|<---->|ChromeDriver|<------->|h| |e| +--------+ +------------+ |r|

    |s| |o| |t|<------------------------------------------->|m| +-+ |e| +-+ WebSocket Connection / / / / / / / / / / 41
  22. +-+ +-+ +--------+ +------------+ |C| |T|<---->|Selenium|<---->|ChromeDriver|<------->|h| |e| +--------+ +------------+ |r|

    |s| |o| |t|<------------------------------------------->|m| +-+ |e| +-+ WebSocket Connection / / / / / / / / / / 43
  23. +-+ +-+ +-+ +--------+ +------------+ |P| |C| |T|<---->|Selenium|<---->|ChromeDriver|<->|r| |h| |e|

    +--------+ +------------+ |o|<->|r| |s| |x| |o| |t|<------------------------------------->|y| |m| +-+ +-+ |e| +-+ WebSocket Connection 44
  24. +-+ |C| |h| |r| |o| |m| |e| |D| |r| |i|

    |v| |e| |r| +-+ POST /session 47
  25. +-+ |C| |h| |r| |o| |m| |e| |D| |r| |i|

    |v| |e| |r| +-+ POST /session DesiredCapabilities 47
  26. +-+ |C| |h| |r| |o| |m| |e| |D| |r| |i|

    |v| |e| |r| +-+ POST /session DesiredCapabilities chromeOptions 47
  27. +-+ |C| |h| |r| |o| |m| |e| |D| |r| |i|

    |v| |e| |r| +-+ POST /session DesiredCapabilities chromeOptions binary 47
  28. +-+ |C| |h| |r| |o| |m| |e| |D| |r| |i|

    |v| |e| |r| +-+ POST /session google-chrome DesiredCapabilities chromeOptions binary 47
  29. +-+ |C| |h| |r| |o| |m| |e| |D| |r| |i|

    |v| |e| |r| +-+ POST /session google-chrome … --remote-debugging-port=X DesiredCapabilities chromeOptions binary 48
  30. +-+ |C| |h| |r| |o| |m| |e| |D| |r| |i|

    |v| |e| |r| +-+ POST /session google-chrome … --remote-debugging-port=X 12000 < X < 13000 DesiredCapabilities chromeOptions binary 48
  31. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| |m| |i| |e| |v| +-+ |e| |r| +-+ 49
  32. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| |m| |i| |e| |v| +-+ |e| |r| +-+ /json/version 49
  33. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| |m| |i| |e| |v| +-+ |e| |r| +-+ /json/version { "Browser": "Chrome/54.0.2840.98", "Protocol-Version": "1.2", "User-Agent": "…", "WebKit-Version": "537.36 (@8ee402c…ad)" } 49
  34. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| |m| |i| |e| |v| +-+ |e| |r| +-+ /json/list /json/version 50
  35. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| |m| |i| |e| |v| +-+ |e| |r| +-+ /json/list [{ "id": "…", "webSocketDebuggerUrl": "…", "devtoolsFrontendUrl": "…", … }, …] /json/version 50
  36. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| |m| |i| |e| |v| +-+ |e| |r| +-+ ws:/ /webSocketDebuggerUrl /json/list /json/version 51
  37. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| |m| |i| |e| |v| +-+ |e| |r| +-+ ws:/ /webSocketDebuggerUrl /json/list /json/version set-up + chromeOptions 51
  38. +-+ |C| |h| |r| |o| |m| |e| |D| |r| |i|

    |v| |e| |r| +-+ POST /session DesiredCapabilities chromeOptions binary 53
  39. +-+ |C| |h| |r| |o| |m| |e| |D| |r| |i|

    |v| |e| |r| +-+ POST /session chrome-wrapper DesiredCapabilities chromeOptions binary 53
  40. +-+ |C| |h| |r| |o| |m| |e| |D| |r| |i|

    |v| |e| |r| +-+ POST /session chrome-wrapper … --remote-debugging-port=X DesiredCapabilities chromeOptions binary 54
  41. +-+ |C| |h| |r| |o| |m| |e| |D| |r| |i|

    |v| |e| |r| +-+ POST /session chrome-wrapper … --remote-debugging-port=X DesiredCapabilities chromeOptions binary portX 54
  42. +-+ |C| |h| |r| |o| |m| |e| |D| |r| |i|

    |v| |e| |r| +-+ POST /session chrome-wrapper … --remote-debugging-port=X DesiredCapabilities chromeOptions binary portY portX 54
  43. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| +--------------+ |m| |i| |DevTools Proxy| |e| |v| +--------------+ +-+ |e| |r| +-+ 55
  44. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| +--------------+ |m| |i| |DevTools Proxy| |e| |v| +--------------+ +-+ |e| |r| +-+ /json/version portX 55
  45. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| +--------------+ |m| |i| |DevTools Proxy| |e| |v| +--------------+ +-+ |e| |r| +-+ /json/version portX portY 55
  46. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| +--------------+ |m| |i| |DevTools Proxy| |e| |v| +--------------+ +-+ |e| |r| +-+ /json/version portX portY 55
  47. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| +--------------+ |m| |i| |DevTools Proxy| |e| |v| +--------------+ +-+ |e| |r| +-+ /json/version portX portY 55
  48. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| +--------------+ |m| |i| |DevTools Proxy| |e| |v| +--------------+ +-+ |e| |r| +-+ ws ws portX portY 56
  49. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| +--------------+ |m| |i| |DevTools Proxy| |e| |v| +--------------+ +-+ |e| |r| +-+ ws ws Tests portX portY 56
  50. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| +--------------+ |m| |i| |DevTools Proxy| |e| |v| +--------------+ +-+ |e| |r| +-+ ws ws Tests w s portX portX portY 56
  51. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| +--------------+ |m| |i| |DevTools Proxy| |e| |v| +--------------+ +-+ |e| |r| +-+ : 12000 < X < 13000 ws ws Tests w s portX portX portY 56
  52. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| +--------------+ |m| |i| |DevTools Proxy| |e| |v| +--------------+ +-+ |e| |r| +-+ ws ws w s Tests portZ portX portY 57
  53. Финальная логика ✦ Включить Performance log в тестах ✦ Получить

    тело ответа для всех запросов ✦ Конвертировать Performance log в HAR ✦ Добавить ответы в HAR 58
  54. Финальная логика ✦ Передать chrome-wrapper в binary в ChromeOptions ✦

    Включить Performance log в тестах ✦ Получить тело ответа для всех запросов ✦ Конвертировать Performance log в HAR ✦ Добавить ответы в HAR 59
  55. < { "id":0, "error":{ "code":-32000, "message":"No resource with given identifier

    found" } } > { "id":0, "method":"Network.getResponseBody", "params":{ "requestId":"28781.18" } } 61
  56. 63

  57. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| |m| |i| |e| |v| +-+ |e| |r| +-+ ws:/ /webSocketDebuggerUrl /json/list /json/version set-up + chromeOptions 64
  58. +-+ |C| |h| |r| +-+ |o| |C| |m| |h| |e|

    |r| |D| |o| |r| |m| |i| |e| |v| +-+ |e| |r| +-+ ws:/ /webSocketDebuggerUrl /json/list /json/version set-up + chromeOptions 64
  59. {'id': 1, 'params': {}, 'method': 'Network.enable'} {'id': 2, 'params': {},

    'method': 'Log.enable'} {'id': 3, 'params': {}, 'method': 'Runtime.enable'} {'id': 5, 'params': {}, 'method': 'Page.enable'} ChromeDriver set-up 65
  60. DevTools set-up {'id': 1, 'method': 'Log.enable'} {'id': 2, 'method': 'Runtime.enable'}

    {'id': 3, 'method': 'Network.enable', 'params': {'maxResourceBufferSize': 5000000, 'maxTotalBufferSize': 10000000}} {'id': 4, 'method': 'Page.enable'} {'id': 6, 'method': 'Debugger.enable'} {'id': 9, 'method': 'DOM.enable'} {'id': 10, 'method': 'CSS.enable'} {'id': 12, 'method': 'Worker.enable'} {'id': 13, 'method': 'Profiler.enable'} {'id': 15, 'method': 'ServiceWorker.enable'} {'id': 23, 'method': 'Inspector.enable'} 66
  61. DevTools set-up {'id': 1, 'method': 'Log.enable'} {'id': 2, 'method': 'Runtime.enable'}

    {'id': 3, 'method': 'Network.enable', 'params': {'maxResourceBufferSize': 5000000, 'maxTotalBufferSize': 10000000}} {'id': 4, 'method': 'Page.enable'} {'id': 6, 'method': 'Debugger.enable'} {'id': 9, 'method': 'DOM.enable'} {'id': 10, 'method': 'CSS.enable'} {'id': 12, 'method': 'Worker.enable'} {'id': 13, 'method': 'Profiler.enable'} {'id': 15, 'method': 'ServiceWorker.enable'} {'id': 23, 'method': 'Inspector.enable'} 66
  62. > { "id":1, "method":"Network.enable", "params":{} } ChromeDriver > { "id":3,

    "method":"Network.enable", "params":{ "maxTotalBufferSize":10000000, "maxResourceBufferSize":5000000 } } DevTools 67
  63. Финальная логика ✦ Передать chrome-wrapper в binary в ChromeOptions ✦

    Включить Performance log в тестах ✦ Получить тело ответа для всех запросов ✦ Конвертировать Performance log в HAR ✦ Добавить ответы в HAR 68
  64. Финальная логика ✦ Передать chrome-wrapper.sh в binary в ChromeOptions ✦

    Включить Performance log в тестах ✦ Отправить “правильный” Network.enable ✦ Получить тело ответа для всех запросов ✦ Конвертировать Performance log в HAR ✦ Добавить ответы в HAR 69
  65. Варианты ответа ✦ Остановить тест за шаг до падения, последний

    шаг проделать вручную (с открытыми DevTools) ✦ Поставить прокси ✦ ??? 75
  66. Варианты ответа ✦ Остановить тест за шаг до падения, последний

    шаг проделать вручную (с открытыми DevTools) ✦ Поставить прокси ✦ Можно получить HAR 76
  67. +-+ | | |C| +----------+ |h| | DevTools | |r|

    +----------+ |o| |m| |e| | | +-+ 79
  68. +-+ | | |C| +----------+ |h| | DevTools | |r|

    +----------+ |o| |m| |e| | | +-+ Network.enable 79
  69. +-+ | | |C| +----------+ |h| | DevTools | |r|

    +----------+ |o| |m| |e| | | +-+ 80
  70. +-+ | | |C| +----------+ |h| | DevTools | |r|

    +----------+ |o| |m| |e| | | +-+ request 80
  71. +-+ | | |C| +----------+ |h| | DevTools | |r|

    +----------+ |o| |m| |e| | | +-+ request 80
  72. +-+ | | |C| +----------+ |h| | DevTools | |r|

    +----------+ |o| |m| |e| | | +-+ response 81
  73. +-+ | | |C| +----------+ |h| | DevTools | |r|

    +----------+ |o| |m| |e| | | +-+ response 81
  74. 82

  75. 83

  76. 84

  77. 85

  78. 86

  79. +----------+ +-+ | Client 1 | | | +----------+ |C|

    |h| |r| |o| +----------+ |m| | Client 2 | |e| +----------+ | | +-+ 87
  80. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ 88
  81. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ 89
  82. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ 89
  83. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ 89
  84. Варианты ответа ✦ Остановить тест за шаг до падения, последний

    шаг проделать вручную (с открытыми DevTools) ✦ Поставить прокси ✦ Можно получить HAR 91
  85. Варианты ответа ✦ Остановить тест за шаг до падения, последний

    шаг проделать вручную (с открытыми DevTools) ✦ Поставить прокси ✦ Можно получить HAR ✦ В нетворке есть всё 92
  86. ?

  87. +-+ +-+ +-+ +--------+ +------------+ |P| |C| |T|<---->|Selenium|<---->|ChromeDriver|<->|r| |h| |e|

    +--------+ +------------+ |o|<->|r| |s| |x| |o| |t|<------------------------------------->|y| |m| +-+ +-+ |e| +-+ WebSocket Connection 107
  88. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ 109
  89. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ { “id”: 1, …} 109
  90. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ { “id”: 1} { “id”: 1, …} 109
  91. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ { “id”: 1} 110
  92. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ { “id”: 1} ¯\_()_/¯ " 110
  93. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ 111
  94. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ { “id”: 19, …} { “id”: 19, …} 111
  95. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ { “id”: 19} { “id”: 19, …} { “id”: 19, …} 111
  96. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ { “id”: 19} ×2 { “id”: 19, …} { “id”: 19, …} 111
  97. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ { “id”: 19} 112
  98. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ { “id”: 19} ¯\_()_/¯ " 112
  99. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ 120
  100. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ { “id”: 19, …} { “id”: 19, …} 120
  101. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ { “id”: 19} { “id”: 19, …} { “id”: 19, …} 120
  102. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ { “id”: 19} { “id”: 19, …} { “id”: 19, …} { “id”: 4194323} 120
  103. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ { “id”: 4194323} 121
  104. +-+ +----------+ | | +-+ | Client 1 | |

    | | | +----------+ |P| |C| |r| |h| |o| |r| |x| |o| +----------+ |y| |m| | Client 2 | | | |e| +----------+ | | | | +-+ +-+ { “id”: 19, …} { “id”: 4194323} 121
  105. Полезно знать ✦ devtools-proxy полностью совместим с Selenium ✦ Пока

    нет поддержки Windows ✦ Только для Chromium / Google Chrome 132
  106. Планы на будущее 135 ✦ Научиться останавливаться на debugger /

    breakpoints ✦ Научиться получать данные Chrome Push Notification
  107. Планы на будущее 138 ✦ Научиться останавливаться на debugger /

    breakpoints ✦ Научиться получать данные Chrome Push Notification
  108. Планы на будущее 138 ✦ Научиться останавливаться на debugger /

    breakpoints ✦ Научиться получать данные Chrome Push Notification ✦ Поддержка Android
  109. Планы на будущее 138 ✦ Научиться останавливаться на debugger /

    breakpoints ✦ Научиться получать данные Chrome Push Notification ✦ Поддержка Android ✦ Поддержка Windows (для chrome-wrapper)
  110. Планы на будущее 138 ✦ Научиться останавливаться на debugger /

    breakpoints ✦ Научиться получать данные Chrome Push Notification ✦ Поддержка Android ✦ Поддержка Windows (для chrome-wrapper) ✦ Поддержка Firefox / Edge
  111. Сегодня я многое понял… ✦ Как видеть HTTP запросы во

    время прохождения теста ✦ Как видеть как идёт тест 139
  112. Сегодня я многое понял… ✦ Как видеть HTTP запросы во

    время прохождения теста ✦ Как видеть как идёт тест ✦ Использовать любые Chrome Debugging Protocol методы 139