From d7daefafe21f1623413f0c94046e030e6085bbb1 Mon Sep 17 00:00:00 2001 From: Eva Marco Date: Tue, 11 Aug 2026 13:05:47 +0200 Subject: [PATCH] :bug: Fix select shape after enter path edition (#11205) --- .../main/data/workspace/path/shortcuts.cljs | 13 +++- .../data/workspace_path_edition_test.cljs | 78 +++++++++++++++++++ frontend/test/frontend_tests/runner.cljs | 2 + 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 frontend/test/frontend_tests/data/workspace_path_edition_test.cljs diff --git a/frontend/src/app/main/data/workspace/path/shortcuts.cljs b/frontend/src/app/main/data/workspace/path/shortcuts.cljs index f4ed3dd8f3..71403d731f 100644 --- a/frontend/src/app/main/data/workspace/path/shortcuts.cljs +++ b/frontend/src/app/main/data/workspace/path/shortcuts.cljs @@ -94,7 +94,18 @@ :fn #(st/emit! (drp/toggle-snap))} :escape {:tooltip (ds/esc) - :command ["escape" "enter" "v"] + :command ["escape" "v"] + :section [:workspace] + :fn #(st/emit! (esc-pressed))} + + ;; Reuses the `:start-editing` key (instead of adding "enter" to + ;; the `:escape` command above) so that merging this shortcut set + ;; on top of the base workspace shortcuts (see `dsc/push-shortcuts`) + ;; deterministically replaces the workspace's `enter` binding + ;; (which enters path edit mode) instead of both ending up bound + ;; to the same physical key at once. + :start-editing {:tooltip (ds/enter) + :command "enter" :section [:workspace] :overwrite true :fn #(st/emit! (esc-pressed))} diff --git a/frontend/test/frontend_tests/data/workspace_path_edition_test.cljs b/frontend/test/frontend_tests/data/workspace_path_edition_test.cljs new file mode 100644 index 0000000000..4cfabcdce2 --- /dev/null +++ b/frontend/test/frontend_tests/data/workspace_path_edition_test.cljs @@ -0,0 +1,78 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC Sucursal en EspaƱa SL + +(ns frontend-tests.data.workspace-path-edition-test + (:require + [app.common.data :as d] + [app.common.test-helpers.files :as cthf] + [app.common.test-helpers.shapes :as cths] + [app.main.data.shortcuts :as dsc] + [app.main.data.workspace :as dw] + [app.main.data.workspace.path.shortcuts :as psc] + [app.main.data.workspace.selection :as dws] + [app.main.data.workspace.shortcuts :as wsc] + [cljs.test :as t :include-macros true] + [frontend-tests.helpers.pages :as thp] + [frontend-tests.helpers.state :as ths] + [potok.v2.core :as ptk])) + +(t/use-fixtures :each + {:before thp/reset-idmap!}) + +(defn- enter-command? + [command] + (if (vector? command) + (some #(= % "enter") command) + (= command "enter"))) + +(t/deftest test-enter-key-is-bound-once-while-path-editing + ;; Regression test for the physical "enter" key ending up bound to + ;; two different shortcuts at once while path editing is active: one + ;; that (re)enters edition mode and one that exits it. `push-shortcuts` + ;; merges shortcut groups by map key (see `app.main.data.shortcuts`), + ;; not by physical key/command, so two shortcuts under different keys + ;; that both claim "enter" survive the merge and both would fire on a + ;; single keypress, breaking the toggle. + (let [file (cthf/sample-file :file1) + store (ths/setup-store file)] + (ptk/emit! store (dsc/push-shortcuts ::workspace wsc/shortcuts :workspace)) + (ptk/emit! store (dsc/push-shortcuts ::path psc/shortcuts :workspace :merge-shortcuts :auto)) + (let [effective (get-in @store [:shortcuts ::path]) + matches (->> effective + (filter (fn [[_ sc]] (enter-command? (:command sc)))) + (map first))] + (t/is (= 1 (count matches)) + (str "expected exactly one shortcut bound to \"enter\" while path editing, got " matches))))) + +(defn- run-scenario + [shape-type] + (let [file (-> (cthf/sample-file :file1) + (cths/add-sample-shape :test-shape :type shape-type)) + shape-id (:id (cths/get-shape file :test-shape)) + store (ths/setup-store file)] + ;; Select the shape, then reproduce what a physical Enter keypress + ;; now dispatches at each step: `start-editing-selected` to enter + ;; path edition mode, `esc-pressed` (-> :interrupt) to exit it, and + ;; `start-editing-selected` again to re-enter. + (ptk/emit! store (dws/select-shapes (d/ordered-set shape-id))) + + (ptk/emit! store (dw/start-editing-selected)) + (t/is (= shape-id (get-in @store [:workspace-local :edition])) + (str "expected " (name shape-type) " to enter path edition mode")) + + (ptk/emit! store (psc/esc-pressed)) + (t/is (nil? (get-in @store [:workspace-local :edition])) + (str "expected " (name shape-type) " to exit path edition mode")) + (t/is (= #{shape-id} (get-in @store [:workspace-local :selected])) + (str "expected " (name shape-type) " to remain selected after exiting path edition mode")) + + (ptk/emit! store (dw/start-editing-selected)) + (t/is (= shape-id (get-in @store [:workspace-local :edition])) + (str "expected " (name shape-type) " to enter path edition mode again")))) + +(t/deftest test-enter-toggles-path-editing-mode + (doseq [shape-type [:rect :circle :path :image]] + (run-scenario shape-type))) diff --git a/frontend/test/frontend_tests/runner.cljs b/frontend/test/frontend_tests/runner.cljs index e0c06b4a08..7c0c5f0889 100644 --- a/frontend/test/frontend_tests/runner.cljs +++ b/frontend/test/frontend_tests/runner.cljs @@ -21,6 +21,7 @@ [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] @@ -113,6 +114,7 @@ '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