samples-js-react icon indicating copy to clipboard operation
samples-js-react copied to clipboard

TypeError: okta_auth_js_1.default is not a constructor

Open MyShah1 opened this issue 5 years ago • 24 comments

React, redux with Visual studio enterprise, created default react app using Visual studio and followed step by step user guide for react application. While rendering Login Page I encountered this error:

LoginForm.tsx:18 Uncaught TypeError: okta_auth_js_1.default is not a constructor at new LoginForm (LoginForm.tsx:18) at constructClassInstance (react-dom.development.js:14185) at updateClassComponent (react-dom.development.js:18394) at beginWork$1 (react-dom.development.js:20161) at HTMLUnknownElement.callCallback (react-dom.development.js:336) at Object.invokeGuardedCallbackDev (react-dom.development.js:385) at invokeGuardedCallback (react-dom.development.js:440) at beginWork$$1 (react-dom.development.js:25738) at performUnitOfWork (react-dom.development.js:24662) at workLoopSync (react-dom.development.js:24638) at performSyncWorkOnRoot (react-dom.development.js:24237) at react-dom.development.js:12180 at unstable_runWithPriority (scheduler.development.js:818) at runWithPriority$2 (react-dom.development.js:12130) at flushSyncCallbackQueueImpl (react-dom.development.js:12175) at flushSyncCallbackQueue (react-dom.development.js:12163) at discreteUpdates$1 (react-dom.development.js:24390) at discreteUpdates (react-dom.development.js:1442) at dispatchDiscreteEvent (react-dom.development.js:5885)

MyShah1 avatar Aug 05 '20 18:08 MyShah1

Tried few tweaks but no luck. New set of issues/observations.

Error | TS2580 | (TS) Cannot find name 'require'. Do you need to install type definitions for node? Try npm i @types/node. | MyApp, MyApp JavaScript Content Files | C:\Users\MSHAH\source\repos\sandbox\MyApp\ClientApp\src\Login\LoginForm.tsx | 27 | Active

MyShah1 avatar Aug 19 '20 17:08 MyShah1

@MyShah1 Thanks for the report. Could you share here the relevant piece of code from LoginForm.tsx ?

aarongranick-okta avatar Aug 19 '20 17:08 aarongranick-okta

Here's the code snippet, last line thows the error.

   var config = {
          pkce: false,

          // other config
          issuer: props.issuer,
          clientId: "123",
      };
      console.info('issuer' + props.issuer);
     // var OktaAuth = require('@okta/okta-auth-js');
    this.oktaAuth = new OktaAuth(config);

MyShah1 avatar Aug 19 '20 17:08 MyShah1

@MyShah1 Are you using the latest version of okta-auth-js (4.0.0)? It was just released and the import style has changed to named exports. The guides in documentation need to be updated.

Use:

import { OktaAuth } from '@okta/okta-auth-js'

more information is here: https://github.com/okta/okta-auth-js#using-the-npm-module

aarongranick-okta avatar Aug 19 '20 19:08 aarongranick-okta

yes, I have already updated that, that is how I have coded but still I have been getting the error.

import { OktaAuth } from '@okta/okta-auth-js'; import { withOktaAuth } from '@okta/okta-react'; import * as React from 'react';

MyShah1 avatar Aug 20 '20 18:08 MyShah1

The error

LoginForm.tsx:18 Uncaught TypeError: okta_auth_js_1.default is not a constructor

Indicates it is trying to use "default" import. This would happen by using a require() statement with Typescripts "esModuleInterop" option turned on, or by import OktaAuth from '@okta/okta-auth-js'. The way you have shown

import { OktaAuth } from '@okta/okta-auth-js' should not produce this error since it is using a named export.

The other possibility is a version conflict. The internal version of okta-auth-js used by React is at version 3. It's possible if you are using yarn/lerna that the dependency may be hoisted to the top level and the error is being emitted from within the React SDK trying to instantiate [email protected]. Since the React SDK is using [email protected], I would recommend using that same version in your project's package.json outside the React SDK. There are no major feature changes in 4.0.0, the main change is this import style. We will have an update for React SDK soon which uses 4.0.

