FilesAppContext.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  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. * @Given I open the Files app
  205. */
  206. public function iOpenTheFilesApp() {
  207. $this->actor->find(self::filesItemInAppMenu(), 10)->click();
  208. }
  209. /**
  210. * @Given I close the details view
  211. */
  212. public function iCloseTheDetailsView() {
  213. $this->actor->find(self::closeDetailsViewButton(), 10)->click();
  214. }
  215. /**
  216. * @Given I open the input field for tags in the details view
  217. */
  218. public function iOpenTheInputFieldForTagsInTheDetailsView() {
  219. $this->actor->find(self::fileDetailsInDetailsViewWithText("Tags"), 10)->click();
  220. }
  221. /**
  222. * @Given I open the :tabName tab in the details view
  223. */
  224. public function iOpenTheTabInTheDetailsView($tabName) {
  225. $this->actor->find(self::tabHeaderInDetailsViewNamed($tabName), 10)->click();
  226. }
  227. /**
  228. * @When I mark the file as favorite in the details view
  229. */
  230. public function iMarkTheFileAsFavoriteInTheDetailsView() {
  231. $this->iSeeThatTheFileIsNotMarkedAsFavoriteInTheDetailsView();
  232. $this->actor->find(self::favoriteActionInFileDetailsInDetailsView(), 10)->click();
  233. }
  234. /**
  235. * @When I unmark the file as favorite in the details view
  236. */
  237. public function iUnmarkTheFileAsFavoriteInTheDetailsView() {
  238. $this->iSeeThatTheFileIsMarkedAsFavoriteInTheDetailsView();
  239. $this->actor->find(self::favoriteActionInFileDetailsInDetailsView(), 10)->click();
  240. }
  241. /**
  242. * @When I check the tag :tag in the dropdown for tags in the details view
  243. */
  244. public function iCheckTheTagInTheDropdownForTagsInTheDetailsView($tag) {
  245. $this->iSeeThatTheTagInTheDropdownForTagsInTheDetailsViewIsNotChecked($tag);
  246. $this->actor->find(self::itemInDropdownForTag($tag), 10)->click();
  247. }
  248. /**
  249. * @When I uncheck the tag :tag in the dropdown for tags in the details view
  250. */
  251. public function iUncheckTheTagInTheDropdownForTagsInTheDetailsView($tag) {
  252. $this->iSeeThatTheTagInTheDropdownForTagsInTheDetailsViewIsChecked($tag);
  253. $this->actor->find(self::itemInDropdownForTag($tag), 10)->click();
  254. }
  255. /**
  256. * @Then I see that the current page is the Files app
  257. */
  258. public function iSeeThatTheCurrentPageIsTheFilesApp() {
  259. PHPUnit_Framework_Assert::assertStringStartsWith(
  260. $this->actor->locatePath("/apps/files/"),
  261. $this->actor->getSession()->getCurrentUrl());
  262. $this->setFileListAncestorForActor(self::currentSectionMainView(), $this->actor);
  263. }
  264. /**
  265. * @Then I see that the details view is open
  266. */
  267. public function iSeeThatTheDetailsViewIsOpen() {
  268. // The sidebar always exists in the DOM, so it has to be explicitly
  269. // waited for it to be visible instead of relying on the implicit wait
  270. // made to find the element.
  271. if (!WaitFor::elementToBeEventuallyShown(
  272. $this->actor,
  273. self::detailsView(),
  274. $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
  275. PHPUnit_Framework_Assert::fail("The details view is not open yet after $timeout seconds");
  276. }
  277. }
  278. /**
  279. * @Then I see that the details view is closed
  280. */
  281. public function iSeeThatTheDetailsViewIsClosed() {
  282. if (!WaitFor::elementToBeEventuallyNotShown(
  283. $this->actor,
  284. self::detailsView(),
  285. $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
  286. PHPUnit_Framework_Assert::fail("The details view is not closed yet after $timeout seconds");
  287. }
  288. }
  289. /**
  290. * @Then I see that the file name shown in the details view is :fileName
  291. */
  292. public function iSeeThatTheFileNameShownInTheDetailsViewIs($fileName) {
  293. PHPUnit_Framework_Assert::assertEquals(
  294. $this->actor->find(self::fileNameInDetailsView(), 10)->getText(), $fileName);
  295. }
  296. /**
  297. * @Then I see that the file is marked as favorite in the details view
  298. */
  299. public function iSeeThatTheFileIsMarkedAsFavoriteInTheDetailsView() {
  300. PHPUnit_Framework_Assert::assertNotNull(
  301. $this->actor->find(self::favoritedStateIconInFileDetailsInDetailsView(), 10));
  302. }
  303. /**
  304. * @Then I see that the file is not marked as favorite in the details view
  305. */
  306. public function iSeeThatTheFileIsNotMarkedAsFavoriteInTheDetailsView() {
  307. PHPUnit_Framework_Assert::assertNotNull(
  308. $this->actor->find(self::notFavoritedStateIconInFileDetailsInDetailsView(), 10));
  309. }
  310. /**
  311. * @Then I see that the input field for tags in the details view is shown
  312. */
  313. public function iSeeThatTheInputFieldForTagsInTheDetailsViewIsShown() {
  314. PHPUnit_Framework_Assert::assertTrue(
  315. $this->actor->find(self::inputFieldForTagsInDetailsView(), 10)->isVisible());
  316. }
  317. /**
  318. * @Then I see that the input field for tags in the details view contains the tag :tag
  319. */
  320. public function iSeeThatTheInputFieldForTagsInTheDetailsViewContainsTheTag($tag) {
  321. PHPUnit_Framework_Assert::assertTrue(
  322. $this->actor->find(self::itemInInputFieldForTagsInDetailsViewForTag($tag), 10)->isVisible());
  323. }
  324. /**
  325. * @Then I see that the input field for tags in the details view does not contain the tag :tag
  326. */
  327. public function iSeeThatTheInputFieldForTagsInTheDetailsViewDoesNotContainTheTag($tag) {
  328. $this->iSeeThatTheInputFieldForTagsInTheDetailsViewIsShown();
  329. try {
  330. PHPUnit_Framework_Assert::assertFalse(
  331. $this->actor->find(self::itemInInputFieldForTagsInDetailsViewForTag($tag))->isVisible());
  332. } catch (NoSuchElementException $exception) {
  333. }
  334. }
  335. /**
  336. * @Then I see that the tag :tag in the dropdown for tags in the details view is checked
  337. */
  338. public function iSeeThatTheTagInTheDropdownForTagsInTheDetailsViewIsChecked($tag) {
  339. PHPUnit_Framework_Assert::assertTrue(
  340. $this->actor->find(self::checkmarkInItemInDropdownForTag($tag), 10)->isVisible());
  341. }
  342. /**
  343. * @Then I see that the tag :tag in the dropdown for tags in the details view is not checked
  344. */
  345. public function iSeeThatTheTagInTheDropdownForTagsInTheDetailsViewIsNotChecked($tag) {
  346. PHPUnit_Framework_Assert::assertTrue(
  347. $this->actor->find(self::itemInDropdownForTag($tag), 10)->isVisible());
  348. PHPUnit_Framework_Assert::assertFalse(
  349. $this->actor->find(self::checkmarkInItemInDropdownForTag($tag))->isVisible());
  350. }
  351. /**
  352. * @When I see that the :tabName tab in the details view is eventually loaded
  353. */
  354. public function iSeeThatTheTabInTheDetailsViewIsEventuallyLoaded($tabName) {
  355. if (!WaitFor::elementToBeEventuallyNotShown(
  356. $this->actor,
  357. self::loadingIconForTabInDetailsViewNamed($tabName),
  358. $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
  359. PHPUnit_Framework_Assert::fail("The $tabName tab in the details view has not been loaded after $timeout seconds");
  360. }
  361. }
  362. }