Speedup and simplify tests
This drastically speeds up tests and simplifies test writing by making it so that no explicit calls for waiting are needed. Elements that are queried for now implicitly waits for them to be available. On my machine, tests used to take 3-4 minutes to complete. Now they take ~1 minute to complete.
This commit is contained in:
parent
616c6eb100
commit
5a4f44b4ee
7 changed files with 40 additions and 83 deletions
|
|
@ -55,7 +55,7 @@ task blankdb, "Creates a blank DB":
|
|||
|
||||
task test, "Runs tester":
|
||||
exec "nimble c -y src/forum.nim"
|
||||
exec "nimble c -y -r tests/browsertester"
|
||||
exec "nimble c -y -r -d:actionDelayMs=0 tests/browsertester"
|
||||
|
||||
task fasttest, "Runs tester without recompiling backend":
|
||||
exec "nimble c -r tests/browsertester"
|
||||
exec "nimble c -r -d:actionDelayMs=0 tests/browsertester"
|
||||
|
|
|
|||
|
|
@ -149,4 +149,4 @@ proc render(): VNode =
|
|||
])
|
||||
|
||||
window.onPopState = onPopState
|
||||
setRenderer render
|
||||
setRenderer render
|
||||
|
|
@ -18,25 +18,21 @@ proc categoriesUserTests(session: Session, baseUrl: string) =
|
|||
|
||||
with session:
|
||||
navigate baseUrl
|
||||
wait()
|
||||
login "user", "user"
|
||||
|
||||
setup:
|
||||
with session:
|
||||
navigate baseUrl
|
||||
wait()
|
||||
|
||||
test "no category add available":
|
||||
with session:
|
||||
click "#new-thread-btn"
|
||||
wait()
|
||||
|
||||
checkIsNone "#add-category"
|
||||
|
||||
test "can create category thread":
|
||||
with session:
|
||||
click "#new-thread-btn"
|
||||
wait()
|
||||
|
||||
sendKeys "#thread-title", title
|
||||
|
||||
|
|
@ -45,12 +41,10 @@ proc categoriesUserTests(session: Session, baseUrl: string) =
|
|||
sendKeys "#reply-textarea", content
|
||||
|
||||
click "#create-thread-btn"
|
||||
wait()
|
||||
|
||||
checkText "#thread-title .category", "Fun"
|
||||
|
||||
navigate baseUrl
|
||||
wait()
|
||||
|
||||
ensureExists title, LinkTextSelector
|
||||
|
||||
|
|
@ -65,18 +59,15 @@ proc categoriesAdminTests(session: Session, baseUrl: string) =
|
|||
suite "admin tests":
|
||||
with session:
|
||||
navigate baseUrl
|
||||
wait()
|
||||
login "admin", "admin"
|
||||
|
||||
test "can create category":
|
||||
with session:
|
||||
click "#new-thread-btn"
|
||||
wait()
|
||||
|
||||
ensureExists "#add-category"
|
||||
|
||||
click "#add-category .plus-btn"
|
||||
wait()
|
||||
|
||||
clear "#add-category input[name='name']"
|
||||
clear "#add-category input[name='color']"
|
||||
|
|
@ -88,7 +79,6 @@ proc categoriesAdminTests(session: Session, baseUrl: string) =
|
|||
sendKeys "#add-category input[name='description']", description
|
||||
|
||||
click "#add-category #add-category-btn"
|
||||
wait()
|
||||
|
||||
checkText "#category-selection .selected-category", name
|
||||
|
||||
|
|
@ -96,10 +86,8 @@ proc categoriesAdminTests(session: Session, baseUrl: string) =
|
|||
|
||||
proc test*(session: Session, baseUrl: string) =
|
||||
session.navigate(baseUrl)
|
||||
session.wait()
|
||||
|
||||
categoriesUserTests(session, baseUrl)
|
||||
categoriesAdminTests(session, baseUrl)
|
||||
|
||||
session.navigate(baseUrl)
|
||||
session.wait()
|
||||
session.navigate(baseUrl)
|
||||
|
|
@ -2,6 +2,9 @@ import os, options, unittest, strutils
|
|||
import webdriver
|
||||
import macros
|
||||
|
||||
const actionDelayMs {.intdefine.} = 0
|
||||
## Inserts a delay in milliseconds between automated actions. Useful for debugging tests
|
||||
|
||||
macro with*(obj: typed, code: untyped): untyped =
|
||||
## Execute a set of statements with an object
|
||||
expectKind code, nnkStmtList
|
||||
|
|
@ -12,24 +15,28 @@ macro with*(obj: typed, code: untyped): untyped =
|
|||
if result[i].kind in {nnkCommand, nnkCall}:
|
||||
result[i].insert(1, obj)
|
||||
|
||||
proc elementIsSome(element: Option[Element]): bool =
|
||||
return element.isSome
|
||||
|
||||
proc elementIsNone(element: Option[Element]): bool =
|
||||
return element.isNone
|
||||
|
||||
proc waitForElement*(session: Session, selector: string, strategy=CssSelector, timeout=20000, pollTime=50, waitCondition=elementIsSome): Option[Element]
|
||||
|
||||
template click*(session: Session, element: string, strategy=CssSelector) =
|
||||
let el = session.findElement(element, strategy)
|
||||
check el.isSome()
|
||||
let el = session.waitForElement(element, strategy)
|
||||
el.get().click()
|
||||
|
||||
template sendKeys*(session: Session, element, keys: string) =
|
||||
let el = session.findElement(element)
|
||||
check el.isSome()
|
||||
let el = session.waitForElement(element)
|
||||
el.get().sendKeys(keys)
|
||||
|
||||
template clear*(session: Session, element: string) =
|
||||
let el = session.findElement(element)
|
||||
check el.isSome()
|
||||
let el = session.waitForElement(element)
|
||||
el.get().clear()
|
||||
|
||||
template sendKeys*(session: Session, element: string, keys: varargs[Key]) =
|
||||
let el = session.findElement(element)
|
||||
check el.isSome()
|
||||
let el = session.waitForElement(element)
|
||||
|
||||
# focus
|
||||
el.get().click()
|
||||
|
|
@ -37,47 +44,47 @@ template sendKeys*(session: Session, element: string, keys: varargs[Key]) =
|
|||
session.press(key)
|
||||
|
||||
template ensureExists*(session: Session, element: string, strategy=CssSelector) =
|
||||
let el = session.findElement(element, strategy)
|
||||
check el.isSome()
|
||||
discard session.waitForElement(element, strategy)
|
||||
|
||||
template check*(session: Session, element: string, function: untyped) =
|
||||
let el = session.findElement(element)
|
||||
let el = session.waitForElement(element)
|
||||
check function(el)
|
||||
|
||||
template check*(session: Session, element: string,
|
||||
strategy: LocationStrategy, function: untyped) =
|
||||
let el = session.findElement(element, strategy)
|
||||
let el = session.waitForElement(element, strategy)
|
||||
check function(el)
|
||||
|
||||
template checkIsNone*(session: Session, element: string, strategy=CssSelector) =
|
||||
let el = session.findElement(element, strategy)
|
||||
check el.isNone()
|
||||
discard session.waitForElement(element, strategy, waitCondition=elementIsNone)
|
||||
|
||||
template checkText*(session: Session, element, expectedValue: string) =
|
||||
let el = session.findElement(element)
|
||||
check el.isSome()
|
||||
let el = session.waitForElement(element)
|
||||
check el.get().getText() == expectedValue
|
||||
|
||||
proc waitForLoad*(session: Session, timeout=20000) =
|
||||
proc waitForElement*(
|
||||
session: Session, selector: string, strategy=CssSelector,
|
||||
timeout=20000, pollTime=50,
|
||||
waitCondition=elementIsSome
|
||||
): Option[Element] =
|
||||
var waitTime = 0
|
||||
sleep(2000)
|
||||
|
||||
when actionDelayMs > 0:
|
||||
sleep(actionDelayMs)
|
||||
|
||||
while true:
|
||||
let loading = session.findElement(".loading")
|
||||
if loading.isNone: return
|
||||
sleep(1000)
|
||||
waitTime += 1000
|
||||
let loading = session.findElement(selector, strategy)
|
||||
if waitCondition(loading):
|
||||
return loading
|
||||
sleep(pollTime)
|
||||
waitTime += pollTime
|
||||
|
||||
if waitTime > timeout:
|
||||
doAssert false, "Wait for load time exceeded"
|
||||
|
||||
proc wait*(session: Session, msTimeout: int = 5000) =
|
||||
session.waitForLoad(msTimeout)
|
||||
|
||||
proc setUserRank*(session: Session, baseUrl, user, rank: string) =
|
||||
with session:
|
||||
navigate(baseUrl & "profile/" & user)
|
||||
wait()
|
||||
|
||||
click "#settings-tab"
|
||||
|
||||
|
|
@ -85,13 +92,11 @@ proc setUserRank*(session: Session, baseUrl, user, rank: string) =
|
|||
click("#rank-field option#rank-" & rank.toLowerAscii)
|
||||
|
||||
click "#save-btn"
|
||||
wait()
|
||||
|
||||
proc logout*(session: Session) =
|
||||
with session:
|
||||
click "#profile-btn"
|
||||
click "#profile-btn #logout-btn"
|
||||
wait()
|
||||
|
||||
# Verify we have logged out by looking for the log in button.
|
||||
ensureExists "#login-btn"
|
||||
|
|
@ -108,8 +113,6 @@ proc login*(session: Session, user, password: string) =
|
|||
|
||||
sendKeys "#login-form input[name='password']", Key.Enter
|
||||
|
||||
wait()
|
||||
|
||||
# Verify that the user menu has been initialised properly.
|
||||
click "#profile-btn"
|
||||
checkText "#profile-btn #profile-name", user
|
||||
|
|
@ -128,7 +131,6 @@ proc register*(session: Session, user, password: string, verify = true) =
|
|||
sendKeys "#signup-form input[name='password']", password
|
||||
|
||||
click "#signup-modal .create-account-btn"
|
||||
wait()
|
||||
|
||||
if verify:
|
||||
with session:
|
||||
|
|
@ -141,13 +143,11 @@ proc register*(session: Session, user, password: string, verify = true) =
|
|||
proc createThread*(session: Session, title, content: string) =
|
||||
with session:
|
||||
click "#new-thread-btn"
|
||||
wait()
|
||||
|
||||
sendKeys "#thread-title", title
|
||||
sendKeys "#reply-textarea", content
|
||||
|
||||
click "#create-thread-btn"
|
||||
wait()
|
||||
|
||||
checkText "#thread-title .title-text", title
|
||||
checkText ".original-post div.post-content", content
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ import webdriver
|
|||
proc test*(session: Session, baseUrl: string) =
|
||||
session.navigate(baseUrl)
|
||||
|
||||
waitForLoad(session)
|
||||
|
||||
test "can see banned posts":
|
||||
with session:
|
||||
register("issue181", "issue181")
|
||||
|
|
@ -19,7 +17,6 @@ proc test*(session: Session, baseUrl: string) =
|
|||
|
||||
login("issue181", "issue181")
|
||||
navigate(baseUrl)
|
||||
wait()
|
||||
|
||||
const title = "Testing issue 181."
|
||||
createThread(title, "Test for issue #181")
|
||||
|
|
@ -33,7 +30,6 @@ proc test*(session: Session, baseUrl: string) =
|
|||
|
||||
# Make sure the banned user's thread is still visible.
|
||||
navigate(baseUrl)
|
||||
wait()
|
||||
ensureExists("tr.banned")
|
||||
checkText("tr.banned .thread-title > a", title)
|
||||
logout()
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ import webdriver
|
|||
proc test*(session: Session, baseUrl: string) =
|
||||
session.navigate(baseUrl)
|
||||
|
||||
waitForLoad(session)
|
||||
|
||||
# Sanity checks
|
||||
test "shows sign up":
|
||||
session.checkText("#signup-btn", "Sign up")
|
||||
|
|
@ -38,10 +36,8 @@ proc test*(session: Session, baseUrl: string) =
|
|||
logout()
|
||||
|
||||
navigate baseUrl
|
||||
wait()
|
||||
|
||||
register "TEst1", "test1", verify = false
|
||||
|
||||
ensureExists "#signup-form .has-error"
|
||||
navigate baseUrl
|
||||
wait()
|
||||
navigate baseUrl
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import unittest, options, os, common
|
||||
import unittest, options, common
|
||||
|
||||
import webdriver
|
||||
|
||||
|
|
@ -27,18 +27,15 @@ proc userTests(session: Session, baseUrl: string) =
|
|||
|
||||
setup:
|
||||
session.navigate(baseUrl)
|
||||
session.wait()
|
||||
|
||||
test "can create thread":
|
||||
with session:
|
||||
click "#new-thread-btn"
|
||||
wait()
|
||||
|
||||
sendKeys "#thread-title", userTitleStr
|
||||
sendKeys "#reply-textarea", userContentStr
|
||||
|
||||
click "#create-thread-btn"
|
||||
wait()
|
||||
|
||||
checkText "#thread-title .title-text", userTitleStr
|
||||
checkText ".original-post div.post-content", userContentStr
|
||||
|
|
@ -50,7 +47,6 @@ proc anonymousTests(session: Session, baseUrl: string) =
|
|||
suite "anonymous user tests":
|
||||
with session:
|
||||
navigate baseUrl
|
||||
wait()
|
||||
|
||||
test "can view banned thread":
|
||||
with session:
|
||||
|
|
@ -58,25 +54,21 @@ proc anonymousTests(session: Session, baseUrl: string) =
|
|||
|
||||
with session:
|
||||
navigate baseUrl
|
||||
wait()
|
||||
|
||||
proc bannedTests(session: Session, baseUrl: string) =
|
||||
suite "banned user thread tests":
|
||||
with session:
|
||||
navigate baseUrl
|
||||
wait()
|
||||
login "banned", "banned"
|
||||
|
||||
test "can't start thread":
|
||||
with session:
|
||||
click "#new-thread-btn"
|
||||
wait()
|
||||
|
||||
sendKeys "#thread-title", "test"
|
||||
sendKeys "#reply-textarea", "test"
|
||||
|
||||
click "#create-thread-btn"
|
||||
wait()
|
||||
|
||||
ensureExists "#new-thread p.text-error"
|
||||
|
||||
|
|
@ -88,7 +80,6 @@ proc adminTests(session: Session, baseUrl: string) =
|
|||
|
||||
setup:
|
||||
session.navigate(baseUrl)
|
||||
session.wait()
|
||||
|
||||
test "can view banned thread":
|
||||
with session:
|
||||
|
|
@ -97,13 +88,11 @@ proc adminTests(session: Session, baseUrl: string) =
|
|||
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 .title-text", adminTitleStr
|
||||
checkText ".original-post div.post-content", adminContentStr
|
||||
|
|
@ -111,7 +100,6 @@ proc adminTests(session: Session, baseUrl: string) =
|
|||
test "try create duplicate thread":
|
||||
with session:
|
||||
click "#new-thread-btn"
|
||||
wait()
|
||||
ensureExists "#new-thread"
|
||||
|
||||
sendKeys "#thread-title", adminTitleStr
|
||||
|
|
@ -119,22 +107,17 @@ proc adminTests(session: Session, baseUrl: string) =
|
|||
|
||||
click "#create-thread-btn"
|
||||
|
||||
wait()
|
||||
|
||||
ensureExists "#new-thread p.text-error"
|
||||
|
||||
test "can edit post":
|
||||
let modificationText = " and I edited it!"
|
||||
with session:
|
||||
click adminTitleStr, LinkTextSelector
|
||||
wait()
|
||||
|
||||
click ".post-buttons .edit-button"
|
||||
wait()
|
||||
|
||||
sendKeys ".original-post #reply-textarea", modificationText
|
||||
click ".edit-buttons .save-button"
|
||||
wait()
|
||||
|
||||
checkText ".original-post div.post-content", adminContentStr & modificationText
|
||||
|
||||
|
|
@ -143,7 +126,6 @@ proc adminTests(session: Session, baseUrl: string) =
|
|||
|
||||
with session:
|
||||
click userTitleStr, LinkTextSelector
|
||||
wait()
|
||||
|
||||
click ".post-buttons .like-button"
|
||||
|
||||
|
|
@ -152,14 +134,11 @@ proc adminTests(session: Session, baseUrl: string) =
|
|||
test "can delete thread":
|
||||
with session:
|
||||
click adminTitleStr, LinkTextSelector
|
||||
wait()
|
||||
|
||||
click ".post-buttons .delete-button"
|
||||
wait()
|
||||
|
||||
# click delete confirmation
|
||||
click "#delete-modal .delete-btn"
|
||||
wait()
|
||||
|
||||
# Make sure the forum post is gone
|
||||
checkIsNone adminTitleStr, LinkTextSelector
|
||||
|
|
@ -168,7 +147,6 @@ proc adminTests(session: Session, baseUrl: string) =
|
|||
|
||||
proc test*(session: Session, baseUrl: string) =
|
||||
session.navigate(baseUrl)
|
||||
session.wait()
|
||||
|
||||
userTests(session, baseUrl)
|
||||
|
||||
|
|
@ -180,5 +158,4 @@ proc test*(session: Session, baseUrl: string) =
|
|||
|
||||
unBanUser(session, baseUrl)
|
||||
|
||||
session.navigate(baseUrl)
|
||||
session.wait()
|
||||
session.navigate(baseUrl)
|
||||
Loading…
Add table
Add a link
Reference in a new issue