From 31e1ee9ac7a6624cd392d2c369857e29143b0ca2 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Thu, 3 Sep 2026 17:02:07 +0800 Subject: [PATCH] feat: add trailer data models and serializers --- addon/models/asset-connection.js | 25 ++++++ addon/models/asset.js | 16 +++- addon/models/attachable-trailer.js | 11 +++ addon/models/attachable.js | 2 +- addon/models/equipment.js | 1 + addon/models/maintenance-subject-trailer.js | 15 ++++ addon/models/maintenance-subject.js | 4 +- addon/models/trailer.js | 90 +++++++++++++++++++ addon/models/vehicle.js | 3 + addon/serializers/asset-connection.js | 11 +++ addon/serializers/device.js | 2 +- addon/serializers/equipment.js | 65 +++++++++++++- addon/serializers/trailer.js | 18 ++++ app/models/asset-connection.js | 1 + app/models/attachable-trailer.js | 1 + app/models/maintenance-subject-trailer.js | 1 + app/models/trailer.js | 1 + app/serializers/asset-connection.js | 1 + app/serializers/trailer.js | 1 + package.json | 1 + pnpm-lock.yaml | 3 + tests/unit/models/asset-connection-test.js | 15 ++++ tests/unit/models/trailer-test.js | 23 +++++ .../unit/serializers/asset-connection-test.js | 14 +++ tests/unit/serializers/device-test.js | 25 ++++++ tests/unit/serializers/equipment-test.js | 25 ++++++ tests/unit/serializers/trailer-test.js | 17 ++++ 27 files changed, 387 insertions(+), 5 deletions(-) create mode 100644 addon/models/asset-connection.js create mode 100644 addon/models/attachable-trailer.js create mode 100644 addon/models/maintenance-subject-trailer.js create mode 100644 addon/models/trailer.js create mode 100644 addon/serializers/asset-connection.js create mode 100644 addon/serializers/trailer.js create mode 100644 app/models/asset-connection.js create mode 100644 app/models/attachable-trailer.js create mode 100644 app/models/maintenance-subject-trailer.js create mode 100644 app/models/trailer.js create mode 100644 app/serializers/asset-connection.js create mode 100644 app/serializers/trailer.js create mode 100644 tests/unit/models/asset-connection-test.js create mode 100644 tests/unit/models/trailer-test.js create mode 100644 tests/unit/serializers/asset-connection-test.js create mode 100644 tests/unit/serializers/trailer-test.js diff --git a/addon/models/asset-connection.js b/addon/models/asset-connection.js new file mode 100644 index 0000000..9c0ec65 --- /dev/null +++ b/addon/models/asset-connection.js @@ -0,0 +1,25 @@ +import Model, { attr, belongsTo } from '@ember-data/model'; + +export default class AssetConnectionModel extends Model { + @attr('string') uuid; + @attr('string') public_id; + @attr('string') company_uuid; + @attr('string') connector_type; + @attr('string') connector_uuid; + @attr('string') connected_type; + @attr('string') connected_uuid; + @attr('string', { defaultValue: 'towing' }) relationship_type; + @attr('number', { defaultValue: 1 }) position; + @attr('string') source; + @attr('string') confidence; + @attr('string') notes; + @attr('raw') meta; + @attr('boolean') active; + @attr('date') connected_at; + @attr('date') disconnected_at; + @attr('date') created_at; + @attr('date') updated_at; + + @belongsTo('vehicle', { async: false }) vehicle; + @belongsTo('trailer', { async: false }) trailer; +} diff --git a/addon/models/asset.js b/addon/models/asset.js index 8387795..dc7ee61 100644 --- a/addon/models/asset.js +++ b/addon/models/asset.js @@ -55,10 +55,22 @@ export default class AssetModel extends Model { @attr('string') odometer_unit; @attr('string') transmission; @attr('string') fuel_volume_unit; - @attr('string') fuel_Type; + @attr('string') fuel_type; @attr('string') ownership_type; @attr('string') engine_hours; @attr('string') gvw; + @attr('number') width; + @attr('number') length; + @attr('number') height; + @attr('number') tare_weight; + @attr('number') gvwr; + @attr('number') payload_capacity; + @attr('number') cargo_volume; + @attr('string') currency; + @attr('string') acquisition_cost; + @attr('string') current_value; + @attr('string') insurance_value; + @attr('string') depreciation_rate; @attr('raw') capacity; @attr('raw') specs; @attr('raw') attributes; @@ -77,6 +89,8 @@ export default class AssetModel extends Model { /** @dates */ @attr('date') deleted_at; + @attr('date') purchased_at; + @attr('date') lease_expires_at; @attr('date') created_at; @attr('date') updated_at; diff --git a/addon/models/attachable-trailer.js b/addon/models/attachable-trailer.js new file mode 100644 index 0000000..68bc3e9 --- /dev/null +++ b/addon/models/attachable-trailer.js @@ -0,0 +1,11 @@ +import AttachableAssetModel from './attachable-asset'; +import { attr } from '@ember-data/model'; + +/** Concrete polymorphic model for a Trailer attached to a device. */ +export default class AttachableTrailerModel extends AttachableAssetModel { + @attr('string') body_type; + @attr('string') coupling_type; + @attr('number') axle_count; + @attr('boolean') refrigerated; + @attr('string') current_vehicle_name; +} diff --git a/addon/models/attachable.js b/addon/models/attachable.js index 6e7b2c2..d366768 100644 --- a/addon/models/attachable.js +++ b/addon/models/attachable.js @@ -4,7 +4,7 @@ import { format as formatDate, isValid as isValidDate, formatDistanceToNow } fro /** * Abstract base model for resources a device can be attached to. - * Concrete types: attachable-vehicle, attachable-asset. + * Concrete types: attachable-vehicle, attachable-asset, attachable-trailer. */ export default class AttachableModel extends Model { /** @ids */ diff --git a/addon/models/equipment.js b/addon/models/equipment.js index a897ade..c2b82ad 100644 --- a/addon/models/equipment.js +++ b/addon/models/equipment.js @@ -15,6 +15,7 @@ export default class EquipmentModel extends Model { /** @relationships */ @belongsTo('warranty', { async: false }) warranty; @belongsTo('file', { async: false }) photo; + @belongsTo('attachable', { polymorphic: true, async: false }) equipable; @hasMany('maintenance', { async: false }) maintenances; @hasMany('custom-field-value', { async: false }) custom_field_values; diff --git a/addon/models/maintenance-subject-trailer.js b/addon/models/maintenance-subject-trailer.js new file mode 100644 index 0000000..f24a4a8 --- /dev/null +++ b/addon/models/maintenance-subject-trailer.js @@ -0,0 +1,15 @@ +import MaintenanceSubjectModel from './maintenance-subject'; +import { attr } from '@ember-data/model'; + +/** Concrete polymorphic model for Trailer maintenance targets. */ +export default class MaintenanceSubjectTrailerModel extends MaintenanceSubjectModel { + @attr('string') code; + @attr('string') vin; + @attr('string') plate_number; + @attr('string') make; + @attr('string') model; + @attr('string') year; + @attr('string') body_type; + @attr('number') axle_count; + @attr('string') current_vehicle_name; +} diff --git a/addon/models/maintenance-subject.js b/addon/models/maintenance-subject.js index efaff85..7b584d2 100644 --- a/addon/models/maintenance-subject.js +++ b/addon/models/maintenance-subject.js @@ -4,10 +4,12 @@ import { format as formatDate, isValid as isValidDate, formatDistanceToNow } fro /** * Abstract base model for polymorphic maintenance subjects. - * Concrete types: maintenance-subject-vehicle, maintenance-subject-equipment + * Concrete types: maintenance-subject-vehicle, maintenance-subject-trailer, + * maintenance-subject-equipment * * The backend stores the type as a PolymorphicType cast string, e.g.: * 'fleet-ops:vehicle' -> maintenance-subject-vehicle + * 'fleet-ops:trailer' -> maintenance-subject-trailer * 'fleet-ops:equipment' -> maintenance-subject-equipment */ export default class MaintenanceSubjectModel extends Model { diff --git a/addon/models/trailer.js b/addon/models/trailer.js new file mode 100644 index 0000000..ea04c75 --- /dev/null +++ b/addon/models/trailer.js @@ -0,0 +1,90 @@ +import AssetModel from './asset'; +import { attr, belongsTo, hasMany } from '@ember-data/model'; +import { computed, get } from '@ember/object'; +import { not } from '@ember/object/computed'; +import isValidCoordinates from '@fleetbase/ember-core/utils/is-valid-coordinates'; + +/** + * A first-class towed fleet asset. + * + * Trailer records share the common Asset contract while exposing the + * operational, connection, capacity, and telemetry fields used by Fleet-Ops. + */ +export default class TrailerModel extends AssetModel { + /** @relationships */ + @belongsTo('vehicle', { async: false, inverse: null }) current_vehicle; + @belongsTo('asset-connection', { async: false, inverse: null }) current_connection; + @hasMany('asset-connection', { async: false, inverse: null }) connections; + @hasMany('maintenance-schedule', { async: false, inverse: null }) maintenance_schedules; + @hasMany('work-order', { async: false, inverse: null }) work_orders; + @hasMany('position', { async: false, inverse: null }) positions; + + /** @classification */ + @attr('string', { defaultValue: 'trailer' }) asset_class; + @attr('string') body_type; + @attr('string') coupling_type; + @attr('string') brake_type; + + /** @capacity and dimensions */ + @attr('number') length; + @attr('number') width; + @attr('number') height; + @attr('number') tare_weight; + @attr('number') gvwr; + @attr('number') payload_capacity; + @attr('number') cargo_volume; + @attr('number') axle_count; + @attr('number') tire_count; + @attr('number') door_count; + + /** @specialized trailer capabilities */ + @attr('boolean') abs_equipped; + @attr('boolean') ebs_equipped; + @attr('boolean') refrigerated; + @attr('number') temperature_min; + @attr('number') temperature_max; + @attr('number') reefer_engine_hours; + + /** @current operational projections */ + @attr('boolean') online; + @attr('string') connectivity_status; + @attr('string') movement_status; + @attr('raw') telematics; + @attr('raw') resolved_location; + @attr('string') current_vehicle_name; + @attr('string') current_vehicle_id; + @attr('date') attached_at; + @attr('number') devices_count; + @attr('number') equipment_count; + @attr('date') last_online_at; + + @computed('name', 'display_name', 'code', 'plate_number', 'vin', 'serial_number', 'yearMakeModel') get searchString() { + return [this.name, this.display_name, this.code, this.plate_number, this.vin, this.serial_number, this.yearMakeModel].filter(Boolean).join(' '); + } + + @computed('location') get longitude() { + return get(this.location, 'coordinates.0'); + } + + @computed('location') get latitude() { + return get(this.location, 'coordinates.1'); + } + + @computed('latitude', 'longitude') get coordinates() { + return [get(this, 'latitude'), get(this, 'longitude')]; + } + + @computed('latitude', 'longitude') get latlng() { + return { lat: get(this, 'latitude'), lng: get(this, 'longitude') }; + } + + @computed('coordinates', 'latitude', 'longitude') get hasValidCoordinates() { + if (this.longitude === 0 || this.latitude === 0) { + return false; + } + + return isValidCoordinates(this.coordinates); + } + + @not('hasValidCoordinates') hasInvalidCoordinates; +} diff --git a/addon/models/vehicle.js b/addon/models/vehicle.js index 7874f2c..8ce1772 100644 --- a/addon/models/vehicle.js +++ b/addon/models/vehicle.js @@ -22,6 +22,9 @@ export default class VehicleModel extends Model { @belongsTo('driver', { async: false }) driver; @belongsTo('vendor', { async: false }) vendor; @hasMany('device', { async: false }) devices; + @hasMany('trailer', { async: false }) trailers; + @hasMany('asset-connection', { async: false }) trailer_connections; + @hasMany('equipment', { async: false }) equipments; @hasMany('custom-field-value', { async: false }) custom_field_values; /** @attributes */ diff --git a/addon/serializers/asset-connection.js b/addon/serializers/asset-connection.js new file mode 100644 index 0000000..095c72c --- /dev/null +++ b/addon/serializers/asset-connection.js @@ -0,0 +1,11 @@ +import ApplicationSerializer from '@fleetbase/ember-core/serializers/application'; +import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest'; + +export default class AssetConnectionSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) { + get attrs() { + return { + vehicle: { embedded: 'always' }, + trailer: { embedded: 'always' }, + }; + } +} diff --git a/addon/serializers/device.js b/addon/serializers/device.js index 3672502..cffdde6 100644 --- a/addon/serializers/device.js +++ b/addon/serializers/device.js @@ -81,7 +81,7 @@ export default class DeviceSerializer extends ApplicationSerializer.extend(Embed .replace(/^attachable-/, '') .toLowerCase(); - if (!['vehicle', 'asset'].includes(type)) { + if (!['vehicle', 'asset', 'trailer'].includes(type)) { return undefined; } diff --git a/addon/serializers/equipment.js b/addon/serializers/equipment.js index 8766fa0..f454f2c 100644 --- a/addon/serializers/equipment.js +++ b/addon/serializers/equipment.js @@ -1,4 +1,67 @@ import ApplicationSerializer from '@fleetbase/ember-core/serializers/application'; import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest'; +import { isBlank } from '@ember/utils'; -export default class EquipmentSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) {} +export default class EquipmentSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) { + get attrs() { + return { + warranty: { embedded: 'always' }, + photo: { embedded: 'always' }, + equipable: { embedded: 'always' }, + custom_field_values: { embedded: 'always' }, + }; + } + + normalize(model, hash, prop) { + const equipableDomainType = hash?.equipable?.type; + + if (hash?.equipable) { + hash.equipable.type = this.equipableModelNameFromType(hash.equipable_type); + } + + const normalized = super.normalize(model, hash, prop); + + if (equipableDomainType && !this.equipableModelNameFromType(equipableDomainType)) { + const equipable = normalized?.data?.relationships?.equipable?.data; + const included = normalized?.included?.find((resource) => resource.type === equipable?.type && resource.id === equipable?.id); + + if (included) { + included.attributes = included.attributes ?? {}; + included.attributes.type = equipableDomainType; + } + } + + return normalized; + } + + serializePolymorphicType(snapshot, json, relationship) { + let key = relationship.key; + + if (key !== 'equipable') { + return typeof super.serializePolymorphicType === 'function' ? super.serializePolymorphicType(...arguments) : undefined; + } + + const belongsTo = snapshot.belongsTo(key); + + if (!isBlank(snapshot.attr(`${key}_type`))) { + return; + } + + key = this.keyForAttribute ? this.keyForAttribute(key, 'serialize') : key; + json[`${key}_type`] = belongsTo ? `fleet-ops:${belongsTo.modelName.replace(/^attachable-/, '')}` : null; + } + + equipableModelNameFromType(type) { + if (!type || typeof type !== 'string') { + return undefined; + } + + const normalized = type + .split('\\') + .pop() + .replace(/^fleet-ops:/, '') + .replace(/^attachable-/, '') + .toLowerCase(); + return ['vehicle', 'trailer', 'driver', 'asset'].includes(normalized) ? `attachable-${normalized}` : undefined; + } +} diff --git a/addon/serializers/trailer.js b/addon/serializers/trailer.js new file mode 100644 index 0000000..e8df37b --- /dev/null +++ b/addon/serializers/trailer.js @@ -0,0 +1,18 @@ +import ApplicationSerializer from '@fleetbase/ember-core/serializers/application'; +import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest'; + +export default class TrailerSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) { + get attrs() { + return { + vendor: { embedded: 'always' }, + warranty: { embedded: 'always' }, + photo: { embedded: 'always' }, + current_vehicle: { embedded: 'always', serialize: false }, + current_connection: { embedded: 'always', serialize: false }, + connections: { embedded: 'always', serialize: false }, + devices: { embedded: 'always', serialize: false }, + equipments: { embedded: 'always', serialize: false }, + custom_field_values: { embedded: 'always' }, + }; + } +} diff --git a/app/models/asset-connection.js b/app/models/asset-connection.js new file mode 100644 index 0000000..78513f8 --- /dev/null +++ b/app/models/asset-connection.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/fleetops-data/models/asset-connection'; diff --git a/app/models/attachable-trailer.js b/app/models/attachable-trailer.js new file mode 100644 index 0000000..e1ec252 --- /dev/null +++ b/app/models/attachable-trailer.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/fleetops-data/models/attachable-trailer'; diff --git a/app/models/maintenance-subject-trailer.js b/app/models/maintenance-subject-trailer.js new file mode 100644 index 0000000..b1f3d42 --- /dev/null +++ b/app/models/maintenance-subject-trailer.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/fleetops-data/models/maintenance-subject-trailer'; diff --git a/app/models/trailer.js b/app/models/trailer.js new file mode 100644 index 0000000..38af3f7 --- /dev/null +++ b/app/models/trailer.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/fleetops-data/models/trailer'; diff --git a/app/serializers/asset-connection.js b/app/serializers/asset-connection.js new file mode 100644 index 0000000..10a5c77 --- /dev/null +++ b/app/serializers/asset-connection.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/fleetops-data/serializers/asset-connection'; diff --git a/app/serializers/trailer.js b/app/serializers/trailer.js new file mode 100644 index 0000000..eaccf02 --- /dev/null +++ b/app/serializers/trailer.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/fleetops-data/serializers/trailer'; diff --git a/package.json b/package.json index 4e2e79b..704b69a 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@babel/eslint-parser": "^7.22.15", "@babel/plugin-proposal-decorators": "^7.23.2", "@ember/optional-features": "^2.0.0", + "@ember/string": "^3.1.1", "@ember/test-helpers": "^3.2.0", "@embroider/test-setup": "^3.0.2", "@glimmer/component": "^1.1.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 810f131..48d7546 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,6 +33,9 @@ importers: '@ember/optional-features': specifier: ^2.0.0 version: 2.3.0 + '@ember/string': + specifier: ^3.1.1 + version: 3.1.1 '@ember/test-helpers': specifier: ^3.2.0 version: 3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.106.2(postcss@8.5.14)))(webpack@5.106.2(postcss@8.5.14)) diff --git a/tests/unit/models/asset-connection-test.js b/tests/unit/models/asset-connection-test.js new file mode 100644 index 0000000..1a2ff0f --- /dev/null +++ b/tests/unit/models/asset-connection-test.js @@ -0,0 +1,15 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'dummy/tests/helpers'; + +module('Unit | Model | asset-connection', function (hooks) { + setupTest(hooks); + + test('it represents an effective-dated towing relationship', function (assert) { + const store = this.owner.lookup('service:store'); + const connection = store.createRecord('asset-connection', { relationship_type: 'towing', active: true, position: 1 }); + + assert.strictEqual(connection.relationship_type, 'towing'); + assert.true(connection.active); + assert.strictEqual(connection.position, 1); + }); +}); diff --git a/tests/unit/models/trailer-test.js b/tests/unit/models/trailer-test.js new file mode 100644 index 0000000..1e01ec7 --- /dev/null +++ b/tests/unit/models/trailer-test.js @@ -0,0 +1,23 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'dummy/tests/helpers'; + +module('Unit | Model | trailer', function (hooks) { + setupTest(hooks); + + test('it exposes first-class identity, capacity, connection, and telemetry state', function (assert) { + const store = this.owner.lookup('service:store'); + const trailer = store.createRecord('trailer', { + name: 'Reefer 12', + year: '2026', + make: 'Utility', + model: '3000R', + location: { type: 'Point', coordinates: [106.9, 47.9] }, + payload_capacity: 20000, + }); + + assert.strictEqual(trailer.asset_class, 'trailer'); + assert.strictEqual(trailer.yearMakeModel, '2026 Utility 3000R'); + assert.strictEqual(trailer.payload_capacity, 20000); + assert.deepEqual(trailer.coordinates, [47.9, 106.9]); + }); +}); diff --git a/tests/unit/serializers/asset-connection-test.js b/tests/unit/serializers/asset-connection-test.js new file mode 100644 index 0000000..ca4064d --- /dev/null +++ b/tests/unit/serializers/asset-connection-test.js @@ -0,0 +1,14 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'dummy/tests/helpers'; + +module('Unit | Serializer | asset-connection', function (hooks) { + setupTest(hooks); + + test('it serializes connection metadata', function (assert) { + const store = this.owner.lookup('service:store'); + const serialized = store.createRecord('asset-connection', { relationship_type: 'towing', source: 'manual' }).serialize(); + + assert.strictEqual(serialized.relationship_type, 'towing'); + assert.strictEqual(serialized.source, 'manual'); + }); +}); diff --git a/tests/unit/serializers/device-test.js b/tests/unit/serializers/device-test.js index 5e0ead8..7c41e71 100644 --- a/tests/unit/serializers/device-test.js +++ b/tests/unit/serializers/device-test.js @@ -128,4 +128,29 @@ module('Unit | Serializer | device', function (hooks) { assert.strictEqual(serialized.attachable_uuid, 'vehicle-1'); assert.strictEqual(serialized.attachable_type, 'fleet-ops:vehicle'); }); + + test('it normalizes and serializes trailer attachments', function (assert) { + const store = this.owner.lookup('service:store'); + const serializer = store.serializerFor('device'); + const normalized = serializer.normalize(store.modelFor('device'), { + uuid: 'device-2', + attachable_uuid: 'trailer-1', + attachable_type: 'fleet-ops:trailer', + attachable: { uuid: 'trailer-1', public_id: 'trailer_1', name: 'Reefer 1' }, + }); + + assert.strictEqual(normalized.data.relationships.attachable.data.type, 'attachable-trailer'); + + const json = {}; + serializer.serializePolymorphicType( + { + attr: () => undefined, + belongsTo: () => ({ modelName: 'attachable-trailer' }), + }, + json, + { key: 'attachable' } + ); + + assert.strictEqual(json.attachable_type, 'fleet-ops:trailer'); + }); }); diff --git a/tests/unit/serializers/equipment-test.js b/tests/unit/serializers/equipment-test.js index 9ae28ec..109536c 100644 --- a/tests/unit/serializers/equipment-test.js +++ b/tests/unit/serializers/equipment-test.js @@ -21,4 +21,29 @@ module('Unit | Serializer | equipment', function (hooks) { assert.ok(serializedRecord); }); + + test('it supports polymorphic vehicle and trailer attachments', function (assert) { + const store = this.owner.lookup('service:store'); + const serializer = store.serializerFor('equipment'); + const normalized = serializer.normalize(store.modelFor('equipment'), { + uuid: 'equipment-1', + equipable_uuid: 'trailer-1', + equipable_type: 'Fleetbase\\FleetOps\\Models\\Trailer', + equipable: { uuid: 'trailer-1', public_id: 'trailer_1', name: 'Flatbed 1' }, + }); + + assert.strictEqual(normalized.data.relationships.equipable.data.type, 'attachable-trailer'); + + const json = {}; + serializer.serializePolymorphicType( + { + attr: () => undefined, + belongsTo: () => ({ modelName: 'attachable-vehicle' }), + }, + json, + { key: 'equipable' } + ); + + assert.strictEqual(json.equipable_type, 'fleet-ops:vehicle'); + }); }); diff --git a/tests/unit/serializers/trailer-test.js b/tests/unit/serializers/trailer-test.js new file mode 100644 index 0000000..41680de --- /dev/null +++ b/tests/unit/serializers/trailer-test.js @@ -0,0 +1,17 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'dummy/tests/helpers'; + +module('Unit | Serializer | trailer', function (hooks) { + setupTest(hooks); + + test('it embeds Trailer relationships without writing read-only projections', function (assert) { + const store = this.owner.lookup('service:store'); + const serializer = store.serializerFor('trailer'); + + assert.ok(serializer); + assert.strictEqual(serializer.attrs.vendor.embedded, 'always'); + assert.strictEqual(serializer.attrs.current_vehicle.serialize, false); + assert.strictEqual(serializer.attrs.connections.serialize, false); + assert.strictEqual(serializer.attrs.devices.serialize, false); + }); +});