From ed060e55b662d883e780f3f3fe5ffe303fd970a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20Schl=C3=BCter?= Date: Wed, 30 May 2018 14:45:11 +0200 Subject: [PATCH] Add tests for auth process --- README.md | 2 ++ src/cljs/airsonic_ui/db.cljs | 3 +- src/cljs/airsonic_ui/events.cljs | 42 ++++++++++++++------------ src/cljs/airsonic_ui/subs.cljs | 2 +- test/cljs/airsonic_ui/events_test.cljs | 28 +++++++++++++++++ 5 files changed, 54 insertions(+), 23 deletions(-) create mode 100644 test/cljs/airsonic_ui/events_test.cljs diff --git a/README.md b/README.md index 07ae2ea..c610beb 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ This project uses [karma](https://karma-runner.github.io/) for tests. Make sure $ npm test ``` +**Note:** If you want nice console output in your tests, make sure to `(enable-console-print!)`. You can call `println` afterwards like you're used to. + ## Build artifacts diff --git a/src/cljs/airsonic_ui/db.cljs b/src/cljs/airsonic_ui/db.cljs index 16f6fd5..7f3b701 100644 --- a/src/cljs/airsonic_ui/db.cljs +++ b/src/cljs/airsonic_ui/db.cljs @@ -2,6 +2,5 @@ (:require [airsonic-ui.routes :as routes])) (def default-db - {:active-requests 0 - ;; because navigate! executes asynchronously we force to display the login screen first + {;; because navigate! executes asynchronously we force to display the login screen first :current-route [routes/default-route]}) diff --git a/src/cljs/airsonic_ui/events.cljs b/src/cljs/airsonic_ui/events.cljs index 0c46fef..4e91a91 100644 --- a/src/cljs/airsonic_ui/events.cljs +++ b/src/cljs/airsonic_ui/events.cljs @@ -18,31 +18,33 @@ (fn [_] db/default-db)) -;; this is called with user and password to try and see if the credentials are -;; correct; if yes, ::auth-success will be fired +;; auth logic + +(defn authenticate + "Tries to authenticate a user by pinging the server with credentials, saving + them when the request was succesful." + [{:keys [db]} [_ user pass server]] + {:db (assoc db :server server) + :http-xhrio {:method :get + :uri (api/url server "ping" {:u user :p pass}) + :response-format (ajax/json-response-format {:keywords? true}) + :on-success [::credentials-verified user pass] + :on-failure [::api-failure]}}) (re-frame/reg-event-fx - ::authenticate - (fn [{:keys [db]} [_ user pass server]] - {:db (-> (update db :active-requests inc) - (assoc :server server)) - :http-xhrio {:method :get - :uri (api/url server "ping" {:u user :p pass}) - :response-format (ajax/json-response-format {:keywords? true}) - :on-success [::auth-success user pass] - :on-failure [::api-failure]}})) + ::authenticate authenticate) -;; TODO: Test that credentials are associated +(defn credentials-verified + "Gets called after the server indicates that the credentials entered by a user + are correct (see `authenticate`)." + [{:keys [db]} [_ user pass response]] + (let [login {:u user :p pass}] + {:routes/set-credentials login + :db (assoc db :login login) + :dispatch [::logged-in]})) (re-frame/reg-event-fx - ::auth-success - (fn [{:keys [db]} [_ user pass response]] - ;; TODO: Handle failures differently - (let [login {:u user :p pass}] - {:routes/set-credentials login - :db (-> (update db :active-requests #(max (dec %) 0)) - (assoc :login login)) - :dispatch [::logged-in]}))) + ::credentials-verified credentials-verified) ;; TODO: We have to find another solution for this once we have routes that ;; don't require a login but have the bottom controls diff --git a/src/cljs/airsonic_ui/subs.cljs b/src/cljs/airsonic_ui/subs.cljs index 1891d2d..9d31228 100644 --- a/src/cljs/airsonic_ui/subs.cljs +++ b/src/cljs/airsonic_ui/subs.cljs @@ -2,8 +2,8 @@ (:require [re-frame.core :as re-frame])) ;; can be used to query the user's credentials -;; TODO: Organize login credentials and server location differently (i.e. together) +;; FIXME: this is used for cover images and it's quite ugly tbh (re-frame/reg-sub ::login (fn [db] diff --git a/test/cljs/airsonic_ui/events_test.cljs b/test/cljs/airsonic_ui/events_test.cljs new file mode 100644 index 0000000..1debe49 --- /dev/null +++ b/test/cljs/airsonic_ui/events_test.cljs @@ -0,0 +1,28 @@ +(ns airsonic-ui.events-test + (:require [cljs.test :refer [deftest testing is]] + [clojure.string :as str] + [airsonic-ui.events :as events])) + +(enable-console-print!) + +(deftest authentication + (testing "Credential verification" + (let [server "https://localhost" + fx (events/authenticate {:db {}} [:_ "user" "pass" server]) + request (:http-xhrio fx)] + (testing "uses correct server url" + (is (str/starts-with? (:uri request) server)) + (is (str/includes? (:uri request) "/ping"))) + (testing "saves the given server location" + (is (= server (get-in fx [:db :server])))) + (testing "invokes correct success callback" + (is (= ::events/credentials-verified (first (:on-success request))))))) + (testing "On succesfull response" + (let [fx (events/credentials-verified {:db {}} [:_ "user" "pass"]) + credentials {:u "user" :p "pass"}] + (testing "credentials are sent to the router for access rights" + (is (= credentials (:routes/set-credentials fx)))) + (testing "credentials are saved in the global state" + (is (= credentials (get-in fx [:db :login])))) + (testing "the login process is finalized" + (is (= [::events/logged-in] (:dispatch fx)))))))