Skip to content

Commit

Permalink
Merge pull request #125 from danpoq/signout-cb-comp
Browse files Browse the repository at this point in the history
Add SignoutCallbackComponent
  • Loading branch information
maxmantz authored Oct 13, 2018
2 parents 55cfad1 + a20c521 commit f5f9d00
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 2 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ It uses the oidc-client-js library to manage OpenID Connect functionality.

It contains the following parts:
- *oidcMiddleware*: [redux middleware](http://redux.js.org/docs/advanced/Middleware.html) to automatically check whether or not the current user is signed in & trigger the authentication flow,
- *CallbackComponent*: A react component processing the callback from the OpenID-Connect provider,
- *CallbackComponent*: A react component processing the signin callback from the OpenID-Connect provider,
- *SignoutCallbackComponent*: A react component processing the signout callback from the OpenID-Connect provider,
- *reducers & actions*: reducers and actions to handle OIDC events,
- *helpers*: create helpers to manage the oidc-client-js library

Expand Down
2 changes: 1 addition & 1 deletion docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ This reducer is to be used for configurations with immutable.js.
`ìmport { immutableReducer } from 'redux-oidc';`

### React components
##### CallbackComponent
##### CallbackComponent / SignoutCallbackComponent
The component to handle the token callback from the authentication server.
*Note:* Register this component at the token callback route you've configured with your authentication server.

Expand Down
2 changes: 2 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ declare module 'redux-oidc' {

export class CallbackComponent extends React.Component<CallbackComponentProps> { }

export class SignoutCallbackComponent extends React.Component<CallbackComponentProps> { }

export interface OidcProviderProps<TSTate> {
readonly userManager: UserManager;
readonly store: Store<TSTate>;
Expand Down
42 changes: 42 additions & 0 deletions src/SignoutCallbackComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import PropTypes from 'prop-types';
import React from 'react';

class SignoutCallbackComponent extends React.Component {
static propTypes = {
// the content to render
children: PropTypes.element.isRequired,

// the userManager
userManager: PropTypes.object.isRequired,

// a function invoked when the callback succeeds
successCallback: PropTypes.func.isRequired,

// a function invoked when the callback fails
errorCallback: PropTypes.func
};

componentDidMount() {
this.props.userManager.signoutRedirectCallback()
.then((user) => this.onRedirectSuccess(user))
.catch((error) => this.onRedirectError(error));
}

onRedirectSuccess = (user) => {
this.props.successCallback(user);
};

onRedirectError = (error) => {
if (this.props.errorCallback) {
this.props.errorCallback(error);
} else {
throw new Error(`Error handling logout redirect callback: ${error.message}`);
}
};

render() {
return React.Children.only(this.props.children);
}
}

export default SignoutCallbackComponent;
68 changes: 68 additions & 0 deletions tests/signoutCallbackComponent.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import './setup';
import expect from 'expect';
import SignoutCallbackComponent from '../src/SignoutCallbackComponent';
import sinon from 'sinon';

describe('<SignoutCallbackComponent />', () => {
let userManagerMock;
let signoutRedirectCallbackStub;
let thenStub;
let catchStub;
let removeItemStub;
let props;
let successCallbackStub;
let errorCallbackStub;
let component;

beforeEach(() => {
catchStub = sinon.stub();
thenStub = sinon.stub().returns({ catch: catchStub });
removeItemStub = sinon.stub();
signoutRedirectCallbackStub = sinon.stub().returns({
then: thenStub
});
successCallbackStub = sinon.stub();
errorCallbackStub = sinon.stub();

userManagerMock = {
signoutRedirectCallback: signoutRedirectCallbackStub,
};

props = { successCallback: successCallbackStub, errorCallback: errorCallbackStub, userManager: userManagerMock };


component = new SignoutCallbackComponent(props);
});

it('should call the userManager on componentDidMount', () => {
component.componentDidMount();

expect(signoutRedirectCallbackStub.called).toEqual(true);
expect(thenStub.called).toEqual(true);
expect(catchStub.called).toEqual(true);
});

it('should handle redirect success correctly', () => {
const user = { some: 'user' };
component.onRedirectSuccess(user);

expect(successCallbackStub.calledWith(user)).toEqual(true);
});

it('should call the redirect error callback when provided', () => {
const error = { message: 'error'};

component.onRedirectError(error);

expect(errorCallbackStub.calledWith(error)).toEqual(true);
});

it('should throw an error when no error callback has been provided', () => {
const error = { message: 'error' };

props = { successCallback: successCallbackStub, userManager: userManagerMock };
component = new SignoutCallbackComponent(props);

expect(() => component.onRedirectError(error)).toThrow(/error/);
});
});

0 comments on commit f5f9d00

Please sign in to comment.