Skip to content

Commit

Permalink
feat(driver-run-trip): Add support for Drivers, Runs, Trips. (#28)
Browse files Browse the repository at this point in the history
* Add Driver and DriversContext resources

* Add trip resource

* Add Run resource
  • Loading branch information
cuevaskoch authored and thzinc committed Nov 21, 2017
1 parent 44b4137 commit 208cf69
Show file tree
Hide file tree
Showing 14 changed files with 645 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/examples/get_drivers.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import fetchMock from 'fetch-mock';
import Track from '../index';
import { charlie, drivers as mockDrivers } from '../mocks';

chai.should();
chai.use(chaiAsPromised);

describe('When searching for drivers by name', () => {
const api = new Track({ autoRenew: false });

beforeEach(() => charlie.setUpSuccessfulMock(api.client));
beforeEach(() => mockDrivers.setUpSuccessfulMock(api.client));
beforeEach(() => fetchMock.catch(503));
afterEach(fetchMock.restore);

it('should get a list of drivers', () => {
api.logIn({ username: '[email protected]', password: 'securepassword' });

const driversPromise = api.customer('SYNC').drivers()
.withQuery('charlie') // drivers containing 'charlie' in their name
.getPage()
.then(page => page.list)
.then(drivers => drivers); // Do things with list of drivers

return driversPromise;
});
});

describe('When retrieving a driver by ID', () => {
const api = new Track({ autoRenew: false });

beforeEach(() => charlie.setUpSuccessfulMock(api.client));
beforeEach(() => mockDrivers.setUpSuccessfulMock(api.client));
beforeEach(() => fetchMock.catch(503));
afterEach(fetchMock.restore);

it('should get a driver', () => {
api.logIn({ username: '[email protected]', password: 'securepassword' });

const driverPromise = api.customer('SYNC').driver(1)
.fetch()
.then(driver => driver); // Do things with driver

return driverPromise;
});
});
27 changes: 27 additions & 0 deletions src/examples/get_run.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import fetchMock from 'fetch-mock';
import Track from '../index';
import { charlie, runs as mockRuns } from '../mocks';

chai.should();
chai.use(chaiAsPromised);

describe('When retrieving a run by ID', () => {
const api = new Track({ autoRenew: false });

beforeEach(() => charlie.setUpSuccessfulMock(api.client));
beforeEach(() => mockRuns.setUpSuccessfulMock(api.client));
beforeEach(() => fetchMock.catch(503));
afterEach(fetchMock.restore);

it('should get a run', () => {
api.logIn({ username: '[email protected]', password: 'securepassword' });

const runPromise = api.customer('SYNC').run(1)
.fetch()
.then(run => run); // Do things with run

return runPromise;
});
});
27 changes: 27 additions & 0 deletions src/examples/get_trip.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import fetchMock from 'fetch-mock';
import Track from '../index';
import { charlie, trips as mockTrips } from '../mocks';

chai.should();
chai.use(chaiAsPromised);

describe('When retrieving a trip by ID', () => {
const api = new Track({ autoRenew: false });

beforeEach(() => charlie.setUpSuccessfulMock(api.client));
beforeEach(() => mockTrips.setUpSuccessfulMock(api.client));
beforeEach(() => fetchMock.catch(503));
afterEach(fetchMock.restore);

it('should get a trip', () => {
api.logIn({ username: '[email protected]', password: 'securepassword' });

const tripPromise = api.customer('SYNC').trip(3)
.fetch()
.then(trip => trip); // Do things with trip

return tripPromise;
});
});
76 changes: 76 additions & 0 deletions src/mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,31 @@ export const agencies = {
}],
};

export const drivers = {
setUpSuccessfulMock: (client) => {
const listResponse = () => new Response(
Client.toBlob(drivers.list), {
headers: {
Link: '</1/SYNC/drivers?page=1&per_page=10&q=charlie&sort=>; rel="next", </1/SYNC/drivers?page=1&per_page=10&q=charlie&sort=>; rel="last"',
},
});
const singleResponse = () => new Response(Client.toBlob(drivers.getById(1)));

fetchMock
.get(client.resolve('/1/SYNC/drivers?page=1&per_page=10&sort='), listResponse)
.get(client.resolve('/1/SYNC/drivers?page=1&per_page=10&q=charlie&sort='), listResponse)
.get(client.resolve('/1/SYNC/drivers/1'), singleResponse);
},
getById: id => drivers.list.find(v => v.id === id),
list: [{
href: '/1/SYNC/drivers/1',
id: 1,
customer_driver_id: '0001',
first_name: 'Charlie',
last_name: 'Singh',
}],
};

