xeqi / kerodon Goto Github PK
View Code? Open in Web Editor NEWinteraction and testing library for html based ring apps.
interaction and testing library for html based ring apps.
My current plan was to implement the following
(defn pick [state selector])
This would work similarly to the (choose)
implementation, unchecking all radio boxes with the same name, and then checking the one requested.
Please, release Kerodon 0.3.0. Version 0.2.0 on Clojars is outdated and doesn't handle things I need to use.
(is there any other solution? lein checkouts?)
When we (press "save")
on this form:
<form action="/myform?email=hi>
<input hidden="email" value="hello"/>
<input type="submit" value="save"/>
</form>
Kerodon will wrongly reuse the query string resulting in a request path of /myform?email=hi&email=hello
. This is inconsistent with the behaviour I see in my browser (latest chrome). Kerodon is also wrong according to specifications mentioned here [1].
This problem surfaces when the parameters are parsed with ring.middleware.params/wrap-params
this results in {"email" ["hi" "hello"]}
instead of {"email" "hello"}
.
My app makes use of the origin and referer headers for some functionality. It would be handy if kerodon automatically detected and provided origin and referer headers. Is this something that could be accepted in a PR?
As specified in http://www.w3.org/TR/html401/interact/forms.html#adef-for
We might as well also support a <label> element which has no "for" attribute, but contains a form control.
Here's a rough outline for the work I'm planning to support HTML forms more completely:
Select box support, picking values and being submitted with the form
(choose "Field" "value")
Checkbox and radio button support, picking values and submitting in the same way a browser would
(pick "Field")
Support for finding elements by placeholder.
I'm not as sure as this one, but the idea is to support fields like this:
<input name="query" type="search" placeholder="Search..." />
My rough implementation plan at the moment is to try and pull some of the common behaviour between form fields into a FormField protocol, I think this will look something like the following, but unsure whether this is actually a good idea.
(defprotocol FormField
"Common behaviour for form fields"
(field-name [this node] "name of the field for form submission")
(field-value [this node] "value of the field for form submission")
(set-field-value! [this node value] "update the value of the field in this enlive resource"))
(deftype InputField [selector]
FormField
(field-name [this node] (-> (enlive/select node [selector]) first :attrs :name))
; ...
)
Typing this out here, I'm less sure it'll work well - but I'll try and implement something to see how it pans out, form-element
would have to be changed to return types that implement FormField
, maybe also becoming a multimethod so that both the factory and the available types are extensible by third parties?
I'd appreciate any input on this :)
I noticed that a test case in my project was failing because an empty file-input element would result in an entry in the kerodon-generated request map like :
:some-key {:0 "" :1 ""}
Where as a browser (tested it with firefox) would generate a request map without such entry.
I am working around it by performing some filtering so that it works both for kerodon and an actual browser.
Just though It would be nice if kerodon can be consistent with an actual browser when possible.
Thanks for the awesome project!
If there are any <a>
tags that contain other HTML tags like images or spans, then an error is thrown.
Okay:
<a href="/">Home</a>
Error:
<a href="/"><span>Home</span></a>
Note the error occurs when (follow "whatever")
is used.
ERROR in (swirl-security) (string.clj:236)
Uncaught exception, not in assertion.
expected: nil
actual: java.lang.ClassCastException: clojure.lang.PersistentStructMap cannot be cast to java.lang.CharSequence
at clojure.string$trim.invoke (string.clj:236)
clojure.core$map$fn__4245.invoke (core.clj:2559)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.LazySeq.equals (LazySeq.java:115)
clojure.lang.LazySeq.equiv (LazySeq.java:100)
clojure.lang.Util.pcequiv (Util.java:124)
clojure.lang.Util.equiv (Util.java:32)
kerodon.impl$css_or_content$fn__16846.invoke (impl.clj:30)
net.cgrand.enlive_html$pred$fn__16009.invoke (enlive_html.clj:241)
net.cgrand.enlive_html$zip_pred$fn__16004.invoke (enlive_html.clj:236)
net.cgrand.enlive_html$intersection$fn__16043.invoke (enlive_html.clj:282)
net.cgrand.enlive_html$predset$fn__16137.invoke (enlive_html.clj:329)
clojure.core$comp$fn__4192.invoke (core.clj:2403)
net.cgrand.enlive_html$step.invoke (enlive_html.clj:390)
net.cgrand.enlive_html$zip_select_nodes_STAR_$select1__16290.invoke (enlive_html.clj:497)
net.cgrand.enlive_html$zip_select_nodes_STAR_$select1__16290$fn__16291.invoke (enlive_html.clj:498)
clojure.core$map$fn__4245.invoke (core.clj:2559)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.Cons.next (Cons.java:39)
clojure.lang.RT.boundedLength (RT.java:1654)
clojure.lang.RestFn.applyTo (RestFn.java:130)
clojure.core$apply.invoke (core.clj:624)
clojure.core$mapcat.doInvoke (core.clj:2586)
clojure.lang.RestFn.invoke (RestFn.java:423)
net.cgrand.enlive_html$zip_select_nodes_STAR_$select1__16290.invoke (enlive_html.clj:498)
net.cgrand.enlive_html$zip_select_nodes_STAR_$select1__16290$fn__16291.invoke (enlive_html.clj:498)
clojure.core$map$fn__4245.invoke (core.clj:2559)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.Cons.next (Cons.java:39)
clojure.lang.RT.boundedLength (RT.java:1654)
clojure.lang.RestFn.applyTo (RestFn.java:130)
clojure.core$apply.invoke (core.clj:624)
clojure.core$mapcat.doInvoke (core.clj:2586)
clojure.lang.RestFn.invoke (RestFn.java:423)
net.cgrand.enlive_html$zip_select_nodes_STAR_$select1__16290.invoke (enlive_html.clj:498)
net.cgrand.enlive_html$zip_select_nodes_STAR_$select1__16290$fn__16291.invoke (enlive_html.clj:498)
clojure.core$map$fn__4245.invoke (core.clj:2559)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.Cons.next (Cons.java:39)
clojure.lang.RT.boundedLength (RT.java:1654)
clojure.lang.RestFn.applyTo (RestFn.java:130)
clojure.core$apply.invoke (core.clj:624)
clojure.core$mapcat.doInvoke (core.clj:2586)
clojure.lang.RestFn.invoke (RestFn.java:423)
net.cgrand.enlive_html$zip_select_nodes_STAR_$select1__16290.invoke (enlive_html.clj:498)
net.cgrand.enlive_html$zip_select_nodes_STAR_$select1__16290$fn__16291.invoke (enlive_html.clj:498)
clojure.core$map$fn__4245.invoke (core.clj:2559)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.Cons.next (Cons.java:39)
clojure.lang.RT.boundedLength (RT.java:1654)
clojure.lang.RestFn.applyTo (RestFn.java:130)
clojure.core$apply.invoke (core.clj:624)
clojure.core$mapcat.doInvoke (core.clj:2586)
clojure.lang.RestFn.invoke (RestFn.java:423)
net.cgrand.enlive_html$zip_select_nodes_STAR_$select1__16290.invoke (enlive_html.clj:498)
net.cgrand.enlive_html$zip_select_nodes_STAR_$select1__16290$fn__16291.invoke (enlive_html.clj:498)
clojure.core$map$fn__4245.invoke (core.clj:2559)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.Cons.next (Cons.java:39)
clojure.lang.RT.boundedLength (RT.java:1654)
clojure.lang.RestFn.applyTo (RestFn.java:130)
clojure.core$apply.invoke (core.clj:624)
clojure.core$mapcat.doInvoke (core.clj:2586)
clojure.lang.RestFn.invoke (RestFn.java:423)
net.cgrand.enlive_html$zip_select_nodes_STAR_$select1__16290.invoke (enlive_html.clj:498)
net.cgrand.enlive_html$zip_select_nodes_STAR_$select1__16290$fn__16291.invoke (enlive_html.clj:498)
clojure.core$map$fn__4245.invoke (core.clj:2559)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.Cons.next (Cons.java:39)
clojure.lang.RT.boundedLength (RT.java:1654)
clojure.lang.RestFn.applyTo (RestFn.java:130)
clojure.core$apply.invoke (core.clj:624)
clojure.core$mapcat.doInvoke (core.clj:2586)
clojure.lang.RestFn.invoke (RestFn.java:423)
net.cgrand.enlive_html$zip_select_nodes_STAR_$select1__16290.invoke (enlive_html.clj:498)
net.cgrand.enlive_html$zip_select_nodes_STAR_$fn__16295.invoke (enlive_html.clj:500)
clojure.core$map$fn__4245.invoke (core.clj:2559)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.RT.seq (RT.java:484)
clojure.core$seq.invoke (core.clj:133)
clojure.core$apply.invoke (core.clj:624)
clojure.core$mapcat.doInvoke (core.clj:2586)
clojure.lang.RestFn.invoke (RestFn.java:423)
net.cgrand.enlive_html$zip_select_nodes_STAR_.invoke (enlive_html.clj:500)
net.cgrand.enlive_html$select_nodes_STAR_.invoke (enlive_html.clj:504)
net.cgrand.enlive_html$select.invoke (enlive_html.clj:543)
kerodon.impl$link.invoke (impl.clj:83)
kerodon.impl$find_url.invoke (impl.clj:213)
kerodon.core$follow.invoke (core.clj:19)
yswrl.features.swirl_features/fn (swirl_features.clj:52)
clojure.test$test_var$fn__7187.invoke (test.clj:704)
clojure.test$test_var.invoke (test.clj:704)
clojure.test$test_vars$fn__7209$fn__7214.invoke (test.clj:722)
clojure.test$default_fixture.invoke (test.clj:674)
clojure.test$test_vars$fn__7209.invoke (test.clj:722)
clojure.test$default_fixture.invoke (test.clj:674)
clojure.test$test_vars.invoke (test.clj:718)
clojure.test$test_all_vars.invoke (test.clj:728)
clojure.test$test_ns.invoke (test.clj:747)
clojure.core$map$fn__4245.invoke (core.clj:2559)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.Cons.next (Cons.java:39)
clojure.lang.RT.next (RT.java:598)
clojure.core$next.invoke (core.clj:64)
clojure.core$reduce1.invoke (core.clj:903)
clojure.core$reduce1.invoke (core.clj:894)
clojure.core$merge_with.doInvoke (core.clj:2777)
clojure.lang.RestFn.applyTo (RestFn.java:139)
clojure.core$apply.invoke (core.clj:626)
clojure.test$run_tests.doInvoke (test.clj:762)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.core$apply.invoke (core.clj:624)
com.jakemccrary.test_refresh$run_selected_tests$fn__656.invoke (test_refresh.clj:129)
com.jakemccrary.test_refresh$suppress_unselected_tests.invoke (test_refresh.clj:103)
com.jakemccrary.test_refresh$run_selected_tests.invoke (test_refresh.clj:127)
com.jakemccrary.test_refresh$run_tests.invoke (test_refresh.clj:135)
com.jakemccrary.test_refresh$monitor_project$fn__672.invoke (test_refresh.clj:192)
com.jakemccrary.test_refresh$monitor_project.invoke (test_refresh.clj:185)
user$eval730.invoke (form-init5254813364040845940.clj:1)
clojure.lang.Compiler.eval (Compiler.java:6703)
clojure.lang.Compiler.eval (Compiler.java:6693)
clojure.lang.Compiler.load (Compiler.java:7130)
clojure.lang.Compiler.loadFile (Compiler.java:7086)
clojure.main$load_script.invoke (main.clj:274)
clojure.main$init_opt.invoke (main.clj:279)
clojure.main$initialize.invoke (main.clj:307)
clojure.main$null_opt.invoke (main.clj:342)
clojure.main$main.doInvoke (main.clj:420)
clojure.lang.RestFn.invoke (RestFn.java:421)
clojure.lang.Var.invoke (Var.java:383)
clojure.lang.AFn.applyToHelper (AFn.java:156)
clojure.lang.Var.applyTo (Var.java:700)
clojure.main.main (main.java:37)
I have a test:
(ns sprint-is.test.routes.auth
(:use [kerodon.core]
[kerodon.test]
[clojure.test]
[korma.core])
(:require
[sprint-is.modules.users]
[sprint-is.handler]))
(defn setup-db []
(do
(delete sprint-is.modules.users/users)
(insert sprint-is.modules.users/users (values
{:id 1 :email "[email protected]" :salt "salt" :password (sprint-is.modules.users/hash-password "pass" "salt")}))))
(deftest user-can-have-bad-password
(setup-db)
(->
(session sprint-is.handler/app)
(visit "/sign/in")
(fill-in "E-mail" "[email protected]")
(fill-in "Password" "bad password")
(press "Prihlasit")
(has (text? "Bad Password"))))
And Route:
(ns sprint-is.routes.auth
(:use compojure.core)
(:use sprint-is.libs.form)
(:use flatland.ordered.map)
(:use sprint-is.libs.errors)
(:require [sprint-is.views.layout :as layout]
[noir.response :as response]
[sprint-is.modules.users :as users]
[noir.session :as session]
))
(defform login-form (ordered-map
:email {:type :text :value "" :label "E-mail" :errors []}
:password {:type :password :value "" :label "Password" :errors []}
:submit {:type :submit :value "Prihlasit" :label "" :errors []}))
(defn login-page
([] (login-page (session/flash-get :message)))
([message] (layout/render "login.html" {:message message :form (render-form login-form)})))
(defn process-login [email password]
(let-or-error (users/login email password)
(fn [user] (session/put! :user user) (response/redirect "/"))
(fn [error] (login-page (error :message)))))
(defn logout-page []
(session/clear!)
(response/redirect "/sign/in"))
(defroutes auth-routes
(GET "/sign/in" [] (login-page))
(POST "/sign/in" [email password] (process-login email password))
(GET "/sign/out" [] (logout-page)))
When I run test, Kerodon runs the code, fill in form and click login, but it goes to URL /sign/ instead of /sign/in (after submitting form) so I get "Not found" page. When I (prn) page after (visit "/sign/in"), {:request {:uri}} is "sign/in", after (press "Prihlasit"), the {:request {:uri}} is "/sign/". Form action is empty string
I have a page that has multiple input
tags, all of which are found without issue, and a single select
, which kerodon cannot find. I have added a println
into the test flow just above where the error occurs:
(deftest user-record-created-on-signup
(let [response (read-string (slurp "test/data/nest_access_token.clj"))]
(fake-http/with-fake-http [nest/token-url response]
(-> (session handler/app)
(visit "/users/new")
(fill-in "email" "[email protected]")
(fill-in "password" "password")
(fill-in "confirm password" "password")
(fill-in "phone number" "123-456-7890")
(println)
(choose "timezone" "America/New_York")
(fill-in "nest pin" "1234")
(press "submit")
(follow-redirect)
(has (some-text? "Welcome [email protected]"))))))
All the output is pasted below, which includes the rendered html. The issue is in finding the "timezone" dropdown.
Thanks for any help!
ask-nest.core=> (clojure.test/run-tests 'ask-nest.integration.new-user-test)
Testing ask-nest.integration.new-user-test
{:response {:status 200, :headers {X-Content-Type-Options nosniff, X-Frame-Options SAMEORIGIN, X-XSS-Protection 1; mode=block, Set-Cookie (ring-session=eee00742-3b90-45c0-86ef-071287b29443;Path=/;HttpOnly), Content-Type text/html; charset=utf-8}, :body <!DOCTYPE html>
<html>
<head>
<title>Whendows </title>
</head>
<body>
<div id="users-new">
<header>
<h1>Sign Up</h1>
</header>
<form action="/users" method="post">
<input id="__anti-forgery-token" name="__anti-forgery-token" type="hidden" value="oLjni6mRPBWb1VPUnRhsc8bILkqOV4ombnZ2XdiVnuwPEL6n2IJ/J16/5FXCDv9meWhpG+YrcwC4MBsl" />
<label for="email">
email
<input type="email" name="email" id="email" />
</label>
<label for="password">
password
<input type="password" name="password" id="password" />
</label>
<label for="confirm-password">
confirm password
<input type="password" name="confirm-password" id="confirm-password" />
</label>
<label for="phone-number">
phone number
<input type="tel" name="phone-number" id="phone-number" />
</label>
<label for="timezone">
timezone
<select id="timezone" name="timezone">
<option>Etc/GMT+12</option>
<option>Etc/GMT+11</option>
<option>Pacific/Apia</option>
<option>Pacific/Midway</option>
<option>Pacific/Niue</option>
<option>Pacific/Pago_Pago</option>
<option>America/Adak</option>
<option>Etc/GMT+10</option>
<option>HST</option>
<option>Pacific/Fakaofo</option>
<option>Pacific/Honolulu</option>
<option>Pacific/Johnston</option>
<option>Pacific/Rarotonga</option>
<option>Pacific/Tahiti</option>
<option>Pacific/Marquesas</option>
<option>America/Anchorage</option>
<option>America/Juneau</option>
<option>America/Nome</option>
<option>America/Yakutat</option>
<option>Etc/GMT+9</option>
<option>Pacific/Gambier</option>
<option>America/Dawson</option>
<option>America/Los_Angeles</option>
<option>America/Santa_Isabel</option>
<option>America/Tijuana</option>
<option>America/Vancouver</option>
<option>America/Whitehorse</option>
<option>Etc/GMT+8</option>
<option>PST8PDT</option>
<option>Pacific/Pitcairn</option>
<option>America/Boise</option>
<option>America/Cambridge_Bay</option>
<option>America/Chihuahua</option>
<option>America/Dawson_Creek</option>
<option>America/Denver</option>
<option>America/Edmonton</option>
<option>America/Hermosillo</option>
<option>America/Inuvik</option>
<option>America/Mazatlan</option>
<option>America/Ojinaga</option>
<option>America/Phoenix</option>
<option>America/Yellowknife</option>
<option>Etc/GMT+7</option>
<option>MST</option>
<option>MST7MDT</option>
<option>America/Bahia_Banderas</option>
<option>America/Belize</option>
<option>America/Cancun</option>
<option>America/Chicago</option>
<option>America/Costa_Rica</option>
<option>America/El_Salvador</option>
<option>America/Guatemala</option>
<option>America/Indiana/Knox</option>
<option>America/Indiana/Tell_City</option>
<option>America/Managua</option>
<option>America/Matamoros</option>
<option>America/Menominee</option>
<option>America/Merida</option>
<option>America/Mexico_City</option>
<option>America/Monterrey</option>
<option>America/North_Dakota/Center</option>
<option>America/North_Dakota/New_Salem</option>
<option>America/Rainy_River</option>
<option>America/Rankin_Inlet</option>
<option>America/Regina</option>
<option>America/Swift_Current</option>
<option>America/Tegucigalpa</option>
<option>America/Winnipeg</option>
<option>CST6CDT</option>
<option>Etc/GMT+6</option>
<option>Pacific/Easter</option>
<option>Pacific/Galapagos</option>
<option>America/Atikokan</option>
<option>America/Bogota</option>
<option>America/Cayman</option>
<option>America/Detroit</option>
<option>America/Grand_Turk</option>
<option>America/Guayaquil</option>
<option>America/Havana</option>
<option>America/Indiana/Indianapolis</option>
<option>America/Indiana/Marengo</option>
<option>America/Indiana/Petersburg</option>
<option>America/Indiana/Vevay</option>
<option>America/Indiana/Vincennes</option>
<option>America/Indiana/Winamac</option>
<option>America/Iqaluit</option>
<option>America/Jamaica</option>
<option>America/Kentucky/Louisville</option>
<option>America/Kentucky/Monticello</option>
<option>America/Lima</option>
<option>America/Montreal</option>
<option>America/Nassau</option>
<option>America/New_York</option>
<option>America/Nipigon</option>
<option>America/Panama</option>
<option>America/Pangnirtung</option>
<option>America/Port-au-Prince</option>
<option>America/Resolute</option>
<option>America/Thunder_Bay</option>
<option>America/Toronto</option>
<option>EST</option>
<option>EST5EDT</option>
<option>Etc/GMT+5</option>
<option>America/Caracas</option>
<option>America/Anguilla</option>
<option>America/Antigua</option>
<option>America/Argentina/San_Luis</option>
<option>America/Aruba</option>
<option>America/Asuncion</option>
<option>America/Barbados</option>
<option>America/Blanc-Sablon</option>
<option>America/Boa_Vista</option>
<option>America/Campo_Grande</option>
<option>America/Cuiaba</option>
<option>America/Curacao</option>
<option>America/Dominica</option>
<option>America/Eirunepe</option>
<option>America/Glace_Bay</option>
<option>America/Goose_Bay</option>
<option>America/Grenada</option>
<option>America/Guadeloupe</option>
<option>America/Guyana</option>
<option>America/Halifax</option>
<option>America/La_Paz</option>
<option>America/Manaus</option>
<option>America/Martinique</option>
<option>America/Moncton</option>
<option>America/Montserrat</option>
<option>America/Port_of_Spain</option>
<option>America/Porto_Velho</option>
<option>America/Puerto_Rico</option>
<option>America/Rio_Branco</option>
<option>America/Santiago</option>
<option>America/Santo_Domingo</option>
<option>America/St_Kitts</option>
<option>America/St_Lucia</option>
<option>America/St_Thomas</option>
<option>America/St_Vincent</option>
<option>America/Thule</option>
<option>America/Tortola</option>
<option>Antarctica/Palmer</option>
<option>Atlantic/Bermuda</option>
<option>Atlantic/Stanley</option>
<option>Etc/GMT+4</option>
<option>America/St_Johns</option>
<option>America/Araguaina</option>
<option>America/Argentina/Buenos_Aires</option>
<option>America/Argentina/Catamarca</option>
<option>America/Argentina/Cordoba</option>
<option>America/Argentina/Jujuy</option>
<option>America/Argentina/La_Rioja</option>
<option>America/Argentina/Mendoza</option>
<option>America/Argentina/Rio_Gallegos</option>
<option>America/Argentina/Salta</option>
<option>America/Argentina/San_Juan</option>
<option>America/Argentina/Tucuman</option>
<option>America/Argentina/Ushuaia</option>
<option>America/Bahia</option>
<option>America/Belem</option>
<option>America/Cayenne</option>
<option>America/Fortaleza</option>
<option>America/Godthab</option>
<option>America/Maceio</option>
<option>America/Miquelon</option>
<option>America/Montevideo</option>
<option>America/Paramaribo</option>
<option>America/Recife</option>
<option>America/Santarem</option>
<option>America/Sao_Paulo</option>
<option>Antarctica/Rothera</option>
<option>Etc/GMT+3</option>
<option>America/Noronha</option>
<option>Atlantic/South_Georgia</option>
<option>Etc/GMT+2</option>
<option>America/Scoresbysund</option>
<option>Atlantic/Azores</option>
<option>Atlantic/Cape_Verde</option>
<option>Etc/GMT+1</option>
<option>Africa/Abidjan</option>
<option>Africa/Accra</option>
<option>Africa/Bamako</option>
<option>Africa/Banjul</option>
<option>Africa/Bissau</option>
<option>Africa/Casablanca</option>
<option>Africa/Conakry</option>
<option>Africa/Dakar</option>
<option>Africa/El_Aaiun</option>
<option>Africa/Freetown</option>
<option>Africa/Lome</option>
<option>Africa/Monrovia</option>
<option>Africa/Nouakchott</option>
<option>Africa/Ouagadougou</option>
<option>Africa/Sao_Tome</option>
<option>America/Danmarkshavn</option>
<option>Atlantic/Canary</option>
<option>Atlantic/Faroe</option>
<option>Atlantic/Madeira</option>
<option>Atlantic/Reykjavik</option>
<option>Atlantic/St_Helena</option>
<option>Etc/GMT</option>
<option>Etc/UCT</option>
<option>Etc/UTC</option>
<option>Europe/Dublin</option>
<option>Europe/Lisbon</option>
<option>Europe/London</option>
<option>UTC</option>
<option>WET</option>
<option>Africa/Algiers</option>
<option>Africa/Bangui</option>
<option>Africa/Brazzaville</option>
<option>Africa/Ceuta</option>
<option>Africa/Douala</option>
<option>Africa/Kinshasa</option>
<option>Africa/Lagos</option>
<option>Africa/Libreville</option>
<option>Africa/Luanda</option>
<option>Africa/Malabo</option>
<option>Africa/Ndjamena</option>
<option>Africa/Niamey</option>
<option>Africa/Porto-Novo</option>
<option>Africa/Tunis</option>
<option>Africa/Windhoek</option>
<option>CET</option>
<option>Etc/GMT-1</option>
<option>Europe/Amsterdam</option>
<option>Europe/Andorra</option>
<option>Europe/Belgrade</option>
<option>Europe/Berlin</option>
<option>Europe/Brussels</option>
<option>Europe/Budapest</option>
<option>Europe/Copenhagen</option>
<option>Europe/Gibraltar</option>
<option>Europe/Luxembourg</option>
<option>Europe/Madrid</option>
<option>Europe/Malta</option>
<option>Europe/Monaco</option>
<option>Europe/Oslo</option>
<option>Europe/Paris</option>
<option>Europe/Prague</option>
<option>Europe/Rome</option>
<option>Europe/Stockholm</option>
<option>Europe/Tirane</option>
<option>Europe/Vaduz</option>
<option>Europe/Vienna</option>
<option>Europe/Warsaw</option>
<option>Europe/Zurich</option>
<option>MET</option>
<option>Africa/Blantyre</option>
<option>Africa/Bujumbura</option>
<option>Africa/Cairo</option>
<option>Africa/Gaborone</option>
<option>Africa/Harare</option>
<option>Africa/Johannesburg</option>
<option>Africa/Kigali</option>
<option>Africa/Lubumbashi</option>
<option>Africa/Lusaka</option>
<option>Africa/Maputo</option>
<option>Africa/Maseru</option>
<option>Africa/Mbabane</option>
<option>Africa/Tripoli</option>
<option>Asia/Amman</option>
<option>Asia/Beirut</option>
<option>Asia/Damascus</option>
<option>Asia/Gaza</option>
<option>Asia/Jerusalem</option>
<option>Asia/Nicosia</option>
<option>EET</option>
<option>Etc/GMT-2</option>
<option>Europe/Athens</option>
<option>Europe/Bucharest</option>
<option>Europe/Chisinau</option>
<option>Europe/Helsinki</option>
<option>Europe/Istanbul</option>
<option>Europe/Kaliningrad</option>
<option>Europe/Kiev</option>
<option>Europe/Minsk</option>
<option>Europe/Riga</option>
<option>Europe/Simferopol</option>
<option>Europe/Sofia</option>
<option>Europe/Tallinn</option>
<option>Europe/Uzhgorod</option>
<option>Europe/Vilnius</option>
<option>Europe/Zaporozhye</option>
<option>Africa/Addis_Ababa</option>
<option>Africa/Asmara</option>
<option>Africa/Dar_es_Salaam</option>
<option>Africa/Djibouti</option>
<option>Africa/Kampala</option>
<option>Africa/Khartoum</option>
<option>Africa/Mogadishu</option>
<option>Africa/Nairobi</option>
<option>Antarctica/Syowa</option>
<option>Asia/Aden</option>
<option>Asia/Baghdad</option>
<option>Asia/Bahrain</option>
<option>Asia/Kuwait</option>
<option>Asia/Qatar</option>
<option>Asia/Riyadh</option>
<option>Etc/GMT-3</option>
<option>Europe/Moscow</option>
<option>Europe/Samara</option>
<option>Europe/Volgograd</option>
<option>Indian/Antananarivo</option>
<option>Indian/Comoro</option>
<option>Indian/Mayotte</option>
<option>Asia/Tehran</option>
<option>Asia/Baku</option>
<option>Asia/Dubai</option>
<option>Asia/Muscat</option>
<option>Asia/Tbilisi</option>
<option>Asia/Yerevan</option>
<option>Etc/GMT-4</option>
<option>Indian/Mahe</option>
<option>Indian/Mauritius</option>
<option>Indian/Reunion</option>
<option>Asia/Kabul</option>
<option>Antarctica/Mawson</option>
<option>Asia/Aqtau</option>
<option>Asia/Aqtobe</option>
<option>Asia/Ashgabat</option>
<option>Asia/Dushanbe</option>
<option>Asia/Karachi</option>
<option>Asia/Oral</option>
<option>Asia/Samarkand</option>
<option>Asia/Tashkent</option>
<option>Asia/Yekaterinburg</option>
<option>Etc/GMT-5</option>
<option>Indian/Kerguelen</option>
<option>Indian/Maldives</option>
<option>Asia/Colombo</option>
<option>Asia/Kolkata</option>
<option>Asia/Kathmandu</option>
<option>Antarctica/Vostok</option>
<option>Asia/Almaty</option>
<option>Asia/Bishkek</option>
<option>Asia/Dhaka</option>
<option>Asia/Novokuznetsk</option>
<option>Asia/Novosibirsk</option>
<option>Asia/Omsk</option>
<option>Asia/Qyzylorda</option>
<option>Asia/Thimphu</option>
<option>Etc/GMT-6</option>
<option>Indian/Chagos</option>
<option>Asia/Rangoon</option>
<option>Indian/Cocos</option>
<option>Antarctica/Davis</option>
<option>Asia/Bangkok</option>
<option>Asia/Ho_Chi_Minh</option>
<option>Asia/Hovd</option>
<option>Asia/Jakarta</option>
<option>Asia/Krasnoyarsk</option>
<option>Asia/Phnom_Penh</option>
<option>Asia/Pontianak</option>
<option>Asia/Vientiane</option>
<option>Etc/GMT-7</option>
<option>Indian/Christmas</option>
<option>Antarctica/Casey</option>
<option>Asia/Brunei</option>
<option>Asia/Choibalsan</option>
<option>Asia/Chongqing</option>
<option>Asia/Harbin</option>
<option>Asia/Hong_Kong</option>
<option>Asia/Irkutsk</option>
<option>Asia/Kashgar</option>
<option>Asia/Kuala_Lumpur</option>
<option>Asia/Kuching</option>
<option>Asia/Macau</option>
<option>Asia/Makassar</option>
<option>Asia/Manila</option>
<option>Asia/Shanghai</option>
<option>Asia/Singapore</option>
<option>Asia/Taipei</option>
<option>Asia/Ulaanbaatar</option>
<option>Asia/Urumqi</option>
<option>Australia/Perth</option>
<option>Etc/GMT-8</option>
<option>Australia/Eucla</option>
<option>Asia/Dili</option>
<option>Asia/Jayapura</option>
<option>Asia/Pyongyang</option>
<option>Asia/Seoul</option>
<option>Asia/Tokyo</option>
<option>Asia/Yakutsk</option>
<option>Etc/GMT-9</option>
<option>Pacific/Palau</option>
<option>Australia/Adelaide</option>
<option>Australia/Broken_Hill</option>
<option>Australia/Darwin</option>
<option>Antarctica/DumontDUrville</option>
<option>Asia/Sakhalin</option>
<option>Asia/Vladivostok</option>
<option>Australia/Brisbane</option>
<option>Australia/Currie</option>
<option>Australia/Hobart</option>
<option>Australia/Lindeman</option>
<option>Australia/Melbourne</option>
<option>Australia/Sydney</option>
<option>Etc/GMT-10</option>
<option>Pacific/Chuuk</option>
<option>Pacific/Guam</option>
<option>Pacific/Port_Moresby</option>
<option>Pacific/Saipan</option>
<option>Australia/Lord_Howe</option>
<option>Antarctica/Macquarie</option>
<option>Asia/Anadyr</option>
<option>Asia/Kamchatka</option>
<option>Asia/Magadan</option>
<option>Etc/GMT-11</option>
<option>Pacific/Efate</option>
<option>Pacific/Guadalcanal</option>
<option>Pacific/Kosrae</option>
<option>Pacific/Noumea</option>
<option>Pacific/Pohnpei</option>
<option>Pacific/Norfolk</option>
<option>Antarctica/McMurdo</option>
<option>Etc/GMT-12</option>
<option>Pacific/Auckland</option>
<option>Pacific/Fiji</option>
<option>Pacific/Funafuti</option>
<option>Pacific/Kwajalein</option>
<option>Pacific/Majuro</option>
<option>Pacific/Nauru</option>
<option>Pacific/Tarawa</option>
<option>Pacific/Wake</option>
<option>Pacific/Wallis</option>
<option>Pacific/Chatham</option>
<option>Etc/GMT-13</option>
<option>Pacific/Enderbury</option>
<option>Pacific/Tongatapu</option>
<option>Etc/GMT-14</option>
<option>Pacific/Kiritimati</option>
</select>
</label>
<label for="nest-pin">
nest pin
<input name="nest-pin" id="nest-pin" />
</label>
<div id="nest-pin-retrieval">
<p>
Follow the link below and log in to Nest. Paste the PIN number that is
shown on the screen into the field above
</p>
<a href="https://home.nest.com/login/oauth2?client_id=nest-client-id&state=fnCLwYer"
target="_blank"
>
nest authorization
</a>
</div>
<input type="submit" id="submit" value="submit" />
</form>
</div>
</body>
</html>
}, :request {:body nil, :server-port 80, :server-name localhost, :remote-addr localhost, :uri /users/new, :query-string nil, :scheme :http, :request-method :get, :headers {host localhost}}, :headers nil, :enlive [{:type :dtd, :data [html nil nil]} {:tag :html, :attrs nil, :content [
{:tag :head, :attrs nil, :content [
{:tag :title, :attrs nil, :content [Whendows ]}
]}
{:tag :body, :attrs nil, :content [
{:tag :div, :attrs {:id users-new}, :content [
{:tag :header, :attrs nil, :content [
{:tag :h1, :attrs nil, :content [Sign Up]}
]}
{:tag :form, :attrs {:method post, :action /users}, :content [
{:tag :input, :attrs {:value oLjni6mRPBWb1VPUnRhsc8bILkqOV4ombnZ2XdiVnuwPEL6n2IJ/J16/5FXCDv9meWhpG+YrcwC4MBsl, :type hidden, :name __anti-forgery-token, :id __anti-forgery-token}, :content []}
{:tag :label, :attrs {:for email}, :content [
email
{:tag :input, :attrs {:value [email protected], :id email, :name email, :type email}, :content []}
]}
{:tag :label, :attrs {:for password}, :content [
password
{:tag :input, :attrs {:value password, :id password, :name password, :type password}, :content []}
]}
{:tag :label, :attrs {:for confirm-password}, :content [
confirm password
{:tag :input, :attrs {:value password, :id confirm-password, :name confirm-password, :type password}, :content []}
]}
{:tag :label, :attrs {:for phone-number}, :content [
phone number
{:tag :input, :attrs {:value 123-456-7890, :id phone-number, :name phone-number, :type tel}, :content []}
]}
{:tag :label, :attrs {:for timezone}, :content [
timezone
{:tag :select, :attrs {:tabindex 0, :name timezone, :id timezone}, :content [
{:tag :option, :attrs nil, :content [Etc/GMT+12]}
{:tag :option, :attrs nil, :content [Etc/GMT+11]}
{:tag :option, :attrs nil, :content [Pacific/Apia]}
{:tag :option, :attrs nil, :content [Pacific/Midway]}
{:tag :option, :attrs nil, :content [Pacific/Niue]}
{:tag :option, :attrs nil, :content [Pacific/Pago_Pago]}
{:tag :option, :attrs nil, :content [America/Adak]}
{:tag :option, :attrs nil, :content [Etc/GMT+10]}
{:tag :option, :attrs nil, :content [HST]}
{:tag :option, :attrs nil, :content [Pacific/Fakaofo]}
{:tag :option, :attrs nil, :content [Pacific/Honolulu]}
{:tag :option, :attrs nil, :content [Pacific/Johnston]}
{:tag :option, :attrs nil, :content [Pacific/Rarotonga]}
{:tag :option, :attrs nil, :content [Pacific/Tahiti]}
{:tag :option, :attrs nil, :content [Pacific/Marquesas]}
{:tag :option, :attrs nil, :content [America/Anchorage]}
{:tag :option, :attrs nil, :content [America/Juneau]}
{:tag :option, :attrs nil, :content [America/Nome]}
{:tag :option, :attrs nil, :content [America/Yakutat]}
{:tag :option, :attrs nil, :content [Etc/GMT+9]}
{:tag :option, :attrs nil, :content [Pacific/Gambier]}
{:tag :option, :attrs nil, :content [America/Dawson]}
{:tag :option, :attrs nil, :content [America/Los_Angeles]}
{:tag :option, :attrs nil, :content [America/Santa_Isabel]}
{:tag :option, :attrs nil, :content [America/Tijuana]}
{:tag :option, :attrs nil, :content [America/Vancouver]}
{:tag :option, :attrs nil, :content [America/Whitehorse]}
{:tag :option, :attrs nil, :content [Etc/GMT+8]}
{:tag :option, :attrs nil, :content [PST8PDT]}
{:tag :option, :attrs nil, :content [Pacific/Pitcairn]}
{:tag :option, :attrs nil, :content [America/Boise]}
{:tag :option, :attrs nil, :content [America/Cambridge_Bay]}
{:tag :option, :attrs nil, :content [America/Chihuahua]}
{:tag :option, :attrs nil, :content [America/Dawson_Creek]}
{:tag :option, :attrs nil, :content [America/Denver]}
{:tag :option, :attrs nil, :content [America/Edmonton]}
{:tag :option, :attrs nil, :content [America/Hermosillo]}
{:tag :option, :attrs nil, :content [America/Inuvik]}
{:tag :option, :attrs nil, :content [America/Mazatlan]}
{:tag :option, :attrs nil, :content [America/Ojinaga]}
{:tag :option, :attrs nil, :content [America/Phoenix]}
{:tag :option, :attrs nil, :content [America/Yellowknife]}
{:tag :option, :attrs nil, :content [Etc/GMT+7]}
{:tag :option, :attrs nil, :content [MST]}
{:tag :option, :attrs nil, :content [MST7MDT]}
{:tag :option, :attrs nil, :content [America/Bahia_Banderas]}
{:tag :option, :attrs nil, :content [America/Belize]}
{:tag :option, :attrs nil, :content [America/Cancun]}
{:tag :option, :attrs nil, :content [America/Chicago]}
{:tag :option, :attrs nil, :content [America/Costa_Rica]}
{:tag :option, :attrs nil, :content [America/El_Salvador]}
{:tag :option, :attrs nil, :content [America/Guatemala]}
{:tag :option, :attrs nil, :content [America/Indiana/Knox]}
{:tag :option, :attrs nil, :content [America/Indiana/Tell_City]}
{:tag :option, :attrs nil, :content [America/Managua]}
{:tag :option, :attrs nil, :content [America/Matamoros]}
{:tag :option, :attrs nil, :content [America/Menominee]}
{:tag :option, :attrs nil, :content [America/Merida]}
{:tag :option, :attrs nil, :content [America/Mexico_City]}
{:tag :option, :attrs nil, :content [America/Monterrey]}
{:tag :option, :attrs nil, :content [America/North_Dakota/Center]}
{:tag :option, :attrs nil, :content [America/North_Dakota/New_Salem]}
{:tag :option, :attrs nil, :content [America/Rainy_River]}
{:tag :option, :attrs nil, :content [America/Rankin_Inlet]}
{:tag :option, :attrs nil, :content [America/Regina]}
{:tag :option, :attrs nil, :content [America/Swift_Current]}
{:tag :option, :attrs nil, :content [America/Tegucigalpa]}
{:tag :option, :attrs nil, :content [America/Winnipeg]}
{:tag :option, :attrs nil, :content [CST6CDT]}
{:tag :option, :attrs nil, :content [Etc/GMT+6]}
{:tag :option, :attrs nil, :content [Pacific/Easter]}
{:tag :option, :attrs nil, :content [Pacific/Galapagos]}
{:tag :option, :attrs nil, :content [America/Atikokan]}
{:tag :option, :attrs nil, :content [America/Bogota]}
{:tag :option, :attrs nil, :content [America/Cayman]}
{:tag :option, :attrs nil, :content [America/Detroit]}
{:tag :option, :attrs nil, :content [America/Grand_Turk]}
{:tag :option, :attrs nil, :content [America/Guayaquil]}
{:tag :option, :attrs nil, :content [America/Havana]}
{:tag :option, :attrs nil, :content [America/Indiana/Indianapolis]}
{:tag :option, :attrs nil, :content [America/Indiana/Marengo]}
{:tag :option, :attrs nil, :content [America/Indiana/Petersburg]}
{:tag :option, :attrs nil, :content [America/Indiana/Vevay]}
{:tag :option, :attrs nil, :content [America/Indiana/Vincennes]}
{:tag :option, :attrs nil, :content [America/Indiana/Winamac]}
{:tag :option, :attrs nil, :content [America/Iqaluit]}
{:tag :option, :attrs nil, :content [America/Jamaica]}
{:tag :option, :attrs nil, :content [America/Kentucky/Louisville]}
{:tag :option, :attrs nil, :content [America/Kentucky/Monticello]}
{:tag :option, :attrs nil, :content [America/Lima]}
{:tag :option, :attrs nil, :content [America/Montreal]}
{:tag :option, :attrs nil, :content [America/Nassau]}
{:tag :option, :attrs nil, :content [America/New_York]}
{:tag :option, :attrs nil, :content [America/Nipigon]}
{:tag :option, :attrs nil, :content [America/Panama]}
{:tag :option, :attrs nil, :content [America/Pangnirtung]}
{:tag :option, :attrs nil, :content [America/Port-au-Prince]}
{:tag :option, :attrs nil, :content [America/Resolute]}
{:tag :option, :attrs nil, :content [America/Thunder_Bay]}
{:tag :option, :attrs nil, :content [America/Toronto]}
{:tag :option, :attrs nil, :content [EST]}
{:tag :option, :attrs nil, :content [EST5EDT]}
{:tag :option, :attrs nil, :content [Etc/GMT+5]}
{:tag :option, :attrs nil, :content [America/Caracas]}
{:tag :option, :attrs nil, :content [America/Anguilla]}
{:tag :option, :attrs nil, :content [America/Antigua]}
{:tag :option, :attrs nil, :content [America/Argentina/San_Luis]}
{:tag :option, :attrs nil, :content [America/Aruba]}
{:tag :option, :attrs nil, :content [America/Asuncion]}
{:tag :option, :attrs nil, :content [America/Barbados]}
{:tag :option, :attrs nil, :content [America/Blanc-Sablon]}
{:tag :option, :attrs nil, :content [America/Boa_Vista]}
{:tag :option, :attrs nil, :content [America/Campo_Grande]}
{:tag :option, :attrs nil, :content [America/Cuiaba]}
{:tag :option, :attrs nil, :content [America/Curacao]}
{:tag :option, :attrs nil, :content [America/Dominica]}
{:tag :option, :attrs nil, :content [America/Eirunepe]}
{:tag :option, :attrs nil, :content [America/Glace_Bay]}
{:tag :option, :attrs nil, :content [America/Goose_Bay]}
{:tag :option, :attrs nil, :content [America/Grenada]}
{:tag :option, :attrs nil, :content [America/Guadeloupe]}
{:tag :option, :attrs nil, :content [America/Guyana]}
{:tag :option, :attrs nil, :content [America/Halifax]}
{:tag :option, :attrs nil, :content [America/La_Paz]}
{:tag :option, :attrs nil, :content [America/Manaus]}
{:tag :option, :attrs nil, :content [America/Martinique]}
{:tag :option, :attrs nil, :content [America/Moncton]}
{:tag :option, :attrs nil, :content [America/Montserrat]}
{:tag :option, :attrs nil, :content [America/Port_of_Spain]}
{:tag :option, :attrs nil, :content [America/Porto_Velho]}
{:tag :option, :attrs nil, :content [America/Puerto_Rico]}
{:tag :option, :attrs nil, :content [America/Rio_Branco]}
{:tag :option, :attrs nil, :content [America/Santiago]}
{:tag :option, :attrs nil, :content [America/Santo_Domingo]}
{:tag :option, :attrs nil, :content [America/St_Kitts]}
{:tag :option, :attrs nil, :content [America/St_Lucia]}
{:tag :option, :attrs nil, :content [America/St_Thomas]}
{:tag :option, :attrs nil, :content [America/St_Vincent]}
{:tag :option, :attrs nil, :content [America/Thule]}
{:tag :option, :attrs nil, :content [America/Tortola]}
{:tag :option, :attrs nil, :content [Antarctica/Palmer]}
{:tag :option, :attrs nil, :content [Atlantic/Bermuda]}
{:tag :option, :attrs nil, :content [Atlantic/Stanley]}
{:tag :option, :attrs nil, :content [Etc/GMT+4]}
{:tag :option, :attrs nil, :content [America/St_Johns]}
{:tag :option, :attrs nil, :content [America/Araguaina]}
{:tag :option, :attrs nil, :content [America/Argentina/Buenos_Aires]}
{:tag :option, :attrs nil, :content [America/Argentina/Catamarca]}
{:tag :option, :attrs nil, :content [America/Argentina/Cordoba]}
{:tag :option, :attrs nil, :content [America/Argentina/Jujuy]}
{:tag :option, :attrs nil, :content [America/Argentina/La_Rioja]}
{:tag :option, :attrs nil, :content [America/Argentina/Mendoza]}
{:tag :option, :attrs nil, :content [America/Argentina/Rio_Gallegos]}
{:tag :option, :attrs nil, :content [America/Argentina/Salta]}
{:tag :option, :attrs nil, :content [America/Argentina/San_Juan]}
{:tag :option, :attrs nil, :content [America/Argentina/Tucuman]}
{:tag :option, :attrs nil, :content [America/Argentina/Ushuaia]}
{:tag :option, :attrs nil, :content [America/Bahia]}
{:tag :option, :attrs nil, :content [America/Belem]}
{:tag :option, :attrs nil, :content [America/Cayenne]}
{:tag :option, :attrs nil, :content [America/Fortaleza]}
{:tag :option, :attrs nil, :content [America/Godthab]}
{:tag :option, :attrs nil, :content [America/Maceio]}
{:tag :option, :attrs nil, :content [America/Miquelon]}
{:tag :option, :attrs nil, :content [America/Montevideo]}
{:tag :option, :attrs nil, :content [America/Paramaribo]}
{:tag :option, :attrs nil, :content [America/Recife]}
{:tag :option, :attrs nil, :content [America/Santarem]}
{:tag :option, :attrs nil, :content [America/Sao_Paulo]}
{:tag :option, :attrs nil, :content [Antarctica/Rothera]}
{:tag :option, :attrs nil, :content [Etc/GMT+3]}
{:tag :option, :attrs nil, :content [America/Noronha]}
{:tag :option, :attrs nil, :content [Atlantic/South_Georgia]}
{:tag :option, :attrs nil, :content [Etc/GMT+2]}
{:tag :option, :attrs nil, :content [America/Scoresbysund]}
{:tag :option, :attrs nil, :content [Atlantic/Azores]}
{:tag :option, :attrs nil, :content [Atlantic/Cape_Verde]}
{:tag :option, :attrs nil, :content [Etc/GMT+1]}
{:tag :option, :attrs nil, :content [Africa/Abidjan]}
{:tag :option, :attrs nil, :content [Africa/Accra]}
{:tag :option, :attrs nil, :content [Africa/Bamako]}
{:tag :option, :attrs nil, :content [Africa/Banjul]}
{:tag :option, :attrs nil, :content [Africa/Bissau]}
{:tag :option, :attrs nil, :content [Africa/Casablanca]}
{:tag :option, :attrs nil, :content [Africa/Conakry]}
{:tag :option, :attrs nil, :content [Africa/Dakar]}
{:tag :option, :attrs nil, :content [Africa/El_Aaiun]}
{:tag :option, :attrs nil, :content [Africa/Freetown]}
{:tag :option, :attrs nil, :content [Africa/Lome]}
{:tag :option, :attrs nil, :content [Africa/Monrovia]}
{:tag :option, :attrs nil, :content [Africa/Nouakchott]}
{:tag :option, :attrs nil, :content [Africa/Ouagadougou]}
{:tag :option, :attrs nil, :content [Africa/Sao_Tome]}
{:tag :option, :attrs nil, :content [America/Danmarkshavn]}
{:tag :option, :attrs nil, :content [Atlantic/Canary]}
{:tag :option, :attrs nil, :content [Atlantic/Faroe]}
{:tag :option, :attrs nil, :content [Atlantic/Madeira]}
{:tag :option, :attrs nil, :content [Atlantic/Reykjavik]}
{:tag :option, :attrs nil, :content [Atlantic/St_Helena]}
{:tag :option, :attrs nil, :content [Etc/GMT]}
{:tag :option, :attrs nil, :content [Etc/UCT]}
{:tag :option, :attrs nil, :content [Etc/UTC]}
{:tag :option, :attrs nil, :content [Europe/Dublin]}
{:tag :option, :attrs nil, :content [Europe/Lisbon]}
{:tag :option, :attrs nil, :content [Europe/London]}
{:tag :option, :attrs nil, :content [UTC]}
{:tag :option, :attrs nil, :content [WET]}
{:tag :option, :attrs nil, :content [Africa/Algiers]}
{:tag :option, :attrs nil, :content [Africa/Bangui]}
{:tag :option, :attrs nil, :content [Africa/Brazzaville]}
{:tag :option, :attrs nil, :content [Africa/Ceuta]}
{:tag :option, :attrs nil, :content [Africa/Douala]}
{:tag :option, :attrs nil, :content [Africa/Kinshasa]}
{:tag :option, :attrs nil, :content [Africa/Lagos]}
{:tag :option, :attrs nil, :content [Africa/Libreville]}
{:tag :option, :attrs nil, :content [Africa/Luanda]}
{:tag :option, :attrs nil, :content [Africa/Malabo]}
{:tag :option, :attrs nil, :content [Africa/Ndjamena]}
{:tag :option, :attrs nil, :content [Africa/Niamey]}
{:tag :option, :attrs nil, :content [Africa/Porto-Novo]}
{:tag :option, :attrs nil, :content [Africa/Tunis]}
{:tag :option, :attrs nil, :content [Africa/Windhoek]}
{:tag :option, :attrs nil, :content [CET]}
{:tag :option, :attrs nil, :content [Etc/GMT-1]}
{:tag :option, :attrs nil, :content [Europe/Amsterdam]}
{:tag :option, :attrs nil, :content [Europe/Andorra]}
{:tag :option, :attrs nil, :content [Europe/Belgrade]}
{:tag :option, :attrs nil, :content [Europe/Berlin]}
{:tag :option, :attrs nil, :content [Europe/Brussels]}
{:tag :option, :attrs nil, :content [Europe/Budapest]}
{:tag :option, :attrs nil, :content [Europe/Copenhagen]}
{:tag :option, :attrs nil, :content [Europe/Gibraltar]}
{:tag :option, :attrs nil, :content [Europe/Luxembourg]}
{:tag :option, :attrs nil, :content [Europe/Madrid]}
{:tag :option, :attrs nil, :content [Europe/Malta]}
{:tag :option, :attrs nil, :content [Europe/Monaco]}
{:tag :option, :attrs nil, :content [Europe/Oslo]}
{:tag :option, :attrs nil, :content [Europe/Paris]}
{:tag :option, :attrs nil, :content [Europe/Prague]}
{:tag :option, :attrs nil, :content [Europe/Rome]}
{:tag :option, :attrs nil, :content [Europe/Stockholm]}
{:tag :option, :attrs nil, :content [Europe/Tirane]}
{:tag :option, :attrs nil, :content [Europe/Vaduz]}
{:tag :option, :attrs nil, :content [Europe/Vienna]}
{:tag :option, :attrs nil, :content [Europe/Warsaw]}
{:tag :option, :attrs nil, :content [Europe/Zurich]}
{:tag :option, :attrs nil, :content [MET]}
{:tag :option, :attrs nil, :content [Africa/Blantyre]}
{:tag :option, :attrs nil, :content [Africa/Bujumbura]}
{:tag :option, :attrs nil, :content [Africa/Cairo]}
{:tag :option, :attrs nil, :content [Africa/Gaborone]}
{:tag :option, :attrs nil, :content [Africa/Harare]}
{:tag :option, :attrs nil, :content [Africa/Johannesburg]}
{:tag :option, :attrs nil, :content [Africa/Kigali]}
{:tag :option, :attrs nil, :content [Africa/Lubumbashi]}
{:tag :option, :attrs nil, :content [Africa/Lusaka]}
{:tag :option, :attrs nil, :content [Africa/Maputo]}
{:tag :option, :attrs nil, :content [Africa/Maseru]}
{:tag :option, :attrs nil, :content [Africa/Mbabane]}
{:tag :option, :attrs nil, :content [Africa/Tripoli]}
{:tag :option, :attrs nil, :content [Asia/Amman]}
{:tag :option, :attrs nil, :content [Asia/Beirut]}
{:tag :option, :attrs nil, :content [Asia/Damascus]}
{:tag :option, :attrs nil, :content [Asia/Gaza]}
{:tag :option, :attrs nil, :content [Asia/Jerusalem]}
{:tag :option, :attrs nil, :content [Asia/Nicosia]}
{:tag :option, :attrs nil, :content [EET]}
{:tag :option, :attrs nil, :content [Etc/GMT-2]}
{:tag :option, :attrs nil, :content [Europe/Athens]}
{:tag :option, :attrs nil, :content [Europe/Bucharest]}
{:tag :option, :attrs nil, :content [Europe/Chisinau]}
{:tag :option, :attrs nil, :content [Europe/Helsinki]}
{:tag :option, :attrs nil, :content [Europe/Istanbul]}
{:tag :option, :attrs nil, :content [Europe/Kaliningrad]}
{:tag :option, :attrs nil, :content [Europe/Kiev]}
{:tag :option, :attrs nil, :content [Europe/Minsk]}
{:tag :option, :attrs nil, :content [Europe/Riga]}
{:tag :option, :attrs nil, :content [Europe/Simferopol]}
{:tag :option, :attrs nil, :content [Europe/Sofia]}
{:tag :option, :attrs nil, :content [Europe/Tallinn]}
{:tag :option, :attrs nil, :content [Europe/Uzhgorod]}
{:tag :option, :attrs nil, :content [Europe/Vilnius]}
{:tag :option, :attrs nil, :content [Europe/Zaporozhye]}
{:tag :option, :attrs nil, :content [Africa/Addis_Ababa]}
{:tag :option, :attrs nil, :content [Africa/Asmara]}
{:tag :option, :attrs nil, :content [Africa/Dar_es_Salaam]}
{:tag :option, :attrs nil, :content [Africa/Djibouti]}
{:tag :option, :attrs nil, :content [Africa/Kampala]}
{:tag :option, :attrs nil, :content [Africa/Khartoum]}
{:tag :option, :attrs nil, :content [Africa/Mogadishu]}
{:tag :option, :attrs nil, :content [Africa/Nairobi]}
{:tag :option, :attrs nil, :content [Antarctica/Syowa]}
{:tag :option, :attrs nil, :content [Asia/Aden]}
{:tag :option, :attrs nil, :content [Asia/Baghdad]}
{:tag :option, :attrs nil, :content [Asia/Bahrain]}
{:tag :option, :attrs nil, :content [Asia/Kuwait]}
{:tag :option, :attrs nil, :content [Asia/Qatar]}
{:tag :option, :attrs nil, :content [Asia/Riyadh]}
{:tag :option, :attrs nil, :content [Etc/GMT-3]}
{:tag :option, :attrs nil, :content [Europe/Moscow]}
{:tag :option, :attrs nil, :content [Europe/Samara]}
{:tag :option, :attrs nil, :content [Europe/Volgograd]}
{:tag :option, :attrs nil, :content [Indian/Antananarivo]}
{:tag :option, :attrs nil, :content [Indian/Comoro]}
{:tag :option, :attrs nil, :content [Indian/Mayotte]}
{:tag :option, :attrs nil, :content [Asia/Tehran]}
{:tag :option, :attrs nil, :content [Asia/Baku]}
{:tag :option, :attrs nil, :content [Asia/Dubai]}
{:tag :option, :attrs nil, :content [Asia/Muscat]}
{:tag :option, :attrs nil, :content [Asia/Tbilisi]}
{:tag :option, :attrs nil, :content [Asia/Yerevan]}
{:tag :option, :attrs nil, :content [Etc/GMT-4]}
{:tag :option, :attrs nil, :content [Indian/Mahe]}
{:tag :option, :attrs nil, :content [Indian/Mauritius]}
{:tag :option, :attrs nil, :content [Indian/Reunion]}
{:tag :option, :attrs nil, :content [Asia/Kabul]}
{:tag :option, :attrs nil, :content [Antarctica/Mawson]}
{:tag :option, :attrs nil, :content [Asia/Aqtau]}
{:tag :option, :attrs nil, :content [Asia/Aqtobe]}
{:tag :option, :attrs nil, :content [Asia/Ashgabat]}
{:tag :option, :attrs nil, :content [Asia/Dushanbe]}
{:tag :option, :attrs nil, :content [Asia/Karachi]}
{:tag :option, :attrs nil, :content [Asia/Oral]}
{:tag :option, :attrs nil, :content [Asia/Samarkand]}
{:tag :option, :attrs nil, :content [Asia/Tashkent]}
{:tag :option, :attrs nil, :content [Asia/Yekaterinburg]}
{:tag :option, :attrs nil, :content [Etc/GMT-5]}
{:tag :option, :attrs nil, :content [Indian/Kerguelen]}
{:tag :option, :attrs nil, :content [Indian/Maldives]}
{:tag :option, :attrs nil, :content [Asia/Colombo]}
{:tag :option, :attrs nil, :content [Asia/Kolkata]}
{:tag :option, :attrs nil, :content [Asia/Kathmandu]}
{:tag :option, :attrs nil, :content [Antarctica/Vostok]}
{:tag :option, :attrs nil, :content [Asia/Almaty]}
{:tag :option, :attrs nil, :content [Asia/Bishkek]}
{:tag :option, :attrs nil, :content [Asia/Dhaka]}
{:tag :option, :attrs nil, :content [Asia/Novokuznetsk]}
{:tag :option, :attrs nil, :content [Asia/Novosibirsk]}
{:tag :option, :attrs nil, :content [Asia/Omsk]}
{:tag :option, :attrs nil, :content [Asia/Qyzylorda]}
{:tag :option, :attrs nil, :content [Asia/Thimphu]}
{:tag :option, :attrs nil, :content [Etc/GMT-6]}
{:tag :option, :attrs nil, :content [Indian/Chagos]}
{:tag :option, :attrs nil, :content [Asia/Rangoon]}
{:tag :option, :attrs nil, :content [Indian/Cocos]}
{:tag :option, :attrs nil, :content [Antarctica/Davis]}
{:tag :option, :attrs nil, :content [Asia/Bangkok]}
{:tag :option, :attrs nil, :content [Asia/Ho_Chi_Minh]}
{:tag :option, :attrs nil, :content [Asia/Hovd]}
{:tag :option, :attrs nil, :content [Asia/Jakarta]}
{:tag :option, :attrs nil, :content [Asia/Krasnoyarsk]}
{:tag :option, :attrs nil, :content [Asia/Phnom_Penh]}
{:tag :option, :attrs nil, :content [Asia/Pontianak]}
{:tag :option, :attrs nil, :content [Asia/Vientiane]}
{:tag :option, :attrs nil, :content [Etc/GMT-7]}
{:tag :option, :attrs nil, :content [Indian/Christmas]}
{:tag :option, :attrs nil, :content [Antarctica/Casey]}
{:tag :option, :attrs nil, :content [Asia/Brunei]}
{:tag :option, :attrs nil, :content [Asia/Choibalsan]}
{:tag :option, :attrs nil, :content [Asia/Chongqing]}
{:tag :option, :attrs nil, :content [Asia/Harbin]}
{:tag :option, :attrs nil, :content [Asia/Hong_Kong]}
{:tag :option, :attrs nil, :content [Asia/Irkutsk]}
{:tag :option, :attrs nil, :content [Asia/Kashgar]}
{:tag :option, :attrs nil, :content [Asia/Kuala_Lumpur]}
{:tag :option, :attrs nil, :content [Asia/Kuching]}
{:tag :option, :attrs nil, :content [Asia/Macau]}
{:tag :option, :attrs nil, :content [Asia/Makassar]}
{:tag :option, :attrs nil, :content [Asia/Manila]}
{:tag :option, :attrs nil, :content [Asia/Shanghai]}
{:tag :option, :attrs nil, :content [Asia/Singapore]}
{:tag :option, :attrs nil, :content [Asia/Taipei]}
{:tag :option, :attrs nil, :content [Asia/Ulaanbaatar]}
{:tag :option, :attrs nil, :content [Asia/Urumqi]}
{:tag :option, :attrs nil, :content [Australia/Perth]}
{:tag :option, :attrs nil, :content [Etc/GMT-8]}
{:tag :option, :attrs nil, :content [Australia/Eucla]}
{:tag :option, :attrs nil, :content [Asia/Dili]}
{:tag :option, :attrs nil, :content [Asia/Jayapura]}
{:tag :option, :attrs nil, :content [Asia/Pyongyang]}
{:tag :option, :attrs nil, :content [Asia/Seoul]}
{:tag :option, :attrs nil, :content [Asia/Tokyo]}
{:tag :option, :attrs nil, :content [Asia/Yakutsk]}
{:tag :option, :attrs nil, :content [Etc/GMT-9]}
{:tag :option, :attrs nil, :content [Pacific/Palau]}
{:tag :option, :attrs nil, :content [Australia/Adelaide]}
{:tag :option, :attrs nil, :content [Australia/Broken_Hill]}
{:tag :option, :attrs nil, :content [Australia/Darwin]}
{:tag :option, :attrs nil, :content [Antarctica/DumontDUrville]}
{:tag :option, :attrs nil, :content [Asia/Sakhalin]}
{:tag :option, :attrs nil, :content [Asia/Vladivostok]}
{:tag :option, :attrs nil, :content [Australia/Brisbane]}
{:tag :option, :attrs nil, :content [Australia/Currie]}
{:tag :option, :attrs nil, :content [Australia/Hobart]}
{:tag :option, :attrs nil, :content [Australia/Lindeman]}
{:tag :option, :attrs nil, :content [Australia/Melbourne]}
{:tag :option, :attrs nil, :content [Australia/Sydney]}
{:tag :option, :attrs nil, :content [Etc/GMT-10]}
{:tag :option, :attrs nil, :content [Pacific/Chuuk]}
{:tag :option, :attrs nil, :content [Pacific/Guam]}
{:tag :option, :attrs nil, :content [Pacific/Port_Moresby]}
{:tag :option, :attrs nil, :content [Pacific/Saipan]}
{:tag :option, :attrs nil, :content [Australia/Lord_Howe]}
{:tag :option, :attrs nil, :content [Antarctica/Macquarie]}
{:tag :option, :attrs nil, :content [Asia/Anadyr]}
{:tag :option, :attrs nil, :content [Asia/Kamchatka]}
{:tag :option, :attrs nil, :content [Asia/Magadan]}
{:tag :option, :attrs nil, :content [Etc/GMT-11]}
{:tag :option, :attrs nil, :content [Pacific/Efate]}
{:tag :option, :attrs nil, :content [Pacific/Guadalcanal]}
{:tag :option, :attrs nil, :content [Pacific/Kosrae]}
{:tag :option, :attrs nil, :content [Pacific/Noumea]}
{:tag :option, :attrs nil, :content [Pacific/Pohnpei]}
{:tag :option, :attrs nil, :content [Pacific/Norfolk]}
{:tag :option, :attrs nil, :content [Antarctica/McMurdo]}
{:tag :option, :attrs nil, :content [Etc/GMT-12]}
{:tag :option, :attrs nil, :content [Pacific/Auckland]}
{:tag :option, :attrs nil, :content [Pacific/Fiji]}
{:tag :option, :attrs nil, :content [Pacific/Funafuti]}
{:tag :option, :attrs nil, :content [Pacific/Kwajalein]}
{:tag :option, :attrs nil, :content [Pacific/Majuro]}
{:tag :option, :attrs nil, :content [Pacific/Nauru]}
{:tag :option, :attrs nil, :content [Pacific/Tarawa]}
{:tag :option, :attrs nil, :content [Pacific/Wake]}
{:tag :option, :attrs nil, :content [Pacific/Wallis]}
{:tag :option, :attrs nil, :content [Pacific/Chatham]}
{:tag :option, :attrs nil, :content [Etc/GMT-13]}
{:tag :option, :attrs nil, :content [Pacific/Enderbury]}
{:tag :option, :attrs nil, :content [Pacific/Tongatapu]}
{:tag :option, :attrs nil, :content [Etc/GMT-14]}
{:tag :option, :attrs nil, :content [Pacific/Kiritimati]}
]}
]}
{:tag :label, :attrs {:for nest-pin}, :content [
nest pin
{:tag :input, :attrs {:id nest-pin, :name nest-pin}, :content []}
]}
{:tag :div, :attrs {:id nest-pin-retrieval}, :content [
{:tag :p, :attrs nil, :content [
Follow the link below and log in to Nest. Paste the PIN number that is
shown on the screen into the field above
]}
{:tag :a, :attrs {:target _blank, :href https://home.nest.com/login/oauth2?client_id=nest-client-id&state=fnCLwYer}, :content [
nest authorization
]}
]}
{:tag :input, :attrs {:value submit, :id submit, :type submit}, :content []}
]}
]}
]}
]}], :app #<middleware$wrap_internal_error$fn__10094 ask_nest.middleware$wrap_internal_error$fn__10094@602ec0dc>, :content-type nil, :cookie-jar {localhost {ring-session {:http-only true, :raw ring-session=eee00742-3b90-45c0-86ef-071287b29443, :domain localhost, :path /, :value eee00742-3b90-45c0-86ef-071287b29443}}}}
ERROR in (user-record-created-on-signup) (impl.clj:50)
Uncaught exception, not in assertion.
expected: nil
actual: java.lang.IllegalArgumentException: field could not be found with selector "timezone"
at kerodon.impl$not_found.invoke (impl.clj:50)
kerodon.impl$form_element.invoke (impl.clj:80)
kerodon.impl$form_element_query.invoke (impl.clj:112)
kerodon.impl$choose_value.invoke (impl.clj:199)
kerodon.core$choose.invoke (core.clj:25)
ask_nest.integration.new_user_test/fn (new_user_test.clj:18)
clojure.test$test_var$fn__7187.invoke (test.clj:704)
clojure.test$test_var.invoke (test.clj:704)
clojure.test$test_vars$fn__7209$fn__7214.invoke (test.clj:722)
ask_nest.integration.new_user_test$eval22126$fn__22127.invoke (new_user_test.clj:13)
clojure.test$compose_fixtures$fn__7181$fn__7182.invoke (test.clj:681)
clojure.test$default_fixture.invoke (test.clj:674)
clojure.test$compose_fixtures$fn__7181.invoke (test.clj:681)
clojure.test$test_vars$fn__7209.invoke (test.clj:722)
ask_nest.integration.new_user_test$eval22122$fn__22123.invoke (new_user_test.clj:12)
clojure.test$compose_fixtures$fn__7181$fn__7182.invoke (test.clj:681)
clojure.test$default_fixture.invoke (test.clj:674)
clojure.test$compose_fixtures$fn__7181.invoke (test.clj:681)
clojure.test$test_vars.invoke (test.clj:718)
clojure.test$test_all_vars.invoke (test.clj:728)
clojure.test$test_ns.invoke (test.clj:747)
clojure.core$map$fn__4245.invoke (core.clj:2559)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.Cons.next (Cons.java:39)
clojure.lang.RT.boundedLength (RT.java:1654)
clojure.lang.RestFn.applyTo (RestFn.java:130)
clojure.core$apply.invoke (core.clj:626)
clojure.test$run_tests.doInvoke (test.clj:762)
clojure.lang.RestFn.invoke (RestFn.java:408)
ask_nest.core$eval22140.invoke (form-init4673959029001529348.clj:1)
clojure.lang.Compiler.eval (Compiler.java:6703)
clojure.lang.Compiler.eval (Compiler.java:6666)
clojure.core$eval.invoke (core.clj:2927)
clojure.main$repl$read_eval_print__6625$fn__6628.invoke (main.clj:239)
clojure.main$repl$read_eval_print__6625.invoke (main.clj:239)
clojure.main$repl$fn__6634.invoke (main.clj:257)
clojure.main$repl.doInvoke (main.clj:257)
clojure.lang.RestFn.invoke (RestFn.java:1523)
clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__10799.invoke (interruptible_eval.clj:72)
clojure.lang.AFn.applyToHelper (AFn.java:152)
clojure.lang.AFn.applyTo (AFn.java:144)
clojure.core$apply.invoke (core.clj:624)
clojure.core$with_bindings_STAR_.doInvoke (core.clj:1862)
clojure.lang.RestFn.invoke (RestFn.java:425)
clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invoke (interruptible_eval.clj:56)
clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__10841$fn__10844.invoke (interruptible_eval.clj:191)
clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__10836.invoke (interruptible_eval.clj:159)
clojure.lang.AFn.run (AFn.java:22)
java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1142)
java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:617)
java.lang.Thread.run (Thread.java:745)
Ran 1 tests containing 1 assertions.
0 failures, 1 errors.
{:type :summary, :fail 0, :error 1, :pass 0, :test 1}
I have a form with multiple inputs sharing the name "members[]"
so that their values will be collected into a vector when the form data is received by ring. I found that when I use fill-in
to fill in one of those inputs (using a selector specific to that one), Kerodon was filling in all of the inputs, not just the one. This turned out to be because impl/field-to-selector
matches by :name
instead of using the more specific selector I had provided.
I can work around this by providing a unique id for each of the inputs (impl/field-to-selector
checks for :id
before going to :name
). However, is there some reason why we can't match inputs with any arbitrary selector?
The project.clj should have profiles with the 1.4 release, and possibly 1.5.0-alpha3.
Looks like the dependency org.flatland/ordered
is required for tests to succeed with Clojure older than 1.7.
If this support is dropped, Kerodon would no longer need its single use of ordered-map
and the dependency could be dropped.
Hi,
Thanks for all of your great work - I'm finding Kerodon really useful!
I just wondered if you have any plans to push a version to Clojars in the near future? The "Browser-like treatment of whitespace in text" in particular is something I'm really to get my hands on.
thanks
Gary
Although it appears that this commit added support for for
-less labels, it's not working for me on version 0.5.0.
Does not work:
<label>Username
<input id="username" type="text" autocomplete="nickname" name="username" autofocus required maxlength="50" value="{{username}}">
</label>
Does work:
<label for="username">Username</label>
<input id="username" type="text" autocomplete="nickname" name="username" autofocus required maxlength="50" value="{{username}}">
Based on the current API, to maintain symmetry, this would probably need a function called (unchoose)
Alternatively, (choose)
could be a toggle action on <select multiple>
Can I use Kerodon for a non ring app? To test a external black box webapp...
Let me know if I'm missing something, but it looks like that press
is working only with <input type="submit">
and not with <button>
. Is there a way to interact with buttons?
Thanks.
I am using the current 0.6.0-SNAPSHOT release.
When I use (kerodon.core/follow "Logout")
I get the following exception:
I also created a pastebin http://pastebin.com/dzQQu5ts with the testing code, the stacktrace and the current state.
1. Unhandled java.lang.ClassCastException
clojure.lang.PersistentStructMap cannot be cast to java.lang.CharSequence
string.clj: 236 clojure.string/trim
core.clj: 2557 clojure.core/map/fn
LazySeq.java: 40 clojure.lang.LazySeq/sval
LazySeq.java: 49 clojure.lang.LazySeq/seq
LazySeq.java: 115 clojure.lang.LazySeq/equals
LazySeq.java: 100 clojure.lang.LazySeq/equiv
Util.java: 124 clojure.lang.Util/pcequiv
Util.java: 32 clojure.lang.Util/equiv
impl.clj: 30 kerodon.impl/css-or-content/fn
enlive_html.clj: 241 net.cgrand.enlive-html/pred/fn
enlive_html.clj: 236 net.cgrand.enlive-html/zip-pred/fn
enlive_html.clj: 282 net.cgrand.enlive-html/intersection/fn
enlive_html.clj: 329 net.cgrand.enlive-html/predset/fn
core.clj: 2403 clojure.core/comp/fn
enlive_html.clj: 390 net.cgrand.enlive-html/step
enlive_html.clj: 497 net.cgrand.enlive-html/zip-select-nodes*/select1
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1/fn
core.clj: 2559 clojure.core/map/fn
LazySeq.java: 40 clojure.lang.LazySeq/sval
LazySeq.java: 49 clojure.lang.LazySeq/seq
RT.java: 484 clojure.lang.RT/seq
core.clj: 133 clojure.core/seq
core.clj: 624 clojure.core/apply
core.clj: 2586 clojure.core/mapcat
RestFn.java: 423 clojure.lang.RestFn/invoke
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1/fn
core.clj: 2559 clojure.core/map/fn
LazySeq.java: 40 clojure.lang.LazySeq/sval
LazySeq.java: 49 clojure.lang.LazySeq/seq
RT.java: 484 clojure.lang.RT/seq
core.clj: 133 clojure.core/seq
core.clj: 624 clojure.core/apply
core.clj: 2586 clojure.core/mapcat
RestFn.java: 423 clojure.lang.RestFn/invoke
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1/fn
core.clj: 2559 clojure.core/map/fn
LazySeq.java: 40 clojure.lang.LazySeq/sval
LazySeq.java: 49 clojure.lang.LazySeq/seq
RT.java: 484 clojure.lang.RT/seq
core.clj: 133 clojure.core/seq
core.clj: 624 clojure.core/apply
core.clj: 2586 clojure.core/mapcat
RestFn.java: 423 clojure.lang.RestFn/invoke
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1/fn
core.clj: 2559 clojure.core/map/fn
LazySeq.java: 40 clojure.lang.LazySeq/sval
LazySeq.java: 49 clojure.lang.LazySeq/seq
Cons.java: 39 clojure.lang.Cons/next
RT.java: 1654 clojure.lang.RT/boundedLength
RestFn.java: 130 clojure.lang.RestFn/applyTo
core.clj: 624 clojure.core/apply
core.clj: 2586 clojure.core/mapcat
RestFn.java: 423 clojure.lang.RestFn/invoke
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1/fn
core.clj: 2559 clojure.core/map/fn
LazySeq.java: 40 clojure.lang.LazySeq/sval
LazySeq.java: 49 clojure.lang.LazySeq/seq
RT.java: 484 clojure.lang.RT/seq
core.clj: 133 clojure.core/seq
core.clj: 624 clojure.core/apply
core.clj: 2586 clojure.core/mapcat
RestFn.java: 423 clojure.lang.RestFn/invoke
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1/fn
core.clj: 2559 clojure.core/map/fn
LazySeq.java: 40 clojure.lang.LazySeq/sval
LazySeq.java: 49 clojure.lang.LazySeq/seq
Cons.java: 39 clojure.lang.Cons/next
RT.java: 1654 clojure.lang.RT/boundedLength
RestFn.java: 130 clojure.lang.RestFn/applyTo
core.clj: 624 clojure.core/apply
core.clj: 2586 clojure.core/mapcat
RestFn.java: 423 clojure.lang.RestFn/invoke
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1/fn
core.clj: 2559 clojure.core/map/fn
LazySeq.java: 40 clojure.lang.LazySeq/sval
LazySeq.java: 49 clojure.lang.LazySeq/seq
Cons.java: 39 clojure.lang.Cons/next
RT.java: 1654 clojure.lang.RT/boundedLength
RestFn.java: 130 clojure.lang.RestFn/applyTo
core.clj: 624 clojure.core/apply
core.clj: 2586 clojure.core/mapcat
RestFn.java: 423 clojure.lang.RestFn/invoke
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1/fn
core.clj: 2559 clojure.core/map/fn
LazySeq.java: 40 clojure.lang.LazySeq/sval
LazySeq.java: 49 clojure.lang.LazySeq/seq
Cons.java: 39 clojure.lang.Cons/next
RT.java: 1654 clojure.lang.RT/boundedLength
RestFn.java: 130 clojure.lang.RestFn/applyTo
core.clj: 624 clojure.core/apply
core.clj: 2586 clojure.core/mapcat
RestFn.java: 423 clojure.lang.RestFn/invoke
enlive_html.clj: 498 net.cgrand.enlive-html/zip-select-nodes*/select1
enlive_html.clj: 500 net.cgrand.enlive-html/zip-select-nodes*/fn
core.clj: 2559 clojure.core/map/fn
LazySeq.java: 40 clojure.lang.LazySeq/sval
LazySeq.java: 49 clojure.lang.LazySeq/seq
RT.java: 484 clojure.lang.RT/seq
core.clj: 133 clojure.core/seq
core.clj: 624 clojure.core/apply
core.clj: 2586 clojure.core/mapcat
RestFn.java: 423 clojure.lang.RestFn/invoke
enlive_html.clj: 500 net.cgrand.enlive-html/zip-select-nodes*
enlive_html.clj: 504 net.cgrand.enlive-html/select-nodes*
enlive_html.clj: 543 net.cgrand.enlive-html/select
impl.clj: 83 kerodon.impl/link
impl.clj: 213 kerodon.impl/find-url
core.clj: 19 kerodon.core/follow
acceptance_test.clj: 66 web.acceptance-test/fn
test.clj: 704 clojure.test/test-var/fn
test.clj: 704 clojure.test/test-var
test.clj: 124 cider.nrepl.middleware.test/test-vars/fn/fn
test_data.clj: 215 clj-demgen.test-data/with-test-data
test.clj: 681 clojure.test/compose-fixtures/fn/fn
acceptance_test.clj: 23 web.acceptance-test/with-test-system
test.clj: 681 clojure.test/compose-fixtures/fn/fn
test.clj: 674 clojure.test/default-fixture
test.clj: 681 clojure.test/compose-fixtures/fn
test.clj: 681 clojure.test/compose-fixtures/fn
test.clj: 124 cider.nrepl.middleware.test/test-vars/fn
test_data.clj: 29 clj-demgen.test-data/with-test-home-folder
test.clj: 681 clojure.test/compose-fixtures/fn/fn
test.clj: 674 clojure.test/default-fixture
test.clj: 681 clojure.test/compose-fixtures/fn
test.clj: 120 cider.nrepl.middleware.test/test-vars
test.clj: 139 cider.nrepl.middleware.test/test-ns
test.clj: 161 cider.nrepl.middleware.test/handle-test/fn
AFn.java: 152 clojure.lang.AFn/applyToHelper
AFn.java: 144 clojure.lang.AFn/applyTo
core.clj: 624 clojure.core/apply
core.clj: 1862 clojure.core/with-bindings*
RestFn.java: 425 clojure.lang.RestFn/invoke
test.clj: 159 cider.nrepl.middleware.test/handle-test
test.clj: 200 cider.nrepl.middleware.test/wrap-test/fn
Using (kerodon.core/follow :#id-of-logout-link)
works fine btw. The link is present on the page.
One thing I noticed we're not doing that browsers do.
At the moment, inputs "reset", "button" and "submit" will all be treated as "text", which could cause some unexpected results.
I believe the spec says "reset" and "button" are never considered successful, and that if there are multiple submit buttons, only the one pressed should be considered successful.
Can't work out what I'm doing wrong here:
Code: (press :.next-swirls)
Error: java.lang.IllegalArgumentException: button could not be found with selector ":.next-swirls"
Print from the session:
{:tag :div, :attrs {:class paging}, :content (
{:tag :button, :attrs {:class previous-swirls}, :content (< Previous 20 Swirls)}
{:tag :button, :attrs {:class next-swirls}, :content (Next 20 Swirls >)}
)}
Html:
<div class="paging">
<button class="previous-swirls">< Previous 20 Swirls</button>
<button class="next-swirls">Next 20 Swirls ></button>
</div>
Note I have tried:
Using ID:
(press [:#next-swirls])
With and without [](press :#next-swirls)
(press [:#next-swirls])
(press .next-swirls)
(press [.next-swirls])
This isn't technically due to kerodon, but kerodon provides the status?
function, so I'm starting here. Looking into this, I realized that the response created by Peridot doesn't have a :status
when I try to use just Peridot. Peridot uses ring-mock
, and that is what is giving us the response from the app handler. Again, trying to just use ring-mock directly, I see that its response doesn't contain :status
or :headers
keys.
Has anyone else run into this?
I have a problem with Kerodon tests when they go through 2 forms that use ring-anti-forgery. This is what happens:
If I however skip step 1. and go to the second page with a form directly, I don't get the error.
I didn't notice this happening in production environment.
Thanks.
Some of my Kerodon tests fail with anti-forgery error.
I suspect it's related to how the URLs are built (http://localhost:2000/my-url vs /my-url) before visiting them.
xeqi/peridot@4cb7747
But anyway, this is solved by bumping the Peridot dependency to version 0.5.4.
(First of all, thanks for writing this useful little library. 😄 I'm attempting to evangelize Clojure among some colleagues who are more accustomed to Rails and browser tests, and I think this library will serve as a nice bridge so that things aren't quite as alien to them.)
I've been learning kerodon and attempting to use it on a simple app. Once I figured out that selectors were mostly enlive selectors (and after I learned those), a lot of things clicked into place. But then I tried using a selector of this sort: [:.parent :.child]
, and it didn't work. It took me a while to understand why: the selector I supply is placed in a context of a larger enlive selector that begins with :form
, like so: [:form [:.parent :.child]]
. As an enlive selector, this means "find a node with both the parent
and child
classes under a <form>
tag". That's not what I wanted, and sadly, there's no way to support such a selector given the implicit context it's put in. I've provided code for a simple test case below.
I have 2 ideas for how to address this. I'll start with the more ambitious.
We could define the interpretation of a selector value to be dependent on its type. If it's:
(1) involves no change to the semantics. (2) and (3) drop the implicit "parent form" context. (2) goes further: users who are using vector to mean "find a node that matches all the criteria specified in this vector" will have to wrap their vectors in another vector to achieve the same semantics. This is annoying and a bit noisy, but it provides a good deal of flexibility for more complex use cases. Plus, the clarity of the definition will (I believe) make it easier for people to learn and use kerodon.
But, this would definitely be a significant breaking change. Given that this is Clojure and our primary thought leader exhorts a rather strict no-breakage approach to change, I suspect that this proposal will not be palatable, even if it went along with a major version bump to 1.0. So:
If a selector is tagged with :kerodon.core/literal-selector
metadata equal to true
, it is interpreted as a literal selector, which means it's neither wrapped in additional vectors nor assumed to be within a "parent form" context. Rather, it's used literally, with no transformations between it and the enlive/select
call. Then, if kerodon.core
is aliased to k
, I could say ^:k/literal-selector [:.parent :.child]
to solve my use case above.
This would be a growth-only change, keeping all existing kerodon uses the same. However, it would require more complexity to accomplish.
(Thanks for bearing with me so far…I know it's long.)
So my question is: are you amenable to either of these proposals? If so, I think I will have some cycles to work on implementation. If not, that's totally cool, and I still thank you for the library. 😄 Maybe I could do this in a fork instead.
Here's an example use case and test case (to be added to the kerodon.unit.impl
namespace):
(defn checked-form-produces [fields-html check-selector expected]
(let [html (str "<form action=/>"
fields-html
"<input type=submit value=Submit>"
"</form>")
enlive (to-html-resource html)
state (check-box {:enlive enlive} check-selector)
parsed (build-request-details state "Submit")
details (apply hash-map :url parsed)]
(is (= expected (:params details)))))
(deftest test-form-element-query
(let [html (str "<div id=broccoli>"
" <label>"
" <input class=yes type=radio name=broccoli value=yes /> Yes"
" </label>"
" <label>"
" <input class=no type=radio name=broccoli value=no /> No"
" </label>"
"</div>"
"<div id=cauliflower>"
" <label>"
" <input class=yes type=radio name=cauliflower value=yes /> Yes"
" </label>"
" <label>"
" <input class=no type=radio name=cauliflower value=no /> No"
" </label>"
"</div>")]
(checked-form-produces html [:div#broccoli :input.yes] {"broccoli" "yes"})
(checked-form-produces html [:div#broccoli :input.no] {"broccoli" "no"})
(checked-form-produces html [:div#cauliflower :input.yes] {"cauliflower" "yes"})
(checked-form-produces html [:div#cauliflower :input.no] {"cauliflower" "no"})))
Note that not even within
can address this use case in the current implementation. I could say something like (within :div#broccoli (check :input.yes))
, but that won't be found because it's implicitly looking for a [:form :input.yes]
inside the div.
(Yes, I realize that with the existing approach I can say [:input.yes (enlive/attr= "name" "broccoli")]
to select the input. The problems with that are (1) this is an undocumented (and maybe not-officially-supported?) way to leverage enlive for a selector, (2) you have to require the enlive library in your project, (3) it's a lot to explain to people like my colleagues who will be learning the library.)
Hi there.
I'm having problem with GET params in the URI. When testing the app with visit
, the app doesn't receive the GET params:
(-> (session app)
(visit "/guy" :params {"key" "guyskey"}))
;; or the equivalent
(-> (session app)
(visit "/guy?key=guyskey"))
In both cases the :query-string
is "key=guyskey"
, but the app doesn't receive those values.
I also get this error when using follow redirect:
(deftest site-navegation-test
(-> (session app)
(visit "/")
(fill-in :#key "André")
(press "Buscar atleta")
(follow-redirect)))
Uncaught exception, not in assertion.
expected: nil
actual: java.lang.IllegalArgumentException: Previous response was not a redirect
at peridot.core$follow_redirect.invoke (core.clj:59)
kerodon.core$follow_redirect.invoke (core.clj:16)
...
Is there anything I'm doing wrong?
I'd like to use kerodon from a test framework other than clojure.test
. It'd be nice to have functions similar to text?
, status?
, value?
etc which simply returned the text, status, or value of the node. That way, I could make my assertions using whatever assertion/test library I want.
For example, using speclj, I would want to be able to write
(should= (attr session [:form] :id) "my-form")
or using midje,
((attr session [:form] :id) => "my-form")
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.