fashion-model
Version:
JavaScript library for defining types and their properties with support for wrapping/unwrapping and serialization/deserialization.
194 lines (155 loc) • 3.97 kB
JavaScript
const test = require('ava');
const Model = require('../Model');
const Enum = require('../Enum');
const ObservableModel = require('../ObservableModel');
test('should support type coercion', function (t) {
const NumericId = Model.extend({
wrap: false,
coerce: function (value) {
if (value != null && value.constructor !== Number) {
value = Number(value.toString());
}
return value;
}
});
const Product = Model.extend({
properties: {
id: NumericId
}
});
const product = new Product({
id: '123'
});
t.is(product.getId(), 123);
});
test('should allow allow type coercion when setting null value for enum', function (t) {
const Visibility = Enum.create({
values: ['private', 'public'],
coerce: function (value, options) {
if (value == null) {
// default to private visibility
return this.private;
}
// Do nothing if we want to rely on default Enum coercion
return value;
}
});
const File = Model.extend({
properties: {
visibility: Visibility
}
});
const file = new File();
file.setVisibility(null);
t.is(file.getVisibility(), Visibility.private);
});
test('should handle converting model from one type to another', function (t) {
const Blah = Model.extend({
properties: {
abc: String
}
});
const IncomingMessage = Model.extend({
properties: {
id: String,
incomingData: Blah
}
});
const OutgoingMessage = Model.extend({
properties: {
id: String,
outgoingData: Blah
}
});
const incomingMessage = new IncomingMessage({
id: 'abc',
incomingData: {
abc: 'testing'
}
});
const outgoingMessage = OutgoingMessage.wrap(incomingMessage);
t.is(incomingMessage.getId(), 'abc');
t.is(incomingMessage.getIncomingData().getAbc(), 'testing');
t.is(outgoingMessage.getId(), 'abc');
t.is(outgoingMessage.data.incomingData, undefined);
});
test('should handle calling coerce to convert model of one type to another without unwrapping', function (t) {
const AddressType = module.exports = Enum.create({
values: [
'Client'
]
});
const Address = Model.extend({
properties: {
type: AddressType,
uri: String
},
coerce: function (value, options) {
if (value == null) {
return value;
}
if (value.constructor === Address) {
return value;
}
if (value.addressType) {
// value is Addressable
return value.getAddress();
}
this.coercionError(value, options);
}
});
const Addressable = {
id: 'Addressable',
initType: function (Type) {
const addressType = Type.prototype.addressType = Type.addressType;
if (!addressType) {
throw new Error('addressType is required for Addressable type');
}
},
prototype: {
getAddress: function () {
const id = this.getId();
if (!id) {
return null;
}
let address = this._address;
if (address === undefined) {
this._address = address = new Address();
address.setType(this.addressType);
address.setUri(this.getId());
}
return address;
}
}
};
const Client = ObservableModel.extend({
addressType: AddressType.Client,
mixins: [Addressable],
properties: {
id: String
}
});
const Message = Model.extend({
properties: {
from: Address
}
});
const client = new Client({
id: 'abc'
});
const message = new Message();
message.setFrom(client);
t.is(message.getFrom().getUri(), 'abc');
t.is(message.getFrom().getType(), AddressType.CLIENT);
});
test('should handle coercing "object" type', function (t) {
const Blah = Model.extend({
properties: {
abc: Object
}
});
const blah = new Blah();
t.throws(() => {
blah.setAbc(1);
}, Error);
});