npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

jest-environment-vscode-extension

v0.0.5

Published

> 🎪 The best way to run and write tests for your VSCode extension

Readme

jest-environment-vscode-extension

🎪 The best way to run and write tests for your VSCode extension

Key Features:

  • run tests using Jest
  • built-in API making tests simpler to write and read
  • zero JS configuration

Setup

1 - Install the following packages:

npm install jest jest-environment-vscode-extension @types/jest @types/jest-environment-vscode-extension --save-dev

2 - On .vscode/tasks.json, add the following within the tasks array:

{
  "label": "create-test-workspace-folder",
  "type": "shell",
  "command": "mkdir",
  "args": ["-p", "test-workspace"],
  "presentation": {
    "reveal": "silent",
    "revealProblems": "onProblem"
  }
},
{
  "label": "remove-test-workspace-folder",
  "type": "shell",
  "command": "rm",
  "args": ["-rf", "test-workspace"],
  "presentation": {
    "reveal": "silent",
    "revealProblems": "onProblem"
  }
},
{
  "label": "insert-monkey-patch-allow-mocks",
  "type": "shell",
  "command": "node ./node_modules/.bin/insert-monkey-patch-allow-mocks ${workspaceFolder}",
  "presentation": {
    "reveal": "silent",
    "revealProblems": "onProblem"
  },
},
{
  "label": "drop-monkey-patch-allow-mocks",
  "type": "shell",
  "command": "node ./node_modules/.bin/drop-monkey-patch-allow-mocks ${workspaceFolder}",
  "presentation": {
    "reveal": "silent",
    "revealProblems": "onProblem"
  }
},
{
  "label": "pre-run-tests",
  "dependsOrder": "sequence",
  "dependsOn": [
    "remove-test-workspace-folder",
    "create-test-workspace-folder",
    "build",
    "insert-monkey-patch-allow-mocks"
  ],
  "presentation": {
    "reveal": "silent",
    "revealProblems": "onProblem"
  }
},
{
  "label": "post-run-tests",
  "dependsOn": [
    "remove-test-workspace-folder",
    "drop-monkey-patch-allow-mocks"
  ],
  "presentation": {
    "reveal": "silent",
    "revealProblems": "onProblem"
  }
}

3 - On .vscode/launch.json, add the following within the configurations array:

{
  "name": "Test Extension - No Workspace",
  "preLaunchTask": "pre-run-tests",
  "postDebugTask": "post-run-tests",
  "type": "extensionHost",
  "request": "launch",
  "runtimeExecutable": "${execPath}",
  "args": [
    "/no-workspace",
    "--disable-extensions",
    "--extensionDevelopmentPath=${workspaceFolder}",
    "--extensionTestsPath=${workspaceFolder}/node_modules/.bin/vscode-tests-runner"
  ],
  "env": {
    "VSCODE_TESTS_PATH": "${workspaceFolder}/out/tests/no-workspace/"
  },
  "outFiles": ["${workspaceFolder}/out/tests/**/*.js"]
},
{
  "name": "Test Extension - With Workspace",
  "preLaunchTask": "pre-run-tests",
  "postDebugTask": "post-run-tests",
  "type": "extensionHost",
  "request": "launch",
  "runtimeExecutable": "${execPath}",
  "args": [
    "${workspaceFolder}/test-workspace",
    "--disable-extensions",
    "--extensionDevelopmentPath=${workspaceFolder}",
    "--extensionTestsPath=${workspaceFolder}/node_modules/.bin/vscode-tests-runner"
  ],
  "env": {
    "VSCODE_TESTS_PATH": "${workspaceFolder}/out/tests/with-workspace/"
  },
  "outFiles": ["${workspaceFolder}/out/tests/**/*.js"]
}

4 - Now, write your tests that depend on a workspace within tests/with-workspace. And if it doesn't need it, you can write them within tests/no-workspace.

Setup finished! 🎉

Now you can run the tests using VSCode:

Running on CI

Running by VSCode is great for development since it's quick and can use breakpoints. But we need to do one more step to can run on CI.

1 - On package.json, add the following within the scripts object:

"tests:ci:no-workspace": "vscode-electron-starter no-workspace insiders out/tests/no-workspace",
"tests:ci:with-workspace": "vscode-electron-starter with-workspace insiders out/tests/with-workspace"

The penultimate parameter is the VSCode version being used. You can use stable, insiders, or a version number (e.g., 1.32.0). The last parameter is the path of the test.

2 - Now you can call these scripts on CI. Following, a script to run on GitHub actions:

on:
  push:
    branches:

