Manual Reference Source Test

test/unit/services.user.v3.mobile.js

import test from 'ava';
import nock from 'nock';
import {
  client,
  clinical6,
  mobileUserService,
  AvailableStrategy,
  AwardedBadge,
  Badge,
  CohortAssignment,
  ConsentGrant,
  Consultation,
  Device,
  EntryGroup,
  Role,
  Rule,
  Schedule,
  User,
} from '../../src';

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

  t.context.getResponseGrants454 = {
    data: [
      {
        id: 3,
        type: 'consent__grants',
        attributes: {
          document: {
            url: '/uploads/test/consent/grant/document/3/1.pdf'
          },
          progress: 'all_signed',
          created_at: '2018-07-20T13:32:51Z',
          updated_at: '2018-07-20T13:32:51Z'
        },
        relationships: {
          granted_for: {
            data: {
              id: 454,
              type: 'mobile_users'
            }
          },
          granted_by: {
            data: {
              id: 454,
              type: 'mobile_users'
            }
          },
          strategy: {
            data: {
              id: 62,
              type: 'consent__strategies'
            }
          },
          form_version: {
            data: null
          },
          agreement: {
            data: null
          }
        }
      },
      {
        id: 4,
        type: 'consent__grants',
        attributes: {
          sign_url: null,
          progress: 'all_signed',
          created_at: '2018-07-20T13:32:51Z',
          updated_at: '2018-07-20T13:32:51Z'
        },
        relationships: {
          granted_for: {
            data: {
              id: 454,
              type: 'mobile_users'
            }
          },
          granted_by: {
            data: {
              id: 454,
              type: 'mobile_users'
            }
          },
          strategy: {
            data: {
              id: 63,
              type: 'consent__strategies'
            }
          },
          form_version: {
            data: {
              id: 37,
              type: 'consent__form_versions'
            }
          },
          agreement: {
            data: {
              id: 18,
              type: 'agreement__agreements'
            }
          }
        }
      }
    ],
    included: [
      {
        id: 62,
        type: 'consent__strategies',
        attributes: {
          name: 'Strategy-67',
          strategy_type: 'paper',
          created_at: '2018-07-20T13:32:51Z',
          updated_at: '2018-07-20T13:32:51Z'
        },
        relationships: {
          cohort: {
            data: {
              id: 105,
              type: 'cohorts'
            }
          },
          forms: {
            data: []
          }
        }
      },
      {
        id: 63,
        type: 'consent__strategies',
        attributes: {
          name: 'Strategy-68',
          strategy_type: 'electronic',
          created_at: '2018-07-20T13:32:51Z',
          updated_at: '2018-07-20T13:32:51Z'
        },
        relationships: {
          cohort: {
            data: {
              id: 106,
              type: 'cohorts'
            }
          },
          forms: {
            data: [
              {
                id: 51,
                type: 'consent__forms'
              }
            ]
          }
        }
      },
      {
        id: 37,
        type: 'consent__form_versions',
        attributes: {
          archived_at: null
        },
        relationships: {
          site: {
            data: {
              id: 115,
              type: 'trials__sites'
            }
          },
          agreement_template: {
            data: {
              id: 102,
              type: 'agreement__templates'
            }
          },
          language: {
            data: {
              id: 63,
              type: 'languages'
            }
          },
          consent_form: {
            data: {
              id: 51,
              type: 'consent__forms'
            }
          },
          approver_groups: {
            data: []
          },
          approvers: {
            data: []
          }
        }
      },
      {
        id: 51,
        type: 'consent__forms',
        attributes: {
          enabled: true,
          name: 'Form 54',
          created_at: '2018-07-20T13:32:51Z',
          updated_at: '2018-07-20T13:32:51Z'
        },
        relationships: {
          consent_form_versions: {
            data: [
              {
                id: 37,
                type: 'consent__form_versions'
              }
            ]
          },
          strategy: {
            data: {
              id: 63,
              type: 'consent__strategies'
            }
          }
        }
      }
    ],
    links: {},
    meta: {
      total_records: 2,
      total_pages: 1
    }
  };

  t.context.getResponse = {
    data: [
      {
        id: '1',
        type: 'mobile_users',
        attributes: {
          udid: 'this-is-a-udid-string',
          technology: 'ios',
          access_token: 'cd68fa04e458d6d1a9d29faec6a329d3',
          push_id: null,
          created_at: '2017-05-19T17:21:26.311Z',
          updated_at: '2017-05-19T17:21:26.311Z',
          app_version: null
        }
      },
      {
        id: '2',
        type: 'mobile_users',
        attributes: {
          udid: 'this-is-a-udid-string',
          technology: 'ios',
          access_token: 'cd68fa04e458d6d1a9d29faec6a329d3',
          push_id: null,
          created_at: '2017-05-19T17:21:26.311Z',
          updated_at: '2017-05-19T17:21:26.311Z',
          app_version: null
        }
      }
    ]
  };

  t.context.getResponse2 = {
    data: {
      id: '2',
      type: 'mobile_users',
      attributes: {
        uuid: 'dddb2ab3-3be9-4a54-8c2c-7687c4ec9bee',
        account_name: '5nl1xkjc',
        username: '5nl1xkjc',
        email: null,
        encryption_key: null,
        created_at: '2017-05-15T19:08:17.076Z',
        updated_at: '2017-05-15T19:08:17.108Z',
        verified_at: null,
        invitation_sent_at: null,
        invitation_accepted_at: null
      },
      relationships: {
        devices: {
          data: [
            {
              id: '1',
              type: 'devices'
            }
          ]
        }
      }
    },
    included: [
      {
        id: '1',
        type: 'devices',
        attributes: {
          udid: '660y6gb90yxlctukngk6',
          technology: 'ios',
          access_token: '4756992a843a504d2f786380b4a67760',
          push_id: 'tsg6mrcgrto71iyi6bt113d1d72x68koo0e22fkd0e3rppztbn40va32qyj98prq',
          created_at: '2017-05-15T19:08:16.000Z',
          updated_at: '2017-05-15T19:08:17.000Z',
          app_version: null
        }
      }
    ]
  };

  t.context.getResponseStrategies77 = {
    data: [
      {
        id: 7,
        type: 'consent__available_strategies',
        relationships: {
          strategy: {
            data: {
              id: 7,
              type: 'consent__strategies'
            }
          },
          forms: {
            data: [
              {
                id: 5,
                type: 'consent__forms'
              },
              {
                id: 6,
                type: 'consent__forms'
              }
            ]
          }
        }
      },
      {
        id: 8,
        type: 'consent__available_strategies',
        relationships: {
          strategy: {
            data: {
              id: 8,
              type: 'consent__strategies'
            }
          },
          forms: {
            data: null
          }
        }
      }
    ],
    included: [
      {
        id: 7,
        type: 'consent__strategies',
        attributes: {
          name: 'Strategy-8',
          strategy_type: 'electronic',
          created_at: '2018-07-16T23:08:26Z',
          updated_at: '2018-07-16T23:08:26Z'
        },
        relationships: {
          cohort: {
            data: {
              id: 9,
              type: 'cohorts'
            }
          },
          forms: {
            data: [
              {
                id: 5,
                type: 'consent__forms'
              },
              {
                id: 6,
                type: 'consent__forms'
              }
            ]
          }
        }
      },
      {
        id: 5,
        type: 'consent__forms',
        attributes: {
          enabled: true,
          name: 'Form 5',
          created_at: '2018-07-16T23:08:26Z',
          updated_at: '2018-07-16T23:08:26Z'
        },
        relationships: {
          consent_form_versions: {
            data: [
              {
                id: 5,
                type: 'consent__form_versions'
              },
              {
                id: 6,
                type: 'consent__form_versions'
              }
            ]
          },
          strategy: {
            data: {
              id: 7,
              type: 'consent__strategies'
            }
          }
        }
      },
      {
        id: 6,
        type: 'consent__forms',
        attributes: {
          enabled: true,
          name: 'Form 6',
          created_at: '2018-07-16T23:08:26Z',
          updated_at: '2018-07-16T23:08:26Z'
        },
        relationships: {
          consent_form_versions: {
            data: [
              {
                id: 7,
                type: 'consent__form_versions'
              }
            ]
          },
          strategy: {
            data: {
              id: 7,
              type: 'consent__strategies'
            }
          }
        }
      },
      {
        id: 8,
        type: 'consent__strategies',
        attributes: {
          name: 'Strategy-9',
          strategy_type: 'waived',
          created_at: '2018-07-16T23:08:26Z',
          updated_at: '2018-07-16T23:08:26Z'
        },
        relationships: {
          cohort: {
            data: {
              id: 9,
              type: 'cohorts'
            }
          },
          forms: {
            data: []
          }
        }
      }
    ]
  };

  t.context.getResponseAssignments80 = {
    data: [
      {
        id: '6',
        type: 'cohort_assignments',
        attributes: {
          created_at: '2018-04-25T17:44:57Z',
          updated_at: '2018-04-25T17:44:57Z'
        },
        relationships: {
          user: {
            data: {
              id: '80',
              type: 'mobile_users'
            }
          },
          cohort: {
            data: {
              id: '22',
              type: 'cohorts'
            }
          }
        }
      },
      {
        id: '7',
        type: 'cohort_assignments',
        attributes: {
          created_at: '2018-04-25T17:44:57Z',
          updated_at: '2018-04-25T17:44:57Z'
        },
        relationships: {
          user: {
            data: {
              id: '80',
              type: 'mobile_users'
            }
          },
          cohort: {
            data: {
              id: '23',
              type: 'cohorts'
            }
          }
        }
      },
      {
        id: '8',
        type: 'cohort_assignments',
        attributes: {
          created_at: '2018-04-25T17:44:57Z',
          updated_at: '2018-04-25T17:44:57Z'
        },
        relationships: {
          user: {
            data: {
              id: '80',
              type: 'mobile_users'
            }
          },
          cohort: {
            data: {
              id: '24',
              type: 'cohorts'
            }
          }
        }
      }
    ],
    included: [
      {
        id: '22',
        type: 'cohorts',
        attributes: {
          name: 'name-22',
          cohort_type: 'static',
          created_at: '2018-04-25T17:44:57Z',
          updated_at: '2018-04-25T17:44:57Z'
        }
      },
      {
        id: '23',
        type: 'cohorts',
        attributes: {
          name: 'name-23',
          cohort_type: 'static',
          created_at: '2018-04-25T17:44:57Z',
          updated_at: '2018-04-25T17:44:57Z'
        }
      },
      {
        id: '24',
        type: 'cohorts',
        attributes: {
          name: 'name-24',
          cohort_type: 'static',
          created_at: '2018-04-25T17:44:57Z',
          updated_at: '2018-04-25T17:44:57Z'
        }
      }
    ]
  };

  t.context.getResponseConfirmRegistration = {
    data: {
      id: '196',
      type: 'mobile_users',
      attributes: {
        uuid: '7cc2ae4d-580e-4bf5-84d6-0a32dd97f231',
        account_name: 'dummy_178',
        email: 'user273@fake.com',
        encryption_key: null,
        created_at: '2017-06-07T23:58:58Z',
        updated_at: '2017-06-07T23:58:58Z',
        disabled_at: '2017-06-07T23:58:58Z',
        verified_at: null,
        invitation_sent_at: null,
        invitation_accepted_at: null
      },
      relationships: {
        devices: {
          data: [
            {
              id: '110',
              type: 'devices'
            }
          ]
        }
      }
    }
  };

  t.context.getResponseConsultation = {
    data: [
      {
        id: '4',
        type: 'video_consultations',
        attributes: {
          name: 'General Consultation',
          start_at: '2018-08-09T19:11:32Z',
          end_at: null,
          status: null,
          session_identity: null,
          confirmed_at: null,
          deleted_at: null,
          created_at: '2018-08-09T19:13:05Z',
          updated_at: '2018-08-09T19:13:05Z'
        },
        relationships: {
          video_consultation_participants: {
            data: [
              {
                id: '2',
                type: 'video_consultation_participants'
              }
            ]
          }
        }
      },
      {
        id: '5',
        type: 'video_consultations',
        attributes: {
          name: 'General Consultation',
          start_at: '2018-08-09T19:11:32Z',
          end_at: null,
          status: null,
          session_identity: null,
          confirmed_at: null,
          deleted_at: null,
          created_at: '2018-08-09T19:13:05Z',
          updated_at: '2018-08-09T19:13:05Z'
        },
        relationships: {
          video_consultation_participants: {
            data: [
              {
                id: '3',
                type: 'video_consultation_participants'
              }
            ]
          }
        }
      },
      {
        id: '6',
        type: 'video_consultations',
        attributes: {
          name: 'General Consultation',
          start_at: '2018-08-09T19:11:32Z',
          end_at: null,
          status: null,
          session_identity: null,
          confirmed_at: null,
          deleted_at: null,
          created_at: '2018-08-09T19:13:05Z',
          updated_at: '2018-08-09T19:13:05Z'
        },
        relationships: {
          video_consultation_participants: {
            data: [
              {
                id: '4',
                type: 'video_consultation_participants'
              }
            ]
          }
        }
      }
    ],
    included: [
      {
        id: '2',
        type: 'video_consultation_participants',
        attributes: {
          created_at: '2018-08-09T19:13:05Z',
          updated_at: '2018-08-09T19:13:05Z'
        },
        relationships: {
          video_consultation: {
            data: {
              id: '4',
              type: 'video_consultations'
            }
          },
          participant: {
            data: {
              id: '217',
              type: 'mobile_users'
            }
          }
        }
      },
      {
        id: '3',
        type: 'video_consultation_participants',
        attributes: {
          created_at: '2018-08-09T19:13:05Z',
          updated_at: '2018-08-09T19:13:05Z'
        },
        relationships: {
          video_consultation: {
            data: {
              id: '5',
              type: 'video_consultations'
            }
          },
          participant: {
            data: {
              id: '217',
              type: 'mobile_users'
            }
          }
        }
      },
      {
        id: '4',
        type: 'video_consultation_participants',
        attributes: {
          created_at: '2018-08-09T19:13:05Z',
          updated_at: '2018-08-09T19:13:05Z'
        },
        relationships: {
          video_consultation: {
            data: {
              id: '6',
              type: 'video_consultations'
            }
          },
          participant: {
            data: {
              id: '217',
              type: 'mobile_users'
            }
          }
        }
      }
    ]
  };

  t.context.getResponseEntries45 = {
    data: [
      {
        id: '1',
        type: 'ediary__entries',
        attributes: {
          created_at: '2017-06-20T17:55:12Z',
          updated_at: '2017-06-20T17:55:12Z',
          date: '2018-06-02'
        },
        relationships: {
          entry_group: {
            data: {
              id: '6',
              type: 'ediary__entry_groups'
            }
          },
          flow_process: {
            data: {
              id: '42',
              type: 'data_collection__flow_processes'
            }
          },
          captured_value_group: {
            data: null
          },
          owner: {
            data: {
              id: '45',
              type: 'mobile_users'
            }
          }
        }
      },
      {
        id: '2',
        type: 'ediary__entries',
        attributes: {
          created_at: '2017-06-20T17:55:12Z',
          updated_at: '2017-06-20T17:55:12Z',
          date: '2018-06-02'
        },
        relationships: {
          entry_group: {
            data: {
              id: '7',
              type: 'ediary__entry_groups'
            }
          },
          flow_process: {
            data: {
              id: '43',
              type: 'data_collection__flow_processes'
            }
          },
          captured_value_group: {
            data: null
          },
          owner: {
            data: {
              id: '45',
              type: 'mobile_users'
            }
          }
        }
      }
    ],
    included: [
      {
        id: '6',
        type: 'ediary__entry_groups',
        attributes: {
          name: 'dummy_378',
          permanent_link: 'dummy_379',
          position: 1,
          category: null,
          created_at: '2017-06-20T17:55:11Z',
          updated_at: '2017-06-20T17:55:11Z'
        },
        relationships: {
          ediary_entries: {
            data: [
              {
                id: '1',
                type: 'ediary__entries'
              }
            ]
          },
          entry_templates: {
            data: []
          },
          child_entry_groups: {
            data: []
          },
          parent_entry_group: {
            data: null
          }
        }
      },
      {
        id: '42',
        type: 'data_collection__flow_processes',
        attributes: {
          name: 'ipsa',
          permanent_link: 'dummy_380',
          consent_credentials: null,
          created_at: '2017-06-20T17:55:12Z',
          updated_at: '2017-06-20T17:55:12Z',
          owner_type: 'User',
          published_at: null,
          conditional_paths: null
        },
        relationships: {
          linked_steps: {
            data: []
          },
          published: {
            data: null
          },
          draft: {
            data: null
          },
          initial_step: {
            data: null
          }
        }
      },
      {
        id: '45',
        type: 'mobile_users',
        attributes: {
          uuid: '2017a89e-387f-410b-93f2-162e990c92db',
          account_name: 'dummy_45',
          email: 'user84@fake.com',
          encryption_key: null,
          created_at: '2017-06-20T17:55:11Z',
          updated_at: '2017-06-20T17:55:12Z',
          verified_at: null,
          invitation_sent_at: null,
          invitation_accepted_at: null
        },
        relationships: {
          devices: {
            data: []
          }
        }
      },
      {
        id: '7',
        type: 'ediary__entry_groups',
        attributes: {
          name: 'dummy_381',
          permanent_link: 'dummy_382',
          position: 2,
          category: null,
          created_at: '2017-06-20T17:55:12Z',
          updated_at: '2017-06-20T17:55:12Z'
        },
        relationships: {
          ediary_entries: {
            data: [
              {
                id: '2',
                type: 'ediary__entries'
              }
            ]
          },
          entry_templates: {
            data: []
          },
          child_entry_groups: {
            data: []
          },
          parent_entry_group: {
            data: null
          }
        }
      },
      {
        id: '43',
        type: 'data_collection__flow_processes',
        attributes: {
          name: 'ipsa',
          permanent_link: 'dummy_383',
          consent_credentials: null,
          created_at: '2017-06-20T17:55:12Z',
          updated_at: '2017-06-20T17:55:12Z',
          owner_type: 'User',
          published_at: null,
          conditional_paths: null
        },
        relationships: {
          linked_steps: {
            data: []
          },
          published: {
            data: null
          },
          draft: {
            data: null
          },
          initial_step: {
            data: null
          }
        }
      }
    ]
  };

  t.context.getResponseSchedules = {
    data: [
      {
        id: '1',
        type: 'scheduler__personalized_rule_schedules',
        attributes: {
          start_date: '2017-09-10',
          end_date: '2017-09-27',
          time: '10:00',
          timezone: 'UTC',
          relative_schedule: null,
          days_of_week: '0,1,2,3,4,5,6',
          relative_unit: null,
          start_date_offset: 0,
          start_date_offset_unit: null,
          skip_exceptions: false,
          enabled: true,
          exception_days: null,
          active_time_start: null,
          active_time_end: null
        },
        relationships: {
          mobile_user: {
            data: {
              id: '72',
              type: 'mobile_users'
            }
          },
          scheduleable: {
            data: {
              id: '1',
              type: 'reminder__rules'
            }
          }
        }
      },
      {
        id: '2',
        type: 'scheduler__personalized_rule_schedules',
        attributes: {
          start_date: '2017-09-10',
          end_date: '2017-09-27',
          time: '10:00',
          timezone: 'UTC',
          relative_schedule: null,
          days_of_week: '0,1,2,3,4,5,6',
          relative_unit: null,
          start_date_offset: 0,
          start_date_offset_unit: null,
          skip_exceptions: false,
          enabled: true,
          exception_days: null,
          active_time_start: null,
          active_time_end: null
        },
        relationships: {
          mobile_user: {
            data: {
              id: '72',
              type: 'mobile_users'
            }
          },
          scheduleable: {
            data: {
              id: '2',
              type: 'reminder__rules'
            }
          }
        }
      },
      {
        id: '3',
        type: 'scheduler__personalized_rule_schedules',
        attributes: {
          start_date: '2017-09-10',
          end_date: '2017-09-27',
          time: '10:00',
          timezone: 'UTC',
          relative_schedule: null,
          days_of_week: '0,1,2,3,4,5,6',
          relative_unit: null,
          start_date_offset: 0,
          start_date_offset_unit: null,
          skip_exceptions: false,
          enabled: true,
          exception_days: null,
          active_time_start: null,
          active_time_end: null
        },
        relationships: {
          mobile_user: {
            data: {
              id: '72',
              type: 'mobile_users'
            }
          },
          scheduleable: {
            data: {
              id: '3',
              type: 'reminder__rules'
            }
          }
        }
      }
    ],
    included: [
      {
        id: '1',
        type: 'reminder__rules',
        attributes: {
          permanent_link: 'dummy_274',
          label: null,
          created_at: '2017-09-12T05:36:25Z',
          updated_at: '2017-09-12T05:36:25Z'
        }
      },
      {
        id: '2',
        type: 'reminder__rules',
        attributes: {
          permanent_link: 'dummy_275',
          label: null,
          created_at: '2017-09-12T05:36:25Z',
          updated_at: '2017-09-12T05:36:25Z'
        }
      },
      {
        id: '3',
        type: 'reminder__rules',
        attributes: {
          permanent_link: 'dummy_276',
          label: null,
          created_at: '2017-09-12T05:36:25Z',
          updated_at: '2017-09-12T05:36:25Z'
        }
      }
    ]
  };

  t.context.deleteRequestMobileUser = {
    data: {
      id: '1',
      type: 'mobile_users',
      attributes: {
        account_name: '5nl1xkjc',
        username: '5nl1xkjc',
        created_at: '2017-05-15T19:08:17.076Z',
        email: null,
        encryption_key: null,
        updated_at: '2017-05-15T19:08:17.108Z',
        uuid: 'dddb2ab3-3be9-4a54-8c2c-7687c4ec9bee',
        verified_at: null,
        invitation_sent_at: null,
        invitation_accepted_at: null
      },
      relationships: {
        devices: {
          data: [
            {
              id: '1',
              type: 'devices'
            }
          ]
        }
      }
    },
    included: [
      {
        id: '1',
        type: 'devices',
        attributes: {
          udid: '660y6gb90yxlctukngk6',
          technology: 'ios',
          access_token: '4756992a843a504d2f786380b4a67760',
          push_id: 'tsg6mrcgrto71iyi6bt113d1d72x68koo0e22fkd0e3rppztbn40va32qyj98prq',
          created_at: '2017-05-15T19:08:16.000Z',
          updated_at: '2017-05-15T19:08:17.000Z',
          app_version: null
        }
      }
    ]
  };

  t.context.insertResponseAwardBadge39 = {
    data: {
      id: '32',
      type: 'awarded_badges',
      attributes: {
        created_at: '2017-08-10T17:54:18Z',
        updated_at: '2017-08-10T17:54:18Z',
        count: 0,
        earned_on_date: null
      },
      relationships: {
        awardee: {
          data: {
            type: 'mobile_users',
            id: '486'
          }
        },
        badge: {
          data: {
            type: 'badges',
            id: '39'
          }
        }
      }
    },
    included: [
      {
        id: '39',
        type: 'badges',
        attributes: {
          created_at: '2017-08-09T16:23:56Z',
          updated_at: '2017-08-09T16:23:56Z',
          title: 'dummy_462',
          description: 'Demo Content info...',
          redemption_points: 250,
          image: {
            image: {
              url: '/uploads/test/reward/image/17/1.png',
              small: {
                url: '/uploads/test/reward/image/17/small_1.png'
              },
              small_hd: {
                url: '/uploads/test/reward/image/17/small_hd_1.png'
              },
              fullscreen: {
                url: '/uploads/test/reward/image/17/fullscreen_1.png'
              },
              main: {
                url: '/uploads/test/reward/image/17/main_1.png'
              },
              fullscreen_hd: {
                url: '/uploads/test/reward/image/17/fullscreen_hd_1.png'
              },
              main_hd: {
                url: '/uploads/test/reward/image/17/main_hd_1.png'
              }
            }
          },
          position: 1,
          enabled: true,
          featured: null,
          based_on: null,
          threshold: null,
          time_unit: null,
          start_point: null,
          start_at: null,
          disabled_image: {
            disabled_image: {
              url: '/default/default.png',
              small: {
                url: '/default/small_default.png'
              },
              small_hd: {
                url: '/default/small_hd_default.png'
              },
              fullscreen: {
                url: '/default/fullscreen_default.png'
              },
              main: {
                url: '/default/main_default.png'
              },
              fullscreen_hd: {
                url: '/default/fullscreen_hd_default.png'
              },
              main_hd: {
                url: '/default/main_hd_default.png'
              }
            }
          },
          cache_token: 'xMnLvzU_uu4'
        }
      }
    ]
  };

  t.context.insertResponseEntries53 = {
    data: {
      id: '7',
      type: 'ediary__entries',
      attributes: {
        created_at: '2017-06-27T20:32:07Z',
        updated_at: '2017-06-27T20:32:07Z',
        date: '2018-06-02'
      },
      relationships: {
        entry_group: {
          data: {
            id: '8',
            type: 'ediary__entry_groups'
          }
        },
        template: {
          data: {
            id: '7',
            type: 'ediary__entry_templates'
          }
        },
        captured_value_group: {
          data: null
        },
        owner: {
          data: {
            id: '22',
            type: 'mobile_users'
          }
        },
        status: {
          data: null
        }
      }
    },
    included: [
      {
        id: '7',
        type: 'ediary__entry_templates',
        attributes: {
          category: 'automatic',
          created_at: '2017-06-27T20:32:07Z',
          updated_at: '2017-06-27T20:32:07Z'
        },
        relationships: {
          entry_group: {
            data: {
              id: '8',
              type: 'ediary__entry_groups'
            }
          },
          flow_process: {
            data: {
              id: '23',
              type: 'data_collection__flow_processes'
            }
          }
        }
      },
      {
        id: '22',
        type: 'mobile_users',
        attributes: {
          uuid: '51edc9a9-6e07-4ffd-a22a-8a620f45ac99',
          account_name: 'dummy_21',
          email: 'user55@fake.com',
          encryption_key: null,
          created_at: '2017-06-27T20:32:07Z',
          updated_at: '2017-06-27T20:32:07Z',
          verified_at: null,
          invitation_sent_at: null,
          invitation_accepted_at: null
        },
        relationships: {
          devices: {
            data: []
          }
        }
      },
      {
        id: '8',
        type: 'ediary__entry_groups',
        attributes: {
          name: 'dummy_3781',
          permanent_link: 'dummy_3791',
          position: 1,
          category: null,
          created_at: '2017-06-20T17:55:11Z',
          updated_at: '2017-06-20T17:55:11Z'
        },
        relationships: {
          ediary_entries: {
            data: [
              {
                id: '7',
                type: 'ediary__entries'
              }
            ]
          },
          entry_templates: {
            data: []
          },
          child_entry_groups: {
            data: []
          },
          parent_entry_group: {
            data: null
          }
        }
      }
    ]
  };

  t.context.insertResponseMobileUser = {
    data: {
      id: '1',
      type: 'mobile_users',
      attributes: {
        account_name: '5nl1xkjc',
        username: '5nl1xkjc',
        created_at: '2017-05-15T19:08:17.076Z',
        email: null,
        encryption_key: null,
        updated_at: '2017-05-15T19:08:17.108Z',
        uuid: 'dddb2ab3-3be9-4a54-8c2c-7687c4ec9bee',
        verified_at: null,
        invitation_sent_at: null,
        invitation_accepted_at: null
      },
      relationships: {
        devices: {
          data: [
            {
              id: '1',
              type: 'devices'
            }
          ]
        }
      }
    },
    included: [
      {
        id: '1',
        type: 'devices',
        attributes: {
          udid: '660y6gb90yxlctukngk6',
          technology: 'ios',
          access_token: '4756992a843a504d2f786380b4a67760',
          push_id: 'tsg6mrcgrto71iyi6bt113d1d72x68koo0e22fkd0e3rppztbn40va32qyj98prq',
          created_at: '2017-05-15T19:08:16.000Z',
          updated_at: '2017-05-15T19:08:17.000Z',
          app_version: null
        }
      }
    ]
  };

  t.context.insertRequestMobileUser = {
    data: {
      type: 'mobile_users',
      attributes: {
        account_name: '5nl1xkjc',
        username: '5nl1xkjc',
        created_at: '2017-05-15T19:08:17.076Z',
        email: null,
        encryption_key: null,
        updated_at: '2017-05-15T19:08:17.108Z',
        uuid: 'dddb2ab3-3be9-4a54-8c2c-7687c4ec9bee',
        verified_at: null,
        invitation_sent_at: null,
        invitation_accepted_at: null
      }
    }
  };

  t.context.updateResponseMobileUser = {
    data: {
      id: 1,
      type: 'mobile_users',
      attributes: {
        account_name: '5nl1xkjc',
        username: '5nl1xkjc',
        created_at: '2017-05-15T19:08:17.076Z',
        email: null,
        encryption_key: null,
        updated_at: '2017-05-15T19:08:17.108Z',
        uuid: 'dddb2ab3-3be9-4a54-8c2c-7687c4ec9bee',
        verified_at: null,
        invitation_sent_at: null,
        invitation_accepted_at: null
      }
    }
  };

  t.context.updateResponseMobileUser9 = {
    data: {
      id: 9,
      type: 'mobile_users',
      attributes: {
        uuid: '6234e115-b9b4-44ae-aa8a-66b8f04d4f0e',
        email: 'user1@fake.com',
        created_at: '2018-02-27T13:41:00Z',
        updated_at: '2018-02-28T04:44:14Z',
        invitation_sent_at: null,
        invitation_accepted_at: null,
        disabled_at: null,
        access_locked: false
      },
      relationships: {
        user_role: {
          data: {
            id: 1,
            type: 'user_roles'
          }
        },
        devices: {
          data: []
        },
        profile: {
          data: {
            id: 6,
            type: 'profiles'
          }
        }
      }
    },
    included: [
      {
        id: 1,
        type: 'user_roles',
        attributes: {
          permanent_link: 'admin',
          name: 'Admin',
          is_super: false,
          is_admin: true,
          is_mobile: false,
          is_default: false
        }
      },
      {
        id: 6,
        type: 'profiles',
        attributes: {
          created_at: '2018-02-27T13:41:00Z',
          updated_at: '2018-02-27T13:41:00Z',
          first_name: 'Molly',
          middle_initial: null,
          last_name: 'Cartwright',
          prefix: null,
          suffix: null,
          gender: 'male',
          ethnicity: '',
          occupation: null,
          avatar: {
            url: '/uploads/development/profile/avatar/6/d1946007ee44d672e4eb2390ce9cad8bf15b7bac.png',
            small: {
              url: '/uploads/development/profile/avatar/6/small_d1946007ee44d672e4eb2390ce9cad8bf15b7bac.png'
            },
            main: {
              url: '/uploads/development/profile/avatar/6/main_d1946007ee44d672e4eb2390ce9cad8bf15b7bac.png'
            },
            thumb: {
              url: '/uploads/development/profile/avatar/6/thumb_d1946007ee44d672e4eb2390ce9cad8bf15b7bac.png'
            }
          },
          username: null,
          dob: null,
          timezone: 'UTC',
          phone: null,
          email: 'user1@fake.com',
          age: 28,
          language: {
            id: 1,
            iso: 'en',
            name: 'English',
            created_at: '2018-02-14T15:43:25Z',
            updated_at: '2018-02-14T15:43:25Z',
            is_default: true,
            image: {
              url: '/assets/default/default-16daaa70b849a969f5ab41d3b7c9513c8ca890a6dd3b30e39c5afc25b8a773b6.png',
              thumb: {
                url: '/assets/default/thumb_default-80b0cfa7e6bd6ee57d0f3806eb25b31a842fe9ab69fc4a594303f5555b5bc4bd.png'
              }
            }
          }
        },
        relationships: {
          profileable: {
            data: {
              id: 4,
              type: 'users'
            }
          }
        }
      }
    ]
  };

  t.context.updateResponseResetPassword = {
    data: {
      id: '32',
      type: 'mobile_users',
      attributes: {
        uuid: 'my-special-uuid',
        account_name: '47926633',
        email: 'myEmail@email.com',
        created_at: '2018-04-16T16:32:36Z',
        updated_at: '2018-04-25T22:04:55Z',
        invitation_sent_at: '2018-04-16T16:32:36Z',
        invitation_accepted_at: '2018-04-16T16:36:17Z',
        disabled: false,
        disabled_at: null
      },
      relationships: {
        devices: {
          data: [
            {
              id: '81',
              type: 'devices'
            },
            {
              id: '91',
              type: 'devices'
            },
            {
              id: '93',
              type: 'devices'
            },
            {
              id: '95',
              type: 'devices'
            },
            {
              id: '100',
              type: 'devices'
            },
            {
              id: '101',
              type: 'devices'
            },
            {
              id: '104',
              type: 'devices'
            },
            {
              id: '114',
              type: 'devices'
            },
            {
              id: '117',
              type: 'devices'
            },
            {
              id: '124',
              type: 'devices'
            },
            {
              id: '134',
              type: 'devices'
            },
            {
              id: '148',
              type: 'devices'
            },
            {
              id: '258',
              type: 'devices'
            },
            {
              id: '259',
              type: 'devices'
            },
            {
              id: '262',
              type: 'devices'
            },
            {
              id: '264',
              type: 'devices'
            },
            {
              id: '267',
              type: 'devices'
            },
            {
              id: '368',
              type: 'devices'
            },
            {
              id: '369',
              type: 'devices'
            },
            {
              id: '371',
              type: 'devices'
            },
            {
              id: '375',
              type: 'devices'
            }
          ]
        },
        user_role: {
          data: {
            id: '8',
            type: 'user_roles'
          }
        },
        profile: {
          data: {
            id: '96',
            type: 'profiles'
          }
        },
        language: {
          data: {
            id: '1',
            type: 'languages'
          }
        },
        patient: {
          data: {
            id: '17',
            type: 'trials__site_members'
          }
        },
        threads: {
          data: []
        }
      }
    },
    included: [
      {
        id: '81',
        type: 'devices',
        attributes: {
          udid: 'android-device-udid',
          technology: 'android',
          access_token: 'android-token-81',
          push_id: null,
          created_at: '2018-04-16T16:35:53Z',
          updated_at: '2018-04-16T16:36:17Z',
          app_version: null
        }
      },
      {
        id: '91',
        type: 'devices',
        attributes: {
          udid: 'android-device-udid',
          technology: 'android',
          access_token: 'android-token-91',
          push_id: null,
          created_at: '2018-04-16T18:12:04Z',
          updated_at: '2018-04-16T18:12:15Z',
          app_version: null
        }
      },
      {
        id: '93',
        type: 'devices',
        attributes: {
          udid: 'android-device-udid',
          technology: 'android',
          access_token: 'android-token-93',
          push_id: null,
          created_at: '2018-04-16T18:17:01Z',
          updated_at: '2018-04-16T18:17:06Z',
          app_version: null
        }
      },
      {
        id: '95',
        type: 'devices',
        attributes: {
          udid: 'android-device-udid',
          technology: 'android',
          access_token: 'android-token-95',
          push_id: null,
          created_at: '2018-04-16T18:21:54Z',
          updated_at: '2018-04-16T18:21:56Z',
          app_version: null
        }
      },
      {
        id: '100',
        type: 'devices',
        attributes: {
          udid: null,
          technology: null,
          access_token: '???-token-100',
          push_id: null,
          created_at: '2018-04-16T18:37:19Z',
          updated_at: '2018-04-16T18:37:21Z',
          app_version: null
        }
      },
      {
        id: '101',
        type: 'devices',
        attributes: {
          udid: 'android-device-udid',
          technology: 'android',
          access_token: 'android-token-101',
          push_id: null,
          created_at: '2018-04-16T18:52:08Z',
          updated_at: '2018-04-16T18:52:10Z',
          app_version: null
        }
      },
      {
        id: '104',
        type: 'devices',
        attributes: {
          udid: 'b0bddcf93bf3638b',
          technology: 'android',
          access_token: 'android-token-104',
          push_id: null,
          created_at: '2018-04-16T19:07:13Z',
          updated_at: '2018-04-16T19:07:20Z',
          app_version: null
        }
      },
      {
        id: '114',
        type: 'devices',
        attributes: {
          udid: 'android-device-udid',
          technology: 'android',
          access_token: 'android-token-114',
          push_id: null,
          created_at: '2018-04-17T00:15:21Z',
          updated_at: '2018-04-17T00:15:48Z',
          app_version: null
        }
      },
      {
        id: '117',
        type: 'devices',
        attributes: {
          udid: 'android-device-udid',
          technology: 'android',
          access_token: 'android-token-117',
          push_id: null,
          created_at: '2018-04-17T00:25:18Z',
          updated_at: '2018-04-17T00:26:01Z',
          app_version: null
        }
      },
      {
        id: '124',
        type: 'devices',
        attributes: {
          udid: 'android-device-udid',
          technology: 'android',
          access_token: 'android-token-124',
          push_id: null,
          created_at: '2018-04-17T18:36:28Z',
          updated_at: '2018-04-17T18:36:36Z',
          app_version: null
        }
      },
      {
        id: '134',
        type: 'devices',
        attributes: {
          udid: null,
          technology: null,
          access_token: '???-token-134',
          push_id: null,
          created_at: '2018-04-17T22:46:25Z',
          updated_at: '2018-04-17T22:46:32Z',
          app_version: null
        }
      },
      {
        id: '148',
        type: 'devices',
        attributes: {
          udid: null,
          technology: null,
          access_token: '???-token-148',
          push_id: null,
          created_at: '2018-04-18T21:39:12Z',
          updated_at: '2018-04-18T21:39:24Z',
          app_version: null
        }
      },
      {
        id: '258',
        type: 'devices',
        attributes: {
          udid: 'android-device-udid',
          technology: 'android',
          access_token: 'android-token-258',
          push_id: null,
          created_at: '2018-04-25T03:41:40Z',
          updated_at: '2018-04-25T03:41:41Z',
          app_version: null
        }
      },
      {
        id: '259',
        type: 'devices',
        attributes: {
          udid: 'android-device-udid',
          technology: 'android',
          access_token: 'android-token-259',
          push_id: null,
          created_at: '2018-04-25T03:44:32Z',
          updated_at: '2018-04-25T03:44:49Z',
          app_version: null
        }
      },
      {
        id: '262',
        type: 'devices',
        attributes: {
          udid: 'android-device-udid',
          technology: 'android',
          access_token: 'android-token-262',
          push_id: null,
          created_at: '2018-04-25T03:48:20Z',
          updated_at: '2018-04-25T03:48:21Z',
          app_version: null
        }
      },
      {
        id: '264',
        type: 'devices',
        attributes: {
          udid: 'android-device-udid',
          technology: 'android',
          access_token: 'android-token-264',
          push_id: null,
          created_at: '2018-04-25T03:57:13Z',
          updated_at: '2018-04-25T03:57:14Z',
          app_version: null
        }
      },
      {
        id: '267',
        type: 'devices',
        attributes: {
          udid: 'android-device-udid',
          technology: 'android',
          access_token: 'android-token-267',
          push_id: null,
          created_at: '2018-04-25T04:00:23Z',
          updated_at: '2018-04-25T04:00:24Z',
          app_version: null
        }
      },
      {
        id: '368',
        type: 'devices',
        attributes: {
          udid: 'ios-device-udid',
          technology: 'ios',
          access_token: 'ios-token-368',
          push_id: null,
          created_at: '2018-04-25T21:49:41Z',
          updated_at: '2018-04-25T21:49:41Z',
          app_version: null
        }
      },
      {
        id: '369',
        type: 'devices',
        attributes: {
          udid: 'ios-device-udid',
          technology: 'ios',
          access_token: 'ios-token-369',
          push_id: null,
          created_at: '2018-04-25T21:55:56Z',
          updated_at: '2018-04-25T21:56:23Z',
          app_version: null
        }
      },
      {
        id: '371',
        type: 'devices',
        attributes: {
          udid: 'ios-device-udid',
          technology: 'ios',
          access_token: 'ios-token-371',
          push_id: null,
          created_at: '2018-04-25T21:57:55Z',
          updated_at: '2018-04-25T21:57:56Z',
          app_version: null
        }
      },
      {
        id: '375',
        type: 'devices',
        attributes: {
          udid: 'ios-device-udid',
          technology: 'ios',
          access_token: 'ios-token-375',
          push_id: null,
          created_at: '2018-04-25T22:04:54Z',
          updated_at: '2018-04-25T22:04:55Z',
          app_version: null
        }
      },
      {
        id: '8',
        type: 'user_roles',
        attributes: {
          permanent_link: 'subject',
          name: 'Subject',
          is_super: false,
          is_admin: false,
          is_mobile: true,
          is_default: false
        }
      }
    ]
  };

  t.context.updateResponseSchedule = {
    data: {
      id: '5',
      type: 'scheduler__personalized_rule_schedules',
      attributes: {
        start_date: '2017-06-02',
        end_date: '2017-09-27',
        time: '10:00',
        timezone: 'UTC',
        relative_schedule: '1,2,4,8,12,14,16',
        days_of_week: '0,1,2,3,4,5,6',
        relative_unit: null,
        start_date_offset: 0,
        start_date_offset_unit: null,
        skip_exceptions: false,
        enabled: false,
        exception_days: null,
        active_time_start: null,
        active_time_end: null
      },
      relationships: {
        mobile_user: {
          data: {
            id: '74',
            type: 'mobile_users'
          }
        },
        scheduleable: {
          data: {
            id: '4',
            type: 'reminder__rules'
          }
        }
      }
    }
  };
});

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

