diff --git a/.ember-cli b/.ember-cli index fd97b187..d4e4e336 100644 --- a/.ember-cli +++ b/.ember-cli @@ -6,5 +6,12 @@ Setting `disableAnalytics` to true will prevent any data from being sent. */ "disableAnalytics": false, + + /** + Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript + rather than JavaScript by default, when a TypeScript version of a given blueprint is available. + */ + "isTypeScriptProject": false, + "port": 4300 } diff --git a/.eslintignore b/.eslintignore index 1c0249db..ae117de9 100644 --- a/.eslintignore +++ b/.eslintignore @@ -19,7 +19,10 @@ # ember-try /.node_modules.ember-try/ /bower.json.ember-try +/npm-shrinkwrap.json.ember-try /package.json.ember-try +/package-lock.json.ember-try +/yarn.lock.ember-try - +# custom /mirage/mirage diff --git a/.eslintrc.js b/.eslintrc.js index 979db294..0147760c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -62,7 +62,7 @@ module.exports = { }, }, { - // Test files: + // test files files: ['tests/**/*-test.{js,ts}'], extends: ['plugin:qunit/recommended'], }, diff --git a/.gitignore b/.gitignore index 82447690..f1e859b2 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,10 @@ # ember-try /.node_modules.ember-try/ /bower.json.ember-try +/npm-shrinkwrap.json.ember-try /package.json.ember-try +/package-lock.json.ember-try +/yarn.lock.ember-try -.travis/*.key +# broccoli-debug +/DEBUG/ diff --git a/.prettierignore b/.prettierignore index 92216555..4178fd57 100644 --- a/.prettierignore +++ b/.prettierignore @@ -14,8 +14,12 @@ /coverage/ !.* .eslintcache +.lint-todo/ # ember-try /.node_modules.ember-try/ /bower.json.ember-try +/npm-shrinkwrap.json.ember-try /package.json.ember-try +/package-lock.json.ember-try +/yarn.lock.ember-try diff --git a/README.md b/README.md index 8ebcab95..e2030dbc 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ You will need the following things properly installed on your computer. * [Git](https://git-scm.com/) * [Node.js](https://nodejs.org/) (with npm) -* [Ember CLI](https://ember-cli.com/) +* [Ember CLI](https://cli.emberjs.com/release/) * [Google Chrome](https://google.com/chrome/) ## Installation @@ -49,7 +49,7 @@ Specify what it takes to deploy your app. ## Further Reading / Useful Links * [ember.js](https://emberjs.com/) -* [ember-cli](https://ember-cli.com/) +* [ember-cli](https://cli.emberjs.com/release/) * Development Browser Extensions * [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi) * [ember inspector for firefox](https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/) diff --git a/app/components/calendar-slot.gjs b/app/components/calendar-slot.gjs index 1bbc9bcf..9d35562b 100644 --- a/app/components/calendar-slot.gjs +++ b/app/components/calendar-slot.gjs @@ -90,11 +90,11 @@ export default class CalendarSlot extends Component { } get hidden() { - return !this.slot?.isNotFull && !this.isCommittedTo; + return !this.isNotFull && !this.isCommittedTo; } get disabled() { - const isNotFull = this.slot?.isNotFull; + const isNotFull = this.isNotFull; const start = this.slot?.start; const toggleIsRunning = this.toggle.isRunning; @@ -118,6 +118,13 @@ export default class CalendarSlot extends Component { return `${dividend}/${divisor}`; } + get isNotFull() { + const count = this.slot?.count ?? 0; + const commitmentCount = this.slot?.commitments?.length ?? 0; + + return count === 0 || commitmentCount < count; + } + toggle = task({ drop: true }, async (event) => { event.preventDefault(); @@ -142,7 +149,7 @@ export default class CalendarSlot extends Component { const errorDetail = error?.errors?.[0]?.detail; this.args.setError(errorDetail || 'Couldn’t save your change'); } - } else if (this.slot?.isNotFull) { + } else if (this.isNotFull) { const newRecord = this.store.createRecord('commitment', { slot: this.slot, person: this.person, diff --git a/app/components/ride-form.gjs b/app/components/ride-form.gjs index 3cc965e4..4b205938 100644 --- a/app/components/ride-form.gjs +++ b/app/components/ride-form.gjs @@ -710,12 +710,12 @@ export default class RideForm extends Component { @action handleSubmit(event) { event?.preventDefault?.(); - this.save?.(); + return this.save?.(); } @action handleCancel(event) { event?.preventDefault?.(); - this.cancel?.(); + return this.cancel?.(); } } diff --git a/app/controllers/admin-calendar.js b/app/controllers/admin-calendar.js index f9e21531..d7a30294 100644 --- a/app/controllers/admin-calendar.js +++ b/app/controllers/admin-calendar.js @@ -75,17 +75,18 @@ export default class AdminCalendarController extends CalendarController { @setDiff('activePeople', 'people') remainingPeople; - @mapBy('viewingSlot.commitments', 'person') - viewingSlotPeople; - - @mapBy('viewingSlotPeople', 'id') - viewingSlotPeopleIds; - - @computed('activePeople.[]', 'viewingSlotPeopleIds.[]') + @computed('activePeople.[]', 'viewingSlot.commitments.{[],@each.person}') get uncommittedPeople() { - const alreadyCommittedPeople = this.viewingSlotPeopleIds; - return this.activePeople.reject((person) => - alreadyCommittedPeople.includes(person.id), + const commitments = this.viewingSlot?.commitments || []; + const committedIds = new Set( + Array.from(commitments) + .map((commitment) => commitment.person?.id) + .filter(Boolean), + ); + const activePeople = this.activePeople || []; + + return Array.from(activePeople).filter( + (person) => !committedIds.has(person.id), ); } @@ -105,27 +106,26 @@ export default class AdminCalendarController extends CalendarController { } @action - createCommitment(person) { + async createCommitment(person) { const slot = this.viewingSlot; const commitment = this.store.createRecord('commitment', { slot: this.viewingSlot, person: person, }); - commitment - .save() - .then(() => { - this.set('errorMessage', undefined); - this.toasts.show( - `Committed ${person.get('name')} to drive on ${moment( - slot.get('start'), - ).format('MMMM D')}`, - ); - }) - .catch((error) => { - const errorDetail = get(error, 'errors.firstObject.detail'); - this.set('errorMessage', errorDetail || 'Couldn’t save your change'); - }); + try { + await commitment.save(); + this.set('errorMessage', undefined); + this.notifyPropertyChange('viewingSlot'); + this.toasts.show( + `Committed ${person.get('name')} to drive on ${moment( + slot.get('start'), + ).format('MMMM D')}`, + ); + } catch (error) { + const errorDetail = get(error, 'errors.firstObject.detail'); + this.set('errorMessage', errorDetail || 'Couldn’t save your change'); + } } @action @@ -137,6 +137,7 @@ export default class AdminCalendarController extends CalendarController { .destroyRecord() .then(() => { this.set('errorMessage', undefined); + this.notifyPropertyChange('viewingSlot'); this.toasts.show(`Deleted ${name}’s commitment on ${date}`); }) .catch((error) => { diff --git a/app/controllers/drivers.js b/app/controllers/drivers.js index b9660e41..3e19f2ea 100644 --- a/app/controllers/drivers.js +++ b/app/controllers/drivers.js @@ -7,6 +7,9 @@ import BufferedProxy from 'ember-buffered-proxy/proxy'; @classic export default class DriversController extends Controller { + @service('people') + peopleService; + @service store; @@ -18,9 +21,15 @@ export default class DriversController extends Controller { sortDir = 'asc'; errorMessage = undefined; - @computed('model.@each.{name,lastRide}', 'sortProp', 'sortDir') + @computed( + 'model', + 'model.[]', + 'model.@each.{name,lastRide}', + 'sortProp', + 'sortDir', + ) get sortedPeople() { - const people = this.model ? this.model.toArray() : []; + const people = Array.from(this.model || []); const sorted = people.slice().sort((a, b) => { let comparison; @@ -82,7 +91,7 @@ export default class DriversController extends Controller { this.set( 'editingPerson', BufferedProxy.create({ - content: this.store.createRecord('person'), + content: this.store.createRecord('person', { active: true }), }), ); } @@ -95,24 +104,24 @@ export default class DriversController extends Controller { } @action - savePerson(event) { + async savePerson(event) { event?.preventDefault(); const proxy = this.editingPerson; proxy.applyBufferedChanges(); - return proxy - .get('content') - .save() - .then(() => { - this.set('editingPerson', undefined); - this.set('errorMessage', undefined); - }) - .catch(() => { - this.set( - 'errorMessage', - 'There was an error saving this driver. Please try again.', - ); - }); + + try { + await proxy.get('content').save(); + await this.peopleService.load(); + + this.set('editingPerson', undefined); + this.set('errorMessage', undefined); + } catch { + this.set( + 'errorMessage', + 'There was an error saving this driver. Please try again.', + ); + } } @action diff --git a/app/controllers/reimbursements.js b/app/controllers/reimbursements.js index 42652d4d..1b47d965 100644 --- a/app/controllers/reimbursements.js +++ b/app/controllers/reimbursements.js @@ -10,9 +10,11 @@ import moment from 'moment-timezone'; @classic export default class ReimbursementsController extends Controller { - queryParams = { - showProcessed: 'processed', - }; + queryParams = [ + { + showProcessed: 'processed', + }, + ]; @alias('model') reimbursements; diff --git a/app/controllers/reports/new.js b/app/controllers/reports/new.js index dcbc1088..88ce4e4a 100644 --- a/app/controllers/reports/new.js +++ b/app/controllers/reports/new.js @@ -1,5 +1,5 @@ import classic from 'ember-classic-decorator'; -import { action } from '@ember/object'; +import { action, computed } from '@ember/object'; import { inject as service } from '@ember/service'; import Controller from '@ember/controller'; @@ -19,6 +19,12 @@ export default class NewController extends Controller { editingRide; errorMessage = undefined; + @computed('model', 'model.{[],@each.complete}') + get reportableRides() { + const rides = Array.from(this.model || []); + return rides.filter((ride) => !ride.complete); + } + _setNumberProperty(property, event) { const ride = this.editingRide; @@ -83,28 +89,27 @@ export default class NewController extends Controller { } @action - submitReport(event) { + async submitReport(event) { event?.preventDefault?.(); let editingRide = this.editingRide; if (editingRide) { - return editingRide.save().then( - () => { - this.set('errorMessage', undefined); - this.toasts.show('Your report was saved'); - - // Remove the ride from the store before reloading from the server - this.store.unloadRecord(this.editingRide); - - this.set('editingRide', undefined); - this.router.transitionTo('application'); - window.scrollTo(0, 0); - }, - () => { - this.set('errorMessage', 'There was an error saving your report!'); - }, - ); + try { + await editingRide.save(); + editingRide.set('complete', true); + + this.set('errorMessage', undefined); + this.toasts.show('Your report was saved'); + + await this.store.findAll('ride', { reload: true }); + + this.set('editingRide', undefined); + this.router.transitionTo('application'); + window.scrollTo(0, 0); + } catch { + this.set('errorMessage', 'There was an error saving your report!'); + } } else { this.set('errorMessage', 'Please choose a ride'); } diff --git a/app/controllers/rides.js b/app/controllers/rides.js index 3c7ca8db..fed097b1 100644 --- a/app/controllers/rides.js +++ b/app/controllers/rides.js @@ -48,23 +48,26 @@ export default class RidesController extends Controller { showCancelled = this.showCancelled; const search = this.search; - let rides = this.model.rejectBy('isCombined').rejectBy('isNew'); + const rides = Array.from(this.model || []); + let filtered = rides.filter((ride) => !ride.isCombined && !ride.isNew); if (!showCompleted) { - rides = rides.filterBy('complete', false); + filtered = filtered.filter((ride) => !ride.complete); } if (!showCancelled) { - rides = rides.filterBy('enabled'); + filtered = filtered.filter((ride) => ride.enabled); } if (search) { - rides = rides.filter((ride) => ride.matches(search)); + filtered = filtered.filter((ride) => ride.matches(search)); } - rides.setEach('isDivider', false); + filtered.forEach((ride) => { + ride.isDivider = false; + }); - let sorted = rides.sortBy('start'); + let sorted = filtered.slice().sort((a, b) => a.start - b.start); const sortDir = this.sortDir; const now = new Date(); @@ -76,13 +79,13 @@ export default class RidesController extends Controller { const firstAfterNow = sorted.find((ride) => ride.start > now); if (firstAfterNow) { - firstAfterNow.set('isDivider', true); + firstAfterNow.isDivider = true; } } else { const firstBeforeNow = sorted.find((ride) => ride.start < now); if (firstBeforeNow) { - firstBeforeNow.set('isDivider', true); + firstBeforeNow.isDivider = true; } } @@ -104,21 +107,21 @@ export default class RidesController extends Controller { } @action - submitRide(proxy) { + async submitRide(proxy) { let buffer = proxy.buffer; proxy.applyBufferedChanges(); - return proxy.content - .save() - .then(() => { - this.editingRide = undefined; - this.rideErrorMessage = undefined; - return this.overlapsService.fetch(); - }) - .catch(() => { - this.rideErrorMessage = 'There was an error saving this ride'; - proxy.setProperties(buffer); - }); + try { + await proxy.content.save(); + + this.editingRide = undefined; + this.rideErrorMessage = undefined; + + await this.overlapsService.fetch(); + } catch { + this.rideErrorMessage = 'There was an error saving this ride'; + proxy.setProperties(buffer); + } } @action diff --git a/app/index.html b/app/index.html index 154cb409..a43b08da 100644 --- a/app/index.html +++ b/app/index.html @@ -2,7 +2,7 @@ - + PrisonRideshareUi diff --git a/app/models/commitment.js b/app/models/commitment.js index 3b113799..e0adbfa3 100644 --- a/app/models/commitment.js +++ b/app/models/commitment.js @@ -2,6 +2,6 @@ import Model, { belongsTo } from '@ember-data/model'; export default Model.extend({ - slot: belongsTo({ async: false }), - person: belongsTo(), + slot: belongsTo('slot', { async: false, inverse: 'commitments' }), + person: belongsTo('person', { async: false, inverse: null }), }); diff --git a/app/models/ride.js b/app/models/ride.js index a3e024d6..777afb6d 100644 --- a/app/models/ride.js +++ b/app/models/ride.js @@ -3,6 +3,7 @@ import Model, { attr, belongsTo, hasMany } from '@ember-data/model'; import { mapBy, gt } from '@ember/object/computed'; import { computed } from '@ember/object'; import { inject as service } from '@ember/service'; +import { tracked } from '@glimmer/tracking'; import dollars from 'prison-rideshare-ui/utils/dollars'; import formatTimespan from 'prison-rideshare-ui/utils/format-timespan'; @@ -92,6 +93,8 @@ export default Model.extend({ donation: attr('boolean'), donatable: attr('boolean'), + isDivider: tracked(), + reimbursementFoodExpenses: mapBy('reimbursements', 'foodExpenses'), reimbursementFoodExpensesSum: computed( 'reimbursementFoodExpenses', diff --git a/app/models/slot.js b/app/models/slot.js index 584a04a5..d7208ea5 100644 --- a/app/models/slot.js +++ b/app/models/slot.js @@ -7,9 +7,9 @@ export default Model.extend({ end: attr('date'), count: attr('number'), - commitments: hasMany({ async: false }), + commitments: hasMany('commitment', { async: false, inverse: 'slot' }), - isNotFull: computed('commitments.length', 'count', function () { + isNotFull: computed('commitments.[]', 'count', function () { const count = this.count; const commitmentCount = this.get('commitments.length'); diff --git a/app/routes/admin-calendar.js b/app/routes/admin-calendar.js index 5d5f23b6..1c97414a 100644 --- a/app/routes/admin-calendar.js +++ b/app/routes/admin-calendar.js @@ -6,16 +6,17 @@ import AuthenticatedRoute from 'prison-rideshare-ui/mixins/authenticated-route'; export default class AdminCalendarRoute extends AuthenticatedRoute { @service store; + @service('people') peopleService; + + async model({ month }) { + await this.store.findAll('slot'); + const slots = this.store + .peekAll('slot') + .filter((slot) => moment(slot.get('start')).format('YYYY-MM') === month); - model({ month }) { return RSVP.hash({ - slots: this.store - .findAll('slot') - .then((slots) => - slots.filter( - (slot) => moment(slot.get('start')).format('YYYY-MM') === month, - ), - ), + slots, + people: this.peopleService.load(), month, }); } diff --git a/app/routes/calendar.js b/app/routes/calendar.js index f865627c..c164b4c0 100644 --- a/app/routes/calendar.js +++ b/app/routes/calendar.js @@ -1,6 +1,5 @@ import { inject as service } from '@ember/service'; import Route from '@ember/routing/route'; -import RSVP from 'rsvp'; import { isEmpty } from '@ember/utils'; import { isTesting } from '@ember/debug'; import fetch from 'fetch'; @@ -44,28 +43,30 @@ export default class CalendarRoute extends Route { throw errorJson; }); }) - .then(({ access_token }) => { + .then(async ({ access_token }) => { localStorage.setItem('person-token', access_token); - return this.store.queryRecord('person', { + const person = await this.store.queryRecord('person', { me: true, token: access_token, }); + + await this.store.findAll('slot'); + + return { + slots: this.store.peekAll('slot'), + person, + month, + }; }) .catch((error) => { - const detail = error?.errors?.firstObject?.detail; + const detail = + error?.errors?.[0]?.detail ?? error?.errors?.firstObject?.detail; if (detail) { throw new Error(detail); } else { throw new Error('We were unable to log you in with that token.'); } - }) - .then((person) => { - return RSVP.hash({ - slots: this.store.findAll('slot'), - person, - month, - }); }); } @@ -73,8 +74,8 @@ export default class CalendarRoute extends Route { pollTask(this, 'poll', POLL_TOKEN); } - poll(next) { - this.store.findAll('slot'); + async poll(next) { + await this.store.findAll('slot', { reload: true }); runTask(this, next, isTesting() ? 10 : 10000); } } diff --git a/app/routes/rides.js b/app/routes/rides.js index 66391a92..e5bed0c8 100644 --- a/app/routes/rides.js +++ b/app/routes/rides.js @@ -5,7 +5,7 @@ import AuthenticatedRoute from 'prison-rideshare-ui/mixins/authenticated-route'; export default class RidesRoute extends AuthenticatedRoute { @service store; - model() { + async model() { return this.store.findAll('ride'); } } diff --git a/app/serializers/application.js b/app/serializers/application.js index 41871047..274ff8e4 100644 --- a/app/serializers/application.js +++ b/app/serializers/application.js @@ -1,4 +1,29 @@ /* eslint-disable ember/no-classic-classes*/ import JSONAPISerializer from '@ember-data/serializer/json-api'; -export default JSONAPISerializer.extend(); +export default JSONAPISerializer.extend({ + extractErrors(store, typeClass, payload, id) { + let extracted = this._super(store, typeClass, payload, id); + + if (payload && Array.isArray(payload.errors)) { + if ( + !extracted || + typeof extracted !== 'object' || + Array.isArray(extracted) + ) { + extracted = {}; + } + + const baseErrors = payload.errors + .filter((error) => !error?.source?.pointer) + .map((error) => error?.detail || error?.title) + .filter(Boolean); + + if (baseErrors.length) { + extracted.base = (extracted.base || []).concat(baseErrors); + } + } + + return extracted; + }, +}); diff --git a/app/services/overlaps.js b/app/services/overlaps.js index a7b3cfbc..3c226dc3 100644 --- a/app/services/overlaps.js +++ b/app/services/overlaps.js @@ -104,6 +104,6 @@ export default class OverlapsService extends Service { } fetch() { - this.fetchOverlaps.perform(); + return this.fetchOverlaps.perform(); } } diff --git a/app/services/people.js b/app/services/people.js index 87257645..0e9e61a1 100644 --- a/app/services/people.js +++ b/app/services/people.js @@ -1,26 +1,49 @@ import classic from 'ember-classic-decorator'; +import { A } from '@ember/array'; import { computed } from '@ember/object'; -import { filterBy } from '@ember/object/computed'; import Service, { inject as service } from '@ember/service'; -import { PromiseArray } from '@ember-data/store/-private'; @classic export default class PeopleService extends Service { @service store; - @computed - get findAll() { - return this.store.findAll('person'); + people = A(); + loadPromise = null; + + init() { + super.init(...arguments); + this.set('people', this.store.peekAll('person')); + this.load(); + } + + load() { + if (this.loadPromise) { + return this.loadPromise; + } + + const promise = this.store + .findAll('person', { reload: true }) + .then(() => { + this.set('people', this.store.peekAll('person')); + this.notifyPropertyChange('people'); + }) + .finally(() => { + this.set('loadPromise', null); + }); + + this.set('loadPromise', promise); + return promise; } - @computed('findAll.@each.name') + @computed('people.{[],people.@each.name}') get all() { - return PromiseArray.create({ - promise: this.findAll.then((people) => people.sortBy('name')), - }); + const people = this.people || A(); + return [...people].sort((a, b) => a.name.localeCompare(b.name)); } - @filterBy('all', 'active') - active; + @computed('all.{[],all.@each.active}') + get active() { + return this.all.filterBy('active'); + } } diff --git a/app/templates/application.gjs b/app/templates/application.gjs index 7d1cdd81..3a2d0a32 100644 --- a/app/templates/application.gjs +++ b/app/templates/application.gjs @@ -1,6 +1,5 @@ import RouteTemplate from 'ember-route-template'; import HeadLayout from 'ember-cli-head/components/head-layout'; -import EmberLoadRemover from 'ember-load/components/ember-load-remover'; import { action } from '@ember/object'; import { concat, fn } from '@ember/helper'; import { on } from '@ember/modifier'; @@ -59,7 +58,6 @@ class ApplicationComponent extends Component { , ); - assert.equal(find('span').innerHTML.trim(), 'hello'); + assert.strictEqual(find('span').innerHTML.trim(), 'hello'); }); test('it extracts a phone number', async function (assert) { @@ -23,7 +23,7 @@ module('Integration | Component | linked contact', function (hooks) { , ); - assert.equal( + assert.strictEqual( find('[data-test-container]').innerHTML.trim(), `hello 212-986-8227 what`, ); @@ -36,7 +36,7 @@ module('Integration | Component | linked contact', function (hooks) { , ); - assert.equal( + assert.strictEqual( find('[data-test-container]').innerHTML.trim(), `hello 2129868227 what`, ); @@ -49,7 +49,7 @@ module('Integration | Component | linked contact', function (hooks) { , ); - assert.equal( + assert.strictEqual( find('[data-test-container]').innerHTML.trim(), `hello 212 986 8227 what`, ); @@ -62,7 +62,7 @@ module('Integration | Component | linked contact', function (hooks) { , ); - assert.equal( + assert.strictEqual( find('[data-test-container]').innerHTML.trim(), `hello (212) 986 8227 what`, ); @@ -74,6 +74,6 @@ module('Integration | Component | linked contact', function (hooks) { , ); - assert.equal(find('[data-test-container]').innerText.trim(), ''); + assert.strictEqual(find('[data-test-container]').innerText.trim(), ''); }); }); diff --git a/tests/unit/utils/anonymise-address-test.js b/tests/unit/utils/anonymise-address-test.js index 98883d4c..9b9cfac3 100644 --- a/tests/unit/utils/anonymise-address-test.js +++ b/tests/unit/utils/anonymise-address-test.js @@ -3,34 +3,52 @@ import { module, test } from 'qunit'; module('Unit | Utility | anonymise address', function () { test('it masks the street number', function (assert) { - assert.equal(anonymiseAddress('123 Main St'), '100 block Main St'); + assert.strictEqual(anonymiseAddress('123 Main St'), '100 block Main St'); }); test('it strips leading apartment numbers, even with a #', function (assert) { - assert.equal(anonymiseAddress('600-123 Main St'), '100 block Main St'); - assert.equal(anonymiseAddress('#600-123 Main St'), '100 block Main St'); + assert.strictEqual( + anonymiseAddress('600-123 Main St'), + '100 block Main St', + ); + assert.strictEqual( + anonymiseAddress('#600-123 Main St'), + '100 block Main St', + ); }); test('it strips trailing bracketed strings', function (assert) { - assert.equal( + assert.strictEqual( anonymiseAddress('440 Jorts street (building X unit 666)'), '400 block Jorts street', ); - assert.equal( + assert.strictEqual( anonymiseAddress('440 Jorts street (building X unit 666) '), '400 block Jorts street', ); }); test('it strips trailing #-led strings', function (assert) { - assert.equal(anonymiseAddress('421 osborne #1919'), '400 block osborne'); + assert.strictEqual( + anonymiseAddress('421 osborne #1919'), + '400 block osborne', + ); }); test('it strips trailing unit/suite/building identifiers', function (assert) { - assert.equal(anonymiseAddress('421 osborne apt B'), '400 block osborne'); - assert.equal(anonymiseAddress('421 osborne uNit 33'), '400 block osborne'); - assert.equal(anonymiseAddress('421 osborne suite X'), '400 block osborne'); - assert.equal( + assert.strictEqual( + anonymiseAddress('421 osborne apt B'), + '400 block osborne', + ); + assert.strictEqual( + anonymiseAddress('421 osborne uNit 33'), + '400 block osborne', + ); + assert.strictEqual( + anonymiseAddress('421 osborne suite X'), + '400 block osborne', + ); + assert.strictEqual( anonymiseAddress('421 osborne building A suite X'), '400 block osborne', ); diff --git a/tests/unit/utils/deduplicate-visitor-suggestions-test.js b/tests/unit/utils/deduplicate-visitor-suggestions-test.js index 0139f680..98ebc4e4 100644 --- a/tests/unit/utils/deduplicate-visitor-suggestions-test.js +++ b/tests/unit/utils/deduplicate-visitor-suggestions-test.js @@ -34,6 +34,6 @@ module('Unit | Utility | deduplicate visitor suggestions', function () { }; }); const result = deduplicateVisitorSuggestions(rides); - assert.equal(result.length, 3); + assert.strictEqual(result.length, 3); }); }); diff --git a/tests/unit/utils/dollars-test.js b/tests/unit/utils/dollars-test.js index 262a5f3a..435bda80 100644 --- a/tests/unit/utils/dollars-test.js +++ b/tests/unit/utils/dollars-test.js @@ -12,12 +12,18 @@ class ClassWithDollars extends EmberObject { module('Unit - dollars', function () { test('converts from cents to dollars', function (assert) { - assert.equal(ClassWithDollars.create({ cents: 50 }).get('dollars'), 0.5); + assert.strictEqual( + ClassWithDollars.create({ cents: 50 }).get('dollars'), + 0.5, + ); }); test('converts from dollars to cents', function (assert) { - assert.equal(ClassWithDollars.create({ dollars: 5.25 }).get('cents'), 525); - assert.equal( + assert.strictEqual( + ClassWithDollars.create({ dollars: 5.25 }).get('cents'), + 525, + ); + assert.strictEqual( ClassWithDollars.create({ dollars: 0.55 }).get('cents'), 55, 'expected floating point rounding', diff --git a/tests/unit/utils/format-timespan-test.js b/tests/unit/utils/format-timespan-test.js index e1f08df6..1a2060b0 100644 --- a/tests/unit/utils/format-timespan-test.js +++ b/tests/unit/utils/format-timespan-test.js @@ -15,7 +15,7 @@ module('Unit | Utility | format timespan', function (hooks) { new Date(2010, 5, 26, 15, 0, 0), ); - assert.equal(noMinutesSameMeridiem, 'Sat Jun 26 2010 1p — 3'); + assert.strictEqual(noMinutesSameMeridiem, 'Sat Jun 26 2010 1p — 3'); const minutesSameMeridiem = formatTimespan( { moment }, @@ -23,7 +23,7 @@ module('Unit | Utility | format timespan', function (hooks) { new Date(2010, 5, 26, 16, 48, 0), ); - assert.equal(minutesSameMeridiem, 'Sat Jun 26 2010 3:30p — 4:48'); + assert.strictEqual(minutesSameMeridiem, 'Sat Jun 26 2010 3:30p — 4:48'); const sameDayDifferentMeridiem = formatTimespan( { moment }, @@ -31,7 +31,7 @@ module('Unit | Utility | format timespan', function (hooks) { new Date(2010, 5, 27, 19, 0, 0), ); - assert.equal(sameDayDifferentMeridiem, 'Sun Jun 27 2010 10:22a — 7p'); + assert.strictEqual(sameDayDifferentMeridiem, 'Sun Jun 27 2010 10:22a — 7p'); const differentDay = formatTimespan( { moment }, @@ -39,6 +39,6 @@ module('Unit | Utility | format timespan', function (hooks) { new Date(2010, 5, 29, 19, 0, 0), ); - assert.equal(differentDay, 'Sun Jun 27 2010 10:22a — Tue 7p'); + assert.strictEqual(differentDay, 'Sun Jun 27 2010 10:22a — Tue 7p'); }); }); diff --git a/tests/unit/utils/parse-timespan-test.js b/tests/unit/utils/parse-timespan-test.js index 7bcfc17e..fdfe9e42 100644 --- a/tests/unit/utils/parse-timespan-test.js +++ b/tests/unit/utils/parse-timespan-test.js @@ -24,8 +24,14 @@ module('Unit | Utility | parse timespan', function (hooks) { ) { const parsed = parseTimespan(timespanString); - assert.equal(moment(parsed.start.date()).format(formatString), startString); - assert.equal(moment(parsed.end.date()).format(formatString), endString); + assert.strictEqual( + moment(parsed.start.date()).format(formatString), + startString, + ); + assert.strictEqual( + moment(parsed.end.date()).format(formatString), + endString, + ); }; test('it parses a well-specified timespan', function (assert) { @@ -67,7 +73,7 @@ module('Unit | Utility | parse timespan', function (hooks) { test('it assumes PM if unspecified even for start alone', function (assert) { const parsed = parseTimespan('september 27 2017 from 630'); - assert.equal( + assert.strictEqual( moment(parsed.start.date()).format(formatString), '2017-09-27 18:30', ); diff --git a/tests/unit/utils/reimbursement-collection-test.js b/tests/unit/utils/reimbursement-collection-test.js index b05c8656..bc3cf7bc 100644 --- a/tests/unit/utils/reimbursement-collection-test.js +++ b/tests/unit/utils/reimbursement-collection-test.js @@ -47,7 +47,7 @@ module('Unit | Utility | reimbursement collection', function () { person, reimbursements: [carReimbursement], }); - assert.equal( + assert.strictEqual( result.get('clipboardText'), `${dateString}\tOctober mileage\tChelsea\t-$33\t\t\t`, ); @@ -59,7 +59,7 @@ module('Unit | Utility | reimbursement collection', function () { reimbursements: [carReimbursement, otherCarReimbursement], donations: true, }); - assert.equal( + assert.strictEqual( result.get('clipboardText'), `${dateString}\tOctober mileage\tChelsea\t-$55\t$55\t\t(donated)`, ); @@ -70,7 +70,7 @@ module('Unit | Utility | reimbursement collection', function () { person, reimbursements: [foodReimbursement, carReimbursement], }); - assert.equal( + assert.strictEqual( result.get('clipboardText'), `${dateString}\tOctober mileage + meal\tChelsea\t-$77\t\t\t`, ); @@ -81,7 +81,7 @@ module('Unit | Utility | reimbursement collection', function () { person, reimbursements: [foodReimbursement, otherFoodReimbursement], }); - assert.equal( + assert.strictEqual( result.get('clipboardText'), `${dateString}\tOctober meal × 2\tChelsea\t-$99\t\t\t`, );