test/unit/services.location.js
import test from 'ava';
import nock from 'nock';
import G_TIMEZONES from './data/timezones';
import {
client,
clinical6,
locationService,
Location,
Timezone,
} from '../../src';
test.before('start server', (t) => {
t.context.storage = client.storageUtility;
client.apiBaseUrl = 'https://somesite.Clinical6.com';
client.authToken = 'valid_token';
t.context.getResponseAll = {
data: [
{
id: '1',
type: 'locations',
attributes: {
country: 'USA',
state: 'CA',
city: 'San Diego',
latitude: '32.8563846',
longitude: '-117.2029363',
title: 'Location Title',
zip_code: null,
address_line_1: 'Main',
address_line_2: null,
address_line_3: null
}
},
{
id: '2',
type: 'locations',
attributes: {
country: 'USA',
state: 'CA',
city: 'San Diego',
latitude: '32.8563846',
longitude: '-117.2029363',
title: 'Location Title',
zip_code: null,
address_line_1: 'Main',
address_line_2: null,
address_line_3: null
}
},
{
id: '3',
type: 'locations',
attributes: {
country: 'USA',
state: 'CA',
city: 'San Diego',
latitude: '32.8563846',
longitude: '-117.2029363',
title: 'Location Title',
zip_code: null,
address_line_1: 'Main',
address_line_2: null,
address_line_3: null
}
}
]
};
t.context.getResponseId = {
data: {
id: '4',
type: 'locations',
attributes: {
country: 'USA',
state: 'CA',
city: 'San Diego',
latitude: '32.8563846',
longitude: '-117.2029363',
title: 'Location Title',
zip_code: null,
address_line_1: 'Main',
address_line_2: null,
address_line_3: null
}
}
};
t.context.getResponseAllTimezones = G_TIMEZONES;
t.context.postResponse = {
data: {
id: '106',
type: 'locations',
attributes: {
country: 'USA',
state: 'CA',
city: 'Poway',
latitude: '12.1223',
longitude: '14.1221',
title: '12345 Cherry Lane, Poway, CA 92064',
zip_code: '92064',
address_line_1: '12345 Cherry Lane',
address_line_2: 'Unit #59',
address_line_3: null
}
}
};
t.context.patchResponse = {
data: {
id: '106',
type: 'locations',
attributes: {
country: 'USA',
state: 'CA',
city: 'Poway',
latitude: '12.1223',
longitude: '14.1221',
title: '12345 Cherry Lane, Poway, CA 92064',
zip_code: '92064',
address_line_1: '12345 Cherry Lane',
address_line_2: 'Unit #59',
address_line_3: null
}
}
};
});
test.beforeEach((t) => {
client.cache = 'never';
client.authToken = 'valid_token';
// client.location = new Location({});
// client.timezone = new Timezone({});
t.context.locationJsonApi = {
id: 106,
type: 'locations',
attributes: {
country: 'USA',
state: 'CA',
city: 'Poway',
latitude: '12.1223',
longitude: '14.1221',
title: '12345 Cherry Lane, Poway, CA 92064',
zip_code: '92064',
address_line_1: '12345 Cherry Lane',
address_line_2: 'Unit #59',
address_line_3: null
}
};
t.context.locationJson = {
id: 106,
type: 'locations',
country: 'USA',
state: 'CA',
city: 'Poway',
latitude: '12.1223',
longitude: '14.1221',
title: '12345 Cherry Lane, Poway, CA 92064',
zip_code: '92064',
address_line_1: '12345 Cherry Lane',
address_line_2: 'Unit #59',
address_line_3: null
};
t.context.location = new Location(t.context.locationJsonApi);
});
/**
* @test {Location}
*/
test('[unit] Location should handle location data with a normal json format', (t) => {
const location = new Location(t.context.locationJsonApi);
t.is(location.id, 106);
t.is(location.type, 'locations');
t.is(location.country, 'USA');
t.is(location.state, 'CA');
t.is(location.city, 'Poway');
t.is(location.latitude, '12.1223');
t.is(location.longitude, '14.1221');
t.is(location.title, '12345 Cherry Lane, Poway, CA 92064');
t.is(location.zipCode, '92064');
t.is(location.addressLine1, '12345 Cherry Lane');
t.is(location.addressLine2, 'Unit #59');
t.is(location.addressLine3, null);
});
/**
* @test {Location}
*/
test('[unit] Location should handle location data with json api format', (t) => {
const { locationJsonApi } = t.context;
const location = new Location({ data: locationJsonApi });
t.is(location.id, 106);
t.is(location.type, 'locations');
t.is(location.country, 'USA');
t.is(location.state, 'CA');
t.is(location.city, 'Poway');
t.is(location.latitude, '12.1223');
t.is(location.longitude, '14.1221');
t.is(location.title, '12345 Cherry Lane, Poway, CA 92064');
t.is(location.zipCode, '92064');
t.is(location.addressLine1, '12345 Cherry Lane');
t.is(location.addressLine2, 'Unit #59');
t.is(location.addressLine3, null);
});
// LocationService.delete method
/**
* @test {LocationService.delete}
*/
test('[unit] LocationService.delete should throw errors for invalid parameters', async (t) => {
const undefinedError = 'LocationService.delete error: location does not have id';
await t.throwsAsync(clinical6.delete(new Location()), undefinedError);
});
/**
* @test {LocationService.delete}
*/
test('[unit] LocationService.delete should make a properly formatted delete request and response', async (t) => {
const { location } = t.context;
location.id = 5;
let request = {};
nock(client.apiBaseUrl).delete(/\/v3\/locations\/([0-9]*)$/).reply(function () {
request = this.req;
return [200, ''];
});
const response = await clinical6.delete(location);
t.is(request.path, `/v3/locations/${location.id}`);
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.falsy(response);
});
/**
* @test {LocationService.delete}
*/
test('[unit] LocationService.delete should remove the element from local storage', async (t) => {
const { location, storage } = t.context;
location.id = 5;
nock(client.apiBaseUrl).delete(/\/v3\/locations\/([0-9]*)$/).reply(200, '');
await storage.set('locations', location.toJSON(), { id: location.id });
await clinical6.delete(location);
t.is(storage.has('locations', { id: location.id }), false);
});
// LocationService.get method
/**
* @test {LocationService.get}
*/
test.serial('[unit] LocationService.get should throw an error when there is no authToken', async (t) => {
client.authToken = undefined;
const expectedError = 'LocationService.get error: requires authToken';
await t.throwsAsync(locationService.get(Location), expectedError);
});
/**
* @test {LocationService.get}
*/
test('[unit] LocationService.get should make a properly formatted get request and response without an id', async (t) => {
const { getResponseAll } = t.context;
let request = {};
nock(client.apiBaseUrl).get('/v3/locations').reply(function () {
request = this.req;
return [200, getResponseAll];
});
const response = await locationService.get(Location);
t.is(request.path, `/v3/locations`);
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(Object.keys(response).length, 3);
});
/**
* @test {LocationService.get}
*/
test('[unit] LocationService.get should receive a valid response for a get request with an id', async (t) => {
const { getResponseId } = t.context;
nock(client.apiBaseUrl).get('/v3/locations/4').reply(200, getResponseId);
const response = await locationService.get(new Location({ id: 4 }));
t.truthy(response);
t.is(response.id, 4);
t.is(response.type, 'locations');
t.is(response.country, 'USA');
t.is(response.state, 'CA');
t.is(response.city, 'San Diego');
t.is(response.latitude, '32.8563846');
t.is(response.longitude, '-117.2029363');
t.is(response.title, 'Location Title');
t.is(response.zipCode, null);
t.is(response.addressLine1, 'Main');
t.is(response.addressLine2, null);
t.is(response.addressLine3, null);
});
// LocationService.insert method
/**
* @test {Location.insert}
*/
test('[unit] Location.insert should successfully insert a location with a location object', async (t) => {
const { postResponse } = t.context;
const json = JSON.parse(JSON.stringify(t.context.locationJsonApi));
const location = new Location({ data: json });
let request = {};
nock(client.apiBaseUrl).post(`/v3/locations`).reply(function (uri, requestBody) {
request = this.req;
request.requestBody = requestBody;
return [201, postResponse];
});
const response = await clinical6.insert(location);
t.is(request.path, `/v3/locations`);
t.is(request.headers.accept, 'application/json');
t.deepEqual(request.requestBody, { data: json });
t.is(request.headers['content-type'], 'application/json');
t.is(request.headers.authorization, 'Token token=valid_token');
t.is(response.id, 106);
t.is(response.type, 'locations');
t.is(response.country, 'USA');
t.is(response.state, 'CA');
t.is(response.city, 'Poway');
t.is(response.latitude, '12.1223');
t.is(response.longitude, '14.1221');
t.is(response.title, '12345 Cherry Lane, Poway, CA 92064');
t.is(response.zipCode, '92064');
t.is(response.addressLine1, '12345 Cherry Lane');
t.is(response.addressLine2, 'Unit #59');
t.is(response.addressLine3, null);
});
// LocationService.getTimezones method
/**
* @test {LocationService.getTimezones}
*/
test('[unit] LocationService.getTimezones should exist', (t) => {
t.truthy(locationService.getTimezones);
});
/**
* @test {LocationService.getTimezones}
*/
test.serial('[unit] LocationService.getTimezones should throw an error when there is no authToken', (t) => {
client.authToken = undefined;
const expectedError = 'LocationService.getTimezones error: requires authToken';
t.throws(() => locationService.getTimezones(), expectedError);
});
/**
* @test {LocationService.getTimezones}
*/
test('[unit] LocationService.getTimezones should return a promise', async (t) => {
t.truthy(await locationService.getTimezones().then);
});
// /**
// * @test {LocationService.getTimezones}
// */
// test('[unit] LocationService.getTimezones should make a properly formatted get request', async (t) => {
// await locationService.getTimezones();
// const request = t.context.server.requests[0];
// t.is(request.method, 'GET');
// t.is(request.url, `${client.apiBaseUrl}/v3/timezones`);
// t.is(request.requestHeaders.Accept, 'application/json');
// t.is(request.requestHeaders['Content-Type'], 'application/json;charset=utf-8');
// t.is(request.requestHeaders.Authorization, 'Token token=valid_token');
// });
/**
* @test {LocationService.getTimezones}
*/
test('[unit] LocationService.getTimezones should receive a valid response for a get request without an id', async (t) => {
const { getResponseAllTimezones } = t.context;
let request = {};
nock(client.apiBaseUrl).get('/v3/timezones').reply(function () {
request = this.req;
return [200, getResponseAllTimezones];
});
const response = await locationService.getTimezones();
t.truthy(response);
t.is(request.path, `/v3/timezones`);
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(Object.keys(response).length, 424);
t.true(response[0] instanceof Timezone);
t.is(response[0].id, 'pacific/pago_pago__-11.0');
t.is(response[0].type, 'timezones');
t.is(response[0].name, 'Pacific/Pago_Pago');
t.is(response[0].offset, -11);
t.is(response[0].region, 'Pacific');
});
// LocationService.update method
/**
* @test {Location.update}
*/
test('[unit] Location.update should successfully update a location with a location object', async (t) => {
const { patchResponse } = t.context;
const json = JSON.parse(JSON.stringify(t.context.locationJsonApi));
const location = new Location({ data: json });
location.id = 106;
let request = {};
nock(client.apiBaseUrl).patch(`/v3/locations/${location.id}`).reply(function (uri, requestBody) {
request = this.req;
request.requestBody = requestBody;
return [200, patchResponse];
});
const response = await clinical6.update(location);
t.is(request.path, `/v3/locations/${location.id}`);
t.is(request.headers.accept, 'application/json');
t.deepEqual(request.requestBody, { data: json });
t.is(request.headers['content-type'], 'application/json');
t.is(request.headers.authorization, 'Token token=valid_token');
t.is(response.id, 106);
t.is(response.type, 'locations');
t.is(response.country, 'USA');
t.is(response.state, 'CA');
t.is(response.city, 'Poway');
t.is(response.latitude, '12.1223');
t.is(response.longitude, '14.1221');
t.is(response.title, '12345 Cherry Lane, Poway, CA 92064');
t.is(response.zipCode, '92064');
t.is(response.addressLine1, '12345 Cherry Lane');
t.is(response.addressLine2, 'Unit #59');
t.is(response.addressLine3, null);
});
// LocationService.update method with reason for changes
/**
* @test {Location.update}
*/
test('[unit] Location.update should successfully update a location with reason for changes', async (t) => {
const location = new Location();
location.id = 106;
location.country = 'United Kingdom';
const meta = {
reason_for_changes: {
country: 'Spelling Error'
}
};
const requestPayload = {
data: {
id: 106,
type: 'locations',
attributes: {
country: 'United Kingdom',
},
},
meta,
};
let request = {};
nock(client.apiBaseUrl).patch(/\/v3\/locations\/([0-9]*)$/, (body) => {
request = body;
return requestPayload;
}).reply(200, {
data: {
id: 106,
type: 'locations',
attributes: {
country: 'United Kingdom',
},
},
meta: {
reason_for_changes: {
country: 'Spelling Error',
},
},
});
const response = await clinical6.update(location, { cacheMode: 'networkOnly', meta });
t.deepEqual(request, requestPayload);
t.is(response.id, 106);
t.is(response.type, 'locations');
t.is(response.country, 'United Kingdom');
});