diff --git a/src/examples/get_rider_app_config.test.js b/src/examples/get_rider_app_config.test.js new file mode 100644 index 0000000..f72c3ce --- /dev/null +++ b/src/examples/get_rider_app_config.test.js @@ -0,0 +1,50 @@ +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import fetchMock from 'fetch-mock'; +import Track from '../index'; +import { charlie, riderAppConfiguration as mocks } from '../mocks'; + +chai.should(); +chai.use(chaiAsPromised); + +describe('When retrieving a rider app configuration', () => { + const api = new Track({ autoRenew: false }); + + beforeEach(() => charlie.setUpSuccessfulMock(api.client)); + beforeEach(() => mocks.setUpSuccessfulMock(api.client)); + beforeEach(() => fetchMock.catch(503)); + afterEach(fetchMock.restore); + + it('should get a the configuration', () => { + api.logIn({ username: 'charlie@example.com', password: 'securepassword' }); + + const configPromise = api.customer('SYNC').riderAppConfiguration() + .fetch() + .then(config => config); // Do things with config + + return configPromise; + }); +}); + +describe('When updating a rider app configuration', () => { + const api = new Track({ autoRenew: false }); + + beforeEach(() => charlie.setUpSuccessfulMock(api.client)); + beforeEach(() => mocks.setUpSuccessfulMock(api.client)); + beforeEach(() => fetchMock.catch(503)); + afterEach(fetchMock.restore); + + it('should update the configuration', () => { + api.logIn({ username: 'charlie@example.com', password: 'securepassword' }); + + const configPromise = api.customer('SYNC').riderAppConfiguration() + .fetch() + .then((config) => { + // eslint-disable-next-line no-param-reassign + config.spash_image_url = 'https://example.com/updated.png'; + return config.update(); + }); + + return configPromise; + }); +}); diff --git a/src/mocks/index.js b/src/mocks/index.js index 0364ac2..6cd8a04 100644 --- a/src/mocks/index.js +++ b/src/mocks/index.js @@ -19,6 +19,7 @@ export { default as messageChannels } from './messageChannels'; export { default as patterns } from './patterns'; export { default as reportingTickets } from './reportingTickets'; export { default as realTime } from './realTime'; +export { default as riderAppConfiguration } from './riderAppConfiguration'; export { default as roles } from './roles'; export { default as routes } from './routes'; export { default as runs } from './runs'; diff --git a/src/mocks/riderAppConfiguration.js b/src/mocks/riderAppConfiguration.js new file mode 100644 index 0000000..49a38f4 --- /dev/null +++ b/src/mocks/riderAppConfiguration.js @@ -0,0 +1,36 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import fetchMock from 'fetch-mock'; +import Client from '../Client'; + +const riderAppConfiguration = { + rawObject: { + href: '/1/SYNC/rider_app_configuration', + splash_image_url: 'https://example.com/logo.png', + accent_color: '#ABCDEF', + information: [{ + title: 'Agency Information', + items: [ + { + title: 'About Us', + link: 'https://example.com/about', + }, + { + title: 'Routes', + link: 'https://example.com/routes', + }, + ], + }], + }, + setUpSuccessfulMock: (client) => { + const url = client.resolve('/1/SYNC/rider_app_configuration'); + + const putResponse = () => new Response(undefined); + const getResponse = () => new Response(Client.toBlob(riderAppConfiguration.rawObject)); + + fetchMock + .put(url, putResponse) + .get(url, getResponse); + } +}; + +export default riderAppConfiguration; diff --git a/src/resources/Customer.js b/src/resources/Customer.js index 3aa6a3e..9f885ff 100644 --- a/src/resources/Customer.js +++ b/src/resources/Customer.js @@ -27,6 +27,7 @@ import DispatchMessageStatus from './DispatchMessageStatus'; import Pattern from './Pattern'; import PatternsContext from './PatternsContext'; import ReportingTicket from './ReportingTicket'; +import RiderAppConfiguration from './RiderAppConfiguration'; import Route from './Route'; import RoutesContext from './RoutesContext'; import Run from './Run'; @@ -296,6 +297,16 @@ class Customer extends Resource { return this.resource(Message, { code: this.code, ...payload }); } + /** + * Gets a Rider App Configuration resource + * @param {Object} payload New properties with which to initialize the Rider App Configuration + * @returns {RiderAppConfiguration} RiderAppConfiguration resource + */ + riderAppConfiguration(payload = {}) { + const href = RiderAppConfiguration.makeHref(this.code); + return this.resource(RiderAppConfiguration, { code: this.code, ...href, ...payload }); + } + /** * Gets a reporting ticket resource * @returns {ReportingTicket} ReportingTicket resource diff --git a/src/resources/Customer.test.js b/src/resources/Customer.test.js index 0f24254..91c10e6 100644 --- a/src/resources/Customer.test.js +++ b/src/resources/Customer.test.js @@ -24,6 +24,7 @@ import Message from './Message'; import MessagesContext from './MessagesContext'; import Pattern from './Pattern'; import PatternsContext from './PatternsContext'; +import RiderAppConfiguration from './RiderAppConfiguration'; import ReportingTicket from './ReportingTicket'; import Route from './Route'; import RoutesContext from './RoutesContext'; @@ -75,6 +76,7 @@ describe('When getting resources related to a customer', () => { it('should allow a message to be retrieved', () => customer.message().should.be.instanceof(Message)); it('should allow patterns to be searched', () => customer.patterns().should.be.instanceof(PatternsContext)); it('should allow a pattern to be retrieved', () => customer.pattern().should.be.instanceof(Pattern)); + it('should allow a rider app configuration to be retrieved', () => customer.riderAppConfiguration().should.be.instanceOf(RiderAppConfiguration)); it('should allow a reporting ticket to be retrieved', () => customer.reportingTicket().should.be.instanceof(ReportingTicket)); 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)); diff --git a/src/resources/RiderAppConfiguration.js b/src/resources/RiderAppConfiguration.js new file mode 100644 index 0000000..0cfadb3 --- /dev/null +++ b/src/resources/RiderAppConfiguration.js @@ -0,0 +1,60 @@ +import Resource from './Resource'; + +/** + * Rider App Configuration resource + */ +class RiderAppConfiguration extends Resource { + /** + * Creates a new RiderAppConfiguration. + * + * @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' || k === 'code'); + + Object.assign(this, newProperties, { + hydrated, + }); + } + + /** + * Creates an href for a given customer code + * + * @param {string} customerCode Customer code + * @returns {{href: string}} URI to instance of Rider App Configuration + */ + static makeHref(customerCode) { + return { + href: `/1/${customerCode}/rider_app_configuration`, + code: customerCode, + }; + } + + /** + * Fetches the Rider App Configuration for this customer data via the client + * @returns {Promise} If successful,a hydrated instance of Rider App Configuration + */ + fetch() { + return this.client.get(this.href) + .then(response => response.json()) + .then(config => new RiderAppConfiguration(this.client, this, config)); + } + + /** + * Updates the Rider App Configuration for this customer via the client + * @returns {Promise} If successful, returns the updated Rider App Configuration + */ + update() { + // eslint-disable-next-line no-unused-vars + const { client, hydrated, code, ...body } = this; + const { href } = RiderAppConfiguration.makeHref(code); + return this.client.put(href, { body }) + .then(() => new RiderAppConfiguration(this.client, { ...this })); + } +} + +export default RiderAppConfiguration; diff --git a/src/resources/RiderAppConfiguration.test.js b/src/resources/RiderAppConfiguration.test.js new file mode 100644 index 0000000..67e2100 --- /dev/null +++ b/src/resources/RiderAppConfiguration.test.js @@ -0,0 +1,63 @@ +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import fetchMock from 'fetch-mock'; +import Client from '../Client'; +import RiderAppConfiguration from './RiderAppConfiguration'; +import { riderAppConfiguration as mocks } from '../mocks'; + +chai.should(); +chai.use(chaiAsPromised); + +describe('When instantiating a Rider App Configuration based on customer', () => { + const client = new Client(); + const config = new RiderAppConfiguration(client, RiderAppConfiguration.makeHref('SYNC')); + + it('should set the href', () => config.href.should.equal('/1/SYNC/rider_app_configuration')); + it('should not be hydrated', () => config.hydrated.should.equal(false)); +}); + +describe('When instantiating a Rider App Configuration based on an object', () => { + const client = new Client(); + const config = new RiderAppConfiguration(client, mocks.rawObject); + + it('should set the href', () => config.href.should.equal('/1/SYNC/rider_app_configuration')); + it('should set the splash image url', () => config.splash_image_url.should.equal('https://example.com/logo.png')); + it('should set the accent color', () => config.accent_color.should.equal('#ABCDEF')); + it('should be hydrated', () => config.hydrated.should.equal(true)); +}); + +describe('When fetching a Rider App Configuration based on customer', () => { + const client = new Client(); + + beforeEach(() => mocks.setUpSuccessfulMock(client)); + beforeEach(() => fetchMock.catch(503)); + afterEach(fetchMock.restore); + + let promise; + beforeEach(() => { + promise = new RiderAppConfiguration(client, RiderAppConfiguration.makeHref('SYNC')).fetch(); + }); + + it('should resolve the promise', () => promise.should.be.fulfilled); + it('should set the href', () => promise.then(v => v.href).should.eventually.equal('/1/SYNC/rider_app_configuration')); + it('should be hydrated', () => promise.then(v => v.hydrated).should.eventually.equal(true)); +}); + +describe('When updating a Rider App Configuration for a customer', () => { + const client = new Client(); + + beforeEach(() => mocks.setUpSuccessfulMock(client)); + beforeEach(() => fetchMock.catch(503)); + afterEach(fetchMock.restore); + + let promise; + beforeEach(() => { + const config = new RiderAppConfiguration(client, RiderAppConfiguration.makeHref('SYNC')); + config.splash_image_url = 'https://example.com/logo.png'; + config.accent_color = '#ABCDEF'; + promise = config.update(); + }); + + it('should resolve the promise', () => promise.should.be.fulfilled); + it('should set the href', () => promise.then(v => v.href).should.eventually.equal('/1/SYNC/rider_app_configuration')); +});