mirror of
https://github.com/logseq/logseq.git
synced 2026-05-24 20:54:09 +00:00
Merge branch 'master' into dev/malli-schema&kondo-config
This commit is contained in:
@@ -77,10 +77,13 @@ mistakes [as noted here](./contributing-to-translations.md#fix-mistakes).
|
||||
|
||||
## Testing
|
||||
|
||||
Even though we have a nightly release channel, it's hard for testing users (thanks to the brave users!) to notice all issues in a limited time, as Logseq is covering so many features (and the hell of combinations)
|
||||
The only solution is automatic end-to-end tests - adding tests for GUI software is always painful but necessary
|
||||
We have unit and end to end tests.
|
||||
|
||||
### End to End Tests
|
||||
|
||||
https://github.com/logseq/logseq/pulls?q=E2E
|
||||
To run end to end tests
|
||||
|
||||
```sh
|
||||
@@ -95,11 +98,15 @@ If e2e failed after first running:
|
||||
- `rm -rdf <repo dir>/tmp/`
|
||||
- Windows: `rmdir /s %APPDATA%/Electron` (Reference: https://www.electronjs.org/de/docs/latest/api/app#appgetpathname)
|
||||
|
||||
If e2e tests fail, they can be debugged by examining a trace dump with [the
|
||||
There's a `traceAll()` helper function to enable playwright trace file dump for specific test files https://github.com/logseq/logseq/pull/8332
|
||||
|
||||
If e2e tests fail in the file, they can be debugged by examining a trace dump with [the
|
||||
playwright trace
|
||||
viewer](https://playwright.dev/docs/trace-viewer#recording-a-trace). Locally
|
||||
this will get dumped into e2e-dump/. On CI the trace file will be under
|
||||
Artifacts at the bottom of a run page e.g.
|
||||
viewer](https://playwright.dev/docs/trace-viewer#recording-a-trace).
|
||||
|
||||
Locally this will get dumped into e2e-dump/.
|
||||
|
||||
On CI the trace file will be under Artifacts at the bottom of a run page e.g.
|
||||
https://github.com/logseq/logseq/actions/runs/3574600322.
|
||||
|
||||
### Unit Testing
|
||||
|
||||
@@ -596,3 +596,90 @@ test('should not erase typed text when expanding block quickly after typing #389
|
||||
''
|
||||
)
|
||||
})
|
||||
|
||||
test('should keep correct undo and redo seq after indenting or outdenting the block #7615',async({page,block}) => {
|
||||
await createRandomPage(page)
|
||||
|
||||
await block.mustFill("foo")
|
||||
|
||||
await page.keyboard.press("Enter")
|
||||
await expect(page.locator('textarea >> nth=0')).toHaveText("")
|
||||
await block.indent()
|
||||
await block.mustFill("bar")
|
||||
await expect(page.locator('textarea >> nth=0')).toHaveText("bar")
|
||||
|
||||
if (IsMac) {
|
||||
await page.keyboard.press('Meta+z')
|
||||
} else {
|
||||
await page.keyboard.press('Control+z')
|
||||
}
|
||||
// should undo "bar" input
|
||||
await expect(page.locator('textarea >> nth=0')).toHaveText("")
|
||||
if (IsMac) {
|
||||
await page.keyboard.press('Shift+Meta+z')
|
||||
} else {
|
||||
await page.keyboard.press('Shift+Control+z')
|
||||
}
|
||||
// should redo "bar" input
|
||||
await expect(page.locator('textarea >> nth=0')).toHaveText("bar")
|
||||
await page.keyboard.press("Shift+Tab")
|
||||
|
||||
await page.keyboard.press("Enter")
|
||||
await expect(page.locator('textarea >> nth=0')).toHaveText("")
|
||||
// swap input seq
|
||||
await block.mustFill("baz")
|
||||
await block.indent()
|
||||
|
||||
if (IsMac) {
|
||||
await page.keyboard.press('Meta+z')
|
||||
} else {
|
||||
await page.keyboard.press('Control+z')
|
||||
}
|
||||
// should undo indention
|
||||
await expect(page.locator('textarea >> nth=0')).toHaveText("baz")
|
||||
await page.keyboard.press("Shift+Tab")
|
||||
|
||||
await page.keyboard.press("Enter")
|
||||
await expect(page.locator('textarea >> nth=0')).toHaveText("")
|
||||
// #7615
|
||||
await page.keyboard.type("aaa")
|
||||
await block.indent()
|
||||
await page.keyboard.type(" bbb")
|
||||
await expect(page.locator('textarea >> nth=0')).toHaveText("aaa bbb")
|
||||
if (IsMac) {
|
||||
await page.keyboard.press('Meta+z')
|
||||
} else {
|
||||
await page.keyboard.press('Control+z')
|
||||
}
|
||||
await expect(page.locator('textarea >> nth=0')).toHaveText("aaa")
|
||||
if (IsMac) {
|
||||
await page.keyboard.press('Meta+z')
|
||||
} else {
|
||||
await page.keyboard.press('Control+z')
|
||||
}
|
||||
await expect(page.locator('textarea >> nth=0')).toHaveText("aaa")
|
||||
if (IsMac) {
|
||||
await page.keyboard.press('Meta+z')
|
||||
} else {
|
||||
await page.keyboard.press('Control+z')
|
||||
}
|
||||
await expect(page.locator('textarea >> nth=0')).toHaveText("")
|
||||
if (IsMac) {
|
||||
await page.keyboard.press('Shift+Meta+z')
|
||||
} else {
|
||||
await page.keyboard.press('Shift+Control+z')
|
||||
}
|
||||
await expect(page.locator('textarea >> nth=0')).toHaveText("aaa")
|
||||
if (IsMac) {
|
||||
await page.keyboard.press('Shift+Meta+z')
|
||||
} else {
|
||||
await page.keyboard.press('Shift+Control+z')
|
||||
}
|
||||
await expect(page.locator('textarea >> nth=0')).toHaveText("aaa")
|
||||
if (IsMac) {
|
||||
await page.keyboard.press('Shift+Meta+z')
|
||||
} else {
|
||||
await page.keyboard.press('Shift+Control+z')
|
||||
}
|
||||
await expect(page.locator('textarea >> nth=0')).toHaveText("aaa bbb")
|
||||
})
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
"@capawesome/capacitor-background-task": "^2.0.0",
|
||||
"@excalidraw/excalidraw": "0.12.0",
|
||||
"@hugotomazi/capacitor-navigation-bar": "^2.0.0",
|
||||
"@logseq/capacitor-file-sync": "0.0.17",
|
||||
"@logseq/capacitor-file-sync": "0.0.18",
|
||||
"@logseq/react-tweet-embed": "1.3.1-1",
|
||||
"@sentry/react": "^6.18.2",
|
||||
"@sentry/tracing": "^6.18.2",
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"https-proxy-agent": "5.0.0",
|
||||
"@sentry/electron": "2.5.1",
|
||||
"posthog-js": "1.10.2",
|
||||
"@logseq/rsapi": "0.0.59",
|
||||
"@logseq/rsapi": "0.0.60",
|
||||
"electron-deeplink": "1.0.10",
|
||||
"abort-controller": "3.0.0",
|
||||
"fastify": "latest",
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
(ns electron.handler
|
||||
"This ns starts the event handling for the electron main process and defines
|
||||
all the application-specific event types"
|
||||
(:require ["electron" :refer [ipcMain dialog app autoUpdater shell]]
|
||||
[cljs-bean.core :as bean]
|
||||
["fs" :as fs]
|
||||
["buffer" :as buffer]
|
||||
["fs-extra" :as fs-extra]
|
||||
["path" :as path]
|
||||
["os" :as os]
|
||||
["diff-match-patch" :as google-diff]
|
||||
["/electron/utils" :as js-utils]
|
||||
(:require ["/electron/utils" :as js-utils]
|
||||
["abort-controller" :as AbortController]
|
||||
[electron.shell :as shell]
|
||||
[electron.fs-watcher :as watcher]
|
||||
[electron.configs :as cfgs]
|
||||
[promesa.core :as p]
|
||||
[clojure.string :as string]
|
||||
[electron.utils :as utils]
|
||||
[electron.logger :as logger]
|
||||
[electron.state :as state]
|
||||
[clojure.core.async :as async]
|
||||
[electron.search :as search]
|
||||
[electron.git :as git]
|
||||
[electron.plugin :as plugin]
|
||||
[electron.window :as win]
|
||||
[electron.file-sync-rsapi :as rsapi]
|
||||
[electron.backup-file :as backup-file]
|
||||
["buffer" :as buffer]
|
||||
["diff-match-patch" :as google-diff]
|
||||
["electron" :refer [app autoUpdater dialog ipcMain shell]]
|
||||
["fs" :as fs]
|
||||
["fs-extra" :as fs-extra]
|
||||
["os" :as os]
|
||||
["path" :as path]
|
||||
[cljs-bean.core :as bean]
|
||||
[cljs.reader :as reader]
|
||||
[clojure.core.async :as async]
|
||||
[clojure.string :as string]
|
||||
[electron.backup-file :as backup-file]
|
||||
[electron.configs :as cfgs]
|
||||
[electron.file-sync-rsapi :as rsapi]
|
||||
[electron.find-in-page :as find]
|
||||
[electron.fs-watcher :as watcher]
|
||||
[electron.git :as git]
|
||||
[electron.logger :as logger]
|
||||
[electron.plugin :as plugin]
|
||||
[electron.search :as search]
|
||||
[electron.server :as server]
|
||||
[electron.find-in-page :as find]))
|
||||
[electron.shell :as shell]
|
||||
[electron.state :as state]
|
||||
[electron.utils :as utils]
|
||||
[electron.window :as win]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(defmulti handle (fn [_window args] (keyword (first args))))
|
||||
|
||||
@@ -177,12 +177,34 @@
|
||||
result (get (js->clj result) "filePaths")]
|
||||
(p/resolved (first result))))
|
||||
|
||||
(defmethod handle :openDir [^js _window _messages]
|
||||
(defn- pretty-print-js-error
|
||||
"Converts file related JS Error messages to a human readable format.
|
||||
Ex.:
|
||||
Error: EACCES: permission denied, scandir '/tmp/test'
|
||||
Permission denied for path: '/tmp/test' (Code: EACCES)"
|
||||
[e]
|
||||
(some->>
|
||||
e
|
||||
str
|
||||
;; Message parsed as "Error: $ERROR_CODE$: $REASON$, function $PATH$"
|
||||
(re-matches #"(?:Error\: )(.+)(?:\: )(.+)(?:, \w+ )('.+')")
|
||||
rest
|
||||
(#(str (string/capitalize (second %)) " for path: " (nth % 2) " (Code: " (first %) ")"))))
|
||||
|
||||
(defmethod handle :openDir [^js window _messages]
|
||||
(logger/info ::open-dir "open folder selection dialog")
|
||||
(p/let [path (open-dir-dialog)]
|
||||
(logger/debug ::open-dir {:path path})
|
||||
(if path
|
||||
(p/resolved (bean/->js (get-files path)))
|
||||
(try
|
||||
(p/resolved (bean/->js (get-files path)))
|
||||
(catch js/Error e
|
||||
(do
|
||||
(utils/send-to-renderer window "notification" {:type "error"
|
||||
:payload (str "Opening the specified directory failed.\n"
|
||||
(or (pretty-print-js-error e) (str "Unexpected error: " e)))})
|
||||
(p/rejected e))))
|
||||
|
||||
(p/rejected (js/Error "path empty")))))
|
||||
|
||||
(defmethod handle :getFiles [_window [_ path]]
|
||||
|
||||
@@ -1660,11 +1660,11 @@
|
||||
[up?]
|
||||
(fn [event]
|
||||
(util/stop event)
|
||||
(save-current-block!)
|
||||
(let [edit-block-id (:block/uuid (state/get-edit-block))
|
||||
move-nodes (fn [blocks]
|
||||
(outliner-tx/transact!
|
||||
{:outliner-op :move-blocks}
|
||||
(save-current-block!)
|
||||
(outliner-core/move-blocks-up-down! blocks up?))
|
||||
(when-let [block-node (util/get-first-block-by-id (:block/uuid (first blocks)))]
|
||||
(.scrollIntoView block-node #js {:behavior "smooth" :block "nearest"})))]
|
||||
@@ -2139,10 +2139,10 @@
|
||||
[node]
|
||||
(when-not (parent-is-page? node)
|
||||
(let [parent-node (tree/-get-parent node)]
|
||||
(save-current-block!)
|
||||
(outliner-tx/transact!
|
||||
{:outliner-op :move-blocks
|
||||
:real-outliner-op :indent-outdent}
|
||||
(save-current-block!)
|
||||
(outliner-core/move-blocks! [(:data node)] (:data parent-node) true)))))
|
||||
|
||||
(defn- last-top-level-child?
|
||||
@@ -2666,6 +2666,7 @@
|
||||
|
||||
(defn indent-outdent
|
||||
[indent?]
|
||||
(save-current-block!)
|
||||
(state/set-editor-op! :indent-outdent)
|
||||
(let [pos (some-> (state/get-input) cursor/pos)
|
||||
{:keys [block]} (get-state)]
|
||||
@@ -2674,8 +2675,7 @@
|
||||
(outliner-tx/transact!
|
||||
{:outliner-op :move-blocks
|
||||
:real-outliner-op :indent-outdent}
|
||||
(save-current-block!)
|
||||
(outliner-core/indent-outdent-blocks! [block] indent?)))
|
||||
(outliner-core/indent-outdent-blocks! [block] indent?)))
|
||||
(state/set-editor-op! :nil)))
|
||||
|
||||
(defn keydown-tab-handler
|
||||
|
||||
@@ -99,4 +99,4 @@
|
||||
(for [command commands]
|
||||
command)]
|
||||
[:div.toolbar-hide-keyboard
|
||||
(command #(state/clear-edit!) "keyboard-show")]])))
|
||||
(command #(state/clear-edit!) {:icon "keyboard-show"})]])))
|
||||
|
||||
@@ -392,41 +392,41 @@
|
||||
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
|
||||
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
|
||||
|
||||
"@logseq/rsapi-darwin-arm64@0.0.59":
|
||||
version "0.0.59"
|
||||
resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-arm64/-/rsapi-darwin-arm64-0.0.59.tgz#3b478c1e045246a536446b39ee0df6943403ec8f"
|
||||
integrity sha512-mi7Z8UVocVGayCB2kKUgq6MGRNI7BX9EZeTnf7JWRLdfVZe4Rf3FDe1Kr/zlY5lO27KYsPzqLC/Pw6IkQtZsvQ==
|
||||
"@logseq/rsapi-darwin-arm64@0.0.60":
|
||||
version "0.0.60"
|
||||
resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-arm64/-/rsapi-darwin-arm64-0.0.60.tgz#5edd887b38dd4d26cae51d397ff0c6f3d96bec43"
|
||||
integrity sha512-Bv0ck+pjHb0z6OaGbuIl4RNbKF1KRF281zDdpiVisdSByVQ6sCQ55lemvgDFgwlZWp3Bp6vyMTrfjlzeuP86ZQ==
|
||||
|
||||
"@logseq/rsapi-darwin-x64@0.0.59":
|
||||
version "0.0.59"
|
||||
resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-x64/-/rsapi-darwin-x64-0.0.59.tgz#7a3d746d4807523dfe0197658d1f1266c66534f3"
|
||||
integrity sha512-hDf5QUa+vQRHJ7p0OBAREWYOwHepUpDUEIbyXhSzTb7g5vsr5yBEOygnRt1Jt6a1DfadMPDdrl925AaUrkZAjA==
|
||||
"@logseq/rsapi-darwin-x64@0.0.60":
|
||||
version "0.0.60"
|
||||
resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-x64/-/rsapi-darwin-x64-0.0.60.tgz#3c099b77f6e4fa5578a61de83e9907bfaf3ac3fa"
|
||||
integrity sha512-iasBB89fB1h5kWAfrV2DQcynlUMKdR85GyruaVbJYspYp0SlkB+ZiR9vh5lkJQyNkMM8Y1hvLRh2ZTMAl+acWA==
|
||||
|
||||
"@logseq/rsapi-linux-arm64-gnu@0.0.59":
|
||||
version "0.0.59"
|
||||
resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-arm64-gnu/-/rsapi-linux-arm64-gnu-0.0.59.tgz#58e83687912deae39e6e15e57093e558d80cf7ea"
|
||||
integrity sha512-3kqeSsIjPgd+O/DvhsawJIXdIa4aPVxNtmQ/YJeyXV7Alx5jPY1kPaxKsZUl6h3qr8Zrr5/wTtg0pUS33BwHPg==
|
||||
"@logseq/rsapi-linux-arm64-gnu@0.0.60":
|
||||
version "0.0.60"
|
||||
resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-arm64-gnu/-/rsapi-linux-arm64-gnu-0.0.60.tgz#77e6ef67e87c975ca6a639da3a0b47a69afad8e7"
|
||||
integrity sha512-op47HnJZUKYvrHsMFnlzkTd5uMeYCGkQXF1bYvYYgQrgREJyU2CzJHKKDoFZth13ahF8rjAccHeXhqg3TGccSg==
|
||||
|
||||
"@logseq/rsapi-linux-x64-gnu@0.0.59":
|
||||
version "0.0.59"
|
||||
resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-x64-gnu/-/rsapi-linux-x64-gnu-0.0.59.tgz#5dd228df20befbd642044d99e0a41df86d9cdda5"
|
||||
integrity sha512-iBTxAlQNKX4g4AMJa2l4tOlActXchIFf0tFrNkSWKmyW1mi2AyQ78eObl90F9H1OAHbziOhOs+zzu8nZvJBIJQ==
|
||||
"@logseq/rsapi-linux-x64-gnu@0.0.60":
|
||||
version "0.0.60"
|
||||
resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-x64-gnu/-/rsapi-linux-x64-gnu-0.0.60.tgz#fd96e37e902d9b4b031c603ec4fe1d06d9b2e594"
|
||||
integrity sha512-LeM/PrGdVH3ix43erCVkKM0N5saXhJG7yxNl000/4bNAUkqdGOQ2Cnhy/TyekgZtMqblKjDl/1tJWboLA5jjLQ==
|
||||
|
||||
"@logseq/rsapi-win32-x64-msvc@0.0.59":
|
||||
version "0.0.59"
|
||||
resolved "https://registry.yarnpkg.com/@logseq/rsapi-win32-x64-msvc/-/rsapi-win32-x64-msvc-0.0.59.tgz#3a44b310ad8fa725cd2d1cb6056dc5d66fa644b2"
|
||||
integrity sha512-tupB5/uxcChl6PZO1Wb1g9w8MpiMArM9wu4d2b0KGTccOExKrMwZzKcusFfgWsCqwiIqF2ozBPVd8JKMnAd+yw==
|
||||
"@logseq/rsapi-win32-x64-msvc@0.0.60":
|
||||
version "0.0.60"
|
||||
resolved "https://registry.yarnpkg.com/@logseq/rsapi-win32-x64-msvc/-/rsapi-win32-x64-msvc-0.0.60.tgz#ed2d072df731c01681c4a24caf5a26baa5ff37a9"
|
||||
integrity sha512-22/RRF/VUAb5flW2DLkG0RUMj+LujghSP9pMgv2zkyap104HG1+Wy8xO4j1DkqtpZnwVd2MCohVuHeimHn8IMA==
|
||||
|
||||
"@logseq/rsapi@0.0.59":
|
||||
version "0.0.59"
|
||||
resolved "https://registry.yarnpkg.com/@logseq/rsapi/-/rsapi-0.0.59.tgz#94b359237632279e2ccaf58fbbd563b0718307dc"
|
||||
integrity sha512-m3Y4/k2VmyuLLrNo1EuSBOiNASXrZHtC8bsN2a/AyHFeFuCDThqiTNJ0g5VqvqeaQBBZBaIUawg3OKsmjkRHhQ==
|
||||
"@logseq/rsapi@0.0.60":
|
||||
version "0.0.60"
|
||||
resolved "https://registry.yarnpkg.com/@logseq/rsapi/-/rsapi-0.0.60.tgz#45763b9988e558c0e9513826cf55069ea0a413c1"
|
||||
integrity sha512-fn2tdNyx8XCvh100YG3yD5yBI+kjv0Hz9WeFKFMHb/8JujwS/MnZdM/IKDbw+JtDp/46TfXPXttLm6FQBa7O2w==
|
||||
optionalDependencies:
|
||||
"@logseq/rsapi-darwin-arm64" "0.0.59"
|
||||
"@logseq/rsapi-darwin-x64" "0.0.59"
|
||||
"@logseq/rsapi-linux-arm64-gnu" "0.0.59"
|
||||
"@logseq/rsapi-linux-x64-gnu" "0.0.59"
|
||||
"@logseq/rsapi-win32-x64-msvc" "0.0.59"
|
||||
"@logseq/rsapi-darwin-arm64" "0.0.60"
|
||||
"@logseq/rsapi-darwin-x64" "0.0.60"
|
||||
"@logseq/rsapi-linux-arm64-gnu" "0.0.60"
|
||||
"@logseq/rsapi-linux-x64-gnu" "0.0.60"
|
||||
"@logseq/rsapi-win32-x64-msvc" "0.0.60"
|
||||
|
||||
"@malept/cross-spawn-promise@^1.0.0", "@malept/cross-spawn-promise@^1.1.0":
|
||||
version "1.1.1"
|
||||
|
||||
@@ -487,10 +487,10 @@
|
||||
"@jridgewell/resolve-uri" "^3.0.3"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
|
||||
"@logseq/capacitor-file-sync@0.0.17":
|
||||
version "0.0.17"
|
||||
resolved "https://registry.yarnpkg.com/@logseq/capacitor-file-sync/-/capacitor-file-sync-0.0.17.tgz#4bb9000c64aee8cc07d79069f5e3cbc0908b2613"
|
||||
integrity sha512-B+VHtmH9tGNXiGcHDKNMY2Ype/YHPg+V+HaGYXqEEtzSVtw2QOe/RLkOZG+wKFhokSk3hNQyVd1/WdMGhdHS/Q==
|
||||
"@logseq/capacitor-file-sync@0.0.18":
|
||||
version "0.0.18"
|
||||
resolved "https://registry.yarnpkg.com/@logseq/capacitor-file-sync/-/capacitor-file-sync-0.0.18.tgz#9e6c1386483fb693ce5fdd5b5a3fbb8627de40fc"
|
||||
integrity sha512-tRcwc9OBh4oayhbMGj9iL+86jsUAT+Y76mLqsdYGsbKhck4Hv+YV3dZ0M9GUEFf18xE1pj6H7sB+qYGMd23X6w==
|
||||
|
||||
"@logseq/react-tweet-embed@1.3.1-1":
|
||||
version "1.3.1-1"
|
||||
|
||||
Reference in New Issue
Block a user