I am pretty new to emacs (doom-emacs in this case) and I have an idea of what I want to do, but not sure how to do it.

What I am after is that when I open a .js file, I want to split my window into 3. one small window on the left where I want to run jest, and one small window on the right if there is a test file for the file opened in the buffer (following the format *.spec.(js|ts)).

is this doable in emacs or should I just give up on these dreams?

  • I have a feeling this question might be a duplicate. Search the tags for this (put a tag in brackets ([]) to search for it). If you find a dup, please delete this one. Thx.
    – Drew
    Oct 21, 2022 at 21:46

2 Answers 2


It's definitely possible. Here is my initial attempt at creating the 3 window split with a jest test runner, a source file, and it's associated spec file. You can put this code in your config and try it out via M-x jest-open.

(defun jest-spec-for-file (file)
  "Given a file, return its matching spec file."
  (let* ((dirname  (file-name-directory    file))
         (filename (file-name-nondirectory file))
         (ext      (file-name-extension    file))
          (replace-regexp-in-string (concat "." ext "$") "" filename)))
    (concat dirname basename ".spec." ext)))

(defvar jest-command "jest --watch"
  "This is the shell command used to run jest.")

(defun jest-run (&optional term)
  "Switch to the jest buffer if it exists or create a new one."
  (if (get-buffer "jest") (switch-to-buffer "jest")
    (cond ((equal term 'vterm)
             (vterm "jest")
             (vterm-send-string (concat jest-command "\n"))))
             (term "/bin/bash")
             (rename-buffer "jest")
             (term-send-raw-string (concat jest-command "\n"))

(defun jest-open (file)
  "Create a 3 window layout containing jest|source|spec."
  (interactive "f")
  (let* ((spec (jest-spec-for-file file)))
    (jest-run)             ; change this to (jest-run 'vterm)
    (find-file file)
    (find-file spec)

How It Works

We have 3 functions and a variable.

(jest-spec-for-file file)

Return the spec file associated with file. This is just pure string manipulation that takes a string like /tmp/index.js and returns /tmp/index.spec.js.


This variable contains the shell command used to invoke jest. Feel free to adapt it to your needs.

(jest-run &optional term)

If a buffer named "jest" exists, switch to it. Otherwise, create a term (or vterm) buffer and run jest-command inside of it. I have it default to use term since it's included with stock emacs, but I highly recommend giving vterm a try. Anything that's even slightly animated will look better in vterm. When you're ready to make the switch, change the line that says:



(jest-run 'vterm)

Also, keep in mind that if you hit q to stop jest, this function won't try to restart it. Once the jest buffer is created, all control is deferred to you.

(jest-open file)

Finally, we have the function that creates the 3 window split and sets up the buffers such that you have a jest test runner on the left, the source in the middle, and a spec file on the right. It will also place the focus on the middle window, because I think that's what would be most intuitive.

You can give it a try by hitting M-x jest-open and selecting a file when prompted. If you end up wanting to use this frequently, you can bind it to a key. You can do it the doom way too.


I tried to write this in a way that works in any Emacs configuration. It should work just fine in Doom. As you explore this code (or any other elisp), I encourage you to use C-h f look up the docs for functions. I also like using M-x ielm to start up an interactive elisp repl to feel how things work. Doing this really accelerated my elisp self-education.


Use M-x window-configuration-to-register (bound to C-x r w in vanilla Emacs, not sure about Doom). From the documentation:

window-configuration-to-register is an interactive and natively compiled function defined in register.el.gz.

Signature (window-configuration-to-register REGISTER)

Documentation Store the window configuration of the selected frame in register REGISTER.

Use C-x r j to restore the configuration. Argument is a character, naming the register.

Interactively, reads the register using register-read-with-preview.

  • The problem I had with window-configuration-to-register is that it's really hard to persist the value of a #<window-configuration> that's in a register between restarts of emacs. However, I did come up with an alternative.
    – g-gundam
    Oct 26, 2022 at 20:58
  • 1
    You need desktop mode (desktop.el) -- that lets you persist anything you specify. Oct 26, 2022 at 22:48
  • I'll look into that. Thanks.
    – g-gundam
    Oct 26, 2022 at 23:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.