syncweek-react-aad / react-aad

A React wrapper for Azure AD using the Microsoft Authentication Library (MSAL). The easiest way to integrate AzureAD with your React for authentication.
MIT License
344 stars 94 forks source link

Jest Testing: Test Suite is Failing to Run #210

Closed joeyzia closed 4 years ago

joeyzia commented 4 years ago

Library versions

Node Version

Describe the bug When running npm run test / "test": "react-scripts test --verbose" Jest is not able to run the test suite. Returns with an unclear error message

> $  npm run test
> react-scripts test --verbose
 FAIL  src/components/auth/AuthButton.test.jsx
  ● Test suite failed to run

    Error: No message was provided

Expected behavior Should either fail with a clear error or pass successfully.

To Reproduce Steps to reproduce the behavior:

/src/components/auth/AuthButton.test.jsx

import React from "react";
import { createShallow } from "@material-ui/core/test-utils";
import AuthButton from "./AuthButton";

describe("AuthButton component", () => {
  let shallow, button;

  beforeEach(() => {
    shallow = createShallow();
  });

  it("should work", () => {
    button = shallow(<AuthButton />);
  });
});

/src/components/auth/AuthButton.jsx

import React, { Component } from "react";
import PropTypes from "prop-types";
import { AzureAD, LoginType, AuthenticationState } from "react-aad-msal";

import Button from "@material-ui/core/Button";
import { withStyles } from "@material-ui/core/styles";

import { authProvider } from "common/authProvider";

const styles = theme => ({
  button: {
    margin: theme.spacing()
  },
  input: {
    display: "none"
  }
});

class AuthButton extends Component {
  constructor(props) {
    super(props);
    const options = authProvider.getProviderOptions();
    options.loginType = LoginType.Redirect;
    authProvider.setProviderOptions(options);

    this.interval = null;
    let redirectEnabled = sessionStorage.getItem("redirectEnabled") || false;
    this.state = {
      counter: 5,
      redirectEnabled: redirectEnabled
    };
  }

  render() {
    let { classes } = this.props;
    return (
      <AzureAD provider={authProvider}>
        {({ login, logout, authenticationState }) => {
          const isInProgress =
            authenticationState === AuthenticationState.InProgress;
          const isAuthenticated =
            authenticationState === AuthenticationState.Authenticated;
          const isUnauthenticated =
            authenticationState === AuthenticationState.Unauthenticated;

          if (isAuthenticated) {
            return (
              <Button
                onClick={logout}
                variant="contained"
                color="secondary"
                className={classes.button}
              >
                Sign Out
              </Button>
            );
          } else if (isUnauthenticated || isInProgress) {
            return (
              <Button
                onClick={login}
                variant="contained"
                color="primary"
                className={classes.button}
              >
                Sign In
              </Button>
            );
          }
        }}
      </AzureAD>
    );
  }
}

AuthButton.propTypes = {
  classes: PropTypes.object.isRequired
};

export default withStyles(styles)(AuthButton);

/src/setupTest.js

import Enzyme, { configure, shallow, mount, render } from "enzyme";
import Adapter from "enzyme-adapter-react-16";

configure({ adapter: new Adapter() });

const localStorageMock = {
  getItem: jest.fn(),
  setItem: jest.fn(),
  removeItem: jest.fn(),
  clear: jest.fn()
};

export { shallow, mount, render };
export default Enzyme;

global.localStorage = localStorageMock;

/package.json

...
  "jest": {
    "collectCoverageFrom": [
      "src/**/*.{js,jsx}",
      "!<rootDir>/node_modules/",
      "!<rootDir>/vendor/**"
    ],
    "coverageThreshold": {
      "global": {
        "branches": 0,
        "functions": 0,
        "lines": 0,
        "statements": 0
      }
    },
    "coverageReporters": [
      "text"
    ],
    "coveragePathIgnorePatterns": [
      "src/index.js",
      "src/serviceWorker.js"
    ]
  },
...
nairmanu commented 4 years ago

try addingimport "regenerator-runtime"; in your setupTests.js

joeyzia commented 4 years ago

src/setupTests.js

import Enzyme, { configure, shallow, mount, render } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import "regenerator-runtime";

configure({ adapter: new Adapter() });

const localStorageMock = {
  getItem: jest.fn(),
  setItem: jest.fn(),
  removeItem: jest.fn(),
  clear: jest.fn(),
};

export { shallow, mount, render };
export default Enzyme;

Does absolutely nothing.

Output:

> react-scripts test --verbose

 FAIL  src/components/auth/AuthButton.test.jsx
  ● Test suite failed to run

    Error: No message was provided
joeyzia commented 4 years ago

Upon researching, realizing this is a silly error. You should be mocking the react-aad-msal library for your tests and "intercepting" the library.

ivan7707 commented 4 years ago

@joeyzia Hi, can you please expand on how you finally were able to create the tests (and mock the library) to test the authenticated and unauthenticated state?

i.e. can you show how you accomplished this:

You should be mocking the react-aad-msal library for your tests and "intercepting" the library.

Thanks