From b86718f46783507d75da428a97eebd9deaea54db Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Tue, 11 Oct 2016 11:21:15 -0400 Subject: [PATCH] Started adding separate client tests from redux tests --- .eslintrc.json | 1 + package.json | 2 +- src/actions/client.js | 77 +++++++++++++++++++++++++--- src/actions/general.js | 54 ++++++++++--------- src/actions/helpers.js | 12 ++--- src/components/select_server_view.js | 8 +-- test/actions/general.test.js | 60 +++++++++++++++------- test/client_general.test.js | 73 ++++++++++++++++++++++++++ test/test_helper.js | 29 +++++++++++ 9 files changed, 255 insertions(+), 61 deletions(-) create mode 100644 test/client_general.test.js create mode 100644 test/test_helper.js diff --git a/.eslintrc.json b/.eslintrc.json index 34f6ab393..3746784cd 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -25,6 +25,7 @@ "it": true, "expect": true, "before": true, + "beforeEach": true, "after": true }, "rules": { diff --git a/package.json b/package.json index acf7a8ca6..275697cf5 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/src/actions/client.js b/src/actions/client.js index 8d4997479..024cbb496 100644 --- a/src/actions/client.js +++ b/src/actions/client.js @@ -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 diff --git a/src/actions/general.js b/src/actions/general.js index cd7113b09..a27db4b49 100644 --- a/src/actions/general.js +++ b/src/actions/general.js @@ -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); -// }; -// } \ No newline at end of file +export function logClientError(message, level = 'ERROR') { + return bindClientFunc( + Client.logClientError, + LOG_CLIENT_ERROR_REQUEST, + LOG_CLIENT_ERROR_SUCCESS, + LOG_CLIENT_ERROR_FAILURE, + message, + level + ); +} \ No newline at end of file diff --git a/src/actions/helpers.js b/src/actions/helpers.js index f1a14818b..4409b7779 100644 --- a/src/actions/helpers.js +++ b/src/actions/helpers.js @@ -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); }; } \ No newline at end of file diff --git a/src/components/select_server_view.js b/src/components/select_server_view.js index 883aa7ee8..1846a9a3d 100644 --- a/src/components/select_server_view.js +++ b/src/components/select_server_view.js @@ -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); diff --git a/test/actions/general.test.js b/test/actions/general.test.js index 8011e78ba..2f6a080fe 100644 --- a/test/actions/general.test.js +++ b/test/actions/general.test.js @@ -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(); + // }); + // }); }); diff --git a/test/client_general.test.js b/test/client_general.test.js new file mode 100644 index 000000000..14dcf0793 --- /dev/null +++ b/test/client_general.test.js @@ -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)(); + // }); +}); diff --git a/test/test_helper.js b/test/test_helper.js new file mode 100644 index 000000000..2e99a868e --- /dev/null +++ b/test/test_helper.js @@ -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'); +}