browser-sdk
Version:
javascript SDK for the lightelligence-platform
356 lines (297 loc) • 10.7 kB
JavaScript
import * as OIDC from 'oidc-client';
import XHRMock from 'xhr-mock';
import BrowserSDK from '../src/index';
import fixtureOpenIDConfiguration from './fixtures/openid-configuration';
const mockUser = (tenant, data) =>
new OIDC.User({
id_token: `${tenant}_id_token`,
session_state: `${tenant}_session_state`,
token_type: `${tenant}_token_type`,
scope: `${tenant}_scope`,
state: `${tenant}_state`,
access_token: `${tenant}_access_token`,
refresh_token: `${tenant}_refresh_token`,
expires_at: Math.floor(Date.now() / 1000) + 60 * 60,
profile: { tenant },
...data,
});
describe('user manager', () => {
beforeEach(() => {
XHRMock.setup();
XHRMock.get(
'https://id.dev.olt-dev.io/v1/id/auth/realms/IoT/.well-known/openid-configuration',
(req, res) =>
res
.status(200)
.body(JSON.stringify(fixtureOpenIDConfiguration))
.header('Content-Type', 'application/json')
);
});
it('should not allow change tenant without refresh token', () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
sdk.manager.getUser = jest
.fn()
.mockResolvedValue(mockUser('foo', { refresh_token: null }));
return sdk.changeTenant('bar').catch(error => {
expect(error.message).toEqual('changeTenant: No refresh token');
});
});
it('should not allow change tenant without user profile loaded', () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
sdk.manager.getUser = jest
.fn()
.mockResolvedValue(mockUser('foo', { profile: null }));
return sdk.changeTenant('bar').catch(error => {
expect(error.message).toEqual(
'changeTenant: No profile loaded for the user'
);
});
});
it('should call tokenClient.exchangeRefreshToken', () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
const tokenClient = sdk.manager._tokenClient; // eslint-disable-line
sdk.manager.getUser = jest.fn().mockResolvedValue(mockUser('foo'));
tokenClient.exchangeRefreshToken = jest.fn().mockResolvedValue({
access_token: 'bar_access_token',
refresh_token: 'bar_refresh_token',
expires_in: Math.floor(Date.now() / 1000) + 60 * 120, // two hours
});
return sdk.changeTenant('bar').then(() => {
expect(tokenClient.exchangeRefreshToken.mock.calls[0][0]).toEqual({
refresh_token: 'foo_refresh_token',
headers: { 'X-Requested-With': 'bar' },
});
});
});
it('should throw error if response was not right', () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
const tokenClient = sdk.manager._tokenClient; // eslint-disable-line
sdk.manager.getUser = jest.fn().mockResolvedValue(mockUser('foo'));
tokenClient.exchangeRefreshToken = jest.fn().mockResolvedValue({
refresh_token: 'bar_refresh_token',
expires_in: Math.floor(Date.now() / 1000) + 60 * 120, // two hours
});
return sdk.changeTenant('bar').catch(error => {
expect(error.message).toEqual(
'changeTenant: Error while changing tenant'
);
});
});
it('should call jsonService.postForm', async () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
const tokenClient = sdk.manager._tokenClient; // eslint-disable-line
const jsonService = tokenClient._jsonService; // eslint-disable-line
sdk.manager.getUser = jest.fn().mockResolvedValue(mockUser('foo'));
jsonService.postForm = jest.fn().mockResolvedValue({
access_token: 'bar_access_token',
refresh_token: 'bar_refresh_token',
expires_in: Math.floor(Date.now() / 1000) + 60 * 120, // two hours
});
return sdk.changeTenant('bar').then(() => {
expect(jsonService.postForm.mock.calls[0][1]).toEqual({
client_id: 'foo-client',
grant_type: 'refresh_token',
refresh_token: 'foo_refresh_token',
headers: {
'X-Requested-With': 'bar',
},
});
});
});
it('should ignore headers in jsonService.postForm', () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
const tokenClient = sdk.manager._tokenClient; // eslint-disable-line
const jsonService = tokenClient._jsonService; // eslint-disable-line
XHRMock.post(/foo/, (req, res) => {
expect(req.header('Content-Type')).toEqual(
'application/x-www-form-urlencoded'
);
expect(req.header('X-Requested-With')).toBeNull();
return res
.status(200)
.body(JSON.stringify({ success: true }))
.header('Content-Type', 'application/json');
});
return jsonService.postForm('foo', { bar: 'baz' }).then(response => {
expect(response).toEqual({ success: true });
});
});
it('should complain if url is not added to jsonService.postForm', () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
const tokenClient = sdk.manager._tokenClient; // eslint-disable-line
const jsonService = tokenClient._jsonService; // eslint-disable-line
expect(() => jsonService.postForm('', { bar: 'baz' })).toThrowError('url');
});
it('should properly call XMLHttpRequest', () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
sdk.manager.getUser = jest.fn().mockResolvedValue(mockUser('foo'));
XHRMock.post(/token$/, (req, res) => {
expect(req.header('Content-Type')).toEqual(
'application/x-www-form-urlencoded'
);
expect(req.header('X-Requested-With')).toEqual('bar');
const response = {
access_token: 'bar_access_token',
refresh_token: 'bar_refresh_token',
expires_in: Math.floor(Date.now() / 1000) + 60 * 120, // two hours
};
return res
.status(200)
.body(JSON.stringify(response))
.header('Content-Type', 'application/json');
});
return sdk.changeTenant('bar');
});
it('should properly handle errors in XMLHttpRequest', () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
sdk.manager.getUser = jest.fn().mockResolvedValue(mockUser('foo'));
XHRMock.post(/token$/, (req, res) =>
res
.status(400)
.body(JSON.stringify({ error: 'Invalid token' }))
.header('Content-Type', 'application/json')
);
return sdk.changeTenant('bar').catch(error => {
expect(error.message).toEqual('Invalid token');
});
});
it('should properly handle no errors in body in XMLHttpRequest', () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
sdk.manager.getUser = jest.fn().mockResolvedValue(mockUser('foo'));
XHRMock.post(/token$/, (req, res) =>
res
.status(400)
.reason('Some other error')
.body(JSON.stringify({}))
.header('Content-Type', 'application/json')
);
return sdk.changeTenant('bar').catch(error => {
expect(error.message).toEqual('Some other error ( 400 )');
});
});
it('should complain for malformed response XMLHttpRequest', () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
sdk.manager.getUser = jest.fn().mockResolvedValue(mockUser('foo'));
XHRMock.post(/token$/, (req, res) =>
res
.status(200)
.body('{ foo: bar }')
.header('Content-Type', 'application/json')
);
return sdk.changeTenant('bar').catch(error => {
expect(error.message).toEqual('Unexpected token f in JSON at position 2');
});
});
it('should properly handle not allowed content type', () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
sdk.manager.getUser = jest.fn().mockResolvedValue(mockUser('foo'));
XHRMock.post(/token$/, (req, res) =>
res
.status(200)
.body(JSON.stringify({ foo: 'bar' }))
.header('Content-Type', 'invalid')
);
return sdk.changeTenant('bar').catch(error => {
expect(error.message).toEqual(
'Invalid response Content-Type: invalid, from URL: http://id.dev.olt-dev.io/v1/id/auth/realms/IoT/protocol/openid-connect/token'
);
});
});
it('should properly handle not allowed content type with 400', () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
sdk.manager.getUser = jest.fn().mockResolvedValue(mockUser('foo'));
XHRMock.post(/token$/, (req, res) =>
res
.status(400)
.reason('Other error')
.body(JSON.stringify({ foo: 'bar' }))
.header('Content-Type', 'invalid')
);
return sdk.changeTenant('bar').catch(error => {
expect(error.message).toEqual('Other error ( 400 )');
});
});
it('should properly handle network errors', () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
sdk.manager.getUser = jest.fn().mockResolvedValue(mockUser('foo'));
XHRMock.post(/token$/, () => Promise.reject(new Error('some error')));
return sdk.changeTenant('bar').catch(error => {
expect(error.message).toEqual('Network Error');
});
});
it('should properly handle server errors in XMLHttpRequest', () => {
const sdk = new BrowserSDK({
baseUrl: 'dev.olt-dev.io/v1/id',
realm: 'IoT',
clientId: 'foo-client',
});
sdk.manager.getUser = jest.fn().mockResolvedValue(mockUser('foo'));
XHRMock.post(/token$/, (req, res) =>
res
.status(500)
.reason('Internal Server Error')
.body(JSON.stringify({ error: 'Invalid token' }))
.header('Content-Type', 'application/json')
);
return sdk.changeTenant('bar').catch(error => {
expect(error.message).toEqual('Internal Server Error ( 500 )');
});
});
afterEach(() => XHRMock.teardown());
});