xwwp-follow-link-test.el 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. ;;; xwwp-follow-link-test.el -- xwwp follow link test suite -*- lexical-binding: t; -*-
  2. ;; Copyright (C) 2020 Damien Merenne <dam@cosinux.org>
  3. ;; This program is free software: you can redistribute it and/or modify
  4. ;; it under the terms of the GNU General Public License as published by
  5. ;; the Free Software Foundation, either version 3 of the License, or
  6. ;; (at your option) any later version.
  7. ;; This program is distributed in the hope that it will be useful,
  8. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. ;; GNU General Public License for more details.
  11. ;; You should have received a copy of the GNU General Public License
  12. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ;;; Commentary:
  14. ;; Test suite for xwidget-webkit-plus-follow-link feature
  15. ;;; Code:
  16. (require 'cl-lib)
  17. (require 'test-helper)
  18. (require 'with-simulated-input)
  19. (require 'xwwp-follow-link)
  20. (require 'xwwp-follow-link-ido)
  21. (require 'xwwp-follow-link-ivy)
  22. (require 'xwwp-follow-link-helm)
  23. (setq completing-read-function #'completing-read-default)
  24. ;; Some usefull javascript
  25. (xwwp-js-def test element-classes (selector)
  26. "Fetch the list of css class for element matching SELECTOR.""
  27. map = Array.prototype.map;
  28. r = {};
  29. document.querySelectorAll(selector).forEach(l => {
  30. r[l.id] = map.call(l.classList, t => {
  31. return t.toString();
  32. });
  33. });
  34. return r;
  35. ")
  36. (xwwp-js-def test current-location ()
  37. "Fetch the current url.""
  38. return '' + window.location;
  39. ")
  40. ;; A mocked backend class that doesn't interactively read anything.
  41. (defclass xwwp-follow-link-completion-backend-test (xwwp-follow-link-completion-backend)
  42. ((candidates-mock :initarg :candidates-mock)
  43. (selected-mock :initarg :selected-mock)
  44. (action-fn)
  45. (classes)
  46. (location)))
  47. (defun xwwp-update-fn-callback (result)
  48. "Called after updating candidates with the css classes in RESULT."
  49. (let ((backend xwwp-follow-link-completion-backend-instance))
  50. ;; Store the results.
  51. (oset backend classes (seq-map #'identity result))
  52. ;; Trigger the action function with the mocked selected link
  53. (funcall (oref backend action-fn) (oref backend selected-mock))
  54. (xwwp-event-dispatch)))
  55. (defun xwwp-location-callback (result)
  56. "Called after updating candidates with the css classes in RESULT."
  57. (let ((backend xwwp-follow-link-completion-backend-instance))
  58. ;; Store the results.
  59. (oset backend location result)))
  60. (cl-defmethod xwwp-follow-link-candidates ((backend xwwp-follow-link-completion-backend-test))
  61. "Return the list of BACKEND mocked candidates."
  62. (oref backend candidates-mock))
  63. (cl-defmethod xwwp-follow-link-read ((backend xwwp-follow-link-completion-backend-test) _ _ action-fn update-fn)
  64. "Store ACTION-FN in BACKEND, call the UPDATE-FN, and fetch the link element classes."
  65. ;; Stoire action so that we can call it after having fetch the css classes.
  66. (oset backend action-fn action-fn)
  67. ;; Trigger the javascript update.
  68. (funcall update-fn)
  69. ;; Fetch css classes.
  70. (xwwp-js-inject (xwidget-webkit-current-session) 'test)
  71. (xwwp-test-element-classes (xwidget-webkit-current-session) "a" #'xwwp-update-fn-callback)
  72. (xwwp-event-dispatch))
  73. (cl-defmethod backend-test-link-classes ((backend xwwp-follow-link-completion-backend-test) link-id)
  74. "Return test BACKEND css class names for LINK-ID."
  75. (cdr (assoc link-id (oref backend classes))))
  76. (defmacro with-backend (backend &rest body)
  77. "Run BODY with the specified BACKEND."
  78. (declare (indent 1))
  79. `(let* ((backend (,(intern (concat "xwwp-follow-link-completion-backend-" (symbol-name backend)))))
  80. (xwwp-follow-link-completion-backend-instance backend))
  81. ,@body))
  82. (defmacro with-test-backend-browse (candidates selected url &rest body)
  83. "Run BODY with the specified BACKEND mocking CANDIDATES and SELECTED while browsing URL."
  84. (declare (indent 3))
  85. `(let* ((xwwp-follow-link-completion-system
  86. (lambda () (xwwp-follow-link-completion-backend-test :candidates-mock ,candidates
  87. :selected-mock ,selected))))
  88. (with-browse ,url
  89. ,@body)))
  90. (ert-deftest test-xwwp-follow-link-prepare-links ()
  91. (let ((links '(("3" . "Functions")
  92. ("1" . "Function Cells")
  93. ("12" . "Structures")
  94. ("2" . "Anonymous Functions")
  95. ("9" . "Declare Form"))))
  96. (should (equal '(("Function Cells" . 1)
  97. ("Anonymous Functions" . 2)
  98. ("Functions" . 3)
  99. ("Declare Form" . 9)
  100. ("Structures" . 12))
  101. (xwwp-follow-link-prepare-links links)))))
  102. (ert-deftest test-xwwp-follow-link-highlight ()
  103. (with-test-backend-browse '(0 0 1) 0 "links.html"
  104. (xwwp-follow-link)
  105. (xwwp-event-loop)
  106. (let ((backend xwwp-follow-link-completion-backend-instance))
  107. (xwwp-js-inject xwidget 'test)
  108. (xwwp-test-current-location xwidget #'xwwp-location-callback)
  109. (xwwp-event-dispatch)
  110. (should (string= "test-1.html" (file-name-nondirectory (oref backend location))))
  111. (should (equal (backend-test-link-classes backend "test-1") '["xwwp-follow-link-selected"]))
  112. (should (equal (backend-test-link-classes backend "test-2") '["xwwp-follow-link-candidate"]))))
  113. (with-test-backend-browse '(1 0 1) 1 "links.html"
  114. (xwwp-follow-link)
  115. (xwwp-event-loop)
  116. (let ((backend xwwp-follow-link-completion-backend-instance))
  117. (xwwp-js-inject xwidget 'test)
  118. (xwwp-test-current-location xwidget #'xwwp-location-callback)
  119. (xwwp-event-dispatch)
  120. (should (string= "test-2.html" (file-name-nondirectory (oref backend location))))
  121. (should (equal (backend-test-link-classes backend "test-1") '["xwwp-follow-link-candidate"]))
  122. (should (equal (backend-test-link-classes backend "test-2") '["xwwp-follow-link-selected"])))))
  123. (ert-deftest test-xwwp-follow-link-highlight-no-candidates ()
  124. (with-test-backend-browse '(1) 1 "links.html"
  125. (xwwp-follow-link)
  126. (xwwp-event-loop)
  127. (let ((backend xwwp-follow-link-completion-backend-instance))
  128. (xwwp-js-inject xwidget 'test)
  129. (xwwp-test-current-location xwidget #'xwwp-location-callback)
  130. (xwwp-event-dispatch)
  131. (should (string= "test-2.html" (file-name-nondirectory (oref backend location))))
  132. (should (equal (backend-test-link-classes backend "test-1") '[]))
  133. (should (equal (backend-test-link-classes backend "test-2") '["xwwp-follow-link-selected"])))))
  134. (defmacro with-read-fixtures (backend &rest body)
  135. (declare (indent 1))
  136. `(let* ((links '(("test 1" . 0) ("test 2" . 1)))
  137. link
  138. (action (lambda (l) (setq link l)))
  139. (update (lambda ())))
  140. (with-backend ,backend
  141. (with-browse "links.html"
  142. ,@body))))
  143. (ert-deftest test-xwwp-follow-link-read-default ()
  144. (with-read-fixtures default
  145. (with-simulated-input "test SPC 2 RET"
  146. (xwwp-follow-link-read backend "Test: " links action update)
  147. (should (= 1 link)))))
  148. (ert-deftest test-xwwp-follow-link-read-ido ()
  149. (require 'ido)
  150. (with-read-fixtures ido
  151. (with-simulated-input "2 RET"
  152. (xwwp-follow-link-read backend "Test: " links action update)
  153. (should (= 1 link)))))
  154. (ert-deftest test-xwwp-follow-link-read-ivy ()
  155. (require 'ivy)
  156. (with-read-fixtures ivy
  157. (with-simulated-input "2 RET"
  158. (xwwp-follow-link-read backend "Test: " links action update)
  159. (should (= 1 link)))))
  160. (ert-deftest test-xwwp-follow-link-read-helm ()
  161. (require 'helm)
  162. (with-read-fixtures helm
  163. (with-simulated-input '("2" (wsi-simulate-idle-time 0.1) "RET")
  164. (xwwp-follow-link-read backend "Test: " links action update)
  165. (should (= 1 link)))))
  166. (defmacro with-feature (feature &rest body)
  167. (declare (indent 1))
  168. (let ((fsym (intern (concat "xwwp-follow-link-" (symbol-name feature)))))
  169. `(cl-letf (((symbol-function 'require) (lambda (f &optional filename no-errors) (eq (quote ,fsym) f))))
  170. ,@body)))
  171. (ert-deftest test-xwwp-follow-link-make-backend-use-custom ()
  172. (let ((xwwp-follow-link-completion-system 'default))
  173. (with-feature nil
  174. (should (eq #'xwwp-follow-link-completion-backend-default (xwwp-follow-link-make-backend)))))
  175. (let ((xwwp-follow-link-completion-system 'ido))
  176. (with-feature ido
  177. (should (eq #'xwwp-follow-link-completion-backend-ido (xwwp-follow-link-make-backend)))))
  178. (let ((xwwp-follow-link-completion-system 'ivy))
  179. (with-feature ivy
  180. (should (eq #'xwwp-follow-link-completion-backend-ivy (xwwp-follow-link-make-backend)))))
  181. (let ((xwwp-follow-link-completion-system 'helm))
  182. (with-feature helm
  183. (should (eq #'xwwp-follow-link-completion-backend-helm (xwwp-follow-link-make-backend)))))
  184. (let ((xwwp-follow-link-completion-system #'identity))
  185. (should (eq #'identity (xwwp-follow-link-make-backend)))))
  186. ;; Local Variables:
  187. ;; eval: (mmm-mode)
  188. ;; eval: (mmm-add-group 'elisp-js '((elisp-rawjs :submode js-mode
  189. ;; :face mmm-code-submode-face
  190. ;; :delimiter-mode nil
  191. ;; :front "xwwp--js \"" :back "\" js--")
  192. ;; (elisp-defjs :submode js-mode
  193. ;; :face mmm-code-submode-face
  194. ;; :delimiter-mode nil
  195. ;; :front "xwwp-js-def .*\n.*\"\"\n" :back "\")\n")))
  196. ;; mmm-classes: elisp-js
  197. ;; End:
  198. (provide 'xwwp-follow-link-test)
  199. ;;; xwwp-follow-link-test.el ends here