test.beforeEach((t) => {
  client.cache = 'never';
  client.authToken = 'valid_token';
  mobileUserService.cacheMode = 'networkOnly';

  const awardee = new User({ id: 510, email: 'test@test.com' });
  awardee.store();

  t.context.storage = client.storageUtility;
  // t.context.storage.clear();
});

// UserService.addAwardedBadge method
/**
 * @test {UserService.addAwardedBadge}
 */
test('[unit] UserService.addAwardedBadge should throw errors for invalid parameters', async (t) => {
  const title = 'UserService.addAwardedBadge error';

  // undefined mobile user
  await t.throwsAsync(mobileUserService.addAwardedBadge(), `${title}: awardedBadge is not defined`);
  await t.throwsAsync(mobileUserService.addAwardedBadge({}), `${title}: awardedBadge does not have badge`);
  const awardedBadge = new AwardedBadge();
  awardedBadge.badge = new Badge();
  awardedBadge.awardee = { hello: 'world' };
  await t.throwsAsync(mobileUserService.addAwardedBadge(awardedBadge), `${title}: awardee does not have id and badge does not have id`);
  awardedBadge.badge.id = 1;
  await t.throwsAsync(mobileUserService.addAwardedBadge(awardedBadge), `${title}: awardee does not have id`);
});

/**
 * @test {UserService.addAwardedBadge}
 */
test('[unit] UserService.addAwardedBadge should successfully addAwardedBadge (api example)', async (t) => {
  // api-doc/1.0/registrations.html
  // http://clinical6-docs.s3-website-us-east-1.amazonaws.com/apidoc/v3relationshipsbadges/create.html
  const { insertResponseAwardBadge39 } = t.context;

  const requestJsonApi = {
    data: {
      type: 'awarded_badges',
      attributes: {},
      relationships: {
        awardee: {
          data: {
            type: 'mobile_users',
            id: 486
          }
        },
        badge: {
          data: {
            type: 'badges',
            id: 39
          }
        }
      }
    }
  };

  const awardedBadge = new AwardedBadge({});
  awardedBadge.awardee = new User({ id: 486 });
  awardedBadge.awardee.store();
  awardedBadge.badge = new Badge({ id: 39 });
  awardedBadge.badge.store();

  let request = {};
  nock(client.apiBaseUrl).post(`/v3/mobile_users/${awardedBadge.awardee.id}/awarded_badges`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [201, insertResponseAwardBadge39];
  });
  const response = await mobileUserService.addAwardedBadge(awardedBadge);

  t.is(request.path, `/v3/mobile_users/${awardedBadge.awardee.id}/awarded_badges`);
  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.truthy(response);
  t.is(response.constructor.name, 'AwardedBadge');
});

/**
 * @test {UserService.update}
 */
test('[unit] UserService.update should enable a user', async (t) => {
  const { updateResponseMobileUser9 } = t.context;
  let request = {};
  nock(client.apiBaseUrl).patch(`/v3/mobile_users/9`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [201, updateResponseMobileUser9];
  });

  const requestJsonApi = {
    data: {
      id: 9,
      type: 'mobile_users',
      attributes: {
        account_name: '5nl1xkjc',
        username: '5nl1xkjc',
        created_at: '2017-05-15T19:08:17.076Z',
        email: null,
        encryption_key: null,
        updated_at: '2017-05-15T19:08:17.108Z',
        uuid: 'dddb2ab3-3be9-4a54-8c2c-7687c4ec9bee',
        verified_at: null,
        invitation_sent_at: null,
        invitation_accepted_at: null,
        enabled: true
      }
    }
  };
  const user = new User(requestJsonApi);
  const response = await mobileUserService.update(user);

  t.is(request.path, `/v3/mobile_users/9`);
  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, 9);
  t.is(response.type, 'mobile_users');
  t.is(response.disabledAt, null);
});

// UserService.addSchedule method
/**
 * @test {UserService.addSchedule}
 */
test('[unit] UserService.addSchedule should throw errors for invalid parameters', async (t) => {
  const title = 'UserService.addSchedule error';

  // undefined mobile user
  await t.throwsAsync(mobileUserService.addSchedule(), `${title}: schedule is not defined`);
  await t.throwsAsync(mobileUserService.addSchedule({}), `${title}: user does not have id`);
});

/**
 * @test {UserService.addSchedule}
 */
test('[unit] UserService.addSchedule should successfully addSchedule (api example)', async (t) => {
  // api-doc/1.0/registrations.html
  // http://clinical6-docs.s3-website-us-east-1.amazonaws.com/apidoc/v3relationshipsschedulerpersonalized_rule_schedules/create.html

  const requestJsonApi = {
    data: {
      type: 'scheduler__personalized_rule_schedules',
      attributes: {
        start_date: '2017-06-02',
        relative_schedule: '1,2,4,8,12,14,16',
        enabled: true
      },
      relationships: {
        mobile_user: {
          data: {
            id: 81,
            type: 'mobile_users'
          }
        },
        scheduleable: {
          data: {
            type: 'ediary__entry_groups',
            id: 1
          }
        }
      }
    }
  };

  const schedule = new Schedule(requestJsonApi);
  schedule.scheduleable = new EntryGroup({ id: 1 });
  schedule.scheduleable.store();
  schedule.mobileUser = new User({ id: 81 });
  schedule.mobileUser.store();

  // /v3/mobile_users/${schedule.mobileUser.id}/scheduler/personalized_rule_schedules
  let request = {};
  nock(client.apiBaseUrl).post(`/v3/mobile_users/${schedule.mobileUser.id}/scheduler/personalized_rule_schedules`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [201, {
      data: {
        id: '5',
        type: 'scheduler__personalized_rule_schedules',
        attributes: {
          start_date: '2017-06-02',
          end_date: null,
          time: null,
          timezone: null,
          relative_schedule: '1,2,4,8,12,14,16',
          days_of_week: null,
          relative_unit: null,
          start_date_offset: null,
          start_date_offset_unit: null,
          skip_exceptions: null,
          enabled: true,
          exception_days: null,
          active_time_start: null,
          active_time_end: null
        },
        relationships: {
          mobile_user: {
            data: {
              id: 81,
              type: 'mobile_users'
            }
          },
          scheduleable: {
            data: {
              id: '1',
              type: 'ediary__entry_groups'
            }
          }
        }
      }
    }];
  });
  const response = await mobileUserService.addSchedule(schedule);

  t.is(request.path, `/v3/mobile_users/${schedule.mobileUser.id}/scheduler/personalized_rule_schedules`);
  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.truthy(response);
  t.is(response.constructor.name, 'Schedule');
});

// UserService.confirm method
/**
 * @test {UserService.confirm}
 */
test('[unit] UserService.confirm should throw errors for invalid parameters', async (t) => {
  const undefinedError = 'UserService.confirm error: token is not defined';
  const validError = 'UserService.confirm error: token is not a string';

  // undefined mobile user
  await t.throwsAsync(mobileUserService.confirm(), undefinedError);
  await t.throwsAsync(mobileUserService.confirm(1234), validError);
});

// http://clinical6-docs.s3-website-us-east-1.amazonaws.com/apidoc/confirmations/show.html
/**
 * @test {UserService.confirm}
 */
test('[unit] UserService.confirm should successfully get the registration status of a mobile user', async (t) => {
  const { getResponseConfirmRegistration } = t.context;
  let request = {};
  nock(client.apiBaseUrl).get(`/v3/mobile_users/confirmation?confirmation_token=ztpt2adhx1l7h3h7e5x1`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, getResponseConfirmRegistration];
  });

  const response = await mobileUserService.confirm('ztpt2adhx1l7h3h7e5x1');

  t.is(request.path, `/v3/mobile_users/confirmation?confirmation_token=ztpt2adhx1l7h3h7e5x1`);
  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.id, 196);
  t.is(response.type, 'mobile_users');
  t.is(response.accountName, 'dummy_178');
  t.is(response.email, 'user273@fake.com');
  t.is(response.createdAt, '2017-06-07T23:58:58Z');
  t.is(response.updatedAt, '2017-06-07T23:58:58Z');
  t.is(response.disabledAt, '2017-06-07T23:58:58Z');
  t.is(response.devices[0].id, 110);
});

/**
 * @test {UserService.confirm}
 */
test('[unit] UserService.confirm should throw an error if the token is invalid', async (t) => {
  let request = {};
  nock(client.apiBaseUrl).get(`/v3/mobile_users/confirmation?confirmation_token=invalid_token`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [422, { confirmation_token: ['is invalid'] }];
  });
  const response = await mobileUserService.confirm('invalid_token').catch(r => r);

  t.is(request.path, `/v3/mobile_users/confirmation?confirmation_token=invalid_token`);
  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);
});

// UserService.delete method
/**
 * @test {UserService.delete}
 */
test('[unit] UserService.delete should throw errors for invalid parameters', async (t) => {
  const undefinedError = 'UserService.delete error: user is not defined';
  await t.throwsAsync(mobileUserService.delete(), undefinedError);
});

/**
 * @test {UserService.delete}
 */
test('[unit] UserService.delete should receive a valid response for a delete request', async (t) => {
  const { deleteRequestMobileUser } = t.context;
  const user = new User(deleteRequestMobileUser);
  let request = {};
  nock(client.apiBaseUrl).delete(`/v3/mobile_users/${user.id}`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [204, { status: 'ok' }];
  });
  const response = await mobileUserService.delete(user);
  t.is(request.path, `/v3/mobile_users/${user.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.truthy(response);
});

/**
 * @test {UserService.delete}
 */
test('[unit] UserService.delete should remove the element from local storage', async (t) => {
  const { deleteRequestMobileUser, storage } = t.context;
  const user = new User(deleteRequestMobileUser);
  user.id = 2938;
  user.store();
  nock(client.apiBaseUrl).delete(`/v3/mobile_users/${user.id}`).reply(204, { status: 'ok' });
  await mobileUserService.delete(user);
  t.is(storage.has('mobile_users', user.id), false);
});

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

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

/**
 * @test {UserService.get}
 */
test('[unit] UserService.get should receive a valid response for a get request with an id', async (t) => {
  const { getResponse2 } = t.context;
  let request = {};
  nock(client.apiBaseUrl).get(`/v3/mobile_users/2`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, getResponse2];
  });
  const response = await mobileUserService.get({ id: 2 });
  t.is(request.path, `/v3/mobile_users/2`);
  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.id, 2);
  t.is(response.type, 'mobile_users');
  t.is(response.uuid, 'dddb2ab3-3be9-4a54-8c2c-7687c4ec9bee');
  t.is(response.accountName, '5nl1xkjc');
  t.is(response.createdAt, '2017-05-15T19:08:17.076Z');
  t.is(response.updatedAt, '2017-05-15T19:08:17.108Z');
});

// UserService.getChildren method
/**
 * @test {Clinical6.getChildren}
 */
test.serial('[unit] UserService.getChildren should throw an error when there is no authToken or invalid params', async (t) => {
  client.authToken = undefined;
  const title = `UserService.getChildren error`;
  const user = new User({ id: 22 });

  await t.throwsAsync(clinical6.getChildren(user, CohortAssignment), `${title}: requires authToken`);
  client.authToken = 'valid_authToken';
  await t.throwsAsync(clinical6.getChildren(user), `${title}: child does not have type`);
});

/**
 * @test {Clinical6.getChildren}
 */
test.serial(`[unit] UserService.getChildren should receive a valid request and response for a get request for CohortAssignments`, async (t) => {
  const { getResponseAssignments80 } = t.context;
  const user = new User({ id: 80 });
  user.type = 'mobile_users';
  user.email = 'myEmail@email.com';
  await user.store();

  let request = {};
  nock(client.apiBaseUrl).get(`/v3/mobile_users/${user.id}/cohort_assignments`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, getResponseAssignments80];
  });

  const response = await clinical6.getChildren(user, CohortAssignment);
  t.is(request.path, `/v3/mobile_users/${user.id}/cohort_assignments`);
  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);

  t.truthy(response[0] instanceof CohortAssignment);
  t.is(response[0].id, 6);
  t.is(response[0].type, 'cohort_assignments');
  t.is(response[0].createdAt, '2018-04-25T17:44:57Z');
  t.is(response[0].updatedAt, '2018-04-25T17:44:57Z');
  t.truthy(response[0].user);
  t.is(response[0].user.id, 80);
  t.is(response[0].user.email, 'myEmail@email.com');
  t.truthy(response[0].cohort);
  t.is(response[0].cohort.id, 22);
  t.is(response[0].cohort.cohortType, 'static');
  t.is(response[0].cohort.createdAt, '2018-04-25T17:44:57Z');
  t.is(response[0].cohort.name, 'name-22');
  t.is(response[0].cohort.updatedAt, '2018-04-25T17:44:57Z');

  t.truthy(response[1] instanceof CohortAssignment);
  t.is(response[1].id, 7);
  t.is(response[1].type, 'cohort_assignments');
  t.is(response[1].createdAt, '2018-04-25T17:44:57Z');
  t.is(response[1].updatedAt, '2018-04-25T17:44:57Z');

  t.truthy(response[2] instanceof CohortAssignment);
  t.is(response[2].id, 8);
  t.is(response[2].type, 'cohort_assignments');
  t.is(response[2].createdAt, '2018-04-25T17:44:57Z');
  t.is(response[2].updatedAt, '2018-04-25T17:44:57Z');
});

/**
 * @test {Clinical6.getChildren}
 */
test.serial(`[unit] UserService.getChildren should receive a valid request and response for a get request for AvailableStrategy`, async (t) => {
  const { getResponseStrategies77 } = t.context;
  const user = new User({ id: 77 });
  user.type = 'mobile_users';
  user.email = 'myEmail@email.com';
  await user.store();

  let request = {};
  nock(client.apiBaseUrl).get(`/v3/${user.type}/${user.id}/consent/available_strategies`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, getResponseStrategies77];
  });

  const response = await clinical6.getChildren(user, AvailableStrategy);
  t.is(request.path, `/v3/${user.type}/${user.id}/consent/available_strategies`);
  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, 2);

  t.truthy(response[0] instanceof AvailableStrategy);
  t.is(response[0].id, 7);
  t.is(response[0].type, 'consent__available_strategies');
  t.is(response[0].strategy.id, 7);
  t.is(response[0].strategy.type, 'consent__strategies');
  t.is(response[0].strategy.name, 'Strategy-8');
  t.is(response[0].strategy.cohort.id, 9);
  t.is(response[0].strategy.cohort.type, 'cohorts');
  t.is(response[0].strategy.forms.length, 2);
  t.is(response[0].strategy.forms[0].id, 5);
  t.is(response[0].strategy.forms[0].type, 'consent__forms');
  t.is(response[0].strategy.forms[1].id, 6);
  t.is(response[0].strategy.forms[1].type, 'consent__forms');

  t.is(response[0].forms.length, 2);
  t.is(response[0].forms[0].id, 5);
  t.is(response[0].forms[0].type, 'consent__forms');
  t.is(response[0].forms[0].enabled, true);
  t.is(response[0].forms[0].name, 'Form 5');
  t.is(response[0].forms[0].consentFormVersions.length, 2);
  t.is(response[0].forms[0].consentFormVersions[0].id, 5);
  t.is(response[0].forms[0].consentFormVersions[0].type, 'consent__form_versions');
  t.is(response[0].forms[0].consentFormVersions[1].id, 6);
  t.is(response[0].forms[0].consentFormVersions[1].type, 'consent__form_versions');
  t.is(response[0].forms[0].consentStrategy.id, 7);
  t.is(response[0].forms[0].consentStrategy.type, 'consent__strategies');

  t.is(response[0].forms[1].id, 6);
  t.is(response[0].forms[1].type, 'consent__forms');

  t.is(response[0].forms[1].consentFormVersions.length, 1);
  t.is(response[0].forms[1].consentFormVersions[0].id, 7);
  t.is(response[0].forms[1].consentFormVersions[0].type, 'consent__form_versions');
  t.is(response[0].forms[1].consentStrategy.id, 7);
  t.is(response[0].forms[1].consentStrategy.type, 'consent__strategies');

  t.truthy(response[1] instanceof AvailableStrategy);
  t.is(response[1].id, 8);
  t.is(response[1].strategy.id, 8);
  t.is(response[1].strategy.type, 'consent__strategies');
  t.is(response[1].strategy.name, 'Strategy-9');
  t.is(response[1].strategy.cohort.id, 9);
  t.is(response[1].strategy.forms.length, 0);
  t.is(response[1].forms, undefined);
});

/**
 * @test {Clinical6.getChildren}
 */
test.serial(`[unit] UserService.getChildren should receive a valid request and response for a get request for ConsentGrants`, async (t) => {
  const { getResponseGrants454 } = t.context;
  const user = new User({ id: 80 });
  user.type = 'mobile_users';
  user.email = 'myEmail@email.com';
  await user.store();

  let request = {};
  nock(client.apiBaseUrl).get(`/v3/mobile_users/${user.id}/consent/grants`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, getResponseGrants454];
  });

  const response = await clinical6.getChildren(user, ConsentGrant);
  t.is(request.path, `/v3/mobile_users/${user.id}/consent/grants`);
  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, 2);

  t.truthy(response[0] instanceof ConsentGrant);
  t.is(response[0].id, 3);
  t.is(response[0].type, 'consent__grants');
  t.is(response[0].documentUrl, '/uploads/test/consent/grant/document/3/1.pdf');
  t.is(response[0].progress, 'all_signed');
  t.is(response[0].createdAt, '2018-07-20T13:32:51Z');
  t.is(response[0].updatedAt, '2018-07-20T13:32:51Z');
  t.truthy(response[0].grantedFor);
  t.is(response[0].grantedFor.id, 454);
  t.is(response[0].grantedFor.type, 'mobile_users');
  t.truthy(response[0].grantedBy);
  t.is(response[0].grantedBy.id, 454);
  t.is(response[0].grantedBy.type, 'mobile_users');
  t.truthy(response[0].strategy);
  t.is(response[0].strategy.id, 62);
  t.is(response[0].strategy.type, 'consent__strategies');
  t.is(response[0].strategy.name, 'Strategy-67');
  t.is(response[0].strategy.strategyType, 'paper');
  t.is(response[0].strategy.createdAt, '2018-07-20T13:32:51Z');
  t.is(response[0].strategy.updatedAt, '2018-07-20T13:32:51Z');
  t.is(response[0].strategy.cohort.id, 105);
  t.is(response[0].strategy.cohort.type, 'cohorts');
  t.is(response[0].strategy.forms.length, 0);
  t.is(response[0].formVersion, null);
  t.is(response[0].agreement, null);

  t.truthy(response[1] instanceof ConsentGrant);
  t.is(response[1].id, 4);
  t.is(response[1].type, 'consent__grants');
  t.is(response[1].signUrl, null);
  t.is(response[1].progress, 'all_signed');
  t.is(response[1].createdAt, '2018-07-20T13:32:51Z');
  t.is(response[1].updatedAt, '2018-07-20T13:32:51Z');
  t.truthy(response[1].grantedFor);
  t.is(response[1].grantedFor.id, 454);
  t.is(response[1].grantedFor.type, 'mobile_users');
  t.truthy(response[1].grantedBy);
  t.is(response[1].grantedBy.id, 454);
  t.is(response[1].grantedBy.type, 'mobile_users');
  t.truthy(response[1].strategy);
  t.is(response[1].strategy.id, 63);
  t.is(response[1].strategy.type, 'consent__strategies');
  t.is(response[1].strategy.name, 'Strategy-68');
  t.is(response[1].strategy.strategyType, 'electronic');
  t.is(response[1].strategy.createdAt, '2018-07-20T13:32:51Z');
  t.is(response[1].strategy.updatedAt, '2018-07-20T13:32:51Z');
  t.is(response[1].strategy.cohort.id, 106);
  t.is(response[1].strategy.cohort.type, 'cohorts');
  t.is(response[1].strategy.forms.length, 1);
  t.is(response[1].strategy.forms[0].id, 51);
  t.is(response[1].strategy.forms[0].type, 'consent__forms');
  t.is(response[1].strategy.forms[0].enabled, true);
  t.is(response[1].strategy.forms[0].name, 'Form 54');
  t.is(response[1].strategy.forms[0].createdAt, '2018-07-20T13:32:51Z');
  t.is(response[1].strategy.forms[0].updatedAt, '2018-07-20T13:32:51Z');
  t.is(response[1].strategy.forms[0].consentFormVersions.length, 1);
  t.is(response[1].strategy.forms[0].consentFormVersions[0].id, 37);
  t.is(response[1].strategy.forms[0].consentFormVersions[0].type, 'consent__form_versions');
  t.is(response[1].strategy.forms[0].consentStrategy.id, 63);
  t.is(response[1].strategy.forms[0].consentStrategy.type, 'consent__strategies');
  t.truthy(response[1].formVersion);
  t.is(response[1].formVersion.id, 37);
  t.is(response[1].formVersion.type, 'consent__form_versions');
  t.is(response[1].formVersion.archivedAt, undefined);
  t.is(response[1].formVersion.site.id, 115);
  t.is(response[1].formVersion.site.type, 'trials__sites');
  t.is(response[1].formVersion.agreementTemplate.id, 102);
  t.is(response[1].formVersion.agreementTemplate.type, 'agreement__templates');
  t.is(response[1].formVersion.language.id, 63);
  t.is(response[1].formVersion.language.type, 'languages');
  t.is(response[1].formVersion.consentForm.id, 51);
  t.is(response[1].formVersion.consentForm.type, 'consent__forms');
  t.is(response[1].formVersion.consentForm.type, 'consent__forms');
  t.is(response[1].formVersion.consentForm.enabled, true);
  t.is(response[1].formVersion.consentForm.name, 'Form 54');
  t.is(response[1].formVersion.consentForm.createdAt, '2018-07-20T13:32:51Z');
  t.is(response[1].formVersion.consentForm.updatedAt, '2018-07-20T13:32:51Z');
  t.is(response[1].formVersion.consentForm.consentFormVersions.length, 1);
  t.is(response[1].formVersion.consentForm.consentFormVersions[0].id, 37);
  t.is(response[1].formVersion.consentForm.consentFormVersions[0].type, 'consent__form_versions');
  t.is(response[1].formVersion.consentForm.consentStrategy.id, 63);
  t.is(response[1].formVersion.consentForm.consentStrategy.type, 'consent__strategies');
  t.is(response[1].formVersion.approverGroups.length, 0);
  t.is(response[1].formVersion.approvers.length, 0);
  t.truthy(response[1].agreement);
  t.is(response[1].agreement.id, 18);
  t.is(response[1].agreement.type, 'agreement__agreements');
});

/**
 * @test {Clinical6.getChildren}
 */
test.serial(`[unit] UserService.getChildren should receive a valid request and response for a get request for Video Consultations`, async (t) => {
  const { getResponseConsultation } = t.context;
  const user = new User({ id: 217 });
  user.type = 'mobile_users';
  user.email = 'myEmail@email.com';
  await user.store();

  let request = {};
  nock(client.apiBaseUrl).get(`/v3/${user.type}/${user.id}/video_consultations`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, getResponseConsultation];
  });

  const response = await clinical6.getChildren(user, Consultation);
  t.is(request.path, `/v3/mobile_users/${user.id}/video_consultations`);
  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);

  t.truthy(response[0] instanceof Consultation);
  t.is(response[0].id, 4);
  t.is(response[0].type, 'video_consultations');
  t.is(response[0].name, 'General Consultation');
  t.is(response[0].startAt, '2018-08-09T19:11:32Z');
  t.is(response[0].createdAt, '2018-08-09T19:13:05Z');
  t.is(response[0].updatedAt, '2018-08-09T19:13:05Z');
  t.true(response[0].participants.length > 0);
  t.is(response[0].participants[0].id, 2);
  t.is(response[0].participants[0].type, 'video_consultation_participants');
  t.is(response[0].participants[0].createdAt, '2018-08-09T19:13:05Z');
  t.is(response[0].participants[0].updatedAt, '2018-08-09T19:13:05Z');
  t.is(response[0].participants[0].user.id, 217);

  t.truthy(response[1] instanceof Consultation);
  t.is(response[1].id, 5);
  t.is(response[1].type, 'video_consultations');
  t.is(response[1].name, 'General Consultation');
  t.is(response[1].startAt, '2018-08-09T19:11:32Z');
  t.is(response[1].createdAt, '2018-08-09T19:13:05Z');
  t.is(response[1].updatedAt, '2018-08-09T19:13:05Z');
  t.true(response[1].participants.length > 0);
  t.is(response[1].participants[0].id, 3);
  t.is(response[1].participants[0].type, 'video_consultation_participants');
  t.is(response[1].participants[0].createdAt, '2018-08-09T19:13:05Z');
  t.is(response[1].participants[0].updatedAt, '2018-08-09T19:13:05Z');
  t.is(response[1].participants[0].user.id, 217);
});

// UserService.getAwardedBadges method
/**
 * @test {UserService.getAwardedBadges}
 */
test.serial('[unit] UserService.getAwardedBadges should throw an error when there is no authToken', async (t) => {
  const expectedError = 'UserService.getAwardedBadges error: requires authToken and awardee does not have id';
  client.authToken = undefined;
  await t.throwsAsync(mobileUserService.getAwardedBadges(), expectedError);
});

/**
 * @test {UserService.getAwardedBadges}
 */
test('[unit] UserService.getAwardedBadges should receive a valid response for a get request without an id', async (t) => {
  const awardee = new User({ id: 45 });

  let request = {};
  nock(client.apiBaseUrl).get(`/v3/mobile_users/${awardee.id}/awarded_badges`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, {
      data: [
        {
          id: '33',
          type: 'awarded_badges',
          attributes: {
            created_at: '2017-08-10T17:54:19Z',
            updated_at: '2017-08-10T17:54:19Z',
            count: 0,
            earned_on_date: null
          },
          relationships: {
            awardee: {
              data: {
                type: 'mobile_users',
                id: '504'
              }
            },
            badge: {
              data: {
                type: 'badges',
                id: '40'
              }
            }
          }
        },
        {
          id: '34',
          type: 'awarded_badges',
          attributes: {
            created_at: '2017-08-10T17:54:19Z',
            updated_at: '2017-08-10T17:54:19Z',
            count: 0,
            earned_on_date: null
          },
          relationships: {
            awardee: {
              data: {
                type: 'mobile_users',
                id: '504'
              }
            },
            badge: {
              data: {
                type: 'badges',
                id: '41'
              }
            }
          }
        },
        {
          id: '35',
          type: 'awarded_badges',
          attributes: {
            created_at: '2017-08-10T17:54:19Z',
            updated_at: '2017-08-10T17:54:19Z',
            count: 0,
            earned_on_date: null
          },
          relationships: {
            awardee: {
              data: {
                type: 'mobile_users',
                id: '504'
              }
            },
            badge: {
              data: {
                type: 'badges',
                id: '42'
              }
            }
          }
        }
      ],
      included: [
        {
          id: '40',
          type: 'badges',
          attributes: {
            created_at: '2017-08-09T16:23:56Z',
            updated_at: '2017-08-09T16:23:56Z',
            title: 'dummy_462',
            description: 'Demo Content info...',
            redemption_points: 250,
            image: {
              image: {
                url: '/uploads/test/reward/image/17/1.png',
                small: {
                  url: '/uploads/test/reward/image/17/small_1.png'
                },
                small_hd: {
                  url: '/uploads/test/reward/image/17/small_hd_1.png'
                },
                fullscreen: {
                  url: '/uploads/test/reward/image/17/fullscreen_1.png'
                },
                main: {
                  url: '/uploads/test/reward/image/17/main_1.png'
                },
                fullscreen_hd: {
                  url: '/uploads/test/reward/image/17/fullscreen_hd_1.png'
                },
                main_hd: {
                  url: '/uploads/test/reward/image/17/main_hd_1.png'
                }
              }
            },
            position: 1,
            enabled: true,
            featured: null,
            based_on: null,
            threshold: null,
            time_unit: null,
            start_point: null,
            start_at: null,
            disabled_image: {
              disabled_image: {
                url: '/default/default.png',
                small: {
                  url: '/default/small_default.png'
                },
                small_hd: {
                  url: '/default/small_hd_default.png'
                },
                fullscreen: {
                  url: '/default/fullscreen_default.png'
                },
                main: {
                  url: '/default/main_default.png'
                },
                fullscreen_hd: {
                  url: '/default/fullscreen_hd_default.png'
                },
                main_hd: {
                  url: '/default/main_hd_default.png'
                }
              }
            },
            cache_token: 'xMnLvzU_uu4'
          }
        },
        {
          id: '41',
          type: 'badges',
          attributes: {
            created_at: '2017-08-09T16:23:56Z',
            updated_at: '2017-08-09T16:23:56Z',
            title: 'dummy_463',
            description: 'Demo Content info...',
            redemption_points: 250,
            image: {
              image: {
                url: '/uploads/test/reward/image/18/1.png',
                small: {
                  url: '/uploads/test/reward/image/18/small_1.png'
                },
                small_hd: {
                  url: '/uploads/test/reward/image/18/small_hd_1.png'
                },
                fullscreen: {
                  url: '/uploads/test/reward/image/18/fullscreen_1.png'
                },
                main: {
                  url: '/uploads/test/reward/image/18/main_1.png'
                },
                fullscreen_hd: {
                  url: '/uploads/test/reward/image/18/fullscreen_hd_1.png'
                },
                main_hd: {
                  url: '/uploads/test/reward/image/18/main_hd_1.png'
                }
              }
            },
            position: 2,
            enabled: true,
            featured: null,
            based_on: null,
            threshold: null,
            time_unit: null,
            start_point: null,
            start_at: null,
            disabled_image: {
              disabled_image: {
                url: '/default/default.png',
                small: {
                  url: '/default/small_default.png'
                },
                small_hd: {
                  url: '/default/small_hd_default.png'
                },
                fullscreen: {
                  url: '/default/fullscreen_default.png'
                },
                main: {
                  url: '/default/main_default.png'
                },
                fullscreen_hd: {
                  url: '/default/fullscreen_hd_default.png'
                },
                main_hd: {
                  url: '/default/main_hd_default.png'
                }
              }
            },
            cache_token: 'DGMVAICukoc'
          }
        },
        {
          id: '42',
          type: 'badges',
          attributes: {
            created_at: '2017-08-09T16:23:56Z',
            updated_at: '2017-08-09T16:23:56Z',
            title: 'dummy_464',
            description: 'Demo Content info...',
            redemption_points: 250,
            image: {
              image: {
                url: '/uploads/test/reward/image/19/1.png',
                small: {
                  url: '/uploads/test/reward/image/19/small_1.png'
                },
                small_hd: {
                  url: '/uploads/test/reward/image/19/small_hd_1.png'
                },
                fullscreen: {
                  url: '/uploads/test/reward/image/19/fullscreen_1.png'
                },
                main: {
                  url: '/uploads/test/reward/image/19/main_1.png'
                },
                fullscreen_hd: {
                  url: '/uploads/test/reward/image/19/fullscreen_hd_1.png'
                },
                main_hd: {
                  url: '/uploads/test/reward/image/19/main_hd_1.png'
                }
              }
            },
            position: 3,
            enabled: true,
            featured: null,
            based_on: null,
            threshold: null,
            time_unit: null,
            start_point: null,
            start_at: null,
            disabled_image: {
              disabled_image: {
                url: '/default/default.png',
                small: {
                  url: '/default/small_default.png'
                },
                small_hd: {
                  url: '/default/small_hd_default.png'
                },
                fullscreen: {
                  url: '/default/fullscreen_default.png'
                },
                main: {
                  url: '/default/main_default.png'
                },
                fullscreen_hd: {
                  url: '/default/fullscreen_hd_default.png'
                },
                main_hd: {
                  url: '/default/main_hd_default.png'
                }
              }
            },
            cache_token: '6vjdF2bL2Tg'
          }
        }
      ]
    }];
  });
  const response = await mobileUserService.getAwardedBadges(awardee);
  t.is(request.path, `/v3/mobile_users/${awardee.id}/awarded_badges`);
  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 {UserService.getAwardedBadges}
 */
test.serial('[unit] UserService.getAwardedBadges should receive a valid response for a get request with a filter', async (t) => {
  const awardee = new User({ id: 510 });
  const awardedBadge = { id: 20 };

  let request = {};
  nock(client.apiBaseUrl).get(`/v3/mobile_users/${awardee.id}/awarded_badges/${awardedBadge.id}`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, {
      data: {
        id: '20',
        type: 'awarded_badges',
        attributes: {
          created_at: '2017-08-10T17:54:18Z',
          updated_at: '2017-08-10T17:54:18Z',
          count: 0,
          earned_on_date: null
        },
        relationships: {
          awardee: {
            data: {
              type: 'mobile_users',
              id: '510'
            }
          },
          badge: {
            data: {
              type: 'badges',
              id: '41'
            }
          }
        }
      },
      included: [
        {
          id: '41',
          type: 'badges',
          attributes: {
            created_at: '2017-08-09T16:23:56Z',
            updated_at: '2017-08-09T16:23:56Z',
            title: 'dummy_462',
            description: 'Demo Content info...',
            redemption_points: 250,
            image: {
              image: {
                url: '/uploads/test/reward/image/17/1.png',
                small: {
                  url: '/uploads/test/reward/image/17/small_1.png'
                },
                small_hd: {
                  url: '/uploads/test/reward/image/17/small_hd_1.png'
                },
                fullscreen: {
                  url: '/uploads/test/reward/image/17/fullscreen_1.png'
                },
                main: {
                  url: '/uploads/test/reward/image/17/main_1.png'
                },
                fullscreen_hd: {
                  url: '/uploads/test/reward/image/17/fullscreen_hd_1.png'
                },
                main_hd: {
                  url: '/uploads/test/reward/image/17/main_hd_1.png'
                }
              }
            },
            position: 1,
            enabled: true,
            featured: null,
            based_on: null,
            threshold: null,
            time_unit: null,
            start_point: null,
            start_at: null,
            disabled_image: {
              disabled_image: {
                url: '/default/default.png',
                small: {
                  url: '/default/small_default.png'
                },
                small_hd: {
                  url: '/default/small_hd_default.png'
                },
                fullscreen: {
                  url: '/default/fullscreen_default.png'
                },
                main: {
                  url: '/default/main_default.png'
                },
                fullscreen_hd: {
                  url: '/default/fullscreen_hd_default.png'
                },
                main_hd: {
                  url: '/default/main_hd_default.png'
                }
              }
            },
            cache_token: 'xMnLvzU_uu4'
          }
        }
      ]
    }];
  });
  const response = await mobileUserService.getAwardedBadges(awardee, awardedBadge);
  t.is(request.path, `/v3/mobile_users/${awardee.id}/awarded_badges/${awardedBadge.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.truthy(response);
  t.is(response.id, 20);
  t.is(response.type, 'awarded_badges');
  t.is(response.createdAt, '2017-08-10T17:54:18Z');
  t.is(response.updatedAt, '2017-08-10T17:54:18Z');
  t.is(response.count, 0);
  t.is(response.badge.id, 41);
  t.is(response.badge.title, 'dummy_462');
  t.is(response.badge.cacheToken, 'xMnLvzU_uu4');
  t.is(response.badge.createdAt, '2017-08-09T16:23:56Z');
  t.is(response.badge.description, 'Demo Content info...');
  t.is(response.badge.enabled, true);
  t.is(response.badge.position, 1);
  t.is(response.badge.redemptionPoints, 250);
  t.is(response.badge.updatedAt, '2017-08-09T16:23:56Z');
  t.is(response.awardee.id, 510);
  t.is(response.awardee.type, 'mobile_users');
});

// UserService.getEntries method
/**
 * @test {UserService.getEntries}
 */
test.serial('[unit] UserService.getEntries should throw an error when there is no authToken', async (t) => {
  const expectedError = 'UserService.getEntries error: requires authToken and user is not defined';
  client.authToken = undefined;
  await t.throwsAsync(mobileUserService.getEntries(), expectedError);

  // const noAuthError = 'UserService.getEntries error: requires authToken';
  const noIdError = 'UserService.getEntries error: user does not have id';
  client.authToken = '1eb4471c95dce68064b8392e02fe8fac';
  // await t.throwsAsync(mobileUserService.getEntries({}), noIdError);

  await t.throwsAsync(mobileUserService.getEntries({}), noIdError);
});

/**
 * @test {UserService.getEntries}
 */
test('[unit] UserService.getEntries should receive a valid response for a get request without an id', async (t) => {
  const { getResponseEntries45 } = t.context;
  const user = new User({ id: 45 });

  let request = {};
  nock(client.apiBaseUrl).get(`/v3/mobile_users/${user.id}/ediary/entries`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, getResponseEntries45];
  });
  const response = await mobileUserService.getEntries(user);
  t.is(request.path, `/v3/mobile_users/${user.id}/ediary/entries`);
  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.length, 2);
});

