0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-20 19:51:23 -05:00

🎉 Add frontend tests for files and events that manage shapes

This commit is contained in:
Andrés Moya 2021-01-19 15:15:17 +01:00 committed by Andrey Antukh
parent 0cfb66ae16
commit 686814f537
5 changed files with 201 additions and 54 deletions

View file

@ -146,6 +146,10 @@
shapes (remove #(= (:type %) :frame) (vals objects))]
(some contains-shape-fn shapes)))
(defn get-top-frame
[objects]
(get objects uuid/zero))
(defn get-parent
"Retrieve the id of the parent for the shape-id (if exists)"
[shape-id objects]

View file

@ -12,6 +12,7 @@
[app.common.exceptions :as ex]
[app.common.geom.point :as gpt]
[app.util.object :as obj]
[app.util.globals :as globals]
[cuerdas.core :as str]
[goog.dom :as dom]))
@ -130,9 +131,9 @@
(defn create-element
([tag]
(.createElement js/document tag))
(.createElement globals/document tag))
([ns tag]
(.createElementNS js/document ns tag)))
(.createElementNS globals/document ns tag)))
(defn set-html!
[el html]
@ -201,11 +202,11 @@
(defn fullscreen?
[]
(cond
(obj/in? js/document "webkitFullscreenElement")
(boolean (.-webkitFullscreenElement js/document))
(obj/in? globals/document "webkitFullscreenElement")
(boolean (.-webkitFullscreenElement globals/document))
(obj/in? js/document "fullscreenElement")
(boolean (.-fullscreenElement js/document))
(obj/in? globals/document "fullscreenElement")
(boolean (.-fullscreenElement globals/document))
:else
(ex/raise :type :not-supported
@ -242,17 +243,17 @@
(-> event get-target (.releasePointerCapture (.-pointerId event))))
(defn get-root []
(query js/document "#app"))
(query globals/document "#app"))
(defn ^boolean class? [node class-name]
(let [class-list (.-classList ^js node)]
(.contains ^js class-list class-name)))
(defn get-user-agent []
(.-userAgent js/navigator))
(.-userAgent globals/navigator))
(defn active? [node]
(= (.-activeElement js/document) node))
(= (.-activeElement globals/document) node))
(defn get-data [^js node ^string attr]
(.getAttribute node (str "data-" attr)))

View file

@ -29,6 +29,14 @@ goog.scope(function() {
}
})();
app.util.globals.document = (function() {
if (typeof goog.global.document !== "undefined") {
return goog.global.document;
} else {
return {};
}
})();
app.util.globals.location = (function() {
if (typeof goog.global.location !== "undefined") {
return goog.global.location;
@ -36,5 +44,13 @@ goog.scope(function() {
return {};
}
})();
app.util.globals.navigator = (function() {
if (typeof goog.global.navigator !== "undefined") {
return goog.global.navigator;
} else {
return {};
}
})();
});

View file

@ -0,0 +1,89 @@
(ns app.test-helpers
(:require [cljs.test :as t :include-macros true]
[cljs.pprint :refer [pprint]]
[beicon.core :as rx]
[potok.core :as ptk]
[app.common.uuid :as uuid]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
[app.common.pages :as cp]
[app.common.pages.helpers :as cph]
[app.main.data.workspace :as dw]))
;; ---- Helpers to manage global events
(defn do-update
"Execute an update event and returns the new state."
[event state]
(ptk/update event state))
(defn do-watch
"Execute a watch event and return an observable, that
emits once a list with all new events."
[event state]
(->> (ptk/watch event state nil)
(rx/reduce conj [])))
(defn do-watch-update
"Execute a watch event and return an observable, that
emits once the new state, after all new events applied
in sequence (considering they are all update events)."
[event state]
(->> (do-watch event state)
(rx/map (fn [new-events]
(reduce
(fn [new-state new-event]
(do-update new-event new-state))
state
new-events)))))
;; ---- Helpers to manage pages and objects
(def current-file-id (uuid/next))
(def initial-state
{:current-file-id current-file-id
:current-page-id nil
:workspace-local dw/workspace-local-default
:workspace-data {:id current-file-id
:components {}
:pages []
:pages-index {}}
:workspace-libraries {}})
(defn current-page
[state]
(let [page-id (:current-page-id state)]
(get-in state [:workspace-data :pages-index page-id])))
(defn sample-page
([state] (sample-page state {}))
([state {:keys [id name] :as props
:or {id (uuid/next)
name "page1"}}]
(-> state
(assoc :current-page-id id)
(update :workspace-data
cp/process-changes
[{:type :add-page
:id id
:name name}]))))
(defn sample-shape
([state type] (sample-shape state type {}))
([state type props]
(let [page (current-page state)
frame (cph/get-top-frame (:objects page))
shape (-> (cp/make-minimal-shape type)
(gsh/setup {:x 0 :y 0 :width 1 :height 1})
(merge props))]
(update state :workspace-data
cp/process-changes
[{:type :add-obj
:id (:id shape)
:page-id (:id page)
:frame-id (:id frame)
:obj shape}]))))

