I'm the maintainer of an Emacs package whose entire purpose is related to user interaction. Whenever I make a change to the code, I have to test it out manually to see if it works. It would be nice if I could do some automated testing, but I have no idea how to simulate user input in the way that would be required to do so. Is there any way to run an interactive function that will prompt the user and then respond to that prompt with simulated typing (including key combinations like C-j)?
To run the function, use M-: ( eval-expression ) and type (count-words-buffer) then RET . If the function needed arguments, you'd need to add them after the function name, e.g. (my-function "first argument" 'second-argument) . Alternatively, go to the *scratch* buffer and type your code (e.g. (count-word-buffers) ).
A Lisp function becomes a command when its body contains, at top level, a form that calls the special form ` (interactive...) '. This special form does nothing when executed, but its presence in the function definition indicates that interactive calling is permitted.
Emacs Lisp is a dialect of the Lisp programming language used as a scripting language by Emacs (a text editor family most commonly associated with GNU Emacs and XEmacs). It is used for implementing most of the editing functionality built into Emacs, the remainder being written in C, as is the Lisp interpreter.
ERT is a tool for automated testing in Emacs Lisp. Its main features are facilities for defining tests, running them and reporting the results, and for debugging test failures interactively.
New: I have reimplemented my with-simulated-input
macro using execute-kbd-macro
, so it now works in batch mode as well. You can view the new implementation here.
I found the answer in a question on the Emacs SX site. Basically, you have to put the desired sequence of keys into unread-command-events
after converting it to the proper format. For example:
(let ((unread-command-events (listify-key-sequence (kbd "blu RET"))))
(ido-completing-read "Select a color: " '("yellow" "blue")))
Properly returns "blue"
.
One thing to be careful about is that you have to make sure that your key sequence will definitely terminate the interactive part of the command, or else the command will continue waiting for input. One way to ensure termination is to append "C-g" to the key sequence, which will abort the command if it hasn't finished by the time it gets to the end of the key sequence. If the command does finish, then any unused input will be discarded when the let-binding goes out of scope, so the C-g event will not signal an error. So a more proper test might be:
;; Runs successfully
(condition-case nil
(let ((unread-command-events (listify-key-sequence (kbd "blu RET C-g"))))
(ido-completing-read "Select a color: " '("yellow" "blue")))
(quit (error "Reached end of `unread-command-events' without terminating")))
;; Throws an error
(condition-case nil
(let ((unread-command-events (listify-key-sequence (kbd "blu C-g"))))
(ido-completing-read "Select a color: " '("yellow" "blue")))
(quit (error "Reached end of `unread-command-events' without terminating")))
An important caveat to this approach is that despite allowing you to run an interactive function completely non-interactively, it will not work in a batch-mode emacs session, presumably because emacs doesn't process keyboard input at all in batch mode.
You can make use of execute-kbd-macro
and ERT. I have a very simple implementation in my test file.
The tests actually look very neat - almost as if I was pressing the keys interactively:
(ert-deftest ivy-read ()
(should (equal
(ivy-with '(ivy-read "pattern: " '("blue" "yellow"))
"C-m")
"blue"))
(should (equal
(ivy-with '(ivy-read "pattern: " '("blue" "yellow"))
"y C-m")
"yellow"))
(should (equal
(ivy-with '(ivy-read "pattern: " '("blue" "yellow"))
"y DEL b C-m")
"blue"))
(should (equal
(ivy-with '(ivy-read "pattern: " '("blue" "yellow"))
"z C-m")
"z")))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With