export const externalApis = {
setUpSuccessfulMock: (client) => {
const listResponse = () => new Response(
Expand Down Expand Up @@ -353,6 +378,29 @@ export const patterns = {
],
};

export const runs = {
setUpSuccessfulMock: (client) => {
const singleResponse = () => new Response(Client.toBlob(runs.getById(1)));

fetchMock
.get(client.resolve('/1/SYNC/runs/1'), singleResponse);
},
getById: id => runs.list.find(v => v.id === id),
list: [{
href: '/1/SYNC/runs/1',
id: 1,
name: 'Run 1',
short_name: 'R01',
service: {
href: '/1/SYNC/services/1',
},
trips: [
{ href: '/1/SYNC/trips/1' },
{ href: '/1/SYNC/trips/2' },
],
}],
};

export const signs = {
setUpSuccessfulMock: (client) => {
const listResponse = () => new Response(
Expand Down Expand Up @@ -447,6 +495,34 @@ export const tags = {
}],
};

export const trips = {
setUpSuccessfulMock: (client) => {
const singleResponse = () => new Response(Client.toBlob(trips.getById(3)));

fetchMock
.get(client.resolve('/1/SYNC/trips/3'), singleResponse);
},
getById: id => trips.list.find(v => v.id === id),
list: [{
href: '/1/SYNC/trips/3',
id: 3,
name: 'T03',
order: 1,
pattern: {
href: '/1/SYNC/patterns/1',
},
service: {
href: '/1/SYNC/services/1',
},
block: {
href: '/1/SYNC/blocks/1',
},
runs: [{
href: '/1/SYNC/runs/1',
}],
}],
};

export const users = {
setUpSuccessfulMock: (client) => {
const listResponse = () => new Response(
Expand Down
39 changes: 39 additions & 0 deletions src/resources/Customer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import RealTimeContextFactory from './RealTimeContextFactory';
import Resource from './Resource';
import Agency from './Agency';
import Driver from './Driver';
import DriversContext from './DriversContext';
import ExternalApi from './ExternalApi';
import ExternalApisContext from './ExternalApisContext';
import MessageTemplate from './MessageTemplate';
Expand All @@ -9,12 +11,14 @@ import Pattern from './Pattern';
import PatternsContext from './PatternsContext';
import Route from './Route';
import RoutesContext from './RoutesContext';
import Run from './Run';
import Sign from './Sign';
import SignsContext from './SignsContext';
import Stop from './Stop';
import StopsContext from './StopsContext';
import Tag from './Tag';
import TagsContext from './TagsContext';
import Trip from './Trip';
import Vehicle from './Vehicle';
import VehiclesContext from './VehiclesContext';

Expand Down Expand Up @@ -58,6 +62,23 @@ class Customer extends Resource {
return this.resource(Agency, Agency.makeHref(this.code), payload);
}

/**
* Gets a context for querying this customer's drivers
* @returns {DriversContext} Context for querying this customer's drivers
*/
drivers() {
return this.resource(DriversContext, this.code);
}

/**
* Gets a driver resource by id
* @param {Number} id Identity of the driver
* @returns {Driver} Driver resource
*/
driver(id) {
return this.resource(Driver, Driver.makeHref(this.code, id));
}

/**
* Gets a context for querying this customer's external APIs
* @returns {ExternalApisContext} Context for querying this customer's external APIs
Expand Down Expand Up @@ -129,6 +150,15 @@ class Customer extends Resource {
return this.resource(Pattern, Pattern.makeHref(this.code, id));
}

/**
* Gets a Run resource by ID
* @param {Number} id Identity of the run
* @returns {Run} Run resource
*/
run(id) {
return this.resource(Run, Run.makeHref(this.code, id));
}

/**
* Gets a context for querying this customer's signs
* @returns {SignsContext} Context for querying this customer's signs
Expand Down Expand Up @@ -183,6 +213,15 @@ class Customer extends Resource {
return this.resource(Tag, { code: this.code, ...id });
}

/**
* Gets a trip resource by id
* @param {Number} id Identity of the trip
* @returns {Trip} Trip resource
*/
trip(id) {
return this.resource(Trip, Trip.makeHref(this.code, id));
}

/**
* Gets a context for querying this customer's vehicles
* @returns {VehiclesContext} Context for querying this customer's vehicles
Expand Down
8 changes: 8 additions & 0 deletions src/resources/Customer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import Client from '../Client';
import Customer from './Customer';
import RealTimeClient from '../RealTimeClient';
import Agency from './Agency';
import Driver from './Driver';
import DriversContext from './DriversContext';
import ExternalApi from './ExternalApi';
import ExternalApisContext from './ExternalApisContext';
import MessageTemplate from './MessageTemplate';
Expand All @@ -12,11 +14,13 @@ import Pattern from './Pattern';
import PatternsContext from './PatternsContext';
import Route from './Route';
import RoutesContext from './RoutesContext';
import Run from './Run';
import Sign from './Sign';
import SignsContext from './SignsContext';
import Stop from './Stop';
import StopsContext from './StopsContext';
import Tag from './Tag';
import Trip from './Trip';
import TagsContext from './TagsContext';
import Vehicle from './Vehicle';
import VehiclesContext from './VehiclesContext';
Expand All @@ -30,6 +34,8 @@ describe('When getting resources related to a customer', () => {
const customer = new Customer(client, realTimeClient, 'SYNC');

it('should allow the agency record to be retrieved', () => customer.agency().should.be.instanceOf(Agency));
it('should allow drivers to be searched', () => customer.drivers().should.be.instanceOf(DriversContext));
it('should allow a driver to be retrieved', () => customer.driver().should.be.instanceOf(Driver));
it('should allow external apis to be searched', () => customer.externalApis().should.be.instanceOf(ExternalApisContext));
it('should allow an external api to be retrieved', () => customer.externalApi().should.be.instanceOf(ExternalApi));
it('should allow message templates to be searched', () => customer.messageTemplates().should.be.instanceof(MessageTemplatesContext));
Expand All @@ -38,12 +44,14 @@ describe('When getting resources related to a customer', () => {
it('should allow a pattern to be retrieved', () => customer.pattern().should.be.instanceof(Pattern));
it('should allow routes to be searched', () => customer.routes().should.be.instanceof(RoutesContext));
it('should allow a route to be retrieved', () => customer.route().should.be.instanceof(Route));
it('should allow a run to be retrieved', () => customer.run().should.be.instanceof(Run));
it('should allow signs to be searched', () => customer.signs().should.be.instanceof(SignsContext));
it('should allow a sign to be retrieved', () => customer.sign().should.be.instanceof(Sign));
it('should allow stops to be searched', () => customer.stops().should.be.instanceof(StopsContext));
it('should allow a stop to be retrieved', () => customer.stop().should.be.instanceof(Stop));
it('should allow tags to be searched', () => customer.tags().should.be.instanceof(TagsContext));
it('should allow a tag to be retrieved', () => customer.tag().should.be.instanceof(Tag));
it('should allow a trip to be retrieved', () => customer.trip().should.be.instanceof(Trip));
it('should allow vehicles to be searched', () => customer.vehicles().should.be.instanceof(VehiclesContext));
it('should allow a vehicle to be retrieved', () => customer.vehicle().should.be.instanceof(Vehicle));
});
Expand Down
58 changes: 58 additions & 0 deletions src/resources/Driver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Resource from './Resource';

/**
* Driver resource
*/
class Driver extends Resource {

/**
* Creates a new driver.
*
* Will populate itself with the values given to it after the client parameter
* @example <caption>Assigning partial driver data to a new instance</caption>
* const client = new Client();
* const partialDriverData = {
* href: '/1/SYNC/drivers/1',
* id: 1,
* customer_driver_id: '0001',
* first_name: 'Charlie',
* last_name: 'Singh',
* };
* const driver = new Driver(client, partialDriverData);
*
* driver.hydrated == true;
* @param {Client} client Instance of pre-configured client
* @param {Array} rest Remaining arguments to use in assigning values to this instance
*/
constructor(client, ...rest) {
super(client);

const newProperties = Object.assign({}, ...rest);
const hydrated = !Object.keys(newProperties).every(k => k === 'href');
Object.assign(this, newProperties, { hydrated });
}

/**
* Makes a href for a given customer code and DI
* @param {string} customerCode Customer code
* @param {number} id Driver ID
* @returns {{href: string}} URI to instance of driver
*/
static makeHref(customerCode, id) {
return {
href: `/1/${customerCode}/drivers/${id}`,
};
}

/**
* Fetches the data for this driver via the client
* @returns {Promise} If successful, a hydrated instance of this driver
*/
fetch() {
return this.client.get(this.href)
.then(response => response.json())
.then(driver => new Driver(this.client, this, driver));
}
}

export default Driver;
Loading

0 comments on commit 208cf69

Please sign in to comment.