Skip to content

Commit

Permalink
Add loadingComponent prop to LoginCallback component
Browse files Browse the repository at this point in the history
OKTA-404404
<<<Jenkins Check-In of Tested SHA: c8ca121 for [email protected]>>>
Artifact: okta-react
Files changed count: 7
PR Link: "okta#144"
  • Loading branch information
ericlifs authored and eng-prod-CI-bot-okta committed Jul 15, 2021
1 parent 51e3a51 commit 22add65
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 9 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 6.1.0

### Features

- [#67](https://github.com/okta/okta-react/pull/67) Adds `loadingComponent` prop to `LoginCallback` component

# 6.0.1

### Bug Fixes
Expand Down
13 changes: 8 additions & 5 deletions src/LoginCallback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ import * as React from 'react';
import { useOktaAuth, OnAuthResumeFunction } from './OktaContext';
import OktaError from './OktaError';

const LoginCallback: React.FC<{
errorComponent?: React.ComponentType<{ error: Error }>,
onAuthResume?: OnAuthResumeFunction,
}> = ({ errorComponent, onAuthResume }) => {
interface LoginCallbackProps {
errorComponent?: React.ComponentType<{ error: Error }>;
onAuthResume?: OnAuthResumeFunction;
loadingComponent?: React.ReactElement;
}

const LoginCallback: React.FC<LoginCallbackProps> = ({ errorComponent, loadingComponent = null, onAuthResume }) => {
const { oktaAuth, authState } = useOktaAuth();
const [callbackError, setCallbackError] = React.useState(null);

Expand All @@ -43,7 +46,7 @@ const LoginCallback: React.FC<{
return <ErrorReporter error={displayError}/>;
}

return null;
return loadingComponent;
};

export default LoginCallback;
7 changes: 6 additions & 1 deletion test/e2e/harness/e2e/App.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,23 @@ import {
AppPage,
OktaSignInPage,
ProtectedPage,
SessionTokenSignInPage
SessionTokenSignInPage,
LoginCallbackPage
} from './page-objects';

describe('React + Okta App', () => {
let appPage;
let oktaLoginPage;
let protectedPage;
let sessionTokenSignInPage;
let loginCallbackPage;

beforeEach(() => {
appPage = new AppPage();
oktaLoginPage = new OktaSignInPage();
protectedPage = new ProtectedPage();
sessionTokenSignInPage = new SessionTokenSignInPage();
loginCallbackPage = new LoginCallbackPage();
});

describe('implicit flow', () => {
Expand Down Expand Up @@ -95,6 +98,7 @@ describe('React + Okta App', () => {
password: process.env.PASSWORD
});

loginCallbackPage.waitUntilVisible();
protectedPage.waitUntilVisible('?pkce=1&state=bar#baz');
expect(protectedPage.getLogoutButton().isPresent()).toBeTruthy();

Expand Down Expand Up @@ -125,6 +129,7 @@ describe('React + Okta App', () => {
password: process.env.PASSWORD
});

loginCallbackPage.waitUntilVisible();
appPage.waitUntilVisible();
expect(protectedPage.getLogoutButton().isPresent()).toBeTruthy();

Expand Down
1 change: 1 addition & 0 deletions test/e2e/harness/e2e/page-objects.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export { AppPage } from './page-objects/app.po';
export { OktaSignInPage } from './page-objects/okta-signin.po';
export { ProtectedPage } from './page-objects/protected.po';
export { SessionTokenSignInPage } from './page-objects/sessionToken-signin.po';
export { LoginCallbackPage } from './page-objects/login-callback.po';
25 changes: 25 additions & 0 deletions test/e2e/harness/e2e/page-objects/login-callback.po.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*!
* Copyright (c) 2017-Present, Okta, Inc. and/or its affiliates. All rights reserved.
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
*
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and limitations under the License.
*/

import { by, element } from 'protractor';
import { Util } from '../util';

export class LoginCallbackPage {
waitUntilVisible() {
Util.waitElement(this.loadingComponent());
}

loadingComponent() {
return element(by.id('login-callback-loading'));
}

}
12 changes: 10 additions & 2 deletions test/e2e/harness/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,19 @@ const App: React.FC<{
>
<Switch>
<Route path='/login' component={CustomLogin} />
<Route path='/widget-login' render={ (props) => <WidgetLogin {...props} baseUrl={baseUrl} /> }/>
<Route path='/widget-login' render={ (props) =>
<WidgetLogin {...props} baseUrl={baseUrl} />
} />
<Route path='/sessionToken-login' component={SessionTokenLogin} />
<SecureRoute exact path='/protected' component={Protected} />
<Route path='/implicit/callback' component={LoginCallback} />
<Route path='/pkce/callback' render={ (props) => <LoginCallback {...props} onAuthResume={ onAuthResume } /> } />
<Route path='/pkce/callback' render={ (props) =>
<LoginCallback
{...props}
onAuthResume={ onAuthResume }
loadingComponent={ <p id='login-callback-loading'>Loading...</p> }
/>
} />
<Route path='/' component={Home} />
</Switch>
</Security>
Expand Down
54 changes: 53 additions & 1 deletion test/jest/loginCallback.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ describe('<LoginCallback />', () => {
};

const MyErrorComponent = ({ error }) => {
return (<p>Override: {error.has}</p>);
return (<p>Override: {error.has}</p>);
};

const wrapper = mount(
Expand Down Expand Up @@ -175,4 +175,56 @@ describe('<LoginCallback />', () => {
});
});

describe('shows loading', () => {
it('does not render loading by default', () => {
const wrapper = mount(
<Security {...mockProps}>
<LoginCallback />
</Security>
);
expect(wrapper.text()).toBe('');
});

it('custom loading component can be passed to render during loading', () => {
const MyLoadingComponent = (<p>loading...</p>);

const wrapper = mount(
<Security {...mockProps}>
<LoginCallback loadingComponent={MyLoadingComponent}/>
</Security>
);
expect(wrapper.text()).toBe('loading...');
});

it('does not render loading component on error', () => {
authState = {
isAuthenticated: true,
error: new Error('oh drat!')
};
const MyLoadingComponent = (<p>loading...</p>);

const wrapper = mount(
<Security {...mockProps}>
<LoginCallback loadingComponent={MyLoadingComponent}/>
</Security>
);
expect(wrapper.text()).toBe('Error: oh drat!');
});

it('renders loading component if onAuthResume is passed', async () => {
oktaAuth.isInteractionRequired = jest.fn().mockImplementation( () => true );
const resumeFunction = jest.fn();
const MyLoadingComponent = (<p>loading...</p>);
jest.spyOn(React, 'useEffect').mockImplementation(f => f())

const wrapper = mount(
<Security {...mockProps}>
<LoginCallback onAuthResume={resumeFunction} loadingComponent={MyLoadingComponent}/>
</Security>
);
expect(resumeFunction).toHaveBeenCalled();
expect(wrapper.text()).toBe('loading...');
});
});

});

0 comments on commit 22add65

Please sign in to comment.