diff --git a/.serena/memories/frontend/dashboard-viewer-subtleties.md b/.serena/memories/frontend/dashboard-viewer-subtleties.md index 975d410dea..f4cfd45cc9 100644 --- a/.serena/memories/frontend/dashboard-viewer-subtleties.md +++ b/.serena/memories/frontend/dashboard-viewer-subtleties.md @@ -13,4 +13,4 @@ - Viewer bundle fetch sends the full supported feature set because anonymous shared viewers may not know team-enabled features. - View-only bundles can contain pointer values in `:pages-index` and file data. Viewer resolves those fragments with `:get-file-fragment` before storing the bundle. - `bundle-fetched` indexes pages and precomputes viewer frames/all-frames, stores libraries/users/thumbnails/permissions under `:viewer`, then navigates to frame id, query index, or auto-selected frame. -- Viewer zoom and interaction mode changes update both `:viewer-local` and the `:viewer` route query params. \ No newline at end of file +- Viewer zoom and interaction mode changes update both `:viewer-local` and the `:viewer` route query params. `update-zoom-querystring` guards with a query-param comparison (`not= current expected`) and uses `::rt/replace`; without that guard the load sequence (`bundle-fetched` → `zoom-to-fill` → `update-zoom-querystring` → `rt/nav`) re-runs on every navigation and crashes with React "maximum update depth exceeded" (2.18.0-RC5 regression, fixed in `31b73460c3`; regression test: `bundle-fetched-with-zoom-fill-url-does-not-navigate`). \ No newline at end of file diff --git a/frontend/test/frontend_tests/data/viewer_test.cljs b/frontend/test/frontend_tests/data/viewer_test.cljs index 482210b24d..5c3b0ca128 100644 --- a/frontend/test/frontend_tests/data/viewer_test.cljs +++ b/frontend/test/frontend_tests/data/viewer_test.cljs @@ -122,3 +122,32 @@ {:keys [params]} (some-> (first events) deref)] (t/is (= 1 (count events))) (t/is (not (contains? params :zoom)))))) + +(t/deftest bundle-fetched-with-zoom-fill-url-does-not-navigate + ;; Regression test for the React "maximum update depth exceeded" + ;; error (2.18.0-RC5): loading the viewer with a URL that already + ;; contains `zoom=fill` re-entered the cycle zoom-to-fill → + ;; update-zoom-querystring → nav → navigated → zoom-to-fill…, + ;; because update-zoom-querystring navigated unconditionally. + ;; At HEAD the guard breaks the cycle, so a bundle fetch must not + ;; emit any navigation. + (let [state (-> (base-state {:frames [{:selrect {:width 100 :height 100}}] + :index 0}) + (assoc-in [:route :query-params :zoom] "fill"))] + (let [events (watch-events (dv/bundle-fetched + {:file {:id page-id + :data {:pages [page-id] + :pages-index {page-id {:objects {}}}}} + :project {} + :team {:features []} + :share-links [] + :libraries [] + :users [] + :permissions {} + :thumbnails {}}) + state) + ;; `update-page-position-data` and `go-to-frame-auto` are part + ;; of the normal init sequence; the navigation events are the + ;; ones that can restart the zoom cycle. + navigations (filter #(= :app.main.router/navigate (ptk/type %)) events)] + (t/is (empty? navigations)))))