mirror of
https://github.com/penpot/penpot.git
synced 2026-11-10 20:10:37 +00:00
* 🐛 Return the full profile from the LDAP invitation branch The invitation branch responded with only {:invitation-token token}, so the session start received a map without id or auth-backend. With the new auth-origin vocabulary that map fails validation and the login breaks in development and tests; in production the event would be emitted without a channel. Return the profile plus the token, like the regular branch, and cover both branches with RPC-level tests. Closes #12849 AI-assisted-by: deepseek-v4.1-flash * 🐛 Mint an auth token in the OIDC callback with the invitation inside The callback used the invitation JWE as the session token, so the frontend landed directly on token verification and never ran the regular session start: no signin event, no teams, no host hook. Always mint an :auth token and carry the invitation in its claims. Token verification returns the claims verbatim, so login-from-token attaches the invitation to the profile and logged-in does the rest, the same pattern the verify-email token already uses. Closes #12849 AI-assisted-by: deepseek-v4.1-flash * ✨ Keep the session origin in the telemetry shadow rows The anonymisation filter drops every string unless it is on a short allowlist. Add source and activation next to lang and auth-backend so the shadow copy keeps them; the email and the full name are still dropped and the email domain is still derived from the email. The filter keeps its two bindings: the transducer discards everything that is not a UUID, a boolean or a number, so the allowlist is applied on the filtered map, never on the raw props. Closes #12849 AI-assisted-by: deepseek-v4.1-flash * ✨ Describe the signup outcome with activation, not with action The three success branches of register-profile labelled a new account as "login", "email-verification" or "accept-invitation", so the event contradicted its own name and the value only lived in context, where the analytics consumers never read it. Add activation to the event props and drop action from those branches: the name already says it is a signup, and a constant action would only add noise. The retry branches keep their action in context because there it distinguishes four different outcomes. Closes #12849 AI-assisted-by: deepseek-v4.1-flash * ✨ Describe the session origin in the signin event The event carried the profile but never said why the session started: the only field that tried was frontend metadata that never leaves the browser, and several flows filled it with the wrong value. Add a small closed vocabulary (source, auth-backend, activation, from-invitation) and compose it from the profile when signin is emitted. The assertion fails in development and tests and is elided in the release build, so a bad value cannot break a real login. Closes #12849 AI-assisted-by: deepseek-v4.1-flash * ✨ Emit the session origin from every login entry point The four emitters stamped a free-form string as metadata, so the session event could not rely on it: two flows that were signups wrote the same value as a login. Route them through origin-meta: password and LDAP logins declare source login, register declares source register with activation immediate, and login-from-token derives both from the token issuer: :auth for a login and :verify-email for a signup that needed the email confirmation. Closes #12849 AI-assisted-by: deepseek-v4.1-flash * 🐛 Send the invitation signups through the regular session start Registering from a team invitation link navigated by hand to token verification, so the session start never ran: no signin event, no teams, no host hook. The same navigation was copied in four places. Teach login-from-register to carry an optional invitation token, extract the profile decoration into with-register-origin, and call it from the four sites instead of the hand-written navigation. Closes #12849 AI-assisted-by: deepseek-v4.1-flash * 🐛 Resolve the invitation without waiting for the teams Registering from an invitation link now goes through the session start, and that start only navigates after the teams request completes. fetch-teams has no error handling, so a network failure there would leave the invitation unaccepted and the user on the signup screen with a session already minted. Move the invitation navigation out of the teams path: it emits as soon as the profile carries a token, and the teams path emits nothing for an invited profile so it cannot move the user away from the token verification screen. Closes #12849 AI-assisted-by: deepseek-v4.1-flash * 📚 Document the session origin vocabulary and the invitation flow Add a focused memory with the four fields, where each value comes from, the table of flows, the LDAP exception and the invitation path through logged-in, and link it from the frontend routing. Update the audit-log memory: source and activation are now on the telemetry allowlist, activation lives in props and action only exists on the retry rows. Closes #12849 AI-assisted-by: deepseek-v4.1-flash * 📎 Cover the invitation session start and fix the auth memories The invitation flows and the token decoration in login-from-token were only covered by helper tests, so removing the guard that keeps the teams path from navigating, or the token attach, broke the behaviour silently. Run the events through ptk/watch with a teams-fetched event as input: an invited profile navigates to the token verification screen and never to the dashboard, and the signin keeps from-invitation. Add the login-from-token cases with and without the token, and fix the memory statements about action, the flow table and from-invitation. Closes #12849 AI-assisted-by: deepseek-v4.1-flash
452 lines
18 KiB
Clojure
452 lines
18 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-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.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-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-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.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.frame-guides-test]
|
|
[frontend-tests.logic.groups-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.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-source-test]
|
|
[frontend-tests.tokens.logic.tokens-status-test]
|
|
[frontend-tests.tokens.style-dictionary-test]
|
|
[frontend-tests.tokens.token-errors-test]
|
|
[frontend-tests.tokens.token-path-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.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.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.shape-filters-test]
|
|
[frontend-tests.ui.shortcuts-labels-test]
|
|
[frontend-tests.ui.sidebar-scroll-test]
|
|
[frontend-tests.ui.static-test]
|
|
[frontend-tests.ui.stroke-menu-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-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.auth-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.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-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.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.frame-guides-test
|
|
'frontend-tests.logic.groups-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.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.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.style-dictionary-test
|
|
'frontend-tests.tokens.token-errors-test
|
|
'frontend-tests.tokens.token-path-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.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.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.shape-filters-test
|
|
'frontend-tests.ui.shortcuts-labels-test
|
|
'frontend-tests.ui.sidebar-scroll-test
|
|
'frontend-tests.ui.static-test
|
|
'frontend-tests.ui.stroke-menu-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-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)))))))
|