Question

I am trying to write Webdriver checks using Clojure. If I was using an object oriented language, I would use the Page Object Pattern. I think modeling a page as an object makes sense, I could create some java classes for the page objects and all would be well.

I want to know if there are any alternatives to the page object pattern using a functional style that maintain the same level of clarity.

Was it helpful?

Solution

A page (especially a RESTful one), can be thought of as a function from request to render (and, if you want to take the next step, the render exposes some set of new requests).

The translation from sending a request to page to applying a function to arguments is simple, and also quite comprehensive.

If you are providing a complex webapp, try taking a functional view of requests. GET can retrieve data, but should not modify server side state, use PUT to create a resource, use POST for mutation.

Once you write your controllers in this way, you can do quite a bit of testing without webdrivers. It should mostly suffice to provide a mockup of the request input to the controller, and verify some properties of the rendered result (for GET) or the storage state (for POST AND PUT).

I have even found it useful to break off request parsing and rendering into separate functions, in order to simplify the testing of the data processing that should happen in the middle, ie.:

(defn parse-home
  [request]
  (let [user-id (-> request :params :session :id)
        account (get-user user-id)]
    {:user-id user-id
     :account account}))

(defn do-home
  [user-id account]
  (let [messages (get-messages account)
        feed (generate-feed user-id)]
    (update-user user-id :last-visited (java.util.Date.))
    {:messages messages
     :feed feed}))

(defn render-home
  [request messages feed account]
  (let [messages (mapv summarize (filter important messages))
        feed  (sort-by :priority feed)
        template (-> request :page :template)]
    (render template (assoc request :data {:messages messages :feed feed :account account}))))

(defn home
   [request]
   (let [{:keys [user-id account]} (parse-home request)
         {:keys [messages feed]} (do-home user-id account)
         body (render-home request messages feed account)]
     {:status 200
      :content-type "text/html"
      :body body}))

Each element of the home page logic can be verified by providing one of these functions with the right input, and verifying some properties of the output. There is no need to mock up state or simulate page interaction unless you are also using clojurescript on the front end (and even in that case the logic you want to verify can be abstracted from the interface of the browser to avoid the need for replay testing).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top