Manual Reference Source Test

test/unit/services.flow.v3.js

import test from 'ava';
import nock from 'nock';
import { client, Flow, flowService } from '../../src';


test.before('start server', (t) => {
  t.context.storage = client.storageUtility;
  client.apiBaseUrl = 'https://somesite.Clinical6.com';

  t.context.getResponseAll = {
    data: [
      {
        id: 155,
        type: 'data_collection__flow_processes',
        attributes: {
          name: 'qui',
          permanent_link: 'dummy_1566',
          published_at: null
        }
      }
    ]
  };

  t.context.patchResponse = {
    data: {
      id: '6',
      type: 'data_collection__flow_processes',
      attributes: {
        name: 'Updated',
        permanent_link: 'dummy_77',
        consent_credentials: null,
        created_at: '2018-08-19T22:03:19Z',
        updated_at: '2018-08-19T22:03:20Z',
        owner_type: 'MobileUser',
        published_at: null,
        conditional_paths: null,
        description: 'Updated flow description'
      },
      relationships: {
        linked_steps: {
          data: []
        },
        published: {
          data: null
        },
        draft: {
          data: null
        },
        initial_step: {
          data: null
        }
      }
    }
  };

  t.context.storage = client.storageUtility;
  client.flow = new Flow({});
  t.context.flowJsonApi = {
    data: {
      type: 'data_collection/flow_processes',
      attributes: {}
    }
  };
});

test.after('server shut down', () => {});

test.beforeEach((t) => {
  client.cache = 'never';
  client.authToken = 'valid_token';
  t.context.flow = new Flow(t.context.flowJsonApi);
});

// FlowService.get method
/**
 * @test {FlowService.get}
 */
test.serial('[unit] FlowService.get should throw an error when there is no authToken', async (t) => {
  client.authToken = undefined;
  const expectedError = 'FlowService.get error: requires authToken';
  await t.throws(() => flowService.get(), expectedError);
});

/**
* @test {Clinical6.get}
*/
test('[unit] FlowService.get should make a properly formatted get request', async (t) => {
  const { getResponseAll } = t.context;
  let request = {};
  nock(client.apiBaseUrl).get(`/v3/data_collection/flow_processes`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, getResponseAll];
  });
  await flowService.get();
  t.is(request.path, `/v3/data_collection/flow_processes`);
  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 {FlowService.get}
*/
test('FlowService.get should receive a valid response for a get request without an id', async (t) => {
  const { getResponseAll } = t.context;
  nock(client.apiBaseUrl).get(`/v3/data_collection/flow_processes`).reply(200, getResponseAll);
  const response = await flowService.get();

  t.truthy(response);
  t.is(Object.keys(response).length, 1);

  t.is(response[0].id, 155);
  t.is(response[0].type, 'data_collection__flow_processes');
  t.is(response[0].name, 'qui');
  t.is(response[0].permanentLink, 'dummy_1566');
  t.is(response[0].publishedAt, null);
});

/**
  * @test {FlowService.get}
  */
// test('[unit] FlowService.get should receive a valid response for a get request with an id', async (t) => {
//   const response = await flowService.get({ id: 4 });
//   t.truthy(response);
//   t.is(response.id, 4);
//   t.is(response.type, 'data_collection/flow_processes');
//   t.is(response.createdAt, '2017-08-09T16:23:55Z');
//   t.is(response.updatedAt, '2017-08-09T16:23:55Z');
//   t.is(response.title, 'dummy_440');
//   t.is(response.description, 'Demo Content info...');
//   t.is(response.redemptionPoints, 250);
//   t.is(response.image.url, '/uploads/test/reward/image/4/1.png');
//   t.is(response.position, 4);
//   t.is(response.enabled, true);
//   t.is(response.featured, null);
//   t.is(response.basedOn, null);
//   t.is(response.threshold, null);
//   t.is(response.timeUnit, null);
//   t.is(response.startPoint, null);
//   t.is(response.startAt, null);
//   t.is(response.disabledImage.url, '/default/default.png');
//   t.is(response.cacheToken, 'QBPu8whNUSE');
// });

// FlowService.delete method
/**
 * @test {FlowService.delete}
 */
// test('[unit] JsonApiService.delete should throw errors for invalid parameters', async (t) => {
//   const undefinedError = 'JsonApiService.delete error: obj is not defined';
//   await t.throws(() => flowService.delete(), undefinedError);
// });

// /**
//  * @test {FlowService.delete}
//  */
// test('[unit] FlowService.delete should make a properly formatted delete request', async (t) => {
//   const { flow } = t.context;
//   flow.id = 5;
//   await flowService.delete(flow);
//   const request = t.context.server.requests[0];
//   t.is(request.method, 'DELETE');
//   t.is(request.url, `${client.apiBaseUrl}/v3/data_collection/flow_processes/${flow.id}`);
//   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 {FlowService.delete}
 */
test('[unit] FlowService.delete should receive a valid response for a delete request', async (t) => {
  const { flow } = t.context;
  flow.id = 5;

  let request = {};
  nock(client.apiBaseUrl).delete(`/v3/data_collection/flow_processes/5`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, ''];
  });
  const response = await flowService.delete(flow);
  t.is(request.path, `/v3/data_collection/flow_processes/5`);
  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 {FlowService.delete}
  */
