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

[Bug]: Jest 28.0.0 breaks vscode Jest testing with "Cannot find module '_isMockFunction' #14095

Closed
JustinGrote opened this issue Apr 22, 2023 · 9 comments · Fixed by #14188
Closed

Comments

@JustinGrote
Copy link

Version

28.0.0 (and latest)

Steps to reproduce

Example Repo:

https://github.com/daddykotex/jest-tests

Further issue description here:
microsoft/vscode#175548

Expected behavior

Tests run as expected

Actual behavior

FAIL ../../../../Projects/vscode-adapter/dist/src/log.test.js
extensionHostProcess.js:102
  ● Test suite failed to run

    Cannot find module '_isMockFunction'
    Require stack:
    - c:\Users\justi\AppData\Local\Programs\Microsoft VS Code\resources\app\out\bootstrap-amd.js
    - c:\Users\justi\AppData\Local\Programs\Microsoft VS Code\resources\app\out\bootstrap-fork.js
    -

      122 | `);const j=this.a+g;if(L>=0)L+=this.a.length;else{this.a=j;return}let G=0;for(;L>=0;)this.m(j.substring(G,L).trim()),G=L+1,L=j.indexOf(`
      123 | `,G);this.a=j.substring(G)}m(g){if(this.b||!g)return;let L;try{L=JSON.parse(g)}catch{throw new Error(`malformed line from rg: ${g}`)}if(L.type==="match"){const j=p(L.data.path),G=O.URI.file(D.join(this.h,j)),Q=this.n(L.data,G);this.p(Q),this.c&&(this.cancel(),this.emit("hitLimit"))}else if(L.type==="context"){const j=p(L.data.path),G=O.URI.file(D.join(this.h,j));this.o(L.data,G).forEach(B=>this.p(B))}}n(g,L){const j=g.line_number-1,G=p(g.lines),Q=Buffer.from(G);let B=0,U=0,z=j;g.submatches.length===0&&g.submatches.push(G.length?{start:0,end:1,match:{text:G[0]}}:{start:0,end:0,match:{text:""}});const M=(0,R.coalesce)(g.submatches.map((x,fe)=>{if(this.c)return null;this.f++,this.f>=this.g&&(this.c=!0);const re=p(x.match),V=Q.slice(B,x.start).toString(),_=t(V),te=_.numLines>0?_.lastLineLength:_.lastLineLength+U,ve=t(re),le=_.numLines+z,ue=ve.numLines+le,q=ve.numLines>0?ve.lastLineLength:ve.lastLineLength+te;return B=x.end,U=q,z=ue,new S.Range(le,te,ue,q)}));return(0,E.createTextSearchResult)(L,G,M,this.j)}o(g,L){const j=p(g.lines),G=g.line_number;return j.replace(/\r?\n$/,"").split(`
    > 124 | `).map((Q,B)=>({text:Q,uri:L,lineNumber:G+B}))}p(g){this.emit("result",g)}}e.RipgrepParser=y;function p(b){return b.bytes?Buffer.from(b.bytes,"base64").toString():b.text}function t(b){const g=/\n/g;let L=0,j=-1,G;for(;G=g.exec(b);)L++,j=G.index;const Q=j>=0?b.length-j-1:b.length;return{numLines:L,lastLineLength:Q}}function o(b,g){const L=["--hidden"];L.push(b.isCaseSensitive?"--case-sensitive":"--ignore-case");const{doubleStarIncludes:j,otherIncludes:G}=(0,P.groupBy)(g.includes,B=>B.startsWith("**")?"doubleStarIncludes":"otherIncludes");if(G&&G.length){const B=new Set;G.forEach(U=>{B.add(U)}),L.push("-g","!*"),B.forEach(U=>{r(U).map(E.anchorGlob).forEach(z=>{L.push("-g",z)})})}j&&j.length&&j.forEach(B=>{L.push("-g",B)}),g.excludes.map(E.anchorGlob).forEach(B=>L.push("-g",`!${B}`)),g.maxFileSize&&L.push("--max-filesize",g.maxFileSize+""),g.useIgnoreFiles?g.useParentIgnoreFiles||L.push("--no-ignore-parent"):L.push("--no-ignore"),g.followSymlinks&&L.push("--follow"),g.encoding&&g.encoding!=="utf8"&&L.push("--encoding",g.encoding),b.pattern==="--"&&(b.isRegExp=!0,b.pattern="\\-\\-"),b.isMultiline&&!b.isRegExp&&(b.pattern=(0,v.escapeRegExpCharacters)(b.pattern),b.isRegExp=!0),g.usePCRE2&&L.push("--pcre2"),L.push("--crlf"),b.isRegExp&&(b.pattern=c(b.pattern),L.push("--engine","auto"));let Q;if(b.isWordMatch){const U=(0,v.createRegExp)(b.pattern,!!b.isRegExp,{wholeWord:b.isWordMatch}).source.replace(/\\\//g,"/");L.push("--regexp",U)}else if(b.isRegExp){let B=f(b.pattern);B=i(B),L.push("--regexp",B)}else Q=b.pattern,L.push("--fixed-strings");return L.push("--no-config"),g.useGlobalIgnoreFiles||L.push("--no-ignore-global"),L.push("--json"),b.isMultiline&&L.push("--multiline"),g.beforeContext&&L.push("--before-context",g.beforeContext+""),g.afterContext&&L.push("--after-context",g.afterContext+""),L.push("--"),Q&&L.push(Q),L.push("."),L}e.getRgArgs=o;function r(b){return u(b).flatMap(L=>{const j=(0,T.splitGlobAware)(L,"/");return j.map((G,Q)=>j.slice(0,Q+1).join("/"))})}function c(b){const g=/((?:[^\\]|^)(?:\\\\)*)\\u([a-z0-9]{4})/gi;for(;b.match(g);)b=b.replace(g,"$1\\x{$2}");const L=/((?:[^\\]|^)(?:\\\\)*)\\u\{([a-z0-9]{4})\}/gi;for(;b.match(L);)b=b.replace(L,"$1\\x{$2}");return b}e.unicodeEscapesToPCRE2=c;const m=b=>b.type==="Assertion"&&b.kind==="lookbehind";function f(b){let g;try{g=new C.RegExpParser().parsePattern(b)}catch{return b}let L="",j=0;const G=(U,z,M)=>{L+=b.slice(j,U)+M,j=z},Q=[];return new C.RegExpVisitor({onCharacterEnter(U){if(U.raw!=="\\n")return;const z=Q[0];if(!z)G(U.start,U.end,"\\r?\\n");else if(!Q.some(m))if(z.type==="CharacterClass")if(z.negate){const M=b.slice(z.start+2,U.start)+b.slice(U.end,z.end-1);z.parent?.type==="Quantifier"?G(z.start,z.end,M?`[^${M}]`:"."):G(z.start,z.end,"(?!\\r?\\n"+(M?`|[${M}]`:"")+")")}else{const M=b.slice(z.start+1,U.start)+b.slice(U.end,z.end-1);G(z.start,z.end,M===""?"\\r?\\n":`(?:[${M}]|\\r?\\n)`)}else z.type==="Quantifier"&&G(U.start,U.end,"(?:\\r?\\n)")},onQuantifierEnter(U){Q.unshift(U)},onQuantifierLeave(){Q.shift()},onCharacterClassRangeEnter(U){Q.unshift(U)},onCharacterClassRangeLeave(){Q.shift()},onCharacterClassEnter(U){Q.unshift(U)},onCharacterClassLeave(){Q.shift()},onAssertionEnter(U){m(U)&&Q.push(U)},onAssertionLeave(U){Q[0]===U&&Q.shift()}}).visit(g),L+=b.slice(j),L}e.fixRegexNewline=f;function i(b){return b.replace(/\n/g,"\\r?\\n")}e.fixNewline=i;function s(b){let g=!1,L=!1,j="",G="";for(let Q=0;Q<b.length;Q++)…                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       ^
      125 |
      126 | //# sourceMappingURL=https://ticino.blob.core.windows.net/sourcemaps/704ed70d4fd1c6bd6342c436f1ede30d1cff4710/core/vs/workbench/api/node/extensionHostProcess.js.map
      127 |

      at m._load (../../../AppData/Local/Programs/Microsoft VS Code/resources/app/out/vs/workbench/api/node/extensionHostProcess.js:124:14199)
      at h._load (../../../AppData/Local/Programs/Microsoft VS Code/resources/app/out/vs/workbench/api/node/extensionHostProcess.js:119:11871)
      at I._load (../../../AppData/Local/Programs/Microsoft VS Code/resources/app/out/vs/workbench/api/node/extensionHostProcess.js:119:11264)
      at Object.get (../../../AppData/Local/Programs/Microsoft VS Code/resources/app/out/bootstrap-amd.js:1:114)
      	at Array.forEach (<anonymous>)
…
extensionHostProcess.js:102

Additional context

Works fine on Jest 27, downgrading is an effective workaround

Environment

System:
    OS: Windows 10 10.0.23440
    CPU: (8) x64 AMD Ryzen 7 4700U with Radeon Graphics
  Binaries:
    Node: 18.15.0 - ~\AppData\Local\pnpm\node.EXE
    Yarn: 1.22.19 - ~\AppData\Local\pnpm\yarn.CMD
    npm: 9.5.0 - ~\AppData\Local\pnpm\npm.CMD
  npmPackages:
    jest: ^28.0.0 => 28.1.3
@mrazauskas
Copy link
Contributor

Could you try swapping two lines in the environment file:

- const NodeEnvironment = require("jest-environment-node");
- const vscode = require("vscode");

+ const vscode = require("vscode");
+ const NodeEnvironment = require("jest-environment-node");

It might be that you are hitting #14086

@JustinGrote
Copy link
Author

JustinGrote commented Apr 22, 2023

@mrazauskas thanks for the response!

No dice, same error in Jest 29. In Jest 27, swapping those two lines prevents the vscode global from being seen to the test.

The main issue is that the vscode global can't be seen with Jest when running inside of the vscode-test spawned instance, hence the workaround that uses a custom test environment to bring in the global with the modulenamemapper. If there's a better way I should be going about this that might avoid the problem, let me know.

@JustinGrote
Copy link
Author

@mrazauskas upon further investigation, it seems to still break on Jest 29 upgrade even if I remove the node environment config completely.

jest.config.js

const path = require("path");

// see https://github.com/microsoft/vscode-test/issues/37#issuecomment-700167820
const rootDir = path.join(__dirname, "dist")

module.exports = {
	rootDir,
	moduleFileExtensions: ["js"],
  testMatch: ["<rootDir>/src/log.test.js"],
  // testEnvironment: path.resolve(rootDir, "../test", "vscode-environment.js"), // Required for the test to see the vscode global
  // moduleNameMapper: {
  //   vscode: path.resolve(rootDir, "../test", "vscode.js"), // Maps to the testEnvironment specified above
  // },
	verbose: true
};

Downgrading to 27 and it "works", albeit the test fails because it cannot find the vscode global without the environment.

Looks like some kind of conflict with the bootstrap-amd that the extensionHostProcess uses to start an extension module and Jest?

@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label May 22, 2023
@KevinEady
Copy link

I randomly decided to update some of my packages today and ran into this issue as well.

@github-actions github-actions bot removed the Stale label May 26, 2023
@lfpvillegas
Copy link

I came up with the same problem. The temporal workaround was to downgrade to Jest 27.5.1 version as @JustinGrote suggested.
But eventually we would need to update to the most recent version.

@rbuckton
Copy link
Contributor

rbuckton commented Jun 8, 2023

Per microsoft/vscode#175548 (comment), the exception is thrown when trying to access _isMockFunction on a Proxy that throws in its get hook. I tested a simple fix for this locally, which is to change this:

if (
((typeof globalMock === 'object' && globalMock !== null) ||
typeof globalMock === 'function') &&
globalMock._isMockFunction === true
) {
globalMock.mockClear();
}

to this:

if (
  ((typeof globalMock === 'object' && globalMock !== null) ||
    typeof globalMock === 'function') &&
  "_isMockFunction" in globalMock && globalMock._isMockFunction === true
) {
  globalMock.mockClear();
}

Where the property access on globalMock is guarded with an in test.

@SimenB
Copy link
Member

SimenB commented Jul 4, 2023

@github-actions
Copy link

github-actions bot commented Aug 4, 2023

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 4, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants