Andrey Antukh dc38eaa843
🐛 Fix font upload crash and preserve font metadata (#11951)
* 🐛 Fix font upload crash and preserve variant metadata

opentype.js 2.0.0 returns no fontSubfamily name for fonts whose
Macintosh name table only holds custom records. That made
parse-font-weight/parse-font-style call re-seq on nil and crash the
upload.

A nil or blank variant is now treated as no match in
app.common.media, defaulting to weight 400 and style normal. The
variant parsing also accepts oblique as italic, and the new
parse-font-family helper derives the family from a filename by
stripping the known weight/style tokens, separating a style token
glued to a weight token ("Roboto-BoldItalic" -> "Roboto").
first-nonblank-string returns the first nonblank candidate, so a
blank preferredFamily/preferredSubfamily no longer shadows a valid
fontFamily/fontSubfamily.

app.main.data.fonts gains resolve-font-metadata and
prepare-font-entry. opentype.js values win per field; any missing
value falls back to the filename-derived family, weight and style.
The parsed and woff2 branches share the same helper, so metadata is
preserved instead of collapsing every face to weight 400, and
fonts with missing vertical-metric tables upload with no height
warning instead of failing.

process-upload reports per-file failures (unknown signature,
unparseable file, preparation error) with a single bad-font
notification instead of silently dropping them, and never errors
for per-file failures.

The upload now sends :variant-name to create-font-variant, which
accepts it as an optional param (ships in 2.20), so the foundry
name survives the upload.

Closes #10436

AI-assisted-by: deepseek-v4.1-flash
AI-assisted-by: muse-spark-1.3-contributor
Signed-off-by: CHOI JUNSOO <junsoo1172@gmail.com>

* 🐛 Parse glued font style tokens in the font parsers

EvaMarco's review on #11951: parse-font-family and
parse-font-weight handled glued tokens like "BoldItalic", but
parse-font-style did not. For names such as
"opensans-bolditalic-webfont.woff2" the three parsers disagreed:
the italic face resolved to style normal and collided with the
bold-only file on the (family, weight, style) join key. One
binary silently overwrote the other during upload, losing one
font face without any warning.

A new private normalize-font-name helper is applied by all three
parsers. It splits a style token glued to a weight token, now
with a lookahead boundary so "LightItalic_v2" splits too, and
strips a trailing technical suffix (-VF or _v<number>).
parse-font-family, parse-font-weight and parse-font-style now
interpret the name consistently.

Tests cover the three cases from the review, the bold-only
control case, and an end-to-end process-upload check that a bold
and a bold-italic WOFF2 survive as two variants.

Relates to #10436 and PR #11951.

AI-assisted-by: inkling-2-small-free

* Remove duplicate frontend test registration

---------

Signed-off-by: CHOI JUNSOO <junsoo1172@gmail.com>
2026-11-12 15:29:30 +01:00

543 lines
22 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.browser-history-test]
[frontend-tests.code-gen-style-test]
[frontend-tests.composable-tests.comp.sync-test]
[frontend-tests.copy-as-svg-test]
[frontend-tests.data.auth-test]
[frontend-tests.data.comments-batches-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.exports-files-test]
[frontend-tests.data.fix-deleted-fonts-test]
[frontend-tests.data.fonts-test]
[frontend-tests.data.imports-test]
[frontend-tests.data.jobs-test]
[frontend-tests.data.modal-test]
[frontend-tests.data.nitrate-test]
[frontend-tests.data.persistence-commits-test]
[frontend-tests.data.persistence-lock-test]
[frontend-tests.data.persistence-retry-test]
[frontend-tests.data.persistence-rollback-test]
[frontend-tests.data.persistence-test]
[frontend-tests.data.pointer-map-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.team-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-focus-test]
[frontend-tests.data.workspace-interactions-test]
[frontend-tests.data.workspace-libraries-sync-test]
[frontend-tests.data.workspace-mcp-test]
[frontend-tests.data.workspace-media-test]
[frontend-tests.data.workspace-notifications-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-undo-test]
[frontend-tests.data.workspace-variant-rename-test]
[frontend-tests.data.workspace-variants-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.bool-move-test]
[frontend-tests.logic.comp-remove-swap-slots-test]
[frontend-tests.logic.comp-watcher-test]
[frontend-tests.logic.components-and-tokens]
[frontend-tests.logic.copy-paste-typography-test]
[frontend-tests.logic.copying-and-duplicating-test]
[frontend-tests.logic.drag-on-save-failure-test]
[frontend-tests.logic.frame-guides-test]
[frontend-tests.logic.groups-test]
[frontend-tests.logic.ignore-tree-test]
[frontend-tests.logic.move-shapes-to-frame-test]
[frontend-tests.logic.multi-variant-switch-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.creation-parent-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.management-test]
[frontend-tests.plugins.page-active-validation-test]
[frontend-tests.plugins.page-test]
[frontend-tests.plugins.parser-test]
[frontend-tests.plugins.read-only-test]
[frontend-tests.plugins.register-test]
[frontend-tests.plugins.shape-bugfixes-test]
[frontend-tests.plugins.system-events-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.shape-proxy-test]
[frontend-tests.render-wasm.text-editor-apply-styles-test]
[frontend-tests.render-wasm.text-editor-caret-color-test]
[frontend-tests.render-wasm.text-editor-content-range-test]
[frontend-tests.render-wasm.text-paste-test]
[frontend-tests.render-wasm.webgl-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-source-test]
[frontend-tests.tokens.logic.tokens-status-test]
[frontend-tests.tokens.referenced-token-value-test]
[frontend-tests.tokens.shadow-form-test]
[frontend-tests.tokens.style-dictionary-test]
[frontend-tests.tokens.token-errors-test]
[frontend-tests.tokens.token-parsing-test]
[frontend-tests.tokens.token-path-test]
[frontend-tests.tokens.token-pill-test]
[frontend-tests.tokens.token-tree-test]
[frontend-tests.tokens.tokenscript-test]
[frontend-tests.tokens.typography-form-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.dashboard-import-linking-test]
[frontend-tests.ui.drawarea-test]
[frontend-tests.ui.ds-controls-numeric-input-test]
[frontend-tests.ui.error-boundary-test]
[frontend-tests.ui.file-restored-modal-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.jobs-progress-test]
[frontend-tests.ui.layout-container-multiple-test]
[frontend-tests.ui.mcp-authorize-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.shape-filters-test]
[frontend-tests.ui.shortcuts-labels-test]
[frontend-tests.ui.sidebar-scroll-test]
[frontend-tests.ui.sortable-auto-scroll-test]
[frontend-tests.ui.static-test]
[frontend-tests.ui.stroke-menu-test]
[frontend-tests.ui.subscription-test]
[frontend-tests.ui.text-attrs-multiple-test]
[frontend-tests.ui.viewport-top-bar-test]
[frontend-tests.ui.workspace-libraries-test]
[frontend-tests.util-clipboard-test]
[frontend-tests.util-http-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-clipboard-test]
[frontend-tests.util-text-editor-test]
[frontend-tests.util-theme-test]
[frontend-tests.util-webapi-test]
[frontend-tests.util-zip-test]
[frontend-tests.util.code-gen-markup-svg-wasm-test]
[frontend-tests.util.dom.dnd-test]
[frontend-tests.worker-snap-test]
[frontend-tests.worker.exports-test]
[frontend-tests.worker.index-test]
[frontend-tests.worker.trim-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.auth-test
'frontend-tests.data.comments-batches-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.modal-test
'frontend-tests.data.nitrate-test
'frontend-tests.data.persistence-commits-test
'frontend-tests.data.persistence-lock-test
'frontend-tests.data.persistence-retry-test
'frontend-tests.data.persistence-rollback-test
'frontend-tests.data.persistence-test
'frontend-tests.data.pointer-map-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.exports-files-test
'frontend-tests.data.fonts-test
'frontend-tests.data.imports-test
'frontend-tests.data.jobs-test
'frontend-tests.worker.exports-test
'frontend-tests.worker.index-test
'frontend-tests.worker.trim-test
'frontend-tests.data.svg-upload-test
'frontend-tests.data.team-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-focus-test
'frontend-tests.data.workspace-interactions-test
'frontend-tests.data.workspace-libraries-sync-test
'frontend-tests.data.workspace-mcp-test
'frontend-tests.data.workspace-media-test
'frontend-tests.data.workspace-notifications-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-undo-test
'frontend-tests.data.workspace-variant-rename-test
'frontend-tests.data.workspace-variants-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.bool-move-test
'frontend-tests.logic.comp-remove-swap-slots-test
'frontend-tests.logic.comp-watcher-test
'frontend-tests.logic.components-and-tokens
'frontend-tests.logic.copy-paste-typography-test
'frontend-tests.logic.copying-and-duplicating-test
'frontend-tests.logic.drag-on-save-failure-test
'frontend-tests.logic.frame-guides-test
'frontend-tests.logic.groups-test
'frontend-tests.logic.ignore-tree-test
'frontend-tests.logic.move-shapes-to-frame-test
'frontend-tests.logic.multi-variant-switch-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.creation-parent-test
'frontend-tests.plugins.events-test
'frontend-tests.plugins.management-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.read-only-test
'frontend-tests.plugins.register-test
'frontend-tests.plugins.shape-bugfixes-test
'frontend-tests.plugins.system-events-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.shape-proxy-test
'frontend-tests.render-wasm.text-editor-apply-styles-test
'frontend-tests.render-wasm.text-editor-caret-color-test
'frontend-tests.render-wasm.text-editor-content-range-test
'frontend-tests.render-wasm.text-paste-test
'frontend-tests.render-wasm.webgl-test
'frontend-tests.browser-history-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.referenced-token-value-test
'frontend-tests.tokens.shadow-form-test
'frontend-tests.tokens.style-dictionary-test
'frontend-tests.tokens.token-errors-test
'frontend-tests.tokens.token-parsing-test
'frontend-tests.tokens.token-path-test
'frontend-tests.tokens.token-pill-test
'frontend-tests.tokens.token-tree-test
'frontend-tests.tokens.tokenscript-test
'frontend-tests.tokens.typography-form-test
'frontend-tests.tokens.logic.tokens-source-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.dashboard-import-linking-test
'frontend-tests.ui.drawarea-test
'frontend-tests.ui.ds-controls-numeric-input-test
'frontend-tests.ui.error-boundary-test
'frontend-tests.ui.file-restored-modal-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.jobs-progress-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.mcp-authorize-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.shape-filters-test
'frontend-tests.ui.shortcuts-labels-test
'frontend-tests.ui.sidebar-scroll-test
'frontend-tests.ui.sortable-auto-scroll-test
'frontend-tests.ui.static-test
'frontend-tests.ui.stroke-menu-test
'frontend-tests.ui.text-attrs-multiple-test
'frontend-tests.ui.viewport-top-bar-test
'frontend-tests.ui.workspace-libraries-test
'frontend-tests.util-clipboard-test
'frontend-tests.util-http-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-clipboard-test
'frontend-tests.util-text-editor-test
'frontend-tests.util-theme-test
'frontend-tests.util-webapi-test
'frontend-tests.util.code-gen-markup-svg-wasm-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)))))))