/**
 * @test {UserService.getEntries}
 */
test('[unit] UserService.getEntries should receive a valid response for a get request with a filter', async (t) => {
  const user = new User({ id: 49 });
  const filters = { entry_group_id: 12, date: '2018-06-02' };

  let request = {};
  nock(client.apiBaseUrl).get(`/v3/mobile_users/49/ediary/entries?filters[entry_group_id]=12&filters[date]=2018-06-02`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, {
      data: [
        {
          id: '4',
          type: 'ediary__entries',
          attributes: {
            created_at: '2017-06-20T17:55:12Z',
            updated_at: '2017-06-20T17:55:12Z',
            date: '2018-06-02'
          },
          relationships: {
            entry_group: {
              data: {
                id: '12',
                type: 'ediary__entry_groups'
              }
            },
            flow_process: {
              data: {
                id: '45',
                type: 'data_collection__flow_processes'
              }
            },
            captured_value_group: {
              data: null
            },
            owner: {
              data: {
                id: '49',
                type: 'mobile_users'
              }
            }
          }
        }
      ],
      included: [
        {
          id: '12',
          type: 'ediary__entry_groups',
          attributes: {
            name: 'dummy_396',
            permanent_link: 'dummy_397',
            position: 4,
            category: null,
            created_at: '2017-06-20T17:55:12Z',
            updated_at: '2017-06-20T17:55:12Z'
          },
          relationships: {
            ediary_entries: {
              data: [
                {
                  id: '4',
                  type: 'ediary__entries'
                }
              ]
            },
            entry_templates: {
              data: []
            },
            child_entry_groups: {
              data: []
            },
            parent_entry_group: {
              data: null
            }
          }
        },
        {
          id: '45',
          type: 'data_collection__flow_processes',
          attributes: {
            name: 'ipsa',
            permanent_link: 'dummy_389',
            consent_credentials: null,
            created_at: '2017-06-20T17:55:12Z',
            updated_at: '2017-06-20T17:55:12Z',
            owner_type: 'User',
            published_at: null,
            conditional_paths: null
          },
          relationships: {
            linked_steps: {
              data: []
            },
            published: {
              data: null
            },
            draft: {
              data: null
            },
            initial_step: {
              data: null
            }
          }
        },
        {
          id: '49',
          type: 'mobile_users',
          attributes: {
            uuid: 'f9996b75-0f0c-4f0a-a2c2-2265b1d2b031',
            account_name: 'dummy_49',
            email: 'user88@fake.com',
            encryption_key: null,
            created_at: '2017-06-20T17:55:12Z',
            updated_at: '2017-06-20T17:55:12Z',
            verified_at: null,
            invitation_sent_at: null,
            invitation_accepted_at: null
          },
          relationships: {
            devices: {
              data: []
            }
          }
        }
      ]
    }];
  });

  const response = await mobileUserService.getEntries(user, filters);
  t.is(request.path, `/v3/mobile_users/${user.id}/ediary/entries?filters[entry_group_id]=12&filters[date]=2018-06-02`);
  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[0].id, 4);
  t.is(response[0].type, 'ediary__entries');
  t.is(response[0].createdAt, '2017-06-20T17:55:12Z');
  t.is(response[0].date, '2018-06-02');
  t.is(response[0].updatedAt, '2017-06-20T17:55:12Z');
  t.is(response[0].flow.id, 45);
  t.is(response[0].flow.permanentLink, 'dummy_389');
  t.is(response[0].flow.name, 'ipsa');
  t.is(response[0].flow.steps.length, 0);
  t.is(response[0].flow.first_step, null);
  t.is(response[0].flow.createdAt, '2017-06-20T17:55:12Z');
  t.is(response[0].flow.owner_type, 'User');
});

// UserService.getRegistrationStatus method
/**
 * @test {UserService.getRegistrationStatus}
 */
test('[unit] UserService.getRegistrationStatus should throw errors for invalid parameters', async (t) => {
  client.authToken = undefined;
  const undefinedError = 'UserService.getRegistrationStatus error: attributes is not defined';
  const validError = 'UserService.getRegistrationStatus error: attributes must be valid';

  // undefined mobile user
  await t.throwsAsync(mobileUserService.getRegistrationStatus(), undefinedError);
  await t.throwsAsync(mobileUserService.getRegistrationStatus({}), validError);
});

/**
 * @test {UserService.getRegistrationStatus}
 */
test('[unit] UserService.getRegistrationStatus should successfully get the registration status of a mobile user', async (t) => {
  // api-doc/1.0/registrations.html
  // https://sanoficore.clinical6.com/api-doc/1.0/registrations.html
  const requestJsonApi = {
    data: {
      type: 'registration_validations',
      attributes: {
        account_name: 'account1234'
      }
    }
  };
  let request = {};
  nock(client.apiBaseUrl).post(`/v3/mobile_users/registration_validation`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, {
      data: {
        id: '1373',
        type: 'statuses',
        attributes: {
          value: 'new'
        },
        relationships: {
          owner: {
            data: {
              id: '34',
              type: 'mobile_users'
            }
          },
          statusable: {
            data: {
              id: '34',
              type: 'mobile_users'
            }
          }
        }
      },
      meta: {
        password_set: true
      }
    }];
  });

  const meta = {};
  const response = await mobileUserService.getRegistrationStatus({ account_name: 'account1234' }, meta);

  t.is(request.path, `/v3/mobile_users/registration_validation`);
  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, undefined);
  t.is(response.value, 'new');
  t.is(meta.passwordSet, true);
});

// UserService.getSchedules method
/**
 * @test {UserService.getSchedules}
 */
test.serial('[unit] UserService.getSchedules should throw an error when there is no authToken', async (t) => {
  const expectedError = 'UserService.getSchedules error: requires authToken and user does not have id';
  client.authToken = undefined;
  await t.throwsAsync(mobileUserService.getSchedules(), expectedError);
});

/**
 * @test {UserService.getSchedules}
 */
