Skip to content
This repository has been archived by the owner on Jul 21, 2023. It is now read-only.

Commit

Permalink
Merge pull request #817 from mturley/settings-tests
Browse files Browse the repository at this point in the history
Add unit tests for Settings page components, actions and reducers

(cherry picked from commit 430933a)

https://bugzilla.redhat.com/show_bug.cgi?id=1657285
  • Loading branch information
michaelkro authored and simaishi committed Dec 11, 2018
1 parent 8e04c01 commit f3b16cd
Show file tree
Hide file tree
Showing 18 changed files with 669 additions and 21 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Expand Up @@ -34,6 +34,7 @@ module.exports = {
}
],
'import/prefer-default-export': 'off',
'import/no-named-as-default': 'off',
'no-underscore-dangle': 'off',
'no-param-reassign': 'off',
'no-restricted-syntax': 'off',
Expand Down
1 change: 1 addition & 0 deletions .jest-setup.js
Expand Up @@ -15,4 +15,5 @@ APImock.reset();
global.API.get = jest.fn(url => APImock.respond('GET', url));
global.API.put = jest.fn(url => APImock.respond('PUT', url));
global.API.post = jest.fn(url => APImock.respond('POST', url));
global.API.patch = jest.fn(url => APImock.respond('PATCH', url));
global.API.delete = jest.fn(url => APImock.respond('DELETE', url));
2 changes: 1 addition & 1 deletion app/javascript/common/mockRequests.js
Expand Up @@ -2,7 +2,7 @@ let mockedRequests;

