Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unable to import vscode in test using jest #37

Open
matthoang08 opened this issue Aug 16, 2019 · 27 comments
Open

unable to import vscode in test using jest #37

matthoang08 opened this issue Aug 16, 2019 · 27 comments
Labels
feature-request Request for new features or functionality

Comments

@matthoang08
Copy link

Hi, I'm trying to run some integration tests for my vscode extension using jest. Unit tests work fine since I'm able to mock vscode however, when I'm trying to run an integration test I'm getting Cannot find module 'vscode' in the files when i'm using vscode api (import * as vscode from 'vscode')

jest config looks like this:

module.exports = {
  moduleFileExtensions: ['js'],
  testMatch: ['<rootDir>/out/test/**/*.int.test.js'],
  verbose: true,
};

runTest.ts

import * as path from 'path';
import { runTests } from 'vscode-test';

async function main() {
	try {
		// The folder containing the Extension Manifest package.json
		// Passed to `--extensionDevelopmentPath`
		const extensionDevelopmentPath = path.resolve(__dirname, '../../');

		// The path to the extension test script
		// Passed to --extensionTestsPath
		const extensionTestsPath = path.resolve(__dirname, './suite/index');

		// Download VS Code, unzip it and run the integration test
		console.log(`running tests... ext path: ${extensionTestsPath}`);
		await runTests({
			extensionDevelopmentPath,
			extensionTestsPath,
			launchArgs: ['--disable-extensions']
		});
	} catch (err) {
		console.error('Failed to run tests', err);
		process.exit(1);
	}
}

main();

index.ts

import * as path from 'path';
import { runCLI } from 'jest-cli';
import * as vscode from 'vscode';

export function run(): Promise<void> {

  return new Promise((resolve, reject) => {
    const projectRootPath = path.join(__dirname, '../../../');
    const config = path.join(projectRootPath, 'jest.e2e.config.js');

    vscode.window.showInformationMessage('Run suite');

    runCLI({ config } as any, [projectRootPath])
      .then(jestCliCallResult => {
        console.log(`complete: ${JSON.stringify(jestCliCallResult)}`);
        console.log('print results');
        jestCliCallResult.results.testResults
          .forEach(testResult => {
            testResult.testResults
              .filter(assertionResult => assertionResult.status === 'passed')
              .forEach(({ ancestorTitles, title, status }) => {
                console.info(`  ● ${ancestorTitles}${title} (${status})`);
              });
          });

        console.log('check results');
        jestCliCallResult.results.testResults
          .forEach(testResult => {
            if (testResult.failureMessage) {
              console.error(testResult.failureMessage);
            }
          });
        resolve();
      })
      .catch(errorCaughtByJestRunner => {
        console.error('error in test runner', errorCaughtByJestRunner);
        reject(errorCaughtByJestRunner);
      });
  });
}

I installed both vscode-test and @types/vscode as dev dependencies. I'm not sure why my tests are unable to find the 'vscode' dependency. Vscode is the only dependency that has this issue, other modules work fine. Can anyone help?

Thanks!

@octref octref added the feature-request Request for new features or functionality label Aug 18, 2019
@octref
Copy link
Contributor

octref commented Aug 18, 2019

Hi @matthoang08, thanks for giving jest a try. vscode is provided in the extension host environment where VS Code runs extensions.

Would https://jestjs.io/docs/en/configuration#globals-object or https://jestjs.io/docs/en/configuration#globalsetup-string help you? jestjs/jest#708 also seems to mention handling global jquery.

I can give it a try later in Monday as well. If this works I can put together an official recipe.

@PeterPorzuczek
Copy link

PeterPorzuczek commented Sep 20, 2019

I was able to reference vscode instance in my tests only through process variable, maybe I was doing something wrong with the globals setup but vscode package couldn't be required there as @octref proposed.

So to make it work with process variable in typescript you have to define your typing anywhere in your project as a separate file ex. process.d.ts
Preview:

declare namespace NodeJS {
	export interface Process {
		vscode?: any
	}
}

Then in suite/index.ts import vscode and set process.vscode, before run function definition
Preview:

import * as path from 'path';
import { runCLI } from 'jest-cli';
import * as vscode from 'vscode';

process.vscode = vscode;

export function run(): Promise<void> {
  return new Promise((resolve, reject) => {
       ...

And finally in your test file you can reference process.vscode
Preview:

describe('Extension Test Suite', () => {
	beforeEach(() => {
		process.vscode.window.showInformationMessage('Start all tests.');
	});

	it('Sample test', () => {
		process.vscode.commands.executeCommand('extension.helloWorld');
		expect(1).toBe(1);
	});
});

It is very hacky way of accessing vscode instance, so try to find a better solution. I just post my findings FYI.

@marcopierobon
Copy link

Are you sure this actually works? I've tried implementing that, but it still fails with the same error when the tests try to load the file that is still loading vscode (in your example that would be the one containing function run())

@spnq
Copy link

spnq commented Dec 13, 2019

Any progress on this?
I tried to run my .spec.ts files with ts-jest and babel-jest, because I thought es6 import has to be transpiled before the test run and that caused the error, but vscode import itself seems to be the issue.

@rmi22186
Copy link

having this issue also. Cannot find module 'vscode' even though all other modules are found okay...

@rmi22186
Copy link

seems like it can't be imported for tests, but it can be by the vs code extension when you do an e2e test. does that sound right?

@mnovakovic
Copy link

Any updates on this? I am having the same problem in my setup.

@vinnichase
Copy link

I found a very slim workaround!

I was also struggling like hell with that. I found that article which got me on the right track: https://www.richardkotze.com/coding/unit-test-mock-vs-code-extension-api-jest

However to make it run in the default TypeScript extension workflow you need to put the __mocks__ folder (yes plural, not singular as stated in the article) under your rootDir as defined in the tsconfig.json. In the default extension boilerplate it's ./src.

Within the __mocks__ folder you create a vscode.ts (not .js as described in the article) with the following content.

export const vscode = {
  // mock the vscode API which you use in your project. Jest will tell you which keys are missing.
};

In my case an empty vscode object was enough since I only use types and interfaces from the vscode namespace. I would recommend the same for all of you for the major parts of the extension logic. Interacting with the vscode API can be limited to the extension.ts which is not unit tested but covered by e.g. end-to-end-tests.

@octref octref modified the milestones: February 2020, April 2020 Apr 10, 2020
@kieferrm kieferrm removed this from the April 2020 milestone Jun 20, 2020
@arogg
Copy link

arogg commented Jun 22, 2020

@vinnichase You have a flaw there. The way vscode extensions are meant to be tested is IN vscode precisely so that you test vscode fully integrated. This is also the way microsoft introduces you to extension testing... Otherwise any vscode update may blow up your extension because you forgot to update your mocks..

You also won't be able to properly test by passing via the process module, because jest runs everything via the node "vm" module ( https://nodejs.org/api/vm.html ) which prevents you from selectively modifying the vscode object if the vscode object is not part of the vms global object (the vm context). That is you will be able to modify it IN the test but your modifications to the vscode module will NOT propagate outwards to your extension code, because of the vm. It does not matter that the process PID is the same. The key point is the "vm" module that jest uses.

The correct way to use jest inside a vscode host is you do


class VsCodeEnvironment extends NodeEnvironment {
  async setup() {
      
    await super.setup();
     this.global.vscode = vscode; // puts vscode into global scope of the vm, but more importantly makes vscode object native to the vm, (allowing you to mock parts of it)
  }

  async teardown() {
      
       delete this.global.vscode;
       await super.teardown();
  }


}

module.exports = VsCodeEnvironment;

and then


await runCLI({

                        testEnvironment:path.join(__dirname,'testenv.js'),
			
		},[jestProject]);

You still wont be able to IMPORT vscode like normal in your tests, which is annoying with those import quickfixes, but vscode is available as a global now and now you can mock those pesky extensions error messages etc. and changes will propagate outwards

@vinnichase
Copy link

vinnichase commented Jun 22, 2020

Thanks for the hint! However this breaks my understanding of unit tests which I was doing in my case. Your approach would apply better in an integration test.

I didn't even mock vscode functionality but only imported a class and used it as an interface and an enum.

There used to be a special vscode typings package on npm for that purpose but maintenance stopped and it deviated from the ones exposed in the vscode extension context. So thats ridiculous that you can not use the interace description (which is by definition the abstraction of the running code) separately from the runtime context.

@MarioCadenas
Copy link

MarioCadenas commented Sep 28, 2020

So I actually manage to inject vscode into jest, and it's not that ugly. This works for me, hope it works for someone else too!

First of all, create your own vscode environment file

// vscode-environment.js
const NodeEnvironment = require('jest-environment-node');
const vscode = require('vscode');

class VsCodeEnvironment extends NodeEnvironment {
  async setup() {
    await super.setup();
    this.global.vscode = vscode;
  }

  async teardown() {
    this.global.vscode = {};
    await super.teardown();
  }

  runScript(script) {
    return super.runScript(script);
  }
}

module.exports = VsCodeEnvironment;

next, make jest use this environment, I did it by adding it into my jest config

// jest config

module.exports = {
  // more config
  testEnvironment: './vscode-environment.js',
  // more config
};

now we are just missing the tricky and most important part. Create a file, call it whatever you want, I called it vscode.js and copy this line

// vscode.js
module.exports = global.vscode;

Final step, go to your jest config, and define a module mapper like this

const path = require('path');

module.exports = {
  testEnvironment: './vscode-environment.js',
  modulePaths: ['<rootDir>'],
  moduleNameMapper: {
    vscode: path.join(__dirname, 'test-jest', 'vscode.js')  // <----- most important line
  },
};

my vscode file is in test-jest/vscode.js place yours wherever you need!

By doing this, any line that is importing vscode will really import it into jest, so you are able to run methods, mock them or do whatever you want because you have the real vscode object!

I hope this helps someone!!

[EDITED]

Forgot to mention you also need to define a custom Vscode jest runner if someone needs this too I'll add it to this comment!

@mark-wiemer
Copy link

@MarioCadenas I would appreciate some guidance on how to define a custom VS Code Jest runner!

@MarioCadenas
Copy link

@MarioCadenas I would appreciate some guidance on how to define a custom VS Code Jest runner!

Hi @mark-wiemer ! of course! What can I help you with? I'll do my best 😄

@mark-wiemer
Copy link

Thanks @MarioCadenas, but just a few hours after posting that I started to consider other options (e.g. just using Mocha instead). I have little experience in this area, so I think I'll do some reading of my own before coming back with more specific questions. If I never reply, it's because I went with an alternative :) Thanks anyway!

@njzydark
Copy link

So I actually manage to inject vscode into jest, and it's not that ugly. This works for me, hope it works for someone else too!

First of all, create your own vscode environment file

// vscode-environment.js
const NodeEnvironment = require('jest-environment-node');
const vscode = require('vscode');

class VsCodeEnvironment extends NodeEnvironment {
  async setup() {
    await super.setup();
    this.global.vscode = vscode;
  }

  async teardown() {
    this.global.vscode = {};
    await super.teardown();
  }

  runScript(script) {
    return super.runScript(script);
  }
}

module.exports = VsCodeEnvironment;

I try this, but the console throw a error: Cannot find module 'vscode'

@MarioCadenas
Copy link

So I actually manage to inject vscode into jest, and it's not that ugly. This works for me, hope it works for someone else too!
First of all, create your own vscode environment file

// vscode-environment.js
const NodeEnvironment = require('jest-environment-node');
const vscode = require('vscode');

class VsCodeEnvironment extends NodeEnvironment {
  async setup() {
    await super.setup();
    this.global.vscode = vscode;
  }

  async teardown() {
    this.global.vscode = {};
    await super.teardown();
  }

  runScript(script) {
    return super.runScript(script);
  }
}

module.exports = VsCodeEnvironment;

I try this, but the console throw a error: Cannot find module 'vscode'

Do you have a repo to check this? Maybe I can try to help 😄

@CharlieGreenman
Copy link

custom Vscode jest ru

@MarioCadenas would it be possible to add the custom vscode jest runner here. Your solution unfortunately is unusable verbatim without it. Thank you.

@daddykotex
Copy link

FYI: I've pulled things from here and there around the web and ended up: https://github.com/daddykotex/jest-tests

it seems to work fine and uses jest as a test runner instead of mocha

@DiegoWong
Copy link

So I actually manage to inject vscode into jest, and it's not that ugly. This works for me, hope it works for someone else too!
First of all, create your own vscode environment file

// vscode-environment.js
const NodeEnvironment = require('jest-environment-node');
const vscode = require('vscode');

class VsCodeEnvironment extends NodeEnvironment {
  async setup() {
    await super.setup();
    this.global.vscode = vscode;
  }

  async teardown() {
    this.global.vscode = {};
    await super.teardown();
  }

  runScript(script) {
    return super.runScript(script);
  }
}

module.exports = VsCodeEnvironment;

I try this, but the console throw a error: Cannot find module 'vscode'

Do you have a repo to check this? Maybe I can try to help 😄

Hi, I know its an old thread, but I'm dealing with the same error, the test environment can't find the vscode dependency, did you find what was happening?

@MarioCadenas
Copy link

So I actually manage to inject vscode into jest, and it's not that ugly. This works for me, hope it works for someone else too!
First of all, create your own vscode environment file

// vscode-environment.js
const NodeEnvironment = require('jest-environment-node');
const vscode = require('vscode');

class VsCodeEnvironment extends NodeEnvironment {
  async setup() {
    await super.setup();
    this.global.vscode = vscode;
  }

  async teardown() {
    this.global.vscode = {};
    await super.teardown();
  }

  runScript(script) {
    return super.runScript(script);
  }
}

module.exports = VsCodeEnvironment;

I try this, but the console throw a error: Cannot find module 'vscode'

Do you have a repo to check this? Maybe I can try to help 😄

Hi, I know its an old thread, but I'm dealing with the same error, the test environment can't find the vscode dependency, did you find what was happening?

HI @DiegoWong I can try to help if you provide a repository

@DiegoWong
Copy link

DiegoWong commented Nov 18, 2022

Hi @MarioCadenas, Here's the repo. Basically is the same repo as @daddykotex but adding webpack as the build tool.

Thanks in advance for your help!

@CharlieGreenman
Copy link

CharlieGreenman commented Jan 18, 2023

Adding a mocks folder for vscode per blog article here is a clean/efficient solution: https://www.richardkotze.com/coding/unit-test-mock-vs-code-extension-api-jest

https://github.com/rkotze/git-mob-vs-code/blob/baf86ae15bf359bf409a6a3bdc7ac74850640433/__mocks__/vscode.js

@JustinGrote
Copy link

JustinGrote commented Apr 21, 2023

Adding a mocks folder for vscode per blog article here is a clean/efficient solution: https://www.richardkotze.com/coding/unit-test-mock-vs-code-extension-api-jest

https://github.com/rkotze/git-mob-vs-code/tree/baf86ae15bf359bf409a6a3bdc7ac74850640433/__mocks__

The problem here is you are using stubs/mocks, so you can't do actual integration/E2E/UI tests and verify things work in vscode instance itself, or verify the API hasn't changed. That's the real benefit of using vscode-test here vs. just mocking/stubbing out all the external calls.

@JustinGrote
Copy link

JustinGrote commented Apr 22, 2023

To summarize the workaround for this issue:

Alternatively, mock all your calls to vscode and just do unit testing, but you'll never be able to verify things actually work or that an API hasn't changed.

@Blond11516
Copy link

I managed to get tests working with the latest version of Jest (29.5.0 as of writing).

The gist is to use NodeEnvironment.TestEnvironment as the parent class of the vscode custom environment.

As a bonus this update also lets you use VSCode up to 1.73 to run tests. Later versions fail to run tests, I haven't really investigated why.

See this commit for the full diff.

@daddykotex Let me know if you'd like me to open a PR on your repo with the updated setup.

@daddykotex
Copy link

Sure @Blond11516 , I'll merge it no problem

qingpeng9802 added a commit to qingpeng9802/vscode-common-lisp that referenced this issue Sep 29, 2023
since it is hard to deal with `import vscode`.
See microsoft/vscode-test#37

Signed-off-by: Qingpeng Li <[email protected]>
@Jason3S
Copy link

Jason3S commented Dec 3, 2023

To address this issue, I created jest-mock-vscode. It can help with testing logic using unit tests. It is not designed for E2E/UI testing. The vscode-test runner is best for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request Request for new features or functionality
Projects
None yet
Development

No branches or pull requests