Add feature room-admin
Change-Id: I3bbe7bd7299b56e84ab918d2a8bb22facafecbf1
This commit is contained in:
parent
8b339db56e
commit
3d9ec623e4
@ -3,6 +3,7 @@ import { routerReducer } from 'react-router-redux';
|
|||||||
import homeReducer from '../features/home/redux/reducer';
|
import homeReducer from '../features/home/redux/reducer';
|
||||||
import commonReducer from '../features/common/redux/reducer';
|
import commonReducer from '../features/common/redux/reducer';
|
||||||
import userAdminReducer from '../features/user-admin/redux/reducer';
|
import userAdminReducer from '../features/user-admin/redux/reducer';
|
||||||
|
import roomAdminReducer from '../features/room-admin/redux/reducer';
|
||||||
|
|
||||||
// NOTE 1: DO NOT CHANGE the 'reducerMap' name and the declaration pattern.
|
// NOTE 1: DO NOT CHANGE the 'reducerMap' name and the declaration pattern.
|
||||||
// This is used for Rekit cmds to register new features, remove features, etc.
|
// This is used for Rekit cmds to register new features, remove features, etc.
|
||||||
@ -14,6 +15,7 @@ const reducerMap = {
|
|||||||
home: homeReducer,
|
home: homeReducer,
|
||||||
common: commonReducer,
|
common: commonReducer,
|
||||||
userAdmin: userAdminReducer,
|
userAdmin: userAdminReducer,
|
||||||
|
roomAdmin: roomAdminReducer,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default combineReducers(reducerMap);
|
export default combineReducers(reducerMap);
|
||||||
|
@ -4,6 +4,7 @@ import _ from 'lodash';
|
|||||||
import commonRoute from '../features/common/route';
|
import commonRoute from '../features/common/route';
|
||||||
import homeRoute from '../features/home/route';
|
import homeRoute from '../features/home/route';
|
||||||
import userAdminRoute from '../features/user-admin/route';
|
import userAdminRoute from '../features/user-admin/route';
|
||||||
|
import roomAdminRoute from '../features/room-admin/route';
|
||||||
|
|
||||||
// NOTE: DO NOT CHANGE the 'childRoutes' name and the declaration pattern.
|
// NOTE: DO NOT CHANGE the 'childRoutes' name and the declaration pattern.
|
||||||
// This is used for Rekit cmds to register routes config for new features, and remove config when remove features, etc.
|
// This is used for Rekit cmds to register routes config for new features, and remove config when remove features, etc.
|
||||||
@ -11,6 +12,7 @@ const childRoutes = [
|
|||||||
homeRoute,
|
homeRoute,
|
||||||
commonRoute,
|
commonRoute,
|
||||||
userAdminRoute,
|
userAdminRoute,
|
||||||
|
roomAdminRoute,
|
||||||
];
|
];
|
||||||
|
|
||||||
const routes = [{
|
const routes = [{
|
||||||
|
@ -80,6 +80,10 @@ class Layout extends Component {
|
|||||||
component={Link} to="/user-admin">
|
component={Link} to="/user-admin">
|
||||||
<ListItemText primary="Users" />
|
<ListItemText primary="Users" />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
<ListItem button key="Rooms" selected={pathname === "/room-admin"}
|
||||||
|
component={Link} to="/room-admin">
|
||||||
|
<ListItemText primary="Rooms" />
|
||||||
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
61
src/features/room-admin/List.js
Normal file
61
src/features/room-admin/List.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { Redirect } from 'react-router-dom'
|
||||||
|
import { Table, TableBody, TableCell, TableHead, TableRow } from '@material-ui/core';
|
||||||
|
import * as actions from './redux/actions';
|
||||||
|
|
||||||
|
export class List extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
roomAdmin: PropTypes.object.isRequired,
|
||||||
|
actions: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { fetchPublicRooms } = this.props.actions;
|
||||||
|
fetchPublicRooms();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { mtx } = this.props;
|
||||||
|
const { roomList, fetchRoomsPending } = this.props.roomAdmin;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="room-admin-list">
|
||||||
|
{(!mtx || !mtx.clientRunning) && <Redirect to="/" />}
|
||||||
|
{fetchRoomsPending && <img alt="logging in" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />}
|
||||||
|
<Table className="room-list">
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Name</TableCell><TableCell>Room-ID</TableCell><TableCell>Members</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{roomList.map(item => (<TableRow key={item.room_id}><TableCell>{item.name}</TableCell><TableCell>{item.room_id}</TableCell><TableCell>{item.num_joined_members}</TableCell></TableRow>))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
function mapStateToProps(state) {
|
||||||
|
return {
|
||||||
|
mtx: state.common.mtx,
|
||||||
|
roomAdmin: state.roomAdmin,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
function mapDispatchToProps(dispatch) {
|
||||||
|
return {
|
||||||
|
actions: bindActionCreators({ ...actions }, dispatch)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(List);
|
9
src/features/room-admin/List.scss
Normal file
9
src/features/room-admin/List.scss
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
@import '../../styles/mixins';
|
||||||
|
|
||||||
|
.room-admin-list {
|
||||||
|
th {
|
||||||
|
background-color: #EEE;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
1
src/features/room-admin/index.js
Normal file
1
src/features/room-admin/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default as List } from './List';
|
1
src/features/room-admin/redux/actions.js
Normal file
1
src/features/room-admin/redux/actions.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { fetchPublicRooms, dismissFetchPublicRoomsError } from './fetchPublicRooms';
|
4
src/features/room-admin/redux/constants.js
Normal file
4
src/features/room-admin/redux/constants.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export const ROOM_ADMIN_FETCH_PUBLIC_ROOMS_BEGIN = 'ROOM_ADMIN_FETCH_PUBLIC_ROOMS_BEGIN';
|
||||||
|
export const ROOM_ADMIN_FETCH_PUBLIC_ROOMS_SUCCESS = 'ROOM_ADMIN_FETCH_PUBLIC_ROOMS_SUCCESS';
|
||||||
|
export const ROOM_ADMIN_FETCH_PUBLIC_ROOMS_FAILURE = 'ROOM_ADMIN_FETCH_PUBLIC_ROOMS_FAILURE';
|
||||||
|
export const ROOM_ADMIN_FETCH_PUBLIC_ROOMS_DISMISS_ERROR = 'ROOM_ADMIN_FETCH_PUBLIC_ROOMS_DISMISS_ERROR';
|
88
src/features/room-admin/redux/fetchPublicRooms.js
Normal file
88
src/features/room-admin/redux/fetchPublicRooms.js
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import {
|
||||||
|
ROOM_ADMIN_FETCH_PUBLIC_ROOMS_BEGIN,
|
||||||
|
ROOM_ADMIN_FETCH_PUBLIC_ROOMS_SUCCESS,
|
||||||
|
ROOM_ADMIN_FETCH_PUBLIC_ROOMS_FAILURE,
|
||||||
|
ROOM_ADMIN_FETCH_PUBLIC_ROOMS_DISMISS_ERROR,
|
||||||
|
} from './constants';
|
||||||
|
|
||||||
|
// Rekit uses redux-thunk for async actions by default: https://github.com/gaearon/redux-thunk
|
||||||
|
// If you prefer redux-saga, you can use rekit-plugin-redux-saga: https://github.com/supnate/rekit-plugin-redux-saga
|
||||||
|
export function fetchPublicRooms(args = {}) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
dispatch({
|
||||||
|
type: ROOM_ADMIN_FETCH_PUBLIC_ROOMS_BEGIN,
|
||||||
|
});
|
||||||
|
|
||||||
|
const promise = new Promise((resolve, reject) => {
|
||||||
|
const mtx = getState().common.mtx;
|
||||||
|
const doRequest = mtx.publicRooms();
|
||||||
|
doRequest.then(
|
||||||
|
(res) => {
|
||||||
|
dispatch({
|
||||||
|
type: ROOM_ADMIN_FETCH_PUBLIC_ROOMS_SUCCESS,
|
||||||
|
data: res,
|
||||||
|
});
|
||||||
|
resolve(res);
|
||||||
|
},
|
||||||
|
// Use rejectHandler as the second argument so that render errors won't be caught.
|
||||||
|
(err) => {
|
||||||
|
dispatch({
|
||||||
|
type: ROOM_ADMIN_FETCH_PUBLIC_ROOMS_FAILURE,
|
||||||
|
data: { error: err },
|
||||||
|
});
|
||||||
|
reject(err);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Async action saves request error by default, this method is used to dismiss the error info.
|
||||||
|
// If you don't want errors to be saved in Redux store, just ignore this method.
|
||||||
|
export function dismissFetchPublicRoomsError() {
|
||||||
|
return {
|
||||||
|
type: ROOM_ADMIN_FETCH_PUBLIC_ROOMS_DISMISS_ERROR,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function reducer(state, action) {
|
||||||
|
switch (action.type) {
|
||||||
|
case ROOM_ADMIN_FETCH_PUBLIC_ROOMS_BEGIN:
|
||||||
|
// Just after a request is sent
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
fetchPublicRoomsPending: true,
|
||||||
|
fetchPublicRoomsError: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
case ROOM_ADMIN_FETCH_PUBLIC_ROOMS_SUCCESS:
|
||||||
|
// The request is success
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
roomList: action.data.chunk,
|
||||||
|
fetchPublicRoomsPending: false,
|
||||||
|
fetchPublicRoomsError: null,
|
||||||
|
//roomList: action.data.chunk,
|
||||||
|
};
|
||||||
|
|
||||||
|
case ROOM_ADMIN_FETCH_PUBLIC_ROOMS_FAILURE:
|
||||||
|
// The request is failed
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
fetchPublicRoomsPending: false,
|
||||||
|
fetchPublicRoomsError: action.data.error,
|
||||||
|
};
|
||||||
|
|
||||||
|
case ROOM_ADMIN_FETCH_PUBLIC_ROOMS_DISMISS_ERROR:
|
||||||
|
// Dismiss the request failure error
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
fetchPublicRoomsError: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
14
src/features/room-admin/redux/initialState.js
Normal file
14
src/features/room-admin/redux/initialState.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Initial state is the place you define all initial values for the Redux store of the feature.
|
||||||
|
// In the 'standard' way, initialState is defined in reducers: http://redux.js.org/docs/basics/Reducers.html
|
||||||
|
// But when application grows, there will be multiple reducers files, it's not intuitive what data is managed by the whole store.
|
||||||
|
// So Rekit extracts the initial state definition into a separate module so that you can have
|
||||||
|
// a quick view about what data is used for the feature, at any time.
|
||||||
|
|
||||||
|
// NOTE: initialState constant is necessary so that Rekit could auto add initial state when creating async actions.
|
||||||
|
const initialState = {
|
||||||
|
fetchPublicRoomsPending: false,
|
||||||
|
fetchPublicRoomsError: null,
|
||||||
|
roomList: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default initialState;
|
25
src/features/room-admin/redux/reducer.js
Normal file
25
src/features/room-admin/redux/reducer.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// This is the root reducer of the feature. It is used for:
|
||||||
|
// 1. Load reducers from each action in the feature and process them one by one.
|
||||||
|
// Note that this part of code is mainly maintained by Rekit, you usually don't need to edit them.
|
||||||
|
// 2. Write cross-topic reducers. If a reducer is not bound to some specific action.
|
||||||
|
// Then it could be written here.
|
||||||
|
// Learn more from the introduction of this approach:
|
||||||
|
// https://medium.com/@nate_wang/a-new-approach-for-managing-redux-actions-91c26ce8b5da.
|
||||||
|
|
||||||
|
import initialState from './initialState';
|
||||||
|
import { reducer as fetchPublicRoomsReducer } from './fetchPublicRooms';
|
||||||
|
|
||||||
|
const reducers = [
|
||||||
|
fetchPublicRoomsReducer,
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function reducer(state = initialState, action) {
|
||||||
|
let newState;
|
||||||
|
switch (action.type) {
|
||||||
|
// Handle cross-topic actions here
|
||||||
|
default:
|
||||||
|
newState = state;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return reducers.reduce((s, r) => r(s, action), newState);
|
||||||
|
}
|
16
src/features/room-admin/route.js
Normal file
16
src/features/room-admin/route.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// This is the JSON way to define React Router rules in a Rekit app.
|
||||||
|
// Learn more from: http://rekit.js.org/docs/routing.html
|
||||||
|
|
||||||
|
import {
|
||||||
|
List,
|
||||||
|
} from './';
|
||||||
|
import { Layout } from '../common';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
path: 'room-admin',
|
||||||
|
name: 'Room admin',
|
||||||
|
component: Layout,
|
||||||
|
childRoutes: [
|
||||||
|
{ path: 'list', name: 'List', component: List, isIndex: true },
|
||||||
|
],
|
||||||
|
};
|
2
src/features/room-admin/style.scss
Normal file
2
src/features/room-admin/style.scss
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
@import '../../styles/mixins';
|
||||||
|
@import './List';
|
@ -3,3 +3,4 @@
|
|||||||
@import '../features/home/style';
|
@import '../features/home/style';
|
||||||
@import '../features/common/style';
|
@import '../features/common/style';
|
||||||
@import '../features/user-admin/style';
|
@import '../features/user-admin/style';
|
||||||
|
@import '../features/room-admin/style';
|
||||||
|
19
tests/features/room-admin/List.test.js
Normal file
19
tests/features/room-admin/List.test.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import { List } from '../../../src/features/room-admin/List';
|
||||||
|
|
||||||
|
describe('room-admin/List', () => {
|
||||||
|
it('renders node with correct class name', () => {
|
||||||
|
const props = {
|
||||||
|
roomAdmin: {},
|
||||||
|
actions: {},
|
||||||
|
};
|
||||||
|
const renderedComponent = shallow(
|
||||||
|
<List {...props} />
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
renderedComponent.find('.room-admin-list').length
|
||||||
|
).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
97
tests/features/room-admin/redux/fetchPublicRooms.test.js
Normal file
97
tests/features/room-admin/redux/fetchPublicRooms.test.js
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import configureMockStore from 'redux-mock-store';
|
||||||
|
import thunk from 'redux-thunk';
|
||||||
|
import nock from 'nock';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ROOM_ADMIN_FETCH_PUBLIC_ROOMS_BEGIN,
|
||||||
|
ROOM_ADMIN_FETCH_PUBLIC_ROOMS_SUCCESS,
|
||||||
|
ROOM_ADMIN_FETCH_PUBLIC_ROOMS_FAILURE,
|
||||||
|
ROOM_ADMIN_FETCH_PUBLIC_ROOMS_DISMISS_ERROR,
|
||||||
|
} from '../../../../src/features/room-admin/redux/constants';
|
||||||
|
|
||||||
|
import {
|
||||||
|
fetchPublicRooms,
|
||||||
|
dismissFetchPublicRoomsError,
|
||||||
|
reducer,
|
||||||
|
} from '../../../../src/features/room-admin/redux/fetchPublicRooms';
|
||||||
|
|
||||||
|
const middlewares = [thunk];
|
||||||
|
const mockStore = configureMockStore(middlewares);
|
||||||
|
|
||||||
|
describe('room-admin/redux/fetchPublicRooms', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
nock.cleanAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('dispatches success action when fetchPublicRooms succeeds', () => {
|
||||||
|
const store = mockStore({});
|
||||||
|
|
||||||
|
return store.dispatch(fetchPublicRooms())
|
||||||
|
.then(() => {
|
||||||
|
const actions = store.getActions();
|
||||||
|
expect(actions[0]).toHaveProperty('type', ROOM_ADMIN_FETCH_PUBLIC_ROOMS_BEGIN);
|
||||||
|
expect(actions[1]).toHaveProperty('type', ROOM_ADMIN_FETCH_PUBLIC_ROOMS_SUCCESS);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('dispatches failure action when fetchPublicRooms fails', () => {
|
||||||
|
const store = mockStore({});
|
||||||
|
|
||||||
|
return store.dispatch(fetchPublicRooms({ error: true }))
|
||||||
|
.catch(() => {
|
||||||
|
const actions = store.getActions();
|
||||||
|
expect(actions[0]).toHaveProperty('type', ROOM_ADMIN_FETCH_PUBLIC_ROOMS_BEGIN);
|
||||||
|
expect(actions[1]).toHaveProperty('type', ROOM_ADMIN_FETCH_PUBLIC_ROOMS_FAILURE);
|
||||||
|
expect(actions[1]).toHaveProperty('data.error', expect.anything());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns correct action by dismissFetchPublicRoomsError', () => {
|
||||||
|
const expectedAction = {
|
||||||
|
type: ROOM_ADMIN_FETCH_PUBLIC_ROOMS_DISMISS_ERROR,
|
||||||
|
};
|
||||||
|
expect(dismissFetchPublicRoomsError()).toEqual(expectedAction);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles action type ROOM_ADMIN_FETCH_PUBLIC_ROOMS_BEGIN correctly', () => {
|
||||||
|
const prevState = { fetchPublicRoomsPending: false };
|
||||||
|
const state = reducer(
|
||||||
|
prevState,
|
||||||
|
{ type: ROOM_ADMIN_FETCH_PUBLIC_ROOMS_BEGIN }
|
||||||
|
);
|
||||||
|
expect(state).not.toBe(prevState); // should be immutable
|
||||||
|
expect(state.fetchPublicRoomsPending).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles action type ROOM_ADMIN_FETCH_PUBLIC_ROOMS_SUCCESS correctly', () => {
|
||||||
|
const prevState = { fetchPublicRoomsPending: true };
|
||||||
|
const state = reducer(
|
||||||
|
prevState,
|
||||||
|
{ type: ROOM_ADMIN_FETCH_PUBLIC_ROOMS_SUCCESS, data: {} }
|
||||||
|
);
|
||||||
|
expect(state).not.toBe(prevState); // should be immutable
|
||||||
|
expect(state.fetchPublicRoomsPending).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles action type ROOM_ADMIN_FETCH_PUBLIC_ROOMS_FAILURE correctly', () => {
|
||||||
|
const prevState = { fetchPublicRoomsPending: true };
|
||||||
|
const state = reducer(
|
||||||
|
prevState,
|
||||||
|
{ type: ROOM_ADMIN_FETCH_PUBLIC_ROOMS_FAILURE, data: { error: new Error('some error') } }
|
||||||
|
);
|
||||||
|
expect(state).not.toBe(prevState); // should be immutable
|
||||||
|
expect(state.fetchPublicRoomsPending).toBe(false);
|
||||||
|
expect(state.fetchPublicRoomsError).toEqual(expect.anything());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles action type ROOM_ADMIN_FETCH_PUBLIC_ROOMS_DISMISS_ERROR correctly', () => {
|
||||||
|
const prevState = { fetchPublicRoomsError: new Error('some error') };
|
||||||
|
const state = reducer(
|
||||||
|
prevState,
|
||||||
|
{ type: ROOM_ADMIN_FETCH_PUBLIC_ROOMS_DISMISS_ERROR }
|
||||||
|
);
|
||||||
|
expect(state).not.toBe(prevState); // should be immutable
|
||||||
|
expect(state.fetchPublicRoomsError).toBe(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
14
tests/features/room-admin/redux/reducer.test.js
Normal file
14
tests/features/room-admin/redux/reducer.test.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import reducer from '../../../../src/features/room-admin/redux/reducer';
|
||||||
|
|
||||||
|
describe('room-admin/redux/reducer', () => {
|
||||||
|
it('does nothing if no matched action', () => {
|
||||||
|
const prevState = {};
|
||||||
|
const state = reducer(
|
||||||
|
prevState,
|
||||||
|
{ type: '__UNKNOWN_ACTION_TYPE__' }
|
||||||
|
);
|
||||||
|
expect(state).toBe(prevState);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: add global reducer test if needed.
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user