mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
645 lines
19 KiB
JavaScript
645 lines
19 KiB
JavaScript
import expect, { createSpy, restoreSpies } from 'expect';
|
|
import { find } from 'lodash';
|
|
|
|
import { formatErrorResponse } from 'redux/nodes/entities/base/helpers';
|
|
import reduxConfig from 'redux/nodes/entities/base/reduxConfig';
|
|
import { reduxMockStore } from 'test/helpers';
|
|
import schemas from 'redux/nodes/entities/base/schemas';
|
|
|
|
const store = {
|
|
entities: {
|
|
invites: {
|
|
errors: {},
|
|
data: {},
|
|
loading: false,
|
|
},
|
|
users: {
|
|
errors: {},
|
|
data: {},
|
|
loading: false,
|
|
},
|
|
},
|
|
};
|
|
const invite = { id: 1, name: 'Gnar Dog', email: '[email protected]' };
|
|
const user = { id: 1, email: '[email protected]' };
|
|
|
|
describe('reduxConfig', () => {
|
|
afterEach(restoreSpies);
|
|
|
|
describe('dispatching the clear errors action', () => {
|
|
it('sets the errors to an empty object', () => {
|
|
const initialState = {
|
|
data: {},
|
|
errors: {
|
|
base: 'Unable to find the current user',
|
|
},
|
|
loading: false,
|
|
};
|
|
|
|
const config = reduxConfig({
|
|
entityName: 'users',
|
|
schema: schemas.USERS,
|
|
});
|
|
const { actions, reducer } = config;
|
|
const newState = reducer(initialState, actions.clearErrors);
|
|
|
|
expect(newState.errors).toEqual({});
|
|
});
|
|
});
|
|
|
|
describe('dispatching the create action', () => {
|
|
describe('successful create call', () => {
|
|
const mockStore = reduxMockStore(store);
|
|
const createFunc = createSpy().andCall(() => {
|
|
return Promise.resolve([user]);
|
|
});
|
|
|
|
const config = reduxConfig({
|
|
createFunc,
|
|
entityName: 'users',
|
|
schema: schemas.USERS,
|
|
});
|
|
const { actions, reducer } = config;
|
|
|
|
it('calls the createFunc', () => {
|
|
mockStore.dispatch(actions.create());
|
|
|
|
expect(createFunc).toHaveBeenCalled();
|
|
});
|
|
|
|
it('dispatches the correct actions', () => {
|
|
mockStore.dispatch(actions.create());
|
|
|
|
const dispatchedActions = mockStore.getActions();
|
|
const dispatchedActionTypes = dispatchedActions.map((action) => { return action.type; });
|
|
|
|
expect(dispatchedActionTypes).toInclude('users_CREATE_REQUEST');
|
|
expect(dispatchedActionTypes).toInclude('users_CREATE_SUCCESS');
|
|
expect(dispatchedActionTypes).toNotInclude('users_CREATE_FAILURE');
|
|
});
|
|
|
|
it('adds the returned user to state', () => {
|
|
const createSuccessAction = {
|
|
type: 'users_CREATE_SUCCESS',
|
|
payload: {
|
|
data: {
|
|
users: {
|
|
[user.id]: user,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
const initialState = {
|
|
loading: false,
|
|
entities: {},
|
|
errors: {},
|
|
};
|
|
const newState = reducer(initialState, createSuccessAction);
|
|
|
|
expect(newState.data[user.id]).toEqual(user);
|
|
});
|
|
});
|
|
|
|
describe('unsuccessful create call', () => {
|
|
const mockStore = reduxMockStore(store);
|
|
const errors = [
|
|
{ name: 'first_name',
|
|
reason: 'is not valid',
|
|
},
|
|
{ name: 'last_name',
|
|
reason: 'must be changed or something',
|
|
},
|
|
];
|
|
const errorResponse = {
|
|
message: {
|
|
message: 'Validation Failed',
|
|
errors,
|
|
},
|
|
};
|
|
const formattedErrors = formatErrorResponse(errorResponse);
|
|
const createFunc = createSpy().andCall(() => {
|
|
return Promise.reject(errorResponse);
|
|
});
|
|
const config = reduxConfig({
|
|
createFunc,
|
|
entityName: 'users',
|
|
schema: schemas.USERS,
|
|
});
|
|
const { actions, reducer } = config;
|
|
|
|
it('calls the createFunc', () => {
|
|
mockStore.dispatch(actions.create());
|
|
|
|
expect(createFunc).toHaveBeenCalled();
|
|
});
|
|
|
|
it('dispatches the correct actions', () => {
|
|
mockStore.dispatch(actions.create());
|
|
|
|
const dispatchedActions = mockStore.getActions();
|
|
const dispatchedActionTypes = dispatchedActions.map((action) => { return action.type; });
|
|
|
|
expect(dispatchedActionTypes).toInclude('users_CREATE_REQUEST');
|
|
expect(dispatchedActionTypes).toNotInclude('users_CREATE_SUCCESS');
|
|
|
|
const createFailureAction = find(dispatchedActions, { type: 'users_CREATE_FAILURE' });
|
|
|
|
expect(createFailureAction.payload).toEqual({
|
|
errors: formattedErrors,
|
|
});
|
|
});
|
|
|
|
it('adds the returned errors to state', () => {
|
|
const createFailureAction = {
|
|
type: 'users_CREATE_FAILURE',
|
|
payload: {
|
|
errors: formattedErrors,
|
|
},
|
|
};
|
|
const initialState = {
|
|
loading: false,
|
|
entities: {},
|
|
errors: {},
|
|
};
|
|
const newState = reducer(initialState, createFailureAction);
|
|
|
|
expect(newState.errors).toEqual(formattedErrors);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('dispatching the update action', () => {
|
|
describe('successful update call', () => {
|
|
const mockStore = reduxMockStore(store);
|
|
const updateFunc = createSpy().andCall(() => {
|
|
return Promise.resolve([{ ...user, updated: true }]);
|
|
});
|
|
|
|
const config = reduxConfig({
|
|
updateFunc,
|
|
entityName: 'users',
|
|
schema: schemas.USERS,
|
|
});
|
|
const { actions, reducer } = config;
|
|
|
|
it('calls the updateFunc', () => {
|
|
mockStore.dispatch(actions.update(user));
|
|
|
|
expect(updateFunc).toHaveBeenCalledWith(user);
|
|
});
|
|
|
|
it('dispatches the correct actions', () => {
|
|
mockStore.dispatch(actions.update());
|
|
|
|
const dispatchedActions = mockStore.getActions();
|
|
const dispatchedActionTypes = dispatchedActions.map((action) => { return action.type; });
|
|
|
|
expect(dispatchedActionTypes).toInclude('users_UPDATE_REQUEST');
|
|
expect(dispatchedActionTypes).toInclude('users_UPDATE_SUCCESS');
|
|
expect(dispatchedActionTypes).toNotInclude('users_UPDATE_FAILURE');
|
|
});
|
|
|
|
it('adds the returned user to state', () => {
|
|
const updateSuccessAction = {
|
|
type: 'users_UPDATE_SUCCESS',
|
|
payload: {
|
|
data: {
|
|
users: {
|
|
[user.id]: { ...user, updated: true },
|
|
},
|
|
},
|
|
},
|
|
};
|
|
const initialState = {
|
|
loading: false,
|
|
entities: {},
|
|
errors: {},
|
|
};
|
|
const newState = reducer(initialState, updateSuccessAction);
|
|
|
|
expect(newState.data[user.id]).toEqual({ ...user, updated: true });
|
|
});
|
|
});
|
|
|
|
describe('unsuccessful update call', () => {
|
|
const mockStore = reduxMockStore(store);
|
|
const errors = [
|
|
{ name: 'first_name',
|
|
reason: 'is not valid',
|
|
},
|
|
{ name: 'last_name',
|
|
reason: 'must be changed or something',
|
|
},
|
|
];
|
|
const errorResponse = {
|
|
message: {
|
|
message: 'Validation Failed',
|
|
errors,
|
|
},
|
|
};
|
|
const formattedErrors = formatErrorResponse(errorResponse);
|
|
const updateFunc = createSpy().andCall(() => {
|
|
return Promise.reject(errorResponse);
|
|
});
|
|
const config = reduxConfig({
|
|
entityName: 'users',
|
|
schema: schemas.USERS,
|
|
updateFunc,
|
|
});
|
|
const { actions, reducer } = config;
|
|
|
|
it('calls the updateFunc', () => {
|
|
mockStore.dispatch(actions.update(user));
|
|
|
|
expect(updateFunc).toHaveBeenCalledWith(user);
|
|
});
|
|
|
|
it('dispatches the correct actions', () => {
|
|
mockStore.dispatch(actions.update());
|
|
|
|
const dispatchedActions = mockStore.getActions();
|
|
const dispatchedActionTypes = dispatchedActions.map((action) => { return action.type; });
|
|
|
|
expect(dispatchedActionTypes).toInclude('users_UPDATE_REQUEST');
|
|
expect(dispatchedActionTypes).toNotInclude('users_UPDATE_SUCCESS');
|
|
|
|
const updateFailureAction = find(dispatchedActions, { type: 'users_UPDATE_FAILURE' });
|
|
|
|
expect(updateFailureAction.payload).toEqual({
|
|
errors: formattedErrors,
|
|
});
|
|
});
|
|
|
|
it('adds the returned errors to state', () => {
|
|
const updateFailureAction = {
|
|
type: 'users_UPDATE_FAILURE',
|
|
payload: {
|
|
errors: formattedErrors,
|
|
},
|
|
};
|
|
const initialState = {
|
|
loading: false,
|
|
entities: {},
|
|
errors: {},
|
|
};
|
|
const newState = reducer(initialState, updateFailureAction);
|
|
|
|
expect(newState.errors).toEqual(formattedErrors);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('dispatching the destroy action', () => {
|
|
describe('successful destroy call', () => {
|
|
const mockStore = reduxMockStore(store);
|
|
const destroyFunc = createSpy().andCall(() => {
|
|
return Promise.resolve();
|
|
});
|
|
|
|
const config = reduxConfig({
|
|
destroyFunc,
|
|
entityName: 'invites',
|
|
schema: schemas.INVITES,
|
|
});
|
|
const { actions, reducer } = config;
|
|
|
|
it('calls the destroyFunc', () => {
|
|
mockStore.dispatch(actions.destroy({ inviteID: invite.id }));
|
|
|
|
expect(destroyFunc).toHaveBeenCalled();
|
|
});
|
|
|
|
it('dispatches the correct actions', () => {
|
|
mockStore.dispatch(actions.destroy({ inviteID: invite.id }));
|
|
|
|
const dispatchedActions = mockStore.getActions();
|
|
const dispatchedActionTypes = dispatchedActions.map((action) => { return action.type; });
|
|
|
|
expect(dispatchedActionTypes).toInclude('invites_DESTROY_REQUEST');
|
|
expect(dispatchedActionTypes).toInclude('invites_DESTROY_SUCCESS');
|
|
expect(dispatchedActionTypes).toNotInclude('invites_DESTROY_FAILURE');
|
|
});
|
|
|
|
it('removes the returned invite from state', () => {
|
|
const destroySuccessAction = {
|
|
type: 'invites_DESTROY_SUCCESS',
|
|
payload: {
|
|
id: 1,
|
|
},
|
|
};
|
|
const initialState = {
|
|
data: {
|
|
[invite.id]: invite,
|
|
2: { id: 2, name: 'Jason Meller' },
|
|
},
|
|
errors: {},
|
|
loading: false,
|
|
};
|
|
const newState = reducer(initialState, destroySuccessAction);
|
|
|
|
expect(newState.data).toEqual({
|
|
2: { id: 2, name: 'Jason Meller' },
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('unsuccessful destroy call', () => {
|
|
const mockStore = reduxMockStore(store);
|
|
const errors = [
|
|
{
|
|
name: 'base',
|
|
reason: 'Unable to create user',
|
|
},
|
|
];
|
|
const errorResponse = {
|
|
message: {
|
|
message: 'Validation Failed',
|
|
errors,
|
|
},
|
|
};
|
|
const destroyFunc = createSpy().andCall(() => {
|
|
return Promise.reject(errorResponse);
|
|
});
|
|
const formattedErrors = formatErrorResponse(errorResponse);
|
|
const config = reduxConfig({
|
|
destroyFunc,
|
|
entityName: 'users',
|
|
schema: schemas.USERS,
|
|
});
|
|
const { actions, reducer } = config;
|
|
|
|
it('calls the createFunc', () => {
|
|
mockStore.dispatch(actions.destroy());
|
|
|
|
expect(destroyFunc).toHaveBeenCalled();
|
|
});
|
|
|
|
it('dispatches the correct actions', () => {
|
|
mockStore.dispatch(actions.destroy());
|
|
|
|
const dispatchedActions = mockStore.getActions();
|
|
const dispatchedActionTypes = dispatchedActions.map((action) => { return action.type; });
|
|
const destroyFailureAction = find(dispatchedActions, { type: 'users_DESTROY_FAILURE' });
|
|
|
|
expect(dispatchedActionTypes).toInclude('users_DESTROY_REQUEST');
|
|
expect(dispatchedActionTypes).toNotInclude('users_DESTROY_SUCCESS');
|
|
|
|
expect(destroyFailureAction.payload).toEqual({
|
|
errors: formattedErrors,
|
|
});
|
|
});
|
|
|
|
it('adds the returned errors to state', () => {
|
|
const destroyFailureAction = {
|
|
type: 'users_DESTROY_FAILURE',
|
|
payload: {
|
|
errors: formattedErrors,
|
|
},
|
|
};
|
|
const initialState = {
|
|
loading: false,
|
|
entities: {},
|
|
errors: {},
|
|
};
|
|
const newState = reducer(initialState, destroyFailureAction);
|
|
|
|
expect(newState.errors).toEqual(formattedErrors);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('dispatching the load action', () => {
|
|
describe('successful load call', () => {
|
|
const mockStore = reduxMockStore(store);
|
|
const loadFunc = createSpy().andCall(() => {
|
|
return Promise.resolve(user);
|
|
});
|
|
|
|
const config = reduxConfig({
|
|
entityName: 'users',
|
|
loadFunc,
|
|
schema: schemas.USERS,
|
|
});
|
|
const { actions, reducer } = config;
|
|
|
|
it('calls the loadFunc', () => {
|
|
mockStore.dispatch(actions.load());
|
|
|
|
expect(loadFunc).toHaveBeenCalled();
|
|
});
|
|
|
|
it('dispatches the correct actions', () => {
|
|
mockStore.dispatch(actions.load());
|
|
|
|
const dispatchedActions = mockStore.getActions();
|
|
const dispatchedActionTypes = dispatchedActions.map((action) => { return action.type; });
|
|
|
|
expect(dispatchedActionTypes).toInclude('users_LOAD_REQUEST');
|
|
expect(dispatchedActionTypes).toInclude('users_LOAD_SUCCESS');
|
|
expect(dispatchedActionTypes).toNotInclude('users_LOAD_FAILURE');
|
|
});
|
|
|
|
it('adds the returned user to state', () => {
|
|
const loadSuccessAction = {
|
|
type: 'users_LOAD_SUCCESS',
|
|
payload: {
|
|
data: {
|
|
users: {
|
|
[user.id]: user,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
const initialState = {
|
|
loading: false,
|
|
entities: {},
|
|
errors: {},
|
|
};
|
|
const newState = reducer(initialState, loadSuccessAction);
|
|
|
|
expect(newState.data[user.id]).toEqual(user);
|
|
});
|
|
});
|
|
|
|
describe('unsuccessful load call', () => {
|
|
const mockStore = reduxMockStore(store);
|
|
const errors = [
|
|
{
|
|
name: 'base',
|
|
reason: 'Unable to load users',
|
|
},
|
|
];
|
|
const errorResponse = {
|
|
message: {
|
|
message: 'Something went wrong',
|
|
errors,
|
|
},
|
|
};
|
|
const formattedErrors = formatErrorResponse(errorResponse);
|
|
const loadFunc = createSpy().andCall(() => {
|
|
return Promise.reject(errorResponse);
|
|
});
|
|
const config = reduxConfig({
|
|
entityName: 'users',
|
|
loadFunc,
|
|
schema: schemas.USERS,
|
|
});
|
|
const { actions, reducer } = config;
|
|
|
|
it('calls the loadFunc', () => {
|
|
mockStore.dispatch(actions.load());
|
|
|
|
expect(loadFunc).toHaveBeenCalled();
|
|
});
|
|
|
|
it('dispatches the correct actions', () => {
|
|
mockStore.dispatch(actions.load());
|
|
|
|
const dispatchedActions = mockStore.getActions();
|
|
const dispatchedActionTypes = dispatchedActions.map((action) => { return action.type; });
|
|
const loadFailureAction = find(dispatchedActions, { type: 'users_LOAD_FAILURE' });
|
|
|
|
expect(dispatchedActionTypes).toInclude('users_LOAD_REQUEST');
|
|
expect(dispatchedActionTypes).toNotInclude('users_LOAD_SUCCESS');
|
|
expect(loadFailureAction.payload).toEqual({
|
|
errors: formattedErrors,
|
|
});
|
|
});
|
|
|
|
it('adds the returned errors to state', () => {
|
|
const loadFailureAction = {
|
|
type: 'users_LOAD_FAILURE',
|
|
payload: {
|
|
errors: formattedErrors,
|
|
},
|
|
};
|
|
const initialState = {
|
|
loading: false,
|
|
entities: {},
|
|
errors: {},
|
|
};
|
|
const newState = reducer(initialState, loadFailureAction);
|
|
|
|
expect(newState.errors).toEqual(formattedErrors);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('dispatching the loadAll action', () => {
|
|
describe('successful load call', () => {
|
|
const mockStore = reduxMockStore(store);
|
|
const loadAllFunc = createSpy().andCall(() => {
|
|
return Promise.resolve([user]);
|
|
});
|
|
|
|
const config = reduxConfig({
|
|
entityName: 'users',
|
|
loadAllFunc,
|
|
schema: schemas.USERS,
|
|
});
|
|
const { actions, reducer } = config;
|
|
|
|
it('calls the loadAllFunc', () => {
|
|
mockStore.dispatch(actions.loadAll());
|
|
|
|
expect(loadAllFunc).toHaveBeenCalled();
|
|
});
|
|
|
|
it('dispatches the correct actions', () => {
|
|
mockStore.dispatch(actions.loadAll());
|
|
|
|
const dispatchedActions = mockStore.getActions();
|
|
const dispatchedActionTypes = dispatchedActions.map((action) => { return action.type; });
|
|
|
|
expect(dispatchedActionTypes).toInclude('users_LOAD_REQUEST');
|
|
expect(dispatchedActionTypes).toInclude('users_LOAD_SUCCESS');
|
|
expect(dispatchedActionTypes).toNotInclude('users_LOAD_FAILURE');
|
|
});
|
|
|
|
it('adds the returned user to state', () => {
|
|
const loadSuccessAction = {
|
|
type: 'users_LOAD_SUCCESS',
|
|
payload: {
|
|
data: {
|
|
users: {
|
|
[user.id]: user,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
const initialState = {
|
|
loading: false,
|
|
entities: {},
|
|
errors: {},
|
|
};
|
|
const newState = reducer(initialState, loadSuccessAction);
|
|
|
|
expect(newState.data[user.id]).toEqual(user);
|
|
});
|
|
});
|
|
|
|
describe('unsuccessful loadAll call', () => {
|
|
const mockStore = reduxMockStore(store);
|
|
const errors = [
|
|
{
|
|
name: 'base',
|
|
reason: 'Unable to load users',
|
|
},
|
|
];
|
|
const errorResponse = {
|
|
message: {
|
|
message: 'Cannot get users',
|
|
errors,
|
|
},
|
|
};
|
|
const formattedErrors = formatErrorResponse(errorResponse);
|
|
const loadAllFunc = createSpy().andCall(() => {
|
|
return Promise.reject(errorResponse);
|
|
});
|
|
const config = reduxConfig({
|
|
entityName: 'users',
|
|
loadAllFunc,
|
|
schema: schemas.USERS,
|
|
});
|
|
const { actions, reducer } = config;
|
|
|
|
it('calls the loadAllFunc', () => {
|
|
mockStore.dispatch(actions.loadAll());
|
|
|
|
expect(loadAllFunc).toHaveBeenCalled();
|
|
});
|
|
|
|
it('dispatches the correct actions', () => {
|
|
mockStore.dispatch(actions.loadAll());
|
|
|
|
const dispatchedActions = mockStore.getActions();
|
|
const dispatchedActionTypes = dispatchedActions.map((action) => { return action.type; });
|
|
const loadAllFailureAction = find(dispatchedActions, { type: 'users_LOAD_FAILURE' });
|
|
|
|
expect(dispatchedActionTypes).toInclude('users_LOAD_REQUEST');
|
|
expect(dispatchedActionTypes).toNotInclude('users_LOAD_SUCCESS');
|
|
|
|
expect(loadAllFailureAction.payload).toEqual({
|
|
errors: formattedErrors,
|
|
});
|
|
});
|
|
|
|
it('adds the returned errors to state', () => {
|
|
const loadAllFailureAction = {
|
|
type: 'users_LOAD_FAILURE',
|
|
payload: {
|
|
errors: formattedErrors,
|
|
},
|
|
};
|
|
const initialState = {
|
|
loading: false,
|
|
entities: {},
|
|
errors: {},
|
|
};
|
|
const newState = reducer(initialState, loadAllFailureAction);
|
|
|
|
expect(newState.errors).toEqual(formattedErrors);
|
|
});
|
|
});
|
|
});
|
|
});
|