WebDriverTest.php 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154
  1. <?php
  2. use Codeception\Step;
  3. use Codeception\Util\Stub;
  4. use Facebook\WebDriver\Cookie;
  5. use Facebook\WebDriver\Remote\DesiredCapabilities;
  6. use Facebook\WebDriver\Remote\RemoteWebDriver;
  7. use Facebook\WebDriver\WebDriverBy;
  8. use Facebook\WebDriver\WebDriverKeys;
  9. require_once codecept_data_dir() . 'app/data.php';
  10. require_once __DIR__ . '/../unit/Codeception/Module/TestsForBrowsers.php';
  11. class WebDriverTest extends TestsForBrowsers
  12. {
  13. /**
  14. * @var \Codeception\Module\WebDriver
  15. */
  16. protected $module;
  17. /**
  18. * @var RemoteWebDriver
  19. */
  20. protected $webDriver;
  21. const MODULE_CLASS = 'Codeception\Module\WebDriver';
  22. const WEBDRIVER_CLASS = 'Facebook\WebDriver\Remote\RemoteWebDriver';
  23. public function _before()
  24. {
  25. $this->module = $this->getModule('WebDriver');
  26. $this->webDriver = &$this->getModule('WebDriver')->webDriver;
  27. }
  28. public function _after()
  29. {
  30. data::clean();
  31. }
  32. public function testClickEventOnCheckbox()
  33. {
  34. $this->module->amOnPage('/form/checkbox');
  35. $this->module->uncheckOption('#checkin');
  36. $this->module->dontSee('ticked', '#notice');
  37. $this->module->checkOption('#checkin');
  38. $this->module->see('ticked', '#notice');
  39. }
  40. public function testAcceptPopup()
  41. {
  42. $this->notForPhantomJS();
  43. $this->module->amOnPage('/form/popup');
  44. $this->module->click('Confirm');
  45. $this->module->acceptPopup();
  46. $this->module->see('Yes', '#result');
  47. }
  48. public function testCancelPopup()
  49. {
  50. $this->notForPhantomJS();
  51. $this->module->amOnPage('/form/popup');
  52. $this->module->click('Confirm');
  53. $this->module->cancelPopup();
  54. $this->module->see('No', '#result');
  55. }
  56. public function testSelectByCss()
  57. {
  58. $this->module->amOnPage('/form/select');
  59. $this->module->selectOption('form select[name=age]', '21-60');
  60. $this->module->click('Submit');
  61. $form = data::get('form');
  62. $this->assertEquals('adult', $form['age']);
  63. }
  64. public function testSelectInvalidOptionForSecondSelectFails()
  65. {
  66. $this->shouldFail();
  67. $this->module->amOnPage('/form/select_second');
  68. $this->module->selectOption('#select2', 'Value2');
  69. }
  70. public function testSeeInPopup()
  71. {
  72. $this->notForPhantomJS();
  73. $this->module->amOnPage('/form/popup');
  74. $this->module->click('Alert');
  75. $this->module->seeInPopup('Really?');
  76. $this->module->cancelPopup();
  77. }
  78. public function testFailedSeeInPopup()
  79. {
  80. $this->notForPhantomJS();
  81. $this->setExpectedException(
  82. '\PHPUnit\Framework\AssertionFailedError',
  83. 'Failed asserting that \'Really?\' contains "Different text"'
  84. );
  85. $this->module->amOnPage('/form/popup');
  86. $this->module->click('Alert');
  87. $this->module->seeInPopup('Different text');
  88. $this->module->cancelPopup();
  89. }
  90. public function testDontSeeInPopup()
  91. {
  92. $this->notForPhantomJS();
  93. $this->module->amOnPage('/form/popup');
  94. $this->module->click('Alert');
  95. $this->module->dontSeeInPopup('Different text');
  96. $this->module->cancelPopup();
  97. }
  98. public function testFailedDontSeeInPopup()
  99. {
  100. $this->notForPhantomJS();
  101. $this->setExpectedException(
  102. '\PHPUnit\Framework\AssertionFailedError',
  103. 'Failed asserting that \'Really?\' does not contain "Really?"'
  104. );
  105. $this->module->amOnPage('/form/popup');
  106. $this->module->click('Alert');
  107. $this->module->dontSeeInPopup('Really?');
  108. $this->module->cancelPopup();
  109. }
  110. public function testScreenshot()
  111. {
  112. $this->module->amOnPage('/');
  113. @unlink(\Codeception\Configuration::outputDir().'testshot.png');
  114. $testName="debugTest";
  115. $this->module->makeScreenshot($testName);
  116. $this->assertFileExists(\Codeception\Configuration::outputDir().'debug/'.$testName.'.png');
  117. @unlink(\Codeception\Configuration::outputDir().'debug/'.$testName.'.png');
  118. $this->module->_saveScreenshot(\Codeception\Configuration::outputDir().'testshot.png');
  119. $this->assertFileExists(\Codeception\Configuration::outputDir().'testshot.png');
  120. @unlink(\Codeception\Configuration::outputDir().'testshot.png');
  121. }
  122. public function testSubmitForm()
  123. {
  124. $this->module->amOnPage('/form/complex');
  125. $this->module->submitForm('form', [
  126. 'name' => 'Davert',
  127. 'age' => 'child',
  128. 'terms' => 'agree',
  129. 'description' => 'My Bio'
  130. ]);
  131. $form = data::get('form');
  132. $this->assertEquals('Davert', $form['name']);
  133. $this->assertEquals('kill_all', $form['action']);
  134. $this->assertEquals('My Bio', $form['description']);
  135. $this->assertEquals('agree', $form['terms']);
  136. $this->assertEquals('child', $form['age']);
  137. }
  138. public function testSubmitFormWithNumbers()
  139. {
  140. $this->module->amOnPage('/form/complex');
  141. $this->module->submitForm('form', [
  142. 'name' => 'Davert',
  143. 'age' => 'child',
  144. 'terms' => 'agree',
  145. 'description' => 10
  146. ]);
  147. $form = data::get('form');
  148. $this->assertEquals('Davert', $form['name']);
  149. $this->assertEquals('kill_all', $form['action']);
  150. $this->assertEquals('10', $form['description']);
  151. $this->assertEquals('agree', $form['terms']);
  152. $this->assertEquals('child', $form['age']);
  153. }
  154. /**
  155. * @dataProvider strictSelectorProvider
  156. */
  157. public function testSubmitFormWithButtonAsStrictSelector(array $selector)
  158. {
  159. $this->module->amOnPage('/form/strict_selectors');
  160. $this->module->submitForm('form', [
  161. 'name' => 'Davert',
  162. 'age' => 'child',
  163. 'terms' => 'agree',
  164. 'description' => 'My Bio'
  165. ], $selector);
  166. $form = data::get('form');
  167. $this->assertEquals('Davert', $form['name']);
  168. $this->assertEquals('kill_all', $form['action']);
  169. $this->assertEquals('My Bio', $form['description']);
  170. $this->assertEquals('agree', $form['terms']);
  171. $this->assertEquals('child', $form['age']);
  172. }
  173. public function strictSelectorProvider()
  174. {
  175. return [
  176. 'by id' => [['id' => 'submit_button']],
  177. 'by name' => [['name' => 'submit_button_name']],
  178. 'by css' => [['css' => 'form #submit_button']],
  179. 'by xpath' => [['xpath' => '//*[@id="submit_button"]']],
  180. 'by link' => [['link' => 'Submit']],
  181. 'by class' => [['class' => 'button']],
  182. ];
  183. }
  184. /**
  185. * @dataProvider webDriverByProvider
  186. */
  187. public function testSubmitFormWithButtonAsWebDriverBy(WebDriverBy $selector)
  188. {
  189. $this->module->amOnPage('/form/strict_selectors');
  190. $this->module->submitForm('form', [
  191. 'name' => 'Davert',
  192. 'age' => 'child',
  193. 'terms' => 'agree',
  194. 'description' => 'My Bio'
  195. ], $selector);
  196. $form = data::get('form');
  197. $this->assertEquals('Davert', $form['name']);
  198. $this->assertEquals('kill_all', $form['action']);
  199. $this->assertEquals('My Bio', $form['description']);
  200. $this->assertEquals('agree', $form['terms']);
  201. $this->assertEquals('child', $form['age']);
  202. }
  203. public function webDriverByProvider()
  204. {
  205. return [
  206. 'by id' => [WebDriverBy::id('submit_button')],
  207. 'by name' => [WebDriverBy::name('submit_button_name')],
  208. 'by css selector' => [WebDriverBy::cssSelector('form #submit_button')],
  209. 'by xpath' => [WebDriverBy::xpath('//*[@id="submit_button"]')],
  210. 'by link text' => [WebDriverBy::linkText('Submit')],
  211. 'by class name' => [WebDriverBy::className('button')],
  212. ];
  213. }
  214. public function testRadioButtonByValue()
  215. {
  216. $this->module->amOnPage('/form/radio');
  217. $this->module->selectOption('form', 'disagree');
  218. $this->module->click('Submit');
  219. $form = data::get('form');
  220. $this->assertEquals('disagree', $form['terms']);
  221. }
  222. public function testRadioButtonByLabelOnContext()
  223. {
  224. $this->module->amOnPage('/form/radio');
  225. $this->module->selectOption('form input', 'Get Off');
  226. $this->module->seeOptionIsSelected('form input', 'disagree');
  227. $this->module->dontSeeOptionIsSelected('form input', 'agree');
  228. $this->module->click('Submit');
  229. $form = data::get('form');
  230. $this->assertEquals('disagree', $form['terms']);
  231. }
  232. public function testRadioButtonByLabel()
  233. {
  234. $this->module->amOnPage('/form/radio');
  235. $this->module->checkOption('Get Off');
  236. $this->module->click('Submit');
  237. $form = data::get('form');
  238. $this->assertEquals('disagree', $form['terms']);
  239. }
  240. public function testRawSelenium()
  241. {
  242. $this->module->amOnPage('/');
  243. $this->module->executeInSelenium(function ($webdriver) {
  244. $webdriver->findElement(WebDriverBy::id('link'))->click();
  245. });
  246. $this->module->seeCurrentUrlEquals('/info');
  247. }
  248. public function testKeys()
  249. {
  250. $this->module->amOnPage('/form/field');
  251. $this->module->pressKey('#name', ['ctrl', 'a'], WebDriverKeys::DELETE);
  252. $this->module->pressKey('#name', 'test', ['shift', '111']);
  253. $this->module->pressKey('#name', '1');
  254. $this->module->seeInField('#name', 'test!!!1');
  255. }
  256. public function testWait()
  257. {
  258. $this->module->amOnPage('/');
  259. $time = time();
  260. $this->module->wait(3);
  261. $this->assertGreaterThanOrEqual($time+3, time());
  262. }
  263. public function testSelectInvalidOptionFails()
  264. {
  265. $this->shouldFail();
  266. $this->module->amOnPage('/form/select');
  267. $this->module->selectOption('#age', '13-22');
  268. }
  269. public function testAppendFieldSelect()
  270. {
  271. $this->module->amOnPage('/form/select_multiple');
  272. $this->module->selectOption('form #like', 'eat');
  273. $this->module->appendField('form #like', 'code');
  274. $this->module->click('Submit');
  275. $form = data::get('form');
  276. $this->assertEmpty(array_diff($form['like'], ["eat", "code"]));
  277. }
  278. public function testAppendFieldSelectFails()
  279. {
  280. $this->shouldFail();
  281. $this->module->amOnPage('/form/select_multiple');
  282. $this->module->appendField('form #like', 'code123');
  283. }
  284. public function testAppendFieldTextarea()
  285. {
  286. $this->module->amOnPage('/form/textarea');
  287. $this->module->fillField('form #description', 'eat');
  288. $this->module->appendField('form #description', ' code');
  289. $this->module->click('Submit');
  290. $form = data::get('form');
  291. $this->assertEquals('eat code', $form['description']);
  292. }
  293. public function testAppendFieldTextareaFails()
  294. {
  295. $this->shouldFail();
  296. $this->module->amOnPage('/form/textarea');
  297. $this->module->appendField('form #description123', ' code');
  298. }
  299. public function testAppendFieldText()
  300. {
  301. $this->module->amOnPage('/form/field');
  302. $this->module->appendField('form #name', ' code');
  303. $this->module->click('Submit');
  304. $form = data::get('form');
  305. $this->assertEquals('OLD_VALUE code', $form['name']);
  306. }
  307. public function testAppendFieldTextFails()
  308. {
  309. $this->shouldFail();
  310. $this->module->amOnPage('/form/field');
  311. $this->module->appendField('form #name123', ' code');
  312. }
  313. public function testAppendFieldCheckboxByValue()
  314. {
  315. $this->module->amOnPage('/form/checkbox');
  316. $this->module->appendField('form input[name=terms]', 'agree');
  317. $this->module->click('Submit');
  318. $form = data::get('form');
  319. $this->assertEquals('agree', $form['terms']);
  320. }
  321. public function testAppendFieldCheckboxByValueFails()
  322. {
  323. $this->shouldFail();
  324. $this->module->amOnPage('/form/checkbox');
  325. $this->module->appendField('form input[name=terms]', 'agree123');
  326. }
  327. public function testAppendFieldCheckboxByLabel()
  328. {
  329. $this->module->amOnPage('/form/checkbox');
  330. $this->module->appendField('form input[name=terms]', 'I Agree');
  331. $this->module->click('Submit');
  332. $form = data::get('form');
  333. $this->assertEquals('agree', $form['terms']);
  334. }
  335. public function testAppendFieldCheckboxByLabelFails()
  336. {
  337. $this->shouldFail();
  338. $this->module->amOnPage('/form/checkbox');
  339. $this->module->appendField('form input[name=terms]', 'I Agree123');
  340. }
  341. public function testAppendFieldRadioButtonByValue()
  342. {
  343. $this->module->amOnPage('/form/radio');
  344. $this->module->appendField('form input[name=terms]', 'disagree');
  345. $this->module->click('Submit');
  346. $form = data::get('form');
  347. $this->assertEquals('disagree', $form['terms']);
  348. }
  349. public function testAppendFieldRadioButtonByValueFails()
  350. {
  351. $this->shouldFail();
  352. $this->module->amOnPage('/form/radio');
  353. $this->module->appendField('form input[name=terms]', 'disagree123');
  354. }
  355. public function testAppendFieldRadioButtonByLabel()
  356. {
  357. $this->module->amOnPage('/form/radio');
  358. $this->module->appendField('form input[name=terms]', 'Get Off');
  359. $this->module->click('Submit');
  360. $form = data::get('form');
  361. $this->assertEquals('disagree', $form['terms']);
  362. }
  363. public function testAppendFieldRadioButtonByLabelFails()
  364. {
  365. $this->shouldFail();
  366. $this->module->amOnPage('/form/radio');
  367. $this->module->appendField('form input[name=terms]', 'Get Off123');
  368. }
  369. public function testPauseExecution()
  370. {
  371. $this->module->amOnPage('/');
  372. $this->module->pauseExecution();
  373. }
  374. // Issue https://github.com/Codeception/Codeception/pull/875
  375. public function testFillPasswordOnFormSubmit()
  376. {
  377. $this->module->amOnPage('/form/complex');
  378. $this->module->submitForm('form', [
  379. 'password' => '123456'
  380. ]);
  381. $form = data::get('form');
  382. $this->assertEquals('123456', $form['password']);
  383. }
  384. public function testEmptyFormSubmit()
  385. {
  386. $this->shouldFail();
  387. $this->module->amOnPage('/form/complex');
  388. $this->module->submitForm('form111', []);
  389. }
  390. public function testWebDriverByLocators()
  391. {
  392. $this->module->amOnPage('/login');
  393. $this->module->seeElement(WebDriverBy::id('submit-label'));
  394. $this->module->seeElement(WebDriverBy::name('password'));
  395. $this->module->seeElement(WebDriverBy::className('optional'));
  396. $this->module->seeElement(WebDriverBy::cssSelector('form.global_form_box'));
  397. $this->module->seeElement(WebDriverBy::xpath(\Codeception\Util\Locator::tabIndex(4)));
  398. $this->module->fillField(WebDriverBy::name('password'), '123456');
  399. $this->module->amOnPage('/form/select');
  400. $this->module->selectOption(WebDriverBy::name('age'), 'child');
  401. $this->module->amOnPage('/form/checkbox');
  402. $this->module->checkOption(WebDriverBy::name('terms'));
  403. $this->module->amOnPage('/');
  404. $this->module->seeElement(WebDriverBy::linkText('Test'));
  405. $this->module->click(WebDriverBy::linkText('Test'));
  406. $this->module->seeCurrentUrlEquals('/form/hidden');
  407. }
  408. public function testSeeVisible()
  409. {
  410. $this->module->amOnPage('/info');
  411. $this->module->dontSee('Invisible text');
  412. $this->module->dontSee('Invisible', '.hidden');
  413. $this->module->seeInPageSource('Invisible text');
  414. }
  415. public function testSeeInvisible()
  416. {
  417. $this->shouldFail();
  418. $this->module->amOnPage('/info');
  419. $this->module->see('Invisible text');
  420. }
  421. public function testFailWebDriverByLocator()
  422. {
  423. $this->shouldFail();
  424. $this->module->amOnPage('/form/checkbox');
  425. $this->module->checkOption(WebDriverBy::name('age'));
  426. }
  427. // fails in PhpBrowser :(
  428. public function testSubmitUnchecked()
  429. {
  430. $this->module->amOnPage('/form/unchecked');
  431. $this->module->seeCheckboxIsChecked('#checkbox');
  432. $this->module->uncheckOption('#checkbox');
  433. $this->module->click('#submit');
  434. ;
  435. $this->module->see('0', '#notice');
  436. }
  437. public function testCreateCeptScreenshotFail()
  438. {
  439. $fakeWd = Stub::make('\Facebook\WebDriver\Remote\RemoteWebDriver', [
  440. 'takeScreenshot' => Stub::once(function () {
  441. }),
  442. 'getPageSource' => Stub::once(function () {
  443. }),
  444. 'manage' => Stub::make('\Facebook\WebDriver\WebDriverOptions', [
  445. 'getAvailableLogTypes' => Stub::atLeastOnce(function () {
  446. return [];
  447. }),
  448. ]),
  449. ]);
  450. $module = Stub::make(self::MODULE_CLASS, ['webDriver' => $fakeWd]);
  451. $cept = (new \Codeception\Test\Cept('loginCept', 'loginCept.php'));
  452. $module->_failed($cept, new \PHPUnit\Framework\AssertionFailedError());
  453. }
  454. public function testCreateCestScreenshotOnFail()
  455. {
  456. $fakeWd = Stub::make(self::WEBDRIVER_CLASS, [
  457. 'takeScreenshot' => Stub::once(function ($filename) {
  458. PHPUnit_Framework_Assert::assertEquals(codecept_log_dir('stdClass.login.fail.png'), $filename);
  459. }),
  460. 'getPageSource' => Stub::once(function () {
  461. }),
  462. 'manage' => Stub::make('\Facebook\WebDriver\WebDriverOptions', [
  463. 'getAvailableLogTypes' => Stub::atLeastOnce(function () {
  464. return [];
  465. }),
  466. ]),
  467. ]);
  468. $module = Stub::make(self::MODULE_CLASS, ['webDriver' => $fakeWd]);
  469. $cest = new \Codeception\Test\Cest(new stdClass(), 'login', 'someCest.php');
  470. $module->_failed($cest, new \PHPUnit\Framework\AssertionFailedError());
  471. }
  472. public function testCreateTestScreenshotOnFail()
  473. {
  474. $test = Stub::make('\Codeception\TestCase\Test', ['getName' => 'testLogin']);
  475. $fakeWd = Stub::make(self::WEBDRIVER_CLASS, [
  476. 'takeScreenshot' => Stub::once(function ($filename) use ($test) {
  477. PHPUnit_Framework_Assert::assertEquals(
  478. codecept_log_dir(get_class($test).'.testLogin.fail.png'),
  479. $filename
  480. );
  481. }),
  482. 'getPageSource' => Stub::once(function () {
  483. }),
  484. 'manage' => Stub::make('\Facebook\WebDriver\WebDriverOptions', [
  485. 'getAvailableLogTypes' => Stub::atLeastOnce(function () {
  486. return [];
  487. }),
  488. ]),
  489. ]);
  490. $module = Stub::make(self::MODULE_CLASS, ['webDriver' => $fakeWd]);
  491. $module->_failed($test, new \PHPUnit\Framework\AssertionFailedError());
  492. }
  493. public function testWebDriverWaits()
  494. {
  495. $fakeWd = Stub::make(self::WEBDRIVER_CLASS, ['wait' => Stub::exactly(16, function () {
  496. return new \Codeception\Util\Maybe();
  497. })]);
  498. $module = Stub::make(self::MODULE_CLASS, ['webDriver' => $fakeWd]);
  499. $module->waitForElement(WebDriverBy::partialLinkText('yeah'));
  500. $module->waitForElement(['id' => 'user']);
  501. $module->waitForElement(['css' => '.user']);
  502. $module->waitForElement('//xpath');
  503. $module->waitForElementVisible(WebDriverBy::partialLinkText('yeah'));
  504. $module->waitForElementVisible(['id' => 'user']);
  505. $module->waitForElementVisible(['css' => '.user']);
  506. $module->waitForElementVisible('//xpath');
  507. $module->waitForElementNotVisible(WebDriverBy::partialLinkText('yeah'));
  508. $module->waitForElementNotVisible(['id' => 'user']);
  509. $module->waitForElementNotVisible(['css' => '.user']);
  510. $module->waitForElementNotVisible('//xpath');
  511. $module->waitForElementClickable(WebDriverBy::partialLinkText('yeah'));
  512. $module->waitForElementClickable(['id' => 'user']);
  513. $module->waitForElementClickable(['css' => '.user']);
  514. $module->waitForElementClickable('//xpath');
  515. }
  516. public function testWaitForElement()
  517. {
  518. $this->module->amOnPage('/form/timeout');
  519. $this->module->waitForElement('#btn');
  520. $this->module->click('Click');
  521. $this->module->see('Hello');
  522. }
  523. public function testImplicitWait()
  524. {
  525. $this->module->_reconfigure(['wait' => 5]);
  526. $this->module->amOnPage('/form/timeout');
  527. $this->module->click('#btn');
  528. $this->module->see('Hello');
  529. }
  530. public function testBug1467()
  531. {
  532. $this->module->amOnPage('/form/bug1467');
  533. $this->module->selectOption('form[name=form2] input[name=first_test_radio]', 'Yes');
  534. $this->module->selectOption('form[name=form2] input[name=second_test_radio]', 'No');
  535. $this->module->seeOptionIsSelected('form[name=form2] input[name=first_test_radio]', 'Yes');
  536. $this->module->seeOptionIsSelected('form[name=form2] input[name=second_test_radio]', 'No');
  537. // shouldn't have touched form1 at all
  538. $this->module->dontSeeOptionIsSelected('form[name=form1] input[name=first_test_radio]', 'No');
  539. $this->module->dontSeeOptionIsSelected('form[name=form1] input[name=first_test_radio]', 'Yes');
  540. $this->module->dontSeeOptionIsSelected('form[name=form1] input[name=second_test_radio]', 'No');
  541. $this->module->dontSeeOptionIsSelected('form[name=form1] input[name=second_test_radio]', 'Yes');
  542. }
  543. /**
  544. * @Issue 1598
  545. */
  546. public function testWaitForTextBug1598()
  547. {
  548. $this->module->amOnPage('/form/bug1598');
  549. $this->module->waitForText('12,345', 10, '#field');
  550. }
  551. public function testSeeElementMalformedWdLocator()
  552. {
  553. $this->setExpectedException('Codeception\Exception\MalformedLocatorException');
  554. $this->module->amOnPage('/');
  555. $this->module->seeElement(WebDriverBy::xpath('H---EY!'));
  556. }
  557. public function testBug1637()
  558. {
  559. $this->module->amOnPage('/form/bug1637');
  560. // confirm that options outside a form are still selectable
  561. $this->module->selectOption('input[name=first_test_radio]', 'Yes');
  562. // confirm that it did what we expected and did not do anything else
  563. $this->module->seeOptionIsSelected('input[name=first_test_radio]', 'Yes');
  564. $this->module->dontSeeOptionIsSelected('input[name=first_test_radio]', 'No');
  565. }
  566. public function testBug2046()
  567. {
  568. $this->module->webDriver = null;
  569. $this->module->_saveScreenshot(\Codeception\Configuration::outputDir().'testshot.png');
  570. }
  571. public function testSessionSnapshots()
  572. {
  573. $this->notForPhantomJS();
  574. $this->module->amOnPage('/');
  575. $this->module->setCookie('PHPSESSID', '123456', ['path' => '/']);
  576. $this->module->saveSessionSnapshot('login');
  577. $this->module->seeCookie('PHPSESSID');
  578. $this->webDriver->manage()->deleteAllCookies();
  579. $this->module->dontSeeCookie('PHPSESSID');
  580. $this->module->loadSessionSnapshot('login');
  581. $this->module->seeCookie('PHPSESSID');
  582. }
  583. public function testSessionSnapshotsAreDeleted()
  584. {
  585. $this->notForPhantomJS();
  586. $this->module->amOnPage('/');
  587. $this->module->setCookie('PHPSESSID', '123456', ['path' => '/']);
  588. $this->module->saveSessionSnapshot('login');
  589. $this->webDriver->manage()->deleteAllCookies();
  590. $this->module->deleteSessionSnapshot('login');
  591. $this->assertFalse($this->module->loadSessionSnapshot('login'));
  592. $this->module->dontSeeCookie('PHPSESSID');
  593. }
  594. public function testSaveSessionSnapshotsExcludeInvalidCookieDomains()
  595. {
  596. $this->notForPhantomJS();
  597. $fakeWdOptions = Stub::make('\Facebook\WebDriver\WebDriverOptions', [
  598. 'getCookies' => Stub::atLeastOnce(function () {
  599. return [
  600. [
  601. 'name' => 'PHPSESSID',
  602. 'value' => '123456',
  603. 'path' => '/',
  604. ],
  605. [
  606. 'name' => '3rdParty',
  607. 'value' => '_value_',
  608. 'path' => '/',
  609. 'domain' => '.3rd-party.net',
  610. ],
  611. ];
  612. }),
  613. ]);
  614. $fakeWd = Stub::make(self::WEBDRIVER_CLASS, [
  615. 'manage' => Stub::atLeastOnce(function () use ($fakeWdOptions) {
  616. return $fakeWdOptions;
  617. }),
  618. ]);
  619. // Mock the WebDriverOptions::getCookies() method on the first call to introduce a 3rd-party cookie
  620. // which has to be ignored when saving a snapshot.
  621. $originalWebDriver = $this->module->webDriver;
  622. $this->module->webDriver = $fakeWd;
  623. $this->module->seeCookie('PHPSESSID');
  624. $this->module->seeCookie('3rdParty');
  625. $this->module->saveSessionSnapshot('login');
  626. // Restore the original WebDriver
  627. $this->module->webDriver = $originalWebDriver;
  628. $this->webDriver->manage()->deleteAllCookies();
  629. $this->module->dontSeeCookie('PHPSESSID');
  630. $this->module->dontSeeCookie('3rdParty');
  631. $this->module->amOnPage('/');
  632. $this->module->loadSessionSnapshot('login');
  633. $this->module->seeCookie('PHPSESSID');
  634. $this->module->dontSeeCookie('3rdParty');
  635. }
  636. public function testSeeInFieldTextarea()
  637. {
  638. $this->module->amOnPage('/form/textarea');
  639. //make sure we see 'sunrise' which is the default text in the textarea
  640. $this->module->seeInField('#description', 'sunrise');
  641. if ($this->notForSelenium()) {
  642. $this->module->seeInField('#whitespaces', ' no_whitespaces ');
  643. }
  644. $this->module->seeInField('#whitespaces', 'no_whitespaces');
  645. //fill in some new text and see if we can see it
  646. $textarea_value = 'test string';
  647. $this->module->fillField('#description', $textarea_value);
  648. $this->module->seeInField('#description', $textarea_value);
  649. }
  650. public function testSeeInFieldSelect()
  651. {
  652. $this->module->amOnPage('/form/select_second');
  653. if ($this->notForSelenium()) {
  654. $this->module->seeInField('#select2', ' no_whitespaces ');
  655. }
  656. $this->module->seeInField('#select2', 'no_whitespaces');
  657. // select new option and check it
  658. $option_value = 'select2_value1';
  659. $this->module->selectOption('#select2', $option_value);
  660. $this->module->seeInField('#select2', $option_value);
  661. }
  662. public function testAppendFieldDiv()
  663. {
  664. $this->notForPhantomJS();
  665. $this->module->amOnPage('/form/div_content_editable');
  666. //make sure we see 'sunrise' which is the default text in the textarea
  667. $this->module->see('sunrise', '#description');
  668. //fill in some new text and see if we can see it
  669. $textarea_value = 'moonrise';
  670. $this->module->appendField('#description', $textarea_value);
  671. $this->module->see('sunrise' . $textarea_value, '#description');
  672. }
  673. public function testOpenPageException()
  674. {
  675. if (!$this->module->_getConfig('restart')) {
  676. $this->markTestSkipped('works only on restarts');
  677. }
  678. parent::testOpenPageException();
  679. }
  680. public function testCookies()
  681. {
  682. $this->notForPhantomJS();
  683. parent::testCookies();
  684. }
  685. public function testSendingCookies()
  686. {
  687. $this->notForPhantomJS();
  688. parent::testSendingCookies();
  689. }
  690. public function testCookiesWithPath()
  691. {
  692. $this->notForPhantomJS();
  693. parent::testCookiesWithPath();
  694. }
  695. protected function notForPhantomJS()
  696. {
  697. if ($this->module->_getConfig('browser') == 'phantomjs') {
  698. $this->markTestSkipped('does not work for phantomjs');
  699. }
  700. }
  701. protected function notForSelenium()
  702. {
  703. if ($this->module->_getConfig('browser') != 'phantom') {
  704. $this->markTestSkipped('does not work for selenium');
  705. }
  706. }
  707. public function testScrollTo()
  708. {
  709. $this->module->amOnPage('/form/example18');
  710. $this->module->scrollTo('#clickme');
  711. $this->module->click('Submit');
  712. $this->module->see('Welcome to test app!');
  713. }
  714. /**
  715. * @Issue 2921
  716. */
  717. public function testSeeInFieldForTextarea()
  718. {
  719. $this->module->amOnPage('/form/bug2921');
  720. $this->module->seeInField('foo', 'bar baz');
  721. }
  722. /**
  723. * @Issue 4726
  724. */
  725. public function testClearField()
  726. {
  727. $this->module->amOnPage('/form/textarea');
  728. $this->module->fillField('#description', 'description');
  729. $this->module->clearField('#description');
  730. $this->module->dontSeeInField('#description', 'description');
  731. }
  732. public function testClickHashLink()
  733. {
  734. $this->module->amOnPage('/form/anchor');
  735. $this->module->click('Hash Link');
  736. $this->module->seeCurrentUrlEquals('/form/anchor#b');
  737. }
  738. /**
  739. * @Issue 3865
  740. */
  741. public function testClickNumericLink()
  742. {
  743. $this->module->amOnPage('/form/bug3865');
  744. $this->module->click('222');
  745. $this->module->see('Welcome to test app');
  746. }
  747. public function testClickHashButton()
  748. {
  749. $this->module->amOnPage('/form/anchor');
  750. $this->module->click('Hash Button');
  751. $this->module->seeCurrentUrlEquals('/form/anchor#c');
  752. }
  753. public function testSubmitHashForm()
  754. {
  755. $this->module->amOnPage('/form/anchor');
  756. $this->module->click('Hash Form');
  757. $this->module->seeCurrentUrlEquals('/form/anchor#a');
  758. }
  759. public function testSubmitHashFormTitle()
  760. {
  761. $this->module->amOnPage('/form/anchor');
  762. $this->module->click('Hash Form Title');
  763. $this->module->seeCurrentUrlEquals('/form/anchor#a');
  764. }
  765. public function testSubmitHashButtonForm()
  766. {
  767. $this->module->amOnPage('/form/anchor');
  768. $this->module->click('Hash Button Form');
  769. $this->module->seeCurrentUrlEquals('/form/anchor#a');
  770. }
  771. public function testJSErrorLoggingPositive()
  772. {
  773. // arrange
  774. $this->module->_setConfig(['log_js_errors' => true]);
  775. $cept = new \Codeception\Test\Cept('foo', 'bar');
  776. // act
  777. $this->module->amOnPage('/jserroronload');
  778. $this->module->_failed($cept, 'anyFailMessage');
  779. // assert
  780. /* @var $steps Step[] */
  781. $steps = $cept->getScenario()->getSteps();
  782. $this->assertGreaterThan(0, count($steps));
  783. $lastStep = end($steps);
  784. $this->assertContains(
  785. "TypeError",
  786. $lastStep->getHtml()
  787. );
  788. }
  789. public function testJSErrorLoggingNegative()
  790. {
  791. // arrange
  792. $this->module->_setConfig(['log_js_errors' => false]);
  793. $cept = new \Codeception\Test\Cept('foo', 'bar');
  794. // act
  795. $this->module->amOnPage('/jserroronload');
  796. $this->module->_failed($cept, 'anyFailMessage');
  797. // assert
  798. /* @var $steps Step[] */
  799. $steps = $cept->getScenario()->getSteps();
  800. $this->assertCount(0, $steps);
  801. }
  802. public function testMoveMouseOver()
  803. {
  804. $this->module->amOnPage('/form/click');
  805. $this->module->moveMouseOver(null, 123, 88);
  806. $this->module->clickWithLeftButton(null, 0, 0);
  807. $this->module->see('click, offsetX: 123 - offsetY: 88');
  808. $this->module->moveMouseOver(null, 10, 10);
  809. $this->module->clickWithLeftButton(null, 0, 0);
  810. $this->module->see('click, offsetX: 133 - offsetY: 98');
  811. $this->module->moveMouseOver('#element2');
  812. $this->module->clickWithLeftButton(null, 0, 0);
  813. $this->module->see('click, offsetX: 58 - offsetY: 158');
  814. $this->module->moveMouseOver('#element2', 0, 0);
  815. $this->module->clickWithLeftButton(null, 0, 0);
  816. $this->module->see('click, offsetX: 8 - offsetY: 108');
  817. }
  818. public function testLeftClick()
  819. {
  820. $this->module->amOnPage('/form/click');
  821. $this->module->clickWithLeftButton(null, 123, 88);
  822. $this->module->see('click, offsetX: 123 - offsetY: 88');
  823. $this->module->clickWithLeftButton('body');
  824. $this->module->see('click, offsetX: 600 - offsetY: 384');
  825. $this->module->clickWithLeftButton('body', 50, 75);
  826. $this->module->see('click, offsetX: 58 - offsetY: 83');
  827. $this->module->clickWithLeftButton('body div');
  828. $this->module->see('click, offsetX: 58 - offsetY: 58');
  829. $this->module->clickWithLeftButton('#element2', 70, 75);
  830. $this->module->see('click, offsetX: 78 - offsetY: 183');
  831. }
  832. public function testRightClick()
  833. {
  834. // actually not supported in phantomjs see https://github.com/ariya/phantomjs/issues/14005
  835. $this->notForPhantomJS();
  836. $this->module->amOnPage('/form/click');
  837. $this->module->clickWithRightButton(null, 123, 88);
  838. $this->module->see('context, offsetX: 123 - offsetY: 88');
  839. $this->module->clickWithRightButton('body');
  840. $this->module->see('context, offsetX: 600 - offsetY: 384');
  841. $this->module->clickWithRightButton('body', 50, 75);
  842. $this->module->see('context, offsetX: 58 - offsetY: 83');
  843. $this->module->clickWithRightButton('body div');
  844. $this->module->see('context, offsetX: 58 - offsetY: 58');
  845. $this->module->clickWithRightButton('#element2', 70, 75);
  846. $this->module->see('context, offsetX: 78 - offsetY: 183');
  847. }
  848. public function testBrowserTabs()
  849. {
  850. $this->notForPhantomJS();
  851. $this->module->amOnPage('/form/example1');
  852. $this->module->openNewTab();
  853. $this->module->amOnPage('/form/example2');
  854. $this->module->openNewTab();
  855. $this->module->amOnPage('/form/example3');
  856. $this->module->openNewTab();
  857. $this->module->amOnPage('/form/example4');
  858. $this->module->openNewTab();
  859. $this->module->amOnPage('/form/example5');
  860. $this->module->closeTab();
  861. $this->module->seeInCurrentUrl('example4');
  862. $this->module->switchToPreviousTab(2);
  863. $this->module->seeInCurrentUrl('example2');
  864. $this->module->switchToNextTab();
  865. $this->module->seeInCurrentUrl('example3');
  866. $this->module->closeTab();
  867. $this->module->seeInCurrentUrl('example2');
  868. $this->module->switchToNextTab(2);
  869. $this->module->seeInCurrentUrl('example1');
  870. }
  871. public function testPerformOnWithArray()
  872. {
  873. $asserts = PHPUnit_Framework_Assert::getCount();
  874. $this->module->amOnPage('/form/example1');
  875. $this->module->performOn('.rememberMe', [
  876. 'see' => 'Remember me next time',
  877. 'seeElement' => '#LoginForm_rememberMe',
  878. 'dontSee' => 'Login'
  879. ]);
  880. $this->assertEquals(3, PHPUnit_Framework_Assert::getCount() - $asserts);
  881. $this->module->see('Login');
  882. }
  883. public function testPerformOnWithCallback()
  884. {
  885. $asserts = PHPUnit_Framework_Assert::getCount();
  886. $this->module->amOnPage('/form/example1');
  887. $this->module->performOn('.rememberMe', function (\Codeception\Module\WebDriver $I) {
  888. $I->see('Remember me next time');
  889. $I->seeElement('#LoginForm_rememberMe');
  890. $I->dontSee('Login');
  891. });
  892. $this->assertEquals(3, PHPUnit_Framework_Assert::getCount() - $asserts);
  893. $this->module->see('Login');
  894. }
  895. public function testPerformOnWithBuiltArray()
  896. {
  897. $asserts = PHPUnit_Framework_Assert::getCount();
  898. $this->module->amOnPage('/form/example1');
  899. $this->module->performOn('.rememberMe', \Codeception\Util\ActionSequence::build()
  900. ->see('Remember me next time')
  901. ->seeElement('#LoginForm_rememberMe')
  902. ->dontSee('Login')
  903. );
  904. $this->assertEquals(3, PHPUnit_Framework_Assert::getCount() - $asserts);
  905. $this->module->see('Login');
  906. }
  907. public function testPerformOnWithArrayAndSimilarActions()
  908. {
  909. $asserts = PHPUnit_Framework_Assert::getCount();
  910. $this->module->amOnPage('/form/example1');
  911. $this->module->performOn('.rememberMe', \Codeception\Util\ActionSequence::build()
  912. ->see('Remember me')
  913. ->see('next time')
  914. ->dontSee('Login')
  915. );
  916. $this->assertEquals(3, PHPUnit_Framework_Assert::getCount() - $asserts);
  917. $this->module->see('Login');
  918. }
  919. public function testPerformOnFail()
  920. {
  921. $this->shouldFail();
  922. $this->module->amOnPage('/form/example1');
  923. $this->module->performOn('.rememberMe', \Codeception\Util\ActionSequence::build()
  924. ->seeElement('#LoginForm_rememberMe')
  925. ->see('Remember me tomorrow')
  926. );
  927. }
  928. public function testPerformOnFail2()
  929. {
  930. $this->shouldFail();
  931. $this->module->amOnPage('/form/example1');
  932. $this->module->performOn('.rememberMe', ['see' => 'Login']);
  933. }
  934. public function testSwitchToIframe()
  935. {
  936. $this->module->amOnPage('iframe');
  937. $this->module->switchToIFrame('content');
  938. $this->module->see('Lots of valuable data here');
  939. $this->module->switchToIFrame();
  940. $this->module->see('Iframe test');
  941. }
  942. public function testGrabPageSourceWhenNotOnPage()
  943. {
  944. $this->setExpectedException(
  945. '\Codeception\Exception\ModuleException',
  946. 'Current url is blank, no page was opened'
  947. );
  948. $this->module->grabPageSource();
  949. }
  950. public function testGrabPageSourceWhenOnPage()
  951. {
  952. $this->module->amOnPage('/minimal');
  953. $sourceExpected =
  954. <<<HTML
  955. <!DOCTYPE html>
  956. <html>
  957. <head>
  958. <title>
  959. Minimal page
  960. </title>
  961. </head>
  962. <body>
  963. <h1>
  964. Minimal page
  965. </h1>
  966. </body>
  967. </html>
  968. HTML
  969. ;
  970. $sourceActualRaw = $this->module->grabPageSource();
  971. // `Selenium` adds the `xmlns` attribute while `PhantomJS` does not do that.
  972. $sourceActual = str_replace('xmlns="http://www.w3.org/1999/xhtml"', '', $sourceActualRaw);
  973. $this->assertXmlStringEqualsXmlString($sourceExpected, $sourceActual);
  974. }
  975. public function testChangingCapabilities()
  976. {
  977. $this->notForPhantomJS();
  978. $this->assertNotTrue($this->module->webDriver->getCapabilities()->getCapability('acceptInsecureCerts'));
  979. $this->module->_closeSession();
  980. $this->module->_capabilities(function($current) {
  981. $current['acceptInsecureCerts'] = true;
  982. return new DesiredCapabilities($current);
  983. });
  984. $this->assertNotTrue($this->module->webDriver->getCapabilities()->getCapability('acceptInsecureCerts'));
  985. $this->module->_initializeSession();
  986. $this->assertTrue($this->module->webDriver->getCapabilities()->getCapability('acceptInsecureCerts'));
  987. }
  988. /**
  989. * @dataProvider strictBug4846Provider
  990. **/
  991. public function testBug4846($selector)
  992. {
  993. $this->module->amOnPage('/');
  994. $this->module->see('Welcome to test app!', $selector);
  995. $this->module->dontSee('You cannot see that', $selector);
  996. }
  997. public function strictBug4846Provider()
  998. {
  999. return [
  1000. 'by id' => ['h1'],
  1001. 'by css' => [['css' => 'body h1']],
  1002. 'by xpath' => ['//body/h1'],
  1003. ];
  1004. }
  1005. }