test('[unit] UserService.getSchedules should receive a valid response for a get request with a filter', async (t) => {
  client.authToken = 'valid_token';
  const { getResponseSchedules } = t.context;
  const user = new User({ id: 72 });

  // /v3/mobile_users/${schedule.mobileUser.id}/scheduler/personalized_rule_schedules
  let request = {};
  nock(client.apiBaseUrl).get(`/v3/mobile_users/${user.id}/scheduler/personalized_rule_schedules`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, getResponseSchedules];
  });
  const response = await mobileUserService.getSchedules(user);
  t.is(request.path, `/v3/mobile_users/${user.id}/scheduler/personalized_rule_schedules`);
  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.length, 3);
  t.is(response[0].constructor.name, 'Schedule');
  t.is(response[0].id, 1);
  t.is(response[0].daysOfWeek, '0,1,2,3,4,5,6');
  t.is(response[0].endDate, '2017-09-27');
  t.is(response[0].startDate, '2017-09-10');
  t.is(response[0].startDateOffset, 0);
  t.is(response[0].time, '10:00');
  t.is(response[0].timezone, 'UTC');
  t.is(response[0].scheduleable.constructor.name, 'Rule');
  t.is(response[0].scheduleable.id, 1);
  t.is(response[1].id, 2);
  t.is(response[1].daysOfWeek, '0,1,2,3,4,5,6');
  t.is(response[1].endDate, '2017-09-27');
  t.is(response[1].startDate, '2017-09-10');
  t.is(response[1].startDateOffset, 0);
  t.is(response[1].time, '10:00');
  t.is(response[1].timezone, 'UTC');
  t.is(response[1].scheduleable.id, 2);
  t.is(response[2].id, 3);
  t.is(response[2].daysOfWeek, '0,1,2,3,4,5,6');
  t.is(response[2].endDate, '2017-09-27');
  t.is(response[2].startDate, '2017-09-10');
  t.is(response[2].startDateOffset, 0);
  t.is(response[2].time, '10:00');
  t.is(response[2].timezone, 'UTC');
  t.is(response[2].scheduleable.id, 3);
});

// UserService.getSession method
/**
 * @test {UserService.getSession}
 */
test('[unit] UserService.getSession should throw errors for invalid parameters', async (t) => {
  const validError = 'UserService.getSession error: token is not a string';
  await t.throwsAsync(mobileUserService.getSession(1234), validError);
});

// http://clinical6-docs.s3-website-us-east-1.amazonaws.com/apidoc/sessions/new.html
/**
 * @test {UserService.getSession}
 */
test('[unit] UserService.getSession should successfully get the registration status of a mobile user', async (t) => {
  let request = {};
  nock(client.apiBaseUrl).get(`/v3/mobile_users/sessions?access_token=dd3df48a5c9911838235e9aa4d51346adb5468d7887a25d055f90a5f8448477c`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, {
      data: {
        id: 493,
        type: 'mobile_users',
        attributes: {
          uuid: '3f6be778-411f-4435-9c7b-d5c4b78c1bff',
          account_name: 'dummy_463',
          email: null,
          created_at: '2018-07-31T18:10:27Z',
          updated_at: '2018-07-31T18:10:27Z',
          invitation_sent_at: null,
          invitation_accepted_at: null,
          disabled: false,
          disabled_at: null,
          password_expired_at: '2018-10-29T18:10:27Z'
        },
        relationships: {
          devices: {
            data: [
              {
                id: 284,
                type: 'devices'
              }
            ]
          },
          user_role: {
            data: null
          },
          profile: {
            data: {
              id: 867,
              type: 'profiles'
            }
          },
          language: {
            data: {
              id: 1,
              type: 'languages'
            }
          },
          patient: {
            data: null
          },
          threads: {
            data: []
          },
          site_member: {
            data: null
          },
          overall_status: {
            data: null
          }
        }
      },
      included: [
        {
          id: 284,
          type: 'devices',
          attributes: {
            udid: '269a493krg5kxnfnh04o',
            technology: 'ios',
            access_token: 'dd3df48a5c9911838235e9aa4d51346adb5468d7887a25d055f90a5f8448477c',
            push_id: 'm3cpk0efd6hs2u2mjnnvsqwjhds0hqzxtes6r4h26r7hd1chhjhxa58l28psa34x',
            created_at: '2018-07-31T18:10:27Z',
            updated_at: '2018-07-31T18:10:27Z',
            app_version: null
          }
        }
      ]
    }];
  });

  const response = await mobileUserService.getSession('dd3df48a5c9911838235e9aa4d51346adb5468d7887a25d055f90a5f8448477c');

  t.is(request.path, `/v3/mobile_users/sessions?access_token=dd3df48a5c9911838235e9aa4d51346adb5468d7887a25d055f90a5f8448477c`);
  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.id, 493);
  t.is(response.uuid, '3f6be778-411f-4435-9c7b-d5c4b78c1bff');
  t.is(response.accountName, 'dummy_463');
  t.is(response.createdAt, '2018-07-31T18:10:27Z');
  t.is(response.updatedAt, '2018-07-31T18:10:27Z');
  t.is(response.passwordExpiredAt, '2018-10-29T18:10:27Z');
  t.is(response.disabled, false);
  t.is(response.disabledAt, null);
  t.is(response.devices[0].id, 284);

  t.is(response.siteMember, null);
});

// UserService.getSites method
/**
 * @test {UserService.getSites}
 */
test.serial('[unit] UserService.getSites should throw errors for invalid token', async (t) => {
  client.authToken = undefined;
  const validError = 'UserService.getSites error: requires authToken';
  await t.throwsAsync(mobileUserService.getSites({ id: 1, type: 'mobile_users' }), validError);
});

/**
 * @test {UserService.getSites}
 */
test('[unit] UserService.getSites should throw errors for invalid parameters user type', async (t) => {
  const validError = 'UserService.getSites error: user does not have type';
  await t.throwsAsync(mobileUserService.getSites({ id: 1 }), validError);
});

/**
 * @test {UserService.getSites}
 */
test('[unit] UserService.getSites should throw errors for invalid user id', async (t) => {
  const validError = 'UserService.getSites error: user does not have id';
  await t.throwsAsync(mobileUserService.getSites({ type: 'mobile_users' }), validError);
});

/**
 * @test {UserService.getSites}
 */
test('[unit] UserService.getSites should successfully get the sites and locations of a mobile user', async (t) => {
  const user = new User({ id: 1, type: 'mobile_users' });

  let request = {};
  nock(client.apiBaseUrl).get(`/v3/mobile_users/${user.id}/sites`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, {
      data: [
        {
          id: '8',
          type: 'trials__sites',
          attributes: {
            site_id: '458559',
            name: 'Best Site',
            email: 'site@site.com',
            phone_number: '555-555-5555',
            fax_number: null,
            contact_name: 'Elwyn Dare',
            contact_email: 'leta.hansen@kuphal.info',
            contact_phone: null,
            contact_fax: null,
            created_at: '2018-01-06T02:15:05Z',
            updated_at: '2018-01-06T02:15:05Z'
          },
          relationships: {
            location: {
              data: {
                id: '35',
                type: 'locations'
              }
            },
            agreement_templates: {
              data: [
                {
                  id: '129',
                  type: 'agreement__templates'
                }
              ]
            }
          }
        }
      ],
      included: [
        {
          id: '129',
          type: 'agreement__templates',
          attributes: {
            template_name: 'dummy_818 129',
            description: 'Sample agreement template',
            expiration: 20,
            message: null,
            redirect_url: 'http://kriswunsch.io/josie',
            approval_required: true,
            approver_first_name: 'John',
            approver_last_name: 'Doe',
            approver_email: 'john@example.com',
            created_at: '2017-09-18T18:20:54Z',
            updated_at: '2017-09-18T18:20:54Z',
            permanent_link: 'dummy81829',
            approver_title: 'Mr.',
            reminder_frequency: 'WEEKLY_UNTIL_SIGNED'
          }
        },
        {
          id: '35',
          type: 'locations',
          attributes: {
            country: 'USA',
            state: 'CA',
            city: 'San Diego',
            street: 'Main',
            latitude: '32.8563846',
            longitude: '-117.2029363',
            title: 'Location Title',
            zip_code: null,
            address_line_1: 'Main',
            address_line_2: null,
            address_line_3: null
          }
        }
      ]
    }];
  });

  const response = await mobileUserService.getSites(user);

  t.is(request.path, `/v3/mobile_users/${user.id}/sites`);
  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[0].id, 8);
  t.is(response[0].siteId, '458559');
  t.is(response[0].type, 'trials__sites');
  t.is(response[0].name, 'Best Site');
  t.is(response[0].location.id, 35);
  t.is(response[0].location.country, 'USA');
  t.is(response[0].location.state, 'CA');
  t.is(response[0].location.city, 'San Diego');
  t.is(response[0].location.zipCode, null);
  t.is(response[0].agreementTemplates.length, 1);
  t.is(response[0].agreementTemplates[0].id, 129);
  t.is(response[0].agreementTemplates[0].templateName, 'dummy_818 129');
  t.is(response[0].agreementTemplates[0].description, 'Sample agreement template');
  t.is(response[0].agreementTemplates[0].documentUrl, undefined);
  t.is(response[0].agreementTemplates[0].expiration, 20);
  t.is(response[0].agreementTemplates[0].message, null);
  t.is(response[0].agreementTemplates[0].redirectUrl, 'http://kriswunsch.io/josie');
  t.is(response[0].agreementTemplates[0].createdAt, '2017-09-18T18:20:54Z');
  t.is(response[0].agreementTemplates[0].updatedAt, '2017-09-18T18:20:54Z');
  t.is(response[0].agreementTemplates[0].permanentLink, 'dummy81829');
  t.is(response[0].agreementTemplates[0].reminderFrequency, 'WEEKLY_UNTIL_SIGNED');
  t.is(response[0].agreementTemplates[0].archivedAt, undefined);
});

// UserService.insert method
/**
 * @test {UserService.insert}
 */
test('[unit] UserService.insert should throw errors for invalid parameters', async (t) => {
  const undefinedError = 'UserService.insert error: user is not defined';
  await t.throwsAsync(mobileUserService.insert(), undefinedError);
});

/**
 * @test {UserService.insert}
 */
test('[unit] UserService.insert should successfully insert mobile user with a mobile user object', async (t) => {
  const { insertRequestMobileUser, insertResponseMobileUser } = t.context;
  const user = new User(insertRequestMobileUser);
  let request = {};
  nock(client.apiBaseUrl).post(`/v3/mobile_users`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, insertResponseMobileUser];
  });

  const response = await mobileUserService.insert(user);
  t.is(request.path, `/v3/mobile_users`);
  t.is(request.headers.accept, 'application/json');
  t.deepEqual(request.requestBody, insertRequestMobileUser);
  t.is(request.headers['content-type'], 'application/json');
  t.is(request.headers.authorization, 'Token token=valid_token');
  t.is(response.id, 1);
  t.is(response.type, 'mobile_users');
});

// UserService.register method
/**
 * @test {UserService.register}
 */
test('[unit] UserService.register should throw errors for invalid parameters', async (t) => {
  const undefinedError = 'UserService.register error: attributes is not defined and device is not defined';
  const validError = 'UserService.register error: attributes must be valid';
  const device = { id: 23 };
  await t.throwsAsync(mobileUserService.register(), undefinedError);
  await t.throwsAsync(mobileUserService.register({}, device), validError);
  await t.throwsAsync(mobileUserService.register({ guest: false }, device), validError);
  await t.throwsAsync(mobileUserService.register({ account_name: 'hello@gmail.com' }, device), validError);
  await t.throwsAsync(mobileUserService.register({ email: 'hello@gmail.com' }, device), validError);
  await t.throwsAsync(mobileUserService.register({ password: '1234' }, device), validError);
});

/**
 * @test {UserService.register}
 */
test.serial('[unit] UserService.register should successfully register a guest user to a device (example 1)', async (t) => {
  // api-doc/1.0/registrations.html
  // https://sanoficore.clinical6.com/api-doc/1.0/registrations.html

  const requestJsonApi = {
    data: {
      type: 'mobile_users',
      attributes: {
        guest: true
      },
      relationships: {
        devices: {
          data: {
            id: 76,
            type: 'devices'
          }
        }
      }
    }
  };

  let request = {};
  nock(client.apiBaseUrl).post(`/v3/mobile_users/registrations`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, {
      data: {
        id: '136',
        type: 'mobile_users',
        attributes: {
          uuid: '454dbea4-c561-4f6f-8e6e-d095e58a4773',
          account_name: 'cthdohmk',
          email: null,
          encryption_key: null,
          created_at: '2017-06-09T23:07:45Z',
          updated_at: '2017-06-09T23:07:45Z',
          verified_at: null,
          invitation_sent_at: null,
          invitation_accepted_at: null
        },
        relationships: {
          devices: {
            data: [
              {
                id: '76',
                type: 'devices'
              }
            ]
          }
        }
      },
      included: [
        {
          id: '76',
          type: 'devices',
          attributes: {
            udid: '2wxte1bm8fw9nxy7e6fr',
            technology: 'ios',
            access_token: '81008bfd10f2d623e393352fb0834504',
            push_id: 'edh0et0xtllk4a063eb00rmeu82ok82oosjeviyxutzbqal7lq5hmyudf1vbukp7',
            created_at: '2017-06-09T23:07:45Z',
            updated_at: '2017-06-09T23:07:45Z',
            app_version: null
          }
        }
      ]
    }];
  });

  const attributes = { guest: true };
  const response = await mobileUserService.register(attributes, { id: 76 });

  t.is(request.path, `/v3/mobile_users/registrations`);
  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, 136);
  t.is(response.type, 'mobile_users');
  t.is(response.uuid, '454dbea4-c561-4f6f-8e6e-d095e58a4773');
  t.is(response.accountName, 'cthdohmk');
  t.is(response.createdAt, '2017-06-09T23:07:45Z');
  t.is(response.updatedAt, '2017-06-09T23:07:45Z');

  const dresp = response.devices[0];
  t.is(dresp.id, 76);
  t.is(dresp.type, 'devices');
  t.is(dresp.udid, '2wxte1bm8fw9nxy7e6fr');
  t.is(dresp.technology, 'ios');
  t.is(dresp.accessToken, '81008bfd10f2d623e393352fb0834504');
  t.is(dresp.pushId, 'edh0et0xtllk4a063eb00rmeu82ok82oosjeviyxutzbqal7lq5hmyudf1vbukp7');
  t.is(dresp.createdAt, '2017-06-09T23:07:45Z');
  t.is(dresp.updatedAt, '2017-06-09T23:07:45Z');

  t.is(client.authToken, 'valid_token');
});

/**
 * @test {UserService.register}
 */
test.serial('[unit] UserService.register should successfully register a guest user to a device (example 2)', async (t) => {
  let request = {};
  nock(client.apiBaseUrl).post(`/v3/mobile_users/registrations`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, {
      data: {
        id: '4',
        type: 'mobile_users',
        attributes: {
          uuid: '57543ae1-e2dc-40d3-8d6c-01cd74bcc5a8',
          account_name: '88e1zppz',
          email: null,
          encryption_key: null,
          created_at: '2017-05-15T19:08:18.110Z',
          updated_at: '2017-05-15T19:08:18.122Z',
          verified_at: null,
          invitation_sent_at: null,
          invitation_accepted_at: null
        },
        relationships: {
          devices: {
            data: [
              {
                id: '3',
                type: 'devices'
              }
            ]
          }
        }
      },
      included: [
        {
          id: '3',
          type: 'devices',
          attributes: {
            udid: 'mztas1qvch5ic2xg3nx2',
            technology: 'ios',
            access_token: null,
            push_id: 'd6jc3wx3kkigkta4nu5n027m595qh20ctui21bdt0set5znmiliz4qg1bqz9kwp0',
            created_at: '2017-05-15T19:08:17.000Z',
            updated_at: '2017-05-15T19:08:18.000Z',
            app_version: null
          }
        }
      ]
    }];
  });

  const requestJsonApi = {
    data: {
      type: 'mobile_users',
      attributes: {
        guest: true
      },
      relationships: {
        devices: {
          data: {
            id: 3,
            type: 'devices',
          }
        }
      }
    }
  };

  const attributes = { guest: true };
  const response = await mobileUserService.register(attributes, { id: 3 });

  t.is(request.path, `/v3/mobile_users/registrations`);
  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, 4);
  t.is(response.type, 'mobile_users');
  t.is(response.uuid, '57543ae1-e2dc-40d3-8d6c-01cd74bcc5a8');
  t.is(response.accountName, '88e1zppz');
  t.is(response.createdAt, '2017-05-15T19:08:18.110Z');
  t.is(response.updatedAt, '2017-05-15T19:08:18.122Z');

  const dresp = response.devices[0];
  t.is(dresp.id, 3);
  t.is(dresp.type, 'devices');
  t.is(dresp.udid, 'mztas1qvch5ic2xg3nx2');
  t.is(dresp.technology, 'ios');
  t.is(dresp.accessToken, null);
  t.is(dresp.pushId, 'd6jc3wx3kkigkta4nu5n027m595qh20ctui21bdt0set5znmiliz4qg1bqz9kwp0');
  t.is(dresp.createdAt, '2017-05-15T19:08:17.000Z');
  t.is(dresp.updatedAt, '2017-05-15T19:08:18.000Z');

  t.is(client.authToken, 'valid_token');
});

