WebDriverTest.php 39 KB

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