Initial commit: nimforum with BaraDB backend
- Replaced SQLite with BaraDB via TCP wire protocol - Added baradb_client.nim and baradb_sqlite.nim adapter - Renamed SQL keywords: status->usrStatus, key->sessionKey, like->postLike - Added NOW() support for datetime defaults - Switched Jester to asynchttpserver (-d:useStdLib) to avoid thread/GC issues - Frontend built and favicon added
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
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
|
||||
|
||||
template checkCompiles(res, default) =
|
||||
when compiles(res):
|
||||
res
|
||||
else:
|
||||
default
|
||||
|
||||
result = code.copy
|
||||
|
||||
# Simply inject obj into call
|
||||
for i in 0 ..< result.len:
|
||||
if result[i].kind in {nnkCommand, nnkCall}:
|
||||
result[i].insert(1, obj)
|
||||
|
||||
result = getAst(checkCompiles(result, code))
|
||||
|
||||
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: proc(element: Option[Element]): bool = elementIsSome): Option[Element]
|
||||
|
||||
proc click*(session: Session, element: string, strategy=CssSelector) =
|
||||
let el = session.waitForElement(element, strategy)
|
||||
el.get().click()
|
||||
|
||||
proc sendKeys*(session: Session, element, keys: string) =
|
||||
let el = session.waitForElement(element)
|
||||
el.get().sendKeys(keys)
|
||||
|
||||
proc clear*(session: Session, element: string) =
|
||||
let el = session.waitForElement(element)
|
||||
el.get().clear()
|
||||
|
||||
proc sendKeys*(session: Session, element: string, keys: varargs[Key]) =
|
||||
let el = session.waitForElement(element)
|
||||
|
||||
# focus
|
||||
el.get().click()
|
||||
for key in keys:
|
||||
session.press(key)
|
||||
|
||||
proc 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)
|
||||
|
||||
proc setColor*(session: Session, element, color: string, strategy=CssSelector) =
|
||||
let el = session.waitForElement(element, strategy)
|
||||
discard session.execute("arguments[0].setAttribute('value', '" & color & "')", el.get())
|
||||
|
||||
proc 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: proc(element: Option[Element]): bool = elementIsSome
|
||||
): Option[Element] =
|
||||
var waitTime = 0
|
||||
|
||||
when actionDelayMs > 0:
|
||||
sleep(actionDelayMs)
|
||||
|
||||
while true:
|
||||
try:
|
||||
let loading = session.findElement(selector, strategy)
|
||||
if waitCondition(loading):
|
||||
return loading
|
||||
finally:
|
||||
discard
|
||||
sleep(pollTime)
|
||||
waitTime += pollTime
|
||||
|
||||
if waitTime > timeout:
|
||||
doAssert false, "Wait for load time exceeded"
|
||||
|
||||
proc waitForElements*(
|
||||
session: Session, selector: string, strategy=CssSelector,
|
||||
timeout=20000, pollTime=50
|
||||
): seq[Element] =
|
||||
var waitTime = 0
|
||||
|
||||
when actionDelayMs > 0:
|
||||
sleep(actionDelayMs)
|
||||
|
||||
while true:
|
||||
let loading = session.findElements(selector, strategy)
|
||||
if loading.len > 0:
|
||||
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
|
||||
Reference in New Issue
Block a user