microsoft-authentication-library-for-js
microsoft-authentication-library-for-js copied to clipboard
msal-react: only publishing as ESM breaks jest tests
Core Library
MSAL.js (@azure/msal-browser)
Core Library Version
3.1.0
Wrapper Library
MSAL React (@azure/msal-react)
Wrapper Library Version
2.0.3
Public or Confidential Client?
Public
Description
The latest major release of msal-react is only published as ESM. Currently jest is not able to test code that contains ESM dependencies. Before msal-react V2 we tested our components together with msal-react and only mocked some functions of it. Now with msal-react V2 we have to mock the complete library as jest is unable to load any code from it.
I can see that you are still building other msal libraries as commonjs+ESM (e.g. msal-browser) could you also add a commonjs build to msal-react so it continous to work with jest.
Thank you!
Error Message
No response
Msal Logs
No response
MSAL Configuration
{}
Relevant Code Snippets
-
Reproduction Steps
Expected Behavior
Identity Provider
Azure AD / MSA
Browsers Affected (Select all that apply)
None (Server)
Regression
msal-react 1.5.11
Source
External (Customer)
it would be nice to have such a change also announced in the release notes. e.g. here https://github.com/AzureAD/microsoft-authentication-library-for-js/releases/tag/msal-react-v2.0.0
This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @hectormmg please follow up.
This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @hectormmg please follow up.
This issue is affecting my projects as well. Any sense as to if/when it will be possible to resolve it? Thank you!!
Marking as a feature, feel free to open a pull request if you need this resolved sooner rather than later.
Does anyone have insights into why this problem is impacting my UAT pipeline while it doesn't seem to have the same effect on my local machine? Also, is there a possible solution or workaround for this issue within a React project?
"Error [ERR_REQUIRE_ESM]: require() of ES Module /app/node_modules/@azure/msal-react/dist/index.js from /app/dist/server/assets/all.page.9a5890d9.js not supported."
hi, same issue on my project! @jansepke can you suggest me how i can mock the entire msal-react library in order to unblock the tests, please?
I'm using create-react-app and I was able to resolve the Jest issue by adding the following into my package.json:
"jest": {
"transformIgnorePatterns": [
"node_modules/(?!(@azure/msal-react)).*\\.js$"
]
},
If you're not using create-react-app you should be able to add this into your jest.config.js file.
Docs: https://jestjs.io/docs/configuration#transformignorepatterns-arraystring
hi, same issue on my project! @jansepke can you suggest me how i can mock the entire msal-react library in order to unblock the tests, please?
you can mock it like this:
jest.mock('@azure/msal-react', () => ({ useMsal: jest.fn(), }));
EDIT: since I see a few downvotes I would like to explain that my suggestion is not a solution to the issue. I shows how @jansepke and I currently work around it by mocking the entire msal library until the issue is fixed. Keeping this workaround is not desirable.
The fix won't work with Next.js which overwrites jest config.
- compile with es-build to a vendor folder and check it in
npx esbuild @azure/msal-react --bundle --platform=node --sourcemap=inline --outfile=vendor/@azure/msal-react.js
- update your jest config - map
@azure/msal-react
to your newly vendored module
const nextJest = require("next/jest");
const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: "./",
});
// Add any custom config to be passed to Jest
const customJestConfig = {
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
testEnvironment: "jest-environment-jsdom",
moduleNameMapper: {
"@azure/msal-react": "<rootDir>/vendor/@azuremsal-react",
},
};
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig);
- mock
jest.mock('@azure/msal-react', () => ({ useMsal: jest.fn(), }));
I have been trying different things, still i am getting same issue export { MsalConsumer, MsalContext } from './MsalContext.js'; ^^^^^^
SyntaxError: Unexpected token 'export'
7 | RedirectRequest,
8 | } from '@azure/msal-browser'
> 9 | import {MsalProvider} from '@azure/msal-react'
SyntaxError: Unexpected token 'export'
Still an issue for me
- @azure/msal-browser": "^3.7.1"
- @azure/msal-react": "^2.0.10"
workaround: mocking the entire msal-react/msal-browser libraries.
Extremely annoying.
Issue in jest https://github.com/jestjs/jest/issues/14805
Any updates on this? Looks like this issue blames Jest...and Jest blames this library.
...or does anyone have a good workaround?
It’s a jest problem at heart. Moving to ESM is the right move long-term, jest just doesn’t support it well yet. As a workaround you can add it to your transformIgnorePatterns (eg transformIgnorePatterns: [“node_modules(?!(@azure/msal-react))“]) so that it is transformed.
It’s a jest problem at heart. Moving to ESM is the right move long-term, jest just doesn’t support it well yet. As a workaround you can add it to your transformIgnorePatterns (eg transformIgnorePatterns: [“node_modules(?!(@azure/msal-react))“]) so that it is transformed.
Still getting the error with that added. Is there maybe some other jest or tsconfig values that maybe I need to be aware of?
Or maybe you can point me to a repo where this is already setup?
TIA!
I'm using:
-
jest
29.7.0 -
ts-jest
29.1.1 -
typescript
5.0.2 -
@azure/msal-browser
3.13.0 -
@azure/msal-react
2.0.15
In my case I had to do two things:
- Change the
ts-jest
preset (I was usingts-jest
's default) tojs-with-ts
- The preset also requires changes
allowJs
to betrue
in my Typescript settings. - From the docs:
TypeScript and JavaScript files (.ts, .tsx, .js, .jsx) will be transformed by ts-jest to CommonJS syntax. You'll need to set allowJs to true in your tsconfig.json file.
- The preset also requires changes
- Add the
transformIgnorePatterns
entry like in other comments.
// jest.config.ts
const config: Config = {
// ...
preset: 'ts-jest/presets/js-with-ts',
// ...
transformIgnorePatterns: ['<rootDir>/node_modules/(?!@azure/msal-react)'],
// ...
}
// tsconfig.json
{
"compilerOptions": {
// ...
"allowJs": true /* Required by ts-jest/presets/js-with-ts */
},
// ...
}
I used this issue as reference: https://github.com/kulshekhar/ts-jest/issues/970
What ended up working for me was writing the test to mock MSAL. This resolved my isssue
import React from "react";
import { render } from "@testing-library/react";
import App from "./App";
jest.mock("@azure/msal-react", () => ({
MsalAuthenticationTemplate: ({ children }: { children: React.ReactNode }) =>
children,
useMsal: () => ({
instance: {},
inProgress: false,
}),
}));
describe("App", () => {
it("renders without crashing", () => {
render(<App />);
});
});
adding global.crypto = require('crypto');
to the setupTests.js file
, fixes the failing tests
I'm using create-react-app
structure for now and solved the issue for was to include this mock bellow in the setupTests.ts
or jest.setup.ts
. As with create-react-app
we need to create an instance of the PublicClientApplication
in the index.tsx
and after call the initialize function, then we need to mock this instance.
jest.mock('./index', () => {
const mockMsalInstance = {
getActiveAccount: jest.fn(),
acquireTokenSilent: jest.fn(),
initialize: jest.fn().mockResolvedValue(undefined),
getAllAccounts: jest.fn().mockReturnValue([]),
setActiveAccount: jest.fn(),
addEventCallback: jest.fn(),
};
return {
msalInstance: mockMsalInstance,
};
});
I'm using
create-react-app
structure for now and solved the issue for was to include this mock bellow in thesetupTests.ts
orjest.setup.ts
. As withcreate-react-app
we need to create an instance of thePublicClientApplication
in theindex.tsx
and after call the initialize function, then we need to mock this instance.jest.mock('./index', () => { const mockMsalInstance = { getActiveAccount: jest.fn(), acquireTokenSilent: jest.fn(), initialize: jest.fn().mockResolvedValue(undefined), getAllAccounts: jest.fn().mockReturnValue([]), setActiveAccount: jest.fn(), addEventCallback: jest.fn(), }; return { msalInstance: mockMsalInstance, }; });
this work for me like a charm with my package.json config
"jest": {
"transform": {
"^.+\\.(js|jsx|ts|tsx)$": "babel-jest"
},
"moduleNameMapper": {
"^@azure/msal-react": "<rootDir>/node_modules/@azure/msal-react/dist/index.js"
},
"setupFilesAfterEnv": [
"<rootDir>/setupTests.js"
],
}
I'm using
create-react-app
structure for now and solved the issue for was to include this mock bellow in thesetupTests.ts
orjest.setup.ts
. As withcreate-react-app
we need to create an instance of thePublicClientApplication
in theindex.tsx
and after call the initialize function, then we need to mock this instance.jest.mock('./index', () => { const mockMsalInstance = { getActiveAccount: jest.fn(), acquireTokenSilent: jest.fn(), initialize: jest.fn().mockResolvedValue(undefined), getAllAccounts: jest.fn().mockReturnValue([]), setActiveAccount: jest.fn(), addEventCallback: jest.fn(), }; return { msalInstance: mockMsalInstance, }; });
this work for me like a charm with my package.json config
"jest": { "transform": { "^.+\\.(js|jsx|ts|tsx)$": "babel-jest" }, "moduleNameMapper": { "^@azure/msal-react": "<rootDir>/node_modules/@azure/msal-react/dist/index.js" }, "setupFilesAfterEnv": [ "<rootDir>/setupTests.js" ], }
You also probably don't need the line "^@azure/msal-react": "<rootDir>/node_modules/@azure/msal-react/dist/index.js"
This is my configurations, I'm using the fileTransform.js
because I'm using CRA and the identity-obj-proxy
is a package to be installed to be mapping css and less files.:
// jest.config.ts
import type { JestConfigWithTsJest } from 'ts-jest';
import { defaults as tsjPreset } from 'ts-jest/presets';
const config: JestConfigWithTsJest = {
roots: ['<rootDir>/src'],
setupFilesAfterEnv: ['<rootDir>/src/jest.setup.ts'],
testEnvironment: 'jsdom',
transform: {
...tsjPreset.transform,
'^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)':
'<rootDir>/config/jest/fileTransform.js',
},
moduleNameMapper: {
'\\.(css|less)$': 'identity-obj-proxy',
},
};
export default config;