Closed nwcm closed 4 months ago
@nolanlawson There's is one thing before we progress.
Currently it will resolve the mock first and then fallback to the implementation. Which is great for all jests generally to avoid tests spanning over components. However, as it is currently when you want to test the actual component. c/componentName
resolves to the mock, so you would need to change it to ../componentName
for the import in the jest file.
This would break everyone's tests if they upgraded!
It doesn't look like we have enough context in the resolve to make a distinction on import from test file vs component file. I'll need to look at the transformer
As for https://github.com/salesforce/lwc-test/pull/260, yes looking to get both merged
However, as it is currently when you want to test the actual component.
c/componentName
resolves to the mock, so you would need to change it to../componentName
for the import in the jest file.
This isn't even possible for parent-child implicit imports – e.g. <c-foo>
in an LWC HTML file will always resolve to c/foo
, not ../c/foo
. You could maybe fix that with moduleNameMapper
, but it would get hairy.
Rather than doing this at the transformer level, I wonder if it would be cleaner to expose a config or something that can be set in the test:
import { setComponentsToMock } from 'somewhere'
beforeEach(() => {
setComponentsToMock(['c/foo', 'c/bar'])
})
afterEach(() => {
setComponentsToMock([])
})
I would expect that any component referenced would use the mock if it is there. Such that tests are shallow and only test the referenced component. So <c-foo>
or import Foo from "c/foo";
in the actual component would resolve to the mock, if it is mocked.
The import c/
vs ../
is only for the import in the test file for createElement()
It seems clean to me without having to have additional config or per test file setups. If there was a way to follow jests requireActual() then you could override the test to use the true implementation. If you have any ideas for this, happy to implement
Some more exploring with Jest and LWC. This may be unnecessary. It's convenient to automatically use any manual mocks created, however, with jest you can use jest.mock('c/foo');
in the test file to apply the manual mock from __mocks__
. However, you would need to call this for each component. Whereas I was seeking a way to automatically use manual mocks.
automock=true
seems to have a different result and not use the manual mocks as I think it should be. That may be something with how LWC and Jest interact
Options I see.
*/lwc/foo/__mocks__/
and manual pointersjest.mock('c/foo')
in each test filejest.mock('c/foo)
in a setupFile configured to run via jest.config setupFiles
"c/foo": "<rootDir>/force-app/main/default/lwc/foo/__mocks__/foo.js"
in moduleNameMapper
in jest.config
All of these require implicit defining per component, which from a management perspective isn't great. Could create a script to generate the setup js but feels hacky. */lwc/foo/__mocks__/
..test.js
(import Foo from ../foo
)
There are quite a few issues with this change, so will abandon it.
I think a setupLwcMocks.js
setup file which is dynamic from a yarn script
from pathlib import Path
JEST_MOCK_SETUP_FILE = "setupLwcMocks.js"
with open(JEST_MOCK_SETUP_FILE, 'w',encoding="utf-8") as file:
for path in Path('force-app/main').rglob('lwc/*/__mocks__/*.js'):
print(path.stem)
file.write(f'jest.mock(\'c/{path.stem}\');\n')
jest.mock('c/foo');
jest.mock('c/bar');
jest.mock('c/cookie');
jest.mock('c/woo');
Thanks for providing so many details! This is helpful for anyone else trying to solve this problem. 💪
Update LWC resolver to attempt to resolve to
**/lwc/componentName/__mocks__/componentName.js
first, then fallback to the actual implementation.This avoids having to set many
moduleNameMapper
items or defining mocks in a separate directory from the components which complicates upkeep.If there was a way to honor
jest.requireActual()
that would be great, but I'm not familiar with how to implement that