Started adding separate client tests from redux tests

This commit is contained in:
Harrison Healey 2016-10-11 11:21:15 -04:00
parent d4dbf0f70b
commit b86718f467
9 changed files with 255 additions and 61 deletions

View file

@ -25,6 +25,7 @@
"it": true,
"expect": true,
"before": true,
"beforeEach": true,
"after": true
},
"rules": {

View file

@ -28,7 +28,7 @@
"scripts": {
"check": "eslint --ext \".jsx\" --ignore-pattern node_modules --quiet .",
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "mocha --compilers js:babel-register test/**/*.test.js",
"test": "mocha --compilers js:babel-register **/*.test.js",
"postinstall": "remotedev-debugger --hostname localhost --port 5678 --injectserver"
},
"babel": {

View file

@ -139,27 +139,88 @@ export class Client {
};
}
getPing = (onRequest, onSuccess, onFailure) => {
return this.doFetch(`${this.getGeneralRoute()}/ping`, {method: 'get'}, onRequest, onSuccess, onFailure);
}
// General routes
getClientConfig = (onRequest, onSuccess, onFailure) => {
return this.doFetch(`${this.getGeneralRoute()}/client_props`, {method: 'get'}, onRequest, onSuccess, onFailure);
return this.doFetch(
`${this.getGeneralRoute()}/client_props`,
{method: 'get'},
onRequest,
onSuccess,
onFailure
);
}
getPing = (onRequest, onSuccess, onFailure) => {
return this.doFetch(
`${this.getGeneralRoute()}/ping`,
{method: 'get'},
onRequest,
onSuccess,
onFailure
);
}
logClientError = (onRequest, onSuccess, onFailure, message, level = 'ERROR') => {
const body = {
message,
level
};
return this.doFetch(
`${this.getGeneralRoute()}/log_client_error`,
{method: 'post', body},
onRequest,
onSuccess,
onFailure
);
}
// User routes
// login(onRequest, onSuccess, onFailure, loginId, password, token) {
// const body = {
// login_id: loginId,
// password,
// token
// };
// return this.doFetch(
// `${this.getUsersRoute()}/login`,
// {method: 'post', body},
// onRequest,
// (data, response) => {
// console.log(response.headers);
// // if (response.headers.)
// onSuccess(data, response);
// },
// onFailure
// );
// }
// getInitialLoad(success, error) {
// request.
// get(`${this.getUsersRoute()}/initial_load`).
// set(this.defaultHeaders).
// type('application/json').
// accept('application/json').
// end(this.handleResponse.bind(this, 'getInitialLoad', success, error));
// }
doFetch = (url, options, onRequest, onSuccess, onFailure) => {
return () => {
onRequest();
return fetch(url, this.getOptions(options)).then(
(response) => {
return response.json().then((json) => ({json, response}));
}).then(({response, json}) => {
return response.json().then((data) => ({data, response}));
}).then(({data, response}) => {
if (!response.ok) {
return Promise.reject(json);
return Promise.reject(data);
}
return onSuccess(json);
return onSuccess(data, response);
}).catch((err) => {
if (this.logToConsole) {
console.log(err); // eslint-disable-line no-console

View file

@ -8,31 +8,39 @@ export const PING_REQUEST = 'PING_REQUEST';
export const PING_SUCCESS = 'PING_SUCCESS';
export const PING_FAILURE = 'PING_FAILURE';
export function loadPing() {
return bindClientFunc(Client.getPing, PING_REQUEST, PING_SUCCESS, PING_FAILURE);
export function getPing() {
return bindClientFunc(
Client.getPing,
PING_REQUEST,
PING_SUCCESS,
PING_FAILURE
);
}
// export const CLIENT_CONFIG_REQUEST = 'CLIENT_CONFIG_REQUEST';
// export const CLIENT_CONFIG_SUCCESS = 'CLIENT_CONFIG_SUCCESS';
// export const CLIENT_CONFIG_FAILURE = 'CLIENT_CONFIG_FAILURE';
export const CLIENT_CONFIG_REQUEST = 'CLIENT_CONFIG_REQUEST';
export const CLIENT_CONFIG_SUCCESS = 'CLIENT_CONFIG_SUCCESS';
export const CLIENT_CONFIG_FAILURE = 'CLIENT_CONFIG_FAILURE';
// function fetchClientConfig() {
// return (dispatch) => {
// dispatch(requestData(CLIENT_CONFIG_REQUEST));
export function getClientConfig() {
return bindClientFunc(
Client.getClientConfig,
CLIENT_CONFIG_REQUEST,
CLIENT_CONFIG_SUCCESS,
CLIENT_CONFIG_FAILURE
);
}
// Client.getClientConfig(
// (data) => {
// dispatch(requestSuccess(CLIENT_CONFIG_SUCCESS, data));
// },
// (err) => {
// dispatch(requestFailure(CLIENT_CONFIG_FAILURE, err));
// }
// );
// };
// }
export const LOG_CLIENT_ERROR_REQUEST = 'LOG_CLIENT_ERROR_REQUEST';
export const LOG_CLIENT_ERROR_SUCCESS = 'LOG_CLIENT_ERROR_SUCCESS';
export const LOG_CLIENT_ERROR_FAILURE = 'LOG_CLIENT_ERROR_FAILURE';
// export function loadClientConfig() {
// return (dispatch, getState) => {
// return dispatch(Client.getClientConfig(CLIENT_CONFIG_REQUEST, CLIENT_CONFIG_SUCCESS, CLIENT_CONFIG_FAILURE), getState);
// };
// }
export function logClientError(message, level = 'ERROR') {
return bindClientFunc(
Client.logClientError,
LOG_CLIENT_ERROR_REQUEST,
LOG_CLIENT_ERROR_SUCCESS,
LOG_CLIENT_ERROR_FAILURE,
message,
level
);
}

View file

@ -30,20 +30,20 @@ export function emptyError() {
};
}
export function bindClientFunc(clientFunc, request, success, failure) {
export function bindClientFunc(clientFunc, request, success, failure, ...args) {
return (dispatch, getState) => {
function onRequest() {
dispatch(requestData(request));
dispatch(requestData(request), getState);
}
function onSuccess(json) {
dispatch(requestSuccess(success, json));
function onSuccess(data) {
dispatch(requestSuccess(success, data), getState);
}
function onFailure(err) {
dispatch(requestFailure(failure, err));
dispatch(requestFailure(failure, err), getState);
}
return dispatch(clientFunc(onRequest, onSuccess, onFailure), getState);
return dispatch(clientFunc(onRequest, onSuccess, onFailure, ...args), getState);
};
}

View file

@ -5,7 +5,7 @@ import React, {Component} from 'react';
import Client from 'actions/client.js';
import {connect} from 'react-redux';
import {loadPing} from 'actions/general.js';
import {getPing} from 'actions/general.js';
import Button from './button.js';
import {AsyncStorage, Image, StyleSheet, Text, TextInput, View} from 'react-native';
@ -32,7 +32,7 @@ const styles = StyleSheet.create({
class SelectServerView extends Component {
static propTypes = {
onProceed: React.PropTypes.func.isRequired,
loadPing: React.PropTypes.func.isRequired,
getPing: React.PropTypes.func.isRequired,
ping: React.PropTypes.object.isRequired,
device: React.PropTypes.object.isRequired
}
@ -48,7 +48,7 @@ class SelectServerView extends Component {
onClick = () => {
Client.setUrl(this.state.serverUrl);
this.props.loadPing().then(() => {
this.props.getPing().then(() => {
AsyncStorage.setItem('serverUrl', this.state.serverUrl, () => {
if (!this.props.ping.error) {
this.props.onProceed();
@ -95,5 +95,5 @@ function mapStateToProps(state) {
}
export default connect(mapStateToProps, {
loadPing
getPing
})(SelectServerView);

View file

@ -1,42 +1,57 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import assert from 'assert';
import * as Actions from 'actions/general.js';
import Client from 'actions/client.js';
import configureStore from 'store/configureStore.js';
describe('General Actions', () => {
// it('getClientConfig', (done) => {
// const store = configureStore();
// store.subscribe(() => {
// expect(store.getState().entities.general.clientConfig.error).toEqual({});
// if (store.getState().entities.general.clientConfig.data.Version &&
// store.getState().entities.general.clientConfig.data.Version.length > 0) {
// done();
// }
// });
describe('Actions.General', () => {
beforeEach(() => {
Client.setUrl('http://localhost:8065');
});
// Actions.loadClientConfig()(store.dispatch, store.getState);
// });
it('Actions.General.getClientConfig', (done) => {
const store = configureStore();
store.subscribe(() => {
const clientConfig = store.getState().entities.general.clientConfig;
it('Get ping basic success', (done) => {
if (!clientConfig.loading) {
if (clientConfig.error) {
done(new Error(clientConfig.error));
} else {
// Check a few basic fields since they may change over time
assert.ok(clientConfig.data.Version);
assert.ok(clientConfig.data.BuildNumber);
assert.ok(clientConfig.data.BuildDate);
assert.ok(clientConfig.data.BuildHash);
done();
}
}
});
Actions.getClientConfig()(store.dispatch, store.getState);
});
it('Actions.General.getPing', (done) => {
const store = configureStore();
store.subscribe(() => {
const ping = store.getState().entities.general.ping;
if (ping.error) {
done.fail(ping.error);
done(new Error(ping.error));
} else if (!ping.loading) {
done();
}
});
Client.setUrl('https://pre-release.mattermost.com');
Actions.loadPing()(store.dispatch, store.getState);
Actions.getPing()(store.dispatch, store.getState);
});
it('Get ping fail with invalid url', (done) => {
it('Actions.General.getPing - Invalid URL', (done) => {
const store = configureStore();
store.subscribe(() => {
@ -47,7 +62,14 @@ describe('General Actions', () => {
}
});
Client.setUrl('https://example.com');
Actions.loadPing()(store.dispatch, store.getState);
Client.setUrl('https://example.com/fake/url');
Actions.getPing()(store.dispatch, store.getState);
});
// it('General.logClientError', function(done) {
// TestHelper.initBasic(() => {
// TestHelper.basicClient().logClientError('this is a test');
// done();
// });
// });
});

View file

@ -0,0 +1,73 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import assert from 'assert';
import Client from 'actions/client.js';
import * as TestHelper from './test_helper.js';
describe('Client.General', () => {
beforeEach(() => {
Client.setUrl('http://localhost:8065');
});
it('General.getClientConfig', (done) => {
const {onRequest, onSuccess, onFailure} = TestHelper.assertOnRequestHappensFirst(
(data) => {
assert.ok(data.Version);
assert.ok(data.BuildNumber);
assert.ok(data.BuildDate);
assert.ok(data.BuildHash);
done();
},
(err) => {
done(new Error(err));
}
);
Client.getClientConfig(onRequest, onSuccess, onFailure)();
});
it('General.getPing', (done) => {
const {onRequest, onSuccess, onFailure} = TestHelper.assertOnRequestHappensFirst(
() => {
done();
},
(err) => {
done(new Error(err));
}
);
Client.getPing(onRequest, onSuccess, onFailure)();
});
it('General.getPing - Invalid URL', (done) => {
const {onRequest, onSuccess, onFailure} = TestHelper.assertOnRequestHappensFirst(
() => {
done(new Error('ping should\'ve failed'));
},
() => {
done();
}
);
Client.setUrl('https://example.com/fake/url');
Client.getPing(onRequest, onSuccess, onFailure)();
});
// it('General.logClientError', function(done) {
// const {onRequest, onSuccess, onFailure} = TestHelper.assertOnRequestHappensFirst(
// (data) => {
// TestHelper.assertStatusOkay(data);
// done();
// },
// (err) => {
// done(new Error(err));
// }
// );
// Client.logClientError(onRequest, onSuccess, onFailure)();
// });
});

29
test/test_helper.js Normal file
View file

@ -0,0 +1,29 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import assert from 'assert';
export function assertOnRequestHappensFirst(onSuccess, onFailure) {
let hasReceivedOnRequest = false;
return {
onRequest: () => {
hasReceivedOnRequest = true;
},
onSuccess: (response, data) => {
assert(hasReceivedOnRequest);
onSuccess(response, data);
},
onFailure: (err) => {
assert(hasReceivedOnRequest);
onFailure(err);
}
};
}
export function assertStatusOkay(data) {
assert(data);
assert(data.status === 'OK');
}