mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 22:10:34 +00:00
* 🐛 Fix nested libraries vanishing from the libraries modal The "This file" tab nests each linked library under a linked library that uses it, taken from the team shared files. A library with such a parent was removed from the top level and only drawn under its parent if the parent was at the top level itself. So: - In a chain of two or more levels (file -> A -> B -> C), C was lost. - In a cycle (A uses B and B uses A), both had a parent, none was at the top level, and both were lost. The libraries showed while the shared files were loading, and vanished when they arrived. Build the list as a tree instead: direct libraries and libraries not used by any other linked library are roots, nested libraries follow their parent at any depth, and each library is added only once, even when the dependencies form a cycle. AI-assisted-by: claude-opus-5-5 * ♻️ Move the linked libraries tree to sort-linked-libraries Extract the code that orders the linked libraries as a tree from the file tab to a public function, so it can be tested on its own. Add tests for a cycle with a direct root, a cycle with no root, a deep chain and no dependencies yet. AI-assisted-by: claude-opus-5-5 * ♻️ Use connected-to to find library parents when sorting The caller already computes :connected-to for each linked library, the reverse index of the dependencies map. sort-linked-libraries rebuilt the same relation from dependencies. Read it from :connected-to instead, so the function takes only the libraries and the component memo no longer depends on dependencies. Reword the cycle-without-root test to say it models the unknown direct flag, and add tests for a diamond, a self-dependency, a cycle of three without root, a parent that is not a linked library, and for no library being lost or duplicated. AI-assisted-by: claude-sonnet-5-5 --------- Co-authored-by: Andrés Moya <andres.moya@kaleidos.net>
424 lines
16 KiB
Clojure
424 lines
16 KiB
Clojure
(ns frontend-tests.runner
|
|
(:require
|
|
[app.common.logging :as l]
|
|
[cljs.test :as t]
|
|
[clojure.string :as str]
|
|
[clojure.tools.cli :refer [parse-opts]]
|
|
[frontend-tests.basic-shapes-test]
|
|
[frontend-tests.code-gen-style-test]
|
|
[frontend-tests.composable-tests.comp.sync-test]
|
|
[frontend-tests.copy-as-svg-test]
|
|
[frontend-tests.data.comments-filters-test]
|
|
[frontend-tests.data.dashboard-test]
|
|
[frontend-tests.data.event-test]
|
|
[frontend-tests.data.exports-assets-test]
|
|
[frontend-tests.data.fix-deleted-fonts-test]
|
|
[frontend-tests.data.nitrate-test]
|
|
[frontend-tests.data.persistence-retry-test]
|
|
[frontend-tests.data.persistence-test]
|
|
[frontend-tests.data.profile-test]
|
|
[frontend-tests.data.repo-test]
|
|
[frontend-tests.data.store-test]
|
|
[frontend-tests.data.svg-upload-test]
|
|
[frontend-tests.data.uploads-test]
|
|
[frontend-tests.data.viewer-test]
|
|
[frontend-tests.data.workspace-colors-test]
|
|
[frontend-tests.data.workspace-comments-test]
|
|
[frontend-tests.data.workspace-context-menu-test]
|
|
[frontend-tests.data.workspace-interactions-test]
|
|
[frontend-tests.data.workspace-mcp-test]
|
|
[frontend-tests.data.workspace-media-test]
|
|
[frontend-tests.data.workspace-pages-test]
|
|
[frontend-tests.data.workspace-path-edition-test]
|
|
[frontend-tests.data.workspace-reflow-test]
|
|
[frontend-tests.data.workspace-shortcuts-test]
|
|
[frontend-tests.data.workspace-texts-test]
|
|
[frontend-tests.data.workspace-thumbnails-test]
|
|
[frontend-tests.data.workspace-versions-test]
|
|
[frontend-tests.debug-logging-test]
|
|
[frontend-tests.errors-governor-test]
|
|
[frontend-tests.errors-test]
|
|
[frontend-tests.fonts-test]
|
|
[frontend-tests.helpers-shapes-test]
|
|
[frontend-tests.logic.comp-remove-swap-slots-test]
|
|
[frontend-tests.logic.components-and-tokens]
|
|
[frontend-tests.logic.copy-paste-typography-test]
|
|
[frontend-tests.logic.copying-and-duplicating-test]
|
|
[frontend-tests.logic.frame-guides-test]
|
|
[frontend-tests.logic.groups-test]
|
|
[frontend-tests.logic.nudge-selected-shapes-test]
|
|
[frontend-tests.logic.pasting-in-containers-test]
|
|
[frontend-tests.logic.path-actions-test]
|
|
[frontend-tests.logic.path-clipboard-test]
|
|
[frontend-tests.logic.path-helpers-test]
|
|
[frontend-tests.logic.path-lifecycle-test]
|
|
[frontend-tests.logic.path-tools-test]
|
|
[frontend-tests.logic.sidebar-transform-coalescing-test]
|
|
[frontend-tests.logic.update-position-test]
|
|
[frontend-tests.logic.wasm-modifiers-nil-id-test]
|
|
[frontend-tests.logic.wasm-pixel-snap-test]
|
|
[frontend-tests.main-errors-test]
|
|
[frontend-tests.main.refs-test]
|
|
[frontend-tests.plugins.comments-test]
|
|
[frontend-tests.plugins.context-shapes-test]
|
|
[frontend-tests.plugins.events-test]
|
|
[frontend-tests.plugins.file-test]
|
|
[frontend-tests.plugins.flex-test]
|
|
[frontend-tests.plugins.format-test]
|
|
[frontend-tests.plugins.grid-test]
|
|
[frontend-tests.plugins.interactions-test]
|
|
[frontend-tests.plugins.library-test]
|
|
[frontend-tests.plugins.local-storage-test]
|
|
[frontend-tests.plugins.page-active-validation-test]
|
|
[frontend-tests.plugins.page-test]
|
|
[frontend-tests.plugins.parser-test]
|
|
[frontend-tests.plugins.register-test]
|
|
[frontend-tests.plugins.shape-bugfixes-test]
|
|
[frontend-tests.plugins.text-test]
|
|
[frontend-tests.plugins.tokens-test]
|
|
[frontend-tests.plugins.user-test]
|
|
[frontend-tests.plugins.utils-test]
|
|
[frontend-tests.plugins.value-objects-test]
|
|
[frontend-tests.render-dimensions-test]
|
|
[frontend-tests.render-wasm.process-objects-test]
|
|
[frontend-tests.render-wasm.serialization-test]
|
|
[frontend-tests.render-wasm.text-editor-apply-styles-test]
|
|
[frontend-tests.render-wasm.text-editor-caret-color-test]
|
|
[frontend-tests.router-test]
|
|
[frontend-tests.svg-fills-test]
|
|
[frontend-tests.svg-filters-test]
|
|
[frontend-tests.text-editor-paste-guard-test]
|
|
[frontend-tests.tokens.context-menu-test]
|
|
[frontend-tests.tokens.copy-paste-props-test]
|
|
[frontend-tests.tokens.import-export-test]
|
|
[frontend-tests.tokens.logic.token-actions-test]
|
|
[frontend-tests.tokens.logic.token-data-test]
|
|
[frontend-tests.tokens.logic.token-remapping-test]
|
|
[frontend-tests.tokens.logic.tokens-status-test]
|
|
[frontend-tests.tokens.style-dictionary-test]
|
|
[frontend-tests.tokens.token-errors-test]
|
|
[frontend-tests.tokens.workspace-tokens-remap-test]
|
|
[frontend-tests.ui.check-updates-test]
|
|
[frontend-tests.ui.color-token-position-test]
|
|
[frontend-tests.ui.colorpicker-token-set-order-test]
|
|
[frontend-tests.ui.comment-input-ime-test]
|
|
[frontend-tests.ui.comments-clustering-test]
|
|
[frontend-tests.ui.comments-position-modifier-test]
|
|
[frontend-tests.ui.drawarea-test]
|
|
[frontend-tests.ui.ds-controls-numeric-input-test]
|
|
[frontend-tests.ui.gradient-handlers-test]
|
|
[frontend-tests.ui.history-test]
|
|
[frontend-tests.ui.inspect-geometry-test]
|
|
[frontend-tests.ui.inspect-stroke-tokens-test]
|
|
[frontend-tests.ui.layout-container-multiple-test]
|
|
[frontend-tests.ui.measurements-test]
|
|
[frontend-tests.ui.measures-menu-props-test]
|
|
[frontend-tests.ui.organization-team-switch-test]
|
|
[frontend-tests.ui.routes-test]
|
|
[frontend-tests.ui.settings-password-schema-test]
|
|
[frontend-tests.ui.settings-shortcuts-test]
|
|
[frontend-tests.ui.shortcuts-labels-test]
|
|
[frontend-tests.ui.sidebar-scroll-test]
|
|
[frontend-tests.ui.stroke-menu-test]
|
|
[frontend-tests.ui.workspace-libraries-test]
|
|
[frontend-tests.util-clipboard-test]
|
|
[frontend-tests.util-object-test]
|
|
[frontend-tests.util-queue-test]
|
|
[frontend-tests.util-range-tree-test]
|
|
[frontend-tests.util-simple-math-test]
|
|
[frontend-tests.util-text-editor-test]
|
|
[frontend-tests.util-webapi-test]
|
|
[frontend-tests.util-zip-test]
|
|
[frontend-tests.util.dom.dnd-test]
|
|
[frontend-tests.worker-snap-test]
|
|
[goog.object :as gobj]))
|
|
|
|
(enable-console-print!)
|
|
|
|
(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)
|
|
(.exit js/process 0)
|
|
(.exit js/process 1)))
|
|
|
|
(def test-namespaces
|
|
['frontend-tests.basic-shapes-test
|
|
'frontend-tests.code-gen-style-test
|
|
'frontend-tests.composable-tests.comp.sync-test
|
|
'frontend-tests.copy-as-svg-test
|
|
'frontend-tests.data.comments-filters-test
|
|
'frontend-tests.data.dashboard-test
|
|
'frontend-tests.data.event-test
|
|
'frontend-tests.data.fix-deleted-fonts-test
|
|
'frontend-tests.data.nitrate-test
|
|
'frontend-tests.data.persistence-retry-test
|
|
'frontend-tests.data.persistence-test
|
|
'frontend-tests.data.profile-test
|
|
'frontend-tests.data.repo-test
|
|
'frontend-tests.data.store-test
|
|
'frontend-tests.data.exports-assets-test
|
|
'frontend-tests.data.svg-upload-test
|
|
'frontend-tests.data.uploads-test
|
|
'frontend-tests.data.viewer-test
|
|
'frontend-tests.data.workspace-colors-test
|
|
'frontend-tests.data.workspace-comments-test
|
|
'frontend-tests.data.workspace-context-menu-test
|
|
'frontend-tests.data.workspace-interactions-test
|
|
'frontend-tests.data.workspace-mcp-test
|
|
'frontend-tests.data.workspace-media-test
|
|
'frontend-tests.data.workspace-pages-test
|
|
'frontend-tests.data.workspace-path-edition-test
|
|
'frontend-tests.data.workspace-reflow-test
|
|
'frontend-tests.data.workspace-shortcuts-test
|
|
'frontend-tests.data.workspace-texts-test
|
|
'frontend-tests.data.workspace-thumbnails-test
|
|
'frontend-tests.data.workspace-versions-test
|
|
'frontend-tests.debug-logging-test
|
|
'frontend-tests.errors-governor-test
|
|
'frontend-tests.errors-test
|
|
'frontend-tests.fonts-test
|
|
'frontend-tests.helpers-shapes-test
|
|
'frontend-tests.logic.comp-remove-swap-slots-test
|
|
'frontend-tests.logic.components-and-tokens
|
|
'frontend-tests.logic.copy-paste-typography-test
|
|
'frontend-tests.logic.copying-and-duplicating-test
|
|
'frontend-tests.logic.frame-guides-test
|
|
'frontend-tests.logic.groups-test
|
|
'frontend-tests.logic.nudge-selected-shapes-test
|
|
'frontend-tests.logic.path-actions-test
|
|
'frontend-tests.logic.path-clipboard-test
|
|
'frontend-tests.logic.path-helpers-test
|
|
'frontend-tests.logic.path-lifecycle-test
|
|
'frontend-tests.logic.path-tools-test
|
|
'frontend-tests.logic.pasting-in-containers-test
|
|
'frontend-tests.main.refs-test
|
|
'frontend-tests.main-errors-test
|
|
'frontend-tests.logic.sidebar-transform-coalescing-test
|
|
'frontend-tests.logic.update-position-test
|
|
'frontend-tests.logic.wasm-modifiers-nil-id-test
|
|
'frontend-tests.logic.wasm-pixel-snap-test
|
|
'frontend-tests.plugins.comments-test
|
|
'frontend-tests.plugins.context-shapes-test
|
|
'frontend-tests.plugins.events-test
|
|
'frontend-tests.plugins.file-test
|
|
'frontend-tests.plugins.flex-test
|
|
'frontend-tests.plugins.format-test
|
|
'frontend-tests.plugins.grid-test
|
|
'frontend-tests.plugins.interactions-test
|
|
'frontend-tests.plugins.library-test
|
|
'frontend-tests.plugins.local-storage-test
|
|
'frontend-tests.plugins.page-active-validation-test
|
|
'frontend-tests.plugins.page-test
|
|
'frontend-tests.plugins.parser-test
|
|
'frontend-tests.plugins.register-test
|
|
'frontend-tests.plugins.shape-bugfixes-test
|
|
'frontend-tests.plugins.text-test
|
|
'frontend-tests.plugins.tokens-test
|
|
'frontend-tests.plugins.user-test
|
|
'frontend-tests.plugins.utils-test
|
|
'frontend-tests.plugins.value-objects-test
|
|
'frontend-tests.render-wasm.process-objects-test
|
|
'frontend-tests.render-wasm.serialization-test
|
|
'frontend-tests.render-wasm.text-editor-apply-styles-test
|
|
'frontend-tests.render-wasm.text-editor-caret-color-test
|
|
'frontend-tests.router-test
|
|
'frontend-tests.svg-fills-test
|
|
'frontend-tests.svg-filters-test
|
|
'frontend-tests.tokens.copy-paste-props-test
|
|
'frontend-tests.tokens.context-menu-test
|
|
'frontend-tests.tokens.import-export-test
|
|
'frontend-tests.tokens.logic.token-actions-test
|
|
'frontend-tests.tokens.logic.token-data-test
|
|
'frontend-tests.tokens.logic.token-remapping-test
|
|
'frontend-tests.tokens.style-dictionary-test
|
|
'frontend-tests.tokens.token-errors-test
|
|
'frontend-tests.tokens.logic.tokens-status-test
|
|
'frontend-tests.tokens.workspace-tokens-remap-test
|
|
'frontend-tests.ui.check-updates-test
|
|
'frontend-tests.ui.color-token-position-test
|
|
'frontend-tests.ui.colorpicker-token-set-order-test
|
|
'frontend-tests.ui.comment-input-ime-test
|
|
'frontend-tests.ui.comments-clustering-test
|
|
'frontend-tests.ui.comments-position-modifier-test
|
|
'frontend-tests.ui.drawarea-test
|
|
'frontend-tests.ui.ds-controls-numeric-input-test
|
|
'frontend-tests.ui.gradient-handlers-test
|
|
'frontend-tests.ui.history-test
|
|
'frontend-tests.ui.inspect-geometry-test
|
|
'frontend-tests.ui.inspect-stroke-tokens-test
|
|
'frontend-tests.ui.layout-container-multiple-test
|
|
'frontend-tests.ui.measurements-test
|
|
'frontend-tests.ui.measures-menu-props-test
|
|
'frontend-tests.ui.organization-team-switch-test
|
|
'frontend-tests.ui.routes-test
|
|
'frontend-tests.render-dimensions-test
|
|
'frontend-tests.text-editor-paste-guard-test
|
|
'frontend-tests.ui.settings-password-schema-test
|
|
'frontend-tests.ui.settings-shortcuts-test
|
|
'frontend-tests.ui.shortcuts-labels-test
|
|
'frontend-tests.ui.sidebar-scroll-test
|
|
'frontend-tests.ui.stroke-menu-test
|
|
'frontend-tests.ui.workspace-libraries-test
|
|
'frontend-tests.util-clipboard-test
|
|
'frontend-tests.util-object-test
|
|
'frontend-tests.util-queue-test
|
|
'frontend-tests.util-range-tree-test
|
|
'frontend-tests.util-simple-math-test
|
|
'frontend-tests.util-text-editor-test
|
|
'frontend-tests.util-webapi-test
|
|
'frontend-tests.util.dom.dnd-test
|
|
'frontend-tests.util-zip-test
|
|
'frontend-tests.worker-snap-test])
|
|
|
|
(assert (every? find-ns-obj test-namespaces)
|
|
"test-namespaces contains a namespace that isn't required in runner.cljs")
|
|
|
|
;; This runner intentionally mirrors common-tests.runner. Both runners need
|
|
;; forwarded CLI args, focused namespace/var execution, fixture preservation,
|
|
;; and app log-level setup. A shared helper could own those mechanics, but we
|
|
;; keep the logic local while there are only two test targets because sharing
|
|
;; it would add cross-module test classpath coupling.
|
|
(def ^:private log-levels
|
|
#{:trace :debug :info :warn :error})
|
|
|
|
(def cli-options
|
|
[["-f" "--focus FOCUS" "Run one test namespace or one test var, e.g. frontend-tests.logic.components-and-tokens/change-token-in-main"]
|
|
["-l" "--log-level LEVEL" "Set app logger level: trace|debug|info|warn|error"
|
|
:parse-fn keyword
|
|
:validate [log-levels "must be one of trace, debug, info, warn, error"]]
|
|
["-h" "--help"]])
|
|
|
|
(defn- argv
|
|
[]
|
|
(let [args (->> (.-argv js/process)
|
|
(array-seq)
|
|
(drop 2))]
|
|
;; `pnpm run test -- --focus ...` forwards the separator to the node
|
|
;; process, so drop one leading `--` before handing args to tools.cli.
|
|
(cond-> args
|
|
(= "--" (first args)) rest)))
|
|
|
|
(defn- usage
|
|
[summary]
|
|
(str "Usage: pnpm run test -- [options]\n\n"
|
|
"Options:\n"
|
|
summary "\n\n"
|
|
"Focus examples:\n"
|
|
" pnpm run test -- --focus frontend-tests.logic.components-and-tokens\n"
|
|
" pnpm run test -- --focus frontend-tests.logic.components-and-tokens/change-token-in-main\n\n"
|
|
"Log level example (quiets app logging during the run):\n"
|
|
" pnpm run test -- --focus frontend-tests.logic.groups-test --log-level warn"))
|
|
|
|
(defn- fail!
|
|
[message]
|
|
(js/console.error message)
|
|
(.exit js/process 1))
|
|
|
|
(defn- parse-focus
|
|
[focus]
|
|
(let [[ns-name test-name & extra] (str/split focus #"/")]
|
|
(cond
|
|
(or (str/blank? ns-name) (seq extra))
|
|
(fail! (str "Invalid --focus value: " focus))
|
|
|
|
(some? test-name)
|
|
{:ns (symbol ns-name) :test test-name}
|
|
|
|
:else
|
|
{:ns (symbol ns-name)})))
|
|
|
|
(defn- fixture-value
|
|
[ns-obj fixture-name]
|
|
(let [value (gobj/get ns-obj (munge fixture-name))]
|
|
(when-not (undefined? value)
|
|
value)))
|
|
|
|
(defn- ns-test-vars
|
|
[ns-sym]
|
|
(when-let [ns-obj (find-ns-obj ns-sym)]
|
|
(->> (js-keys ns-obj)
|
|
(keep (fn [key]
|
|
(some-> (gobj/get ns-obj key)
|
|
(.-cljs$lang$var))))
|
|
(filter (comp :test meta))
|
|
(sort-by (comp :line meta)))))
|
|
|
|
(defn- ns-fixtures
|
|
[ns-sym vars]
|
|
(when-let [ns-obj (find-ns-obj ns-sym)]
|
|
(let [ns-key (or (some-> vars first meta :ns) ns-sym)
|
|
once-fixtures (fixture-value ns-obj "cljs-test-once-fixtures")
|
|
each-fixtures (fixture-value ns-obj "cljs-test-each-fixtures")]
|
|
{:once (when once-fixtures {ns-key once-fixtures})
|
|
:each (when each-fixtures {ns-key each-fixtures})})))
|
|
|
|
(defn- selected-tests
|
|
[{:keys [ns test]}]
|
|
(when-not (some #{ns} test-namespaces)
|
|
(fail! (str "Unknown test namespace: " ns)))
|
|
(let [vars (vec (ns-test-vars ns))]
|
|
(when (empty? vars)
|
|
(fail! (str "No tests found in namespace: " ns)))
|
|
(if test
|
|
(let [test-sym (symbol test)
|
|
test-var (some #(when (= test-sym (:name (meta %))) %) vars)]
|
|
(if test-var
|
|
{:vars [test-var]
|
|
:fixtures (ns-fixtures ns [test-var])}
|
|
(fail! (str "Unknown test var: " ns "/" test))))
|
|
{:vars vars
|
|
:fixtures (ns-fixtures ns vars)})))
|
|
|
|
(defn- merge-fixtures
|
|
[fixtures]
|
|
{:once (apply merge (keep :once fixtures))
|
|
:each (apply merge (keep :each fixtures))})
|
|
|
|
(defn- run-test-vars!
|
|
[tests]
|
|
(let [vars (vec (mapcat :vars tests))
|
|
fixtures (merge-fixtures (map :fixtures tests))
|
|
env (assoc (t/empty-env)
|
|
:once-fixtures (:once fixtures)
|
|
:each-fixtures (:each fixtures))
|
|
summary (volatile! {:test 0 :pass 0 :fail 0 :error 0 :type :summary})]
|
|
|
|
(t/set-env! env)
|
|
|
|
(t/run-block
|
|
(concat (t/test-vars-block vars)
|
|
[(fn []
|
|
(vswap! summary
|
|
(partial merge-with +)
|
|
(:report-counters (t/get-current-env))))
|
|
(fn []
|
|
(t/report @summary)
|
|
(t/report (assoc @summary :type :end-run-tests)))]))))
|
|
|
|
(defn- run-focused-test!
|
|
[focus]
|
|
(run-test-vars! [(selected-tests (parse-focus focus))]))
|
|
|
|
(defn init
|
|
[]
|
|
(let [{:keys [options errors summary]} (parse-opts (argv) cli-options)]
|
|
(cond
|
|
(seq errors)
|
|
(fail! (str/join "\n" errors))
|
|
|
|
(:help options)
|
|
(do
|
|
(println (usage summary))
|
|
(.exit js/process 0))
|
|
|
|
:else
|
|
(do
|
|
(l/setup! {:app (or (:log-level options) :warn)})
|
|
|
|
(if (:focus options)
|
|
(run-focused-test! (:focus options))
|
|
(run-test-vars! (map #(selected-tests {:ns %}) test-namespaces)))))))
|