From 8611b3e28a740461fac16f74b0a3d2c4a68f0fd9 Mon Sep 17 00:00:00 2001 From: Thomas Hopkins Date: Mon, 17 Oct 2016 11:37:18 -0700 Subject: [PATCH] Use fetch-mock to mock requests in tests (#18) * Use fetch-mock to mock requests in tests * Use flag to enable/disable fetch-mock --- package.json | 1 + src/client/client.js | 6 +- test/client/client.test.js | 31 +++++++- test/fetch_mock.js | 20 +++++ test/sanity.test.js | 7 +- test/test_helper.js | 152 ++++++++++++++++++++++++++++++++++++- 6 files changed, 213 insertions(+), 4 deletions(-) create mode 100644 test/fetch_mock.js diff --git a/package.json b/package.json index 8f6eb75f5..8196a7714 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "babel-register": "6.16.3", "eslint": "3.7.1", "eslint-plugin-react": "6.3.0", + "fetch-mock": "5.5.0", "mocha": "3.1.0", "react-native-mock": "0.2.7", "react-test-renderer": "15.3.2", diff --git a/src/client/client.js b/src/client/client.js index 488e73bbb..660e94e68 100644 --- a/src/client/client.js +++ b/src/client/client.js @@ -247,7 +247,11 @@ export default class Client { try { const response = await fetch(url, this.getOptions(options)); const data = await response.json(); - return response.ok ? onSuccess(data, response) : Promise.reject(data); + if (response.ok) { + return onSuccess(data, response); + } + const {message} = data; + throw new Error(message || 'Failed to fetch'); } catch (err) { if (this.logToConsole) { console.log(err); // eslint-disable-line no-console diff --git a/test/client/client.test.js b/test/client/client.test.js index 3aa7718c4..13c4a8b35 100644 --- a/test/client/client.test.js +++ b/test/client/client.test.js @@ -2,9 +2,38 @@ // See License.txt for license information. import assert from 'assert'; - +import fetchMock from 'fetch_mock'; import TestHelper from 'test_helper.js'; +const fakeNotFoundResp = { + status: 404, + body: { + id: 'api.context.404.app_error', + message: 'Sorry, we could not find the page.', + detailed_error: [ + "There doesn't appear to be an api call for the url='/api/v3/fake/url/general/ping'.", + 'Typo? are you missing a team_id or user_id as part of the url?' + ].join(' '), + status_code: 404 + } +}; + +fetchMock.get(/\/ping/, (url) => { + if (url.match(/\/fake\/url/)) { + return fakeNotFoundResp; + } + return { + server_time: `${Date.now()}`, + version: '3.4.0' + }; +}); + +fetchMock.post(/\/log_client/, { + status: 200, + headers: {'Content-Type': 'application/json'}, + body: {status: 'OK'} +}); + describe('Client', () => { it('doFetch', (done) => { const client = TestHelper.createClient(); diff --git a/test/fetch_mock.js b/test/fetch_mock.js new file mode 100644 index 000000000..e12e1f38d --- /dev/null +++ b/test/fetch_mock.js @@ -0,0 +1,20 @@ +/* eslint-disable no-empty-function */ + +// set this to false to allow requests to server in test suite +const MOCK_FETCH = false; + +let fetchMock = { + mock: () => {}, + delete: () => {}, + get: () => {}, + head: () => {}, + patch: () => {}, + post: () => {}, + put: () => {} +}; + +if (MOCK_FETCH) { + fetchMock = require('fetch-mock'); +} + +export default fetchMock; diff --git a/test/sanity.test.js b/test/sanity.test.js index 4e1d5fb4c..64130158e 100644 --- a/test/sanity.test.js +++ b/test/sanity.test.js @@ -2,6 +2,11 @@ // See License.txt for license information. import 'react-native'; +import fetchMock from 'fetch_mock'; + +fetchMock.get('http://example.com', { + status: 200 +}); // Ensure that everything is imported correctly for testing describe('Sanity test', () => { @@ -20,4 +25,4 @@ describe('Sanity test', () => { done.fail(err); }); }); -}); \ No newline at end of file +}); diff --git a/test/test_helper.js b/test/test_helper.js index 4f1fe2925..b9809fb70 100644 --- a/test/test_helper.js +++ b/test/test_helper.js @@ -2,10 +2,160 @@ // See License.txt for license information. import assert from 'assert'; - +import fetchMock from 'fetch_mock'; import Client from 'client/client.js'; import Config from 'config/config.js'; +const fakeUserId = '146677bbcefgjjmmnpqqrruxyz'; +const fakeTeamId = '1378899bbcddefghknnpqsttyz'; +const fakeChannelId = '1335568899aaccefkkmmpprtwz'; +const fakePostId = '346aabceeffhhikopruuwxyyyy'; +const fakeTimestamp = Date.now(); + +const fakeTeamRespBody = { + id: fakeTeamId, + create_at: fakeTimestamp, + update_at: fakeTimestamp, + delete_at: 0, + display_name: `est-eam-${fakeTimestamp}`, + name: `est-eam-${fakeTimestamp}`, + email: '', + type: 'O', + company_name: '', + allowed_domains: '', + invite_id: '', + allow_open_invite: false +}; +const fakeChannelRespBody = { + id: fakeChannelId, + create_at: fakeTimestamp, + update_at: fakeTimestamp, + delete_at: 0, + team_id: fakeTeamId, + type: 'O', + display_name: 'bestchannel', + name: 'bestchannel', + header: '', + purpose: '', + last_post_at: 0, + total_msg_count: 0, + extra_update_at: fakeTimestamp, + creator_id: fakeUserId +}; +const fakePostRespBody = { + id: fakePostId, + create_at: fakeTimestamp, + update_at: fakeTimestamp, + delete_at: 0, + user_id: fakeUserId, + channel_id: fakeChannelId, + root_id: '', + parent_id: '', + original_id: '', + message: 'TEST POST', + type: '', + props: {}, + hashtags: '', + pending_post_id: '' +}; +const fakeUserRespBody = { + id: fakeUserId, + create_at: fakeTimestamp, + update_at: fakeTimestamp, + delete_at: 0, + username: 'testuser', + auth_data: '', + auth_service: '', + email: 'testuser', + nickname: '', + first_name: '', + last_name: '', + roles: 'system_user', + allow_marketing: true, + notify_props: { + channel: 'true', + desktop: 'all', + desktop_sound: 'true', + email: 'true', + first_name: 'false', + mention_keys: 'testuser,@testuser', + push: 'mention' + }, + last_password_update: fakeTimestamp, + locale: 'en' +}; +const fakeClientConfig = { + Version: '3.4.0', + BuildNumber: 'dev', + BuildDate: 'Wed Dec 14 23:59:59 UTC 2016', + BuildHash: '01111123555566677788888888abbbbcccccdeff' +}; +const fakeInitLoadRespBody = { + user: fakeUserRespBody, + team_members: [{ + team_id: fakeTeamId, + user_id: fakeUserId, + roles: 'team_user team_admin', + delete_at: 0 + }], + teams: [fakeTeamRespBody], + direct_profiles: {}, + preferences: [{ + user_id: fakeUserId, + category: 'last', + name: 'channel', + value: fakeChannelId + }, { + user_id: fakeUserId, + category: 'tutorial_step', + name: fakeUserId, + value: '1' + }], + client_cfg: fakeClientConfig, + license_cfg: { + IsLicensed: 'false' + }, + no_accounts: false +}; + +fetchMock.post(/\/users\/create$/, (url, opts) => ({ + headers: {'Content-Type': 'application/json'}, + body: {...fakeUserRespBody, ...JSON.parse(opts.body)} +})); +fetchMock.post(/\/users\/login$/, (url, opts) => { + const reqBody = JSON.parse(opts.body); + return { + headers: { + 'Content-Type': 'application/json', + token: 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' + }, + body: {...fakeUserRespBody, + ...reqBody, + email: reqBody.login_id + } + }; +}); +fetchMock.post(/\/teams\/create/, (url, opts) => ({ + headers: {'Content-Type': 'application/json'}, + body: {...fakeTeamRespBody, ...JSON.parse(opts.body)} +})); +fetchMock.post(/\/channels\/create/, (url, opts) => ({ + headers: {'Content-Type': 'application/json'}, + body: {...fakeChannelRespBody, ...JSON.parse(opts.body)} +})); +fetchMock.post(/\/posts\/create$/, { + headers: {'Content-Type': 'application/json'}, + body: fakePostRespBody +}); +fetchMock.get(/\/users\/initial_load$/, { + headers: {'Content-Type': 'application/json'}, + body: fakeInitLoadRespBody +}); +fetchMock.get(/\/general\/client_props$/, { + headers: {'Content-Type': 'application/json'}, + body: fakeClientConfig +}); + const PASSWORD = 'password1'; class TestHelper {