plugins_basic_test.clj 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. (ns logseq.e2e.plugins-basic-test
  2. (:require
  3. [clojure.string :as string]
  4. [clojure.test :refer [deftest testing is use-fixtures]]
  5. [jsonista.core :as json]
  6. [logseq.e2e.assert :as assert]
  7. [logseq.e2e.fixtures :as fixtures]
  8. [logseq.e2e.keyboard :as k]
  9. [logseq.e2e.page :as page]
  10. [logseq.e2e.util :as util]
  11. [wally.main :as w]
  12. [wally.repl :as repl]))
  13. (use-fixtures :once fixtures/open-page)
  14. (use-fixtures :each fixtures/new-logseq-page)
  15. (defn- to-snake-case
  16. "Converts a string to snake_case. Handles camelCase, PascalCase, spaces, hyphens, and existing underscores.
  17. Examples:
  18. 'HelloWorld' -> 'hello_world'
  19. 'Hello World' -> 'hello_world'
  20. 'hello-world' -> 'hello_world'
  21. 'Hello__World' -> 'hello_world'"
  22. [s]
  23. (when (string? s)
  24. (-> s
  25. ;; Normalize input: replace hyphens/spaces with underscores, collapse multiple underscores
  26. (clojure.string/replace #"[-\s]+" "_")
  27. ;; Split on uppercase letters (except at start) and join with underscore
  28. (clojure.string/replace #"(?<!^)([A-Z])" "_$1")
  29. ;; Remove redundant underscores and trim
  30. (clojure.string/replace #"_+" "_")
  31. (clojure.string/trim)
  32. ;; Convert to lowercase
  33. (clojure.string/lower-case))))
  34. (defn- ls-api-call!
  35. [tag & args]
  36. (let [tag (name tag)
  37. ns' (string/split tag #"\.")
  38. ns? (and (seq ns') (= (count ns') 2))
  39. inbuilt? (contains? #{"app" "editor"} (first ns'))
  40. ns1 (string/lower-case (if (and ns? (not inbuilt?))
  41. (str "sdk." (first ns')) "api"))
  42. name1 (if ns? (to-snake-case (last ns')) tag)
  43. estr (format "s => { const args = JSON.parse(s);const o=logseq.%1$s; return o['%2$s']?.apply(null, args || []); }" ns1 name1)]
  44. (let [args (json/write-value-as-string (vec args))]
  45. ;(prn "Debug: eval-js #" estr args)
  46. (w/eval-js estr args))))
  47. (defn- assert-api-ls-block!
  48. ([ret] (assert-api-ls-block! ret 1))
  49. ([ret-or-uuid count]
  50. (let [uuid' (or (get ret-or-uuid "uuid") ret-or-uuid)]
  51. (is (string? uuid'))
  52. (assert/assert-have-count (str "#ls-block-" uuid') count)
  53. uuid')))
  54. (deftest apis-related-test
  55. (testing "block related apis"
  56. (page/new-page "test-block-apis")
  57. (ls-api-call! :ui.showMsg "hello world" "info")
  58. (let [ret (ls-api-call! :editor.appendBlockInPage "test-block-apis" "append-block-in-page-0")
  59. ret1 (ls-api-call! :editor.appendBlockInPage "append-block-in-current-page-0")
  60. _ (assert-api-ls-block! ret1)
  61. uuid' (assert-api-ls-block! ret)]
  62. (-> (ls-api-call! :editor.insertBlock uuid' "insert-0")
  63. (assert-api-ls-block!))
  64. (ls-api-call! :editor.updateBlock uuid' "append-but-updated-0")
  65. (k/esc)
  66. (w/wait-for ".block-title-wrap:text('append-but-updated-0')")
  67. (ls-api-call! :editor.removeBlock uuid')
  68. (assert-api-ls-block! uuid' 0)))
  69. (testing "block properties related apis"
  70. (page/new-page "test-block-properties-apis")
  71. (let [ret (ls-api-call! :editor.appendBlockInPage "test-block-properties-apis" "block-in-page-0" {:properties {:p1 1}})
  72. uuid' (assert-api-ls-block! ret)
  73. prop1 (ls-api-call! :editor.getBlockProperty uuid' "p1")
  74. props1 (ls-api-call! :editor.getBlockProperties uuid' "p1")
  75. props2 (ls-api-call! :editor.getPageProperties "test-block-properties-apis")]
  76. (w/wait-for ".property-k:text('p1')")
  77. (is (= 1 (get prop1 "value")))
  78. (is (= (get prop1 "ident") ":plugin.property._api/p1"))
  79. (is (= 1 (get props1 ":plugin.property._api/p1")))
  80. (is (= ["Page"] (get props2 ":block/tags")))
  81. (ls-api-call! :editor.upsertBlockProperty uuid' "p2" "p2")
  82. (ls-api-call! :editor.upsertBlockProperty uuid' "p3" true)
  83. (ls-api-call! :editor.upsertBlockProperty uuid' "p4" {:a 1, :b [2, 3]})
  84. (let [prop2 (ls-api-call! :editor.getBlockProperty uuid' "p2")
  85. prop3 (ls-api-call! :editor.getBlockProperty uuid' "p3")
  86. prop4 (ls-api-call! :editor.getBlockProperty uuid' "p4")]
  87. (w/wait-for ".property-k:text('p2')")
  88. (is (= "p2" (get prop2 "value")))
  89. (is (true? prop3))
  90. (is (= prop4 {"a" 1, "b" [2 3]})))
  91. (ls-api-call! :editor.removeBlockProperty uuid' "p4")
  92. ;; wait for react re-render
  93. (util/wait-timeout 16)
  94. (is (nil? (w/find-one-by-text ".property-k" "p4")))
  95. (ls-api-call! :editor.upsertBlockProperty uuid' "p3" false)
  96. (ls-api-call! :editor.upsertBlockProperty uuid' "p2" "p2-updated")
  97. (w/wait-for ".block-title-wrap:text('p2-updated')")
  98. (let [props (ls-api-call! :editor.getBlockProperties uuid')]
  99. (is (= (get props ":plugin.property._api/p3") false))
  100. (is (= (get props ":plugin.property._api/p2") "p2-updated")))))
  101. (testing "properties management related apis"
  102. (let [_ (ls-api-call! :editor.upsertProperty "o1")
  103. _ (ls-api-call! :editor.upsertProperty "o2" {:type "number"})
  104. _ (ls-api-call! :editor.upsertProperty "user.property/o3" {:type "node"})
  105. prop1 (ls-api-call! :editor.getProperty "o1")
  106. prop2 (ls-api-call! :editor.getProperty "o2")
  107. prop3 (ls-api-call! :editor.getProperty "user.property/o3")]
  108. (is (= (get prop1 "ident") ":plugin.property._api/o1"))
  109. (is (= (get prop1 "type") "default"))
  110. (is (= (get prop2 "type") "number"))
  111. (is (= (get prop3 "ident") ":user.property/o3"))
  112. (is (= (get prop3 "type") "node"))
  113. (ls-api-call! :editor.removeProperty "o2")
  114. (is (nil? (w/find-one-by-text ".property-k" "o2"))))))