export const APImock = {
reset: () => {
mockedRequests = { GET: {}, POST: {}, PUT: {}, DELETE: {} };
mockedRequests = { GET: {}, POST: {}, PUT: {}, PATCH: {}, DELETE: {} };
},
mock: (method, url, status, response) => {
mockedRequests[method][url] = { status, response };
Expand Down
5 changes: 2 additions & 3 deletions app/javascript/components/dates/IsoDate.test.js
@@ -1,7 +1,6 @@
import React from 'react';
import { configure, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import toJson from 'enzyme-to-json';
import IsoDate from './IsoDate';
import { i18nProviderWrapperFactory } from '../../common/i18nProviderWrapperFactory';

Expand All @@ -14,12 +13,12 @@ describe('Date', () => {

it('formats date', () => {
const wrapper = mount(<IntlDate data={{ date, defaultValue: 'Default value' }} />);
expect(toJson(wrapper.find('IsoDate'))).toMatchSnapshot();
expect(wrapper.find('IsoDate')).toMatchSnapshot();
});

it('renders default value', () => {
const wrapper = mount(<IntlDate data={{ date: null, defaultValue: 'Default value' }} />);

expect(toJson(wrapper.find('IsoDate'))).toMatchSnapshot();
expect(wrapper.find('IsoDate')).toMatchSnapshot();
});
});
7 changes: 3 additions & 4 deletions app/javascript/components/dates/LongDateTime.test.js
@@ -1,6 +1,5 @@
import { configure, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import toJson from 'enzyme-to-json';
import React from 'react';
import LongDateTime from './LongDateTime';
import { i18nProviderWrapperFactory } from '../../common/i18nProviderWrapperFactory';
Expand All @@ -15,7 +14,7 @@ describe('LongDateTime', () => {
it('formats date', () => {
const wrapper = mount(<IntlDate data={{ date, defaultValue: 'Default value' }} />);

expect(toJson(wrapper.find('LongDateTime'))).toMatchSnapshot();
expect(wrapper.find('LongDateTime')).toMatchSnapshot();
});

it('formats date with seconds', () => {
Expand All @@ -29,12 +28,12 @@ describe('LongDateTime', () => {
/>
);

expect(toJson(wrapper.find('LongDateTime'))).toMatchSnapshot();
expect(wrapper.find('LongDateTime')).toMatchSnapshot();
});

it('renders default value', () => {
const wrapper = mount(<IntlDate data={{ date: null, defaultValue: 'Default value' }} />);

expect(toJson(wrapper.find('LongDateTime'))).toMatchSnapshot();
expect(wrapper.find('LongDateTime')).toMatchSnapshot();
});
});
5 changes: 2 additions & 3 deletions app/javascript/components/dates/RelativeDateTime.test.js
@@ -1,6 +1,5 @@
import { configure, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import toJson from 'enzyme-to-json';
import React from 'react';
import RelativeDateTime from './RelativeDateTime';
import { i18nProviderWrapperFactory } from '../../common/i18nProviderWrapperFactory';
Expand All @@ -22,12 +21,12 @@ describe('RelativeDateTime', () => {
/>
);

expect(toJson(wrapper.find('RelativeDateTime'))).toMatchSnapshot();
expect(wrapper.find('RelativeDateTime')).toMatchSnapshot();
});

it('renders default value', () => {
const wrapper = mount(<IntlDate data={{ date: null, defaultValue: 'Default value' }} />);

expect(toJson(wrapper.find('RelativeDateTime'))).toMatchSnapshot();
expect(wrapper.find('RelativeDateTime')).toMatchSnapshot();
});
});
7 changes: 3 additions & 4 deletions app/javascript/components/dates/ShortDateTime.test.js
@@ -1,6 +1,5 @@
import { configure, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import toJson from 'enzyme-to-json';
import React from 'react';
import ShortDateTime from './ShortDateTime';
import { i18nProviderWrapperFactory } from '../../common/i18nProviderWrapperFactory';
Expand All @@ -15,7 +14,7 @@ describe('ShortDateTime', () => {
it('formats date', () => {
const wrapper = mount(<IntlDate data={{ date, defaultValue: 'Default value' }} />);

expect(toJson(wrapper.find('ShortDateTime'))).toMatchSnapshot();
expect(wrapper.find('ShortDateTime')).toMatchSnapshot();
});

it('formats date with seconds', () => {
Expand All @@ -29,12 +28,12 @@ describe('ShortDateTime', () => {
/>
);

expect(toJson(wrapper.find('ShortDateTime'))).toMatchSnapshot();
expect(wrapper.find('ShortDateTime')).toMatchSnapshot();
});

it('renders default value', () => {
const wrapper = mount(<IntlDate data={{ date: null, defaultValue: 'Default value' }} />);

expect(toJson(wrapper.find('ShortDateTime'))).toMatchSnapshot();
expect(wrapper.find('ShortDateTime')).toMatchSnapshot();
});
});
@@ -1,6 +1,5 @@
import React from 'react';
import { shallow } from 'enzyme';
import toJson from 'enzyme-to-json';
import MappingWizard from '../MappingWizard';

import { coreComponents } from '../../../../../../../components/';
Expand All @@ -18,6 +17,6 @@ describe('MappingWizard component', () => {

it('renders the mapping wizard', () => {
const component = shallow(<MappingWizard {...getBaseProps()} />);
expect(toJson(component)).toMatchSnapshot();
expect(component).toMatchSnapshot();
});
});
2 changes: 1 addition & 1 deletion app/javascript/react/screens/App/Settings/Settings.js
Expand Up @@ -5,7 +5,7 @@ import { Breadcrumb, Form, Button, Spinner } from 'patternfly-react';
import Toolbar from '../../../config/Toolbar';
import NumberInput from '../common/forms/NumberInput';

class Settings extends React.Component {
export class Settings extends React.Component {
componentDidMount() {
const { fetchServersAction, fetchServersUrl, fetchSettingsAction, fetchSettingsUrl } = this.props;
fetchServersAction(fetchServersUrl);
Expand Down
@@ -0,0 +1,36 @@
import React from 'react';
import { Spinner } from 'patternfly-react';
import { shallow } from 'enzyme';
import { Settings } from '../Settings';
import { servers, settings } from '../settings.fixures';
import { getFormValuesFromApiSettings } from '../helpers';

describe('Settings component', () => {
const defaultFormValues = getFormValuesFromApiSettings(settings);
const getBaseProps = () => ({
fetchServersAction: jest.fn(),
fetchSettingsAction: jest.fn(),
patchSettingsAction: jest.fn(),
savedSettings: defaultFormValues,
settingsForm: { values: defaultFormValues },
servers: servers.resources
});

it('renders the settings page', () => {
const component = shallow(<Settings {...getBaseProps()} />);
expect(component).toMatchSnapshot();
});

it('renders the settings page with Applying spinner when saving', () => {
const component = shallow(<Settings {...getBaseProps()} isSavingSettings />);
const applying = component.find(Spinner).findWhere(child => child.text() === ' Applying...');
expect(applying).toHaveLength(1);
});

it('properly calls patchSettingsAction on apply click', () => {
const patchSettingsAction = jest.fn();
const component = shallow(<Settings {...getBaseProps()} patchSettingsAction={patchSettingsAction} />);
component.find('Button').simulate('click');
expect(patchSettingsAction).toBeCalledWith(servers.resources, defaultFormValues);
});
});
@@ -0,0 +1,103 @@
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import promiseMiddleware from 'redux-promise-middleware';
import * as actions from '../SettingsActions';
import {
fetchServersData,
servers,
settingsFormValues,
fetchSettingsData,
patchSettingsData
} from '../settings.fixures';
import { initialState } from '../SettingsReducer';
import { mockRequest, mockReset } from '../../../../../common/mockRequests';

const middlewares = [thunk, promiseMiddleware()];
const mockStore = configureMockStore(middlewares);
const store = mockStore(initialState);

afterEach(() => {
store.clearActions();
mockReset();
});

describe('settings actions', () => {
it('should fetch servers and return PENDING and FULFILLED action', () => {
const { method, fetchServersUrl, response } = fetchServersData;
mockRequest({
method,
url: fetchServersUrl,
status: 200,
response
});
return store.dispatch(actions.fetchServersAction(fetchServersUrl)).then(() => {
expect(store.getActions()).toMatchSnapshot();
});
});

it('should fetch servers and return PENDING and REJECTED action', () => {
const { method, fetchServersUrl } = fetchServersData;
mockRequest({
method,
url: fetchServersUrl,
status: 500
});
return store.dispatch(actions.fetchServersAction(fetchServersUrl)).catch(() => {
expect(store.getActions()).toMatchSnapshot();
});
});

it('should fetch settings and return PENDING and FULFILLED action', () => {
const { method, fetchSettingsUrl, response } = fetchSettingsData;
mockRequest({
method,
url: fetchSettingsUrl,
status: 200,
response
});
return store.dispatch(actions.fetchSettingsAction(fetchSettingsUrl)).then(() => {
expect(store.getActions()).toMatchSnapshot();
});
});

it('should fetch settings and return PENDING and REJECTED action', () => {
const { method, fetchSettingsUrl } = fetchSettingsData;
mockRequest({
method,
url: fetchSettingsUrl,
status: 500
});
return store.dispatch(actions.fetchSettingsAction(fetchSettingsUrl)).catch(() => {
expect(store.getActions()).toMatchSnapshot();
});
});

it('should patch settings and return PENDING and FULFILLED actions', () => {
const { method, response } = patchSettingsData;
servers.resources.forEach(server => {
mockRequest({
method,
url: `${server.href}/settings`,
status: 200,
response
});
});
return store.dispatch(actions.patchSettingsAction(servers.resources, settingsFormValues)).then(() => {
expect(store.getActions()).toMatchSnapshot();
});
});

it('should patch settings and return PENDING and REJECTED action', () => {
const { method } = patchSettingsData;
servers.resources.forEach(server => {
mockRequest({
method,
url: `${server.href}/settings`,
status: 500
});
});
return store.dispatch(actions.patchSettingsAction(servers.resources, settingsFormValues)).catch(() => {
expect(store.getActions()).toMatchSnapshot();
});
});
});
@@ -0,0 +1,104 @@
import settingsReducer, { initialState } from '../SettingsReducer';
import { V2V_FETCH_SERVERS, V2V_FETCH_SETTINGS, V2V_PATCH_SETTINGS } from '../SettingsConstants';
import { servers, settings } from '../settings.fixures';

it('sets default state', () => {
const action = { type: '@@INIT' };
const state = settingsReducer(undefined, action);
expect(state).toMatchSnapshot();
});

describe('fetching servers', () => {
it('is pending', () => {
const action = {
type: `${V2V_FETCH_SERVERS}_PENDING`
};
const prevState = initialState.set('fetchingServersRejected', true);
const state = settingsReducer(prevState, action);
expect(state).toMatchSnapshot();
});

it('is rejected', () => {
const action = {
type: `${V2V_FETCH_SERVERS}_REJECTED`,
payload: 'error'
};
const prevState = initialState.set('isFetchingServers', true);
const state = settingsReducer(prevState, action);
expect(state).toMatchSnapshot();
});

it('is successful', () => {
const action = {
type: `${V2V_FETCH_SERVERS}_FULFILLED`,
payload: { data: servers }
};
const prevState = initialState.set('fetchingServersRejected', true).set('isFetchingServers', true);
const state = settingsReducer(prevState, action);
expect(state.fetchingServersRejected).toBe(false);
expect(state.isFetchingServers).toBe(false);
expect(state.servers).toHaveLength(2);
});
});

describe('fetching settings', () => {
it('is pending', () => {
const action = {
type: `${V2V_FETCH_SETTINGS}_PENDING`
};
const prevState = initialState.set('fetchingSettingsRejected', true);
const state = settingsReducer(prevState, action);
expect(state).toMatchSnapshot();
});

it('is rejected', () => {
const action = {
type: `${V2V_FETCH_SETTINGS}_REJECTED`,
payload: 'error'
};
const prevState = initialState.set('isFetchingSettings', true);
const state = settingsReducer(prevState, action);
expect(state).toMatchSnapshot();
});

it('is successful', () => {
const action = {
type: `${V2V_FETCH_SETTINGS}_FULFILLED`,
payload: { data: settings }
};
const prevState = initialState.set('fetchingSettingsRejected', true).set('isFetchingSettings', true);
const state = settingsReducer(prevState, action);
expect(state).toMatchSnapshot();
});
});

describe('saving settings', () => {
it('is pending', () => {
const action = {
type: `${V2V_PATCH_SETTINGS}_PENDING`
};
const prevState = initialState.set('savingSettingsRejected', true);
const state = settingsReducer(prevState, action);
expect(state).toMatchSnapshot();
});

it('is rejected', () => {
const action = {
type: `${V2V_PATCH_SETTINGS}_REJECTED`,
payload: 'error'
};
const prevState = initialState.set('isSavingSettings', true);
const state = settingsReducer(prevState, action);
expect(state).toMatchSnapshot();
});

it('is successful', () => {
const action = {
type: `${V2V_PATCH_SETTINGS}_FULFILLED`,
payload: settings
};
const prevState = initialState.set('savingSettingsRejected', true).set('isSavingSettings', true);
const state = settingsReducer(prevState, action);
expect(state).toMatchSnapshot();
});
});

0 comments on commit f3b16cd

Please sign in to comment.