Files
jasmine/spec/core/RunableResourcesSpec.js
2025-09-27 13:21:09 -07:00

558 lines
18 KiB
JavaScript

describe('RunableResources', function() {
describe('#spies', function() {
behavesLikeAPerRunableMutableArray(
'spies',
'Spies must be created in a before function or a spec',
false
);
});
describe('#customSpyStrategies', function() {
behavesLikeAPerRunableMutableObject(
'customSpyStrategies',
'Custom spy strategies must be added in a before function or a spec'
);
});
describe('#customEqualityTesters', function() {
behavesLikeAPerRunableMutableArray(
'customEqualityTesters',
'Custom Equalities must be added in a before function or a spec'
);
});
describe('#customObjectFormatters', function() {
behavesLikeAPerRunableMutableArray(
'customObjectFormatters',
'Custom object formatters must be added in a before function or a spec'
);
});
describe('#customMatchers', function() {
behavesLikeAPerRunableMutableObject(
'customMatchers',
'Matchers must be added in a before function or a spec'
);
});
describe('#addCustomMatchers', function() {
it("adds all properties to the current runable's matchers", function() {
const currentRunableId = 1;
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
function toBeFoo() {}
function toBeBar() {}
function toBeBaz() {}
runableResources.addCustomMatchers({ toBeFoo });
expect(runableResources.customMatchers()).toEqual({ toBeFoo });
runableResources.addCustomMatchers({ toBeBar, toBeBaz });
expect(runableResources.customMatchers()).toEqual({
toBeFoo,
toBeBar,
toBeBaz
});
});
});
describe('#customAsyncMatchers', function() {
behavesLikeAPerRunableMutableObject(
'customAsyncMatchers',
'Async Matchers must be added in a before function or a spec'
);
});
describe('#addCustomAsyncMatchers', function() {
it("adds all properties to the current runable's matchers", function() {
const currentRunableId = 1;
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
function toBeFoo() {}
function toBeBar() {}
function toBeBaz() {}
runableResources.addCustomAsyncMatchers({ toBeFoo });
expect(runableResources.customAsyncMatchers()).toEqual({ toBeFoo });
runableResources.addCustomAsyncMatchers({ toBeBar, toBeBaz });
expect(runableResources.customAsyncMatchers()).toEqual({
toBeFoo,
toBeBar,
toBeBaz
});
});
});
describe('#defaultSpyStrategy', function() {
it('returns undefined for a newly initialized resource', function() {
let currentRunableId = 1;
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
expect(runableResources.defaultSpyStrategy()).toBeUndefined();
});
it('returns the value previously set by #setDefaultSpyStrategy', function() {
let currentRunableId = 1;
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
const fn = () => {};
runableResources.setDefaultSpyStrategy(fn);
expect(runableResources.defaultSpyStrategy()).toBe(fn);
});
it('is per-runable', function() {
let currentRunableId = 1;
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
runableResources.setDefaultSpyStrategy(() => {});
currentRunableId = 2;
runableResources.initForRunable(2);
expect(runableResources.defaultSpyStrategy()).toBeUndefined();
});
it('does not require a current runable', function() {
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => null
});
expect(runableResources.defaultSpyStrategy()).toBeUndefined();
});
it("inherits the parent runable's value", function() {
let currentRunableId = 1;
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
const fn = () => {};
runableResources.setDefaultSpyStrategy(fn);
currentRunableId = 2;
runableResources.initForRunable(2, 1);
expect(runableResources.defaultSpyStrategy()).toBe(fn);
});
});
describe('#setDefaultSpyStrategy', function() {
it('throws a user-facing error when there is no current runable', function() {
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => null
});
expect(function() {
runableResources.setDefaultSpyStrategy();
}).toThrowError(
'Default spy strategy must be set in a before function or a spec'
);
});
});
describe('#makePrettyPrinter', function() {
it('returns a pretty printer configured with the current customObjectFormatters', function() {
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => 1
});
runableResources.initForRunable(1);
function cof() {}
runableResources.customObjectFormatters().push(cof);
spyOn(privateUnderTest, 'makePrettyPrinter').and.callThrough();
const pp = runableResources.makePrettyPrinter();
expect(privateUnderTest.makePrettyPrinter).toHaveBeenCalledOnceWith([
cof
]);
expect(pp).toBe(
privateUnderTest.makePrettyPrinter.calls.first().returnValue
);
});
});
describe('#makeMatchersUtil', function() {
describe('When there is a current runable', function() {
it('returns a MatchersUtil configured with the current resources', function() {
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => 1
});
runableResources.initForRunable(1);
function cof() {}
runableResources.customObjectFormatters().push(cof);
function ceq() {}
runableResources.customEqualityTesters().push(ceq);
const expectedPP = {};
const expectedMatchersUtil = {};
spyOn(privateUnderTest, 'makePrettyPrinter').and.returnValue(
expectedPP
);
spyOn(privateUnderTest, 'MatchersUtil').and.returnValue(
expectedMatchersUtil
);
const matchersUtil = runableResources.makeMatchersUtil();
expect(matchersUtil).toBe(expectedMatchersUtil);
expect(privateUnderTest.makePrettyPrinter).toHaveBeenCalledOnceWith([
cof
]);
// We need === equality on the pp passed to MatchersUtil
expect(privateUnderTest.MatchersUtil).toHaveBeenCalledOnceWith(
jasmine.objectContaining({
customTesters: [ceq]
})
);
expect(privateUnderTest.MatchersUtil.calls.argsFor(0)[0].pp).toBe(
expectedPP
);
});
});
describe('When there is no current runable', function() {
it('returns a MatchersUtil configured with defaults', function() {
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => null
});
const expectedMatchersUtil = {};
spyOn(privateUnderTest, 'MatchersUtil').and.returnValue(
expectedMatchersUtil
);
const matchersUtil = runableResources.makeMatchersUtil();
expect(matchersUtil).toBe(expectedMatchersUtil);
// We need === equality on the pp passed to MatchersUtil
expect(privateUnderTest.MatchersUtil).toHaveBeenCalledTimes(1);
expect(privateUnderTest.MatchersUtil.calls.argsFor(0)[0].pp).toBe(
privateUnderTest.basicPrettyPrinter
);
expect(
privateUnderTest.MatchersUtil.calls.argsFor(0)[0].customTesters
).toBeUndefined();
});
});
});
describe('.spyFactory', function() {
describe('When there is no current runable', function() {
it('is configured with default strategies and matchersUtil', function() {
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => null
});
spyOn(privateUnderTest, 'Spy');
const matchersUtil = {};
spyOn(runableResources, 'makeMatchersUtil').and.returnValue(
matchersUtil
);
runableResources.spyFactory.createSpy('foo');
expect(privateUnderTest.Spy).toHaveBeenCalledWith(
'foo',
is(matchersUtil),
jasmine.objectContaining({
customStrategies: {},
defaultStrategyFn: undefined
})
);
});
});
describe('When there is a current runable', function() {
it("is configured with the current runable's strategies and matchersUtil", function() {
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => 1
});
runableResources.initForRunable(1);
function customStrategy() {}
function defaultStrategy() {}
runableResources.customSpyStrategies().foo = customStrategy;
runableResources.setDefaultSpyStrategy(defaultStrategy);
spyOn(privateUnderTest, 'Spy');
const matchersUtil = {};
spyOn(runableResources, 'makeMatchersUtil').and.returnValue(
matchersUtil
);
runableResources.spyFactory.createSpy('foo');
expect(privateUnderTest.Spy).toHaveBeenCalledWith(
'foo',
is(matchersUtil),
jasmine.objectContaining({
customStrategies: { foo: customStrategy },
defaultStrategyFn: defaultStrategy
})
);
});
});
function is(expected) {
return {
asymmetricMatch: function(actual) {
return actual === expected;
},
jasmineToString: function(pp) {
return '<same instance as ' + pp(expected) + '>';
}
};
}
});
describe('.spyRegistry', function() {
it("writes to the current runable's spies", function() {
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => 1
});
runableResources.initForRunable(1);
function foo() {}
const spyObj = { foo };
runableResources.spyRegistry.spyOn(spyObj, 'foo');
expect(runableResources.spies()).toEqual([
jasmine.objectContaining({
restoreObjectToOriginalState: jasmine.any(Function)
})
]);
expect(jasmineUnderTest.isSpy(spyObj.foo)).toBeTrue();
runableResources.spyRegistry.clearSpies();
expect(spyObj.foo).toBe(foo);
});
});
describe('#clearForRunable', function() {
it('removes resources for the specified runable', function() {
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => 1
});
runableResources.initForRunable(1);
expect(function() {
runableResources.spies();
}).not.toThrow();
runableResources.clearForRunable(1);
expect(function() {
runableResources.spies();
}).toThrowError('Spies must be created in a before function or a spec');
});
it('clears spies', function() {
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => 1
});
runableResources.initForRunable(1);
function foo() {}
const spyObj = { foo };
runableResources.spyRegistry.spyOn(spyObj, 'foo');
expect(spyObj.foo).not.toBe(foo);
runableResources.clearForRunable(1);
expect(spyObj.foo).toBe(foo);
});
it('clears the global error spy', function() {
const globalErrors = jasmine.createSpyObj('globalErrors', [
'removeOverrideListener'
]);
const runableResources = new privateUnderTest.RunableResources({
getCurrentRunableId: () => 1,
globalErrors
});
runableResources.initForRunable(1);
runableResources.clearForRunable(1);
expect(globalErrors.removeOverrideListener).toHaveBeenCalled();
});
it('does not remove resources for other runables', function() {
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => 1
});
runableResources.initForRunable(1);
function cof() {}
runableResources.customObjectFormatters().push(cof);
runableResources.clearForRunable(2);
expect(runableResources.customObjectFormatters()).toEqual([cof]);
});
});
function behavesLikeAPerRunableMutableArray(
methodName,
errorMsg,
inherits = true
) {
it('is initially empty', function() {
const currentRunableId = 1;
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
expect(runableResources[methodName]()).toEqual([]);
});
it('is mutable', function() {
const currentRunableId = 1;
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
function newItem() {}
runableResources[methodName]().push(newItem);
expect(runableResources[methodName]()).toEqual([newItem]);
});
it('is per-runable', function() {
let currentRunableId = 1;
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
runableResources[methodName]().push(() => {});
runableResources.initForRunable(2);
currentRunableId = 2;
expect(runableResources[methodName]()).toEqual([]);
});
it('throws a user-facing error when there is no current runable', function() {
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => null
});
expect(function() {
runableResources[methodName]();
}).toThrowError(errorMsg);
});
if (inherits) {
it('inherits from the parent runable', function() {
let currentRunableId = 1;
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
function parentItem() {}
runableResources[methodName]().push(parentItem);
runableResources.initForRunable(2, 1);
currentRunableId = 2;
function childItem() {}
runableResources[methodName]().push(childItem);
expect(runableResources[methodName]()).toEqual([parentItem, childItem]);
currentRunableId = 1;
expect(runableResources[methodName]()).toEqual([parentItem]);
});
}
}
function behavesLikeAPerRunableMutableObject(methodName, errorMsg) {
it('is initially empty', function() {
const currentRunableId = 1;
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
expect(runableResources[methodName]()).toEqual({});
});
it('is mutable', function() {
const currentRunableId = 1;
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
function newItem() {}
runableResources[methodName]().foo = newItem;
expect(runableResources[methodName]()).toEqual({ foo: newItem });
});
it('is per-runable', function() {
let currentRunableId = 1;
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
runableResources[methodName]().foo = function() {};
runableResources.initForRunable(2);
currentRunableId = 2;
expect(runableResources[methodName]()).toEqual({});
});
it('throws a user-facing error when there is no current runable', function() {
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => null
});
expect(function() {
runableResources[methodName]();
}).toThrowError(errorMsg);
});
it('inherits from the parent runable', function() {
let currentRunableId = 1;
const runableResources = new privateUnderTest.RunableResources({
globalErrors: stubGlobalErrors(),
getCurrentRunableId: () => currentRunableId
});
runableResources.initForRunable(1);
function parentItem() {}
runableResources[methodName]().parentName = parentItem;
runableResources.initForRunable(2, 1);
currentRunableId = 2;
function childItem() {}
runableResources[methodName]().childName = childItem;
expect(runableResources[methodName]()).toEqual({
parentName: parentItem,
childName: childItem
});
currentRunableId = 1;
expect(runableResources[methodName]()).toEqual({
parentName: parentItem
});
});
}
function stubGlobalErrors() {
return {
removeOverrideListener() {}
};
}
});