View file

@ -2,60 +2,97 @@
(:require [cljs.test :as t :include-macros true]
[cljs.pprint :refer [pprint]]
[beicon.core :as rx]
[potok.core :as ptk]
[app.main.data.workspace.libraries :as dwl]))
[app.test-helpers :as th]
[app.common.data :as d]
[app.common.uuid :as uuid]
[app.common.pages.helpers :as cph]
[app.main.data.workspace :as dw]
[app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.libraries-helpers :as dwlh]))
;; ---- Helpers
(t/deftest test-create-page
(t/testing "create page"
(let [state (-> th/initial-state
(th/sample-page))
page (th/current-page state)]
(t/is (= (:name page) "page1")))))
(defn do-update
[state event cb]
(let [new-state (ptk/update event state)]
(cb new-state)))
(defn do-watch
[state event cb]
(->> (ptk/watch event state nil)
(rx/reduce conj [])
(rx/subs cb)))
(defn do-watch-update
[state event & cbs]
(do-watch state event
(fn [events]
(t/is (= (count events) (count cbs)))
(reduce
(fn [new-state [event cb]]
(do-update new-state event cb))
state
(map list events cbs)))))
;; ---- Tests
(t/deftest test-create-shape
(t/testing "create shape"
(let [id (uuid/next)
state (-> th/initial-state
(th/sample-page)
(th/sample-shape :rect {:id id
:name "Rect 1"}))
page (th/current-page state)
shape (cph/get-shape page id)]
(t/is (= (:name shape) "Rect 1")))))
(t/deftest synctest
(t/testing "synctest"
(let [state {:workspace-local {:color-for-rename "something"}}]
(do-update
state
dwl/clear-color-for-rename
(fn [new-state]
(t/is (= (get-in new-state [:workspace-local :color-for-rename])
nil)))))))
(let [state {:workspace-local {:color-for-rename "something"}}
new-state (->> state
(th/do-update
dwl/clear-color-for-rename))]
(t/is (= (get-in new-state [:workspace-local :color-for-rename])
nil)))))
(t/deftest asynctest
(t/testing "asynctest"
(t/async done
(let [state {}
color {:color "#ffffff"}]
(do-watch-update
state
(dwl/add-recent-color color)
(fn [new-state]
(t/is (= (get-in new-state [:workspace-file
:data
:recent-colors])
[color]))
(t/is (= (get-in new-state [:workspace-data
:recent-colors])
[color]))
(done)))))))
(->> state
(th/do-watch-update
(dwl/add-recent-color color))
(rx/map
(fn [new-state]
(t/is (= (get-in new-state [:workspace-file
:data
:recent-colors])
[color]))
(t/is (= (get-in new-state [:workspace-data
:recent-colors])
[color]))))
(rx/subs done))))))
(t/deftest test-add-component
(t/testing "Add a component"
(t/async done
(let [id1 (uuid/next)
state (-> th/initial-state
(th/sample-page)
(th/sample-shape :rect
{:id id1
:name "Rect 1"}))]
(->> state
(th/do-update (dw/select-shape id1))
(th/do-watch-update dwl/add-component)
(rx/map
(fn [new-state]
(let [page (th/current-page new-state)
shape (cph/get-shape page id1)
group (cph/get-shape page (:parent-id shape))
component (cph/get-component
(:component-id group)
(:current-file-id new-state)
(dwlh/get-local-file new-state)
nil)
c-shape (cph/get-shape
component
(:shape-ref shape))
c-group (cph/get-shape
component
(:shape-ref group))]
(t/is (= (:name shape) "Rect 1"))
(t/is (= (:name group) "Component-1"))
(t/is (= (:name component) "Component-1"))
(t/is (= (:name c-shape) "Rect 1"))
(t/is (= (:name c-group) "Component-1")))))
(rx/subs done))))))