jobs:
  test:
    name: Test
    strategy:
      matrix:
        os: [ubuntu-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Setup Node.js
        uses: actions/setup-node@v1
        with:
          node-version: 16
      - name: Install dependencies
        run: npm install
      - name: Build
        run: npm run build
      - name: Run test - No workspace
        uses: GabrielBB/[email protected]
        with:
          run: npm run tests:ci:no-workspace
      - name: Run test - With workspace
        uses: GabrielBB/[email protected]
        with:
          run: npm run tests:ci:with-workspace

Writing your first test using jest-environment-vscode-extension

It's almost the same idea as writing any other test using Jest, but we have a powerful API focused on VSCode.

Let's do a walkthrough writing a simple test. We want to test if the "go to the definition" works well at the second x:

const x = 42
console.log(x)

1 - Firstly, our test doesn't depend on a workspace. Then we'll write it at tests/no-workspace/definitions.test.ts. Usually, a test depends on a workspace if it interacts with other files on the same workspace.

2 - Let's write the test itself:

// get some things from the global variable `vscode`
const { Position, Range } = vscode

describe('#Definition', () => {
  it('on message interpolation', () => {
    // create a new file
    return using({
      files: {
        'index.js': dedent(`
          const x = 42
          console.log(x)
        `),
      }},
      async (mapFileToDoc) => {
        // on the file `index.js`, take the definitions at 1:12 (the `x` within the `console.log`)
        const definitions = await take.definitions(mapFileToDoc['index.js'], new Position(1, 12))

        // assert that it's as the expected
        expect(definitions).toHaveLength(1)
        expect(definitions[0]).toMatchObject({
          originSelectionRange: new Range(new Position(1, 12), new Position(1, 13)),
          targetRange: new Range(new Position(0, 12), new Position(0, 0)),
          targetSelectionRange: new Range(new Position(0, 6), new Position(0, 7)),
        })
      })
  })
})

On the above test, we used some variables injected by jest-environment-vscode-extension: vscode, using, dedent, and take. Think of them as the Jest's describe or it, but focused on helping you while working with VSCode.

Let's talk about them!

API

using

Our most useful function.

It creates the files and, optionally, can mock VSCode's functions. It receives a callback and, when it's finished, clear the files and mocks.

Files

You can create as many files as needed, and their TextDocument is sent to the callback:

using(
  {
    files: {
      'index.js': '"example";',
      'foo.js': '1;',
      'bar.js': '2;',
    },
  },
  async (mapFileToDoc) => {
    mapFileToDoc['index.js'] // TextDocument
    mapFileToDoc['foo.js']   // TextDocument
    mapFileToDoc['bar.js']   // TextDocument
  }
)

Mocks

There are some VSCode features in which we can't manipulate, such as the window.showQuickPick. But no worries! We can easily mock it:

using(
  {
    files: {
      'index.js': '"example";',
    },
    mocks: {
      'window.showQuickPick': async () => 'My Option',
    },
  },
  async (mapFileToDoc) => {

  }
)

Now, if the extension calls window.showQuickPick it'll return Promise<'My Option'>.

But there is a rule to use mocks: You should ensure that the extension is initialized. For example, let's say that your extension is initialized only when there is a .ml file in the workspace:

"activationEvents": [
  "workspaceContains:**/*.ml"
]

So you should run the tests using workspace and create at least one .ml file:

using(
  {
    files: {
      'main.ml': 'let hello () = print_endline "hey there"',
    },
    mocks: {
      'window.showQuickPick': async () => 'My Option',
    },
  },
  async (mapFileToDoc) => {

  }
)

dedent

Function to remove indentation. Helpful with using.

vscode

It's the same vscode used by the extension itself. So you can use it to manipulate the VSCode.

For example, if you want to open and show a document, you should do:

const { workspace, window } = vscode

const doc = await workspace.openTextDocument(mapFileToDoc['index.js'])
await window.showTextDocument(doc)

It doesn't export the types. If you want them, you should do:

import type { Position } from 'vscode'

const printPosition = (position: Position) => {
  console.log({
    line: position.line,
    character: position.character,
  })
}

take

It exposes many helper functions to take values from the VSCode. Just use TypeScript's intellisense to explore what it has.

waitFor

It exposes a helper function to wait for something.

For example, if your extension takes time to initialize, it can be useful:

const waitForDocumentSymbols = async (doc, position) => {
  return await waitFor(async () => {
    const hovers = await take.hovers(doc, position)
    expect(hovers).toHaveLength(1)
    return hovers
  })
}

describe("#Document Symbol", () => {
  it("includes function declaration", () => {
    return using(
      {
        files: {
          'main.ml': 'let hello () = print_endline "hey there"',
        },
      },
      async (mapFileToDoc) => {
        const symbols = await waitForDocumentSymbols(mapFileToDoc['main.ml'])

        expect(symbols[0]).toMatchObject({
            name: 'hello',
            detail: 'unit -> unit',
        })
      }
    )
  })
})

Who is using