-
Notifications
You must be signed in to change notification settings - Fork 63
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
feat(component-testing): implement mocks #1027
Conversation
c7a350c
to
2c471d4
Compare
package.json
Outdated
@@ -34,6 +33,10 @@ | |||
"type": "git", | |||
"url": "git://github.com/gemini-testing/testplane.git" | |||
}, | |||
"exports": { | |||
".": "./src/index.js", | |||
"./mock": "./src/mock.js" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be used correctly only in component testing, where this module replaced only in browser env in order to correctly mock modules. In node env provide only stubs of mock
and unmock
in order to be able to read tests.
Other options that I've been considering:
- export mock interface from the main file. Can be implemented but in this case in browser env I will not be able to use something else from main module, because it is replaced on browser implementation;
- create another package and replace it in browser env. Can be done, but I don't sure that we need another small package with stub mock, unmock and reexport
vite/spy
Problem with current solution:
- user can import this module -
testplane/mock
in nodejs environment and try to use it (I don't know why and looks like that in integration tests it should not be used). But it will not works correctly becausemock
andunmock
has stubs right now and replaced on browser env. I can fix it by throw error and ignore if user run inbrowser
env. Not implemented right now, but I can do it;
What do you think?
package.json
Outdated
@@ -56,6 +59,7 @@ | |||
"@jspm/core": "2.0.1", | |||
"@types/debug": "4.1.12", | |||
"@types/yallist": "4.0.4", | |||
"@vitest/spy": "2.1.2", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used in order to reexport fn
and spyOn
from testplane/mock
@@ -81,6 +85,7 @@ | |||
"mocha": "10.2.0", | |||
"plugins-loader": "1.3.4", | |||
"png-validator": "1.1.0", | |||
"recast": "0.23.6", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used in browser env in order to correctly modify ast tree to correctly work with mock
src/mock.ts
Outdated
export function mock(_moduleName: string, _factory?: MockFactory): void {} | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
export function unmock(_moduleName: string): void {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here mock and unmock do nothing (stubs). This module replaced in browser env using vite plugin.
throw new Error(`Cannot find mocked module "${mockModuleName}"`); | ||
} | ||
|
||
return b.expressionStatement(b.awaitExpression(mockCallExpression)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here code like:
mock("./utils", () => {...});
Will be modifed to code like:
await mock("./utils", () => {...}, __testplane_import_1__);
Here:
await
is used because browser implementation of mock is async__testplane_import_1__
- the name of original module, which is passed tomock
implementation in filesrc/runner/browser-env/vite/browser-modules/mock.ts
. Used in order to correctly handle factory.
return b.expressionStatement(b.awaitExpression(mockCallExpression)); | ||
}); | ||
|
||
ast.program.body.unshift(...preparedMockCalls); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add new lines of code to the top of the file.
In order to run code with mocking module before code with import method, which is mocked.
It gives ability to user first import method and then mock it.
|
||
// Move import module with mocks to the top of the file | ||
state.mockCalls.push(declaration); | ||
nodePath.prune(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here remove original nodePath. It will be move to the top from state.mockCalls
at the end.
const mockCall = exp.expression as types.namedTypes.CallExpression; | ||
|
||
if (mockCall.arguments.length === 1) { | ||
manualMock.mock((mockCall.arguments[0] as types.namedTypes.StringLiteral).value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use manual mock if user do not specify factory. It means write mock like this - mock("axios")
manualMock.mock((mockCall.arguments[0] as types.namedTypes.StringLiteral).value); | ||
} else { | ||
if ((exp.expression as types.namedTypes.CallExpression).arguments.length) { | ||
registeredMocks.add( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Save mocks with factory which must be executed with original module. It means like this:
mock('./utils', () => ({
handleClick: fn()
}));
2c471d4
to
f503bf5
Compare
package.json
Outdated
".": "./build/src/index.js", | ||
"./mock": "./build/src/mock/index.js" | ||
}, | ||
"typesVersions": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to correctly set paths to types
@@ -0,0 +1,580 @@ | |||
// TODO: use @vitest/spy when migrate to esm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file copied as is from @vitest/spy and used in nodejs environment. In browser environment this file replaced to special file which works only in browser env.
Copied because module is esm and I can't use it correctly in cjs world.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file copied as is from @vitest/spy
Lets leave a comment about it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than exports
in package.json and unreliable isRunInBrowserEnv
check, /ok
Also checking "absModuleUrl" with absolute module name (starting with /) is preferred
@@ -0,0 +1,580 @@ | |||
// TODO: use @vitest/spy when migrate to esm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file copied as is from @vitest/spy
Lets leave a comment about it
f503bf5
to
5ff7426
Compare
5ff7426
to
da513f4
Compare
What is done:
Implement ability to mock modules and use spies in component testing. The same as in jest.
How it works
I'll explain it with a simple example:
In order to correctly mock
handleClick
method fromutils.ts
source code of test file and dependencies which used mocked module modified in runtime. Test file will looks like:What happens:
utils
moved to the top and saves to generated variable -__testplane_import_1__
. It is used in order to correctly mock module (for example if user mock only on method);fn
andmock
also moved to the top in order to callmock
before import all other modules;mock
withawait
and send original module as third argument. Moreover move it to the top. Here usedmock
fromsrc/runner/browser-env/vite/browser-modules/mock.ts
which is async.await mock
will be executed;importWithMock
which gets mocked implementation of module instead of original module.Component file will looks like (after modify in runtime):
What happens:
__testplane_import_2__
;importWithMock
Discuss:
mock
for something more understandable? This file not only exportmock
andunmock
methods but also spied:fn
,spyOn
. Moreover this module works only in browser environment. And can't be called in node env.