test/unit/services.user.profile.js
import test from 'ava';
import nock from 'nock';
import {
client,
userService,
Profile,
User,
} from '../../src';
test.before('start server', (t) => {
t.context.storage = client.storageUtility;
client.apiBaseUrl = 'https://somesite.Clinical6.com';
t.context.deleteAttributeResponse = {
status: 'ok',
message: 'Profile value was successfully deleted'
};
t.context.getAttributeResponseAll = {
status: 'ok',
content: [{
id: 2,
value: '2',
profile_attribute_id: 1,
profile_id: 5,
created_at: '2016-07-27T23:38:59.000Z',
updated_at: '2016-07-27T23:38:59.000Z',
recurrent_capture_id: null,
recurrent_capture_type: null
}, {
id: 3,
value: '2',
profile_attribute_id: 1,
profile_id: 5,
created_at: '2016-07-28T01:30:28.000Z',
updated_at: '2016-07-28T01:30:28.000Z',
recurrent_capture_id: null,
recurrent_capture_type: null
}
],
total_pages: 1
};
t.context.getAttributesResponse = {
status: 'ok',
content: [],
total_pages: 1
};
t.context.getProfileResponse = {
data: {
id: '164',
type: 'profiles',
attributes: {
height: 170,
diabetes: true,
cancer: false,
created_at: '2017-08-14T22:55:55Z',
updated_at: '2017-08-14T22:55:55Z',
first_name: 'Brisa',
middle_initial: null,
last_name: 'Bailey',
prefix: null,
suffix: null,
gender: 'male',
ethnicity: '',
occupation: null,
avatar: {
url: '/uploads/test/profile/avatar/164/1.png',
small: {
url: '/uploads/test/profile/avatar/164/small_1.png'
},
main: {
url: '/uploads/test/profile/avatar/164/main_1.png'
},
thumb: {
url: '/uploads/test/profile/avatar/164/thumb_1.png'
}
},
username: null,
dob: null,
street: null,
city: null,
zip_code: null,
timezone: 'UTC'
},
relationships: {
profileable: {
data: {
id: '161',
type: 'mobile_users'
}
}
}
}
};
t.context.getAttributesHiddenResponse = {
status: 'ok',
content: [{
allow_multiple_values: null,
api_key: 'fairfax_resident',
attribute_type: 'list',
created_at: '2014-09-11T23:53:03Z',
id: 1,
is_recurrent_capture: false,
is_visible: null,
name: 'Fairfax Resident',
options: ['Non Resident', 'Resident'],
updated_at: '2014-09-12T00:18:02Z'
}],
total_pages: 1
};
t.context.getAttributesIncludedResponse = {
status: 'ok',
content: [{
allow_multiple_values: null,
api_key: 'fairfax_resident',
attribute_type: 'list',
created_at: '2014-09-11T23:53:03Z',
id: 1,
is_recurrent_capture: false,
is_visible: null,
name: 'Fairfax Resident',
options: ['Non Resident', 'Resident'],
updated_at: '2014-09-12T00:18:02Z'
}],
total_pages: 1
};
t.context.getAttributesAllResponse = {
status: 'ok',
content: [{
allow_multiple_values: null,
api_key: 'fairfax_resident',
attribute_type: 'list',
created_at: '2014-09-11T23:53:03Z',
id: 1,
is_recurrent_capture: false,
is_visible: null,
name: 'Fairfax Resident',
options: ['Non Resident', 'Resident'],
updated_at: '2014-09-12T00:18:02Z'
}],
total_pages: 1
};
t.context.updateProfileResponse = {
data: {
id: '167',
type: 'profiles',
attributes: {
height: 180,
diabetes: true,
cancer: false,
created_at: '2017-08-14T22:55:55Z',
updated_at: '2017-08-14T22:55:55Z',
first_name: 'Davion',
middle_initial: null,
last_name: 'Kunde',
prefix: null,
suffix: null,
gender: 'male',
ethnicity: '',
occupation: 'doctor',
avatar: {
url: '/uploads/test/profile/avatar/167/1.png',
small: {
url: '/uploads/test/profile/avatar/167/small_1.png'
},
main: {
url: '/uploads/test/profile/avatar/167/main_1.png'
},
thumb: {
url: '/uploads/test/profile/avatar/167/thumb_1.png'
}
},
username: null,
dob: null,
street: null,
city: null,
zip_code: null,
timezone: 'UTC'
},
relationships: {
profileable: {
data: {
id: '164',
type: 'mobile_users'
}
}
}
}
};
t.context.updateProfileV2Response = {
status: 'ok',
id: 1,
content: {
id: 1,
value: '321',
profile_attribute_id: 1,
profile_id: 5,
created_at: '2016-07-27T23:17:04.000Z',
updated_at: '2016-07-28T15:20:58.111Z',
recurrent_capture_id: null,
recurrent_capture_type: null
}
};
});
test.after('server shut down', () => {});
test.beforeEach(() => {
client.authToken = 'valid_token';
client.cache = 'never';
});
// UserService.insertProfileAttribute method
/**
* @test {UserService.insertProfileAttribute}
*/
test.serial('[unit] UserService.insertProfileAttribute should throw an error when there is no authToken', async (t) => {
client.authToken = undefined;
const expectedError = 'UserService.insertProfileAttribute error: requires authToken '
+ 'and key is not defined and val is not defined';
await t.throwsAsync(userService.insertProfileAttribute(), expectedError);
});
/**
* @test {UserService.insertProfileAttribute}
*/
test('[unit] UserService.insertProfileAttribute should throw an error when the required parameters are not provided', async (t) => {
const expectedError = 'UserService.insertProfileAttribute error: key is not defined'
+ ' and val is not defined';
await t.throwsAsync(userService.insertProfileAttribute(), expectedError);
});
/**
* @test {UserService.insertProfileAttribute}
*/
test('[unit] UserService.insertProfileAttribute should successfully create a new profile attribute with the required parameters', async (t) => {
let request = {};
nock(client.apiBaseUrl).post(`/api/profile_attributes`).reply(function (uri, requestBody) {
request = this.req;
request.requestBody = requestBody;
return [201, {
status: 'ok',
id: 1,
content: {
id: 1,
value: '2',
profile_attribute_id: 1,
profile_id: 5,
created_at: '2016-07-27T23:17:04.825Z',
updated_at: '2016-07-27T23:17:04.825Z',
recurrent_capture_id: null,
recurrent_capture_type: null
}
}];
});
const response = await userService.insertProfileAttribute('example', 2);
t.is(request.path, `/api/profile_attributes`);
t.is(request.headers.accept, 'application/json');
t.is(request.headers['content-type'], 'application/json');
t.is(request.headers.authorization, 'Token token=valid_token');
t.truthy(response);
t.is(response.status, 'ok');
t.is(response.id, 1);
t.is(response.content.id, 1);
t.is(response.content.value, '2');
t.is(response.content.profile_attribute_id, 1);
t.is(response.content.profile_id, 5);
t.is(response.content.created_at, '2016-07-27T23:17:04.825Z');
t.is(response.content.updated_at, '2016-07-27T23:17:04.825Z');
t.is(response.content.recurrent_capture_id, null);
t.is(response.content.recurrent_capture_type, null);
});
// UserService.deleteProfileAttribute method
/**
* @test {UserService.deleteProfileAttribute}
*/
test.serial('[unit] UserService.deleteProfileAttribute should throw an error when there is no authToken', async (t) => {
client.authToken = undefined;
const expectedError = 'UserService.deleteProfileAttribute error: requires authToken and id is not defined';
await t.throwsAsync(userService.deleteProfileAttribute(), expectedError);
});
/**
* @test {UserService.deleteProfileAttribute}
*/
test('[unit] UserService.deleteProfileAttribute should throw an error when there is no id parameter', async (t) => {
const expectedError = 'UserService.deleteProfileAttribute error: id is not defined';
await t.throwsAsync(userService.deleteProfileAttribute(), expectedError);
});
/**
* @test {UserService.deleteProfileAttribute}
*/
test('[unit] UserService.deleteProfileAttribute should successfully delete a user profile attribute value with an id value', async (t) => {
const { deleteAttributeResponse } = t.context;
let request = {};
nock(client.apiBaseUrl).delete(`/api/profile_attributes/1`).reply(function (uri, requestBody) {
request = this.req;
request.requestBody = requestBody;
return [200, deleteAttributeResponse];
});
const response = await userService.deleteProfileAttribute(1);
t.is(request.path, `/api/profile_attributes/1`);
t.is(request.headers.accept, 'application/json');
t.is(request.headers['content-type'], 'application/json');
t.is(request.headers.authorization, 'Token token=valid_token');
t.is(response.status, 'ok');
t.is(response.message, 'Profile value was successfully deleted');
});
// UserService.getAllProfileAttributes method
/**
* @test {UserService.getAllProfileAttributes}
*/
test.serial('[unit] UserService.getAllProfileAttributes should throw an error when there is no authToken', async (t) => {
client.authToken = undefined;
const expectedError = 'UserService.getAllProfileAttributes error: requires authToken and apiKey is not defined';
await t.throwsAsync(userService.getAllProfileAttributes(), expectedError);
});
/**
* @test {UserService.getAllProfileAttributes}
*/
test('[unit] UserService.getAllProfileAttributes should throw an error when there is no apiKey parameter', async (t) => {
const expectedError = 'UserService.getAllProfileAttributes error: apiKey is not defined';
await t.throwsAsync(userService.getAllProfileAttributes(), expectedError);
});
/**
* @test {UserService.getAllProfileAttributes}
*/
test('[unit] UserService.getAllProfileAttributes should successfully get all profile attribute values', async (t) => {
const { getAttributeResponseAll } = t.context;
nock(client.apiBaseUrl).get(`/api/profile_attributes/example`).reply(200, getAttributeResponseAll);
const response = await userService.getAllProfileAttributes('example');
t.truthy(response);
t.is(Object.keys(response).length, 3);
t.is(response.status, 'ok');
t.is(response.content[0].id, 2);
t.is(response.content[0].value, '2');
t.is(response.content[0].profile_attribute_id, 1);
t.is(response.content[0].profile_id, 5);
t.is(response.content[0].created_at, '2016-07-27T23:38:59.000Z');
t.is(response.content[0].updated_at, '2016-07-27T23:38:59.000Z');
t.is(response.content[0].recurrent_capture_id, null);
t.is(response.content[0].recurrent_capture_type, null);
t.is(response.content[1].id, 3);
t.is(response.content[1].value, '2');
t.is(response.content[1].profile_attribute_id, 1);
t.is(response.content[1].profile_id, 5);
t.is(response.content[1].created_at, '2016-07-28T01:30:28.000Z');
t.is(response.content[1].updated_at, '2016-07-28T01:30:28.000Z');
t.is(response.content[1].recurrent_capture_id, null);
t.is(response.content[1].recurrent_capture_type, null);
t.is(response.total_pages, 1);
});
// UserService.getProfile method
/**
* @test {UserService.getProfile}
*/
test.serial('[unit] UserService.getProfile should throw an error when there is no authToken', async (t) => {
client.authToken = undefined;
const expectedError = 'UserService.getProfile error: requires authToken and user does not have id';
await t.throwsAsync(userService.getProfile(), expectedError);
});
// UserService.getProfile method
/**
* @test {UserService.getProfile}
*/
test.serial('[unit] UserService.getProfile should throw an error when there is no user id', async (t) => {
const expectedError = 'UserService.getProfile error: user does not have id';
await t.throwsAsync(userService.getProfile(), expectedError);
});
/**
* @test {UserService.getProfile}
*/
test('[unit] UserService.getProfile should make a properly formatted get request', async (t) => {
const { getProfileResponse } = t.context;
let request = {};
const user = new User({ id: 164 });
nock(client.apiBaseUrl).get(`/v3/mobile_users/${user.id}/profile`).reply(function (uri, requestBody) {
request = this.req;
request.requestBody = requestBody;
return [200, getProfileResponse];
});
await userService.getProfile(user);
t.is(request.path, `/v3/mobile_users/${user.id}/profile`);
t.is(request.headers.accept, 'application/json');
t.is(request.headers['content-type'], 'application/json');
t.is(request.headers.authorization, 'Token token=valid_token');
});
/**
* @test {UserService.getProfile}
*/
test('[unit] UserService.getProfile should receive a valid response', async (t) => {
const { getProfileResponse } = t.context;
const user = new User({ id: 164 });
nock(client.apiBaseUrl).get(`/v3/mobile_users/${user.id}/profile`).reply(200, getProfileResponse);
const response = await userService.getProfile(user);
t.truthy(response);
t.truthy(response);
t.is(response.firstName, 'Brisa');
t.is(response.middleInitial, null);
t.is(response.dob, null);
t.is(response.updatedAt, '2017-08-14T22:55:55Z');
t.is(response.street, null);
t.is(response.city, null);
t.is(response.lastName, 'Bailey');
t.is(response.tempEmail, undefined);
t.is(response.state, undefined);
t.is(response.id, 164);
t.is(response.occupation, null);
t.is(response.gender, 'male');
t.is(response.email, undefined);
t.is(response.zipCode, null);
t.is(response.phone, undefined);
t.is(response.timezone, 'UTC');
t.is(response.ethnicity, '');
t.is(response.profileableId, undefined);
t.is(response.age, undefined);
t.is(response.avatar.url, '/uploads/test/profile/avatar/164/1.png');
t.is(response.createdAt, '2017-08-14T22:55:55Z');
t.is(response.username, null);
});
// UserService.getProfileAttributes method
/**
* @test {UserService.getProfileAttributes}
*/
test('[unit] UserService.getProfileAttributes should make a properly formatted GET request', async (t) => {
const { getAttributesResponse } = t.context;
let request = {};
nock(client.apiBaseUrl).get(`/api/profile_attributes`).reply(function (uri, requestBody) {
request = this.req;
request.requestBody = requestBody;
return [200, getAttributesResponse];
});
await userService.getProfileAttributes();
t.is(request.path, `/api/profile_attributes`);
t.is(request.headers.accept, 'application/json');
t.is(request.headers['content-type'], 'application/json');
t.is(request.headers.authorization, 'Token token=valid_token');
});
/**
* @test {UserService.getProfileAttributes}
*/
test('[unit] UserService.getProfileAttributes should make a properly formatted GET request with includeHidden parameter defined', async (t) => {
const { getAttributesHiddenResponse } = t.context;
let request = {};
nock(client.apiBaseUrl).get(`/api/profile_attributes?include_hidden=true`).reply(function (uri, requestBody) {
request = this.req;
request.requestBody = requestBody;
return [200, getAttributesHiddenResponse];
});
await userService.getProfileAttributes(true);
t.is(request.path, `/api/profile_attributes?include_hidden=true`);
t.is(request.headers.accept, 'application/json');
t.is(request.headers['content-type'], 'application/json');
t.is(request.headers.authorization, 'Token token=valid_token');
});
/**
* @test {UserService.getProfileAttributes}
*/
test('[unit] UserService.getProfileAttributes should make a properly formatted GET request with includeValues parameter defined', async (t) => {
const { getAttributesIncludedResponse } = t.context;
let request = {};
nock(client.apiBaseUrl).get(`/api/profile_attributes?include_values=true`).reply(function (uri, requestBody) {
request = this.req;
request.requestBody = requestBody;
return [200, getAttributesIncludedResponse];
});
await userService.getProfileAttributes(false, true);
t.is(request.path, `/api/profile_attributes?include_values=true`);
t.is(request.headers.accept, 'application/json');
t.is(request.headers['content-type'], 'application/json');
t.is(request.headers.authorization, 'Token token=valid_token');
});
/**
* @test {UserService.getProfileAttributes}
*/
test('[unit] UserService.getProfileAttributes should make a properly formatted GET request with both includeHidden and includeValues parameters defined', async (t) => {
const { getResponseAll } = t.context;
let request = {};
nock(client.apiBaseUrl).get(`/api/profile_attributes?include_hidden=true&include_values=true`).reply(function (uri, requestBody) {
request = this.req;
request.requestBody = requestBody;
return [200, getResponseAll];
});
await userService.getProfileAttributes(true, true);
t.is(request.path, `/api/profile_attributes?include_hidden=true&include_values=true`);
t.is(request.headers.accept, 'application/json');
t.is(request.headers['content-type'], 'application/json');
t.is(request.headers.authorization, 'Token token=valid_token');
});
/**
* @test {UserService.getProfileAttributes}
*/
test('[unit] UserService.getProfileAttributes should receive valid response for a get request', async (t) => {
const { getAttributesResponse } = t.context;
nock(client.apiBaseUrl).get(`/api/profile_attributes`).reply(200, getAttributesResponse);
const response = await userService.getProfileAttributes();
t.truthy(response);
t.is(response.status, 'ok');
t.is(response.total_pages, 1);
t.is(response.content.length, 0);
t.is(client.authToken, 'valid_token');
});
/**
* @test {UserService.getProfileAttributes}
*/
test('[unit] UserService.getProfileAttributes should receive valid response for get request with includeHidden parameter', async (t) => {
const { getAttributesHiddenResponse } = t.context;
nock(client.apiBaseUrl).get(`/api/profile_attributes?include_hidden=true`).reply(200, getAttributesHiddenResponse);
const response = await userService.getProfileAttributes(true);
t.truthy(response);
t.is(response.status, 'ok');
t.is(response.content[0].allow_multiple_values, null);
t.is(response.content[0].api_key, 'fairfax_resident');
t.is(response.content[0].attribute_type, 'list');
t.is(response.content[0].created_at, '2014-09-11T23:53:03Z');
t.is(response.content[0].id, 1);
t.is(response.content[0].is_recurrent_capture, false);
t.is(response.content[0].is_visible, null);
t.is(response.content[0].name, 'Fairfax Resident');
t.deepEqual(response.content[0].options, ['Non Resident', 'Resident']);
t.is(response.content[0].updated_at, '2014-09-12T00:18:02Z');
t.is(response.total_pages, 1);
t.is(client.authToken, 'valid_token');
});
/**
* @test {UserService.getProfileAttributes}
*/
test('[unit] UserService.getProfileAttributes should receive valid response for get request with both includeHidden and includeValues parameter', async (t) => {
const { getAttributesAllResponse } = t.context;
nock(client.apiBaseUrl).get(`/api/profile_attributes?include_hidden=true&include_values=true`).reply(200, getAttributesAllResponse);
const response = await userService.getProfileAttributes(true, true);
t.truthy(response);
t.is(response.status, 'ok');
t.is(response.content[0].allow_multiple_values, null);
t.is(response.content[0].api_key, 'fairfax_resident');
t.is(response.content[0].attribute_type, 'list');
t.is(response.content[0].created_at, '2014-09-11T23:53:03Z');
t.is(response.content[0].id, 1);
t.is(response.content[0].is_recurrent_capture, false);
t.is(response.content[0].is_visible, null);
t.is(response.content[0].name, 'Fairfax Resident');
t.deepEqual(response.content[0].options, ['Non Resident', 'Resident']);
t.is(response.content[0].updated_at, '2014-09-12T00:18:02Z');
t.is(response.total_pages, 1);
t.is(client.authToken, 'valid_token');
});
// UserService.saveProfile method
/**
* @test {UserService.saveProfile}
*/
test('[unit] UserService.saveProfile should throw errors for invalid parameters', async (t) => {
const title = `UserService.saveProfile error`;
await t.throwsAsync(userService.saveProfile(), `${title}: user does not have id`);
await t.throwsAsync(userService.saveProfile({}), `${title}: user does not have id`);
const user = new User();
await t.throwsAsync(userService.saveProfile(user), `${title}: user does not have id`);
const profile = new Profile();
await t.throwsAsync(userService.saveProfile(profile), `${title}: user is not defined`);
});
/**
* @test {UserService.saveProfile}
*/
test('[unit] UserService.saveProfile should successfully update user profile with a profile object', async (t) => {
const { updateProfileResponse } = t.context;
let request = {};
client.reset();
client.authToken = 'valid_token';
const updateProfileRequest = {
data: {
type: 'profiles',
attributes: {
occupation: 'doctor',
height: 180
}
}
};
const user = new User({ id: 164 });
user.profile = new Profile(updateProfileRequest);
nock(client.apiBaseUrl).post(`/v3/mobile_users/${user.id}/profile`).reply(function (uri, requestBody) {
request = this.req;
request.requestBody = requestBody;
return [200, updateProfileResponse];
});
const response = await userService.saveProfile(user);
t.is(request.path, `/v3/mobile_users/${user.id}/profile`);
t.is(request.headers.accept, 'application/json');
t.is(request.headers['content-type'], 'application/json');
t.is(request.headers.authorization, 'Token token=valid_token');
t.deepEqual(request.requestBody, updateProfileRequest);
t.is(response.occupation, 'doctor');
t.is(response.height, 180);
});
/**
* @test {UserService.saveProfile}
*/
test('[unit] UserService.saveProfile should successfully update user profile with an inline object', async (t) => {
const { updateProfileResponse } = t.context;
let request = {};
client.reset();
client.authToken = 'valid_token';
const updateProfileRequest = {
data: {
type: 'profiles',
attributes: {
occupation: 'doctor',
height: 180
}
}
};
const user = new User({ id: 164 });
user.profile = new Profile(updateProfileRequest);
nock(client.apiBaseUrl).post(`/v3/mobile_users/${user.id}/profile`).reply(function (uri, requestBody) {
request = this.req;
request.requestBody = requestBody;
return [200, updateProfileResponse];
});
const response = await userService.saveProfile({ user, profile: { occupation: 'doctor', height: 180 } });
t.is(request.path, `/v3/mobile_users/${user.id}/profile`);
t.is(request.headers.accept, 'application/json');
t.is(request.headers['content-type'], 'application/json');
t.is(request.headers.authorization, 'Token token=valid_token');
t.deepEqual(request.requestBody, updateProfileRequest);
t.is(response.occupation, 'doctor');
t.is(response.height, 180);
});
// UserService.updateProfileAttribute method
/**
* @test {UserService.updateProfileAttribute}
*/
test.serial('[unit] UserService.updateProfileAttribute should throw an error when there is no authToken', async (t) => {
client.authToken = undefined;
const expectedError = 'UserService.updateProfileAttribute error: requires authToken and'
+ ' profile is not defined and id is not defined';
await t.throwsAsync(userService.updateProfileAttribute(), expectedError);
});
/**
* @test {UserService.updateProfileAttribute}
*/
test('[unit] UserService.updateProfileAttribute should throw an error when there is no profile parameter', async (t) => {
const expectedError = 'UserService.updateProfileAttribute error: profile is not defined '
+ 'and id is not defined';
await t.throwsAsync(userService.updateProfileAttribute(), expectedError);
});
/**
* @test {UserService.updateProfileAttribute}
*/
test('[unit] UserService.updateProfileAttribute should throw an error when there is no id parameter', async (t) => {
const profile = {
value: 321,
};
const expectedError = 'UserService.updateProfileAttribute error: id is not defined';
await t.throwsAsync(userService.updateProfileAttribute(profile), expectedError);
});
/**
* @test {UserService.updateProfileAttribute}
*/
test('[unit] UserService.updateProfileAttribute should successfully update a user profile attribute with a profile object and an id value', async (t) => {
const { updateProfileV2Response } = t.context;
let request = {};
client.reset();
client.authToken = 'valid_token';
const profile = {
value: 321,
};
nock(client.apiBaseUrl).put(`/api/profile_attributes/1`).reply(function (uri, requestBody) {
request = this.req;
request.requestBody = requestBody;
return [200, updateProfileV2Response];
});
const response = await userService.updateProfileAttribute(profile, 1);
t.is(request.path, `/api/profile_attributes/1`);
t.is(request.headers.accept, 'application/json');
t.is(request.headers['content-type'], 'application/json');
t.is(request.headers.authorization, 'Token token=valid_token');
t.deepEqual(request.requestBody, profile);
t.is(response.status, 'ok');
t.is(response.id, 1);
t.is(response.content.id, 1);
t.is(response.content.value, '321');
t.is(response.content.profile_attribute_id, 1);
t.is(response.content.profile_id, 5);
t.is(response.content.created_at, '2016-07-27T23:17:04.000Z');
t.is(response.content.updated_at, '2016-07-28T15:20:58.111Z');
t.is(response.content.recurrent_capture_id, null);
t.is(response.content.recurrent_capture_type, null);
});