Added some more client APIs and refactored the client so it doesn't return a function

This commit is contained in:
Harrison Healey 2016-10-11 15:50:08 -04:00
parent a4c7e96cb6
commit 559ea98840
8 changed files with 276 additions and 109 deletions

View file

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

View file

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

View file

@ -6,11 +6,11 @@ import 'isomorphic-fetch';
const HEADER_AUTH = 'Authorization';
const HEADER_BEARER = 'BEARER';
const HEADER_REQUESTED_WITH = 'X-Requested-With';
const HEADER_TOKEN = 'token';
export default class Client {
constructor() {
this.teamId = '';
this.serverVersion = ''; // ??
this.logToConsole = false;
this.token = '';
this.url = '';
@ -26,10 +26,6 @@ export default class Client {
this.url = url;
}
setAcceptLanguage(locale) {
this.defaultHeaders['Accept-Language'] = locale;
}
setTeamId(id) {
this.teamId = id;
}
@ -42,10 +38,6 @@ export default class Client {
return this.teamId;
}
getServerVersion() {
return this.serverVersion;
}
getBaseRoute() {
return `${this.url}${this.urlVersion}`;
}
@ -114,27 +106,21 @@ export default class Client {
return `${this.url}${this.urlVersion}/users/${userId}`;
}
setTranslations(messages) {
this.translations = messages;
}
enableLogErrorsToConsole(enabled) {
this.logToConsole = enabled;
}
useHeaderToken() {
this.useToken = true;
if (this.token !== '') {
this.defaultHeaders[HEADER_AUTH] = `${HEADER_BEARER} ${this.token}`;
}
}
getOptions(options) {
const headers = {
[HEADER_REQUESTED_WITH]: 'XMLHttpRequest'
};
if (this.token) {
headers[HEADER_AUTH] = `${HEADER_BEARER} ${this.token}`;
}
return {
headers: {
[HEADER_AUTH]: this.token,
[HEADER_REQUESTED_WITH]: 'XMLHttpRequest'
},
headers,
...options
};
}
@ -178,26 +164,37 @@ export default class Client {
// User routes
// login(onRequest, onSuccess, onFailure, loginId, password, token) {
// const body = {
// login_id: loginId,
// password,
// token
// };
createUser = (onRequest, onSuccess, onFailure, user) => {
return this.doFetch(
`${this.getUsersRoute()}/create`,
{method: 'post', body: JSON.stringify(user)},
onRequest,
onSuccess,
onFailure
);
}
// return this.doFetch(
// `${this.getUsersRoute()}/login`,
// {method: 'post', body},
// onRequest,
// (data, response) => {
// console.log(response.headers);
// // if (response.headers.)
login = (onRequest, onSuccess, onFailure, loginId, password, token = null) => {
const body = {
login_id: loginId,
password,
token
};
// onSuccess(data, response);
// },
// onFailure
// );
// }
return this.doFetch(
`${this.getUsersRoute()}/login`,
{method: 'post', body: JSON.stringify(body)},
onRequest,
(data, response) => {
if (response.headers.has(HEADER_TOKEN)) {
this.token = response.headers.get(HEADER_TOKEN);
}
onSuccess(data, response);
},
onFailure
);
}
// getInitialLoad(success, error) {
// request.
@ -208,29 +205,41 @@ export default class Client {
// end(this.handleResponse.bind(this, 'getInitialLoad', success, error));
// }
// Team routes
createTeam = (onRequest, onSuccess, onFailure, team) => {
return this.doFetch(
`${this.getTeamsRoute()}/create`,
{method: 'post', body: JSON.stringify(team)},
onRequest,
onSuccess,
onFailure
);
}
doFetch = (url, options, onRequest, onSuccess, onFailure) => {
return () => {
if (onRequest) {
onRequest();
}
return fetch(url, this.getOptions(options)).then(
(response) => {
return response.json().then((data) => ({data, response}));
}).then(({data, response}) => {
if (!response.ok) {
return Promise.reject(data);
}
return onSuccess(data, response);
}).catch((err) => {
// TODO errors that return non-json data get sent here
if (this.logToConsole) {
console.log(err); // eslint-disable-line no-console
}
onFailure(err);
return fetch(url, this.getOptions(options)).then(
(response) => {
return response.json().then((data) => ({data, response}));
}).then(({data, response}) => {
if (!response.ok) {
return Promise.reject(data);
}
);
};
return onSuccess(data, response);
}).catch((err) => {
// TODO errors that return non-json data get sent here
if (this.logToConsole) {
console.log(err); // eslint-disable-line no-console
}
onFailure(err);
}
);
}
}

30
test/client.test.js Normal file
View file

@ -0,0 +1,30 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import assert from 'assert';
import TestHelper from './test_helper.js';
describe('Client', () => {
it('doFetch', (done) => {
const client = TestHelper.createClient();
let onRequestCalled = false;
client.doFetch(
`${client.getGeneralRoute()}/ping`,
{},
() => {
onRequestCalled = true;
},
() => {
assert.ok(onRequestCalled, 'onSuccess called before onRequest');
done();
},
(err) => {
done(new Error(err));
}
);
});
});

View file

@ -8,7 +8,8 @@ import TestHelper from './test_helper.js';
describe('Client.General', () => {
it('General.getClientConfig', (done) => {
TestHelper.initBasic(({client}) => {
const {onRequest, onSuccess, onFailure} = TestHelper.assertOnRequestHappensFirst(
client.getClientConfig(
null,
(data) => {
assert.ok(data.Version);
assert.ok(data.BuildNumber);
@ -21,14 +22,13 @@ describe('Client.General', () => {
done(new Error(err));
}
);
client.getClientConfig(onRequest, onSuccess, onFailure)();
});
});
it('General.getPing', (done) => {
TestHelper.initBasic(({client}) => {
const {onRequest, onSuccess, onFailure} = TestHelper.assertOnRequestHappensFirst(
client.getPing(
null,
() => {
done();
},
@ -36,14 +36,14 @@ describe('Client.General', () => {
done(new Error(err));
}
);
client.getPing(onRequest, onSuccess, onFailure)();
});
});
it('General.getPing - Invalid URL', (done) => {
TestHelper.initBasic(({client}) => {
const {onRequest, onSuccess, onFailure} = TestHelper.assertOnRequestHappensFirst(
client.setUrl('https://example.com/fake/url');
client.getPing(
null,
() => {
done(new Error('ping should\'ve failed'));
},
@ -51,24 +51,22 @@ describe('Client.General', () => {
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);
// TestHelper.initBasic(({client}) => {
// client.logClientError(
// null,
// (data) => {
// TestHelper.assertStatusOkay(data);
// done();
// },
// (err) => {
// done(new Error(err));
// }
// );
// Client.logClientError(onRequest, onSuccess, onFailure)();
// done();
// },
// (err) => {
// done(new Error(err));
// }
// )();
// });
// });
});

27
test/client_team.test.js Normal file
View file

@ -0,0 +1,27 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import assert from 'assert';
import TestHelper from './test_helper.js';
describe('Client.Team', () => {
it('createTeam', (done) => {
const client = TestHelper.createClient();
const team = TestHelper.fakeTeam();
client.createTeam(
null,
(data) => {
assert.equal(data.id.length > 0, true);
assert.equal(data.name, team.name);
done();
},
(err) => {
done(new Error(err));
},
team
);
});
});

58
test/client_user.test.js Normal file
View file

@ -0,0 +1,58 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import assert from 'assert';
import TestHelper from './test_helper.js';
describe('Client.User', () => {
it('createUser', (done) => {
const client = TestHelper.createClient();
const user = TestHelper.fakeUser();
client.createUser(
null,
(data) => {
assert.ok(data.id, 'id is empty');
assert.equal(data.email, user.email, 'email addresses aren\'t equal');
done();
},
(err) => {
done(new Error(err));
},
user
);
});
it('login', (done) => {
const client = TestHelper.createClient();
const user = TestHelper.fakeUser();
client.createUser(
null,
() => {
client.login(
null,
(data) => {
assert.ok(data.id, 'id is empty');
assert.equal(data.email, user.email, 'email addresses aren\'t equal');
assert.ok(client.token, 'token is empty');
done();
},
(err) => {
done(new Error(err));
},
user.email,
user.password
);
},
(err) => {
console.log(err);
done(new Error(err));
},
user
);
});
});

View file

@ -6,32 +6,36 @@ import assert from 'assert';
import Client from 'client/client.js';
class TestHelper {
assertOnRequestHappensFirst(onSuccess, onFailure) {
let hasReceivedOnRequest = false;
return {
onRequest: () => {
hasReceivedOnRequest = true;
},
onSuccess: (response, data) => {
assert(hasReceivedOnRequest);
onSuccess(response, data);
},
onFailure: (err) => {
assert(hasReceivedOnRequest);
onFailure(err);
}
};
constructor() {
this.basicClient = null;
}
assertStatusOkay(data) {
assertStatusOkay = (data) => {
assert(data);
assert(data.status === 'OK');
}
createClient() {
generateId = () => {
// Implementation taken from http://stackoverflow.com/a/2117523
let id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
id = id.replace(/[xy]/g, (c) => {
const r = Math.floor(Math.random() * 16);
let v;
if (c === 'x') {
v = r;
} else {
v = (r & 0x3) | 0x8;
}
return v.toString(16);
});
return 'uid' + id;
}
createClient = () => {
const client = new Client();
client.setUrl('http://localhost:8065');
@ -39,7 +43,48 @@ class TestHelper {
return client;
}
initBasic(callback) {
fakeEmail = () => {
return 'success' + this.generateId() + '@simulator.amazonses.com';
}
fakeUser = () => {
return {
email: this.fakeEmail(),
allow_marketing: true,
password: 'password1',
username: this.generateId()
};
}
fakeTeam = () => {
const name = this.generateId();
return {
name,
display_name: `Unit Test ${name}`,
type: 'O',
email: this.fakeEmail(),
allowed_domains: ''
};
}
fakeChannel = () => {
const name = this.generateId();
return {
name,
display_name: `Unit Test ${name}`,
type: 'O'
};
}
fakePost = () => {
return {
message: `Unit Test ${this.generateId()}`
};
}
initBasic = (callback) => {
const client = this.createClient();
callback({client});