/**
 * @test {UserService.register}
 */
test('[unit] UserService.register should throw an error when registering a guest user to an existing device (example 3)', async (t) => {
  let request = {};
  nock(client.apiBaseUrl).post(`/v3/mobile_users/registrations`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [422, {
      errors: [
        {
          status: 422,
          detail: 'Device already in use.'
        }
      ]
    }];
  });

  const requestJsonApi = {
    data: {
      type: 'mobile_users',
      attributes: {
        guest: true
      },
      relationships: {
        devices: {
          data: {
            id: 5,
            type: 'devices',
          }
        }
      }
    }
  };

  const attributes = { guest: true };
  let response;
  await mobileUserService.register(attributes, { id: 5, type: 'devices' }).catch(res => (response = res));

  t.is(request.path, `/v3/mobile_users/registrations`);
  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._response.errors.length, 1);
});

/**
 * @test {UserService.register}
 */
test.serial('[unit] UserService.register should successfully register a user with account and password to a device (example 4)', async (t) => {
  let request = {};
  nock(client.apiBaseUrl).post(`/v3/mobile_users/registrations`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, {
      data: {
        id: '7',
        type: 'mobile_users',
        attributes: {
          uuid: '0b276d4b-25e6-4073-9e66-43489c90b013',
          account_name: 'some_identifier',
          email: null,
          encryption_key: null,
          created_at: '2017-05-15T19:08:18.390Z',
          updated_at: '2017-05-15T19:08:18.403Z',
          verified_at: null,
          invitation_sent_at: null,
          invitation_accepted_at: null
        },
        relationships: {
          devices: {
            data: [
              {
                id: '6',
                type: 'devices'
              }
            ]
          }
        }
      },
      included: [
        {
          id: '6',
          type: 'devices',
          attributes: {
            udid: 'htyatf9r5fkph3wobaf4',
            technology: 'ios',
            access_token: '12be22de3b09065120193b601ebdbc09',
            push_id: 'vyqe0gvfvyhkw8x3ms46qv9ariwdf47pxyp2yg9mkqyhi73mx8ysoii0si6gdmbv',
            created_at: '2017-05-15T19:08:18.000Z',
            updated_at: '2017-05-15T19:08:18.000Z',
            app_version: null
          }
        }
      ]
    }];
  });

  const requestJsonApi = {
    data: {
      type: 'mobile_users',
      attributes: {
        account_name: 'some_identifier',
        password: 'ww3123'
      },
      relationships: {
        devices: {
          data: {
            id: 6,
            type: 'devices',
          }
        }
      }
    }
  };

  const attributes = { account_name: 'some_identifier', password: 'ww3123' };
  const response = await mobileUserService.register(attributes, { id: 6, type: 'devices' });

  t.is(request.path, `/v3/mobile_users/registrations`);
  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, 7);
  t.is(response.type, 'mobile_users');
  t.is(response.uuid, '0b276d4b-25e6-4073-9e66-43489c90b013');
  t.is(response.accountName, 'some_identifier');
  t.is(response.createdAt, '2017-05-15T19:08:18.390Z');
  t.is(response.updatedAt, '2017-05-15T19:08:18.403Z');

  const dresp = response.devices[0];
  t.is(dresp.id, 6);
  t.is(dresp.type, 'devices');
  t.is(dresp.udid, 'htyatf9r5fkph3wobaf4');
  t.is(dresp.technology, 'ios');
  t.is(dresp.accessToken, '12be22de3b09065120193b601ebdbc09');
  t.is(dresp.pushId, 'vyqe0gvfvyhkw8x3ms46qv9ariwdf47pxyp2yg9mkqyhi73mx8ysoii0si6gdmbv');
  t.is(dresp.createdAt, '2017-05-15T19:08:18.000Z');
  t.is(dresp.updatedAt, '2017-05-15T19:08:18.000Z');

  t.is(client.authToken, 'valid_token');
});

// UserService.removeAwardedBadge method
/**
 * @test {UserService.removeAwardedBadge}
 */
test('[unit] UserService.removeAwardedBadge should throw errors for invalid parameters', async (t) => {
  const title = 'UserService.removeAwardedBadge error';

  // undefined mobile user
  await t.throwsAsync(mobileUserService.removeAwardedBadge(), `${title}: awardedBadge is not defined`);
  await t.throwsAsync(mobileUserService.removeAwardedBadge({}), `${title}: awardedBadge does not have awardee`);
  const awardedBadge = new AwardedBadge({ });
  awardedBadge.badge = new Badge();
  awardedBadge.awardee = { hello: 'world' };
  await t.throwsAsync(mobileUserService.removeAwardedBadge(awardedBadge), `${title}: awardee does not have id and awardedBadge does not have id`);
  awardedBadge.id = 25;
  await t.throwsAsync(mobileUserService.removeAwardedBadge(awardedBadge), `${title}: awardee does not have id`);
  awardedBadge.badge.id = 1;
  await t.throwsAsync(mobileUserService.removeAwardedBadge(awardedBadge), `${title}: awardee does not have id`);
});

/**
 * @test {UserService.removeAwardedBadge}
 */
