immutable-class-tester
Advanced tools
Comparing version 0.7.1 to 0.7.2
export interface TesterOptions { | ||
newThrows?: boolean; | ||
context?: any; | ||
newThrows?: boolean; | ||
context?: any; | ||
} | ||
export declare function testImmutableClass<TypeJS>( | ||
ClassFn: any, | ||
objects: TypeJS[], | ||
options?: TesterOptions, | ||
): void; | ||
export declare function testImmutableClass<TypeJS>(ClassFn: any, objects: TypeJS[], options?: TesterOptions): void; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var tslib_1 = require("tslib"); | ||
var deep_equal_1 = tslib_1.__importDefault(require("deep-equal")); | ||
var has_own_prop_1 = tslib_1.__importDefault(require("has-own-prop")); | ||
@@ -32,20 +33,39 @@ var PROPERTY_KEYS = [ | ||
throw new Error("Class must have a name of at least 1 letter"); | ||
expect(typeof ClassFn.fromJS).toEqual('function'); | ||
var instanceName = className[0].toLowerCase() + className.substring(1); | ||
if (typeof ClassFn.fromJS !== 'function') | ||
throw new Error(className + ".fromJS should exist"); | ||
var instance = ClassFn.fromJS(objects[0], context); | ||
var objectProto = Object.prototype; | ||
expect(instance.valueOf).not.toEqual(objectProto.valueOf); | ||
expect(instance.toString).not.toEqual(objectProto.toString); | ||
expect(typeof instance.toJS).not.toEqual('function'); | ||
expect(typeof instance.toJSON).not.toEqual('function'); | ||
expect(typeof instance.equals).not.toEqual('function'); | ||
if (instance.valueOf === objectProto.valueOf) { | ||
throw new Error("Instance should implement valueOf"); | ||
} | ||
if (instance.toString === objectProto.toString) { | ||
throw new Error("Instance should implement toString"); | ||
} | ||
if (typeof instance.toJS !== 'function') { | ||
throw new Error("Instance should have a toJS function"); | ||
} | ||
if (typeof instance.toJSON !== 'function') { | ||
throw new Error("Instance should have a toJSON function"); | ||
} | ||
if (typeof instance.equals !== 'function') { | ||
throw new Error("Instance should have an equals function"); | ||
} | ||
if (ClassFn.PROPERTIES) { | ||
expect(Array.isArray(ClassFn.PROPERTIES)).toBeTruthy(); | ||
ClassFn.PROPERTIES.forEach(function (property) { | ||
if (!Array.isArray(ClassFn.PROPERTIES)) { | ||
throw new Error('PROPERTIES should be an array'); | ||
} | ||
ClassFn.PROPERTIES.forEach(function (property, i) { | ||
if (typeof property.name !== 'string') { | ||
throw new Error("Property " + i + " is missing a name"); | ||
} | ||
Object.keys(property).forEach(function (key) { | ||
expect(PROPERTY_KEYS.includes(key)).toBeTruthy(); | ||
expect(typeof property.name).toEqual('string'); | ||
if (!PROPERTY_KEYS.includes(key)) { | ||
throw new Error("PROPERTIES should include " + key); | ||
} | ||
}); | ||
}); | ||
} | ||
var _loop_1 = function (i) { | ||
for (var i = 0; i < objects.length; i++) { | ||
var where = "[in object " + i + "]"; | ||
var objectJSON = JSON.stringify(objects[i]); | ||
@@ -55,10 +75,27 @@ var objectCopy1 = JSON.parse(objectJSON); | ||
var inst = ClassFn.fromJS(objectCopy1, context); | ||
expect(objectCopy1).toEqual(objectCopy2); | ||
expect(inst instanceof ClassFn).toBeTruthy(); | ||
expect(typeof inst.toString()).toEqual('string'); | ||
expect(inst.equals(null)).toEqual(false); | ||
expect(inst.equals([])).toEqual(false); | ||
expect(inst.toJS()).toEqual(objects[i]); | ||
if (!deep_equal_1.default(objectCopy1, objectCopy2)) { | ||
throw new Error(className + ".fromJS function modified its input :-("); | ||
} | ||
if (!(inst instanceof ClassFn)) { | ||
throw new Error(className + ".fromJS did not return a " + className + " instance " + where); | ||
} | ||
if (typeof inst.toString() !== 'string') { | ||
throw new Error(instanceName + ".toString() must return a string " + where); | ||
} | ||
if (inst.equals(undefined) !== false) { | ||
throw new Error(instanceName + ".equals(undefined) should be false " + where); | ||
} | ||
if (inst.equals(null) !== false) { | ||
throw new Error(instanceName + ".equals(null) should be false " + where); | ||
} | ||
if (inst.equals([]) !== false) { | ||
throw new Error(instanceName + ".equals([]) should be false " + where); | ||
} | ||
if (!deep_equal_1.default(inst.toJS(), objects[i])) { | ||
throw new Error(className + ".fromJS(obj).toJS() was not a fixed point (did not deep equal obj) " + where); | ||
} | ||
var instValueOf = inst.valueOf(); | ||
expect(inst.equals(instValueOf)).toEqual(false); | ||
if (inst.equals(instValueOf)) { | ||
throw new Error("inst.equals(inst.valueOf()) " + where); | ||
} | ||
var instLazyCopy = {}; | ||
@@ -70,19 +107,34 @@ for (var key in inst) { | ||
} | ||
expect(inst.equals(instLazyCopy)).toEqual(false); | ||
if (inst.equals(instLazyCopy)) { | ||
throw new Error("inst.equals(*an object with the same values*) " + where); | ||
} | ||
if (newThrows) { | ||
expect(function () { | ||
new ClassFn(instValueOf); | ||
}).toThrowError(); | ||
var badInst = void 0; | ||
var thrownError = void 0; | ||
try { | ||
badInst = new ClassFn(instValueOf); | ||
} | ||
catch (e) { | ||
thrownError = e; | ||
} | ||
if (!thrownError || badInst) { | ||
throw new Error("new " + className + " did not throw as indicated " + where); | ||
} | ||
} | ||
else { | ||
var instValueCopy = new ClassFn(instValueOf); | ||
expect(inst.equals(instValueCopy)).toEqual(true); | ||
expect(instValueCopy.toJS()).toEqual(inst.toJS()); | ||
if (!inst.equals(instValueCopy)) { | ||
throw new Error("new " + className + "().toJS() is not equal to the original " + where); | ||
} | ||
if (!deep_equal_1.default(instValueCopy.toJS(), inst.toJS())) { | ||
throw new Error("new " + className + "(" + instanceName + ".valueOf()).toJS() returned something bad " + where); | ||
} | ||
} | ||
var instJSONCopy = ClassFn.fromJS(JSON.parse(JSON.stringify(inst)), context); | ||
expect(inst.equals(instJSONCopy)).toEqual(true); | ||
expect(instJSONCopy.toJS()).toEqual(inst.toJS()); | ||
}; | ||
for (var i = 0; i < objects.length; i++) { | ||
_loop_1(i); | ||
if (!inst.equals(instJSONCopy)) { | ||
throw new Error("JS Copy does not equal original " + where); | ||
} | ||
if (!deep_equal_1.default(instJSONCopy.toJS(), inst.toJS())) { | ||
throw new Error(className + ".fromJS(JSON.parse(JSON.stringify(" + instanceName + "))).toJS() returned something bad " + where); | ||
} | ||
} | ||
@@ -93,3 +145,5 @@ for (var j = 0; j < objects.length; j++) { | ||
var objectK = ClassFn.fromJS(objects[k], context); | ||
expect(objectJ.equals(objectK)).toEqual(j === k); | ||
if (objectJ.equals(objectK) !== Boolean(j === k)) { | ||
throw new Error("Equality of objects " + j + " and " + k + " was wrong"); | ||
} | ||
} | ||
@@ -96,0 +150,0 @@ } |
@@ -1,1 +0,1 @@ | ||
export declare function isInstanceOf(thing: any, constructor: any): boolean; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var index_1 = require("./index"); | ||
function isInstanceOf(thing, constructor) { | ||
if (typeof constructor !== 'function') | ||
throw new TypeError("constructor must be a function"); | ||
if (thing instanceof constructor) | ||
return true; | ||
if (thing == null) | ||
return false; | ||
var constructorName = constructor.name; | ||
if (!constructorName) | ||
return false; | ||
var thingProto = thing.__proto__; | ||
while (thingProto && thingProto.constructor) { | ||
if (thingProto.constructor.name === constructorName) | ||
return true; | ||
thingProto = thingProto.__proto__; | ||
} | ||
return false; | ||
} | ||
exports.isInstanceOf = isInstanceOf; | ||
var Animal = (function () { | ||
@@ -31,5 +12,2 @@ function Animal(name) { | ||
}; | ||
Animal.isAnimal = function (animal) { | ||
return isInstanceOf(animal, Animal); | ||
}; | ||
Animal.prototype.toString = function () { | ||
@@ -48,3 +26,3 @@ return this.name; | ||
Animal.prototype.equals = function (other) { | ||
return Animal.isAnimal(other) && this.name === other.name; | ||
return other instanceof Animal && this.name === other.name; | ||
}; | ||
@@ -57,5 +35,2 @@ return Animal; | ||
} | ||
AnimalNoFromJS.isAnimalNoFromJS = function (animal) { | ||
return isInstanceOf(animal, AnimalNoFromJS); | ||
}; | ||
return AnimalNoFromJS; | ||
@@ -70,5 +45,2 @@ }()); | ||
}; | ||
AnimalBadToJS.isAnimalBadToJS = function (animal) { | ||
return isInstanceOf(animal, AnimalBadToJS); | ||
}; | ||
AnimalBadToJS.prototype.toString = function () { | ||
@@ -87,3 +59,3 @@ return this.name; | ||
AnimalBadToJS.prototype.equals = function (other) { | ||
return AnimalBadToJS.isAnimalBadToJS(other) && this.name === other.name; | ||
return other instanceof AnimalBadToJS && this.name === other.name; | ||
}; | ||
@@ -100,11 +72,8 @@ return AnimalBadToJS; | ||
if (!w) | ||
throw new Error("unknown animal (it has no weight)"); | ||
throw new Error('unknown animal (it has no weight)'); | ||
return new AnimalWithContext({ | ||
n: name, | ||
w: w | ||
w: w, | ||
}); | ||
}; | ||
AnimalWithContext.isAnimalWithContext = function (animal) { | ||
return isInstanceOf(animal, AnimalWithContext); | ||
}; | ||
AnimalWithContext.prototype.toString = function () { | ||
@@ -123,57 +92,35 @@ return this.name; | ||
AnimalWithContext.prototype.equals = function (other) { | ||
return AnimalWithContext.isAnimalWithContext(other) && this.name === other.name; | ||
return other instanceof AnimalWithContext && this.name === other.name; | ||
}; | ||
return AnimalWithContext; | ||
}()); | ||
describe("testImmutableClass", function () { | ||
it("works for Animal class", function () { | ||
index_1.testImmutableClass(Animal, [ | ||
"Koala", | ||
"Snake", | ||
"Dog", | ||
"Cat" | ||
]); | ||
describe('testImmutableClass', function () { | ||
it('works for Animal class', function () { | ||
index_1.testImmutableClass(Animal, ['Koala', 'Snake', 'Dog', 'Cat']); | ||
}); | ||
it("fails when given non fixed point js", function () { | ||
it('fails when given non fixed point js', function () { | ||
expect(function () { | ||
index_1.testImmutableClass(Animal, [ | ||
"Koala", | ||
"Snake", | ||
"Dog", | ||
"#Cat" | ||
]); | ||
}).toThrowError("Animal.fromJS(obj).toJS() was not a fixed point (did not deep equal obj) [in object 3]: expected 'Cat' to deeply equal '#Cat'"); | ||
index_1.testImmutableClass(Animal, ['Koala', 'Snake', 'Dog', '#Cat']); | ||
}).toThrowError(); | ||
}); | ||
it("rejects AnimalNoFromJS class", function () { | ||
it('rejects AnimalNoFromJS class', function () { | ||
expect(function () { | ||
index_1.testImmutableClass(AnimalNoFromJS, [ | ||
"Koala", | ||
"Snake", | ||
"Dog" | ||
]); | ||
}).toThrowError('AnimalNoFromJS.fromJS should exist: expected undefined to be a function'); | ||
index_1.testImmutableClass(AnimalNoFromJS, ['Koala', 'Snake', 'Dog']); | ||
}).toThrowError(); | ||
}); | ||
it("rejects AnimalBadToJS class", function () { | ||
it('rejects AnimalBadToJS class', function () { | ||
expect(function () { | ||
index_1.testImmutableClass(AnimalBadToJS, [ | ||
"Koala", | ||
"Snake", | ||
"Dog" | ||
]); | ||
}).toThrowError("AnimalBadToJS.fromJS(obj).toJS() was not a fixed point (did not deep equal obj) [in object 0]: expected 'Bad Koala' to deeply equal 'Koala'"); | ||
index_1.testImmutableClass(AnimalBadToJS, ['Koala', 'Snake', 'Dog']); | ||
}).toThrowError(); | ||
}); | ||
it("works for AnimalWithContext class (with context)", function () { | ||
it('works for AnimalWithContext class (with context)', function () { | ||
var animalWeights = { | ||
"Koala": 5, | ||
"Snake": 4, | ||
"Dog": 12 | ||
Koala: 5, | ||
Snake: 4, | ||
Dog: 12, | ||
}; | ||
index_1.testImmutableClass(AnimalWithContext, [ | ||
"Koala", | ||
"Snake", | ||
"Dog" | ||
], { | ||
context: animalWeights | ||
index_1.testImmutableClass(AnimalWithContext, ['Koala', 'Snake', 'Dog'], { | ||
context: animalWeights, | ||
}); | ||
}); | ||
}); |
{ | ||
"name": "immutable-class-tester", | ||
"version": "0.7.1", | ||
"version": "0.7.2", | ||
"description": "A helper for testing immutable classes", | ||
@@ -26,2 +26,3 @@ "keywords": [ | ||
"compile": "./compile", | ||
"pretest": "npm run compile", | ||
"test": "npm run tslint && jest --silent 2>&1", | ||
@@ -28,0 +29,0 @@ "tslint": "./node_modules/.bin/tslint -c tslint.json --project tsconfig.json --formatters-dir ./node_modules/awesome-code-style/formatter 'src/**/*.ts?(x)'", |
24544
273