测试MSAL React应用程序时嘲笑身份验证

发布于 2025-02-09 15:41:53 字数 2812 浏览 2 评论 0原文

我们的应用程序以标准方式从@azure/msal -react中包裹在MSAL身份验证模板中 - 下面总结了关键代码段。

我们希望使用React测试库(或类似的内容)测试应用程序的单个组件。当然,当诸如SampleComponendSundertest之类的React组件应通过测试正确渲染,如下面的简单测试所示,它也必须包裹在MSAL组件中。

是否有适当的方法来嘲笑MSAL身份验证过程?无论如何,要在MSAL中包装正在测试的组件并直接提供测试用户的凭据对正在测试的组件?对有用的文档,博客文章,视频等的任何引用将不胜感激。

一个简单的测试

test('first test', () => {
  const { getByText } = render(<SampleComponentUnderTest />);
  const someText = getByText('A line of text');
  expect(someText).toBeInTheDocument();
});

config>

export const msalConfig: Configuration = {
  auth: {
    clientId: `${process.env.REACT_APP_CLIENT_ID}`,
    authority: `https://login.microsoftonline.com/${process.env.REACT_APP_TENANT_ID}`,
    redirectUri:
      process.env.NODE_ENV === 'development'
        ? 'http://localhost:3000/'
        : process.env.REACT_APP_DEPLOY_URL,
  },
  cache: {
    cacheLocation: 'sessionStorage',
    storeAuthStateInCookie: false,
  },
  system: {
    loggerOptions: {
      loggerCallback: (level, message, containsPii) => {
        if (containsPii) {
          return;
        }
        switch (level) {
          case LogLevel.Error:
            console.error(message);
            return;
          case LogLevel.Info:
            console.info(message);
            return;
          case LogLevel.Verbose:
            console.debug(message);
            return;
          case LogLevel.Warning:
            console.warn(message);
            return;
          default:
            console.error(message);
        }
      },
    },
  },
};

主应用程序组件

const msalInstance = new PublicClientApplication(msalConfig);

<MsalProvider instance={msalInstance}>
  {!isAuthenticated && <UnauthenticatedHomePage />}
  {isAuthenticated && <Protected />}
</MsalProvider>

未经身份验证的组件

const signInClickHandler = (instance: IPublicClientApplication) => {
  instance.loginRedirect(loginRequest).catch((e) => {
    console.log(e);
  });
};

<UnauthenticatedTemplate>
  <Button onClick={() => signInClickHandler(instance)}>Sign in</Button>
</UnauthenticatedTemplate>

受保护的组件

<MsalAuthenticationTemplate
  interactionType={InteractionType.Redirect}
  errorComponent={ErrorComponent}
  loadingComponent={LoadingComponent}
>
    <SampleComponentUnderTest />
</MsalAuthenticationTemplate>

Our app is wrapped in the MSAL Authentication Template from @azure/msal-react in a standard way - key code segments are summarized below.

We would like to test app's individual components using react testing library (or something similar). Of course, when a React component such as SampleComponentUnderTest is to be properly rendered by a test as is shown in the simple test below, it must be wrapped in an MSAL component as well.

Is there a proper way to mock the MSAL authentication process for such purposes? Anyway to wrap a component under test in MSAL and directly provide test user's credentials to this component under test? Any references to useful documentation, blog posts, video, etc. to point us in the right direction would be greatly appreciated.

A Simple test

test('first test', () => {
  const { getByText } = render(<SampleComponentUnderTest />);
  const someText = getByText('A line of text');
  expect(someText).toBeInTheDocument();
});

Config

export const msalConfig: Configuration = {
  auth: {
    clientId: `${process.env.REACT_APP_CLIENT_ID}`,
    authority: `https://login.microsoftonline.com/${process.env.REACT_APP_TENANT_ID}`,
    redirectUri:
      process.env.NODE_ENV === 'development'
        ? 'http://localhost:3000/'
        : process.env.REACT_APP_DEPLOY_URL,
  },
  cache: {
    cacheLocation: 'sessionStorage',
    storeAuthStateInCookie: false,
  },
  system: {
    loggerOptions: {
      loggerCallback: (level, message, containsPii) => {
        if (containsPii) {
          return;
        }
        switch (level) {
          case LogLevel.Error:
            console.error(message);
            return;
          case LogLevel.Info:
            console.info(message);
            return;
          case LogLevel.Verbose:
            console.debug(message);
            return;
          case LogLevel.Warning:
            console.warn(message);
            return;
          default:
            console.error(message);
        }
      },
    },
  },
};

Main app component

const msalInstance = new PublicClientApplication(msalConfig);

<MsalProvider instance={msalInstance}>
  {!isAuthenticated && <UnauthenticatedHomePage />}
  {isAuthenticated && <Protected />}
</MsalProvider>

Unauthenticated component

const signInClickHandler = (instance: IPublicClientApplication) => {
  instance.loginRedirect(loginRequest).catch((e) => {
    console.log(e);
  });
};

<UnauthenticatedTemplate>
  <Button onClick={() => signInClickHandler(instance)}>Sign in</Button>
</UnauthenticatedTemplate>

Protected component

<MsalAuthenticationTemplate
  interactionType={InteractionType.Redirect}
  errorComponent={ErrorComponent}
  loadingComponent={LoadingComponent}
>
    <SampleComponentUnderTest />
