alonso.torres 9ea2a8e6eb ✨ Keep the children of a transformed copy shape derived
Decision (f) of the component contract, with a fix it needed and a check of
decision (g) (Phase 3c).

- Return empty modifiers for a scale constraint axis.

  The constraint of each axis of a child gives the modifiers that the
  parent's resize adds to the child; :scale has no method of its own and
  took the default, which returned an empty vector. Adding a vector to
  modifiers reads its :last-order as nil: JavaScript adds nil as 0, the JVM
  throws, so a child scaled on one axis and constrained on the other (scale
  and top, say) could not be resized on the JVM. The default now returns
  empty modifiers.

  geom-shapes-constraints-test checks the default is empty and adds to
  modifiers.

- Keep the children of a transformed copy shape derived.

  Decision (f) of the component contract: transforming a copy shape touches
  that shape only; its children change as a consequence and stay untouched,
  and sync gives them their expected geometry, their main's placed against
  their parent and resized through their constraints.

  Touch. The placement step decided per shape whether a transform touched it
  by comparing it with its copy root, so the children of a resized root that
  stretched (scale, left and right) were touched (F10), a derived width or
  height always touched (F22), and a resize that scales the content touched
  the strokes, radii and the like of every child (F39). The editor now tells
  the placement step which shapes the user transformed (the keys of the
  modifiers given, or those the stored modifiers were set for); any other
  shape of the transform changes only as a consequence of theirs (a child
  through its constraints, a board that hugs them) and touches nothing.

  Sync. Sync placed every main shape by the offset between the roots only,
  so the children of a resized copy root that a resize leaves untouched
  (center) went back to their main's place at the next sync of the main
  (F10). Now, before it walks the children of a copy shape that keeps its
  own geometry, sync resizes, turns and moves the main shape's subtree to
  match it, its children following through their constraints and layouts,
  and walks those: each child gets that geometry unless it has its own.

  comp-expected-geometry-test: a copy root resized as the editor does places
  a child constrained left, right, center, scale and left-right, leaves it
  untouched and keeps it there through a sync; a resize that scales the
  content scales the child's stroke and touches only the root. The frontend
  golden master records, in cases AI and the touched child under a main
  rotation, the children the resize or rotation of a root no longer touches.

- Check a copy child resize leaves its hug board untouched.

  Decision (g) of the component contract: the size of a board that hugs its
  content is the layout's, never an override. The layout reflow writes it as
  derived, and a transform touches only the shapes the user transformed
  (decision (f)), so a resize of a copy child that grows the board it sits
  in touches the child only.

  workspace-layout-owned-sizes-test pins it.

Benchmark (lower quantile, ms; baseline / now / ratio); the machine
was loaded, and the code before this change, run in between, gave the
same spread (0.44 to 0.59):
  deepest-edit-through-three-levels    35.2 /  16.7 / 0.47
  edit-through-a-chain-of-dependents   68.9 /  33.4 / 0.48
  library-update-into-copies           83.1 /  40.3 / 0.49
  main-edit-among-many-shapes           4.8 /   2.4 / 0.49
  main-edit-into-10-copies              1.8 /   1.0 / 0.54
  main-edit-into-100-copies            15.4 /   8.8 / 0.57
  main-edit-into-1000-copies          153.1 /  92.7 / 0.61
  variant-switch-into-copies           32.1 /  19.6 / 0.61

AI-assisted-by: claude-opus-5-5
2026-10-30 09:50:07 +01:00

514 lines
20 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.composable-tests.completion-contract-test]
[frontend-tests.copy-as-svg-test]
[frontend-tests.data.changes-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.imports-test]
[frontend-tests.data.jobs-test]
[frontend-tests.data.modal-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-edit-watchers-test]
[frontend-tests.data.workspace-font-variants-test]
[frontend-tests.data.workspace-frame-guides-undo-test]
[frontend-tests.data.workspace-interactions-test]
[frontend-tests.data.workspace-layout-owned-sizes-test]
[frontend-tests.data.workspace-libraries-test]
[frontend-tests.data.workspace-library-links-test]
[frontend-tests.data.workspace-library-updates-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-sync-barrier-test]
[frontend-tests.data.workspace-sync-wasm-text-test]
[frontend-tests.data.workspace-text-modifier-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-variant-switch-wasm-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-watcher-test]
[frontend-tests.logic.comp-move-swapped-copies-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.management-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.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.style-dictionary-test]
[frontend-tests.tokens.token-errors-test]
[frontend-tests.tokens.token-path-test]
[frontend-tests.tokens.tokenscript-test]
[frontend-tests.tokens.workspace-tokens-remap-test]
[frontend-tests.ui.assets-components-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.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.text-attrs-multiple-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]
[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.composable-tests.completion-contract-test
'frontend-tests.copy-as-svg-test
'frontend-tests.data.changes-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-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.exports-files-test
'frontend-tests.data.imports-test
'frontend-tests.data.jobs-test
'frontend-tests.worker.exports-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-edit-watchers-test
'frontend-tests.data.workspace-interactions-test
'frontend-tests.data.workspace-layout-owned-sizes-test
'frontend-tests.data.workspace-font-variants-test
'frontend-tests.data.workspace-frame-guides-undo-test
'frontend-tests.data.workspace-text-modifier-test
'frontend-tests.data.workspace-libraries-test
'frontend-tests.data.workspace-library-links-test
'frontend-tests.data.workspace-library-updates-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-sync-barrier-test
'frontend-tests.data.workspace-sync-wasm-text-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-variant-switch-wasm-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-watcher-test
'frontend-tests.logic.comp-move-swapped-copies-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.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.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.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.style-dictionary-test
'frontend-tests.tokens.token-errors-test
'frontend-tests.tokens.token-path-test
'frontend-tests.tokens.tokenscript-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.assets-components-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.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.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)))))))