test('[unit] FlowService.delete should remove the element from local storage', async (t) => {
  const { flow, storage } = t.context;
  flow.id = 5;
  nock(client.apiBaseUrl).delete(`/v3/data_collection/flow_processes/5`).reply(204, '');
  await storage.set('data_collection/flow_processes', flow.toJSON(), { id: flow.id });
  await flowService.delete(flow);
  t.is(storage.has('data_collection/flow_processes', { id: flow.id }), false);
});

// FlowService.insert method
/**
 * @test {FlowService.insert}
 */
test.serial('[unit] [unit] FlowService.insert should throw an error when there is no authToken', async (t) => {
  client.authToken = undefined;
  const expectedError = 'FlowService.insert error: requires authToken';
  await t.throws(() => flowService.insert({}), expectedError);
});

/**
 * @test {FlowService.insert}
 */
test('[unit] FlowService.insert should successfully insert a flow with a flow object', async (t) => {
  let request = {};
  nock(client.apiBaseUrl).post(`/v3/data_collection/flow_processes`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [201, {
      data: {
        id: '2',
        type: 'data_collection__flow_processes',
        attributes: {
          name: 'Flow Name',
          permanent_link: 'flow_name',
          consent_credentials: null,
          created_at: '2018-03-01T21:25:00Z',
          updated_at: '2018-03-01T21:25:00Z',
          owner_type: 'MobileUser',
          published_at: null,
          conditional_paths: null
        },
        relationships: {
          linked_steps: { data: [] },
          published: { data: null },
          draft: { data: null },
          initial_step: { data: null }
        }
      }
    }];
  });

  const requestJsonApi = {
    data: {
      type: 'data_collection__flow_processes',
      attributes: {
        name: 'Flow Name',
        permanent_link: 'flow_name',
        steps: []
      }
    }
  };

  client.mobileApplicationKey = '0355b2fb1c8fa7210bec203abb32b916';
  const flow = new Flow(requestJsonApi);
  const response = await flowService.insert(flow);

  t.is(request.path, `/v3/data_collection/flow_processes`);
  t.is(request.headers.accept, 'application/json');
  t.deepEqual(request.requestBody, requestJsonApi);
  t.is(request.headers['content-type'], 'application/json');
  t.is(request.headers.authorization, 'Token token=valid_token');

  t.is(response.id, 2);
  t.is(response.type, 'data_collection__flow_processes');
  t.is(response.name, 'Flow Name');
  t.is(response.permanentLink, 'flow_name');
});

/**
 * @test {FlowService.insert}
 */
test('[unit] FlowService.insert should throw an error with an invalid token', async (t) => {
  let request = {};
  flowService.cacheMode = 'networkOnly';
  nock(client.apiBaseUrl).post(`/v3/data_collection/flow_processes`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [422, {
      errors: [
        {
          source: {
            pointer: '/data/attributes/mobile_application_key'
          },
          detail: 'can\'t be blank'
        }
      ]
    }];
  });

  const requestJsonApi = {
    data: {
      type: 'data_collection/flow_processes',
      attributes: {
        push_id: 'FAKE_ID',
        mobile_application_key: 'invalid'
      }
    }
  };

  client.mobileApplicationKey = 'invalid';
  const flow = new Flow(requestJsonApi);

  const response = await flowService.insert(flow).catch(err => err);

  t.is(response.message, `"/data/attributes/mobile_application_key": can't be blank`);
});

// FlowService.update method
/**
 * @test {FlowService.update}
 */
test.serial('[unit] FlowService.update should throw errors for invalid parameters', async (t) => {
  client.authToken = undefined;
  const undefinedError = 'FlowService.update error: requires authToken and flow is not defined';
  await t.throws(() => flowService.update(), undefinedError);
});

// FlowService.update method
/**
 * @test {FlowService.update}
 */
test('[unit] FlowService.update should successfully update a flow with a flow object', async (t) => {
  const { patchResponse } = t.context;
  const flowJsonApi = {
    data: {
      id: 6,
      type: 'data_collection__flow_processes',
      attributes: {
        name: 'Updated',
        description: 'Updated flow description',
        permanent_link: 'dummy_77',
        steps: []
      }
    }
  };

  const flow = new Flow(flowJsonApi);

  let request = {};
  client.reset();
  client.authToken = 'valid_token';
  nock(client.apiBaseUrl).patch(`/v3/data_collection/flow_processes/6`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, patchResponse];
  });
  const response = await flowService.update(flow);

  t.is(request.path, `/v3/data_collection/flow_processes/6`);
  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, flowJsonApi);

  t.is(response.id, 6);
  t.is(response.type, 'data_collection__flow_processes');
  t.is(response.name, 'Updated');
  t.is(response.description, 'Updated flow description');
  t.is(response.permanentLink, 'dummy_77');
  t.is(response.consentCredentials, null);
  t.is(response.createdAt, '2018-08-19T22:03:19Z');
  t.is(response.updatedAt, '2018-08-19T22:03:20Z');
  t.is(response.ownerType, 'MobileUser');
  t.is(response.publishedAt, null);
  t.is(response.conditionalPaths, null);
  t.is(response.steps.length, 0);
  t.deepEqual(response.steps, []);
  t.is(response.published, null);
  t.is(response.draft, null);
  t.is(response.first_step, null);
});