</MsalAuthenticationTemplate>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

孤蝉 2025-02-16 15:41:53

对于MSAL反应下的组件测试,我遇到了同样的问题。
我花了几天时间才弄清楚如何实现正确的验证模拟。
这就是为什么我在这里创建了一个软件包的原因,它封装了所有样板代码: https:https:https:https:https: //github.com/mimetis/mmetis/msal-react-tester

基本上,您可以执行多个方案(用户已经记录,未记录用户,用户必须登录,等等...)在任何情况下,都不必配置任何东西,当然也无需达到Azure AD:

describe('Home page', () => {

  let msalTester: MsalReactTester;
  beforeEach(() => {
    // new instance of msal tester for each test
    msalTester = new MsalReactTester();

    // spy all required msal things
    msalTester.spyMsal();
  });

  afterEach(() => {
    msalTester.resetSpyMsal();
  });

  test('Home page render correctly when user is logged in', async () => {

    msalTester.isLogged();

    render(
      <MsalProvider instance={msalTester.client}>
        <MemoryRouter>
          <Layout>
            <HomePage />
          </Layout>
        </MemoryRouter>
      </MsalProvider>,
    );

    await msalTester.waitForRedirect();

    let allLoggedInButtons = await screen.findAllByRole('button', { name: `${msalTester.activeAccount.name}` });
    expect(allLoggedInButtons).toHaveLength(2);
  });

  test('Home page render correctly when user logs in using redirect', async () => {

    msalTester.isNotLogged();
    render(
      <MsalProvider instance={msalTester.client}>
        <MemoryRouter>
          <Layout>
            <HomePage />
          </Layout>
        </MemoryRouter>
      </MsalProvider>,
    );

    await msalTester.waitForRedirect();

    let signin = screen.getByRole('button', { name: 'Sign In - Redirect' });
    userEvent.click(signin);

    await msalTester.waitForLogin();

    let allLoggedInButtons = await screen.findAllByRole('button', { name: `${msalTester.activeAccount.name}` });
    expect(allLoggedInButtons).toHaveLength(2);
  });


I had the same issue as you regarding component's test under msal-react.
It took me a couple of days to figure out how to implement a correct auth mock.
That's why I've created a package you will find here, that encapsulates all the boilerplate code : https://github.com/Mimetis/msal-react-tester

Basically, you can do multiple scenaris (user is already logged, user is not logged, user must log in etc ...) in a couple of lines, without having to configure anything and of course without having to reach Azure AD in any cases:

describe('Home page', () => {

  let msalTester: MsalReactTester;
  beforeEach(() => {
    // new instance of msal tester for each test
    msalTester = new MsalReactTester();

    // spy all required msal things
    msalTester.spyMsal();
  });

  afterEach(() => {
    msalTester.resetSpyMsal();
  });

  test('Home page render correctly when user is logged in', async () => {

    msalTester.isLogged();

    render(
      <MsalProvider instance={msalTester.client}>
        <MemoryRouter>
          <Layout>
            <HomePage />
          </Layout>
        </MemoryRouter>
      </MsalProvider>,
    );

    await msalTester.waitForRedirect();

    let allLoggedInButtons = await screen.findAllByRole('button', { name: `${msalTester.activeAccount.name}` });
    expect(allLoggedInButtons).toHaveLength(2);
  });

  test('Home page render correctly when user logs in using redirect', async () => {

    msalTester.isNotLogged();
    render(
      <MsalProvider instance={msalTester.client}>
        <MemoryRouter>
          <Layout>
            <HomePage />
          </Layout>
        </MemoryRouter>
      </MsalProvider>,
    );

    await msalTester.waitForRedirect();

    let signin = screen.getByRole('button', { name: 'Sign In - Redirect' });
    userEvent.click(signin);

    await msalTester.waitForLogin();

    let allLoggedInButtons = await screen.findAllByRole('button', { name: `${msalTester.activeAccount.name}` });
    expect(allLoggedInButtons).toHaveLength(2);
  });


违心° 2025-02-16 15:41:53

我也对此感到好奇,但从略有不同的角度来看。我试图避免直接从MSAL中乱扔代码库,以防我们想在某个时候交换身份提供商。这样做的主要方法是将钩子用作抽象层,例如通过该钩子而不是MSAL组件库本身揭示iShauthenticatientical层。

UseAuth Hook将直接使用MSAL包。但是,对于包装器组件,我认为我们只需要创建一个单独的组件,该组件要么返回MSALPROVIDER或您选择的模拟Auth提供商。由于MSALPROVIDER在引擎盖下使用Usecontext,因此我认为您不需要在另一个上下文提供商中包装它。

希望这些想法在您通过做到这一点的方式思考时会有所帮助。知道这不是您问题的直接答案。

I am also curious about this, but from a slightly different perspective. I am trying to avoid littering the code base with components directly from msal in case we want to swap out identity providers at some point. The primary way to do this is to use a hook as an abstraction layer such as exposing isAuthenticated through that hook rather than the msal component library itself.

The useAuth hook would use the MSAL package directly. For the wrapper component however, I think we have to just create a separate component that either returns the MsalProvider OR a mocked auth provider of your choice. Since MsalProvider uses useContext beneath the hood I don't think you need to wrap it in another context provider.

Hope these ideas help while you are thinking through ways to do this. Know this isn't a direct answer to your question.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文