test('[unit] UserService.removeAwardedBadge should successfully removeAwardedBadge (api example)', async (t) => {
  // DELETE //v3/mobile_users/:mobile_user_id/badges/:id
  // http://clinical6-docs.s3-website-us-east-1.amazonaws.com/apidoc/v3relationshipsbadges/destroy.html
  const { storage } = t.context;
  const awardedBadge = new AwardedBadge({ id: 15 });
  awardedBadge.awardee = new User({ id: 487 });
  awardedBadge.awardee.store();
  awardedBadge.badge = new Badge({ id: 62 });
  awardedBadge.badge.store();
  awardedBadge.store();
  t.is(storage.has('awarded_badges', awardedBadge.id), true);

  let request = {};
  nock(client.apiBaseUrl).delete(`/v3/mobile_users/${awardedBadge.awardee.id}/awarded_badges/${awardedBadge.id}`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [204, { status: 'ok' }];
  });
  const response = await mobileUserService.removeAwardedBadge(awardedBadge);

  t.is(request.path, `/v3/mobile_users/${awardedBadge.awardee.id}/awarded_badges/${awardedBadge.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.truthy(response);

  // storage should be empty
  t.is(storage.has('awarded_badges', awardedBadge.id), false);
});

// UserService.requestPasswordReset method
/**
 * @test {UserService.requestPasswordReset}
 */
test('[unit] UserService.requestPasswordReset should throw errors for invalid parameters', async (t) => {
  const undefinedError = 'UserService.requestPasswordReset error: attributes is not defined';
  const validError = 'UserService.requestPasswordReset error: attributes must be valid';
  await t.throwsAsync(mobileUserService.requestPasswordReset(), undefinedError);
  await t.throwsAsync(mobileUserService.requestPasswordReset({}), validError);
});

/**
 * @test {UserService.requestPasswordReset}
 */
test('[unit] UserService.requestPasswordReset should successfully requestPasswordReset mobile user with a mobile user object', async (t) => {
  const requestJson = {
    data: {
      type: 'password_resets',
      attributes: {
        email: 'user116@fake.com'
      }
    }
  };
  let request = {};
  nock(client.apiBaseUrl).post(`/v3/mobile_users/password`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [201, ''];
  });
  const response = await mobileUserService.requestPasswordReset({ email: 'user116@fake.com' });
  t.is(request.path, `/v3/mobile_users/password`);
  t.is(request.headers.accept, 'application/json');
  t.deepEqual(request.requestBody, requestJson);
  t.is(request.headers['content-type'], 'application/json');
  t.is(request.headers.authorization, 'Token token=valid_token');
  t.is(response, undefined);
});

/**
 * @test {UserService.requestPasswordReset}
 */
test('[unit] UserService.requestPasswordReset should throw an error if the email is invalid', async (t) => {
  let request = {};
  nock(client.apiBaseUrl).post(`/v3/mobile_users/password`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [422, {
      errors: [
        {
          source: {
            pointer: '/data/attributes/email'
          },
          detail: 'not found'
        }
      ]
    }];
  });
  const requestJsonInvalid = {
    data: {
      type: 'password_resets',
      attributes: {
        email: 'invalidEmail@invalid.com'
      }
    }
  };
  let response;
  await mobileUserService.requestPasswordReset({ email: 'invalidEmail@invalid.com' }).catch(res => (response = res));
  t.is(request.path, `/v3/mobile_users/password`);
  t.is(request.headers.accept, 'application/json');
  t.deepEqual(request.requestBody, requestJsonInvalid);
  t.is(request.headers['content-type'], 'application/json');
  t.is(request.headers.authorization, 'Token token=valid_token');
  t.truthy(response);
});

// UserService.resetPassword method
/**
 * @test {UserService.resetPassword}
 */
test('[unit] UserService.resetPassword should throw errors for invalid parameters', async (t) => {
  const pre = 'UserService.resetPassword error:';

  await t.throwsAsync(mobileUserService.resetPassword(), `${pre} attributes is not defined`);

  const attr = {};
  const device = new Device({ id: 5 });
  await t.throwsAsync(mobileUserService.resetPassword(attr, device), `${pre} attributes does not have reset_password_token and attributes does not have password`);

  attr.reset_password_token = 23;
  await t.throwsAsync(mobileUserService.resetPassword(attr, device), `${pre} attributes does not have password`);

  attr.password = 23;
  await t.throwsAsync(mobileUserService.resetPassword(attr, device), `${pre} reset_password_token is not a string and password is not a string`);

  attr.reset_password_token = 'asdf';
  await t.throwsAsync(mobileUserService.resetPassword(attr, device), `${pre} password is not a string`);

  attr.password = 'asdf';
  attr.email = 23;
  await t.throwsAsync(mobileUserService.resetPassword(attr, device), `${pre} email is not a string and email must be a valid email`);
});

/**
 * @test {UserService.resetPassword}
 */
test.serial('[unit] UserService.resetPassword should successfully resetPassword mobile user with correct attributes', async (t) => {
  const { updateResponseResetPassword } = t.context;
  const requestJson = {
    data: {
      type: 'password_resets',
      attributes: {
        reset_password_token: '16700800',
        password: 'my_new_sekret',
        email: 'test@test.com'
      },
      relationships: {
        devices: {
          data: {
            id: 375,
            type: 'devices'
          }
        }
      }
    }
  };
  let request = {};
  nock(client.apiBaseUrl).patch(`/v3/mobile_users/password`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, updateResponseResetPassword];
  });

  clinical6.device = new Device({
    data: {
      id: '375',
      type: 'devices',
      attributes: {
        udid: 'ios-device-udid',
        technology: 'ios',
        access_token: 'ios-token-375-new-device',
        push_id: null,
        created_at: '2018-04-25T22:04:54Z',
        updated_at: '2018-04-25T22:04:54Z',
        app_version: null
      }
    }
  });
  client.authToken = 'ios-token-375-new-device';
  const response = await mobileUserService.resetPassword({
    reset_password_token: '16700800',
    password: 'my_new_sekret',
    email: 'test@test.com'
  });
  t.is(request.path, `/v3/mobile_users/password`);
  t.is(request.headers.accept, 'application/json');
  t.deepEqual(request.requestBody, requestJson);
  t.is(request.headers['content-type'], 'application/json');
  t.is(request.headers.authorization, 'Token token=ios-token-375-new-device');

  t.truthy(response);
  t.true(response instanceof User);
  t.is(response.type, 'mobile_users');
  t.is(response.id, 32);
  t.is(response.createdAt, '2018-04-16T16:32:36Z');
  t.is(response.email, 'myEmail@email.com');
  t.is(response.updatedAt, '2018-04-25T22:04:55Z');
  t.is(response.uuid, 'my-special-uuid');

  t.true(response.role instanceof Role);
  t.is(response.role.type, 'user_roles');
  t.is(response.role.id, 8);
  t.is(response.role.permanentLink, 'subject');
  t.is(response.role.name, 'Subject');
  t.is(response.role.isSuper, false);
  t.is(response.role.isAdmin, false);
  t.is(response.role.isMobile, true);
  t.is(response.role.isDefault, false);

  t.is(client.authToken, 'ios-token-375');
  client.reset();
  client.authToken = `1eb4471c95dce68064b8392e02fe8fac`;
});

/**
 * @test {UserService.resetPassword}
 */
test('[unit] UserService.resetPassword should throw an error if the password token is invalid', async (t) => {
  let request = {};
  nock(client.apiBaseUrl).patch(`/v3/mobile_users/password`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [422, {
      errors: [
        {
          source: {
            pointer: '/data/attributes/reset_password_token'
          },
          detail: 'is invalid'
        }
      ]
    }];
  });
  const requestJsonInvalid = {
    data: {
      type: 'password_resets',
      attributes: {
        reset_password_token: '73169657',
        password: 'my_new_sekret',
        email: 'test@test.com'
      }
    }
  };
  let response;
  await mobileUserService.resetPassword({
    reset_password_token: '73169657',
    password: 'my_new_sekret',
    email: 'test@test.com'
  }).catch(res => (response = res));
  t.is(request.path, `/v3/mobile_users/password`);
  t.is(request.headers.accept, 'application/json');
  t.deepEqual(request.requestBody, requestJsonInvalid);
  t.is(request.headers['content-type'], 'application/json');
  t.is(request.headers.authorization, 'Token token=valid_token');
  t.truthy(response);
});

// UserService.revokeConsent method
/**
 * @test {UserService.revokeConsent}
 */
test('[unit] UserService.revokeConsent should throw errors for invalid parameters', async (t) => {
  const undefinedError = 'UserService.revokeConsent error: user is not defined';
  const validError = 'UserService.revokeConsent error: user does not have id and user does not have type';
  await t.throwsAsync(mobileUserService.revokeConsent(), undefinedError);
  await t.throwsAsync(mobileUserService.revokeConsent({}), validError);
});

/**
 * @test {UserService.revokeConsent}
 */
test('[unit] UserService.revokeConsent should successfully revoke consent', async (t) => {
  // http://clinical6-docs.s3-website-us-east-1.amazonaws.com/apidoc/v3relationshipsconsentconsents/destroy.html
  let request = {};
  nock(client.apiBaseUrl).delete(`/v3/mobile_users/306/consent/consent`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [204, ''];
  });
  const response = await mobileUserService.revokeConsent({ id: 306, type: 'mobile_users' });
  t.is(request.path, `/v3/mobile_users/306/consent/consent`);
  t.is(request.headers.accept, 'application/json');
  t.deepEqual(request.requestBody, '');
  t.is(request.headers['content-type'], 'application/json');
  t.is(request.headers.authorization, 'Token token=valid_token');
  t.falsy(response);
});

// UserService.sendConfirmation method
/**
 * @test {UserService.sendConfirmation}
 */
test('[unit] UserService.sendConfirmation should throw errors for invalid parameters', async (t) => {
  const undefinedError = 'UserService.sendConfirmation error: email is not defined';
  const validError = 'UserService.sendConfirmation error: email is not a string';
  await t.throwsAsync(mobileUserService.sendConfirmation(), undefinedError);
  await t.throwsAsync(mobileUserService.sendConfirmation(1234), validError);
});

/**
 * @test {UserService.sendConfirmation}
 */
test('[unit] UserService.sendConfirmation should successfully send a confirmation', async (t) => {
  // http://clinical6-docs.s3-website-us-east-1.amazonaws.com/apidoc/confirmations/create.html
  const requestJsonApi = {
    data: {
      type: 'confirmations',
      attributes: {
        email: 'user277@fake.com'
      }
    }
  };
  let request = {};
  nock(client.apiBaseUrl).post(`/v3/mobile_users/confirmation`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [201, {}];
  });
  const response = await mobileUserService.sendConfirmation('user277@fake.com');
  t.is(request.path, `/v3/mobile_users/confirmation`);
  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.truthy(response);
});

/**
 * @test {UserService.sendConfirmation}
 */
test('[unit] UserService.sendConfirmation should throw an error if the email is considered blank', async (t) => {
  let request = {};
  nock(client.apiBaseUrl).post(`/v3/mobile_users/confirmation`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [422, {
      errors: [
        {
          source: {
            pointer: '/data/attributes/email'
          },
          detail: 'can\'t be blank'
        }
      ]
    }];
  });
  let response;
  await mobileUserService.sendConfirmation('user277@fake.com').catch(res => (response = res));

  t.is(request.path, `/v3/mobile_users/confirmation`);
  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);
});

// UserService.signIn method
/**
 * @test {UserService.signIn}
 */
test('[unit] UserService.signIn should throw errors for invalid parameters', async (t) => {
  const undefinedError = 'UserService.signIn error: attributes is not defined';
  const validError = 'UserService.signIn error: attributes must be valid';
  await t.throwsAsync(mobileUserService.signIn(), undefinedError);
  await t.throwsAsync(mobileUserService.signIn({}, { id: 5 }), validError);
  await t.throwsAsync(mobileUserService.signIn({ account_name: 'hello@gmail.com' }, { id: 5 }), validError);
  await t.throwsAsync(mobileUserService.signIn({ email: 'hello@gmail.com' }, { id: 5 }), validError);
  await t.throwsAsync(mobileUserService.signIn({ password: '1234' }, { id: 5 }), validError);
});

/**
 * @test {UserService.signIn}
 */
test('[unit] UserService.signIn should successfully signIn', async (t) => {
  // http://clinical6-docs.s3-website-us-east-1.amazonaws.com/apidoc/confirmations/create.html

  const requestJsonApi = {
    data: {
      type: 'sessions',
      attributes: {
        account_name: 'dummy_211',
        password: 'my_sekret_password'
      },
      relationships: {
        devices: {
          data: {
            id: 91,
            type: 'devices'
          }
        }
      }
    }
  };

  let request = {};
  nock(client.apiBaseUrl).post(`/v3/mobile_users/sessions`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [201, {
      data: {
        id: 154,
        type: 'mobile_users',
        attributes: {
          uuid: 'a519586e-cf05-439f-af8b-c0c1088c8492',
          account_name: 'dummy_150',
          email: 'user347@fake.com',
          created_at: '2018-07-28T02:46:43Z',
          updated_at: '2018-07-28T02:46:43Z',
          invitation_sent_at: null,
          invitation_accepted_at: null,
          disabled: false,
          disabled_at: null,
          password_expired_at: '2018-10-26T02:46:43Z'
        },
        relationships: {
          devices: {
            data: [
              {
                id: 91,
                type: 'devices'
              }
            ]
          },
          user_role: {
            data: {
              id: 215,
              type: 'user_roles'
            }
          },
          profile: {
            data: {
              id: 343,
              type: 'profiles'
            }
          },
          language: {
            data: {
              id: 1,
              type: 'languages'
            }
          },
          patient: {
            data: {
              id: 6,
              type: 'trials__site_members'
            }
          },
          threads: {
            data: []
          },
          site_member: {
            data: {
              id: 6,
              type: 'trials__site_members'
            }
          },
          overall_status: {
            data: null
          }
        }
      },
      included: [
        {
          id: 91,
          type: 'devices',
          attributes: {
            udid: 'pvv1tgsczeo5t9i6unfp',
            technology: 'ios',
            access_token: '591420c626e1dbb019f77c9e2ab426b74d9c0d4a1469ad0a04c5a9801a06ae4d',
            push_id: 'csqo7fmp21dhk4ip66ob7kwb18yq3n37jn6jnosvavu9r8dmdns6s001jrb0jly6',
            created_at: '2018-07-28T02:46:43Z',
            updated_at: '2018-07-28T02:46:43Z',
            app_version: null
          }
        },
        {
          id: 215,
          type: 'user_roles',
          attributes: {
            permanent_link: 'valid_role',
            name: 'aperiam',
            is_super: false,
            is_admin: false,
            is_mobile: false,
            is_default: false,
            description: 'Random Role normal level'
          }
        },
        {
          id: 6,
          type: 'trials__site_members',
          attributes: {
            member_type: 'patient',
            consent_status: null,
            first_consented_at: null,
            last_consented_at: null,
            created_at: '2018-07-28T02:46:43Z',
            updated_at: '2018-07-28T02:46:43Z'
          },
          relationships: {
            site: {
              data: {
                id: 47,
                type: 'trials__sites'
              }
            },
            mobile_user: {
              data: {
                id: 154,
                type: 'mobile_users'
              }
            },
            consent_strategy: {
              data: null
            }
          }
        }
      ]
    }];
  });

  const response = await mobileUserService.signIn(
    { account_name: 'dummy_211', password: 'my_sekret_password' },
    { id: 91, type: 'device' }
  );

  t.is(request.path, `/v3/mobile_users/sessions`);
  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, undefined);

  t.truthy(response.user);
  t.is(response.user.id, 154);
  t.is(response.user.type, 'mobile_users');
  t.is(response.user.uuid, 'a519586e-cf05-439f-af8b-c0c1088c8492');
  t.is(response.user.accountName, 'dummy_150');
  t.is(response.user.createdAt, '2018-07-28T02:46:43Z');
  t.is(response.user.updatedAt, '2018-07-28T02:46:43Z');
  t.is(response.user.passwordExpiredAt, '2018-10-26T02:46:43Z');
  t.is(response.user.disabled, false);

  t.is(response.user.siteMember.id, 6);
  t.is(response.user.siteMember.type, 'trials__site_members');
  t.is(response.user.siteMember.memberType, 'patient');
  t.is(response.user.siteMember.firstConsentedAt, null);
  t.is(response.user.siteMember.lastConsentedAt, null);
  t.is(response.user.siteMember.consentStatus, null);
  t.is(response.user.siteMember.createdAt, '2018-07-28T02:46:43Z');
  t.is(response.user.siteMember.updatedAt, '2018-07-28T02:46:43Z');
  t.is(response.user.siteMember.site.id, 47);
  t.is(response.user.siteMember.site.type, 'trials__sites');
  t.is(response.user.siteMember.mobileUser.id, 154);
  t.is(response.user.siteMember.mobileUser.type, 'mobile_users');
  t.is(response.user.siteMember.consentStrategy, null);

  const dresp = response.user.devices[0];
  t.is(dresp.id, 91);
  t.is(dresp.type, 'devices');
  t.is(dresp.udid, 'pvv1tgsczeo5t9i6unfp');
  t.is(dresp.technology, 'ios');
  t.is(dresp.accessToken, '591420c626e1dbb019f77c9e2ab426b74d9c0d4a1469ad0a04c5a9801a06ae4d');
  t.is(dresp.pushId, 'csqo7fmp21dhk4ip66ob7kwb18yq3n37jn6jnosvavu9r8dmdns6s001jrb0jly6');
  t.is(dresp.createdAt, '2018-07-28T02:46:43Z');
  t.is(dresp.updatedAt, '2018-07-28T02:46:43Z');

  t.is(client.authToken, '591420c626e1dbb019f77c9e2ab426b74d9c0d4a1469ad0a04c5a9801a06ae4d');
});

/**
 * @test {UserService.signIn}
 */
test('[unit] UserService.signIn should throw an error if the email is considered blank', async (t) => {
  let request = {};
  nock(client.apiBaseUrl).post(`/v3/mobile_users/sessions`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [422, {
      errors: [
        {
          source: {
            pointer: '/data/attributes/email'
          },
          detail: 'can\'t be blank'
        }
      ]
    }];
  });
  let response;
  await mobileUserService.signIn({ email: 'user277@fake.com', password: 'test' }, { id: 134, type: 'device' }).catch(res => (response = res));
  t.is(request.path, `/v3/mobile_users/sessions`);
  t.is(request.headers.accept, 'application/json');
  t.is(request.headers['content-type'], 'application/json');
  t.is(request.headers.authorization, undefined);
  t.truthy(response);
});

// UserService.unlockUser method
/**
 * @test {UserService.unlockUser}
 */
test('[unit] UserService.unlockUser should throw errors for invalid parameters', async (t) => {
  const undefinedError = 'UserService.unlockUser error: email is not defined and unlockToken is not defined';
  const validError = 'UserService.unlockUser error: unlockToken is not defined and email is not a string';
  const validError2 = 'UserService.unlockUser error: email is not a string and unlockToken is not a string';
  await t.throwsAsync(mobileUserService.unlockUser(), undefinedError);
  await t.throwsAsync(mobileUserService.unlockUser(1234), validError);
  await t.throwsAsync(mobileUserService.unlockUser(1234, 1234), validError2);
});

/**
 * @test {UserService.unlockUser}
 */
test('[unit] UserService.unlockUser should successfully send a confirmation', async (t) => {
  // http://clinical6-docs.s3-website-us-east-1.amazonaws.com/apidoc/v3mobile_usersunlocks/update.html
  const requestJsonApi = {
    data: {
      type: 'mobile_user__unlocks',
      attributes: {
        email: 'user277@fake.com',
        unlock_token: '58031608'
      }
    }
  };

  client.authToken = 'valid_token';

  let request = {};
  nock(client.apiBaseUrl).patch(`/v3/mobile_users/unlock`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, {}];
  });
  const response = await mobileUserService.unlockUser('user277@fake.com', '58031608');
  t.is(request.path, `/v3/mobile_users/unlock`);
  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.truthy(response);
});

// UserService.update method
/**
 * @test {UserService.update}
 */
test('[unit] UserService.update should successfully update mobile user with a mobile user object', async (t) => {
  const { updateResponseMobileUser } = t.context;
  const user = new User(updateResponseMobileUser);
  let request = {};
  nock(client.apiBaseUrl).patch(`/v3/mobile_users/${user.id}`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [201, t.context.updateResponseMobileUser];
  });
  const response = await mobileUserService.update(user);
  t.is(request.path, `/v3/mobile_users/${user.id}`);
  t.is(request.headers.accept, 'application/json');
  t.deepEqual(request.requestBody, updateResponseMobileUser);
  t.is(request.headers['content-type'], 'application/json');
  t.is(request.headers.authorization, 'Token token=valid_token');
  t.is(response.id, 1);
  t.is(response.type, 'mobile_users');
});

// UserService.updateAwardedBadge method
/**
 * @test {UserService.updateAwardedBadge}
 */
test('[unit] UserService.updateAwardedBadge should throw errors for invalid parameters', async (t) => {
  client.authToken = 'valid_token';
  const title = 'UserService.updateAwardedBadge error';

  // undefined mobile user
  await t.throwsAsync(mobileUserService.updateAwardedBadge(), `${title}: awardedBadge is not defined`);
  await t.throwsAsync(mobileUserService.updateAwardedBadge({}), `${title}: awardedBadge does not have badge`);
  const awardedBadge = new AwardedBadge();
  awardedBadge.badge = new Badge();
  awardedBadge.awardee = { hello: 'world' };
  await t.throwsAsync(mobileUserService.updateAwardedBadge(awardedBadge), `${title}: awardedBadge does not have id and awardee does not have id and badge does not have id`);
  awardedBadge.badge.id = 1;
  await t.throwsAsync(mobileUserService.updateAwardedBadge(awardedBadge), `${title}: awardedBadge does not have id and awardee does not have id`);
  awardedBadge.awardee.id = 1;
  await t.throwsAsync(mobileUserService.updateAwardedBadge(awardedBadge), `${title}: awardedBadge does not have id`);
});

/**
 * @test {UserService.updateAwardedBadge}
 */
test('[unit] UserService.updateAwardedBadge should successfully updateAwardedBadge (api example)', async (t) => {
  // api-doc/1.0/registrations.html
  // http://clinical6-docs.s3-website-us-east-1.amazonaws.com/apidoc/v3relationshipsbadges/update.html
  const { storage } = t.context;

  const requestJsonApi = {
    data: {
      id: 283,
      type: 'awarded_badges',
      attributes: {},
      relationships: {
        awardee: {
          data: {
            type: 'mobile_users',
            id: 583
          }
        },
        badge: {
          data: {
            type: 'badges',
            id: 159
          }
        }
      }
    }
  };

  const awardedBadge = new AwardedBadge({ id: 283 });
  awardedBadge.awardee = new User({ id: 583 });
  awardedBadge.awardee.store();
  awardedBadge.badge = new Badge({ id: 159 });
  awardedBadge.badge.store();

  let request = {};
  nock(client.apiBaseUrl).patch(`/v3/mobile_users/${awardedBadge.awardee.id}/awarded_badges/${awardedBadge.id}`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, {
      data: {
        id: '20',
        type: 'awarded_badges',
        attributes: {
          created_at: '2017-08-10T17:54:18Z',
          updated_at: '2017-08-10T17:54:18Z',
          count: 0,
          earned_on_date: null
        },
        relationships: {
          awardee: {
            data: {
              type: 'mobile_users',
              id: '510'
            }
          },
          badge: {
            data: {
              type: 'badges',
              id: '41'
            }
          }
        }
      },
      included: [
        {
          id: '41',
          type: 'badges',
          attributes: {
            created_at: '2017-08-09T16:23:56Z',
            updated_at: '2017-08-09T16:23:56Z',
            title: 'dummy_462',
            description: 'Demo Content info...',
            redemption_points: 250,
            image: {
              image: {
                url: '/uploads/test/reward/image/17/1.png',
                small: {
                  url: '/uploads/test/reward/image/17/small_1.png'
                },
                small_hd: {
                  url: '/uploads/test/reward/image/17/small_hd_1.png'
                },
                fullscreen: {
                  url: '/uploads/test/reward/image/17/fullscreen_1.png'
                },
                main: {
                  url: '/uploads/test/reward/image/17/main_1.png'
                },
                fullscreen_hd: {
                  url: '/uploads/test/reward/image/17/fullscreen_hd_1.png'
                },
                main_hd: {
                  url: '/uploads/test/reward/image/17/main_hd_1.png'
                }
              }
            },
            position: 1,
            enabled: true,
            featured: null,
            based_on: null,
            threshold: null,
            time_unit: null,
            start_point: null,
            start_at: null,
            disabled_image: {
              disabled_image: {
                url: '/default/default.png',
                small: {
                  url: '/default/small_default.png'
                },
                small_hd: {
                  url: '/default/small_hd_default.png'
                },
                fullscreen: {
                  url: '/default/fullscreen_default.png'
                },
                main: {
                  url: '/default/main_default.png'
                },
                fullscreen_hd: {
                  url: '/default/fullscreen_hd_default.png'
                },
                main_hd: {
                  url: '/default/main_hd_default.png'
                }
              }
            },
            cache_token: 'xMnLvzU_uu4'
          }
        }
      ]
    }];
  });
  const response = await mobileUserService.updateAwardedBadge(awardedBadge);

  t.is(request.path, `/v3/mobile_users/${awardedBadge.awardee.id}/awarded_badges/${awardedBadge.id}`);
  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.truthy(response);
  t.is(response.constructor.name, 'AwardedBadge');
  storage.clear(awardedBadge.badge.type, awardedBadge.badge.id);
  storage.clear(awardedBadge.awardee.type, awardedBadge.awardee.id);
  storage.clear(awardedBadge.type, awardedBadge.id);
});

// UserService.updateSchedule method
/**
 * @test {UserService.updateSchedule}
 */
test('[unit] UserService.updateSchedule should throw errors for invalid parameters', async (t) => {
  const title = 'UserService.updateSchedule error';

  // undefined mobile user
  await t.throwsAsync(mobileUserService.updateSchedule(), `${title}: schedule is not defined`);
  await t.throwsAsync(mobileUserService.updateSchedule({}), `${title}: schedule does not have id`);
  const schedule = new Schedule();
  await t.throwsAsync(mobileUserService.updateSchedule(schedule), `${title}: schedule does not have id`);
  schedule.id = 1;
  schedule.mobileUser = new User();
  await t.throwsAsync(mobileUserService.updateSchedule(schedule), `${title}: user does not have id`);
});

/**
 * @test {UserService.updateSchedule}
 */
test('[unit] UserService.updateSchedule should successfully updateSchedule (api example)', async (t) => {
  // api-doc/1.0/registrations.html
  // http://clinical6-docs.s3-website-us-east-1.amazonaws.com/apidoc/v3relationshipsschedulerpersonalized_rule_schedules/update.html
  const { storage, updateResponseSchedule } = t.context;

  const requestJsonApi = {
    data: {
      id: 5,
      type: 'scheduler__personalized_rule_schedules',
      attributes: {
        start_date: '2017-06-02',
        relative_schedule: '1,2,4,8,12,14,16',
        enabled: false
      },
      relationships: {
        scheduleable: {
          data: {
            type: 'reminder__rules',
            id: 4
          }
        },
        mobile_user: {
          data: {
            type: 'mobile_users',
            id: 75
          }
        }
      }
    }
  };

  new Rule({ id: 4 }).store();
  new User({ id: 75 }).store();
  const schedule = new Schedule(requestJsonApi);
  await schedule.syncRelationships();

  let request = {};
  nock(client.apiBaseUrl).patch(`/v3/mobile_users/${schedule.mobileUser.id}/scheduler/personalized_rule_schedules/${schedule.id}`).reply(function (uri, requestBody) {
    request = this.req;
    request.requestBody = requestBody;
    return [200, updateResponseSchedule];
  });

  const response = await mobileUserService.updateSchedule(schedule);

  t.is(request.path, `/v3/mobile_users/${schedule.mobileUser.id}/scheduler/personalized_rule_schedules/${schedule.id}`);
  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.truthy(response);
  t.is(response.constructor.name, 'Schedule');
  storage.clear(schedule.mobileUser.type, schedule.mobileUser.id);
  storage.clear(schedule.scheduleable.type, schedule.scheduleable.id);
  storage.clear(schedule.type, schedule.id);
});