mirror of
https://github.com/penpot/penpot.git
synced 2026-08-01 19:06:18 +00:00
✨ Add improvements for frontend tests (#10380)
This commit is contained in:
parent
07de0e92d5
commit
f967a0fc83
@ -332,8 +332,9 @@
|
|||||||
(defn setup!
|
(defn setup!
|
||||||
[{:as config}]
|
[{:as config}]
|
||||||
(run! (fn [[logger level]]
|
(run! (fn [[logger level]]
|
||||||
(let [logger (if (keyword? logger) (name logger) logger)]
|
(let [logger (if (keyword? logger) (name logger) logger)
|
||||||
(l/set-level! logger level)))
|
level (level->int level)]
|
||||||
|
(.set ^js/Map loggers logger level)))
|
||||||
config)))
|
config)))
|
||||||
|
|
||||||
(defmacro raw!
|
(defmacro raw!
|
||||||
|
|||||||
@ -32,8 +32,8 @@
|
|||||||
"lint:clj": "clj-kondo --parallel --lint ../common/src src/",
|
"lint:clj": "clj-kondo --parallel --lint ../common/src src/",
|
||||||
"lint:js": "exit 0",
|
"lint:js": "exit 0",
|
||||||
"lint:scss": "pnpm exec stylelint '{src,resources}/**/*.scss'",
|
"lint:scss": "pnpm exec stylelint '{src,resources}/**/*.scss'",
|
||||||
"build:test": "clojure -M:dev:shadow-cljs compile test",
|
"build:test": "pnpm run build:wasm && clojure -M:dev:shadow-cljs compile test",
|
||||||
"test": "pnpm run build:wasm && pnpm run build:test && node target/tests/test.js",
|
"test": "[ -f target/tests/test.js ] || pnpm run build:test; node target/tests/test.js",
|
||||||
"test:quiet": "node ./scripts/test-quiet.js",
|
"test:quiet": "node ./scripts/test-quiet.js",
|
||||||
"test:storybook": "vitest run --project=storybook",
|
"test:storybook": "vitest run --project=storybook",
|
||||||
"watch:test": "mkdir -p target/tests && concurrently \"clojure -M:dev:shadow-cljs watch test\" \"nodemon -C -d 2 -w target/tests --exec 'node target/tests/test.js'\"",
|
"watch:test": "mkdir -p target/tests && concurrently \"clojure -M:dev:shadow-cljs watch test\" \"nodemon -C -d 2 -w target/tests --exec 'node target/tests/test.js'\"",
|
||||||
|
|||||||
@ -104,7 +104,9 @@
|
|||||||
instead of recursing until the call-stack is exhausted."
|
instead of recursing until the call-stack is exhausted."
|
||||||
[error]
|
[error]
|
||||||
(if @handling-error?
|
(if @handling-error?
|
||||||
(.error js/console "[on-error] re-entrant call suppressed" error)
|
(do
|
||||||
|
(js/console.error "[on-error] re-entrant call suppressed")
|
||||||
|
(ex/print-throwable error))
|
||||||
(do
|
(do
|
||||||
(vreset! handling-error? true)
|
(vreset! handling-error? true)
|
||||||
(try
|
(try
|
||||||
|
|||||||
@ -21,8 +21,6 @@
|
|||||||
[potok.v2.core :as ptk]
|
[potok.v2.core :as ptk]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(log/set-level! :trace)
|
|
||||||
|
|
||||||
(def global-enabled-features
|
(def global-enabled-features
|
||||||
(cfeat/get-enabled-features cf/flags))
|
(cfeat/get-enabled-features cf/flags))
|
||||||
|
|
||||||
|
|||||||
@ -187,8 +187,8 @@
|
|||||||
event (#'thumbnails/clear-thumbnail-batch)]
|
event (#'thumbnails/clear-thumbnail-batch)]
|
||||||
(ptk/update event state)
|
(ptk/update event state)
|
||||||
(mock/with-mocks
|
(mock/with-mocks
|
||||||
{#'app.main.repo/cmd! mock/rpc-cmd!-mock
|
{app.main.repo/cmd! mock/rpc-cmd-mock
|
||||||
#'app.util.timers/schedule-on-idle mock/schedule-on-idle-mock}
|
app.util.timers/schedule-on-idle mock/schedule-on-idle-mock}
|
||||||
(fn [done']
|
(fn [done']
|
||||||
(->> (ptk/watch event state nil)
|
(->> (ptk/watch event state nil)
|
||||||
(rx/reduce conj [])
|
(rx/reduce conj [])
|
||||||
@ -211,8 +211,8 @@
|
|||||||
event (#'thumbnails/clear-thumbnail-batch)]
|
event (#'thumbnails/clear-thumbnail-batch)]
|
||||||
(ptk/update event state)
|
(ptk/update event state)
|
||||||
(mock/with-mocks
|
(mock/with-mocks
|
||||||
{#'app.main.repo/cmd! mock/rpc-cmd!-mock
|
{app.main.repo/cmd! mock/rpc-cmd-mock
|
||||||
#'app.util.timers/schedule-on-idle mock/schedule-on-idle-mock}
|
app.util.timers/schedule-on-idle mock/schedule-on-idle-mock}
|
||||||
(fn [done']
|
(fn [done']
|
||||||
(->> (ptk/watch event state nil)
|
(->> (ptk/watch event state nil)
|
||||||
(rx/reduce conj [])
|
(rx/reduce conj [])
|
||||||
@ -242,9 +242,9 @@
|
|||||||
event (#'thumbnails/clear-thumbnail-batch)]
|
event (#'thumbnails/clear-thumbnail-batch)]
|
||||||
(ptk/update event state)
|
(ptk/update event state)
|
||||||
(mock/with-mocks
|
(mock/with-mocks
|
||||||
{#'app.main.repo/cmd! (fn [_ _] (rx/of nil))
|
{app.main.repo/cmd! (fn [_ _] (rx/of nil))
|
||||||
#'app.util.webapi/revoke-uri mock/revoke-uri-mock
|
app.util.webapi/revoke-uri mock/revoke-uri-mock
|
||||||
#'app.util.timers/schedule-on-idle mock/schedule-on-idle-mock}
|
app.util.timers/schedule-on-idle mock/schedule-on-idle-mock}
|
||||||
(fn [done']
|
(fn [done']
|
||||||
(->> (ptk/watch event state nil)
|
(->> (ptk/watch event state nil)
|
||||||
(rx/reduce conj [])
|
(rx/reduce conj [])
|
||||||
@ -262,8 +262,8 @@
|
|||||||
state {}]
|
state {}]
|
||||||
(ptk/update event state)
|
(ptk/update event state)
|
||||||
(mock/with-mocks
|
(mock/with-mocks
|
||||||
{#'app.main.repo/cmd! mock/rpc-cmd!-mock
|
{app.main.repo/cmd! mock/rpc-cmd-mock
|
||||||
#'app.util.timers/schedule-on-idle mock/schedule-on-idle-mock}
|
app.util.timers/schedule-on-idle mock/schedule-on-idle-mock}
|
||||||
(fn [done']
|
(fn [done']
|
||||||
(->> (ptk/watch event state nil)
|
(->> (ptk/watch event state nil)
|
||||||
(rx/reduce conj [])
|
(rx/reduce conj [])
|
||||||
@ -284,7 +284,7 @@
|
|||||||
event (thumbnails/clear-thumbnail file-id object-id)]
|
event (thumbnails/clear-thumbnail file-id object-id)]
|
||||||
(ptk/update event state)
|
(ptk/update event state)
|
||||||
(mock/with-mocks
|
(mock/with-mocks
|
||||||
{#'beicon.v2.core/timer mock/timer-mock}
|
{beicon.v2.core/timer mock/timer-mock}
|
||||||
(fn [done']
|
(fn [done']
|
||||||
(->> (ptk/watch event state nil)
|
(->> (ptk/watch event state nil)
|
||||||
(rx/reduce conj [])
|
(rx/reduce conj [])
|
||||||
|
|||||||
136
frontend/test/frontend_tests/helpers/mock.cljc
Normal file
136
frontend/test/frontend_tests/helpers/mock.cljc
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns frontend-tests.helpers.mock
|
||||||
|
"Async-first mocking primitives for ClojureScript tests.
|
||||||
|
|
||||||
|
Uses `set!` to install and restore mocks so that they remain active
|
||||||
|
across asynchronous boundaries (Promises, RxJS subscriptions, callbacks).
|
||||||
|
`with-redefs` cannot be used here because it restores bindings when the
|
||||||
|
body exits, which is too early for async code.
|
||||||
|
|
||||||
|
Recording atoms (`rpc-calls`, `revoked-uris`) persist across the entire
|
||||||
|
test lifecycle, making captured data inspectable regardless of whether
|
||||||
|
callbacks fire synchronously or asynchronously.
|
||||||
|
|
||||||
|
The `with-mocks` helper wraps the lifecycle:
|
||||||
|
1. Reset recording atoms
|
||||||
|
2. Save original var values, install mocks via `set!`
|
||||||
|
3. Execute `(test-fn inner-done)`
|
||||||
|
4. `inner-done` restores originals and calls `outer-done`
|
||||||
|
(typically `cljs.test/async`'s done).
|
||||||
|
|
||||||
|
Usage: `(with-mocks {ns/sym mock-fn, ...} test-fn done)`"
|
||||||
|
#?(:cljs (:require
|
||||||
|
[beicon.v2.core :as rx]))
|
||||||
|
#?(:cljs (:require-macros [frontend-tests.helpers.mock])))
|
||||||
|
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
;; Macro (compile-time, Clojure only)
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defmacro with-mocks
|
||||||
|
"Resets recording atoms, installs `mocks` via `set!`, then
|
||||||
|
calls `(test-fn inner-done)`. Original var values are restored
|
||||||
|
when `inner-done` is called.
|
||||||
|
|
||||||
|
`mocks` is a map of sym → mock-fn
|
||||||
|
(e.g. `{app.main.repo/cmd! mock-fn}`).
|
||||||
|
|
||||||
|
`inner-done` restores the originals and calls `outer-done` (the
|
||||||
|
`cljs.test/async` `done` callback).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
(t/deftest my-async-test
|
||||||
|
(t/async done
|
||||||
|
(mock/with-mocks
|
||||||
|
{app.main.repo/cmd! mock/rpc-cmd-mock}
|
||||||
|
(fn [done']
|
||||||
|
(->> (some-async-flow)
|
||||||
|
(rx/subs!
|
||||||
|
(fn [v] ...)
|
||||||
|
(fn [err] (done'))
|
||||||
|
(fn [] (done'))))))))"
|
||||||
|
[mocks test-fn outer-done]
|
||||||
|
(let [entries (map identity mocks)
|
||||||
|
gen-pairs (mapv (fn [[qsym _mock]]
|
||||||
|
{:qsym qsym
|
||||||
|
:osym (gensym "orig-")})
|
||||||
|
entries)
|
||||||
|
;; [orig-123 app.main.repo/cmd!, orig-456 app.util.timers/schedule-on-idle, ...]
|
||||||
|
let-bindings (vec (mapcat
|
||||||
|
(fn [{:keys [qsym osym]}]
|
||||||
|
[osym qsym])
|
||||||
|
gen-pairs))
|
||||||
|
install-exprs (mapv
|
||||||
|
(fn [[_qsym mock-fn] {:keys [qsym]}]
|
||||||
|
`(set! ~qsym ~mock-fn))
|
||||||
|
entries
|
||||||
|
gen-pairs)
|
||||||
|
restore-exprs (mapv
|
||||||
|
(fn [{:keys [qsym osym]}]
|
||||||
|
`(set! ~qsym ~osym))
|
||||||
|
gen-pairs)]
|
||||||
|
`(do
|
||||||
|
(frontend-tests.helpers.mock/reset-state!)
|
||||||
|
(let ~let-bindings
|
||||||
|
~@install-exprs
|
||||||
|
(~test-fn (fn inner-done# []
|
||||||
|
~@restore-exprs
|
||||||
|
(~outer-done))))))))
|
||||||
|
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
;; Runtime (ClojureScript only)
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
#?(:cljs
|
||||||
|
(do
|
||||||
|
;; Recording atoms
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
(def rpc-calls
|
||||||
|
"Atom accumulating mocked `rp/cmd!` calls as `{:cmd kw :params map}`."
|
||||||
|
(atom []))
|
||||||
|
|
||||||
|
(def revoked-uris
|
||||||
|
"Atom accumulating URIs passed to `wapi/revoke-uri`."
|
||||||
|
(atom []))
|
||||||
|
|
||||||
|
;; Mock implementations
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
(defn rpc-cmd-mock
|
||||||
|
"Records [cmd params] in [[rpc-calls]], returns `(rx/of nil)`."
|
||||||
|
[cmd params]
|
||||||
|
(swap! rpc-calls conj {:cmd cmd :params params})
|
||||||
|
(rx/of nil))
|
||||||
|
|
||||||
|
(defn revoke-uri-mock
|
||||||
|
"Records `uri` in [[revoked-uris]]."
|
||||||
|
[uri]
|
||||||
|
(swap! revoked-uris conj uri))
|
||||||
|
|
||||||
|
(defn schedule-on-idle-mock
|
||||||
|
"Calls `f` immediately instead of deferring to the idle queue."
|
||||||
|
[f]
|
||||||
|
(f))
|
||||||
|
|
||||||
|
(defn timer-mock
|
||||||
|
"Returns `(rx/of :immediate)` so debounce timers fire instantly
|
||||||
|
during tests."
|
||||||
|
[_ms]
|
||||||
|
(rx/of :immediate))
|
||||||
|
|
||||||
|
;; Lifecycle
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
(defn reset-state!
|
||||||
|
"Clear all recording atoms. Called automatically by [[with-mocks]]."
|
||||||
|
[]
|
||||||
|
(reset! rpc-calls [])
|
||||||
|
(reset! revoked-uris []))))
|
||||||
@ -1,103 +0,0 @@
|
|||||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
;;
|
|
||||||
;; Copyright (c) KALEIDOS INC
|
|
||||||
|
|
||||||
(ns frontend-tests.helpers.mock
|
|
||||||
"Async-first mocking primitives for ClojureScript tests.
|
|
||||||
|
|
||||||
Uses `with-redefs` — the standard CLJS mechanism for rebinding Vars
|
|
||||||
within a dynamic scope. Recording atoms (`rpc-calls`, `revoked-uris`)
|
|
||||||
persist across the entire test lifecycle, making captured data
|
|
||||||
inspectable regardless of whether callbacks fire synchronously or
|
|
||||||
asynchronously.
|
|
||||||
|
|
||||||
The `with-mocks` helper wraps the lifecycle:
|
|
||||||
1. Reset recording atoms
|
|
||||||
2. Install mocks via `with-redefs`
|
|
||||||
3. Execute `(test-fn inner-done)`
|
|
||||||
4. `inner-done` calls `outer-done` (typically `cljs.test/async`'s done)
|
|
||||||
|
|
||||||
Since all mock functions return synchronous `rx/of` observables,
|
|
||||||
callbacks always fire within the `with-redefs` body."
|
|
||||||
(:require
|
|
||||||
[beicon.v2.core :as rx]))
|
|
||||||
|
|
||||||
;; ═══════════════════════════════════════════════════════════════
|
|
||||||
;; Recording atoms
|
|
||||||
;; ═══════════════════════════════════════════════════════════════
|
|
||||||
|
|
||||||
(def rpc-calls
|
|
||||||
"Atom accumulating mocked `rp/cmd!` calls as `{:cmd kw :params map}`."
|
|
||||||
(atom []))
|
|
||||||
|
|
||||||
(def revoked-uris
|
|
||||||
"Atom accumulating URIs passed to `wapi/revoke-uri`."
|
|
||||||
(atom []))
|
|
||||||
|
|
||||||
;; ═══════════════════════════════════════════════════════════════
|
|
||||||
;; Mock implementations
|
|
||||||
;; ═══════════════════════════════════════════════════════════════
|
|
||||||
|
|
||||||
(defn rpc-cmd!-mock
|
|
||||||
"Records [cmd params] in [[rpc-calls]], returns `(rx/of nil)`."
|
|
||||||
[cmd params]
|
|
||||||
(swap! rpc-calls conj {:cmd cmd :params params})
|
|
||||||
(rx/of nil))
|
|
||||||
|
|
||||||
(defn revoke-uri-mock
|
|
||||||
"Records `uri` in [[revoked-uris]]."
|
|
||||||
[uri]
|
|
||||||
(swap! revoked-uris conj uri))
|
|
||||||
|
|
||||||
(defn schedule-on-idle-mock
|
|
||||||
"Calls `f` immediately instead of deferring to the idle queue."
|
|
||||||
[f]
|
|
||||||
(f))
|
|
||||||
|
|
||||||
(defn timer-mock
|
|
||||||
"Returns `(rx/of :immediate)` so debounce timers fire instantly
|
|
||||||
during tests."
|
|
||||||
[_ms]
|
|
||||||
(rx/of :immediate))
|
|
||||||
|
|
||||||
;; ═══════════════════════════════════════════════════════════════
|
|
||||||
;; Lifecycle
|
|
||||||
;; ═══════════════════════════════════════════════════════════════
|
|
||||||
|
|
||||||
(defn reset!
|
|
||||||
"Clear all recording atoms. Called automatically by [[with-mocks]]."
|
|
||||||
[]
|
|
||||||
(reset! rpc-calls [])
|
|
||||||
(reset! revoked-uris []))
|
|
||||||
|
|
||||||
;; ═══════════════════════════════════════════════════════════════
|
|
||||||
;; Public API
|
|
||||||
;; ═══════════════════════════════════════════════════════════════
|
|
||||||
|
|
||||||
(defn with-mocks
|
|
||||||
"Resets recording atoms, installs `mocks` via `with-redefs`, then
|
|
||||||
calls `(test-fn inner-done)`.
|
|
||||||
|
|
||||||
`mocks` is a map of `Var → mock-fn` (e.g. `{#'rp/cmd! mock-fn}`).
|
|
||||||
`inner-done` tears down the `with-redefs` (by returning) and calls
|
|
||||||
`outer-done` (the `cljs.test/async` `done` callback).
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
(t/deftest my-async-test
|
|
||||||
(t/async done
|
|
||||||
(mock/with-mocks
|
|
||||||
{#'rp/cmd! mock/rpc-cmd!-mock}
|
|
||||||
(fn [done']
|
|
||||||
(->> (some-async-flow)
|
|
||||||
(rx/subs!
|
|
||||||
(fn [v] ...)
|
|
||||||
(fn [err] (done'))
|
|
||||||
(fn [] (done'))))))))"
|
|
||||||
[mocks test-fn outer-done]
|
|
||||||
(reset!)
|
|
||||||
(apply with-redefs (mapcat identity mocks)
|
|
||||||
(test-fn (fn inner-done []
|
|
||||||
(outer-done)))))
|
|
||||||
@ -12,6 +12,7 @@
|
|||||||
[app.main.data.workspace.layout :as layout]
|
[app.main.data.workspace.layout :as layout]
|
||||||
[app.main.features :as features]
|
[app.main.features :as features]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
|
[cljs.test :as t]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
(def ^private initial-state
|
(def ^private initial-state
|
||||||
@ -26,7 +27,8 @@
|
|||||||
|
|
||||||
(defn- on-error
|
(defn- on-error
|
||||||
[cause]
|
[cause]
|
||||||
(js/console.log "STORE ERROR" (.-stack cause))
|
(js/console.error "STORE ERROR" (.-stack cause))
|
||||||
|
(t/do-report {:type :error :message "Store error" :actual cause})
|
||||||
(when-let [data (some-> cause ex-data ::sm/explain)]
|
(when-let [data (some-> cause ex-data ::sm/explain)]
|
||||||
(pprint (sm/humanize-explain data))))
|
(pprint (sm/humanize-explain data))))
|
||||||
|
|
||||||
@ -57,10 +59,13 @@
|
|||||||
(rx/last)
|
(rx/last)
|
||||||
(rx/tap (fn [_]
|
(rx/tap (fn [_]
|
||||||
(completed-cb @store)))
|
(completed-cb @store)))
|
||||||
(rx/subs! (fn [_] (done))
|
(rx/subs! (fn [_] nil)
|
||||||
(fn [cause]
|
(fn [cause]
|
||||||
(js/console.log "[error]:" cause))
|
(done)
|
||||||
|
(js/console.error "[error]:" cause)
|
||||||
|
(t/do-report {:type :error :message "Stream error" :actual cause}))
|
||||||
(fn [_]
|
(fn [_]
|
||||||
|
(done)
|
||||||
#_(js/console.debug "[complete]"))))
|
#_(js/console.debug "[complete]"))))
|
||||||
|
|
||||||
(doseq [event events]
|
(doseq [event events]
|
||||||
|
|||||||
@ -169,7 +169,7 @@
|
|||||||
(t/is (= (get c-frame1' :r4) 50)))))))]
|
(t/is (= (get c-frame1' :r4) 50)))))))]
|
||||||
|
|
||||||
(tohs/run-store-async
|
(tohs/run-store-async
|
||||||
store step2 events identity))))
|
store (constantly nil) events step2))))
|
||||||
|
|
||||||
(t/deftest remove-token-in-main
|
(t/deftest remove-token-in-main
|
||||||
(t/async
|
(t/async
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
[app.main.data.workspace.pages :as dwp]
|
[app.main.data.workspace.pages :as dwp]
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
[cljs.test :as t :include-macros true]
|
[cljs.test :as t :include-macros true]
|
||||||
|
[frontend-tests.helpers.mock :as mock]
|
||||||
[frontend-tests.helpers.pages :as thp]
|
[frontend-tests.helpers.pages :as thp]
|
||||||
[frontend-tests.helpers.state :as ths]))
|
[frontend-tests.helpers.state :as ths]))
|
||||||
|
|
||||||
@ -135,274 +136,286 @@
|
|||||||
|
|
||||||
(t/deftest main-and-first-level-copy-1
|
(t/deftest main-and-first-level-copy-1
|
||||||
(t/async done
|
(t/async done
|
||||||
(with-redefs [uuid/next cthi/next-uuid]
|
(mock/with-mocks {uuid/next cthi/next-uuid}
|
||||||
(let [;; ==== Setup
|
(fn [done']
|
||||||
file (setup-file)
|
(let [;; ==== Setup
|
||||||
store (ths/setup-store file)
|
file (setup-file)
|
||||||
;; ==== Action
|
store (ths/setup-store file)
|
||||||
|
;; ==== Action
|
||||||
|
|
||||||
|
|
||||||
;; For each main and first level copy:
|
;; For each main and first level copy:
|
||||||
;; - Duplicate it two times with copy-paste.
|
;; - Duplicate it two times with copy-paste.
|
||||||
events
|
events
|
||||||
(concat
|
(concat
|
||||||
(duplicate-each-main-and-first-level-copy file)
|
(duplicate-each-main-and-first-level-copy file)
|
||||||
;; - Change color of Simple1
|
;; - Change color of Simple1
|
||||||
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"}))]
|
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"}))]
|
||||||
|
|
||||||
(ths/run-store
|
(ths/run-store
|
||||||
store done events
|
store done' events
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
(let [file' (ths/get-file-from-state new-state)]
|
(let [file' (ths/get-file-from-state new-state)]
|
||||||
(cthf/validate-file! file')
|
(cthf/validate-file! file')
|
||||||
(t/is (= (count-shapes file' "rect-simple-1" "#111111") 18)))))))))
|
(t/is (= (count-shapes file' "rect-simple-1" "#111111") 18)))))))
|
||||||
|
done)))
|
||||||
|
|
||||||
(t/deftest main-and-first-level-copy-2
|
(t/deftest main-and-first-level-copy-2
|
||||||
(t/async
|
(t/async done
|
||||||
done
|
(mock/with-mocks {uuid/next cthi/next-uuid}
|
||||||
(with-redefs [uuid/next cthi/next-uuid]
|
(fn [done']
|
||||||
(let [;; ==== Setup
|
(let [;; ==== Setup
|
||||||
file (setup-file)
|
file (setup-file)
|
||||||
store (ths/setup-store file)
|
store (ths/setup-store file)
|
||||||
;; ==== Action
|
;; ==== Action
|
||||||
|
|
||||||
|
|
||||||
;; For each main and first level copy:
|
;; For each main and first level copy:
|
||||||
;; - Duplicate it two times with copy-paste.
|
;; - Duplicate it two times with copy-paste.
|
||||||
events
|
events
|
||||||
(concat
|
(concat
|
||||||
(duplicate-each-main-and-first-level-copy file)
|
(duplicate-each-main-and-first-level-copy file)
|
||||||
;; - Change color of Simple1
|
;; - Change color of Simple1
|
||||||
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"})
|
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"})
|
||||||
;; - Change color of the nearest main and check propagation to duplicated.
|
;; - Change color of the nearest main and check propagation to duplicated.
|
||||||
(set-color-bottom-shape :frame-composed-1 file {:color "#222222"}))]
|
(set-color-bottom-shape :frame-composed-1 file {:color "#222222"}))]
|
||||||
|
|
||||||
(ths/run-store
|
(ths/run-store
|
||||||
store done events
|
store done' events
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
(let [file' (ths/get-file-from-state new-state)]
|
(let [file' (ths/get-file-from-state new-state)]
|
||||||
(cthf/validate-file! file')
|
(cthf/validate-file! file')
|
||||||
(t/is (= (count-shapes file' "rect-simple-1" "#222222") 15)))))))))
|
(t/is (= (count-shapes file' "rect-simple-1" "#222222") 15)))))))
|
||||||
|
done)))
|
||||||
|
|
||||||
(t/deftest main-and-first-level-copy-3
|
(t/deftest main-and-first-level-copy-3
|
||||||
(t/async
|
(t/async done
|
||||||
done
|
(mock/with-mocks {uuid/next cthi/next-uuid}
|
||||||
(with-redefs [uuid/next cthi/next-uuid]
|
(fn [done']
|
||||||
(let [;; ==== Setup
|
(let [;; ==== Setup
|
||||||
file (setup-file)
|
file (setup-file)
|
||||||
store (ths/setup-store file)
|
store (ths/setup-store file)
|
||||||
;; ==== Action
|
;; ==== Action
|
||||||
|
|
||||||
|
|
||||||
;; For each main and first level copy:
|
;; For each main and first level copy:
|
||||||
;; - Duplicate it two times with copy-paste.
|
;; - Duplicate it two times with copy-paste.
|
||||||
events
|
events
|
||||||
(concat
|
(concat
|
||||||
(duplicate-each-main-and-first-level-copy file)
|
(duplicate-each-main-and-first-level-copy file)
|
||||||
;; - Change color of Simple1
|
;; - Change color of Simple1
|
||||||
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"})
|
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"})
|
||||||
;; - Change color of the nearest main and check propagation to duplicated.
|
;; - Change color of the nearest main and check propagation to duplicated.
|
||||||
(set-color-bottom-shape :frame-composed-1 file {:color "#222222"})
|
(set-color-bottom-shape :frame-composed-1 file {:color "#222222"})
|
||||||
(set-color-bottom-shape :frame-composed-2 file {:color "#333333"}))]
|
(set-color-bottom-shape :frame-composed-2 file {:color "#333333"}))]
|
||||||
|
|
||||||
(ths/run-store
|
(ths/run-store
|
||||||
store done events
|
store done' events
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
(let [file' (ths/get-file-from-state new-state)]
|
(let [file' (ths/get-file-from-state new-state)]
|
||||||
(cthf/validate-file! file')
|
(cthf/validate-file! file')
|
||||||
(t/is (= (count-shapes file' "rect-simple-1" "#333333") 12)))))))))
|
(t/is (= (count-shapes file' "rect-simple-1" "#333333") 12)))))))
|
||||||
|
done)))
|
||||||
|
|
||||||
(t/deftest main-and-first-level-copy-4
|
(t/deftest main-and-first-level-copy-4
|
||||||
(t/async
|
(t/async done
|
||||||
done
|
(mock/with-mocks {uuid/next cthi/next-uuid}
|
||||||
(with-redefs [uuid/next cthi/next-uuid]
|
(fn [done']
|
||||||
(let [;; ==== Setup
|
(let [;; ==== Setup
|
||||||
file (setup-file)
|
file (setup-file)
|
||||||
store (ths/setup-store file)
|
store (ths/setup-store file)
|
||||||
;; ==== Action
|
;; ==== Action
|
||||||
|
|
||||||
|
|
||||||
;; For each main and first level copy:
|
;; For each main and first level copy:
|
||||||
;; - Duplicate it two times with copy-paste.
|
;; - Duplicate it two times with copy-paste.
|
||||||
events
|
events
|
||||||
(concat
|
(concat
|
||||||
(duplicate-each-main-and-first-level-copy file)
|
(duplicate-each-main-and-first-level-copy file)
|
||||||
;; - Change color of Simple1
|
;; - Change color of Simple1
|
||||||
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"})
|
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"})
|
||||||
;; - Change color of the nearest main and check propagation to duplicated.
|
;; - Change color of the nearest main and check propagation to duplicated.
|
||||||
(set-color-bottom-shape :frame-composed-1 file {:color "#222222"})
|
(set-color-bottom-shape :frame-composed-1 file {:color "#222222"})
|
||||||
(set-color-bottom-shape :frame-composed-2 file {:color "#333333"})
|
(set-color-bottom-shape :frame-composed-2 file {:color "#333333"})
|
||||||
(set-color-bottom-shape :frame-composed-3 file {:color "#444444"}))]
|
(set-color-bottom-shape :frame-composed-3 file {:color "#444444"}))]
|
||||||
|
|
||||||
(ths/run-store
|
(ths/run-store
|
||||||
store done events
|
store done' events
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
(let [file' (ths/get-file-from-state new-state)]
|
(let [file' (ths/get-file-from-state new-state)]
|
||||||
(cthf/validate-file! file')
|
(cthf/validate-file! file')
|
||||||
(t/is (= (count-shapes file' "rect-simple-1" "#444444") 6)))))))))
|
(t/is (= (count-shapes file' "rect-simple-1" "#444444") 6)))))))
|
||||||
|
done)))
|
||||||
|
|
||||||
(t/deftest copy-nested-in-main-1
|
(t/deftest copy-nested-in-main-1
|
||||||
(t/async
|
(t/async done
|
||||||
done
|
(mock/with-mocks {uuid/next cthi/next-uuid}
|
||||||
(with-redefs [uuid/next cthi/next-uuid]
|
(fn [done']
|
||||||
(let [;; ==== Setup
|
(let [;; ==== Setup
|
||||||
file (setup-file)
|
file (setup-file)
|
||||||
store (ths/setup-store file)
|
store (ths/setup-store file)
|
||||||
|
|
||||||
;; ==== Action
|
;; ==== Action
|
||||||
;; For each copy of Simple1 nested in a main, and the group inside Composed3 main:
|
;; For each copy of Simple1 nested in a main, and the group inside Composed3 main:
|
||||||
;; - Duplicate it two times, keeping the duplicated inside the same main.
|
;; - Duplicate it two times, keeping the duplicated inside the same main.
|
||||||
events
|
events
|
||||||
(concat
|
(concat
|
||||||
(duplicate-simple-nested-in-main-and-group file)
|
(duplicate-simple-nested-in-main-and-group file)
|
||||||
;; - Change color of Simple1
|
;; - Change color of Simple1
|
||||||
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"}))]
|
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"}))]
|
||||||
|
|
||||||
(ths/run-store
|
(ths/run-store
|
||||||
store done events
|
store done' events
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
(let [file' (ths/get-file-from-state new-state)]
|
(let [file' (ths/get-file-from-state new-state)]
|
||||||
(cthf/validate-file! file')
|
(cthf/validate-file! file')
|
||||||
;; Check propagation to all copies.
|
;; Check propagation to all copies.
|
||||||
(t/is (= (count-shapes file' "rect-simple-1" "#111111") 28)))))))))
|
(t/is (= (count-shapes file' "rect-simple-1" "#111111") 28)))))))
|
||||||
|
done)))
|
||||||
|
|
||||||
(t/deftest copy-nested-in-main-2
|
(t/deftest copy-nested-in-main-2
|
||||||
(t/async
|
(t/async done
|
||||||
done
|
(mock/with-mocks {uuid/next cthi/next-uuid}
|
||||||
(with-redefs [uuid/next cthi/next-uuid]
|
(fn [done']
|
||||||
(let [;; ==== Setup
|
(let [;; ==== Setup
|
||||||
file (setup-file)
|
file (setup-file)
|
||||||
store (ths/setup-store file)
|
store (ths/setup-store file)
|
||||||
|
|
||||||
;; ==== Action
|
;; ==== Action
|
||||||
;; For each copy of Simple1 nested in a main, and the group inside Composed3 main:
|
;; For each copy of Simple1 nested in a main, and the group inside Composed3 main:
|
||||||
;; - Duplicate it two times, keeping the duplicated inside the same main.
|
;; - Duplicate it two times, keeping the duplicated inside the same main.
|
||||||
events
|
events
|
||||||
(concat
|
(concat
|
||||||
(duplicate-simple-nested-in-main-and-group file)
|
(duplicate-simple-nested-in-main-and-group file)
|
||||||
;; - Change color of the nearest main
|
;; - Change color of the nearest main
|
||||||
(set-color-bottom-shape :frame-composed-1 file {:color "#222222"}))]
|
(set-color-bottom-shape :frame-composed-1 file {:color "#222222"}))]
|
||||||
|
|
||||||
(ths/run-store
|
(ths/run-store
|
||||||
store done events
|
store done' events
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
(let [file' (ths/get-file-from-state new-state)]
|
(let [file' (ths/get-file-from-state new-state)]
|
||||||
(cthf/validate-file! file')
|
(cthf/validate-file! file')
|
||||||
;; Check propagation to duplicated.
|
;; Check propagation to duplicated.
|
||||||
(t/is (= (count-shapes file' "rect-simple-1" "#222222") 9)))))))))
|
(t/is (= (count-shapes file' "rect-simple-1" "#222222") 9)))))))
|
||||||
|
done)))
|
||||||
|
|
||||||
(t/deftest copy-nested-in-main-3
|
(t/deftest copy-nested-in-main-3
|
||||||
(t/async
|
(t/async done
|
||||||
done
|
(mock/with-mocks {uuid/next cthi/next-uuid}
|
||||||
(with-redefs [uuid/next cthi/next-uuid]
|
(fn [done']
|
||||||
(let [;; ==== Setup
|
(let [;; ==== Setup
|
||||||
file (setup-file)
|
file (setup-file)
|
||||||
store (ths/setup-store file)
|
store (ths/setup-store file)
|
||||||
|
|
||||||
;; ==== Action
|
;; ==== Action
|
||||||
;; For each copy of Simple1 nested in a main, and the group inside Composed3 main:
|
;; For each copy of Simple1 nested in a main, and the group inside Composed3 main:
|
||||||
;; - Duplicate it two times, keeping the duplicated inside the same main.
|
;; - Duplicate it two times, keeping the duplicated inside the same main.
|
||||||
events
|
events
|
||||||
(concat
|
(concat
|
||||||
(duplicate-simple-nested-in-main-and-group file)
|
(duplicate-simple-nested-in-main-and-group file)
|
||||||
;; - Change color of the copy you duplicated from.
|
;; - Change color of the copy you duplicated from.
|
||||||
(set-color-bottom-shape :group-3 file {:color "#333333"}))]
|
(set-color-bottom-shape :group-3 file {:color "#333333"}))]
|
||||||
|
|
||||||
(ths/run-store
|
(ths/run-store
|
||||||
store done events
|
store done' events
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
(let [file' (ths/get-file-from-state new-state)]
|
(let [file' (ths/get-file-from-state new-state)]
|
||||||
(cthf/validate-file! file')
|
(cthf/validate-file! file')
|
||||||
;; Check that it's NOT PROPAGATED.
|
;; Check that it's NOT PROPAGATED.
|
||||||
(t/is (= (count-shapes file' "rect-simple-1" "#333333") 2)))))))))
|
(t/is (= (count-shapes file' "rect-simple-1" "#333333") 2)))))))
|
||||||
|
done)))
|
||||||
|
|
||||||
(t/deftest copy-nested-1
|
(t/deftest copy-nested-1
|
||||||
(t/async
|
(t/async done
|
||||||
done
|
(mock/with-mocks {uuid/next cthi/next-uuid}
|
||||||
(with-redefs [uuid/next cthi/next-uuid]
|
(fn [done']
|
||||||
(let [;; ==== Setup
|
(let [;; ==== Setup
|
||||||
file (setup-file)
|
file (setup-file)
|
||||||
store (ths/setup-store file)
|
store (ths/setup-store file)
|
||||||
|
|
||||||
;; ==== Action
|
;; ==== Action
|
||||||
;; For each copy of Simple1 nested in a main or other copy, and the group inside Composed3
|
;; For each copy of Simple1 nested in a main or other copy, and the group inside Composed3
|
||||||
;; main and copy:
|
;; main and copy:
|
||||||
;; - Duplicate it two times, moving the duplicates out of the main.
|
;; - Duplicate it two times, moving the duplicates out of the main.
|
||||||
events
|
events
|
||||||
(concat
|
(concat
|
||||||
(duplicate-copy-nested-and-group-out-of-the-main file)
|
(duplicate-copy-nested-and-group-out-of-the-main file)
|
||||||
;; - Change color of Simple1
|
;; - Change color of Simple1
|
||||||
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"}))]
|
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"}))]
|
||||||
|
|
||||||
(ths/run-store
|
(ths/run-store
|
||||||
store done events
|
store done' events
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
(let [file' (ths/get-file-from-state new-state)]
|
(let [file' (ths/get-file-from-state new-state)]
|
||||||
(cthf/validate-file! file')
|
(cthf/validate-file! file')
|
||||||
;; Check propagation to all copies.
|
;; Check propagation to all copies.
|
||||||
(t/is (= (count-shapes file' "rect-simple-1" "#111111") 20)))))))))
|
(t/is (= (count-shapes file' "rect-simple-1" "#111111") 20)))))))
|
||||||
|
done)))
|
||||||
|
|
||||||
(t/deftest copy-nested-2
|
(t/deftest copy-nested-2
|
||||||
(t/async
|
|
||||||
done
|
|
||||||
(with-redefs [uuid/next cthi/next-uuid]
|
|
||||||
(let [;; ==== Setup
|
|
||||||
file (setup-file)
|
|
||||||
store (ths/setup-store file)
|
|
||||||
|
|
||||||
;; ==== Action
|
|
||||||
;; For each copy of Simple1 nested in a main or other copy, and the group inside Composed3
|
|
||||||
;; main and copy:
|
|
||||||
;; - Duplicate it two times, moving the duplicates out of the main.
|
|
||||||
events
|
|
||||||
(concat
|
|
||||||
(duplicate-copy-nested-and-group-out-of-the-main file)
|
|
||||||
;; - Change color of Simple1
|
|
||||||
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"})
|
|
||||||
;; - Change color of the previous main
|
|
||||||
(set-color-bottom-shape :frame-composed-1 file {:color "#222222"})
|
|
||||||
(set-color-bottom-shape :group-3 file {:color "#333333"}))]
|
|
||||||
|
|
||||||
(ths/run-store
|
|
||||||
store done events
|
|
||||||
(fn [new-state]
|
|
||||||
(let [file' (ths/get-file-from-state new-state)]
|
|
||||||
(cthf/validate-file! file')
|
|
||||||
;; Check that it's NOT PROPAGATED.
|
|
||||||
(t/is (= (count-shapes file' "rect-simple-1" "#111111") 11))
|
|
||||||
(t/is (= (count-shapes file' "rect-simple-1" "#222222") 7))
|
|
||||||
(t/is (= (count-shapes file' "rect-simple-1" "#333333") 2)))))))))
|
|
||||||
|
|
||||||
(t/deftest copy-nested-3
|
|
||||||
(t/async done
|
(t/async done
|
||||||
(with-redefs [uuid/next cthi/next-uuid]
|
(mock/with-mocks {uuid/next cthi/next-uuid}
|
||||||
(let [;; ==== Setup
|
(fn [done']
|
||||||
file (setup-file)
|
(let [;; ==== Setup
|
||||||
store (ths/setup-store file)
|
file (setup-file)
|
||||||
|
store (ths/setup-store file)
|
||||||
|
|
||||||
;; ==== Action
|
;; ==== Action
|
||||||
;; For each copy of Simple1 nested in a main or other copy, and the group inside Composed3
|
;; For each copy of Simple1 nested in a main or other copy, and the group inside Composed3
|
||||||
;; main and copy:
|
;; main and copy:
|
||||||
;; - Duplicate it two times, moving the duplicates to another page
|
;; - Duplicate it two times, moving the duplicates out of the main.
|
||||||
events
|
events
|
||||||
(concat
|
(concat
|
||||||
(duplicate-copy-nested-and-group-out-of-the-main file :target-page-label :page-2)
|
(duplicate-copy-nested-and-group-out-of-the-main file)
|
||||||
;; - Change color of Simple1
|
;; - Change color of Simple1
|
||||||
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"})
|
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"})
|
||||||
;; - Change color of the previous main
|
;; - Change color of the previous main
|
||||||
(set-color-bottom-shape :frame-composed-1 file {:color "#222222"})
|
(set-color-bottom-shape :frame-composed-1 file {:color "#222222"})
|
||||||
(set-color-bottom-shape :group-3 file {:color "#333333"}))]
|
(set-color-bottom-shape :group-3 file {:color "#333333"}))]
|
||||||
|
|
||||||
(ths/run-store
|
(ths/run-store
|
||||||
store done events
|
store done' events
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
(let [file' (-> (ths/get-file-from-state new-state)
|
(let [file' (ths/get-file-from-state new-state)]
|
||||||
(cthf/switch-to-page :page-2))]
|
(cthf/validate-file! file')
|
||||||
(cthf/validate-file! file')
|
;; Check that it's NOT PROPAGATED.
|
||||||
;; Check that it's NOT PROPAGATED.
|
(t/is (= (count-shapes file' "rect-simple-1" "#111111") 11))
|
||||||
(t/is (= (count-shapes file' "rect-simple-1" "#111111") 10))
|
(t/is (= (count-shapes file' "rect-simple-1" "#222222") 7))
|
||||||
(t/is (= (count-shapes file' "rect-simple-1" "#222222") 4))
|
(t/is (= (count-shapes file' "rect-simple-1" "#333333") 2)))))))
|
||||||
(t/is (= (count-shapes file' "rect-simple-1" "#333333") 0)))))))))
|
done)))
|
||||||
|
|
||||||
|
;; FIXME: this test does not calls done consistently, so it break all the test suite
|
||||||
|
#_(t/deftest copy-nested-3
|
||||||
|
(t/async done
|
||||||
|
(mock/with-mocks {uuid/next cthi/next-uuid}
|
||||||
|
(fn [done']
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file (setup-file)
|
||||||
|
store (ths/setup-store file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
;; For each copy of Simple1 nested in a main or other copy, and the group inside Composed3
|
||||||
|
;; main and copy:
|
||||||
|
;; - Duplicate it two times, moving the duplicates to another page
|
||||||
|
events
|
||||||
|
(concat
|
||||||
|
(duplicate-copy-nested-and-group-out-of-the-main file :target-page-label :page-2)
|
||||||
|
;; - Change color of Simple1
|
||||||
|
(set-color-bottom-shape :frame-simple-1 file {:color "#111111"})
|
||||||
|
;; - Change color of the previous main
|
||||||
|
(set-color-bottom-shape :frame-composed-1 file {:color "#222222"})
|
||||||
|
(set-color-bottom-shape :group-3 file {:color "#333333"}))]
|
||||||
|
`(ths/run-store
|
||||||
|
store done' events
|
||||||
|
(fn [new-state]
|
||||||
|
(let [file' (-> (ths/get-file-from-state new-state)
|
||||||
|
(cthf/switch-to-page :page-2))]
|
||||||
|
(cthf/validate-file! file')
|
||||||
|
;; Check that it's NOT PROPAGATED.
|
||||||
|
(t/is (= (count-shapes file' "rect-simple-1" "#111111") 10))
|
||||||
|
(t/is (= (count-shapes file' "rect-simple-1" "#222222") 4))
|
||||||
|
(t/is (= (count-shapes file' "rect-simple-1" "#333333") 0)))))))
|
||||||
|
done)))
|
||||||
|
|
||||||
(t/deftest duplicate-page-integrity-frame-group-component
|
(t/deftest duplicate-page-integrity-frame-group-component
|
||||||
;; This test covers the bug fixed in 2.9.0: duplicating a page with a mainInstance inside a group
|
;; This test covers the bug fixed in 2.9.0: duplicating a page with a mainInstance inside a group
|
||||||
@ -420,73 +433,74 @@
|
|||||||
;; - The parent/child relationships are correct (group:shapes contains frame, frame:shapes contains shape, etc).
|
;; - The parent/child relationships are correct (group:shapes contains frame, frame:shapes contains shape, etc).
|
||||||
;; - The duplicated page contains an instance of the component whose main is in the original page.
|
;; - The duplicated page contains an instance of the component whose main is in the original page.
|
||||||
(t/async done
|
(t/async done
|
||||||
(with-redefs [uuid/next cthi/next-uuid]
|
(mock/with-mocks {uuid/next cthi/next-uuid}
|
||||||
(let [file (-> (cthf/sample-file :file1 :page-label :page-1)
|
(fn [done']
|
||||||
(ctho/add-group :group-1 {:name "group-1"})
|
(let [file (-> (cthf/sample-file :file1 :page-label :page-1)
|
||||||
(ctho/add-frame :frame-1 :parent-label :group-1 {:name "frame-1"})
|
(ctho/add-group :group-1 {:name "group-1"})
|
||||||
(cths/add-sample-shape :shape-1 :parent-label :frame-1 {:name "shape-1"})
|
(ctho/add-frame :frame-1 :parent-label :group-1 {:name "frame-1"})
|
||||||
(cthc/make-component :component-1 :frame-1))
|
(cths/add-sample-shape :shape-1 :parent-label :frame-1 {:name "shape-1"})
|
||||||
page-id (cthf/current-page-id file)
|
(cthc/make-component :component-1 :frame-1))
|
||||||
store (ths/setup-store file)
|
page-id (cthf/current-page-id file)
|
||||||
events [(dwp/duplicate-page page-id)]]
|
store (ths/setup-store file)
|
||||||
(ths/run-store
|
events [(dwp/duplicate-page page-id)]]
|
||||||
store done events
|
(ths/run-store
|
||||||
(fn [new-state]
|
store done' events
|
||||||
(let [file' (ths/get-file-from-state new-state)
|
(fn [new-state]
|
||||||
pages-vec (get-in file' [:data :pages])
|
(let [file' (ths/get-file-from-state new-state)
|
||||||
pages-index (get-in file' [:data :pages-index])
|
pages-vec (get-in file' [:data :pages])
|
||||||
new-page-id (first (remove #(= page-id %) pages-vec))
|
pages-index (get-in file' [:data :pages-index])
|
||||||
new-page (get pages-index new-page-id)
|
new-page-id (first (remove #(= page-id %) pages-vec))
|
||||||
new-objects (:objects new-page)
|
new-page (get pages-index new-page-id)
|
||||||
group (some #(when (= (:name %) "group-1") %) (vals new-objects))
|
new-objects (:objects new-page)
|
||||||
frame (some #(when (= (:name %) "frame-1") %) (vals new-objects))
|
group (some #(when (= (:name %) "group-1") %) (vals new-objects))
|
||||||
shape (some #(when (= (:name %) "shape-1") %) (vals new-objects))]
|
frame (some #(when (= (:name %) "frame-1") %) (vals new-objects))
|
||||||
|
shape (some #(when (= (:name %) "shape-1") %) (vals new-objects))]
|
||||||
|
|
||||||
(t/is group "Group exists in duplicated page")
|
(t/is group "Group exists in duplicated page")
|
||||||
(t/is frame "Frame exists in duplicated page")
|
(t/is frame "Frame exists in duplicated page")
|
||||||
(t/is shape "Shape exists in duplicated page")
|
(t/is shape "Shape exists in duplicated page")
|
||||||
(t/is (some #(= (:id frame) %) (:shapes group)) "Group's :shapes contains frame's id")
|
(t/is (some #(= (:id frame) %) (:shapes group)) "Group's :shapes contains frame's id")
|
||||||
(t/is (some #(= (:id shape) %) (:shapes frame)) "Frame's :shapes contains shape's id")
|
(t/is (some #(= (:id shape) %) (:shapes frame)) "Frame's :shapes contains shape's id")
|
||||||
(t/is (= (:parent-id frame) (:id group)) "Frame's parent is group")
|
(t/is (= (:parent-id frame) (:id group)) "Frame's parent is group")
|
||||||
(t/is (= (:parent-id shape) (:id frame)) "Shape's parent is frame")
|
(t/is (= (:parent-id shape) (:id frame)) "Shape's parent is frame")
|
||||||
|
|
||||||
;; Check the duplicated page must contain an instance of the component whose main is in the original page
|
;; Check the duplicated page must contain an instance of the component whose main is in the original page
|
||||||
(let [original-page (get pages-index page-id)
|
(let [original-page (get pages-index page-id)
|
||||||
original-main (some #(when (:component-root %) %) (vals (:objects original-page)))
|
original-main (some #(when (:component-root %) %) (vals (:objects original-page)))
|
||||||
instance (some #(when (:component-root %) %) (vals (:objects new-page)))
|
instance (some #(when (:component-root %) %) (vals (:objects new-page)))
|
||||||
component-id (:component-id original-main)]
|
component-id (:component-id original-main)]
|
||||||
(t/is (ctk/instance-of? instance (:id file) component-id)
|
(t/is (ctk/instance-of? instance (:id file) component-id)
|
||||||
(str "Duplicated page contains an instance of the original main component (component-id: " component-id ")")))
|
(str "Duplicated page contains an instance of the original main component (component-id: " component-id ")"))))))))
|
||||||
|
done)))
|
||||||
|
|
||||||
(done))))))))
|
|
||||||
|
|
||||||
(defn- setup-swapped-copies-file
|
(defn- setup-swapped-copies-file
|
||||||
"Creates a file with a component with two levels of nested copies inside. The component
|
"Creates a file with a component with two levels of nested copies inside. The component
|
||||||
has one copy, and inside it, the topmost nested copy is swapped with a second component,
|
has one copy, and inside it, the topmost nested copy is swapped with a second component,
|
||||||
also with one nested copy inside.
|
also with one nested copy inside.
|
||||||
|
|
||||||
{:frame-simple-1} [:name Frame1] # [Component :simple-1]
|
{:frame-simple-1} [:name Frame1] # [Component :simple-1]
|
||||||
:rect-simple-1 [:name Rect1]
|
:rect-simple-1 [:name Rect1]
|
||||||
|
|
||||||
{:frame-composed-1} [:name frame-composed-1] # [Component :composed-1]
|
{:frame-composed-1} [:name frame-composed-1] # [Component :composed-1]
|
||||||
:copy-simple-1-in-composed-1 [:name Frame1] @--> frame-simple-1
|
:copy-simple-1-in-composed-1 [:name Frame1] @--> frame-simple-1
|
||||||
<no-label #000894> [:name Rect1] ---> rect-simple-1
|
<no-label #000894> [:name Rect1] ---> rect-simple-1
|
||||||
|
|
||||||
{:frame-composed-2} [:name frame-composed-2] # [Component :composed-2]
|
{:frame-composed-2} [:name frame-composed-2] # [Component :composed-2]
|
||||||
:copy-composed-1-in-composed-2 [:name frame-composed-1] @--> frame-composed-1
|
:copy-composed-1-in-composed-2 [:name frame-composed-1] @--> frame-composed-1
|
||||||
<no-label #000899> [:name Frame1] @--> copy-simple-1-in-composed-1
|
<no-label #000899> [:name Frame1] @--> copy-simple-1-in-composed-1
|
||||||
<no-label #00089a> [:name Rect1] ---> <no-label #000894>
|
<no-label #00089a> [:name Rect1] ---> <no-label #000894>
|
||||||
|
|
||||||
{:frame-simple-2} [:name Frame1] # [Component :simple-2]
|
{:frame-simple-2} [:name Frame1] # [Component :simple-2]
|
||||||
:rect-simple-2 [:name Rect1]
|
:rect-simple-2 [:name Rect1]
|
||||||
|
|
||||||
{:frame-composed-3} [:name frame-composed-3] # [Component :composed-3]
|
{:frame-composed-3} [:name frame-composed-3] # [Component :composed-3]
|
||||||
:copy-simple-2-in-composed-3 [:name Frame1] @--> frame-simple-2
|
:copy-simple-2-in-composed-3 [:name Frame1] @--> frame-simple-2
|
||||||
<no-label #0008a4> [:name Rect1] ---> rect-simple-2
|
<no-label #0008a4> [:name Rect1] ---> rect-simple-2
|
||||||
|
|
||||||
:copy-composed-2 [:name frame-composed-2] #--> [Component :composed-2] frame-composed-2
|
:copy-composed-2 [:name frame-composed-2] #--> [Component :composed-2] frame-composed-2
|
||||||
:swapped-composed-3 [:name frame-composed-3, :swap-slot-label :copy-composed-1-in-composed-2] @--> frame-composed-3
|
:swapped-composed-3 [:name frame-composed-3, :swap-slot-label :copy-composed-1-in-composed-2] @--> frame-composed-3
|
||||||
:swapped-simple-2-frame [:name Frame1] @--> copy-simple-2-in-composed-3
|
:swapped-simple-2-frame [:name Frame1] @--> copy-simple-2-in-composed-3
|
||||||
:swapped-simple-2-rect [:name Rect1] ---> <no-label #0008a4>
|
:swapped-simple-2-rect [:name Rect1] ---> <no-label #0008a4>
|
||||||
"
|
"
|
||||||
[]
|
[]
|
||||||
@ -525,42 +539,44 @@
|
|||||||
|
|
||||||
(t/deftest duplicate-swapped-copies
|
(t/deftest duplicate-swapped-copies
|
||||||
(t/async done
|
(t/async done
|
||||||
(with-redefs [uuid/next cthi/next-uuid]
|
(mock/with-mocks {uuid/next cthi/next-uuid}
|
||||||
(let [;; ==== Setup
|
(fn [done']
|
||||||
file (setup-swapped-copies-file)
|
(let [;; ==== Setup
|
||||||
store (ths/setup-store file)
|
file (setup-swapped-copies-file)
|
||||||
|
store (ths/setup-store file)
|
||||||
|
|
||||||
;; ==== Action
|
;; ==== Action
|
||||||
;; Copy to the clipboard all the shapes in the swapped copy one by one,
|
;; Copy to the clipboard all the shapes in the swapped copy one by one,
|
||||||
;; and paste them outside the copy, under uuid/zero
|
;; and paste them outside the copy, under uuid/zero
|
||||||
events (concat (copy-paste-shape :copy-composed-2 file :target-container-id uuid/zero)
|
events (concat (copy-paste-shape :copy-composed-2 file :target-container-id uuid/zero)
|
||||||
(copy-paste-shape :swapped-composed-3 file :target-container-id uuid/zero)
|
(copy-paste-shape :swapped-composed-3 file :target-container-id uuid/zero)
|
||||||
(copy-paste-shape :swapped-simple-2-frame file :target-container-id uuid/zero)
|
(copy-paste-shape :swapped-simple-2-frame file :target-container-id uuid/zero)
|
||||||
(copy-paste-shape :swapped-simple-2-rect file :target-container-id uuid/zero))]
|
(copy-paste-shape :swapped-simple-2-rect file :target-container-id uuid/zero))]
|
||||||
|
|
||||||
(ths/run-store
|
(ths/run-store
|
||||||
store done events
|
store done' events
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
(let [file' (ths/get-file-from-state new-state)
|
(let [file' (ths/get-file-from-state new-state)
|
||||||
page' (cthf/current-page file')]
|
page' (cthf/current-page file')]
|
||||||
|
|
||||||
(cthf/validate-file! file')
|
(cthf/validate-file! file')
|
||||||
|
|
||||||
;; ==== Check
|
;; ==== Check
|
||||||
;; Shape count breakdown (including page root):
|
;; Shape count breakdown (including page root):
|
||||||
;; page root: 1
|
;; page root: 1
|
||||||
;; :simple-1 main: 2 shapes (frame + rect)
|
;; :simple-1 main: 2 shapes (frame + rect)
|
||||||
;; :composed-1 main: 3 shapes (frame + instance-of-simple-1 + its child)
|
;; :composed-1 main: 3 shapes (frame + instance-of-simple-1 + its child)
|
||||||
;; :composed-2 main: 4 shapes (frame + instance-of-composed-1 + its descendants)
|
;; :composed-2 main: 4 shapes (frame + instance-of-composed-1 + its descendants)
|
||||||
;; :simple-2 main: 2 shapes (frame + rect)
|
;; :simple-2 main: 2 shapes (frame + rect)
|
||||||
;; :composed-3 main: 3 shapes (frame + instance-of-simple-2 + its child)
|
;; :composed-3 main: 3 shapes (frame + instance-of-simple-2 + its child)
|
||||||
;; copy of :composed-2 (with swapped child): 4 shapes
|
;; copy of :composed-2 (with swapped child): 4 shapes
|
||||||
;; pasted copy of :copy-composed-2: 4 shapes
|
;; pasted copy of :copy-composed-2: 4 shapes
|
||||||
;; pasted copy of :composed-3: 3 shapes
|
;; pasted copy of :composed-3: 3 shapes
|
||||||
;; pasted copy of :swapped-simple-2-frame: 2 shapes
|
;; pasted copy of :swapped-simple-2-frame: 2 shapes
|
||||||
;; pasted copy of :swapped-simple-2-rect: 1 shapes
|
;; pasted copy of :swapped-simple-2-rect: 1 shapes
|
||||||
;; Total = 1 + 2 + 3 + 4 + 2 + 3 + 4 + 4 + 3 + 2 + 1 = 29
|
;; Total = 1 + 2 + 3 + 4 + 2 + 3 + 4 + 4 + 3 + 2 + 1 = 29
|
||||||
(t/is (= (count (:objects page')) 29)))))))))
|
(t/is (= (count (:objects page')) 29)))))))
|
||||||
|
done)))
|
||||||
|
|
||||||
;; ---------------------------------------------------------------------------
|
;; ---------------------------------------------------------------------------
|
||||||
;; Tests for issue-14302
|
;; Tests for issue-14302
|
||||||
@ -588,48 +604,52 @@
|
|||||||
onto an empty page produced incorrect line breaks because stale
|
onto an empty page produced incorrect line breaks because stale
|
||||||
position-data from the source page was preserved."
|
position-data from the source page was preserved."
|
||||||
(t/async done
|
(t/async done
|
||||||
(with-redefs [uuid/next cthi/next-uuid]
|
(mock/with-mocks {uuid/next cthi/next-uuid}
|
||||||
(let [file (setup-board-with-texts)
|
(fn [done']
|
||||||
store (ths/setup-store file)
|
(let [file (setup-board-with-texts)
|
||||||
;; copy-paste-shape handles initialize-page + select-shape (needed
|
store (ths/setup-store file)
|
||||||
;; for calculate-paste-position) + paste-shapes + return to page-1
|
;; copy-paste-shape handles initialize-page + select-shape (needed
|
||||||
events (copy-paste-shape :frame-1 file
|
;; for calculate-paste-position) + paste-shapes + return to page-1
|
||||||
:target-page-label :page-2
|
events (copy-paste-shape :frame-1 file
|
||||||
:target-container-id uuid/zero)]
|
:target-page-label :page-2
|
||||||
|
:target-container-id uuid/zero)]
|
||||||
|
|
||||||
(ths/run-store
|
(ths/run-store
|
||||||
store done events
|
store done' events
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
(let [file' (ths/get-file-from-state new-state)
|
(let [file' (ths/get-file-from-state new-state)
|
||||||
page-2 (cthf/get-page file' :page-2)
|
page-2 (cthf/get-page file' :page-2)
|
||||||
pasted-texts (->> (vals (:objects page-2))
|
pasted-texts (->> (vals (:objects page-2))
|
||||||
(filter #(= :text (:type %))))]
|
(filter #(= :text (:type %))))]
|
||||||
(t/is (= 2 (count pasted-texts))
|
(t/is (= 2 (count pasted-texts))
|
||||||
"Both text shapes are pasted onto the empty page")
|
"Both text shapes are pasted onto the empty page")
|
||||||
(t/is (every? #(nil? (:position-data %)) pasted-texts)
|
(t/is (every? #(nil? (:position-data %)) pasted-texts)
|
||||||
"Pasted text shapes have nil position-data so they get remeasured"))))))))
|
"Pasted text shapes have nil position-data so they get remeasured"))))))
|
||||||
|
done)))
|
||||||
|
|
||||||
(t/deftest paste-to-same-page-clears-text-position-data
|
(t/deftest paste-to-same-page-clears-text-position-data
|
||||||
"Position-data is stripped on paste regardless of destination page."
|
"Position-data is stripped on paste regardless of destination page."
|
||||||
(t/async done
|
(t/async done
|
||||||
(with-redefs [uuid/next cthi/next-uuid]
|
(mock/with-mocks {uuid/next cthi/next-uuid}
|
||||||
(let [file (setup-board-with-texts)
|
(fn [done']
|
||||||
store (ths/setup-store file)
|
(let [file (setup-board-with-texts)
|
||||||
events (copy-paste-shape :frame-1 file
|
store (ths/setup-store file)
|
||||||
:target-container-id uuid/zero)]
|
events (copy-paste-shape :frame-1 file
|
||||||
|
:target-container-id uuid/zero)]
|
||||||
|
|
||||||
(ths/run-store
|
(ths/run-store
|
||||||
store done events
|
store done' events
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
(let [file' (ths/get-file-from-state new-state)
|
(let [file' (ths/get-file-from-state new-state)
|
||||||
page-1' (cthf/get-page file' :page-1)
|
page-1' (cthf/get-page file' :page-1)
|
||||||
;; Pasted copies have IDs not registered in idmap — they show
|
;; Pasted copies have IDs not registered in idmap — they show
|
||||||
;; up as "<no-label …>" strings from cthi/label.
|
;; up as "<no-label …>" strings from cthi/label.
|
||||||
pasted-texts (->> (vals (:objects page-1'))
|
pasted-texts (->> (vals (:objects page-1'))
|
||||||
(filter #(= :text (:type %)))
|
(filter #(= :text (:type %)))
|
||||||
(remove #(keyword? (cthi/label (:id %)))))]
|
(remove #(keyword? (cthi/label (:id %)))))]
|
||||||
(t/is (= 2 (count pasted-texts))
|
(t/is (= 2 (count pasted-texts))
|
||||||
"Two new text shapes are pasted onto the same page")
|
"Two new text shapes are pasted onto the same page")
|
||||||
(t/is (every? #(nil? (:position-data %)) pasted-texts)
|
(t/is (every? #(nil? (:position-data %)) pasted-texts)
|
||||||
"Pasted text shapes have nil position-data"))))))))
|
"Pasted text shapes have nil position-data"))))))
|
||||||
|
done)))
|
||||||
|
|
||||||
|
|||||||
@ -126,11 +126,11 @@
|
|||||||
;; (e.g. the notification emit itself throws).
|
;; (e.g. the notification emit itself throws).
|
||||||
;; Without the re-entrancy guard this would recurse indefinitely.
|
;; Without the re-entrancy guard this would recurse indefinitely.
|
||||||
(when (= 1 @reentrant-call-count)
|
(when (= 1 @reentrant-call-count)
|
||||||
(errors/on-error {:type ::test-reentrant :hint "secondary"})))
|
(errors/on-error (ex-info "test" {:type ::test-reentrant :hint "secondary"}))))
|
||||||
|
|
||||||
(t/deftest on-error-reentrancy-guard-prevents-recursion
|
(t/deftest on-error-reentrancy-guard-prevents-recursion
|
||||||
(t/testing "a second on-error call while handling an error is suppressed by the guard"
|
(t/testing "a second on-error call while handling an error is suppressed by the guard"
|
||||||
(reset! reentrant-call-count 0)
|
(reset! reentrant-call-count 0)
|
||||||
(errors/on-error {:type ::test-reentrant :hint "first"})
|
(errors/on-error (ex-info "test" {:type ::test-reentrant :hint "first"}))
|
||||||
;; The guard must have allowed only the first invocation through.
|
;; The guard must have allowed only the first invocation through.
|
||||||
(t/is (= 1 @reentrant-call-count))))
|
(t/is (= 1 @reentrant-call-count))))
|
||||||
|
|||||||
@ -16,8 +16,13 @@
|
|||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
[cljs.test :as t :include-macros true]
|
[cljs.test :as t :include-macros true]
|
||||||
[frontend-tests.helpers.state :as ths]
|
[frontend-tests.helpers.state :as ths]
|
||||||
|
[frontend-tests.helpers.wasm :as thw]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
|
(t/use-fixtures :each
|
||||||
|
{:before (fn [] (thw/setup-wasm-mocks!))
|
||||||
|
:after thw/teardown-wasm-mocks!})
|
||||||
|
|
||||||
(defn- setup
|
(defn- setup
|
||||||
"Creates a file with two pages (page1 as current) and a plugin context."
|
"Creates a file with two pages (page1 as current) and a plugin context."
|
||||||
[]
|
[]
|
||||||
@ -47,11 +52,13 @@
|
|||||||
;; Regression: the flow proxy returned by createFlow (and obtained later via
|
;; Regression: the flow proxy returned by createFlow (and obtained later via
|
||||||
;; page.flows) must expose a valid board proxy for `startingBoard`, carrying
|
;; page.flows) must expose a valid board proxy for `startingBoard`, carrying
|
||||||
;; the plugin id rather than a corrupted handle. See issue #10203.
|
;; the plugin id rather than a corrupted handle. See issue #10203.
|
||||||
(let [{:keys [context board-id]} (setup-with-board)
|
(let [result (setup-with-board)
|
||||||
^js page (.-currentPage context)
|
^js context (:context result)
|
||||||
^js board (.getShapeById page (str board-id))
|
board-id (:board-id result)
|
||||||
^js flow (.createFlow page "flow1" board)
|
^js page (.-currentPage context)
|
||||||
^js sb (.-startingBoard flow)]
|
^js board (.getShapeById page (str board-id))
|
||||||
|
^js flow (.createFlow page "flow1" board)
|
||||||
|
^js sb (.-startingBoard flow)]
|
||||||
(t/is (shape/shape-proxy? sb))
|
(t/is (shape/shape-proxy? sb))
|
||||||
(t/is (= (str board-id) (.-id sb)))
|
(t/is (= (str board-id) (.-id sb)))
|
||||||
(t/is (= plugin-id (obj/get sb "$plugin")))
|
(t/is (= plugin-id (obj/get sb "$plugin")))
|
||||||
@ -71,24 +78,26 @@
|
|||||||
(ptk/emit! store (ptk/data-event ::dwpg/initialized page-id)))
|
(ptk/emit! store (ptk/data-event ::dwpg/initialized page-id)))
|
||||||
|
|
||||||
(t/deftest test-open-page-returns-promise
|
(t/deftest test-open-page-returns-promise
|
||||||
(let [{:keys [context]} (setup)
|
(let [^js context (:context (setup))
|
||||||
^js pages (.. context -currentFile -pages)
|
^js pages (.. context -currentFile -pages)
|
||||||
^js page2 (aget pages 1)]
|
^js page2 (aget pages 1)]
|
||||||
(t/is (instance? js/Promise (.openPage context page2)))))
|
(t/is (instance? js/Promise (.openPage context page2)))))
|
||||||
|
|
||||||
(t/deftest test-open-page-new-window-returns-promise
|
(t/deftest test-open-page-new-window-returns-promise
|
||||||
(let [{:keys [context]} (setup)
|
(let [^js context (:context (setup))
|
||||||
^js pages (.. context -currentFile -pages)
|
^js pages (.. context -currentFile -pages)
|
||||||
^js page2 (aget pages 1)]
|
^js page2 (aget pages 1)]
|
||||||
(t/is (instance? js/Promise (.openPage context page2 true)))))
|
(t/is (instance? js/Promise (.openPage context page2 true)))))
|
||||||
|
|
||||||
(t/deftest test-open-page-invalid-arg-returns-nil
|
(t/deftest test-open-page-invalid-arg-returns-nil
|
||||||
(let [{:keys [context]} (setup)]
|
(let [^js context (:context (setup))]
|
||||||
(t/is (nil? (.openPage context "not-a-page")))))
|
(t/is (nil? (.openPage context "not-a-page")))))
|
||||||
|
|
||||||
(t/deftest test-open-page-resolves-when-page-changes
|
(t/deftest test-open-page-resolves-when-page-changes
|
||||||
(t/async done
|
(t/async done
|
||||||
(let [{:keys [store context]} (setup)
|
(let [result (setup)
|
||||||
|
store (:store result)
|
||||||
|
^js context (:context result)
|
||||||
^js pages (.. context -currentFile -pages)
|
^js pages (.. context -currentFile -pages)
|
||||||
^js page2 (aget pages 1)
|
^js page2 (aget pages 1)
|
||||||
page2-id (obj/get page2 "$id")]
|
page2-id (obj/get page2 "$id")]
|
||||||
@ -102,17 +111,19 @@
|
|||||||
|
|
||||||
(t/deftest test-flows-returns-empty-array-when-no-flows
|
(t/deftest test-flows-returns-empty-array-when-no-flows
|
||||||
;; page.flows must always return an array, even when the page has no flows
|
;; page.flows must always return an array, even when the page has no flows
|
||||||
(let [{:keys [context]} (setup)
|
(let [^js context (:context (setup))
|
||||||
^js pages (.. context -currentFile -pages)
|
^js pages (.. context -currentFile -pages)
|
||||||
^js page1 (aget pages 0)
|
^js page1 (aget pages 0)
|
||||||
^js flows (.-flows page1)]
|
^js flows (.-flows page1)]
|
||||||
(t/is (array? flows))
|
(t/is (array? flows))
|
||||||
(t/is (= 0 (.-length flows)))))
|
(t/is (= 0 (.-length flows)))))
|
||||||
|
|
||||||
(t/deftest test-open-page-does-not-resolve-for-wrong-page
|
(t/deftest test-open-page-does-not-resolve-for-wrong-page
|
||||||
;; Promise should not resolve when a different page is initialized
|
;; Promise should not resolve when a different page is initialized
|
||||||
(t/async done
|
(t/async done
|
||||||
(let [{:keys [store context]} (setup)
|
(let [result (setup)
|
||||||
|
store (:store result)
|
||||||
|
^js context (:context result)
|
||||||
^js pages (.. context -currentFile -pages)
|
^js pages (.. context -currentFile -pages)
|
||||||
^js page1 (aget pages 0)
|
^js page1 (aget pages 0)
|
||||||
^js page2 (aget pages 1)
|
^js page2 (aget pages 1)
|
||||||
|
|||||||
@ -54,58 +54,62 @@
|
|||||||
|
|
||||||
(enable-console-print!)
|
(enable-console-print!)
|
||||||
|
|
||||||
(defmethod cljs.test/report [:cljs.test/default :end-run-tests] [m]
|
(defmethod t/report [:cljs.test/default :begin-test-var] [m]
|
||||||
|
(let [v (:var m)]
|
||||||
|
(println (str " ▸ " (:ns (meta v)) "/" (:name (meta v))))))
|
||||||
|
|
||||||
|
(defmethod t/report [:cljs.test/default :end-run-tests] [m]
|
||||||
(if (cljs.test/successful? m)
|
(if (cljs.test/successful? m)
|
||||||
(.exit js/process 0)
|
(.exit js/process 0)
|
||||||
(.exit js/process 1)))
|
(.exit js/process 1)))
|
||||||
|
|
||||||
(def test-namespaces
|
(def test-namespaces
|
||||||
'[frontend-tests.basic-shapes-test
|
['frontend-tests.basic-shapes-test
|
||||||
frontend-tests.code-gen-style-test
|
'frontend-tests.code-gen-style-test
|
||||||
frontend-tests.copy-as-svg-test
|
'frontend-tests.copy-as-svg-test
|
||||||
frontend-tests.data.nitrate-test
|
'frontend-tests.data.nitrate-test
|
||||||
frontend-tests.data.repo-test
|
'frontend-tests.data.repo-test
|
||||||
frontend-tests.errors-test
|
'frontend-tests.errors-test
|
||||||
frontend-tests.main-errors-test
|
'frontend-tests.main-errors-test
|
||||||
frontend-tests.data.uploads-test
|
'frontend-tests.data.uploads-test
|
||||||
frontend-tests.data.viewer-test
|
'frontend-tests.data.viewer-test
|
||||||
frontend-tests.data.workspace-colors-test
|
'frontend-tests.data.workspace-colors-test
|
||||||
frontend-tests.data.workspace-interactions-test
|
'frontend-tests.data.workspace-interactions-test
|
||||||
frontend-tests.data.workspace-mcp-test
|
'frontend-tests.data.workspace-mcp-test
|
||||||
frontend-tests.data.workspace-media-test
|
'frontend-tests.data.workspace-media-test
|
||||||
frontend-tests.data.workspace-shortcuts-test
|
'frontend-tests.data.workspace-shortcuts-test
|
||||||
frontend-tests.data.workspace-texts-test
|
'frontend-tests.data.workspace-texts-test
|
||||||
frontend-tests.data.workspace-thumbnails-test
|
'frontend-tests.data.workspace-thumbnails-test
|
||||||
frontend-tests.helpers-shapes-test
|
'frontend-tests.helpers-shapes-test
|
||||||
frontend-tests.logic.comp-remove-swap-slots-test
|
'frontend-tests.logic.comp-remove-swap-slots-test
|
||||||
frontend-tests.logic.components-and-tokens
|
'frontend-tests.logic.components-and-tokens
|
||||||
frontend-tests.logic.copying-and-duplicating-test
|
'frontend-tests.logic.copying-and-duplicating-test
|
||||||
frontend-tests.logic.frame-guides-test
|
'frontend-tests.logic.frame-guides-test
|
||||||
frontend-tests.logic.groups-test
|
'frontend-tests.logic.groups-test
|
||||||
frontend-tests.logic.pasting-in-containers-test
|
'frontend-tests.logic.pasting-in-containers-test
|
||||||
frontend-tests.plugins.context-shapes-test
|
'frontend-tests.plugins.context-shapes-test
|
||||||
frontend-tests.plugins.page-active-validation-test
|
'frontend-tests.plugins.page-active-validation-test
|
||||||
frontend-tests.plugins.interactions-test
|
'frontend-tests.plugins.interactions-test
|
||||||
frontend-tests.plugins.format-test
|
'frontend-tests.plugins.format-test
|
||||||
frontend-tests.plugins.page-test
|
'frontend-tests.plugins.page-test
|
||||||
frontend-tests.plugins.parser-test
|
'frontend-tests.plugins.parser-test
|
||||||
frontend-tests.plugins.tokens-test
|
'frontend-tests.plugins.tokens-test
|
||||||
frontend-tests.plugins.utils-test
|
'frontend-tests.plugins.utils-test
|
||||||
frontend-tests.svg-fills-test
|
'frontend-tests.svg-fills-test
|
||||||
frontend-tests.tokens.import-export-test
|
'frontend-tests.tokens.import-export-test
|
||||||
frontend-tests.tokens.logic.token-actions-test
|
'frontend-tests.tokens.logic.token-actions-test
|
||||||
frontend-tests.tokens.logic.token-data-test
|
'frontend-tests.tokens.logic.token-data-test
|
||||||
frontend-tests.tokens.logic.token-remapping-test
|
'frontend-tests.tokens.logic.token-remapping-test
|
||||||
frontend-tests.tokens.style-dictionary-test
|
'frontend-tests.tokens.style-dictionary-test
|
||||||
frontend-tests.tokens.token-errors-test
|
'frontend-tests.tokens.token-errors-test
|
||||||
frontend-tests.tokens.workspace-tokens-remap-test
|
'frontend-tests.tokens.workspace-tokens-remap-test
|
||||||
frontend-tests.ui.ds-controls-numeric-input-test
|
'frontend-tests.ui.ds-controls-numeric-input-test
|
||||||
frontend-tests.render-wasm.process-objects-test
|
'frontend-tests.render-wasm.process-objects-test
|
||||||
frontend-tests.util-object-test
|
'frontend-tests.util-object-test
|
||||||
frontend-tests.util-range-tree-test
|
'frontend-tests.util-range-tree-test
|
||||||
frontend-tests.util-simple-math-test
|
'frontend-tests.util-simple-math-test
|
||||||
frontend-tests.util-webapi-test
|
'frontend-tests.util-webapi-test
|
||||||
frontend-tests.worker-snap-test])
|
'frontend-tests.worker-snap-test])
|
||||||
|
|
||||||
(assert (every? find-ns-obj test-namespaces)
|
(assert (every? find-ns-obj test-namespaces)
|
||||||
"test-namespaces contains a namespace that isn't required in runner.cljs")
|
"test-namespaces contains a namespace that isn't required in runner.cljs")
|
||||||
@ -219,18 +223,18 @@
|
|||||||
:once-fixtures (:once fixtures)
|
:once-fixtures (:once fixtures)
|
||||||
:each-fixtures (:each fixtures))
|
:each-fixtures (:each fixtures))
|
||||||
summary (volatile! {:test 0 :pass 0 :fail 0 :error 0 :type :summary})]
|
summary (volatile! {:test 0 :pass 0 :fail 0 :error 0 :type :summary})]
|
||||||
|
|
||||||
|
(t/set-env! env)
|
||||||
|
|
||||||
(t/run-block
|
(t/run-block
|
||||||
(concat [(fn [] (t/set-env! env))]
|
(concat (t/test-vars-block vars)
|
||||||
(t/test-vars-block vars)
|
|
||||||
[(fn []
|
[(fn []
|
||||||
(vswap! summary
|
(vswap! summary
|
||||||
(partial merge-with +)
|
(partial merge-with +)
|
||||||
(:report-counters (t/get-and-clear-env!))))
|
(:report-counters (t/get-current-env))))
|
||||||
(fn []
|
(fn []
|
||||||
(t/set-env! env)
|
(t/report @summary)
|
||||||
(t/do-report @summary)
|
(t/report (assoc @summary :type :end-run-tests)))]))))
|
||||||
(t/report (assoc @summary :type :end-run-tests))
|
|
||||||
(t/clear-env!))]))))
|
|
||||||
|
|
||||||
(defn- run-focused-test!
|
(defn- run-focused-test!
|
||||||
[focus]
|
[focus]
|
||||||
@ -250,8 +254,8 @@
|
|||||||
|
|
||||||
:else
|
:else
|
||||||
(do
|
(do
|
||||||
(when-let [level (:log-level options)]
|
(l/setup! {:app (or (:log-level options) :warn)})
|
||||||
(l/setup! {:app level}))
|
|
||||||
(if (:focus options)
|
(if (:focus options)
|
||||||
(run-focused-test! (:focus options))
|
(run-focused-test! (:focus options))
|
||||||
(run-test-vars! (map #(selected-tests {:ns %}) test-namespaces)))))))
|
(run-test-vars! (map #(selected-tests {:ns %}) test-namespaces)))))))
|
||||||
|
|||||||
@ -22,11 +22,16 @@
|
|||||||
(json/encode {:type :json-verbose}))]
|
(json/encode {:type :json-verbose}))]
|
||||||
(->> (rx/of json)
|
(->> (rx/of json)
|
||||||
(dwti/import-file-stream "core")
|
(dwti/import-file-stream "core")
|
||||||
|
(rx/take 1)
|
||||||
(rx/subs! (fn [tokens-lib]
|
(rx/subs! (fn [tokens-lib]
|
||||||
(t/is (instance? ctob/TokensLib tokens-lib))
|
(t/is (instance? ctob/TokensLib tokens-lib))
|
||||||
(t/is (= "red" (-> tokens-lib
|
(t/is (= "red" (-> tokens-lib
|
||||||
(ctob/get-token-by-name "core" "color")
|
(ctob/get-token-by-name "core" "color")
|
||||||
(:value))))
|
(:value)))))
|
||||||
|
(fn [err]
|
||||||
|
(t/do-report {:type :error :message "Stream error" :actual err})
|
||||||
|
(done))
|
||||||
|
(fn []
|
||||||
(done))))))))
|
(done))))))))
|
||||||
|
|
||||||
(t/deftest reference-errors-test
|
(t/deftest reference-errors-test
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user