You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FilesAppContext.php 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. <?php
  2. /**
  3. *
  4. * @copyright Copyright (c) 2017, Daniel Calviño Sánchez (danxuliu@gmail.com)
  5. *
  6. * @license GNU AGPL version 3 or any later version
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License as
  10. * published by the Free Software Foundation, either version 3 of the
  11. * License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Affero General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. use Behat\Behat\Context\Context;
  23. class FilesAppContext implements Context, ActorAwareInterface {
  24. use ActorAware;
  25. use FileListAncestorSetter;
  26. /**
  27. * @return array
  28. */
  29. public static function sections() {
  30. return [ "All files" => "files",
  31. "Recent" => "recent",
  32. "Favorites" => "favorites",
  33. "Shared with you" => "sharingin",
  34. "Shared with others" => "sharingout",
  35. "Shared by link" => "sharinglinks",
  36. "Tags" => "systemtagsfilter",
  37. "Deleted files" => "trashbin" ];
  38. }
  39. /**
  40. * @return Locator
  41. */
  42. private static function appMenu() {
  43. return Locator::forThe()->id("appmenu")->
  44. describedAs("App menu in header");
  45. }
  46. /**
  47. * @return Locator
  48. */
  49. public static function filesItemInAppMenu() {
  50. return Locator::forThe()->xpath("/li[@data-id = 'files']")->
  51. descendantOf(self::appMenu())->
  52. describedAs("Files item in app menu in header");
  53. }
  54. /**
  55. * @return Locator
  56. */
  57. public static function mainViewForSection($section) {
  58. $sectionId = self::sections()[$section];
  59. return Locator::forThe()->id("app-content-$sectionId")->
  60. describedAs("Main view for section $section in Files app");
  61. }
  62. /**
  63. * @return Locator
  64. */
  65. public static function currentSectionMainView() {
  66. return Locator::forThe()->xpath("//*[starts-with(@id, 'app-content-') and not(contains(concat(' ', normalize-space(@class), ' '), ' hidden '))]")->
  67. describedAs("Current section main view in Files app");
  68. }
  69. /**
  70. * @return Locator
  71. */
  72. public static function detailsView() {
  73. return Locator::forThe()->id("app-sidebar")->
  74. describedAs("Details view in Files app");
  75. }
  76. /**
  77. * @return Locator
  78. */
  79. public static function closeDetailsViewButton() {
  80. return Locator::forThe()->css(".icon-close")->
  81. descendantOf(self::detailsView())->
  82. describedAs("Close details view in Files app");
  83. }
  84. /**
  85. * @return Locator
  86. */
  87. public static function fileNameInDetailsView() {
  88. return Locator::forThe()->css(".fileName")->
  89. descendantOf(self::detailsView())->
  90. describedAs("File name in details view in Files app");
  91. }
  92. /**
  93. * @return Locator
  94. */
  95. public static function favoriteActionInFileDetailsInDetailsView() {
  96. return Locator::forThe()->css(".action-favorite")->
  97. descendantOf(self::fileDetailsInDetailsView())->
  98. describedAs("Favorite action in file details in details view in Files app");
  99. }
  100. /**
  101. * @return Locator
  102. */
  103. public static function notFavoritedStateIconInFileDetailsInDetailsView() {
  104. return Locator::forThe()->css(".icon-star")->
  105. descendantOf(self::favoriteActionInFileDetailsInDetailsView())->
  106. describedAs("Not favorited state icon in file details in details view in Files app");
  107. }
  108. /**
  109. * @return Locator
  110. */
  111. public static function favoritedStateIconInFileDetailsInDetailsView() {
  112. return Locator::forThe()->css(".icon-starred")->
  113. descendantOf(self::favoriteActionInFileDetailsInDetailsView())->
  114. describedAs("Favorited state icon in file details in details view in Files app");
  115. }
  116. /**
  117. * @return Locator
  118. */
  119. public static function fileDetailsInDetailsViewWithText($fileDetailsText) {
  120. return Locator::forThe()->xpath("//span[normalize-space() = '$fileDetailsText']")->
  121. descendantOf(self::fileDetailsInDetailsView())->
  122. describedAs("File details with text \"$fileDetailsText\" in details view in Files app");
  123. }
  124. /**
  125. * @return Locator
  126. */
  127. private static function fileDetailsInDetailsView() {
  128. return Locator::forThe()->css(".file-details")->
  129. descendantOf(self::detailsView())->
  130. describedAs("File details in details view in Files app");
  131. }
  132. /**
  133. * @return Locator
  134. */
  135. public static function inputFieldForTagsInDetailsView() {
  136. return Locator::forThe()->css(".systemTagsInfoView")->
  137. descendantOf(self::detailsView())->
  138. describedAs("Input field for tags in details view in Files app");
  139. }
  140. /**
  141. * @return Locator
  142. */
  143. public static function itemInInputFieldForTagsInDetailsViewForTag($tag) {
  144. return Locator::forThe()->xpath("//span[normalize-space() = '$tag']")->
  145. descendantOf(self::inputFieldForTagsInDetailsView())->
  146. describedAs("Item in input field for tags in details view for tag $tag in Files app");
  147. }
  148. /**
  149. * @return Locator
  150. */
  151. public static function itemInDropdownForTag($tag) {
  152. return Locator::forThe()->xpath("//*[contains(concat(' ', normalize-space(@class), ' '), ' select2-result-label ')]//span[normalize-space() = '$tag']/ancestor::li")->
  153. descendantOf(self::select2Dropdown())->
  154. describedAs("Item in dropdown for tag $tag in Files app");
  155. }
  156. /**
  157. * @return Locator
  158. */
  159. public static function checkmarkInItemInDropdownForTag($tag) {
  160. return Locator::forThe()->css(".checkmark")->
  161. descendantOf(self::itemInDropdownForTag($tag))->
  162. describedAs("Checkmark in item in dropdown for tag $tag in Files app");
  163. }
  164. /**
  165. * @return Locator
  166. */
  167. private static function select2Dropdown() {
  168. return Locator::forThe()->css("#select2-drop")->
  169. describedAs("Select2 dropdown in Files app");
  170. }
  171. /**
  172. * @return Locator
  173. */
  174. public static function tabHeaderInDetailsViewNamed($tabHeaderName) {
  175. return Locator::forThe()->xpath("//li[normalize-space() = '$tabHeaderName']")->
  176. descendantOf(self::tabHeadersInDetailsView())->
  177. describedAs("Tab header named $tabHeaderName in details view in Files app");
  178. }
  179. /**
  180. * @return Locator
  181. */
  182. private static function tabHeadersInDetailsView() {
  183. return Locator::forThe()->css(".tabHeaders")->
  184. descendantOf(self::detailsView())->
  185. describedAs("Tab headers in details view in Files app");
  186. }
  187. /**
  188. * @return Locator
  189. */
  190. public static function tabInDetailsViewNamed($tabName) {
  191. return Locator::forThe()->xpath("//div[@id=//*[contains(concat(' ', normalize-space(@class), ' '), ' tabHeader ') and normalize-space() = '$tabName']/@data-tabid]")->
  192. descendantOf(self::detailsView())->
  193. describedAs("Tab named $tabName in details view in Files app");
  194. }
  195. /**
  196. * @return Locator
  197. */
  198. public static function loadingIconForTabInDetailsViewNamed($tabName) {
  199. return Locator::forThe()->css(".loading")->
  200. descendantOf(self::tabInDetailsViewNamed($tabName))->
  201. describedAs("Loading icon for tab named $tabName in details view in Files app");
  202. }
  203. /**
  204. * @return Locator
  205. */
  206. public static function sharedByLabel() {
  207. return Locator::forThe()->css(".reshare")->
  208. descendantOf(self::detailsView())->
  209. describedAs("Shared by label in the details view in Files app");
  210. }
  211. /**
  212. * @return Locator
  213. */
  214. public static function shareWithInput() {
  215. return Locator::forThe()->css(".shareWithField")->
  216. descendantOf(self::detailsView())->
  217. describedAs("Share with input in the details view in Files app");
  218. }
  219. /**
  220. * @return Locator
  221. */
  222. public static function shareeList() {
  223. return Locator::forThe()->css(".shareeListView")->
  224. descendantOf(self::detailsView())->
  225. describedAs("Sharee list in the details view in Files app");
  226. }
  227. /**
  228. * @return Locator
  229. */
  230. public static function sharedWithRow($sharedWithName) {
  231. // "username" class is used for any type of share, not only for shares
  232. // with users.
  233. return Locator::forThe()->xpath("//span[contains(concat(' ', normalize-space(@class), ' '), ' username ') and normalize-space() = '$sharedWithName']/ancestor::li")->
  234. descendantOf(self::shareeList())->
  235. describedAs("Shared with $sharedWithName row in the details view in Files app");
  236. }
  237. /**
  238. * @return Locator
  239. */
  240. public static function shareWithMenuButton($sharedWithName) {
  241. return Locator::forThe()->css(".share-menu > .icon")->
  242. descendantOf(self::sharedWithRow($sharedWithName))->
  243. describedAs("Share with $sharedWithName menu button in the details view in Files app");
  244. }
  245. /**
  246. * @return Locator
  247. */
  248. public static function shareWithMenu($sharedWithName) {
  249. return Locator::forThe()->css(".share-menu > .menu")->
  250. descendantOf(self::sharedWithRow($sharedWithName))->
  251. describedAs("Share with $sharedWithName menu in the details view in Files app");
  252. }
  253. /**
  254. * @return Locator
  255. */
  256. public static function canReshareCheckbox($sharedWithName) {
  257. // forThe()->checkbox("Can reshare") can not be used here; that would
  258. // return the checkbox itself, but the element that the user interacts
  259. // with is the label.
  260. return Locator::forThe()->xpath("//label[normalize-space() = 'Can reshare']")->
  261. descendantOf(self::shareWithMenu($sharedWithName))->
  262. describedAs("Can reshare checkbox in the share with $sharedWithName menu in the details view in Files app");
  263. }
  264. /**
  265. * @return Locator
  266. */
  267. public static function canReshareCheckboxInput($sharedWithName) {
  268. return Locator::forThe()->checkbox("Can reshare")->
  269. descendantOf(self::shareWithMenu($sharedWithName))->
  270. describedAs("Can reshare checkbox input in the share with $sharedWithName menu in the details view in Files app");
  271. }
  272. /**
  273. * @return Locator
  274. */
  275. public static function shareLinkRow() {
  276. return Locator::forThe()->css(".linkShareView .shareWithList:first-child")->
  277. descendantOf(self::detailsView())->
  278. describedAs("Share link row in the details view in Files app");
  279. }
  280. /**
  281. * @return Locator
  282. */
  283. public static function shareLinkAddNewButton() {
  284. // When there is no link share the "Add new share" item is shown instead
  285. // of the menu button as a direct child of ".share-menu".
  286. return Locator::forThe()->css(".share-menu > .new-share")->
  287. descendantOf(self::shareLinkRow())->
  288. describedAs("Add new share link button in the details view in Files app");
  289. }
  290. /**
  291. * @return Locator
  292. */
  293. public static function copyLinkButton() {
  294. return Locator::forThe()->css("a.clipboard-button")->
  295. descendantOf(self::shareLinkRow())->
  296. describedAs("Copy link button in the details view in Files app");
  297. }
  298. /**
  299. * @return Locator
  300. */
  301. public static function shareLinkMenuButton() {
  302. return Locator::forThe()->css(".share-menu > .icon")->
  303. descendantOf(self::shareLinkRow())->
  304. describedAs("Share link menu button in the details view in Files app");
  305. }
  306. /**
  307. * @return Locator
  308. */
  309. public static function shareLinkMenu() {
  310. return Locator::forThe()->css(".share-menu > .menu")->
  311. descendantOf(self::shareLinkRow())->
  312. describedAs("Share link menu in the details view in Files app");
  313. }
  314. /**
  315. * @return Locator
  316. */
  317. public static function hideDownloadCheckbox() {
  318. // forThe()->checkbox("Hide download") can not be used here; that would
  319. // return the checkbox itself, but the element that the user interacts
  320. // with is the label.
  321. return Locator::forThe()->xpath("//label[normalize-space() = 'Hide download']")->
  322. descendantOf(self::shareLinkMenu())->
  323. describedAs("Hide download checkbox in the details view in Files app");
  324. }
  325. /**
  326. * @return Locator
  327. */
  328. public static function hideDownloadCheckboxInput() {
  329. return Locator::forThe()->checkbox("Hide download")->
  330. descendantOf(self::shareLinkMenu())->
  331. describedAs("Hide download checkbox input in the details view in Files app");
  332. }
  333. /**
  334. * @return Locator
  335. */
  336. public static function allowUploadAndEditingRadioButton() {
  337. // forThe()->radio("Allow upload and editing") can not be used here;
  338. // that would return the radio button itself, but the element that the
  339. // user interacts with is the label.
  340. return Locator::forThe()->xpath("//label[normalize-space() = 'Allow upload and editing']")->
  341. descendantOf(self::shareLinkMenu())->
  342. describedAs("Allow upload and editing radio button in the details view in Files app");
  343. }
  344. /**
  345. * @return Locator
  346. */
  347. public static function passwordProtectCheckbox() {
  348. // forThe()->checkbox("Password protect") can not be used here; that
  349. // would return the checkbox itself, but the element that the user
  350. // interacts with is the label.
  351. return Locator::forThe()->xpath("//label[normalize-space() = 'Password protect']")->
  352. descendantOf(self::shareLinkMenu())->
  353. describedAs("Password protect checkbox in the details view in Files app");
  354. }
  355. /**
  356. * @return Locator
  357. */
  358. public static function passwordProtectCheckboxInput() {
  359. return Locator::forThe()->checkbox("Password protect")->
  360. descendantOf(self::shareLinkMenu())->
  361. describedAs("Password protect checkbox input in the details view in Files app");
  362. }
  363. /**
  364. * @return Locator
  365. */
  366. public static function passwordProtectField() {
  367. return Locator::forThe()->css(".linkPassText")->descendantOf(self::shareLinkMenu())->
  368. describedAs("Password protect field in the details view in Files app");
  369. }
  370. /**
  371. * @return Locator
  372. */
  373. public static function passwordProtectWorkingIcon() {
  374. return Locator::forThe()->css(".linkPassMenu .icon-loading-small")->descendantOf(self::shareLinkMenu())->
  375. describedAs("Password protect working icon in the details view in Files app");
  376. }
  377. /**
  378. * @return Locator
  379. */
  380. public static function passwordProtectByTalkCheckbox() {
  381. // forThe()->checkbox("Password protect by Talk") can not be used here;
  382. // that would return the checkbox itself, but the element that the user
  383. // interacts with is the label.
  384. return Locator::forThe()->xpath("//label[normalize-space() = 'Password protect by Talk']")->
  385. descendantOf(self::shareLinkMenu())->
  386. describedAs("Password protect by Talk checkbox in the details view in Files app");
  387. }
  388. /**
  389. * @return Locator
  390. */
  391. public static function passwordProtectByTalkCheckboxInput() {
  392. return Locator::forThe()->checkbox("Password protect by Talk")->
  393. descendantOf(self::shareLinkMenu())->
  394. describedAs("Password protect by Talk checkbox input in the details view in Files app");
  395. }
  396. /**
  397. * @Given I open the Files app
  398. */
  399. public function iOpenTheFilesApp() {
  400. $this->actor->find(self::filesItemInAppMenu(), 10)->click();
  401. }
  402. /**
  403. * @Given I close the details view
  404. */
  405. public function iCloseTheDetailsView() {
  406. $this->actor->find(self::closeDetailsViewButton(), 10)->click();
  407. }
  408. /**
  409. * @Given I open the input field for tags in the details view
  410. */
  411. public function iOpenTheInputFieldForTagsInTheDetailsView() {
  412. $this->actor->find(self::fileDetailsInDetailsViewWithText("Tags"), 10)->click();
  413. }
  414. /**
  415. * @Given I open the :tabName tab in the details view
  416. */
  417. public function iOpenTheTabInTheDetailsView($tabName) {
  418. $this->actor->find(self::tabHeaderInDetailsViewNamed($tabName), 10)->click();
  419. }
  420. /**
  421. * @Given I share the link for :fileName
  422. */
  423. public function iShareTheLinkFor($fileName) {
  424. $this->actor->find(FileListContext::shareActionForFile(self::currentSectionMainView(), $fileName), 10)->click();
  425. $this->actor->find(self::shareLinkAddNewButton(), 5)->click();
  426. // Wait until the menu was opened after the share creation to continue.
  427. if (!WaitFor::elementToBeEventuallyShown(
  428. $this->actor,
  429. self::shareLinkMenu(),
  430. $timeout = 5 * $this->actor->getFindTimeoutMultiplier())) {
  431. PHPUnit_Framework_Assert::fail("The share link menu is not open yet after $timeout seconds");
  432. }
  433. }
  434. /**
  435. * @Given I share :fileName with :shareWithName
  436. */
  437. public function iShareWith($fileName, $shareWithName) {
  438. $this->actor->find(FileListContext::shareActionForFile(self::currentSectionMainView(), $fileName), 10)->click();
  439. $this->actor->find(self::shareWithInput(), 5)->setValue($shareWithName . "\r");
  440. }
  441. /**
  442. * @Given I write down the shared link
  443. */
  444. public function iWriteDownTheSharedLink() {
  445. $this->actor->find(self::copyLinkButton(), 10)->click();
  446. // Clicking on the menu item copies the link to the clipboard, but it is
  447. // not possible to access that value from the acceptance tests. Due to
  448. // this the value of the attribute that holds the URL is used instead.
  449. $this->actor->getSharedNotebook()["shared link"] = $this->actor->find(self::copyLinkButton(), 2)->getWrappedElement()->getAttribute("data-clipboard-text");
  450. }
  451. /**
  452. * @When I mark the file as favorite in the details view
  453. */
  454. public function iMarkTheFileAsFavoriteInTheDetailsView() {
  455. $this->iSeeThatTheFileIsNotMarkedAsFavoriteInTheDetailsView();
  456. $this->actor->find(self::favoriteActionInFileDetailsInDetailsView(), 10)->click();
  457. }
  458. /**
  459. * @When I unmark the file as favorite in the details view
  460. */
  461. public function iUnmarkTheFileAsFavoriteInTheDetailsView() {
  462. $this->iSeeThatTheFileIsMarkedAsFavoriteInTheDetailsView();
  463. $this->actor->find(self::favoriteActionInFileDetailsInDetailsView(), 10)->click();
  464. }
  465. /**
  466. * @When I check the tag :tag in the dropdown for tags in the details view
  467. */
  468. public function iCheckTheTagInTheDropdownForTagsInTheDetailsView($tag) {
  469. $this->iSeeThatTheTagInTheDropdownForTagsInTheDetailsViewIsNotChecked($tag);
  470. $this->actor->find(self::itemInDropdownForTag($tag), 10)->click();
  471. }
  472. /**
  473. * @When I uncheck the tag :tag in the dropdown for tags in the details view
  474. */
  475. public function iUncheckTheTagInTheDropdownForTagsInTheDetailsView($tag) {
  476. $this->iSeeThatTheTagInTheDropdownForTagsInTheDetailsViewIsChecked($tag);
  477. $this->actor->find(self::itemInDropdownForTag($tag), 10)->click();
  478. }
  479. /**
  480. * @When I set the download of the shared link as hidden
  481. */
  482. public function iSetTheDownloadOfTheSharedLinkAsHidden() {
  483. $this->showShareLinkMenuIfNeeded();
  484. $this->iSeeThatTheDownloadOfTheLinkShareIsShown();
  485. $this->actor->find(self::hideDownloadCheckbox(), 2)->click();
  486. }
  487. /**
  488. * @When I set the download of the shared link as shown
  489. */
  490. public function iSetTheDownloadOfTheSharedLinkAsShown() {
  491. $this->showShareLinkMenuIfNeeded();
  492. $this->iSeeThatTheDownloadOfTheLinkShareIsHidden();
  493. $this->actor->find(self::hideDownloadCheckbox(), 2)->click();
  494. }
  495. /**
  496. * @When I set the shared link as editable
  497. */
  498. public function iSetTheSharedLinkAsEditable() {
  499. $this->showShareLinkMenuIfNeeded();
  500. $this->actor->find(self::allowUploadAndEditingRadioButton(), 2)->click();
  501. }
  502. /**
  503. * @When I protect the shared link with the password :password
  504. */
  505. public function iProtectTheSharedLinkWithThePassword($password) {
  506. $this->showShareLinkMenuIfNeeded();
  507. $this->actor->find(self::passwordProtectCheckbox(), 2)->click();
  508. $this->actor->find(self::passwordProtectField(), 2)->setValue($password . "\r");
  509. }
  510. /**
  511. * @When I set the password of the shared link as protected by Talk
  512. */
  513. public function iSetThePasswordOfTheSharedLinkAsProtectedByTalk() {
  514. $this->showShareLinkMenuIfNeeded();
  515. $this->iSeeThatThePasswordOfTheLinkShareIsNotProtectedByTalk();
  516. $this->actor->find(self::passwordProtectByTalkCheckbox(), 2)->click();
  517. }
  518. /**
  519. * @When I set the password of the shared link as not protected by Talk
  520. */
  521. public function iSetThePasswordOfTheSharedLinkAsNotProtectedByTalk() {
  522. $this->showShareLinkMenuIfNeeded();
  523. $this->iSeeThatThePasswordOfTheLinkShareIsProtectedByTalk();
  524. $this->actor->find(self::passwordProtectByTalkCheckbox(), 2)->click();
  525. }
  526. /**
  527. * @When I set the share with :shareWithName as not reshareable
  528. */
  529. public function iSetTheShareWithAsNotReshareable($shareWithName) {
  530. $this->showShareWithMenuIfNeeded($shareWithName);
  531. $this->iSeeThatCanReshareTheShare($shareWithName);
  532. $this->actor->find(self::canReshareCheckbox($shareWithName), 2)->click();
  533. }
  534. /**
  535. * @Then I see that the current page is the Files app
  536. */
  537. public function iSeeThatTheCurrentPageIsTheFilesApp() {
  538. PHPUnit_Framework_Assert::assertStringStartsWith(
  539. $this->actor->locatePath("/apps/files/"),
  540. $this->actor->getSession()->getCurrentUrl());
  541. $this->setFileListAncestorForActor(self::currentSectionMainView(), $this->actor);
  542. }
  543. /**
  544. * @Then I see that the details view is open
  545. */
  546. public function iSeeThatTheDetailsViewIsOpen() {
  547. // The sidebar always exists in the DOM, so it has to be explicitly
  548. // waited for it to be visible instead of relying on the implicit wait
  549. // made to find the element.
  550. if (!WaitFor::elementToBeEventuallyShown(
  551. $this->actor,
  552. self::detailsView(),
  553. $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
  554. PHPUnit_Framework_Assert::fail("The details view is not open yet after $timeout seconds");
  555. }
  556. }
  557. /**
  558. * @Then I see that the details view is closed
  559. */
  560. public function iSeeThatTheDetailsViewIsClosed() {
  561. if (!WaitFor::elementToBeEventuallyNotShown(
  562. $this->actor,
  563. self::detailsView(),
  564. $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
  565. PHPUnit_Framework_Assert::fail("The details view is not closed yet after $timeout seconds");
  566. }
  567. }
  568. /**
  569. * @Then I see that the file name shown in the details view is :fileName
  570. */
  571. public function iSeeThatTheFileNameShownInTheDetailsViewIs($fileName) {
  572. PHPUnit_Framework_Assert::assertEquals(
  573. $this->actor->find(self::fileNameInDetailsView(), 10)->getText(), $fileName);
  574. }
  575. /**
  576. * @Then I see that the file is marked as favorite in the details view
  577. */
  578. public function iSeeThatTheFileIsMarkedAsFavoriteInTheDetailsView() {
  579. PHPUnit_Framework_Assert::assertNotNull(
  580. $this->actor->find(self::favoritedStateIconInFileDetailsInDetailsView(), 10));
  581. }
  582. /**
  583. * @Then I see that the file is not marked as favorite in the details view
  584. */
  585. public function iSeeThatTheFileIsNotMarkedAsFavoriteInTheDetailsView() {
  586. PHPUnit_Framework_Assert::assertNotNull(
  587. $this->actor->find(self::notFavoritedStateIconInFileDetailsInDetailsView(), 10));
  588. }
  589. /**
  590. * @Then I see that the input field for tags in the details view is shown
  591. */
  592. public function iSeeThatTheInputFieldForTagsInTheDetailsViewIsShown() {
  593. PHPUnit_Framework_Assert::assertTrue(
  594. $this->actor->find(self::inputFieldForTagsInDetailsView(), 10)->isVisible());
  595. }
  596. /**
  597. * @Then I see that the input field for tags in the details view contains the tag :tag
  598. */
  599. public function iSeeThatTheInputFieldForTagsInTheDetailsViewContainsTheTag($tag) {
  600. PHPUnit_Framework_Assert::assertTrue(
  601. $this->actor->find(self::itemInInputFieldForTagsInDetailsViewForTag($tag), 10)->isVisible());
  602. }
  603. /**
  604. * @Then I see that the input field for tags in the details view does not contain the tag :tag
  605. */
  606. public function iSeeThatTheInputFieldForTagsInTheDetailsViewDoesNotContainTheTag($tag) {
  607. $this->iSeeThatTheInputFieldForTagsInTheDetailsViewIsShown();
  608. try {
  609. PHPUnit_Framework_Assert::assertFalse(
  610. $this->actor->find(self::itemInInputFieldForTagsInDetailsViewForTag($tag))->isVisible());
  611. } catch (NoSuchElementException $exception) {
  612. }
  613. }
  614. /**
  615. * @Then I see that the tag :tag in the dropdown for tags in the details view is checked
  616. */
  617. public function iSeeThatTheTagInTheDropdownForTagsInTheDetailsViewIsChecked($tag) {
  618. PHPUnit_Framework_Assert::assertTrue(
  619. $this->actor->find(self::checkmarkInItemInDropdownForTag($tag), 10)->isVisible());
  620. }
  621. /**
  622. * @Then I see that the tag :tag in the dropdown for tags in the details view is not checked
  623. */
  624. public function iSeeThatTheTagInTheDropdownForTagsInTheDetailsViewIsNotChecked($tag) {
  625. PHPUnit_Framework_Assert::assertTrue(
  626. $this->actor->find(self::itemInDropdownForTag($tag), 10)->isVisible());
  627. PHPUnit_Framework_Assert::assertFalse(
  628. $this->actor->find(self::checkmarkInItemInDropdownForTag($tag))->isVisible());
  629. }
  630. /**
  631. * @When I see that the :tabName tab in the details view is eventually loaded
  632. */
  633. public function iSeeThatTheTabInTheDetailsViewIsEventuallyLoaded($tabName) {
  634. if (!WaitFor::elementToBeEventuallyNotShown(
  635. $this->actor,
  636. self::loadingIconForTabInDetailsViewNamed($tabName),
  637. $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
  638. PHPUnit_Framework_Assert::fail("The $tabName tab in the details view has not been loaded after $timeout seconds");
  639. }
  640. }
  641. /**
  642. * @Then I see that the file is shared with me by :sharedByName
  643. */
  644. public function iSeeThatTheFileIsSharedWithMeBy($sharedByName) {
  645. PHPUnit_Framework_Assert::assertEquals(
  646. $this->actor->find(self::sharedByLabel(), 10)->getText(), "Shared with you by $sharedByName");
  647. }
  648. /**
  649. * @Then I see that the file is shared with :sharedWithName
  650. */
  651. public function iSeeThatTheFileIsSharedWith($sharedWithName) {
  652. PHPUnit_Framework_Assert::assertTrue(
  653. $this->actor->find(self::sharedWithRow($sharedWithName), 10)->isVisible());
  654. }
  655. /**
  656. * @Then I see that resharing the file is not allowed
  657. */
  658. public function iSeeThatResharingTheFileIsNotAllowed() {
  659. PHPUnit_Framework_Assert::assertEquals(
  660. $this->actor->find(self::shareWithInput(), 10)->getWrappedElement()->getAttribute("disabled"), "disabled");
  661. PHPUnit_Framework_Assert::assertEquals(
  662. $this->actor->find(self::shareWithInput(), 10)->getWrappedElement()->getAttribute("placeholder"), "Resharing is not allowed");
  663. }
  664. /**
  665. * @Then I see that :sharedWithName can reshare the share
  666. */
  667. public function iSeeThatCanReshareTheShare($sharedWithName) {
  668. $this->showShareWithMenuIfNeeded($sharedWithName);
  669. PHPUnit_Framework_Assert::assertTrue(
  670. $this->actor->find(self::canReshareCheckboxInput($sharedWithName), 10)->isChecked());
  671. }
  672. /**
  673. * @Then I see that :sharedWithName can not reshare the share
  674. */
  675. public function iSeeThatCanNotReshareTheShare($sharedWithName) {
  676. $this->showShareWithMenuIfNeeded($sharedWithName);
  677. PHPUnit_Framework_Assert::assertFalse(
  678. $this->actor->find(self::canReshareCheckboxInput($sharedWithName), 10)->isChecked());
  679. }
  680. /**
  681. * @Then I see that the download of the link share is hidden
  682. */
  683. public function iSeeThatTheDownloadOfTheLinkShareIsHidden() {
  684. $this->showShareLinkMenuIfNeeded();
  685. PHPUnit_Framework_Assert::assertTrue($this->actor->find(self::hideDownloadCheckboxInput(), 10)->isChecked());
  686. }
  687. /**
  688. * @Then I see that the download of the link share is shown
  689. */
  690. public function iSeeThatTheDownloadOfTheLinkShareIsShown() {
  691. $this->showShareLinkMenuIfNeeded();
  692. PHPUnit_Framework_Assert::assertFalse($this->actor->find(self::hideDownloadCheckboxInput(), 10)->isChecked());
  693. }
  694. /**
  695. * @Then I see that the working icon for password protect is shown
  696. */
  697. public function iSeeThatTheWorkingIconForPasswordProtectIsShown() {
  698. PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::passwordProtectWorkingIcon(), 10));
  699. }
  700. /**
  701. * @Then I see that the working icon for password protect is eventually not shown
  702. */
  703. public function iSeeThatTheWorkingIconForPasswordProtectIsEventuallyNotShown() {
  704. if (!WaitFor::elementToBeEventuallyNotShown(
  705. $this->actor,
  706. self::passwordProtectWorkingIcon(),
  707. $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
  708. PHPUnit_Framework_Assert::fail("The working icon for password protect is still shown after $timeout seconds");
  709. }
  710. }
  711. /**
  712. * @Then I see that the link share is password protected
  713. */
  714. public function iSeeThatTheLinkShareIsPasswordProtected() {
  715. $this->showShareLinkMenuIfNeeded();
  716. PHPUnit_Framework_Assert::assertTrue($this->actor->find(self::passwordProtectCheckboxInput(), 10)->isChecked(), "Password protect checkbox is checked");
  717. PHPUnit_Framework_Assert::assertTrue($this->actor->find(self::passwordProtectField(), 10)->isVisible(), "Password protect field is visible");
  718. }
  719. /**
  720. * @Then I see that the password of the link share is protected by Talk
  721. */
  722. public function iSeeThatThePasswordOfTheLinkShareIsProtectedByTalk() {
  723. $this->showShareLinkMenuIfNeeded();
  724. PHPUnit_Framework_Assert::assertTrue($this->actor->find(self::passwordProtectByTalkCheckboxInput(), 10)->isChecked());
  725. }
  726. /**
  727. * @Then I see that the password of the link share is not protected by Talk
  728. */
  729. public function iSeeThatThePasswordOfTheLinkShareIsNotProtectedByTalk() {
  730. $this->showShareLinkMenuIfNeeded();
  731. PHPUnit_Framework_Assert::assertFalse($this->actor->find(self::passwordProtectByTalkCheckboxInput(), 10)->isChecked());
  732. }
  733. /**
  734. * @Then I see that the checkbox to protect the password of the link share by Talk is not shown
  735. */
  736. public function iSeeThatTheCheckboxToProtectThePasswordOfTheLinkShareByTalkIsNotShown() {
  737. $this->showShareLinkMenuIfNeeded();
  738. try {
  739. PHPUnit_Framework_Assert::assertFalse(
  740. $this->actor->find(self::passwordProtectByTalkCheckbox())->isVisible());
  741. } catch (NoSuchElementException $exception) {
  742. }
  743. }
  744. /**
  745. * @Given I share the link for :fileName protected by the password :password
  746. */
  747. public function iShareTheLinkForProtectedByThePassword($fileName, $password) {
  748. $this->iShareTheLinkFor($fileName);
  749. $this->iProtectTheSharedLinkWithThePassword($password);
  750. $this->iSeeThatTheWorkingIconForPasswordProtectIsShown();
  751. $this->iSeeThatTheWorkingIconForPasswordProtectIsEventuallyNotShown();
  752. }
  753. private function showShareLinkMenuIfNeeded() {
  754. // In some cases the share menu is hidden after clicking on an action of
  755. // the menu. Therefore, if the menu is visible, wait a little just in
  756. // case it is in the process of being hidden due to a previous action,
  757. // in which case it is shown again.
  758. if (WaitFor::elementToBeEventuallyNotShown(
  759. $this->actor,
  760. self::shareLinkMenu(),
  761. $timeout = 2 * $this->actor->getFindTimeoutMultiplier())) {
  762. $this->actor->find(self::shareLinkMenuButton(), 10)->click();
  763. }
  764. }
  765. private function showShareWithMenuIfNeeded($shareWithName) {
  766. // In some cases the share menu is hidden after clicking on an action of
  767. // the menu. Therefore, if the menu is visible, wait a little just in
  768. // case it is in the process of being hidden due to a previous action,
  769. // in which case it is shown again.
  770. if (WaitFor::elementToBeEventuallyNotShown(
  771. $this->actor,
  772. self::shareWithMenu($shareWithName),
  773. $timeout = 2 * $this->actor->getFindTimeoutMultiplier())) {
  774. $this->actor->find(self::shareWithMenuButton($shareWithName), 10)->click();
  775. }
  776. }
  777. }