2

I'm trying to mock the @salesforce/community/basePath scoped module with different values for each jest test.

I've mocked it globally :

jest.mock(
    "@salesforce/i18n/lang",
     () => {
         return {
             default: { code: "fr", label: "FR" },
         };
     },
{ virtual: true }
);

This works great as I'm able to see my component use the label from the lang property.

Is it possible to mock this scoped module with a different value? I tried inserting it within my describe block like the following :

//I've declared the above snippet outside of the describe block

describe("Component", () => {
    it("change label", ... {
      jest.mock(
          "@salesforce/i18n/lang",
           () => {
               return {
                   default: { code: "jp", label: "JA" },
               };
           },
     { virtual: true }
     );
  }
}

Why is jest picking up the mock I created globally instead of the one that is within the scope of the test?

1 Answer 1

0

Why is jest picking up the mock I created globally instead of the one that is within the scope of the test?

In pure jest terms, I would expect the behavior you noted based on the code you shared. There's this large discussion on a closed jest issue that has some good information

So jest.mock is being hoisted to the function scope, that's why it won't work with requires (and definitely not imports which are hoisted to module scope) if you call it inside a function other than describe (which is treated specially by Jasmine). Your jest.mock call will be hoisted to the top of that very function (not the module), that's why it won't work the way you expect.

You'll notice the key consideration is the scope and the fact that jest.mock() is hoisted - this is covered in Jest Mocking:

Jest will automatically hoist jest.mock calls to the top of the module (before any imports)

This is how your global jest.mock(), even though being defined after the import, is able to provide the mocked value when the module is imported. Along with that, it also explains why, your test-specific jest.mock(), has no impact - it would be set after the global mock/import has occurred as it isn't within the module scope along with the import.

This is why, in Jest documentation, there's mention of needing to mock modules globally

Note: In order to mock properly, Jest needs jest.mock('moduleName') to be in the same scope as the require/import statement.

You'll notice in that above threads, there are discussions/ways to achieve different values for mocked modules (beforeEach, require(), jest.resetModules) - unfortunately the key consideration with your use case is you're dealing with a salesforce schema scoped import that returns a value.

Jest Test Patterns and Mock Dependencies has a section for @salesforce scoped imports where it mentions the following (in the context of @salesforce/label):

In Jest tests, we use a jest-transformer to convert the @salesforce/label import statement into a variable declaration

The example they use is custom labels, but @salesforce/i18n/lang also uses a jest-transformer that utilizes the same method (stringScopedImportTransform) to do the same as you can see under i18n-scoped-import.js. The transformer returns a value - the default being en even if you don't import/mock in your jest test. A comment in the method shows the following

This approach gives these special imports a default value to ease testing components with imports, but allows test authors to call jest.mock() to provide their own value.

However, this behavior seems to be the blocker for you as it's done globally and it's transformed by default if you don't. Which means I don't believe there is a way to mock a different value for these special imports within individuals tests in a LWC jest.

To accomplish what you want, you could still create multiple jest test files

  • lwc_FR.test.js
  • lwc_JA.test.js
  • ...

Where you change this value in the global jest.mock to test different languages - just make sure to provide a similar mock as to what is actually returned

jest.mock(
    "@salesforce/i18n/lang",
     () => {
         return {
            "fr"
         };
     },
     { virtual: true }
);

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .