Implements web driver test suite and simple test.
This commit is contained in:
parent
770b5cddab
commit
c6ed9e80c9
8 changed files with 183 additions and 29 deletions
|
|
@ -20,13 +20,33 @@ requires "sass"
|
||||||
|
|
||||||
requires "karax"
|
requires "karax"
|
||||||
|
|
||||||
|
requires "webdriver"
|
||||||
|
|
||||||
# Tasks
|
# Tasks
|
||||||
|
|
||||||
task backend, "Runs the forum backend":
|
task backend, "Compiles and runs the forum backend":
|
||||||
exec "nimble c src/forum.nim"
|
exec "nimble c src/forum.nim"
|
||||||
exec "./src/forum"
|
exec "./src/forum"
|
||||||
|
|
||||||
|
task runbackend, "Runs the forum backend":
|
||||||
|
exec "./src/forum"
|
||||||
|
|
||||||
task frontend, "Builds the necessary JS frontend":
|
task frontend, "Builds the necessary JS frontend":
|
||||||
exec "nimble js src/frontend/forum.nim"
|
exec "nimble js src/frontend/forum.nim"
|
||||||
mkDir "public/js"
|
mkDir "public/js"
|
||||||
cpFile "src/frontend/nimcache/forum.js", "public/js/forum.js"
|
cpFile "src/frontend/nimcache/forum.js", "public/js/forum.js"
|
||||||
|
|
||||||
|
task testdb, "Creates a test DB":
|
||||||
|
exec "nimble c src/setup_nimforum"
|
||||||
|
exec "./src/setup_nimforum --test"
|
||||||
|
|
||||||
|
task devdb, "Creates a test DB":
|
||||||
|
exec "nimble c src/setup_nimforum"
|
||||||
|
exec "./src/setup_nimforum --dev"
|
||||||
|
|
||||||
|
task test, "Runs tester":
|
||||||
|
exec "nimble c src/forum.nim"
|
||||||
|
exec "nimble c -r tests/browsertester"
|
||||||
|
|
||||||
|
task fasttest, "Runs tester without recompiling backend":
|
||||||
|
exec "nimble c -r tests/browsertester"
|
||||||
|
|
@ -856,10 +856,6 @@ proc prependRe(s: string): string =
|
||||||
|
|
||||||
proc initialise() =
|
proc initialise() =
|
||||||
randomize()
|
randomize()
|
||||||
db = open(connection="nimforum.db", user="postgres", password="",
|
|
||||||
database="nimforum")
|
|
||||||
isFTSAvailable = db.getAllRows(sql("SELECT name FROM sqlite_master WHERE " &
|
|
||||||
"type='table' AND name='post_fts'")).len == 1
|
|
||||||
|
|
||||||
config = loadConfig()
|
config = loadConfig()
|
||||||
if len(config.recaptchaSecretKey) > 0 and len(config.recaptchaSiteKey) > 0:
|
if len(config.recaptchaSecretKey) > 0 and len(config.recaptchaSiteKey) > 0:
|
||||||
|
|
@ -868,6 +864,11 @@ proc initialise() =
|
||||||
doAssert config.isDev, "Recaptcha required for production!"
|
doAssert config.isDev, "Recaptcha required for production!"
|
||||||
echo("[WARNING] No recaptcha secret key specified.")
|
echo("[WARNING] No recaptcha secret key specified.")
|
||||||
|
|
||||||
|
db = open(connection=config.dbPath, user="", password="",
|
||||||
|
database="nimforum")
|
||||||
|
isFTSAvailable = db.getAllRows(sql("SELECT name FROM sqlite_master WHERE " &
|
||||||
|
"type='table' AND name='post_fts'")).len == 1
|
||||||
|
|
||||||
let cssLoc = "public" / "css"
|
let cssLoc = "public" / "css"
|
||||||
if not existsFile(cssLoc / "nimforum.css"):
|
if not existsFile(cssLoc / "nimforum.css"):
|
||||||
sass.compileFile(cssLoc / "nimforum.scss", cssLoc / "nimforum.css")
|
sass.compileFile(cssLoc / "nimforum.scss", cssLoc / "nimforum.css")
|
||||||
|
|
|
||||||
|
|
@ -93,11 +93,11 @@ when defined(js):
|
||||||
if state.loading:
|
if state.loading:
|
||||||
tdiv(class="loading")
|
tdiv(class="loading")
|
||||||
elif user.isNone:
|
elif user.isNone:
|
||||||
button(class="btn btn-primary btn-sm",
|
button(id="signup-btn", class="btn btn-primary btn-sm",
|
||||||
onClick=(e: Event, n: VNode) => state.signupModal.show()):
|
onClick=(e: Event, n: VNode) => state.signupModal.show()):
|
||||||
italic(class="fas fa-user-plus")
|
italic(class="fas fa-user-plus")
|
||||||
text " Sign up"
|
text " Sign up"
|
||||||
button(class="btn btn-primary btn-sm",
|
button(id="login-btn", class="btn btn-primary btn-sm",
|
||||||
onClick=(e: Event, n: VNode) => state.loginModal.show()):
|
onClick=(e: Event, n: VNode) => state.loginModal.show()):
|
||||||
italic(class="fas fa-sign-in-alt")
|
italic(class="fas fa-sign-in-alt")
|
||||||
text " Log in"
|
text " Log in"
|
||||||
|
|
|
||||||
|
|
@ -7,21 +7,30 @@
|
||||||
#
|
#
|
||||||
# Script to initialise the nimforum.
|
# Script to initialise the nimforum.
|
||||||
|
|
||||||
import strutils, db_sqlite, os, times, json
|
import strutils, db_sqlite, os, times, json, options
|
||||||
|
|
||||||
import auth, frontend/user
|
import auth, frontend/user
|
||||||
|
|
||||||
proc backup(path: string) =
|
proc backup(path: string, contents: Option[string]=none[string]()) =
|
||||||
if existsFile(path):
|
if existsFile(path):
|
||||||
|
if contents.isSome() and readFile(path) == contents.get():
|
||||||
|
# Don't backup if the files are equivalent.
|
||||||
|
echo("Not backing up because new file is the same.")
|
||||||
|
return
|
||||||
|
|
||||||
let backupPath = path & "." & $getTime().toUnix()
|
let backupPath = path & "." & $getTime().toUnix()
|
||||||
echo(path, " already exists. Moving to ", backupPath)
|
echo(path, " already exists. Moving to ", backupPath)
|
||||||
moveFile(path, backupPath)
|
moveFile(path, backupPath)
|
||||||
|
|
||||||
proc initialiseDb(admin: tuple[username, password, email: string]) =
|
proc initialiseDb(admin: tuple[username, password, email: string],
|
||||||
let path = getCurrentDir() / "nimforum.db"
|
filename="nimforum.db") =
|
||||||
backup(path)
|
let path = getCurrentDir() / filename
|
||||||
|
if "-dev" notin filename and "-test" notin filename:
|
||||||
|
backup(path)
|
||||||
|
|
||||||
var db = open(connection="nimforum.db", user="", password="",
|
removeFile(path)
|
||||||
|
|
||||||
|
var db = open(connection=path, user="", password="",
|
||||||
database="nimforum")
|
database="nimforum")
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -198,10 +207,10 @@ proc initialiseConfig(
|
||||||
name, hostname: string,
|
name, hostname: string,
|
||||||
recaptcha: tuple[siteKey, secretKey: string],
|
recaptcha: tuple[siteKey, secretKey: string],
|
||||||
smtp: tuple[address, user, password: string],
|
smtp: tuple[address, user, password: string],
|
||||||
isDev: bool
|
isDev: bool,
|
||||||
|
dbPath: string
|
||||||
) =
|
) =
|
||||||
let path = getCurrentDir() / "forum.json"
|
let path = getCurrentDir() / "forum.json"
|
||||||
backup(path)
|
|
||||||
|
|
||||||
var j = %{
|
var j = %{
|
||||||
"name": %name,
|
"name": %name,
|
||||||
|
|
@ -211,23 +220,47 @@ proc initialiseConfig(
|
||||||
"smtpAddress": %smtp.address,
|
"smtpAddress": %smtp.address,
|
||||||
"smtpUser": %smtp.user,
|
"smtpUser": %smtp.user,
|
||||||
"smtpPassword": %smtp.password,
|
"smtpPassword": %smtp.password,
|
||||||
"isDev": %isDev
|
"isDev": %isDev,
|
||||||
|
"dbPath": %dbPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
backup(path, some($j))
|
||||||
writeFile(path, $j)
|
writeFile(path, $j)
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
if paramCount() > 0 and paramStr(1) == "--dev":
|
if paramCount() > 0:
|
||||||
echo("Initialising nimforum for development...")
|
case paramStr(1)
|
||||||
initialiseConfig(
|
of "--dev":
|
||||||
"Development Forum",
|
let dbPath = "nimforum-dev.db"
|
||||||
"localhost.local",
|
echo("Initialising nimforum for development...")
|
||||||
recaptcha=("", ""),
|
initialiseConfig(
|
||||||
smtp=("", "", ""),
|
"Development Forum",
|
||||||
isDev=true
|
"localhost.local",
|
||||||
)
|
recaptcha=("", ""),
|
||||||
|
smtp=("", "", ""),
|
||||||
|
isDev=true,
|
||||||
|
dbPath
|
||||||
|
)
|
||||||
|
|
||||||
initialiseDb(
|
initialiseDb(
|
||||||
admin=("admin", "admin", "admin@localhost.local")
|
admin=("admin", "admin", "admin@localhost.local"),
|
||||||
)
|
dbPath
|
||||||
|
)
|
||||||
|
of "--test":
|
||||||
|
let dbPath = "nimforum-test.db"
|
||||||
|
echo("Initialising nimforum for testing...")
|
||||||
|
initialiseConfig(
|
||||||
|
"Test Forum",
|
||||||
|
"localhost.local",
|
||||||
|
recaptcha=("", ""),
|
||||||
|
smtp=("", "", ""),
|
||||||
|
isDev=true,
|
||||||
|
dbPath
|
||||||
|
)
|
||||||
|
|
||||||
|
initialiseDb(
|
||||||
|
admin=("admin", "admin", "admin@localhost.local"),
|
||||||
|
dbPath
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
quit("--dev|--test")
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ type
|
||||||
recaptchaSecretKey*: string
|
recaptchaSecretKey*: string
|
||||||
recaptchaSiteKey*: string
|
recaptchaSiteKey*: string
|
||||||
isDev*: bool
|
isDev*: bool
|
||||||
|
dbPath*: string
|
||||||
|
|
||||||
var docConfig: StringTableRef
|
var docConfig: StringTableRef
|
||||||
|
|
||||||
|
|
@ -45,6 +46,7 @@ proc loadConfig*(filename = getCurrentDir() / "forum.json"): Config =
|
||||||
result.recaptchaSecretKey = root{"recaptchaSecretKey"}.getStr("")
|
result.recaptchaSecretKey = root{"recaptchaSecretKey"}.getStr("")
|
||||||
result.recaptchaSiteKey = root{"recaptchaSiteKey"}.getStr("")
|
result.recaptchaSiteKey = root{"recaptchaSiteKey"}.getStr("")
|
||||||
result.isDev = root{"isDev"}.getBool()
|
result.isDev = root{"isDev"}.getBool()
|
||||||
|
result.dbPath = root{"dbPath"}.getStr("nimforum.db")
|
||||||
except:
|
except:
|
||||||
echo("[WARNING] Couldn't read config file: ", filename)
|
echo("[WARNING] Couldn't read config file: ", filename)
|
||||||
|
|
||||||
|
|
|
||||||
68
tests/browsertester.nim
Normal file
68
tests/browsertester.nim
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
import options, osproc, streams, threadpool, os, strformat, httpclient
|
||||||
|
|
||||||
|
import webdriver
|
||||||
|
|
||||||
|
proc runProcess(cmd: string) =
|
||||||
|
let p = startProcess(
|
||||||
|
cmd,
|
||||||
|
options={
|
||||||
|
poStdErrToStdOut,
|
||||||
|
poEvalCommand
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
let o = p.outputStream
|
||||||
|
while p.running and (not o.atEnd):
|
||||||
|
echo cmd.substr(0, 10), ": ", o.readLine()
|
||||||
|
|
||||||
|
p.close()
|
||||||
|
|
||||||
|
const backend = "forum"
|
||||||
|
const port = 5000
|
||||||
|
const baseUrl = "http://localhost:" & $port & "/"
|
||||||
|
template withBackend(body: untyped): untyped =
|
||||||
|
## Starts a new backend instance with a fresh DB.
|
||||||
|
doAssert(execCmd("nimble testdb") == QuitSuccess)
|
||||||
|
|
||||||
|
spawn runProcess("nimble runbackend")
|
||||||
|
defer:
|
||||||
|
discard execCmd("killall " & backend)
|
||||||
|
|
||||||
|
echo("Waiting for server...")
|
||||||
|
var success = false
|
||||||
|
for i in 0..5:
|
||||||
|
sleep(5000)
|
||||||
|
try:
|
||||||
|
let client = newHttpClient()
|
||||||
|
doAssert client.getContent(baseUrl).len > 0
|
||||||
|
success = true
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
echo("Failed to getContent")
|
||||||
|
|
||||||
|
doAssert success
|
||||||
|
|
||||||
|
body
|
||||||
|
|
||||||
|
import browsertests/scenario1
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
spawn runProcess("geckodriver -p 4444 --log config")
|
||||||
|
defer:
|
||||||
|
discard execCmd("killall geckodriver")
|
||||||
|
|
||||||
|
doAssert(execCmd("nimble frontend") == QuitSuccess)
|
||||||
|
echo("Waiting for geckodriver to startup...")
|
||||||
|
sleep(5000)
|
||||||
|
|
||||||
|
try:
|
||||||
|
let driver = newWebDriver()
|
||||||
|
let session = driver.createSession()
|
||||||
|
|
||||||
|
withBackend:
|
||||||
|
scenario1.test(session, baseUrl)
|
||||||
|
|
||||||
|
session.close()
|
||||||
|
except:
|
||||||
|
sleep(10000) # See if we can grab any more output.
|
||||||
|
raise
|
||||||
1
tests/browsertester.nims
Normal file
1
tests/browsertester.nims
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
--threads:on
|
||||||
29
tests/browsertests/scenario1.nim
Normal file
29
tests/browsertests/scenario1.nim
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import unittest, options, os
|
||||||
|
|
||||||
|
import webdriver
|
||||||
|
|
||||||
|
proc waitForLoad(session: Session) =
|
||||||
|
sleep(2000)
|
||||||
|
|
||||||
|
while true:
|
||||||
|
let loading = session.findElement(".loading")
|
||||||
|
if loading.isNone: return
|
||||||
|
sleep(1000)
|
||||||
|
|
||||||
|
proc test*(session: Session, baseUrl: string) =
|
||||||
|
session.navigate(baseUrl)
|
||||||
|
|
||||||
|
waitForLoad(session)
|
||||||
|
|
||||||
|
# Sanity checks
|
||||||
|
test "shows sign up":
|
||||||
|
let signUp = session.findElement("#signup-btn")
|
||||||
|
check signUp.get().getText() == "Sign up"
|
||||||
|
|
||||||
|
test "shows log in":
|
||||||
|
let signUp = session.findElement("#login-btn")
|
||||||
|
check signUp.get().getText() == "Log in"
|
||||||
|
|
||||||
|
test "is empty":
|
||||||
|
let thread = session.findElement("tr > td.thread-title")
|
||||||
|
check thread.isNone()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue