Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to test Auth0 component using jest | enzyme #2325

Open
jahnaviv opened this issue Feb 4, 2020 · 5 comments
Open

How to test Auth0 component using jest | enzyme #2325

jahnaviv opened this issue Feb 4, 2020 · 5 comments

Comments

@jahnaviv
Copy link

jahnaviv commented Feb 4, 2020

No description provided.

@jahnaviv jahnaviv changed the title How to test Auth0 component How to test Auth0 component using jest | enzyme Feb 4, 2020
@ljharb
Copy link
Member

ljharb commented Feb 4, 2020

You'll have to elaborate; what is Auth0? What is an Auth0 component?

@jahnaviv
Copy link
Author

jahnaviv commented Feb 4, 2020

auth0 component:

import React from 'react';
import Auth0Lock from 'auth0-lock';
import jwtDecode from 'jwt-decode';
import PropTypes from 'prop-types';
import { setUser } from 'Utils/googleAnalytics';
import Storage from 'Utils/storage';
import './Auth0.scss';

const propTypes = {
  onLogout: PropTypes.oneOfType([
    PropTypes.func,
    PropTypes.oneOf([undefined]),
  ]),
  children: PropTypes.oneOfType([
    PropTypes.func,
    PropTypes.string,
    PropTypes.element,
    PropTypes.arrayOf(PropTypes.element),
    PropTypes.arrayOf(PropTypes.element),
    PropTypes.oneOf([undefined, false, null]),
  ]),
};

const defaultProps = {
  children: undefined,
  onLogout: undefined,
};

class Auth0 extends React.Component {
  constructor(props) {
    super(props);

    this.auth = new Auth0Lock(process.env.AUTH0_CLIENT_ID, process.env.AUTH0_DOMAIN, {
      configurationBaseUrl: 'https://cdn.auth0.com',
      auth: {
        responseType: 'token id_token',
        redirectUrl: `${window.location.href}`,
        redirect: false,
        audience: `${process.env.AUTH0_AUDIENCE}`,
        params: {
          scope: 'openid profile email roles read:brands read:users read:analytics',
        },
      },
      theme: {
        logo: 'https://s3.amazonaws.com/insights.clearstream.tv/assets/EMX+Logo+-+primary-red.png',
        primaryColor: '#c72127',
      },
      languageDictionary: {
        title: 'EMX Digital',
      },
      closable: false,
    });

    this.auth.on('authenticated', this.onAuthenticated);
    this.auth.hasRoles = this.hasRoles;
    this.auth.logout = this.logout;
    this.auth.isAuthenticated = this.isAuthenticated;

    this.state = { authenticated: false };
  }

  componentWillMount = () => {
    this.setState({ authenticated: this.isAuthenticated() });
  };

  onAuthenticated = (authResult) => {
    this.auth.hide();

    const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());

    Storage.set('access_token', authResult.accessToken);
    Storage.set('id_token', authResult.idToken);
    Storage.set('expires_at', expiresAt);
    Storage.set('user_info', authResult.idTokenPayload.name);

    setUser(authResult.idTokenPayload.name.replace('@', '.'));

    this.auth.getUserInfo(authResult.accessToken, (error, profile) => {
      if (error) return console.log(error);
      Storage.set('profile', JSON.stringify(profile));
      return this.setState({ authenticated: true });
    });
  };

  isAuthenticated = () => {
    let accessToken = Storage.get('access_token');
    accessToken = accessToken ? jwtDecode(accessToken) : {};

    let expiresAt = 0;
    if (accessToken) {
      expiresAt = accessToken.exp * 1000 || 0;
    }
    const now = new Date().getTime();
    const diff = expiresAt - now;
    if (diff > 0) {
      if (this.timer) {
        clearTimeout(this.timer);
        this.timer = undefined;
      }
      this.timer = setTimeout(() => this.logout(), diff);
    }

    const authenticated = now < expiresAt;

    if (authenticated) this.auth.hide();
    else this.auth.show();

    return authenticated;
  };

  hasRoles = (...args) => {
    const roles = jwtDecode(Storage.get('access_token'))['https://emxanswers.com/roles'] || [];
    for (let i = 0; i < roles.length; i += 1) {
      if (args.indexOf(roles[i]) > -1) return true;
    }
    return false;
  };

  logout = () => {
    const {
      onLogout,
    } = this.props;
    // Clear Access Token and ID Token from local storage
    Storage.remove('access_token');
    Storage.remove('id_token');
    Storage.remove('expires_at');
    Storage.remove('user_info');
    Storage.remove('profile');
    this.setState({ authenticated: false });
    this.auth.show();
    return onLogout && onLogout();
  };

  render = () => {
    const {
      authenticated,
    } = this.state;
    const {
      children,
    } = this.props;
    this.isAuthenticated();
    return typeof children === 'function'
      ? children({ auth: this.auth, isAuthenticated: authenticated })
      : children;
  };
}

Auth0.propTypes = propTypes;
Auth0.defaultProps = defaultProps;

export default Auth0;

@ljharb
Copy link
Member

ljharb commented Feb 4, 2020

First, don't put functions in class fields.

Second, make propType warnings fail your tests by mocking console.error/console.warn.

Third, write as many tests as you can using shallow, asserting on what's rendered based on what props are passed to Auth0.

At that point, you should have very little uncovered; you can write a mount test for that.

@jahnaviv
Copy link
Author

jahnaviv commented Feb 4, 2020

test('Should call hasRoles()', () => {
    wrapper.instance().onAuthenticated(authResult);
    wrapper.instance().hasRoles('RTA User');
    
  });

For this test-case its gives me error Invalid token specifiedInvalidTokenError and its pointed to import jwtDecode from 'jwt-decode'; line

@ljharb
Copy link
Member

ljharb commented Feb 4, 2020

no, not like that.

I'm suggesting starting by mocking nothing, and passing different props in, and shallow-rendering it, and asserting on what it renders.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants