nimforum/tests/browsertests/common.nim
Joey Yakimowich-Payne 5a4f44b4ee 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.
2020-02-17 08:53:30 +01:00

153 lines
4.6 KiB
Nim

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
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)
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.waitForElement(element, strategy)
el.get().click()
template sendKeys*(session: Session, element, keys: string) =
let el = session.waitForElement(element)
el.get().sendKeys(keys)
template clear*(session: Session, element: string) =
let el = session.waitForElement(element)
el.get().clear()
template sendKeys*(session: Session, element: string, keys: varargs[Key]) =
let el = session.waitForElement(element)
# focus
el.get().click()
for key in keys:
session.press(key)
template ensureExists*(session: Session, element: string, strategy=CssSelector) =
discard session.waitForElement(element, strategy)
template check*(session: Session, element: string, function: untyped) =
let el = session.waitForElement(element)
check function(el)
template check*(session: Session, element: string,
strategy: LocationStrategy, function: untyped) =
let el = session.waitForElement(element, strategy)
check function(el)
template checkIsNone*(session: Session, element: string, strategy=CssSelector) =
discard session.waitForElement(element, strategy, waitCondition=elementIsNone)
template checkText*(session: Session, element, expectedValue: string) =
let el = session.waitForElement(element)
check el.get().getText() == expectedValue
proc waitForElement*(
session: Session, selector: string, strategy=CssSelector,
timeout=20000, pollTime=50,
waitCondition=elementIsSome
): Option[Element] =
var waitTime = 0
when actionDelayMs > 0:
sleep(actionDelayMs)
while true:
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 setUserRank*(session: Session, baseUrl, user, rank: string) =
with session:
navigate(baseUrl & "profile/" & user)
click "#settings-tab"
click "#rank-field"
click("#rank-field option#rank-" & rank.toLowerAscii)
click "#save-btn"
proc logout*(session: Session) =
with session:
click "#profile-btn"
click "#profile-btn #logout-btn"
# Verify we have logged out by looking for the log in button.
ensureExists "#login-btn"
proc login*(session: Session, user, password: string) =
with session:
click "#login-btn"
clear "#login-form input[name='username']"
clear "#login-form input[name='password']"
sendKeys "#login-form input[name='username']", user
sendKeys "#login-form input[name='password']", password
sendKeys "#login-form input[name='password']", Key.Enter
# Verify that the user menu has been initialised properly.
click "#profile-btn"
checkText "#profile-btn #profile-name", user
click "#profile-btn"
proc register*(session: Session, user, password: string, verify = true) =
with session:
click "#signup-btn"
clear "#signup-form input[name='email']"
clear "#signup-form input[name='username']"
clear "#signup-form input[name='password']"
sendKeys "#signup-form input[name='email']", user & "@" & user & ".com"
sendKeys "#signup-form input[name='username']", user
sendKeys "#signup-form input[name='password']", password
click "#signup-modal .create-account-btn"
if verify:
with session:
# Verify that the user menu has been initialised properly.
click "#profile-btn"
checkText "#profile-btn #profile-name", user
# close menu
click "#profile-btn"
proc createThread*(session: Session, title, content: string) =
with session:
click "#new-thread-btn"
sendKeys "#thread-title", title
sendKeys "#reply-textarea", content
click "#create-thread-btn"
checkText "#thread-title .title-text", title
checkText ".original-post div.post-content", content