|
1 | 1 | (ns reagenttest.utils
|
2 | 2 | (:require-macros reagenttest.utils)
|
3 |
| - (:require [promesa.core :as p] |
| 3 | + (:require [react :as react] |
| 4 | + [promesa.core :as p] |
4 | 5 | [reagent.core :as r]
|
5 |
| - [reagent.debug :as debug] |
6 |
| - [reagent.dom :as rdom] |
| 6 | + [reagent.debug :as debug :refer [dev?]] |
7 | 7 | [reagent.dom.server :as server]
|
8 | 8 | [reagent.dom.client :as rdomc]
|
9 |
| - [reagent.impl.template :as tmpl])) |
| 9 | + [reagent.impl.template :as tmpl] |
| 10 | + promesa.core)) |
10 | 11 |
|
11 | 12 | ;; Should be only set for tests....
|
12 | 13 | ;; (set! (.-IS_REACT_ACT_ENVIRONMENT js/window) true)
|
13 | 14 |
|
14 |
| -;; Silence ReactDOM.render warning |
15 | 15 | (defonce original-console-error (.-error js/console))
|
16 | 16 |
|
17 | 17 | (set! (.-error js/console)
|
18 | 18 | (fn [& [first-arg :as args]]
|
19 | 19 | (cond
|
20 |
| - (and (string? first-arg) (.startsWith first-arg "Warning: ReactDOM.render is no longer supported in React 18.")) |
21 |
| - nil |
22 |
| - |
23 | 20 | (and (string? first-arg) (.startsWith first-arg "Warning: The current testing environment is not configured to support"))
|
24 | 21 | nil
|
25 | 22 |
|
|
81 | 78 | (defn act*
|
82 | 79 | "Run f to trigger Reagent updates,
|
83 | 80 | will return Promise which will resolve after
|
84 |
| - Reagent and React render." |
| 81 | + Reagent and React render. |
| 82 | +
|
| 83 | + In production builds, the React.act isn't available, |
| 84 | + so just mock with 17ms timeout... Hopefully that usually |
| 85 | + is enough time for React to flush the queue?" |
85 | 86 | [f]
|
86 |
| - (let [p (p/deferred)] |
87 |
| - (f) |
88 |
| - (r/flush) |
89 |
| - (r/after-render (fn [] |
90 |
| - (p/resolve! p))) |
91 |
| - p)) |
| 87 | + ;; async act doesn't return a real promise (with chainable then), |
| 88 | + ;; so wrap it. |
| 89 | + (if (dev?) |
| 90 | + (js/Promise. |
| 91 | + (fn [resolve reject] |
| 92 | + (try |
| 93 | + (.then (react/act f) |
| 94 | + resolve |
| 95 | + reject) |
| 96 | + (catch :default e |
| 97 | + (reject e))))) |
| 98 | + (js/Promise. |
| 99 | + (fn [resolve reject] |
| 100 | + (try |
| 101 | + (f) |
| 102 | + (js/setTimeout (fn [] |
| 103 | + (resolve)) |
| 104 | + ;; 16.6ms is one animation frame @ 60hz |
| 105 | + 17) |
| 106 | + (catch :default e |
| 107 | + (reject e))))))) |
92 | 108 |
|
93 | 109 | (def ^:dynamic *render-error* nil)
|
94 | 110 |
|
95 | 111 | (defn with-render*
|
96 |
| - "Render the given component to a DOM node, |
97 |
| - after the the component is mounted to DOM, |
98 |
| - run the given function and wait for the Promise |
99 |
| - returned from the function to be resolved |
100 |
| - before unmounting the component from DOM." |
| 112 | + "Run initial render with React/act and then run |
| 113 | + given function to check the results. If the function |
| 114 | + also returns a Promise or thenable, this function |
| 115 | + waits until that is resolved, before unmounting the |
| 116 | + root and resolving the Promise this function returns." |
101 | 117 | ([comp f]
|
102 | 118 | (with-render* comp *test-compiler* f))
|
103 | 119 | ([comp options f]
|
|
108 | 124 | compiler (:compiler options)
|
109 | 125 | restore-error-handlers (when (:capture-errors options)
|
110 | 126 | (init-capture))
|
| 127 | + root (rdomc/create-root div) |
111 | 128 | ;; Magic setup to make exception from render available to the
|
112 | 129 | ;; with-render body.
|
113 | 130 | render-error (atom nil)]
|
114 |
| - (try |
115 |
| - (if compiler |
116 |
| - (rdom/render comp div {:compiler compiler |
117 |
| - :callback callback}) |
118 |
| - (rdom/render comp div callback)) |
119 |
| - (catch :default e |
120 |
| - (reset! render-error e) |
121 |
| - nil)) |
122 |
| - (-> first-render |
| 131 | + (-> (act* (fn [] |
| 132 | + (if compiler |
| 133 | + (rdomc/render root comp compiler) |
| 134 | + (rdomc/render root comp)))) |
123 | 135 | ;; The callback is called even if render throws an error,
|
124 | 136 | ;; so this is always resolved.
|
125 | 137 | (p/then (fn []
|
|
131 | 143 | ;; Not sure if this makes sense.
|
132 | 144 | (p/catch (fn [] nil))
|
133 | 145 | (p/then (fn []
|
134 |
| - (rdom/unmount-component-at-node div) |
| 146 | + (.unmount root) |
135 | 147 | ;; Need to wait for reagent tick after unmount
|
136 | 148 | ;; for the ratom watches to be removed?
|
137 | 149 | (let [ratoms-cleaned (p/deferred)]
|
|
0 commit comments