cljs / test / ird / test_util.cljs
407 words
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
(ns ird.test-util
  "Shared test tooling: fake transports injected through the client's
  :http-fn, an instant :sleep-fn, the vendored spec, and the live API key."
  (:require-macros [ird.test-util])
  (:require [clojure.string :as str]
            [cljs.core.async :as async :refer [go]]
            [ird.async :as a]))

(def ^:private fs (js/require "node:fs"))

(defn ->json
  "BODY as a JSON string: strings pass through, data is serialised."
  [body]
  (if (string? body) body (js/JSON.stringify (clj->js body))))

(defn capturing
  "An :http-fn recording every request into CAPTURED (an atom of a vector)
  and answering {} with 200."
  [captured]
  (fn [req]
    (swap! captured conj req)
    (go {:status 200 :body "{}"})))

(defn responding
  "An :http-fn answering STATUS and BODY (data serialised to JSON, or a raw
  string) to every request, recording into CAPTURED when given."
  ([status body] (responding (atom []) status body))
  ([captured status body]
   (fn [req]
     (swap! captured conj req)
     (go {:status status :body (->json body)}))))

(defn scripted
  "An :http-fn answering successive requests with the next [status body] of
  RESPONSES, recording into CAPTURED; once exhausted it delivers an
  ExceptionInfo (which the transport reports as a transport error)."
  [captured responses]
  (let [queue (atom (vec responses))]
    (fn [req]
      (swap! captured conj req)
      (let [[status body] (first @queue)]
        (swap! queue #(if (seq %) (subvec % 1) %))
        (go (if status
              {:status status :body (->json body)}
              (ex-info "Scripted responses exhausted" {:url (:url req)})))))))

(defn failing
  "An :http-fn whose channel delivers ERR (an Error) — a connection failure."
  [err]
  (fn [_] (go err)))

(defn no-sleep
  "A :sleep-fn that never waits."
  [_ms]
  (doto (async/chan) async/close!))

(defn json-body
  "The request's JSON body, parsed with keyword keys."
  [req]
  (js->clj (js/JSON.parse (:body req)) :keywordize-keys true))

(defn path-of
  "The request's URL without the API base."
  [req]
  (subs (:url req) (count "https://api.ird.ro")))

(defn op-of
  "\"METHOD /path\" of a request, for comparing request sequences."
  [req]
  (str (str/upper-case (name (:method req))) " " (path-of req)))

(defn spec
  "The vendored OpenAPI spec (string keys)."
  []
  (js->clj (js/JSON.parse (.readFileSync fs "spec/openapi.json" "utf8"))))

(defn spec-operations
  "Every \"METHOD /path\" the vendored spec declares."
  []
  (set (for [[path item] (get (spec) "paths")
             [method _] item
             :when (contains? #{"get" "post" "put" "patch" "delete"} method)]
         (str (str/upper-case method) " " path))))

(defn api-key
  "IRD_API_KEY from the environment, else from a local .env file
  (KEY=value lines); nil when neither has it."
  []
  (or (not-empty (str/trim (or (.. js/process -env -IRD_API_KEY) "")))
      (when (.existsSync fs ".env")
        (some (fn [line]
                (let [line (str/trim line)]
                  (when (str/starts-with? line "IRD_API_KEY=")
                    (-> (subs line (count "IRD_API_KEY="))
                        str/trim
                        (str/replace #"^[\"']|[\"']$" "")
                        not-empty))))
              (str/split-lines (.readFileSync fs ".env" "utf8"))))))

(def error? a/error?)

static mirror of HEAD · about · clone: git clone https://ird.cod-sursa.ro/cljs.git