Mocking the VS Code extension API in unit tests using Jest

When unit testing VS Code extension, we usually encounter a problem. The functions of the VS Code editor used in the code all depend on the vscode library. However, we did not add dependence on the vscode library in the unit test , so it caused the run An error occurred during unit testing. Since the vscode library is introduced into our VS Code extension as a third-party dependency, it is not under our control. The best way is to simulate the API in the unit test. In this article I will introduce how to use Jest to simulate the API of the vscode library.

  If you're not familiar with how to start creating a VS Code extension, the documentation here can teach you how to get started quickly.

After creating the VS Code extension project, you will find a package.json file   in the root directory . VS Code extension will read configuration items from it to manage UI interface elements. In actual development, you may use some of these attributes. . We can set the dependencies required by the project through package.json . Here we add Jest as a dev dependency and add an npm script to run Jest unit tests.

npm i -D jest
{
  "scripts": {
    "test": "jest"
  }
}

Simulation VS Code node module

  Jest provides some mocking options, but since we want to mock the entire vscode node module, the easiest way is to create a __mocks__ folder in the same location as the node_modules folder (usually the root directory of the project) and put it in Add a file ( vscode.js ) with the same name as the module you want to mock .

  You don't need to import this module in your test code, mock will load it automatically. Jest calls this manual mocks .

  The biggest benefit of this method is that it separates our test code from the modules it depends on, making the test code look cleaner. There is a small problem here . New developers need to know the __mocks__ folder, otherwise it will be difficult to understand how the unit test works properly, because there is no code for the VS Code module to be mocked in the unit test.

  The following is the code to simulate the VS Code module. We are not mocking the entire API, you can adjust it as needed.

// vscode.js

const languages = {
  createDiagnosticCollection: jest.fn()
};

const StatusBarAlignment = {};

const window = {
  createStatusBarItem: jest.fn(() => ({
    show: jest.fn()
  })),
  showErrorMessage: jest.fn(),
  showWarningMessage: jest.fn(),
  createTextEditorDecorationType: jest.fn()
};

const workspace = {
  getConfiguration: jest.fn(),
  workspaceFolders: [],
  onDidSaveTextDocument: jest.fn()
};

const OverviewRulerLane = {
  Left: null
};

const Uri = {
  file: f => f,
  parse: jest.fn()
};
const Range = jest.fn();
const Diagnostic = jest.fn();
const DiagnosticSeverity = { Error: 0, Warning: 1, Information: 2, Hint: 3 };

const debug = {
  onDidTerminateDebugSession: jest.fn(),
  startDebugging: jest.fn()
};

const commands = {
  executeCommand: jest.fn()
};

const vscode = {
  languages,
  StatusBarAlignment,
  window,
  workspace,
  OverviewRulerLane,
  Uri,
  Range,
  Diagnostic,
  DiagnosticSeverity,
  debug,
  commands
};

module.exports = vscode;

Example of using mocked VS Code modules

This approach is used in   my open source project Git Mob for VS Code , and I'll use the code from it to illustrate how to use mocked VS Code modules.

  In the example below, the status bar of the VS Code editor will be adjusted accordingly based on whether the Git hook prepare-commit-msg is called. You can see that I did not import the vscode module into my test file and It performs simulation.

// git-mob-hook-status.spec.js

const { hasPrepareCommitMsgTemplate } = require("../prepare-commit-msg-file");
const { gitMobHookStatus } = require("./git-mob-hook-status");

jest.mock("./../prepare-commit-msg-file");

describe("Hook or template status", function() {
  let mockContext;
  beforeAll(function() {
    mockContext = {
      subscriptions: []
    };
  });

  afterEach(function() {
    hasPrepareCommitMsgTemplate.mockReset();
  });

  it("using git template for co-authors", () => {
    hasPrepareCommitMsgTemplate.mockReturnValue(false);
    const statusBar = gitMobHookStatus({ context: mockContext })();
    expect(statusBar).toEqual(
      expect.objectContaining({
        text: "$(file-code) Git Mob",
        tooltip: "Using .gitmessage template"
      })
    );
  });

  it("using git prepare commit msg for co-authors", () => {
    hasPrepareCommitMsgTemplate.mockReturnValue(true);
    const statusBar = gitMobHookStatus({ context: mockContext })();
    expect(statusBar).toEqual(
      expect.objectContaining({
        text: "$(zap) Git Mob",
        tooltip: "Using prepare-commit-msg hook"
      })
    );
  });
});

// git-mob-hook-status.js
const vscode = require("vscode");
const { hasPrepareCommitMsgTemplate } = require("../prepare-commit-msg-file");

function gitMobHookStatus({ context }) {
  const myStatusBarItem = vscode.window.createStatusBarItem(
    vscode.StatusBarAlignment.Left,
    10
  );
  context.subscriptions.push(myStatusBarItem);
  return function() {
    myStatusBarItem.text = "$(file-code) Git Mob";
    myStatusBarItem.tooltip = "Using .gitmessage template";
    if (hasPrepareCommitMsgTemplate()) {
      myStatusBarItem.text = "$(zap) Git Mob";
      myStatusBarItem.tooltip = "Using prepare-commit-msg hook";
    }
    myStatusBarItem.show();
    return myStatusBarItem;
  };
}

exports.gitMobHookStatus = gitMobHookStatus;

  You can view the source code here:

Can I check if a method in vscode module is called?

  You can import simulated vscode modules. In the code below, I want to check whether the onDidSaveTextDocument event is subscribed when the user modifies the co-author file.

const vscode = require("../__mocks__/vscode");

// ...
test("Reload co-author list when git-coauthors file saved", () => {
  reloadOnSave(coAuthorProviderStub);
  expect(vscode.workspace.onDidSaveTextDocument).toHaveBeenCalledWith(
    expect.any(Function)
  );
  // ...
});
// ...

  You can see that these are all standard usages of the Jest mock API, which means that we can use the methods of the vscode module normally in the code without any restrictions on manual mock . For example, we can also use mockImplementation to modify the implementation.

  More examples can be found in the source code here:

  The biggest advantage of writing unit tests is that you can get feedback results quickly. If you are fond of TDD (Test-Driven Development, test-driven development), then unit tests will make you more confident in the development of VS Code extension.


 How to obtain information

【Message 777】

Friends who want to get the source code and other tutorial materials, please like + comment + collect , three times in a row!

After three consecutive rounds , I will send you private messages one by one in the comment area~

Guess you like

Origin blog.csdn.net/GDYY3721/article/details/132210242
Recommended