From d422b07394de1259c7c09088b7e8ab05375fffeb Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 16 Jul 2018 14:49:06 +0900 Subject: [PATCH 01/14] Add more helpful classes and ids --- src/frontend/editbox.nim | 4 ++-- src/frontend/forum.nim | 2 +- src/frontend/signup.nim | 9 +++++---- src/frontend/usermenu.nim | 12 +++++++----- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/frontend/editbox.nim b/src/frontend/editbox.nim index 3f8753e..d461f90 100644 --- a/src/frontend/editbox.nim +++ b/src/frontend/editbox.nim @@ -87,7 +87,7 @@ when defined(js): text state.error.get().message tdiv(class="edit-buttons"): - tdiv(class="reply-button"): + tdiv(class="cancel-button"): button(class="btn btn-link", onClick=(e: Event, n: VNode) => (state.onEditCancel())): text " Cancel" @@ -95,4 +95,4 @@ when defined(js): button(class=class({"loading": state.loading}, "btn btn-primary"), onClick=(e: Event, n: VNode) => state.save()): italic(class="fas fa-check") - text " Save" \ No newline at end of file + text " Save" diff --git a/src/frontend/forum.nim b/src/frontend/forum.nim index cfc4151..4dea047 100644 --- a/src/frontend/forum.nim +++ b/src/frontend/forum.nim @@ -149,4 +149,4 @@ proc render(): VNode = ]) window.onPopState = onPopState -setRenderer render \ No newline at end of file +setRenderer render diff --git a/src/frontend/signup.nim b/src/frontend/signup.nim index 20a14ae..1a4b47a 100644 --- a/src/frontend/signup.nim +++ b/src/frontend/signup.nim @@ -78,10 +78,11 @@ when defined(js): "data-sitekey"=recaptchaSiteKey.get()) script(src="https://www.google.com/recaptcha/api.js") tdiv(class="modal-footer"): - button(class=class({"loading": state.loading}, "btn btn-primary"), - onClick=(ev: Event, n: VNode) => onSignUpClick(ev, n, state)): + button(class=class({"loading": state.loading}, + "btn btn-primary create-account-btn"), + onClick=(ev: Event, n: VNode) => onSignUpClick(ev, n, state)): text "Create account" - button(class="btn", + button(class="btn login-btn", onClick=(ev: Event, n: VNode) => (state.onLogIn(); state.shown = false)): text "Log in" @@ -92,4 +93,4 @@ when defined(js): onClick=(ev: Event, n: VNode) => (state.shown = false; anchorCB(ev, n))): text "content license" - text "." \ No newline at end of file + text "." diff --git a/src/frontend/usermenu.nim b/src/frontend/usermenu.nim index 65ea45c..89954a9 100644 --- a/src/frontend/usermenu.nim +++ b/src/frontend/usermenu.nim @@ -24,7 +24,7 @@ when defined(js): proc render*(state: UserMenu, user: User): VNode = result = buildHtml(): - tdiv(): + tdiv(id="profile-btn"): figure(class="avatar c-hand", onClick=(e: Event, n: VNode) => onClick(e, n, state)): img(src=user.avatarUrl, title=user.name) @@ -52,13 +52,15 @@ when defined(js): tdiv(class="tile-icon"): img(class="avatar", src=user.avatarUrl, title=user.name) - tdiv(class="tile-content"): + tdiv(id="profile-name", class="tile-content"): text user.name li(class="divider") li(class="menu-item"): - a(href=makeUri("/profile/" & user.name)): + a(id="myprofile-btn", + href=makeUri("/profile/" & user.name)): text "My profile" li(class="menu-item c-hand"): - a(onClick = (e: Event, n: VNode) => + a(id="logout-btn", + onClick = (e: Event, n: VNode) => (state.shown=false; state.onLogout())): - text "Logout" \ No newline at end of file + text "Logout" From cb5923d9f8caf97f19aee09e7e243d582cd9c904 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 16 Jul 2018 14:49:56 +0900 Subject: [PATCH 02/14] Add helpful macro and procs for testing --- tests/browsertests/common.nim | 80 ++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 21 deletions(-) diff --git a/tests/browsertests/common.nim b/tests/browsertests/common.nim index 3d651e3..7100116 100644 --- a/tests/browsertests/common.nim +++ b/tests/browsertests/common.nim @@ -1,5 +1,48 @@ -import os, options +import os, options, unittest import webdriver +import macros + +macro with*(obj: typed, code: untyped): untyped = + ## Execute a set of statements with an object + expectKind code, nnkStmtList + result = code + + # Simply inject obj into call + for i in 0 ..< result.len: + if result[i].kind in {nnkCommand, nnkCall}: + result[i].insert(1, obj) + +template click*(session: Session, element: string, strategy=CssSelector) = + let el = session.findElement(element, strategy) + check el.isSome() + el.get().click() + +template sendKeys*(session: Session, element, keys: string) = + let el = session.findElement(element) + check el.isSome() + el.get().sendKeys(keys) + +template sendKeys*(session: Session, element: string, keys: varargs[Key]) = + let el = session.findElement(element) + check el.isSome() + + # focus + el.get().click() + for key in keys: + session.press(key) + +template ensureExists*(session: Session, element: string) = + let el = session.findElement(element) + check el.isSome() + +template check*(session: Session, element: string, function: untyped) = + let el = session.findElement(element) + check function(el) + +template checkText*(session: Session, element, expectedValue: string) = + let el = session.findElement(element) + check el.isSome() + check el.get().getText() == expectedValue proc waitForLoad*(session: Session, timeout=20000) = var waitTime = 0 @@ -14,29 +57,24 @@ proc waitForLoad*(session: Session, timeout=20000) = if waitTime > timeout: doAssert false, "Wait for load time exceeded" +proc wait*(session: Session) = + session.waitForLoad() + +proc wait*(session: Session, msTimeout: int) = + session.waitForLoad(msTimeout) + proc logout*(session: Session) = - # Check whether we can log out. - let logoutLink = session.findElement( - "Logout", - LinkTextSelector - ).get() - logoutLink.click() + with session: + click "#profile-btn" + click "#logout-btn" proc login*(session: Session, user, password: string) = - let logIn = session.findElement("#login-btn").get() - logIn.click() + with session: + click "#login-btn" - let usernameField = session.findElement( - "#login-form input[name='username']" - ) + sendKeys "#login-form input[name='username']", "admin" + sendKeys "#login-form input[name='password']", "admin" - let passwordField = session.findElement( - "#login-form input[name='password']" - ) + sendKeys "#login-form input[name='password']", Key.Enter - usernameField.get().sendKeys("admin") - passwordField.get().sendKeys("admin") - passwordField.get().click() # Focus field. - session.press(Key.Enter) - - waitForLoad(session, 5000) \ No newline at end of file + wait(5000) From 1b55aec5d26195852c8f9e96809d35d7a5590d54 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 16 Jul 2018 14:50:33 +0900 Subject: [PATCH 03/14] Rewrite scenario1 with new macro --- tests/browsertests/scenario1.nim | 108 +++++++++---------------------- 1 file changed, 32 insertions(+), 76 deletions(-) diff --git a/tests/browsertests/scenario1.nim b/tests/browsertests/scenario1.nim index fe8ef22..1674130 100644 --- a/tests/browsertests/scenario1.nim +++ b/tests/browsertests/scenario1.nim @@ -9,96 +9,52 @@ proc test*(session: Session, baseUrl: string) = # Sanity checks test "shows sign up": - let signUp = session.findElement("#signup-btn") - check signUp.get().getText() == "Sign up" + with session: + checkText "#signup-btn", "Sign up" test "shows log in": - let logIn = session.findElement("#login-btn") - check logIn.get().getText() == "Log in" + with session: + checkText "#login-btn", "Log in" test "is empty": - let thread = session.findElement("tr > td.thread-title") - check thread.isNone() + with session: + check "tr > td.thread-title", isNone # Logging in test "can login/logout": - let logIn = session.findElement("#login-btn").get() - logIn.click() + with session: + click "#login-btn" - let usernameField = session.findElement( - "#login-form input[name='username']" - ) - check usernameField.isSome() - let passwordField = session.findElement( - "#login-form input[name='password']" - ) - check passwordField.isSome() + sendKeys "#login-form input[name='username']", "admin" + sendKeys "#login-form input[name='password']", "admin" - usernameField.get().sendKeys("admin") - passwordField.get().sendKeys("admin") - passwordField.get().click() # Focus field. - session.press(Key.Enter) + sendKeys "#login-form input[name='password']", Key.Enter + wait(5000) - waitForLoad(session, 5000) + # Verify that the user menu has been initialised properly. + click "#profile-btn" + checkText "#profile-btn #profile-name", "admin" - # Verify that the user menu has been initialised properly. - let profileButton = session.findElement( - "#main-navbar figure.avatar" - ).get() - profileButton.click() - - let profileName = session.findElement( - "#main-navbar .menu-right div.tile-content" - ).get() - - check profileName.getText() == "admin" - - # Check whether we can log out. - let logoutLink = session.findElement( - "Logout", - LinkTextSelector - ).get() - logoutLink.click() - - # Verify we have logged out by looking for the log in button. - check session.findElement("#login-btn").isSome() + # Check whether we can log out. + click "#logout-btn" + # Verify we have logged out by looking for the log in button. + ensureExists "#login-btn" test "can register": - let signup = session.findElement("#signup-btn").get() - signup.click() + with session: + click "#signup-btn" - let emailField = session.findElement( - "#signup-form input[name='email']" - ).get() - let usernameField = session.findElement( - "#signup-form input[name='username']" - ).get() - let passwordField = session.findElement( - "#signup-form input[name='password']" - ).get() + sendKeys "#signup-form input[name='email']", "test@test.com" + sendKeys "#signup-form input[name='username']", "test" + sendKeys "#signup-form input[name='password']", "test" - emailField.sendKeys("test@test.com") - usernameField.sendKeys("test") - passwordField.sendKeys("test") + click "#signup-modal .create-account-btn" + wait(5000) - let createAccount = session.findElement( - "#signup-modal .modal-footer .btn-primary" - ).get() + # Verify that the user menu has been initialised properly. + click "#profile-btn" + checkText "#profile-btn #profile-name", "test" + # close menu + click "#profile-btn" - createAccount.click() - - waitForLoad(session, 5000) - - # Verify that the user menu has been initialised properly. - let profileButton = session.findElement( - "#main-navbar figure.avatar" - ).get() - profileButton.click() - - let profileName = session.findElement( - "#main-navbar .menu-right div.tile-content" - ).get() - - check profileName.getText() == "test" - - logout(session) \ No newline at end of file + logout(session) From d7f3a038a95bc9e2e90499c8e10d73bc5228e846 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 16 Jul 2018 14:51:21 +0900 Subject: [PATCH 04/14] Rewrite threads tests with new macro --- tests/browsertests/threads.nim | 71 +++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/tests/browsertests/threads.nim b/tests/browsertests/threads.nim index 1474ec6..23ffce2 100644 --- a/tests/browsertests/threads.nim +++ b/tests/browsertests/threads.nim @@ -3,44 +3,61 @@ import unittest, options, os, common import webdriver proc test*(session: Session, baseUrl: string) = - session.navigate(baseUrl) - - waitForLoad(session) - - login(session, "admin", "admin") - - test "can create thread": - let newThreadBtn = session.findElement("#new-thread-btn").get() - newThreadBtn.click() + let + titleStr = "This is a thread title!" + contentStr = "This is content" + suite "thread tests": + session.navigate(baseUrl) waitForLoad(session) + login(session, "admin", "admin") - let newThread = session.findElement("#new-thread") - check newThread.isSome() + setup: + session.navigate(baseUrl) + waitForLoad(session) - let createThreadBtn = session.findElement("#create-thread-btn") - check createThreadBtn.isSome() + test "can create thread": + with session: + click "#new-thread-btn" + wait() + sendKeys "#thread-title", titleStr + sendKeys "#reply-textarea", contentStr - let threadTitle = session.findElement("#thread-title") - check threadTitle.isSome() + click "#create-thread-btn" + wait() - let replyBox = session.findElement("#reply-textarea") - check replyBox.isSome() + checkText "#thread-title", titleStr + checkText ".original-post div.post-content", contentStr - threadTitle.get().sendKeys("This is a thread title!") - replyBox.get().sendKeys("This is content.") + test "try create duplicate thread": + with session: + click "#new-thread-btn" + wait() + ensureExists "#new-thread" - createThreadBtn.get().click() + sendKeys "#thread-title", titleStr + sendKeys "#reply-textarea", contentStr - waitForLoad(session) + click "#create-thread-btn" - let newThreadTitle = session.findElement("#thread-title") - check newThreadTitle.isSome() + wait() - check newThreadTitle.get().getText() == "This is a thread title!" + ensureExists "#new-thread p.text-error" - let content = session.findElement(".original-post div.post-content") - check content.isSome() + test "can edit post": + let modificationText = " and I edited it!" + with session: + click titleStr, LinkTextSelector + wait() - check content.get().getText() == "This is content." + click ".post-buttons .edit-button" + wait() + + sendKeys ".original-post #reply-textarea", modificationText + click ".edit-buttons .save-button" + wait() + + checkText ".original-post div.post-content", contentStr & modificationText + + logout(session) From 3c932248173080cee0c62de97d773d942ac28491 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 16 Jul 2018 19:05:26 +0900 Subject: [PATCH 05/14] Fix user/password combo --- tests/browsertests/common.nim | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/browsertests/common.nim b/tests/browsertests/common.nim index 7100116..cb16831 100644 --- a/tests/browsertests/common.nim +++ b/tests/browsertests/common.nim @@ -39,6 +39,11 @@ template check*(session: Session, element: string, function: untyped) = let el = session.findElement(element) check function(el) +template check*(session: Session, element: string, + strategy: LocationStrategy, function: untyped) = + let el = session.findElement(element, strategy) + check function(el) + template checkText*(session: Session, element, expectedValue: string) = let el = session.findElement(element) check el.isSome() @@ -67,13 +72,14 @@ proc logout*(session: Session) = with session: click "#profile-btn" click "#logout-btn" + wait(5000) proc login*(session: Session, user, password: string) = with session: click "#login-btn" - sendKeys "#login-form input[name='username']", "admin" - sendKeys "#login-form input[name='password']", "admin" + sendKeys "#login-form input[name='username']", user + sendKeys "#login-form input[name='password']", password sendKeys "#login-form input[name='password']", Key.Enter From 0d67eab62642bcab571cdfffe4358281f6464b10 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 16 Jul 2018 19:06:00 +0900 Subject: [PATCH 06/14] Create test and dev users for testing --- src/setup_nimforum.nim | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/setup_nimforum.nim b/src/setup_nimforum.nim index a015f2d..9c93080 100644 --- a/src/setup_nimforum.nim +++ b/src/setup_nimforum.nim @@ -22,10 +22,26 @@ proc backup(path: string, contents: Option[string]=none[string]()) = echo(path, " already exists. Moving to ", backupPath) moveFile(path, backupPath) +proc createUser(db: DbConn, user: tuple[username, password, email: string], + rank: Rank) = + + if user.username.len != 0: + let salt = makeSalt() + let password = makePassword(user.password, salt) + + exec(db, sql""" + INSERT INTO person(name, password, email, salt, status, lastOnline) + VALUES (?, ?, ?, ?, ?, DATETIME('now')) + """, user.username, password, user.email, salt, $rank) + proc initialiseDb(admin: tuple[username, password, email: string], filename="nimforum.db") = - let path = getCurrentDir() / filename - if "-dev" notin filename and "-test" notin filename: + let + path = getCurrentDir() / filename + isTest = "-test" in filename + isDev = "-dev" in filename + + if not isDev and not isTest: backup(path) removeFile(path) @@ -98,13 +114,16 @@ proc initialiseDb(admin: tuple[username, password, email: string], db.exec sql"create index PersonStatusIdx on person(status);" # Create default user. - if admin.username.len != 0: - let salt = makeSalt() - let password = makePassword(admin.password, salt) - db.exec(sql""" - insert into person (id, name, password, email, salt, status) - values (1, ?, ?, ?, ?, ?); - """, admin.username, password, admin.email, salt, $Admin) + db.createUser(admin, Admin) + + # Create test users if test or development + if isTest or isDev: + for rank in Spammer..Moderator: + let rankLower = toLowerAscii($rank) + let user = (username: $rankLower, + password: $rankLower, + email: $rankLower & "@localhost.local") + db.createUser(user, rank) # -- Post From 6fb5cfbfa236c0c627a03184784569a4142df6d2 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 16 Jul 2018 21:09:24 +0900 Subject: [PATCH 07/14] Add more friendly classes --- src/frontend/delete.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/frontend/delete.nim b/src/frontend/delete.nim index 789aebc..37446e5 100644 --- a/src/frontend/delete.nim +++ b/src/frontend/delete.nim @@ -94,7 +94,7 @@ when defined(js): proc render*(state: DeleteModal): VNode = result = buildHtml(): tdiv(class=class({"active": state.shown}, "modal modal-sm"), - id="login-modal"): + id="delete-modal"): a(href="", class="modal-overlay", "aria-label"="close", onClick=(ev: Event, n: VNode) => onClose(ev, n, state)) tdiv(class="modal-container"): @@ -122,11 +122,11 @@ when defined(js): button(class=class( {"loading": state.loading}, - "btn btn-primary" + "btn btn-primary delete-btn" ), onClick=(ev: Event, n: VNode) => onDelete(ev, n, state)): italic(class="fas fa-trash-alt") text " Delete" - button(class="btn", + button(class="btn cancel-btn", onClick=(ev: Event, n: VNode) => (state.shown = false)): - text "Cancel" \ No newline at end of file + text "Cancel" From 3324f37faa31512f8a5a29e453379f1ba7e5fadd Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 16 Jul 2018 21:09:55 +0900 Subject: [PATCH 08/14] Cleanup in scenario1 --- tests/browsertests/scenario1.nim | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/browsertests/scenario1.nim b/tests/browsertests/scenario1.nim index 1674130..d5c2fe5 100644 --- a/tests/browsertests/scenario1.nim +++ b/tests/browsertests/scenario1.nim @@ -9,16 +9,13 @@ proc test*(session: Session, baseUrl: string) = # Sanity checks test "shows sign up": - with session: - checkText "#signup-btn", "Sign up" + session.checkText("#signup-btn", "Sign up") test "shows log in": - with session: - checkText "#login-btn", "Log in" + session.checkText("#login-btn", "Log in") test "is empty": - with session: - check "tr > td.thread-title", isNone + session.check("tr > td.thread-title", isNone) # Logging in test "can login/logout": @@ -29,7 +26,7 @@ proc test*(session: Session, baseUrl: string) = sendKeys "#login-form input[name='password']", "admin" sendKeys "#login-form input[name='password']", Key.Enter - wait(5000) + wait 5000 # Verify that the user menu has been initialised properly. click "#profile-btn" @@ -49,7 +46,7 @@ proc test*(session: Session, baseUrl: string) = sendKeys "#signup-form input[name='password']", "test" click "#signup-modal .create-account-btn" - wait(5000) + wait 5000 # Verify that the user menu has been initialised properly. click "#profile-btn" From f315be7361a3078c747f0783ab3fd680fc4676dd Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 16 Jul 2018 21:10:46 +0900 Subject: [PATCH 09/14] Add tests for like/delete thread --- tests/browsertests/threads.nim | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/browsertests/threads.nim b/tests/browsertests/threads.nim index 23ffce2..4a26148 100644 --- a/tests/browsertests/threads.nim +++ b/tests/browsertests/threads.nim @@ -60,4 +60,36 @@ proc test*(session: Session, baseUrl: string) = checkText ".original-post div.post-content", contentStr & modificationText + test "can like thread": + # logout admin and login to regular user + logout(session) + login(session, "user", "user") + + with session: + click titleStr, LinkTextSelector + wait() + + click ".post-buttons .like-button" + + checkText ".post-buttons .like-button .like-count", "1" + + logout(session) + session.navigate(baseUrl) + waitForLoad(session) + login(session, "admin", "admin") + + test "can delete thread": + with session: + click titleStr, LinkTextSelector + wait() + + click ".post-buttons .delete-button" + wait() + + # click delete confirmation + click "#delete-modal .delete-btn" + + # Make sure the forum post is gone + check titleStr, LinkTextSelector, isNone + logout(session) From b2fc4dfbe060eac87caec14bd340204704da09af Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Tue, 17 Jul 2018 12:50:23 +0900 Subject: [PATCH 10/14] Add license id --- src/frontend/signup.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/signup.nim b/src/frontend/signup.nim index 1a4b47a..6a422d6 100644 --- a/src/frontend/signup.nim +++ b/src/frontend/signup.nim @@ -89,7 +89,7 @@ when defined(js): p(class="license-text text-gray"): text "By registering, you agree to the " - a(href=makeUri("/about/license"), + a(id="license", href=makeUri("/about/license"), onClick=(ev: Event, n: VNode) => (state.shown = false; anchorCB(ev, n))): text "content license" From 0050ad42f5cb7971fd9b91b263b50b5736a2100d Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Tue, 17 Jul 2018 19:55:17 +0900 Subject: [PATCH 11/14] Try to appease travis --- tests/browsertests/common.nim | 7 ++++++- tests/browsertests/scenario1.nim | 2 +- tests/browsertests/threads.nim | 5 ++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/browsertests/common.nim b/tests/browsertests/common.nim index cb16831..340492c 100644 --- a/tests/browsertests/common.nim +++ b/tests/browsertests/common.nim @@ -44,6 +44,10 @@ template check*(session: Session, element: string, let el = session.findElement(element, strategy) check function(el) +template checkIsNone*(session: Session, element: string, strategy=CssSelector) = + let el = session.findElement(element, strategy) + check el.isNone() + template checkText*(session: Session, element, expectedValue: string) = let el = session.findElement(element) check el.isSome() @@ -70,8 +74,9 @@ proc wait*(session: Session, msTimeout: int) = proc logout*(session: Session) = with session: + wait(5000) click "#profile-btn" - click "#logout-btn" + click "#profile-btn #logout-btn" wait(5000) proc login*(session: Session, user, password: string) = diff --git a/tests/browsertests/scenario1.nim b/tests/browsertests/scenario1.nim index d5c2fe5..89dc76b 100644 --- a/tests/browsertests/scenario1.nim +++ b/tests/browsertests/scenario1.nim @@ -15,7 +15,7 @@ proc test*(session: Session, baseUrl: string) = session.checkText("#login-btn", "Log in") test "is empty": - session.check("tr > td.thread-title", isNone) + session.checkIsNone("tr > td.thread-title") # Logging in test "can login/logout": diff --git a/tests/browsertests/threads.nim b/tests/browsertests/threads.nim index 4a26148..5181b11 100644 --- a/tests/browsertests/threads.nim +++ b/tests/browsertests/threads.nim @@ -80,6 +80,7 @@ proc test*(session: Session, baseUrl: string) = test "can delete thread": with session: + wait() click titleStr, LinkTextSelector wait() @@ -90,6 +91,8 @@ proc test*(session: Session, baseUrl: string) = click "#delete-modal .delete-btn" # Make sure the forum post is gone - check titleStr, LinkTextSelector, isNone + checkIsNone titleStr, LinkTextSelector + session.navigate(baseUrl) + waitForLoad(session) logout(session) From c361fda523b4ce0fe9ea9f6c33ab5fae3e8badac Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Tue, 17 Jul 2018 22:29:51 +0900 Subject: [PATCH 12/14] Replace len check with assert --- src/setup_nimforum.nim | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/setup_nimforum.nim b/src/setup_nimforum.nim index 9c93080..3c5cf5b 100644 --- a/src/setup_nimforum.nim +++ b/src/setup_nimforum.nim @@ -24,15 +24,14 @@ proc backup(path: string, contents: Option[string]=none[string]()) = proc createUser(db: DbConn, user: tuple[username, password, email: string], rank: Rank) = + assert user.username.len != 0 + let salt = makeSalt() + let password = makePassword(user.password, salt) - if user.username.len != 0: - let salt = makeSalt() - let password = makePassword(user.password, salt) - - exec(db, sql""" - INSERT INTO person(name, password, email, salt, status, lastOnline) - VALUES (?, ?, ?, ?, ?, DATETIME('now')) - """, user.username, password, user.email, salt, $rank) + exec(db, sql""" + INSERT INTO person(name, password, email, salt, status, lastOnline) + VALUES (?, ?, ?, ?, ?, DATETIME('now')) + """, user.username, password, user.email, salt, $rank) proc initialiseDb(admin: tuple[username, password, email: string], filename="nimforum.db") = From 80558b6bfb5364c8745639b7e17b6f05d6df8ca8 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Tue, 17 Jul 2018 22:32:38 +0900 Subject: [PATCH 13/14] Make 5000 ms default wait --- tests/browsertests/common.nim | 11 ++++------- tests/browsertests/scenario1.nim | 4 ++-- tests/browsertests/threads.nim | 4 ++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/tests/browsertests/common.nim b/tests/browsertests/common.nim index 340492c..a2fb09b 100644 --- a/tests/browsertests/common.nim +++ b/tests/browsertests/common.nim @@ -66,18 +66,15 @@ proc waitForLoad*(session: Session, timeout=20000) = if waitTime > timeout: doAssert false, "Wait for load time exceeded" -proc wait*(session: Session) = - session.waitForLoad() - -proc wait*(session: Session, msTimeout: int) = +proc wait*(session: Session, msTimeout: int = 5000) = session.waitForLoad(msTimeout) proc logout*(session: Session) = with session: - wait(5000) + wait() click "#profile-btn" click "#profile-btn #logout-btn" - wait(5000) + wait() proc login*(session: Session, user, password: string) = with session: @@ -88,4 +85,4 @@ proc login*(session: Session, user, password: string) = sendKeys "#login-form input[name='password']", Key.Enter - wait(5000) + wait() diff --git a/tests/browsertests/scenario1.nim b/tests/browsertests/scenario1.nim index 89dc76b..f8efe48 100644 --- a/tests/browsertests/scenario1.nim +++ b/tests/browsertests/scenario1.nim @@ -26,7 +26,7 @@ proc test*(session: Session, baseUrl: string) = sendKeys "#login-form input[name='password']", "admin" sendKeys "#login-form input[name='password']", Key.Enter - wait 5000 + wait() # Verify that the user menu has been initialised properly. click "#profile-btn" @@ -46,7 +46,7 @@ proc test*(session: Session, baseUrl: string) = sendKeys "#signup-form input[name='password']", "test" click "#signup-modal .create-account-btn" - wait 5000 + wait() # Verify that the user menu has been initialised properly. click "#profile-btn" diff --git a/tests/browsertests/threads.nim b/tests/browsertests/threads.nim index 5181b11..a74d59e 100644 --- a/tests/browsertests/threads.nim +++ b/tests/browsertests/threads.nim @@ -80,7 +80,6 @@ proc test*(session: Session, baseUrl: string) = test "can delete thread": with session: - wait() click titleStr, LinkTextSelector wait() @@ -89,10 +88,11 @@ proc test*(session: Session, baseUrl: string) = # click delete confirmation click "#delete-modal .delete-btn" + wait() # Make sure the forum post is gone checkIsNone titleStr, LinkTextSelector session.navigate(baseUrl) - waitForLoad(session) + session.wait() logout(session) From b405f63a32ed5c99bf7efeeebf4c7f28fea0b121 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Tue, 17 Jul 2018 22:51:01 +0900 Subject: [PATCH 14/14] Separate user and admin tests --- tests/browsertests/scenario1.nim | 2 + tests/browsertests/threads.nim | 73 +++++++++++++++++++++----------- 2 files changed, 50 insertions(+), 25 deletions(-) diff --git a/tests/browsertests/scenario1.nim b/tests/browsertests/scenario1.nim index f8efe48..18d1bc7 100644 --- a/tests/browsertests/scenario1.nim +++ b/tests/browsertests/scenario1.nim @@ -54,4 +54,6 @@ proc test*(session: Session, baseUrl: string) = # close menu click "#profile-btn" + session.navigate(baseUrl) + session.wait() logout(session) diff --git a/tests/browsertests/threads.nim b/tests/browsertests/threads.nim index a74d59e..74729a3 100644 --- a/tests/browsertests/threads.nim +++ b/tests/browsertests/threads.nim @@ -4,31 +4,61 @@ import webdriver proc test*(session: Session, baseUrl: string) = let - titleStr = "This is a thread title!" - contentStr = "This is content" + userTitleStr = "This is a user thread!" + userContentStr = "A user has filled this out" - suite "thread tests": + adminTitleStr = "This is a thread title!" + adminContentStr = "This is content" + + suite "user thread tests": session.navigate(baseUrl) - waitForLoad(session) - login(session, "admin", "admin") + session.wait() + login(session, "user", "user") setup: session.navigate(baseUrl) - waitForLoad(session) + session.wait() test "can create thread": with session: click "#new-thread-btn" wait() - sendKeys "#thread-title", titleStr - sendKeys "#reply-textarea", contentStr + sendKeys "#thread-title", userTitleStr + sendKeys "#reply-textarea", userContentStr click "#create-thread-btn" wait() - checkText "#thread-title", titleStr - checkText ".original-post div.post-content", contentStr + checkText "#thread-title", userTitleStr + checkText ".original-post div.post-content", userContentStr + + session.navigate(baseUrl) + session.wait() + logout(session) + + suite "admin thread tests": + session.navigate(baseUrl) + session.wait() + login(session, "admin", "admin") + + setup: + session.navigate(baseUrl) + session.wait() + + test "can create thread": + with session: + click "#new-thread-btn" + wait() + + sendKeys "#thread-title", adminTitleStr + sendKeys "#reply-textarea", adminContentStr + + click "#create-thread-btn" + wait() + + checkText "#thread-title", adminTitleStr + checkText ".original-post div.post-content", adminContentStr test "try create duplicate thread": with session: @@ -36,8 +66,8 @@ proc test*(session: Session, baseUrl: string) = wait() ensureExists "#new-thread" - sendKeys "#thread-title", titleStr - sendKeys "#reply-textarea", contentStr + sendKeys "#thread-title", adminTitleStr + sendKeys "#reply-textarea", adminContentStr click "#create-thread-btn" @@ -48,7 +78,7 @@ proc test*(session: Session, baseUrl: string) = test "can edit post": let modificationText = " and I edited it!" with session: - click titleStr, LinkTextSelector + click adminTitleStr, LinkTextSelector wait() click ".post-buttons .edit-button" @@ -58,29 +88,22 @@ proc test*(session: Session, baseUrl: string) = click ".edit-buttons .save-button" wait() - checkText ".original-post div.post-content", contentStr & modificationText + checkText ".original-post div.post-content", adminContentStr & modificationText test "can like thread": - # logout admin and login to regular user - logout(session) - login(session, "user", "user") + # Try to like the user thread above with session: - click titleStr, LinkTextSelector + click userTitleStr, LinkTextSelector wait() click ".post-buttons .like-button" checkText ".post-buttons .like-button .like-count", "1" - logout(session) - session.navigate(baseUrl) - waitForLoad(session) - login(session, "admin", "admin") - test "can delete thread": with session: - click titleStr, LinkTextSelector + click adminTitleStr, LinkTextSelector wait() click ".post-buttons .delete-button" @@ -91,7 +114,7 @@ proc test*(session: Session, baseUrl: string) = wait() # Make sure the forum post is gone - checkIsNone titleStr, LinkTextSelector + checkIsNone adminTitleStr, LinkTextSelector session.navigate(baseUrl) session.wait()