PageTest.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. <?php
  2. /*
  3. * This file is part of Chrome PHP.
  4. *
  5. * (c) Soufiane Ghzal <sghzal@gmail.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace HeadlessChromium\Test;
  11. use finfo;
  12. use HeadlessChromium\BrowserFactory;
  13. use HeadlessChromium\Exception\InvalidTimezoneId;
  14. /**
  15. * @covers \HeadlessChromium\Page
  16. */
  17. class PageTest extends BaseTestCase
  18. {
  19. public function testSetViewport(): void
  20. {
  21. $factory = new BrowserFactory();
  22. $browser = $factory->createBrowser([
  23. 'windowSize' => [500, 500],
  24. ]);
  25. $page = $browser->createPage();
  26. $page->setViewport(100, 300)->await();
  27. $response = $page->evaluate('[window.innerWidth, window.innerHeight]')->getReturnValue();
  28. self::assertEquals([100, 300], $response);
  29. }
  30. public function testSetUserAgent(): void
  31. {
  32. $factory = new BrowserFactory();
  33. $browser = $factory->createBrowser();
  34. $pageFooBar = $browser->createPage();
  35. $pageBarBaz = $browser->createPage();
  36. $pageFooBar->setUserAgent('foobar')->await();
  37. $pageBarBaz->setUserAgent('barbaz')->await();
  38. $pageFooBar->navigate(self::sitePath('a.html'))->waitForNavigation();
  39. $pageBarBaz->navigate(self::sitePath('a.html'))->waitForNavigation();
  40. $value1 = $pageFooBar->evaluate('navigator.userAgent')->getReturnValue();
  41. $value2 = $pageBarBaz->evaluate('navigator.userAgent')->getReturnValue();
  42. self::assertEquals('foobar', $value1);
  43. self::assertEquals('barbaz', $value2);
  44. }
  45. public function testSetTimezone(): void
  46. {
  47. $factory = new BrowserFactory();
  48. $browser = $factory->createBrowser();
  49. $page = $browser->createPage();
  50. $page->evaluate('
  51. globalThis.date = new Date(1479579154987);
  52. ');
  53. $page->setTimezone('America/Jamaica');
  54. self::assertStringStartsWith(
  55. 'Sat Nov 19 2016 13:12:34 GMT-0500',
  56. $page->evaluate('date.toString()')->getReturnValue()
  57. );
  58. $page->setTimezone('Pacific/Honolulu');
  59. self::assertStringStartsWith(
  60. 'Sat Nov 19 2016 08:12:34 GMT-1000',
  61. $page->evaluate('date.toString()')->getReturnValue()
  62. );
  63. $page->setTimezone('America/Buenos_Aires');
  64. self::assertStringStartsWith(
  65. 'Sat Nov 19 2016 15:12:34 GMT-0300',
  66. $page->evaluate('date.toString()')->getReturnValue()
  67. );
  68. $page->setTimezone('Europe/Berlin');
  69. self::assertStringStartsWith(
  70. 'Sat Nov 19 2016 19:12:34 GMT+0100',
  71. $page->evaluate('date.toString()')->getReturnValue()
  72. );
  73. $page->setTimezone('Europe/Berlin');
  74. self::assertStringStartsWith(
  75. 'Sat Nov 19 2016 19:12:34 GMT+0100',
  76. $page->evaluate('date.toString()')->getReturnValue()
  77. );
  78. $page->setTimezone('gteged');
  79. }
  80. public function testSetTimezoneInvalid(): void
  81. {
  82. $this->expectException(InvalidTimezoneId::class);
  83. $factory = new BrowserFactory();
  84. $browser = $factory->createBrowser();
  85. $page = $browser->createPage();
  86. $page->setTimezone('Foo/Bar');
  87. $this->expectExceptionMessage('Invalid Timezone ID: Foo/Bar');
  88. $page->setTimezone('Baz/Qux');
  89. $this->expectExceptionMessage('Invalid Timezone ID: Baz/Qux');
  90. }
  91. public function testPreScriptOption(): void
  92. {
  93. $factory = new BrowserFactory();
  94. $browser = $factory->createBrowser();
  95. $preScript1 =
  96. "if(!('foo' in navigator)) {
  97. navigator.foo = 0
  98. }
  99. navigator.foo++;";
  100. $preScript2 =
  101. "if(!('bar' in navigator)) {
  102. navigator.bar = 10
  103. }
  104. navigator.bar++;";
  105. $page = $browser->createPage();
  106. $page2 = $browser->createPage();
  107. $page->addPreScript($preScript1);
  108. $page->addPreScript($preScript2);
  109. // make sure prescript evaluates
  110. $page->navigate(self::sitePath('a.html'))->waitForNavigation();
  111. $fooValue = $page->evaluate('navigator.foo')->getReturnValue();
  112. $barValue = $page->evaluate('navigator.bar')->getReturnValue();
  113. self::assertEquals(1, $fooValue);
  114. self::assertEquals(11, $barValue);
  115. // make sure prescript is not adding again and again on every requests
  116. $page->navigate(self::sitePath('b.html'))->waitForNavigation();
  117. $fooValue = $page->evaluate('navigator.foo')->getReturnValue();
  118. $barValue = $page->evaluate('navigator.bar')->getReturnValue();
  119. self::assertEquals(1, $fooValue);
  120. self::assertEquals(11, $barValue);
  121. // make sure prescript did not pollute other pages
  122. $page2->navigate(self::sitePath('b.html'))->waitForNavigation();
  123. $fooValue = $page2->evaluate('navigator.foo')->getReturnValue();
  124. $barValue = $page2->evaluate('navigator.bar')->getReturnValue();
  125. self::assertEquals(null, $fooValue);
  126. self::assertEquals(null, $barValue);
  127. }
  128. public function testCallFunction(): void
  129. {
  130. $factory = new BrowserFactory();
  131. $browser = $factory->createBrowser();
  132. $page = $browser->createPage();
  133. $evaluation = $page->callFunction('function(a, b) { window.foo = a + b; return window.foo;}', [1, 2]);
  134. self::assertEquals(3, $evaluation->getReturnValue());
  135. self::assertEquals(3, $page->evaluate('window.foo')->getReturnValue());
  136. }
  137. public function testCallFunctionPromise(): void
  138. {
  139. $factory = new BrowserFactory();
  140. $browser = $factory->createBrowser();
  141. $page = $browser->createPage();
  142. $evaluation = $page->callFunction('function(a, b) {
  143. return new Promise(resolve => {
  144. setTimeout(() => {
  145. resolve(a + b);
  146. }, 100);
  147. })
  148. }', [1, 2]);
  149. self::assertEquals(3, $evaluation->getReturnValue());
  150. }
  151. public function testEvaluatePromise(): void
  152. {
  153. $factory = new BrowserFactory();
  154. $browser = $factory->createBrowser();
  155. $page = $browser->createPage();
  156. $evaluation = $page->evaluate('new Promise(resolve => {
  157. setTimeout(() => {
  158. resolve(11);
  159. }, 100);
  160. })');
  161. self::assertEquals(11, $evaluation->getReturnValue());
  162. }
  163. public function testAddScriptTagContent(): void
  164. {
  165. $factory = new BrowserFactory();
  166. $browser = $factory->createBrowser();
  167. $page = $browser->createPage();
  168. $page->addScriptTag([
  169. 'content' => 'window.foo = "bar";',
  170. ])->waitForResponse();
  171. self::assertEquals('bar', $page->evaluate('window.foo')->getReturnValue());
  172. }
  173. public function testAddScriptTagUrl(): void
  174. {
  175. $factory = new BrowserFactory();
  176. $browser = $factory->createBrowser();
  177. $page = $browser->createPage();
  178. $page->navigate(
  179. self::sitePath('a.html')
  180. )->waitForNavigation();
  181. $page->addScriptTag([
  182. 'url' => self::sitePath('jsInclude.js'),
  183. ])->waitForResponse();
  184. $isIncluded = $page->evaluate('window.testJsIsIncluded')->getReturnValue();
  185. $scriptSrc = $page->evaluate('document.querySelector("script").getAttribute("src")')->getReturnValue();
  186. self::assertEquals('isIncluded', $isIncluded);
  187. self::assertStringStartsWith('file://', $scriptSrc);
  188. self::assertStringEndsWith('/jsInclude.js', $scriptSrc);
  189. }
  190. public function testGetLayoutMetrics(): void
  191. {
  192. $factory = new BrowserFactory();
  193. $browser = $factory->createBrowser([
  194. 'windowSize' => [500, 500],
  195. ]);
  196. $page = $browser->createPage();
  197. $page->navigate(self::sitePath('bigLayout.html'))->waitForNavigation();
  198. $page->setViewport(100, 300)->await();
  199. $metrics = $page->getLayoutMetrics();
  200. $contentSize = $metrics->getContentSize();
  201. $layoutViewport = $metrics->getLayoutViewport();
  202. $visualViewport = $metrics->getVisualViewport();
  203. $cssContentSize = $metrics->getCssContentSize();
  204. $cssLayoutViewport = $metrics->getCssLayoutViewport();
  205. $cssVisualViewport = $metrics->getCssVisualViewport();
  206. self::assertEquals(
  207. [
  208. 'x' => 0,
  209. 'y' => 0,
  210. 'width' => 900,
  211. 'height' => 1000,
  212. ],
  213. $contentSize
  214. );
  215. self::assertEquals(
  216. [
  217. 'pageX' => 0,
  218. 'pageY' => 0,
  219. 'clientWidth' => 100,
  220. 'clientHeight' => 300,
  221. ],
  222. $layoutViewport
  223. );
  224. self::assertEquals(
  225. [
  226. 'offsetX' => 0,
  227. 'offsetY' => 0,
  228. 'pageX' => 0,
  229. 'pageY' => 0,
  230. 'clientWidth' => 100,
  231. 'clientHeight' => 300,
  232. 'scale' => 1,
  233. 'zoom' => 1,
  234. ],
  235. $visualViewport
  236. );
  237. // This is made to be a bit loose to pass on retina displays
  238. self::assertContains(
  239. $cssContentSize,
  240. [
  241. [
  242. 'x' => 0,
  243. 'y' => 0,
  244. 'width' => 900,
  245. 'height' => 1000,
  246. ],
  247. [
  248. 'x' => 0,
  249. 'y' => 0,
  250. 'width' => 1800,
  251. 'height' => 2000,
  252. ],
  253. ]
  254. );
  255. self::assertContains(
  256. $cssLayoutViewport,
  257. [
  258. [
  259. 'pageX' => 0,
  260. 'pageY' => 0,
  261. 'clientWidth' => 100,
  262. 'clientHeight' => 300,
  263. ],
  264. [
  265. 'pageX' => 0,
  266. 'pageY' => 0,
  267. 'clientWidth' => 200,
  268. 'clientHeight' => 600,
  269. ],
  270. ]
  271. );
  272. self::assertContains(
  273. $cssVisualViewport,
  274. [
  275. [
  276. 'offsetX' => 0,
  277. 'offsetY' => 0,
  278. 'pageX' => 0,
  279. 'pageY' => 0,
  280. 'clientWidth' => 100,
  281. 'clientHeight' => 300,
  282. 'scale' => 1,
  283. 'zoom' => 1,
  284. ],
  285. [
  286. 'offsetX' => 0,
  287. 'offsetY' => 0,
  288. 'pageX' => 0,
  289. 'pageY' => 0,
  290. 'clientWidth' => 200,
  291. 'clientHeight' => 600,
  292. 'scale' => 1,
  293. 'zoom' => 1,
  294. ],
  295. ]
  296. );
  297. }
  298. public function testGetFullPageClip(): void
  299. {
  300. $factory = new BrowserFactory();
  301. $browser = $factory->createBrowser([
  302. 'windowSize' => [500, 500],
  303. ]);
  304. $page = $browser->createPage();
  305. $page->navigate(self::sitePath('bigLayout.html'))->waitForNavigation();
  306. $clip = $page->getFullPageClip();
  307. self::assertEquals(0, $clip->getX());
  308. self::assertEquals(0, $clip->getY());
  309. self::assertEquals(900, $clip->getWidth());
  310. self::assertEquals(1000, $clip->getHeight());
  311. }
  312. public function testPdf(): void
  313. {
  314. $finfo = new finfo(\FILEINFO_MIME_TYPE);
  315. $factory = new BrowserFactory();
  316. $browser = $factory->createBrowser();
  317. $page = $browser->createPage();
  318. $page->navigate(self::sitePath('index.html'))->waitForNavigation();
  319. $pagePdf = $page->pdf(['landscape' => false]);
  320. $pdf = $pagePdf->getBase64();
  321. $mimeType = $finfo->buffer(\base64_decode($pdf));
  322. self::assertSame('application/pdf', $mimeType);
  323. }
  324. public function testGetHtml(): void
  325. {
  326. $factory = new BrowserFactory();
  327. $browser = $factory->createBrowser();
  328. $page = $browser->createPage();
  329. $page->navigate(self::sitePath('index.html'))->waitForNavigation();
  330. self::assertStringContainsString('<h1>bar</h1>', $page->getHtml());
  331. }
  332. public function testSetHtml(): void
  333. {
  334. $html = '<p>set html test</p>';
  335. $factory = new BrowserFactory();
  336. $page = $factory->createBrowser()->createPage();
  337. $page->setHtml($html);
  338. self::assertStringContainsString($html, $page->getHtml());
  339. }
  340. public function testWaitUntilContainsElement(): void
  341. {
  342. $factory = new BrowserFactory();
  343. $browser = $factory->createBrowser();
  344. $page = $browser->createPage();
  345. $page->navigate(self::sitePath('elementLoad.html'))->waitForNavigation();
  346. $page->waitUntilContainsElement('div[data-name=\"el\"]');
  347. self::assertStringContainsString('<div data-name="el"></div>', $page->getHtml());
  348. }
  349. public function testSetExtraHTTPHeaders(): void
  350. {
  351. $factory = new BrowserFactory();
  352. $page = $factory->createBrowser()->createPage();
  353. $page->setExtraHTTPHeaders(['test' => 'test']);
  354. $this->expectNotToPerformAssertions();
  355. }
  356. }