import feathers from '@feathersjs/feathers';
import { Application, Service } from 'feathersjs__feathers';
import { NotFound } from '@feathersjs/errors';
import ArangoDbService, { IArangoDbService, AUTH_TYPES } from '../src';
import { AutoDatabse } from '../src/auto-database';
import { expect, assert } from 'chai';

const serviceName = 'people';
const idProp = '_key';

describe(`Feathers common tests, ${serviceName} service with \\${idProp}\\ id property `, () => {
  const promiseDatabase = 'TEST_PROMISE_DB';
  const testDatabase = 'TEST_DB';
  const testCollection = 'TEST_COL';
  const testUser = 'root';
  const testPass = 'root';
  let app: Application | any;
  let service: IArangoDbService<any>;
  let _ids: any = {};

  before(async () => {
    app = feathers();
    app.use(
      `/${serviceName}`,
      ArangoDbService({
        id: idProp,
        collection: testCollection,
        database: testDatabase,
        authType: AUTH_TYPES.BASIC_AUTH,
        username: testUser,
        password: testPass,
        events: ['testing']
      })
    );
    service = <IArangoDbService<any>>app.service(serviceName);
  });

  after(async () => {
    const database = new AutoDatabse();
    database.useBasicAuth(testUser, testPass);
    await database.dropDatabase(testDatabase);
    await database.dropDatabase(promiseDatabase);
  });

  beforeEach(async () => {
    const data: any = await service.create({
      name: 'Doug',
      age: 32
    });
    _ids.Doug = data[idProp];
  });

  afterEach(async () => {
    await service.remove(_ids.Doug).catch(() => {});
  });

  it('Service connects', async () => {
    await service.connect();
    expect(service.database).not.to.be.undefined
    expect(service.collection).not.to.be.undefined
  });

  it('Can connect to a specified database url', async () => {
    app.use(
      `/tasks`,
      ArangoDbService({
        id: idProp,
        collection: 'tasks',
        database: testDatabase,
        authType: AUTH_TYPES.BASIC_AUTH,
        username: testUser,
        password: testPass,
        events: ['testing'],
        dbConfig: {
          url: 'http://localhost:8529',
        }
      })
    );
    const otherUrl = <IArangoDbService<any>>app.service('tasks');
    await otherUrl.connect();
    expect(otherUrl.database).not.to.be.undefined
    expect(otherUrl.collection).not.to.be.undefined
  });

  it('Service setup check', async () => {
    await service.setup();
    expect(service.database).not.to.be.undefined;
    expect(service.collection).not.to.be.undefined;
  });

  it('works', async () => {
    const something = true;
    expect(service).not.to.be.undefined;
    expect(something).to.be.true;
  });

  it('sets `id` property on the service', () => {
    expect(service.id).to.eq(idProp);
  });

  it('Accepts a promise as a database reference', async () => {
    const autoDb = new AutoDatabse();
    autoDb.useBasicAuth(testUser, testPass);
    const promiseDb = autoDb.autoUseDatabase(promiseDatabase);
    const dbService = ArangoDbService({
      id: idProp,
      collection: testCollection,
      database: promiseDb
    });
    await dbService.connect();
    const info = await dbService.database.get();
    expect(dbService.database).not.to.be.undefined;
    expect(dbService.collection).not.to.be.undefined;
    expect(info.name).to.eq(promiseDatabase);
  });

  it('Accepts a promise as a collection reference', async () => {
    const autoDb = new AutoDatabse();
    autoDb.useBasicAuth(testUser, testPass);
    const db = await autoDb.autoUseDatabase(promiseDatabase);
    const collectionPromise = autoDb.autoCollection('PROMISE_COLLECTION');
    const dbService = ArangoDbService({
      id: idProp,
      collection: collectionPromise,
      database: db
    });
    await dbService.connect();
    const info = await dbService.collection.get();
    expect(dbService.database).not.to.be.undefined;
    expect(dbService.collection).not.to.be.undefined;
    expect(info.name).to.eq('PROMISE_COLLECTION');
  });

  it('Accepts string as database & collection', async () => {
    const dbService = ArangoDbService({
      id: idProp,
      collection: testCollection,
      database: testDatabase,
      authType: AUTH_TYPES.BASIC_AUTH,
      username: testUser,
      password: testPass
    });
    await dbService.connect();
    expect(dbService.database).not.to.be.undefined;
    expect(dbService.collection).not.to.be.undefined;
  });

  it('Accepts a database & collection as arguments', async () => {
    const database = new AutoDatabse();
    database.useBasicAuth(testUser, testPass);
    database.useDatabase(testDatabase);
    const collection = await database.collection(testCollection);
    const dbService = ArangoDbService({
      database,
      collection
    });
    expect(dbService.database).not.to.be.undefined;
    expect(dbService.collection).not.to.be.undefined;
  });

  it('sets `events` property from options', () => {
    expect(service.events.indexOf('testing')).not.to.eq(-1);
  });

  describe('extend', () => {
    it('extends and uses extended method', async () => {
      const now = new Date().getTime();
      // @ts-ignore  Extend added inside feathersJS via Uberproto
      const extended = service.extend({
        create: function create(data: any) {
          data.time = now;
          return this._super.apply(this, arguments);
        }
      });
      const createResult = await extended.create({ name: 'Dave' });
      const removeResult = await extended.remove(createResult[idProp]);
      expect(removeResult.time).to.eq(now);
    });
  });

  describe('get', () => {

    it('returns an instance that exists', async () => {
      const result = await service.get(_ids.Doug);
      expect(result[idProp].toString()).to.eq(_ids.Doug.toString());
      expect(result.name).to.eq('Doug');
      expect(result.age).to.eq(32);
    });

    it('supports $select', async () => {
      const result = await service.get(_ids.Doug, {
        query: { $select: ['name'] }
      });
      expect(result[idProp]).to.eq(_ids.Doug);
      expect(result.name).to.eq('Doug');
      expect(result.age).to.be.undefined;
    });

    it('returns NotFound error for non-existing id', () => {
      const badId = '568225fbfe21222432e836ff';
      service
        .get(badId)
        .then(() => {
          throw Error('Should NOT succeed!!!');
        })
        .catch(error => {
          expect(error instanceof NotFound).to.be.true;
          expect(error.message).to.eq(`No record found for id '${badId}'`);
        });
    });
  });

  describe('remove', () => {

    it('deletes an existing instance and returns the deleted instance', async () => {
      const result = await service.remove(_ids.Doug);
      expect(result['name']).to.eq('Doug');
    });

    it('deletes an existing instance supports $select', async () => {
      const result = await service.remove(_ids.Doug, {query: { $select: ['name']}});
      expect(result[idProp]).to.eq(_ids.Doug);
      expect(result['name']).to.eq('Doug');
      expect(result['age']).to.be.undefined;
    });

    it('deletes multiple instances', async () => {
      await service.create({name: 'Dave', age: 29, created: true});
      await service.create({name: 'David', age: 48, created: true});
      const result = await service.remove(null, {query: { created: true }});
      const names = result.map((person:any) => person.name);
      expect(names.indexOf('Dave')).to.be.greaterThan(-1);
      expect(names.indexOf('David')).to.be.greaterThan(-1);
    })
  });

  describe('find', () => {
    // Doug 32, Bob 25, ALice 19
    beforeEach(async () => {
      const bob = await service.create({ name: 'Bob', age: 25 });
      _ids.Bob = bob[idProp];
      const alice = await service.create({ name: 'Alice', age: 19 });
      _ids.Alice = alice[idProp];
    });

    afterEach(async () => {
      await service.remove(_ids.Bob);
      await service.remove(_ids.Alice);
    });

    it('returns all items', async () => {
      const result = <[any]> await service.find();
      expect(Array.isArray(result)).to.be.true;
      expect(result.length).to.eq(3);
    });

    it('filters results by a single parameter', async () => {
      const result = <[any]>await service.find({ query: { name: 'Alice' } });
      expect(Array.isArray(result)).to.be.true;
      expect(result.length).to.eq(1);
      expect(result[0].name).to.eq('Alice');
    });

    it('filters results by multiple parameters', async () => {
      // TODO This is a POOR test. Should be strengthened by having more than one age 19 or Alice
      const result = <[any]>await service.find({ query: { name: 'Alice', age: 19 } });
      expect(Array.isArray(result)).to.be.true;
      expect(result.length).to.eq(1);
      expect(result[0].name).to.eq('Alice');
    });

    describe('falsy values', () => {

      beforeEach(async () => {
        const philip = await service.create({ name: 'Philip', age: 0});
        _ids.philip = philip[idProp];
        const steven = await service.create({ name: 'Steven'});
        _ids.steven = steven[idProp];
      });

      it('can $ne to 0', async () => {
        const params = {
          query: {age: {$ne: 0}, $sort: {name: 1}}
        }
        const result = <Array<any>>await service.find(params)
        expect(result.length).to.eq(4)
        expect(result[0].name).to.eq('Alice')
        expect(result[1].name).to.eq('Bob')
        expect(result[2].name).to.eq('Doug')
        expect(result[3].name).to.eq('Steven')
      })

      it('can $gt than 0', async () => {
        const params = {
          query: {age: {$gt: 0}, $sort: {name: 1}}
        }
        const result = <Array<any>>await service.find(params)
        expect(result.length).to.eq(3)
        expect(result[0].name).to.eq('Alice')
        expect(result[1].name).to.eq('Bob')
        expect(result[2].name).to.eq('Doug')
      })

      it('can $ne to null', async () => {
        const params = {
          query: {age: {$ne: null}, $sort: {name: 1}}
        }
        const result = <Array<any>>await service.find(params)
        expect(result.length).to.eq(4)
        expect(result[0].name).to.eq('Alice')
        expect(result[1].name).to.eq('Bob')
        expect(result[2].name).to.eq('Doug')
        expect(result[3].name).to.eq('Philip')
      })

      it('can equal to null', async () => {
        const params = {
          query: {age: null}
        }
        const result = <Array<any>>await service.find(params)
        expect(result.length).to.eq(1)
        expect(result[0].name).to.eq('Steven')
      })

      afterEach(async () => {
        await service.remove(_ids.philip);
        await service.remove(_ids.steven);
      });
    })
    describe('array functions', () => {
      beforeEach(async () => {
        const mike = await service.create({ name: 'Mike', age: 0, friends: [{name: 'Alice'}, {name: 'Bob'}], parents: [{name: 'Freek'}]});
        _ids.mike = mike[idProp];

        const jake = await service.create({ name: 'Jake', age: 0, friends: [{ name: 'Doug'}], parents: [{name: 'Anne'}]});
        _ids.jake = jake[idProp];
      });
      afterEach(async () => {
        await service.remove(_ids.mike).catch(() => {});
        await service.remove(_ids.jake).catch(() => {});
      })

      it('can $elemMatch', async () => {
        const params = {
          query: { friends: { $elemMatch: { name: {$in: ['Alice']}}}}
        };
        const result = <any[]>await service.find(params);
        const names = result.map(r => r.name)
        assert.equal(names.length,1)
        assert.include(names,'Mike')
      });

      it('can $elemMatch for multiple', async () => {
        const params = {
          query: { friends: { $elemMatch: { name: {$in: ['Bob','Doug']}}}}
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(2);
        const names = result.map(r => r.name)
        assert.include(names,'Mike')
        assert.include(names,'Jake')
      });

      it('can $elemMatch with $or', async () => {
        const params = {
          query: { $or: [
            {friends: { $elemMatch: { name: {$in: ['Doug']} }}},
            {parents: { $elemMatch: { name: {$in: ['Freek']} }}}
          ]
        }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(2);
        const names = result.map(r => r.name)
        assert.include(names,'Mike')
        assert.include(names,'Jake')
      });

      it('can $size equal to value', async () => {
        const params = {
          query: {friends: {$size: 2}}
        }
        const result = <Array<any>>await service.find(params)
        expect(result.length).to.eq(1)
        expect(result[0].name).to.eq('Mike')
      })
      it('can $size greater then value', async () => {
        const params = {
          query: {friends: {$size: {$gte: 1}}}
        }
        const result = <Array<any>>await service.find(params)
        expect(result.length).to.eq(2)
        expect(result[0].name).to.eq('Mike')
        expect(result[1].name).to.eq('Jake')
      })
    })
    describe('special filters', () => {

      it('can $sort', async () => {
        const params = {
          query: { $sort: { name: 1 } }
        };
        const result = <Array<any>>await service.find(params);
        expect(result.length).to.eq(3);
        expect(result[0].name).to.eq('Alice');
        expect(result[1].name).to.eq('Bob');
        expect(result[2].name).to.eq('Doug');
      });

      it('can $sort with strings', async () => {
        const params = {
          query: { $sort: { name: '1' } }
        };
        const result = <Array<any>>await service.find(params);
        expect(result.length).to.eq(3);
        expect(result[0].name).to.eq('Alice');
        expect(result[1].name).to.eq('Bob');
        expect(result[2].name).to.eq('Doug');
      });

      it('can $limit', async () => {
        const params = {
          query: { $limit: 2 }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(2);
      });

      it('can $limit 0', async () => {
        const params = {
          query: { $limit: 0 }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(0);
      });

      it('can $skip', async () => {
        const params = {
          query: { $sort: { name: 1 }, $skip: 1 }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(2);
        expect(result[0].name).to.eq('Bob');
        expect(result[1].name).to.eq('Doug');
      });

      it('can $select', async () => {
        const params = {
          query: { name: 'Alice', $select: ['name'] }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(1);
        expect(result[0].name).to.eq('Alice');
        expect(result[0].age).to.be.undefined;
      });

      it('can $or', async () => {
        const params = {
          query: { $or: [{ name: 'Alice' }, { name: 'Bob' }], $sort: { name: 1 } }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(2);
        expect(result[0].name).to.eq('Alice');
        expect(result[1].name).to.eq('Bob');
      });

      it('can $not', async () => {
        const params = {
          query: { age: { $not: 19 }, name: { $not: 'Doug' } }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(1);
        expect(result[0].name).to.eq('Bob');
      });

      it('can $in', async () => {
        const params = {
          query: { name: { $in: ['Alice', 'Bob'] }, $sort: { name: 1 } }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(2);
        expect(result[0].name).to.eq('Alice');
        expect(result[1].name).to.eq('Bob');
      });

      it('can $nin', async () => {
        const params = {
          query: { name: { $nin: ['Alice', 'Bob'] } }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(1);
        expect(result[0].name).to.eq('Doug');
      });

      it('can $lt', async () => {
        const params = {
          query: { age: { $lt: 30 }, $sort: { name: 1 } }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(2);
        expect(result[0].name).to.eq('Alice');
        expect(result[1].name).to.eq('Bob');
      });

      it('can $lte', async () => {
        const params = {
          query: { age: { $lte: 25 }, $sort: { name: 1 } }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(2);
        expect(result[0].name).to.eq('Alice');
        expect(result[1].name).to.eq('Bob');
      });

      it('can $gt', async () => {
        const params = {
          query: { age: { $gt: 30 }, $sort: { name: 1 } }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(1);
        expect(result[0].name).to.eq('Doug');
      });

      it('can $gte', async () => {
        const params = {
          query: { age: { $gte: 25 }, $sort: { name: 1 } }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(2);
        expect(result[0].name).to.eq('Bob');
        expect(result[1].name).to.eq('Doug');
      });

      it('can $ne', async () => {
        const params = {
          query: { age: { $ne: 25 }, $sort: { name: 1 } }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(2);
        expect(result[0].name).to.eq('Alice');
        expect(result[1].name).to.eq('Doug');
      });


      it('can $gt and $lt and $sort', async () => {
        const params = {
          query: { age: { $gt: 18, $lt: 30 }, $sort: { name: 1 } }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(2);
        expect(result[0].name).to.eq('Alice');
        expect(result[1].name).to.eq('Bob');
      });

      it('can handle nested $or queries and $sort', async () => {
        const params = {
          query: {
            $or: [{ name: 'Doug' }, {
              age: {
                $gte: 18,
                $lt: 25
              }
            }],
            $sort: { name: 1 }
          }
        };
        const result = <any[]>await service.find(params);
        expect(result.length).to.eq(2);
        expect(result[0].name).to.eq('Alice');
        expect(result[1].name).to.eq('Doug');
      });

      it('can handle mixed OR and AND in one query', async () => {
        const params = {
          query: {
            $or:[{
              age: 32,
            },
            {
              age:25,
            }],
            name: "Bob",
          },
        }
        const result = <any[]>await service.find(params)
        expect(result.length).to.eq(1)
        expect(result[0].age).to.eq(25)
      })

      it('can handle advanced OR and AND mix', async () => {
        const params = {
          query: {
            $and: [
              {$or:[{
                age: 32,
              },
              {
                age:25,
              }]},
              {$or:[{
                name: "Bob",
              },
              {
                name: "Alice",
              }]}
            ]
          },
        }
        const result = <any[]>await service.find(params)
        expect(result.length).to.eq(1)
        expect(result[0].name).to.eq("Bob")
      })
    });

    describe('paginate', () => {
      beforeEach(async () => {
        service.paginate = { default: 1, max: 2 };
      });
      afterEach(async () => {
        service.paginate = {};
      });

      it('returns paginated object, paginates by default and shows total', async () => {
        const params = { query: { $sort: { name: -1 } } };
        const result = <any>await service.find(params);
        expect(result.total).to.eq(3);
        expect(result.limit).to.eq(1);
        expect(result.skip).to.eq(0);
        expect(result.data[0].name).to.eq('Doug');
      });

      it('paginates max and skips', async () => {
        const params = { query: { $skip: 1, $limit: 4, $sort: { name: -1 } } };
        const result = <any>await service.find(params);
        expect(result.total).to.eq(3);
        expect(result.limit).to.eq(2);
        expect(result.skip).to.eq(1);
        expect(result.data[0].name).to.eq('Bob');
        expect(result.data[1].name).to.eq('Alice');
      });

      it('$limit 0 with pagination', async () => {
        const params = { query: { $limit: 0 } };
        const result = <any>await service.find(params);
        expect(result.data.length).to.eq(0);
      });

      it('allows to override paginate in params', async () => {
        const params = { paginate: { default: 2, max: 1000 } };
        const result = <any>await service.find(params);
        expect(result.limit).to.eq(2);
        expect(result.skip).to.eq(0);
      });

      it('total works with filter', async () => {
        const params = { query: { $sort: {name: 1}, $limit: 1, age: {$gt: 20} } };
        const result = <any>await service.find(params);
        expect(result.total).to.eq(2);
        expect(result.limit).to.eq(1);
        expect(result.skip).to.eq(0);
        expect(result.data[0].name).to.eq('Bob');
      });
    });
  });

  describe('update', () => {

    it('replaces an existing instance, does not modify original data', async () => {
      const newData:any = { name: 'Dougler'};
      newData[idProp] = _ids.Doug;
      const result = await service.update(_ids.Doug, newData);
      expect(result[idProp]).to.eq(_ids.Doug);
      expect(result['name']).to.eq('Dougler');
      expect(result['age']).to.be.undefined;
    });

    it('replaces an existing instance, supports $select', async () => {
      const newData:any = { name: 'Dougler', age: 10};
      newData[idProp] = _ids.Doug;
      const result = await service.update(_ids.Doug, newData, {query: { $select: ['name'] }});
      expect(result[idProp]).to.eq(_ids.Doug);
      expect(result['name']).to.eq('Dougler');
      expect(result['age']).to.be.undefined;
    });

    it('returns NotFound error for non-existing id', async () => {
      const badId = '568225fbfe21222432e836ff';
      const newData:any = { name: 'NotFound'};
      newData[idProp] = badId;
      await service.update(badId, newData).catch( error => {
        expect(error instanceof NotFound).to.be.true;
        expect(error.message).to.eq(`No record found for id '${badId}'`);
      })
    });
  });

  describe('patch', () => {
    it('updates an existing instance, does not modify original data', async () => {
      const newData:any = { name: 'PatchDoug'};
      newData[idProp] = _ids.Doug;
      const result = await service.patch(_ids.Doug, newData);
      expect(result[idProp]).to.eq(_ids.Doug);
      expect(result['name']).to.eq('PatchDoug');
      expect(result['age']).to.eq(32);
    });

    it('updates an existing instance, supports $select', async () => {
      const newData:any = { name: 'PatchDoug'};
      newData[idProp] = _ids.Doug;
      const result = await service.patch(_ids.Doug, newData, {query: { $select: ['name'] }});
      expect(result[idProp]).to.eq(_ids.Doug);
      expect(result['name']).to.eq('PatchDoug');
      expect(result['age']).to.be.undefined
    });

    it('patches multiple instances', async () => {
      const params = { query: { created: true } };
      await service.create({name: 'Dave', age: 29, created: true});
      await service.create({name: 'David', age: 3, created: true});
      const result = await service.patch(null, { age: 2 }, params);
      expect(result.length).to.eq(2);
      expect(result[0].age).to.eq(2);
      expect(result[1].age).to.eq(2);
      await service.remove(null, params);
    });

    it('patches multiple instances and returns the actually changed items', async () => {
      const params = { query: { age: { $lt: 10 } } };
      await service.create({name: 'Dave', age: 8, created: true});
      await service.create({name: 'David', age: 4, created: true});
      const result = await service.patch(null, { age: 2 }, params);
      expect(result.length).to.eq(2);
      expect(result[0].age).to.eq(2);
      expect(result[1].age).to.eq(2);
      await service.remove(null, params);
    });

    it('patches multiple, returns correct items', async () => {
      await service.create({name: 'Dave', age: 2, created: true});
      await service.create({name: 'David', age: 2, created: true});
      await service.create({name: 'Frank', age: 8, created: true});
      const result = await service.patch(null, { age: 8 }, { query: { age: 2 } });
      expect(result.length).to.eq(2);
      expect(result[0].age).to.eq(8);
      expect(result[1].age).to.eq(8);
      await service.remove(null, { query: { age: 8 } });
    });

    it('returns NotFound error for non-existing id', async () => {
      const badId = '568225fbfe21222432e836ff';
      const newData:any = { name: 'NotFound'};
      newData[idProp] = badId;
      await service.patch(badId, newData).catch( error => {
        expect(error instanceof NotFound).to.be.true;
        expect(error.message).to.eq(`No record found for id '${badId}'`);
      })
    });
  });

  describe('create', () => {
    it('creates a single new instance and returns the created instance', async () => {
      const originalData = { name: 'Bill', age: 40 };
      const result = await service.create(originalData);
      expect(result).not.to.be.undefined;
      expect(result).to.be.an('object').that.contains.keys(Object.keys(originalData));
      expect(result.name).to.eq('Bill')
      expect(result.age).to.eq(40)
      await service.remove(result[idProp]);
    });

    it('creates a single new instance, supports $select', async () => {
      const originalData = { name: 'William', age: 23 };
      const result = await service.create(originalData, {query: { $select: ['name'] }});
      expect(result).not.to.be.undefined;
      expect(result.name).to.eq('William');
      expect(result.age).to.be.undefined;
      await service.remove(result[idProp]);
    });

    it('creates multiple new instances', async () => {
      const originalData = [{
        name: 'Gerald',
        age: 18
      }, {
        name: 'Herald',
        age: 18
      }];
      const result = await service.create(originalData);
      expect(result).not.to.be.undefined;
      expect(Array.isArray(result)).to.be.true;
      expect(result[0].name).to.eq('Gerald');
      expect(result[1].name).to.eq('Herald');
      await service.remove(result[0][idProp]);
      await service.remove(result[1][idProp]);
    });
  });

  ///  HERE WE GO  !!!!!!!
  describe('Services don\'t call public methods internally', () => {
    let throwing:any;
    before(() => {
      // @ts-ignore  Extended isn't properly typed
      throwing = <any>service.extend({
        get store() {
          // @ts-ignore  Not sure where this comes from...
          return service.store;
        },

        find: function find() {
          throw new Error('find method called');
        },
        get: function get() {
          throw new Error('get method called');
        },
        create: function create() {
          throw new Error('create method called');
        },
        update: function update() {
          throw new Error('update method called');
        },
        patch: function patch() {
          throw new Error('patch method called');
        },
        remove: function remove() {
          throw new Error('remove method called');
        }
      });
    });

    it('find', async () => {
      await service.find.call(throwing);
    });

    it('get', async () => {
      await service.get.call(throwing, _ids.Doug);
    });

    it('create', async () => {
      const result = await service.create.call(throwing, { name: 'Bob', age: 25 });
      await service.remove(result[idProp]);
    });

    it('update', async () => {
      await service.update.call(throwing, _ids.Doug, { name: 'Dougler' });
    });

    it('patch', async () => {
      await service.patch.call(throwing, _ids.Doug, { name: 'PatchDoug' });
    });

    it('remove', async () => {
      await service.remove.call(throwing, _ids.Doug);
    });

  })

});