Alternatively you can access the React SDK's internal auth-js instance, it is available as a property named _oktaAuth

aarongranick-okta avatar Aug 20 '20 18:08 aarongranick-okta

Here's my import statements

import { OktaAuth } from '@okta/okta-auth-js'; import { withOktaAuth } from '@okta/okta-react'; import * as React from 'react';

require does not work as well, I'm willing to share my project and visual studio settings if required to troubleshoot the issue.

MyShah1 avatar Sep 01 '20 13:09 MyShah1

can you please share some more details on how to access _oktaAuth? thanks

MyShah1 avatar Sep 01 '20 13:09 MyShah1

@MyShah1 I notice you imported both okta-auth-js and okta-react in your code, which may cause tokens inconsistency issue if you have autoRenew turned on (it's on by default), since more than one autoRenew process will run together in the background. I would suggest to stay with only @okta/okta-react v3.x (which is depends on auth-js v3.x) for now. We will have auth-js v4.x included in the react SDK in the next major release.

Also wondering is there any specific reason that you want to use those two SDKs together?

shuowu avatar Sep 01 '20 16:09 shuowu

@shuowu I believe both okta-auth-js and okta-react are required by Okta React v4.0.0 now.

I have this in my src/App.js:

import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import { OktaAuth } from '@okta/okta-auth-js';
import { LoginCallback, Security } from '@okta/okta-react';
import Home from './Home';

const oktaAuth = new OktaAuth({
  issuer: 'https://dev-133320.okta.com/oauth2/default',
  clientId: '0oa5nak5fmUbfT3O3357',
  redirectUri: window.location.origin + '/callback'
});

class App extends Component {

  render() {
    return (
      <Router>
        <Security oktaAuth={oktaAuth}>
          <Route path="/" exact={true} component={Home}/>
          <Route path="/callback" component={LoginCallback}/>
        </Security>
      </Router>
    );
  }
}

export default App;

In my src/App.test.ts, I have:

import React from 'react';
import ReactDOM from 'react-dom';
import { act } from 'react-dom/test-utils';
import App from './App';

let container;

beforeEach(() => {
  container = document.createElement('div');
  document.body.appendChild(container);
});

afterEach(() => {
  document.body.removeChild(container);
  container = null;
});

test('renders learn react link', async () => {
  await act(async () => {
    ReactDOM.render(<App/>, container);
  });

  const linkElement = container.querySelector('a');
  expect(linkElement.textContent).toBe('Learn React');
});

When I run npm test, it fails with this error:

 FAIL  src/App.test.js
  ✕ renders learn react link (76 ms)

  ● renders learn react link

    TypeError: Cannot read property 'getAuthState' of undefined

      18 | test('renders learn react link', async () => {
      19 |   await act(async () => {
    > 20 |     ReactDOM.render(<App/>, container);
         |              ^
      21 |   });
      22 | 
      23 |   const linkElement = container.querySelector('a');

      at node_modules/@okta/src/Security.tsx:48:24

Any idea how to fix it?

mraible avatar Nov 21 '20 22:11 mraible

For those seeing this issue in tests, you may need to adjust your config: https://github.com/okta/okta-react/blob/master/jest.config.js#L23

okta-auth-js is an isomorphic module so it supports both a browser and node (server-side) endpoint. Jest tests run on Node and will use the server-side endpoint BY DEFAULT. The server-side module does not support the full interface, notably it does not have a getAuthState method.

aarongranick-okta avatar Jan 11 '21 17:01 aarongranick-okta

Thanks @aarongranick-okta! Adding this snippet to my package.json fixed the tests:

"jest": {
    "moduleNameMapper": {
      "^@okta/okta-auth-js$": "<rootDir>/node_modules/@okta/okta-auth-js/dist/okta-auth-js.umd.js"
    }
 }

dev-dyson avatar Feb 03 '21 06:02 dev-dyson

@MyShah1 were you able to resolve your issue, or can we provide further assistance?

aarongranick-okta avatar Feb 03 '21 17:02 aarongranick-okta

@mraible - I am facing exact issue while running my app locally (dint try tests) - were you able to fix this issue?

niteshchaudhary avatar Feb 24 '21 23:02 niteshchaudhary

@niteshchaudhary This error usually means that the commonJS version of the library is loaded, but the calling code is expecting ES. This can happen easily with esModuleInterop turned on in a typescript app, because it generates some code to make it work both ways.

If you are using ES syntax (recommended), it should be:

import { OktaAuth } from '@okta/okta-auth-js

Note that { OktaAuth } is inside curly braces.

If using commonJS (not recommended unless this is a NodeJS application)

const OktaAuth = require('@okta/okta-auth-js')

aarongranick-okta avatar Feb 24 '21 23:02 aarongranick-okta

@aarongranick-okta - I am using curly braces.

niteshchaudhary avatar Feb 24 '21 23:02 niteshchaudhary

@niteshchaudhary I'm assuming you are using the latest version of okta-auth-js (4.7.x). Are you using a yarn or lerna workspace or otherwise hoisting modules such that it is possible it is using an older version of the module?

What are you using for bundling? typescript, babel, webpack?

Any of these tools should be able to find the correct "browser" or "module" entrypoint, but if the bundler is confused, you may have to point it directly to the module entry:

node_modules/@okta/okta-auth-js/dist/okta-auth-js.umd.js

(hopefully it should not come to this)

aarongranick-okta avatar Feb 25 '21 00:02 aarongranick-okta

@aarongranick-okta - I guess, I got some hold of the issue. when I try to print oktaAuth.authStateManager - it prints "undefined". Hence I get error as TypeError: Cannot read property 'getAuthState' of undefined Can you suggest, how I should define it? I am using webpack and using okta-auth-js=4.7.1 and okta-react=4.1.0

and I changed my oktaConfig as below:

const oktaConfig = {
    clientId: 'abcd,
    issuer: 'https://abcdabcd.okta.com',
    pkce: false,
    transformAuthState: async (oktaAuth, authState) => {
        if (!authState.isAuthenticated) {
            return authState;
        }
    }
};

reference: https://github.com/okta/okta-auth-js#transformauthstate

niteshchaudhary avatar Feb 25 '21 05:02 niteshchaudhary

@niteshchaudhary authStateManager will exist on the browser instance, but would not exist on the node (server) instance. My guess is somehow your bundler is choosing the server entry point instead of browser. There is a module resolution strategy option for both babel and typescript, check if it is forcing commonJS.

aarongranick-okta avatar Feb 26 '21 23:02 aarongranick-okta

Hey guys, adding this worked

"jest": {
    "moduleNameMapper": {
      "^@okta/okta-auth-js$": "<rootDir>/node_modules/@okta/okta-auth-js/dist/okta-auth-js.umd.js"
    }
 }

However, I'm curios to know if this makes a real call out to the issuer url? I'd rather not be making real network requests during tests and just mock the auth object itself instead which is passed into the <Security> component. Any ideas on how to do that?

cmacdonnacha avatar May 20 '21 13:05 cmacdonnacha

Is there any update on this?

I'm trying to test App.tsx file containing following code:

import { CircularProgress } from '@mui/material';
import { OktaAuth, toRelativeUrl } from '@okta/okta-auth-js';
import { LoginCallback, SecureRoute, Security } from '@okta/okta-react';
import {
  Route, useHistory, useLocation, Redirect,
} from 'react-router-dom';
import './App.css';
import Header from './components/header';
import { oktaAuthConfig } from './config/env-constants';
import LandingPage from './modules/landing-page';
import LoginScreen from './modules/login';
import ErrorCallbackComponent from './modules/login-callback-error';

const errorCallbackComponent = (propsParam: any) => <ErrorCallbackComponent error={propsParam.error} />;

const oktaAuth = new OktaAuth({ ...oktaAuthConfig });

function App() {
  const history = useHistory();
  const restoreOriginalUri = async (_oktaAuth: any, originalUri: any) => {
    history.replace(toRelativeUrl(originalUri, window.location.origin));
  };
  const location = useLocation();
  const isUserLoggedIn = () => {
    const localStorageItem = JSON.parse(localStorage.getItem('okta-token-storage') || '{ }');
    return (
      !!(localStorageItem
        && localStorageItem.accessToken
        && localStorageItem.accessToken.accessToken));
  };

  return (
      <Security oktaAuth={oktaAuth} restoreOriginalUri={restoreOriginalUri}>
        <Header />
        <div>
          <Route
            path="/"
            exact
            render={() => { return isUserLoggedIn() ? <Redirect to="/home" /> : <LoginScreen />; }}
          />
          <SecureRoute path="/home" exact component={LandingPage} />
          <Route
            path="/callback"
            render={() => (
              <LoginCallback
                errorComponent={(props) => errorCallbackComponent(props)}
                loadingElement={(
                  <div style={{
                    height: '100vh',
                    width: '100vw',
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    alignContent: 'center',
                    }}
                  >
                    <CircularProgress color="inherit" />
                  </div>
                )}
              />
            )}
          />
        </div>
      </Security>
  );
}
export default App;

And the test is

import { render, waitFor } from '@testing-library/react';
import { MemoryRouter as Router } from 'react-router-dom';

import App from './App';

test('renders app', async () => {
  render(<Router initialEntries={['/home']}><App /></Router>);
  // const linkElement = screen.getByText(/learn react/i);
  // expect(linkElement).toBeInTheDocument();
  await waitFor(() => {
    expect(true).toBeTruthy();
  });
});

I keep getting TypeError: _oktaAuthJs.OktaAuth is not a constructor. I've added following configuration in package.json.

  "jest": {
    "moduleNameMapper": {
      "^@okta/okta-auth-js$": "<rootDir>/node_modules/@okta/okta-auth-js/dist/okta-auth-js.min.js"
    }
  }

However if I change the configuration to point to <rootDir>/node_modules/@okta/okta-auth-js/dist/okta-auth-js.umd.js, I get

 FAIL  src/App.test.tsx (9.356 s)
  × renders app (989 ms)

  ● renders app

    No useable method found in ["native","idb","localstorage"]

       5 |
       6 | test('renders app', async () => {
    >  7 |   render(<Router initialEntries={['/home']}><App /></Router>);
         |   ^
       8 |   // const linkElement = screen.getByText(/learn react/i);
       9 |   // expect(linkElement).toBeInTheDocument();
      10 |   await waitFor(() => {

      at node_modules/@okta/okta-auth-js/dist/webpack:/OktaAuth/node_modules/broadcast-channel/dist/esbrowser/method-chooser.js:42:25

nikhileshncyb avatar Apr 01 '22 06:04 nikhileshncyb

@nikhileshncyb As a workaround, please add in jest setup file:

// broadcast-channel should not detect node environment
// https://github.com/pubkey/broadcast-channel/blob/master/src/util.js#L61
process[Symbol.toStringTag] = 'Process';

denysoblohin-okta avatar Apr 01 '22 16:04 denysoblohin-okta

hey, did anyone manage to run it? I'm using jest, I've already done the mapping of the module and the solution above and still nothing

dayamoraes avatar Feb 22 '23 21:02 dayamoraes

+1, The workaround is not working for me as well.

I am in an non-ejected create-react-app, which requires putting jest setup code in src/setupTests.js (instead of configuring the setupFilesAfterEnv clause). Ostensibly it should be the same effect.

I have the line process[Symbol.toStringTag] = 'Process'; in my setupTests.js file, and confirm it is updating process toString to return "Process". But still seeing:

TypeError: _oktaAuthJs.OktaAuth is not a constructor

I know there have been new releases in both okta-auth-js and broadcast-channel since a year ago, any of those changes effect this?

mraymond77 avatar Apr 25 '23 22:04 mraymond77