IntegrationSpec.scala 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. import play.api.test.Helpers._
  2. import play.api.test.{FakeRequest}
  3. import play.api.libs.json.{JsObject,Json}
  4. import org.openqa.selenium.By
  5. import org.scalatest.{Assertion,BeforeAndAfterAll,BeforeAndAfterEach}
  6. import org.scalatestplus.play._
  7. import org.scalatestplus.play.guice.GuiceOneServerPerSuite
  8. import com.weEat.shared.models.User
  9. import scala.concurrent.{ExecutionContext,Future,blocking}
  10. import scala.concurrent.duration._
  11. import scala.language.postfixOps
  12. import java.util.concurrent.TimeoutException
  13. class IntegrationSpec extends PlaySpec
  14. with BeforeAndAfterAll
  15. with BeforeAndAfterEach
  16. with GuiceOneServerPerSuite
  17. with AllBrowsersPerTest {
  18. val users = Seq(
  19. (User("test", "user", "tuser@sample.org"), "password"),
  20. (User("another", "user", "usert@sample.org"), "password")
  21. )
  22. override def beforeAll() = {
  23. val Some(resp) = route(app, FakeRequest(PUT, "/user/").withJsonBody(
  24. Json.parse(s"""|{
  25. | "fname": "${users(0)._1.fname}",
  26. | "lname": "${users(0)._1.lname}",
  27. | "email": "${users(0)._1.email}",
  28. | "password": "${users(0)._2}"
  29. |}""".stripMargin)
  30. ))
  31. status(resp) mustEqual OK
  32. }
  33. override lazy val browsers = Vector(
  34. FirefoxInfo(firefoxProfile),
  35. //ChromeInfo
  36. )
  37. val address = s"http://localhost:$port"
  38. /* Will repeatedly attempt to test until a result is returned.
  39. * A None value implies the test is not yet ready to run and will be attempted
  40. * again after the frequency has passed..
  41. *
  42. * A Some value means the test has completed with the contained assertion
  43. * result.
  44. */
  45. def poll(
  46. test: () => Option[Assertion],
  47. frequency: Duration = 100.millisecond
  48. ): Future[Assertion] = {
  49. test() match {
  50. case Some(result) => Future.successful(result)
  51. case None => {
  52. blocking {
  53. Thread.sleep(frequency.toMillis)
  54. }
  55. poll(test, frequency)
  56. }
  57. }
  58. }
  59. def waitForReady[T](
  60. timeout: Duration = 1 minute,
  61. period: Duration = 100 millisecond
  62. )(fn: => T): Future[T] =
  63. if (executeScript("return jQuery.active == 0 && selAsyncCount == 0;").asInstanceOf[Boolean])
  64. Future.successful(fn)
  65. else if (timeout < 0.second)
  66. Future.failed(new TimeoutException())
  67. else {
  68. blocking {
  69. Thread.sleep(period.toMillis)
  70. }
  71. waitForReady(timeout - period, period)(fn)
  72. }
  73. def sharedTests(browser: BrowserInfo) = {
  74. "The register menu" must {
  75. "display when register button is clicked " + browser.name in {
  76. go to address
  77. click on id("btn-signup")
  78. waitForReady() {
  79. click on id("view-register").webElement.findElement(By.xpath("./.."))
  80. //id("content").webElement.getText mustEqual ("")
  81. }
  82. }
  83. def testUserList() = {
  84. val Some(resp) = route(app, FakeRequest(GET, "/user/"))
  85. status(resp) mustEqual OK
  86. contentAsJson(resp).as[Seq[String]] must matchPattern {
  87. case Seq(user1, user2) =>
  88. }
  89. }
  90. "accept a new user " + browser.name in {
  91. go to address
  92. click on id("btn-signup")
  93. waitForReady() {
  94. textField("email").value = users(1)._1.email
  95. name("password").webElement.sendKeys(users(1)._2)
  96. name("password2").webElement.sendKeys(users(1)._2)
  97. textField("fname").value = users(1)._1.fname
  98. textField("lname").value = users(1)._1.lname
  99. click on cssSelector("*[data-cb='success']")
  100. waitForReady() {
  101. find("#view-register") must be (None)
  102. id("btn-logout").webElement must be ("displayed")
  103. // id("content").webElement.getText
  104. // .mustEqual(s"Hello, ${users(1)._1.fname} ${users(1)._1.lname}!")
  105. // testUserList()
  106. }
  107. }
  108. }
  109. "reject a used email " + browser.name in {
  110. go to address
  111. click on id("btn-signup")
  112. waitForReady() {
  113. textField("email").value = users(0)._1.email
  114. name("password").webElement.sendKeys("_"+users(0)._2)
  115. name("password2").webElement.sendKeys("_"+users(0)._2)
  116. textField("fname").value = "_"+users(0)._1.fname
  117. textField("lname").value = "_"+users(0)._1.lname
  118. click on cssSelector("*[data-cb='success']")
  119. waitForReady() {
  120. cssSelector(".alert-danger").webElement.getText
  121. .mustEqual("Error: This email address is already registered.")
  122. id("btn-logout").webElement mustNot be ("displayed")
  123. //id("content").webElement.getText mustEqual("")
  124. testUserList()
  125. }
  126. }
  127. }
  128. "reject an invalid email " + browser.name in {
  129. go to address
  130. click on id("btn-signup")
  131. waitForReady() {
  132. textField("email").value = "hello World!"
  133. name("password").webElement.sendKeys("_"+users(0)._2)
  134. name("password2").webElement.sendKeys("_"+users(0)._2)
  135. textField("fname").value = "_"+users(0)._1.fname
  136. textField("lname").value = "_"+users(0)._1.lname
  137. click on cssSelector("*[data-cb='success']")
  138. waitForReady() {
  139. cssSelector(".alert-danger").webElement.getText
  140. .mustEqual("Error: Invalid email.")
  141. id("btn-logout").webElement mustNot be ("displayed")
  142. //id("content").webElement.getText mustEqual("")
  143. testUserList()
  144. }
  145. }
  146. }
  147. "reject a password below 8 characters " + browser.name in {
  148. go to address
  149. click on id("btn-signup")
  150. waitForReady() {
  151. textField("email").value = "_"+users(0)._1.email
  152. name("password").webElement.sendKeys("1234567")
  153. name("password2").webElement.sendKeys("1234567")
  154. textField("fname").value = "_"+users(0)._1.fname
  155. textField("lname").value = "_"+users(0)._1.lname
  156. click on cssSelector("*[data-cb='success']")
  157. waitForReady() {
  158. cssSelector(".alert-danger").webElement.getText
  159. .mustEqual("Error: Password too short (Minimum 8 characters).")
  160. id("btn-logout").webElement mustNot be ("displayed")
  161. //id("content").webElement.getText mustEqual("")
  162. testUserList()
  163. }
  164. }
  165. }
  166. "reject a non-matching passwords " + browser.name in {
  167. go to address
  168. click on id("btn-signup")
  169. waitForReady() {
  170. textField("email").value = "_"+users(0)._1.email
  171. name("password").webElement.sendKeys(users(0)._2)
  172. name("password2").webElement.sendKeys("_"+users(0)._2)
  173. textField("fname").value = "_"+users(0)._1.fname
  174. textField("lname").value = "_"+users(0)._1.lname
  175. click on cssSelector("*[data-cb='success']")
  176. waitForReady() {
  177. cssSelector(".alert-danger").webElement.getText
  178. .mustEqual("Error: Passwords do not match.")
  179. id("btn-logout").webElement mustNot be ("displayed")
  180. //id("content").webElement.getText mustEqual("")
  181. testUserList()
  182. }
  183. }
  184. }
  185. }
  186. "The login menu" must {
  187. "display when login button is clicked " + browser.name in {
  188. go to address
  189. click on id("btn-login")
  190. waitForReady() {
  191. click on id("view-login").webElement.findElement(By.xpath("./.."))
  192. id("btn-logout").webElement mustNot be ("displayed")
  193. //id("content").webElement.getText mustEqual("")
  194. }
  195. }
  196. "accept user created from API " + browser.name in {
  197. go to address
  198. click on id("btn-login")
  199. waitForReady() {
  200. textField("email").value = users(0)._1.email
  201. name("password").webElement.sendKeys(users(0)._2)
  202. click on cssSelector("*[data-cb='success']")
  203. waitForReady() {
  204. find("#view-login") must be (None)
  205. id("btn-logout").webElement must be ("displayed")
  206. // id("content").webElement.getText
  207. // .mustEqual(s"Hello, ${users(0)._1.fname} ${users(0)._1.lname}!")
  208. }
  209. }
  210. }
  211. "accept user created from UI " + browser.name in {
  212. go to address
  213. click on id("btn-login")
  214. waitForReady() {
  215. textField("email").value = users(1)._1.email
  216. name("password").webElement.sendKeys(users(1)._2)
  217. click on cssSelector("*[data-cb='success']")
  218. waitForReady() {
  219. find("#view-login") must be (None)
  220. id("btn-logout").webElement must be ("displayed")
  221. // id("content").webElement.getText
  222. // .mustEqual(s"Hello, ${users(1)._1.fname} ${users(1)._1.lname}!")
  223. }
  224. }
  225. }
  226. "reject an incorrect email " + browser.name in {
  227. go to address
  228. click on id("btn-login")
  229. waitForReady() {
  230. textField("email").value = "_"+users(1)._1.email
  231. name("password").webElement.sendKeys(users(0)._2)
  232. click on cssSelector("*[data-cb='success']")
  233. waitForReady() {
  234. cssSelector(".alert-danger").webElement.getText
  235. .mustEqual("Error: Invalid client or client is not authorized")
  236. id("btn-logout").webElement mustNot be ("displayed")
  237. //id("content").webElement.getText mustEqual("")
  238. }
  239. }
  240. }
  241. "reject an incorrect password " + browser.name in {
  242. go to address
  243. click on id("btn-login")
  244. waitForReady() {
  245. textField("email").value = users(1)._1.email
  246. name("password").webElement.sendKeys("_"+users(0)._2)
  247. click on cssSelector("*[data-cb='success']")
  248. waitForReady() {
  249. cssSelector(".alert-danger").webElement.getText
  250. .mustEqual("Error: Invalid client or client is not authorized")
  251. id("btn-logout").webElement mustNot be ("displayed")
  252. //id("content").webElement.getText mustEqual("")
  253. }
  254. }
  255. }
  256. "reject an incorrect email and password " + browser.name in {
  257. go to address
  258. click on id("btn-login")
  259. waitForReady() {
  260. textField("email").value = "_"+users(1)._1.email
  261. name("password").webElement.sendKeys("_"+users(0)._2)
  262. click on cssSelector("*[data-cb='success']")
  263. waitForReady() {
  264. cssSelector(".alert-danger").webElement.getText
  265. .mustEqual("Error: Invalid client or client is not authorized")
  266. id("btn-logout").webElement mustNot be ("displayed")
  267. //id("content").webElement.getText mustEqual("")
  268. }
  269. }
  270. }
  271. "maintain login info across refresh " + browser.name in {
  272. go to address
  273. click on id("btn-login")
  274. waitForReady() {
  275. textField("email").value = users(1)._1.email
  276. name("password").webElement.sendKeys(users(1)._2)
  277. click on cssSelector("*[data-cb='success']")
  278. waitForReady() {
  279. go to address
  280. waitForReady() {
  281. find("#view-login") must be (None)
  282. id("btn-logout").webElement must be ("displayed")
  283. // id("content").webElement.getText
  284. // .mustEqual(s"Hello, ${users(1)._1.fname} ${users(1)._1.lname}!")
  285. id("btn-logout").webElement must be ("displayed")
  286. }
  287. }
  288. }
  289. }
  290. }
  291. "The logout button" must {
  292. "not display when not logged in " + browser.name in {
  293. go to address
  294. waitForReady() {
  295. id("btn-logout").webElement mustNot be ("displayed")
  296. //id("content").webElement.getText mustEqual("")
  297. }
  298. }
  299. "display when logged in" + browser.name in {
  300. go to address
  301. click on id("btn-login")
  302. waitForReady() {
  303. textField("email").value = users(0)._1.email
  304. name("password").webElement.sendKeys(users(0)._2)
  305. click on cssSelector("*[data-cb='success']")
  306. waitForReady() {
  307. id("btn-logout").webElement must be ("displayed")
  308. }
  309. }
  310. }
  311. "remove user information when clicked " + browser.name in {
  312. go to address
  313. click on id("btn-login")
  314. waitForReady() {
  315. textField("email").value = users(0)._1.email
  316. name("password").webElement.sendKeys(users(0)._2)
  317. click on cssSelector("*[data-cb='success']")
  318. waitForReady() {
  319. click on id("btn-logout")
  320. waitForReady() {
  321. id("btn-logout").webElement mustNot be ("displayed")
  322. //id("content").webElement.getText mustEqual("")
  323. }
  324. }
  325. }
  326. }
  327. "remove stored user information when clicked " + browser.name in {
  328. go to address
  329. click on id("btn-login")
  330. waitForReady() {
  331. textField("email").value = users(0)._1.email
  332. name("password").webElement.sendKeys(users(0)._2)
  333. click on cssSelector("*[data-cb='success']")
  334. waitForReady() {
  335. click on id("btn-logout")
  336. waitForReady() {
  337. go to address
  338. id("btn-logout").webElement mustNot be ("displayed")
  339. //id("content").webElement.getText mustEqual("")
  340. }
  341. }
  342. }
  343. }
  344. }
  345. }
  346. }