0

I have built a React app that is using Auth0 as Authentication. I am trying to implement test suit using Jest to test one of the functions in a component.

I want to test a createProject() function in a React Component Project, just to see if the function would cause any error after execute.

Here is my test code:

import Project from '../components/Projects/index'
import { shallow } from 'enzyme'

describe('Project testing', () => {
    it('createProject should be working', () => {
        const wrapper = shallow(<Project />);
        const instance = wrapper.instance();
        instance.createProject();
        expect(instance.createProject()).toHaveBeenCalled();
    })
})

After I run the test, I received the error message of following snapshot: Error message snapshot

Here is my Auth.js

import auth0 from 'auth0-js'

class Auth {
    constructor() {
        this.auth0 = new auth0.WebAuth({
            // the following three lines MUST be updated
            domain: process.env.REACT_APP_AUTH0_DOMAIN,
            audience: `https://${process.env.REACT_APP_AUTH0_DOMAIN}/userinfo`,
            clientID: process.env.REACT_APP_AUTH0_CLIENT_ID,
            redirectUri: `${process.env.REACT_APP_BASE_URL}/callback`,
            responseType: 'token id_token',
            scope: 'openid email profile',
        })

        this.getProfile = this.getProfile.bind(this)
        this.handleAuthentication = this.handleAuthentication.bind(this)
        this.isAuthenticated = this.isAuthenticated.bind(this)
        this.signIn = this.signIn.bind(this)
        this.signOut = this.signOut.bind(this)
    }

    getProfile() {
        return this.profile
    }

    getIdToken() {
        return this.idToken
    }

    isAuthenticated() {
        return new Date().getTime() < this.expiresAt
    }

    signIn() {
        this.auth0.authorize({}, (err, authResult) => {
            if (err) this.localLogout()
            else {
                this.localLogin(authResult)
                this.accessToken = authResult.accessToken
            }
        })
    }

    handleAuthentication() {
        return new Promise((resolve, reject) => {
            this.auth0.parseHash((err, authResult) => {
                if (err) {
                    alert(err.errorDescription)
                    this.signOut()
                    return reject(err)
                }
                if (!authResult || !authResult.idToken) {
                    return reject(err)
                }
                this.setSession(authResult)
                resolve()
            })
        })
    }

    setSession(authResult) {
        this.idToken = authResult.idToken
        this.profile = authResult.idTokenPayload
        // set the time that the id token will expire at
        this.expiresAt = authResult.idTokenPayload.exp * 1000
    }

    signOut() {
        // clear id token, profile, and expiration
        this.auth0.logout({
            returnTo: process.env.REACT_APP_BASE_URL,
            clientID: process.env.REACT_APP_AUTH0_CLIENT_ID,
        })
    }

    silentAuth() {
        return new Promise((resolve, reject) => {
            this.auth0.checkSession({}, (err, authResult) => {
                if (err) return reject(err)
                this.setSession(authResult)
                resolve()
            })
        })
    }
}

const auth0Client = new Auth()

export default auth0Client

My Auth0 domain, client ID, ..etc are all defined in .env file.

Anyone has any idea how to solve this problem on Jest testing ?

Eric Lee
  • 5
  • 1
  • 2

2 Answers2

1

You'll need to define your custom process.env properties before you start instantiating your components:

beforeAll(() => {
  process.env = Object.assign(process.env, {
    REACT_APP_AUTH0_DOMAIN: 'foo',
    REACT_APP_AUTH0_CLIENT_ID: 'bar',
    REACT_APP_BASE_URL: 'baz'
  });
});

(I'm not sure if REACT_APP_BASE_URL is defined or not out of the box. Try without and if it still breaks, add it.)

Michael Landis
  • 1,074
  • 7
  • 12
  • Thanks for the answer! I tried to add `beforeAll()` and includes all the process.env variables in the Object.assign, but I still got the same error. (I also included the REACT_APP_BASE_URL) – Eric Lee Feb 26 '20 at 01:10
  • Can you console.log() within your test and see the properties being included? – Michael Landis Feb 26 '20 at 01:17
  • I tried `console.log(process.env)`, but see nothing got printed out. I think the error happens on the line I do `import Project from '../components/Projects/index'` – Eric Lee Feb 26 '20 at 01:57
  • Hmm. The screenshot shows the error in the auth0 constructor. Maybe try setting these directly in the test instead of in beforeAll? – Michael Landis Feb 28 '20 at 06:27
  • I tried to put the code inside the test('...') blocks, but it still shows the same error. – Eric Lee Feb 28 '20 at 18:50
  • Ahhh, I see what you mean about the import. Another alternative would be to put the lines in setupTests.js. I believe that loads before the imports. – Michael Landis Feb 29 '20 at 09:15
  • I created a `setupTests.js` under src, and put the above lines inside beforeAll() into the setupTests.js, but it still caused me same error.. Thanks a lot for the help btw ! – Eric Lee Mar 02 '20 at 18:29
  • Hmmm. Maybe the constructor is being called before any other functions in order for the import to be available? You might want to consider exporting a function instead of the constructed aurh0 instance. Then you could lazily instantiate the object in the function, and set the test properties before calling the function, or inject the properties through the function, giving you full control of how they get populated. Other than that, it seems you'd need to modify your webpack config, or wrap Jest in something that lets Node prepopulate your variables. Which sounds terrifying. XD – Michael Landis Mar 04 '20 at 04:01
0

I had the exact same problem. And as Michael said, it was because the environment variables were not defined in our tests. You can resolve the problem by using Jest's setupFiles feature. This list of files get run once immediately before each test to set up the testing environment.

I followed Serhan's answer in this post (https://stackoverflow.com/a/57944454/8286893) because I didn't want to expose our .env file, but you can also define the environmental variables in the setup file itself (no need for dotenv npm package).

You can look at this post for more answers: test process.env with Jest

Wooksauce
  • 1
  • 1