Update test specs to use Jasmine 3 (#2089)

* Updated Karma and Jasmine versions

* Added DOMObserver class. Supports promise-based testing of DOM changes

Update asynchronous test specs to use promises or done() instead of waitsFor/runs

* Modified ActionCapability to duplicate context object properties as own properties for better object equality comparisons

* Global find + replace to fix syntax issues

* Fixed various issues caused by non-deterministic runtime order of tests in Jasmine 3. Fixed issues caused by changes to determination of object equality

* Addressed review comments

* Resolved merge conflicts with master

* Fixed style errors

* Use spy.calls.count() instead of manually tracking
This commit is contained in:
Andrew Henry
2018-06-29 17:32:59 -07:00
committed by Pete Richards
parent 013eba744d
commit 433dee0314
305 changed files with 2866 additions and 3324 deletions

View File

@@ -19,6 +19,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global console*/
/**
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
@@ -48,9 +49,19 @@ define(
controller;
function waitsForNavigation() {
var calls = mockNavigationService.setNavigation.calls.length;
waitsFor(function () {
return mockNavigationService.setNavigation.calls.length > calls;
return new Promise(function (resolve) {
mockNavigationService.setNavigation.and.callFake(function (obj) {
var returnValue;
try {
returnValue = NavigationService.prototype.setNavigation.call(mockNavigationService, obj);
} catch (err) {
console.error(err);
//Not rejecting because 'setNavigation' has been called, which is what's being tested here.
//Rejecting will fail tests.
}
resolve();
return returnValue;
});
});
}
@@ -78,7 +89,7 @@ define(
"urlService",
["urlForLocation"]
);
mockUrlService.urlForLocation.andCallFake(function (mode, object) {
mockUrlService.urlForLocation.and.callFake(function (mode, object) {
if (object === mockDefaultRootObject) {
return [mode, testDefaultRoot].join('/');
}
@@ -106,7 +117,7 @@ define(
"removeListener"
].forEach(function (method) {
spyOn(mockNavigationService, method)
.andCallThrough();
.and.callThrough();
});
mockRootObject = jasmine.createSpyObj(
"rootObjectContainer",
@@ -124,60 +135,58 @@ define(
"nestedDomainObject",
["getId", "getCapability", "getModel", "useCapability", "hasCapability"]
);
mockObjectService.getObjects.andReturn(Promise.resolve({
mockObjectService.getObjects.and.returnValue(Promise.resolve({
ROOT: mockRootObject
}));
mockRootObject.useCapability.andReturn(Promise.resolve([
mockRootObject.useCapability.and.returnValue(Promise.resolve([
mockOtherDomainObject,
mockDefaultRootObject
]));
mockRootObject.hasCapability.andReturn(true);
mockDefaultRootObject.useCapability.andReturn(Promise.resolve([
mockRootObject.hasCapability.and.returnValue(true);
mockDefaultRootObject.useCapability.and.returnValue(Promise.resolve([
mockNextObject
]));
mockDefaultRootObject.hasCapability.andReturn(true);
mockOtherDomainObject.hasCapability.andReturn(false);
mockNextObject.useCapability.andReturn(undefined);
mockNextObject.hasCapability.andReturn(false);
mockNextObject.getId.andReturn("next");
mockDefaultRootObject.getId.andReturn(testDefaultRoot);
mockDefaultRootObject.hasCapability.and.returnValue(true);
mockOtherDomainObject.hasCapability.and.returnValue(false);
mockNextObject.useCapability.and.returnValue(undefined);
mockNextObject.hasCapability.and.returnValue(false);
mockNextObject.getId.and.returnValue("next");
mockDefaultRootObject.getId.and.returnValue(testDefaultRoot);
instantiateController();
waitsForNavigation();
return waitsForNavigation();
});
it("uses composition to set the navigated object, if there is none", function () {
instantiateController();
waitsForNavigation();
runs(function () {
return waitsForNavigation().then(function () {
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDefaultRootObject);
.toHaveBeenCalledWith(mockDefaultRootObject);
});
});
it("navigates to a root-level object, even when default path is not found", function () {
mockDefaultRootObject.getId
.andReturn("something-other-than-the-" + testDefaultRoot);
.and.returnValue("something-other-than-the-" + testDefaultRoot);
instantiateController();
waitsForNavigation();
runs(function () {
return waitsForNavigation().then(function () {
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDefaultRootObject);
.toHaveBeenCalledWith(mockDefaultRootObject);
});
});
});
//
it("does not try to override navigation", function () {
mockNavigationService.getNavigation.andReturn(mockDefaultRootObject);
mockNavigationService.getNavigation.and.returnValue(mockDefaultRootObject);
instantiateController();
waitsForNavigation();
expect(mockScope.navigatedObject).toBe(mockDefaultRootObject);
return waitsForNavigation().then(function () {
expect(mockScope.navigatedObject).toBe(mockDefaultRootObject);
});
});
//
it("updates scope when navigated object changes", function () {
// Should have registered a listener - call it
mockNavigationService.addListener.mostRecentCall.args[0](
mockNavigationService.addListener.calls.mostRecent().args[0](
mockOtherDomainObject
);
expect(mockScope.navigatedObject).toEqual(mockOtherDomainObject);
@@ -189,19 +198,18 @@ define(
"$destroy",
jasmine.any(Function)
);
mockScope.$on.mostRecentCall.args[1]();
mockScope.$on.calls.mostRecent().args[1]();
// Should remove the listener it added earlier
expect(mockNavigationService.removeListener).toHaveBeenCalledWith(
mockNavigationService.addListener.mostRecentCall.args[0]
mockNavigationService.addListener.calls.mostRecent().args[0]
);
});
it("uses route parameters to choose initially-navigated object", function () {
mockRoute.current.params.ids = testDefaultRoot + "/next";
instantiateController();
waitsForNavigation();
runs(function () {
return waitsForNavigation().then(function () {
expect(mockScope.navigatedObject).toBe(mockNextObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockNextObject);
@@ -214,12 +222,10 @@ define(
// it hits an invalid ID.
mockRoute.current.params.ids = testDefaultRoot + "/junk";
instantiateController();
waitsForNavigation();
runs(function () {
return waitsForNavigation().then(function () {
expect(mockScope.navigatedObject).toBe(mockDefaultRootObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDefaultRootObject);
});
});
@@ -229,8 +235,7 @@ define(
// should stop at it since remaining IDs cannot be loaded.
mockRoute.current.params.ids = testDefaultRoot + "/next/junk";
instantiateController();
waitsForNavigation();
runs(function () {
return waitsForNavigation().then(function () {
expect(mockScope.navigatedObject).toBe(mockNextObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockNextObject);
@@ -244,11 +249,11 @@ define(
expect(mockRoute.current.pathParams.ids)
.not
.toBe(testDefaultRoot + '/next');
mockLocation.path.andCallFake(function () {
mockLocation.path.and.callFake(function () {
expect(mockRoute.current.pathParams.ids)
.toBe(testDefaultRoot + '/next');
});
mockNavigationService.addListener.mostRecentCall.args[0](
mockNavigationService.addListener.calls.mostRecent().args[0](
mockNextObject
);
expect(mockLocation.path).toHaveBeenCalledWith(

View File

@@ -20,7 +20,6 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
["../src/BrowseObjectController"],
function (BrowseObjectController) {
@@ -33,7 +32,7 @@ define(
// Utility function; look for a $watch on scope and fire it
function fireWatch(expr, value) {
mockScope.$watch.calls.forEach(function (call) {
mockScope.$watch.calls.all().forEach(function (call) {
if (call.args[0] === expr) {
call.args[1](value);
}
@@ -50,7 +49,7 @@ define(
"$location",
["path", "search"]
);
mockLocation.search.andReturn({});
mockLocation.search.and.returnValue({});
controller = new BrowseObjectController(
mockScope,
@@ -65,7 +64,7 @@ define(
// Allows the path index to be checked
// prior to setting $route.current
mockLocation.path.andReturn("/browse/");
mockLocation.path.and.returnValue("/browse/");
});
it("sets the active view from query parameters", function () {
@@ -79,10 +78,10 @@ define(
{ key: 'xyz' }
];
mockDomainObject.useCapability.andCallFake(function (c) {
mockDomainObject.useCapability.and.callFake(function (c) {
return (c === 'view') && testViews;
});
mockLocation.search.andReturn({ view: 'def' });
mockLocation.search.and.returnValue({ view: 'def' });
fireWatch('domainObject', mockDomainObject);
expect(mockScope.representation.selected)

View File

@@ -50,14 +50,14 @@ define(
"navigationService",
["getNavigation", "addListener"]
);
mockNavigationService.addListener.andReturn(mockNavigationUnlistener);
mockNavigationService.addListener.and.returnValue(mockNavigationUnlistener);
mockStatusUnlistener = jasmine.createSpy("statusUnlistener");
mockStatusCapability = jasmine.createSpyObj(
"statusCapability",
["listen"]
);
mockStatusCapability.listen.andReturn(mockStatusUnlistener);
mockStatusCapability.listen.and.returnValue(mockStatusUnlistener);
mockDomainObject = jasmine.createSpyObj(
'domainObject',
@@ -68,13 +68,13 @@ define(
'hasCapability'
]
);
mockDomainObject.getId.andReturn("domainObject");
mockDomainObject.getModel.andReturn({});
mockDomainObject.hasCapability.andReturn(true);
mockDomainObject.getCapability.andReturn(mockStatusCapability);
mockDomainObject.getId.and.returnValue("domainObject");
mockDomainObject.getModel.and.returnValue({});
mockDomainObject.hasCapability.and.returnValue(true);
mockDomainObject.getCapability.and.returnValue(mockStatusCapability);
mockLocation = jasmine.createSpyObj('location', ['search']);
mockLocation.search.andReturn({});
mockLocation.search.and.returnValue({});
mockAttrs = {};
@@ -84,7 +84,7 @@ define(
it("listens for changes to navigation and attaches a status" +
" listener", function () {
expect(mockNavigationService.addListener).toHaveBeenCalledWith(jasmine.any(Function));
mockNavigationService.addListener.mostRecentCall.args[0](mockDomainObject);
mockNavigationService.addListener.calls.mostRecent().args[0](mockDomainObject);
expect(mockStatusCapability.listen).toHaveBeenCalledWith(jasmine.any(Function));
});
@@ -93,8 +93,8 @@ define(
controller.toggle();
// test pre-condition that inspector is hidden
expect(controller.visible()).toBe(false);
mockNavigationService.addListener.mostRecentCall.args[0](mockDomainObject);
mockStatusCapability.listen.mostRecentCall.args[0](["editing"]);
mockNavigationService.addListener.calls.mostRecent().args[0](mockDomainObject);
mockStatusCapability.listen.calls.mostRecent().args[0](["editing"]);
expect(controller.visible()).toBe(true);
});

View File

@@ -60,8 +60,8 @@ define(
mockActionContext.domainObject = mockDomainObject;
mockActionContext.event = mockEvent;
mockScope.domainObject = mockDomainObject;
mockDomainObject.getCapability.andReturn(mockContextMenuAction);
mockContextMenuAction.perform.andReturn(jasmine.any(Function));
mockDomainObject.getCapability.and.returnValue(mockContextMenuAction);
mockContextMenuAction.perform.and.returnValue(jasmine.any(Function));
controller = new MenuArrowController(mockScope);
});

View File

@@ -39,7 +39,7 @@ define(
mockMutationCapability = jasmine.createSpyObj("mutation", ["mutate"]);
mockTypeCapability = jasmine.createSpyObj("type", ["typeDef", "hasFeature"]);
mockTypeCapability.typeDef = { name: ""};
mockTypeCapability.hasFeature.andCallFake(function (feature) {
mockTypeCapability.hasFeature.and.callFake(function (feature) {
return feature === 'creation';
});
@@ -52,8 +52,8 @@ define(
name: "Test name"
};
mockDomainObject = jasmine.createSpyObj("domainObject", ["getCapability", "getModel"]);
mockDomainObject.getModel.andReturn(model);
mockDomainObject.getCapability.andCallFake(function (key) {
mockDomainObject.getModel.and.returnValue(model);
mockDomainObject.getCapability.and.callFake(function (key) {
return mockCapabilities[key];
});
@@ -62,7 +62,7 @@ define(
};
mockCurrentTarget = jasmine.createSpyObj("currentTarget", ["blur", "textContent"]);
mockCurrentTarget.blur.andReturn(mockCurrentTarget);
mockCurrentTarget.blur.and.returnValue(mockCurrentTarget);
mockEvent = {
which: {},
@@ -109,7 +109,7 @@ define(
expect(mockMutationCapability.mutate).toHaveBeenCalledWith(jasmine.any(Function));
mockMutationCapability.mutate.mostRecentCall.args[0](model);
mockMutationCapability.mutate.calls.mostRecent().args[0](model);
expect(mockDomainObject.getModel().name).toBe("New name");
});
@@ -127,7 +127,7 @@ define(
});
it("disallows editting name when object is non-creatable", function () {
mockTypeCapability.hasFeature.andReturn(false);
mockTypeCapability.hasFeature.and.returnValue(false);
expect(controller.allowEdit()).toBe(false);

View File

@@ -53,8 +53,8 @@ define(
['getId', 'getModel', 'getCapability']
);
mockDomainObject.getId.andReturn(id);
mockDomainObject.getModel.andReturn({});
mockDomainObject.getId.and.returnValue(id);
mockDomainObject.getModel.and.returnValue({});
return mockDomainObject;
});
@@ -65,7 +65,7 @@ define(
mockWindow = jasmine.createSpyObj("$window", ["open"]);
mockLocation = jasmine.createSpyObj('location', ['search']);
mockLocation.search.andReturn({});
mockLocation.search.and.returnValue({});
mockAttrs = {};
});
@@ -83,9 +83,9 @@ define(
});
it("collapses on navigation changes on portrait-oriented phones", function () {
mockAgentService.isMobile.andReturn(true);
mockAgentService.isPhone.andReturn(true);
mockAgentService.isPortrait.andReturn(true);
mockAgentService.isMobile.and.returnValue(true);
mockAgentService.isPhone.and.returnValue(true);
mockAgentService.isPortrait.and.returnValue(true);
controller = instantiateController();
expect(controller.visible()).toBeTruthy();
@@ -102,13 +102,13 @@ define(
});
it("sets pane state to false when in location.search", function () {
mockLocation.search.andReturn({'hideTree': true});
mockLocation.search.and.returnValue({'hideTree': true});
expect(instantiateController().visible()).toBe(false);
expect(mockLocation.search).toHaveBeenCalledWith('hideTree', undefined);
});
it("sets state to true when not found in location.search", function () {
mockLocation.search.andReturn({});
mockLocation.search.and.returnValue({});
expect(instantiateController().visible()).toBe(true);
expect(mockLocation.search).not.toHaveBeenCalledWith('hideTree', undefined);
});

View File

@@ -34,17 +34,6 @@ define([
mockDomainObject,
action;
function waitForCall() {
var called = false;
waitsFor(function () {
return called;
});
return function () {
called = true;
};
}
beforeEach(function () {
mockNavigationService = jasmine.createSpyObj(
"navigationService",
@@ -63,26 +52,24 @@ define([
});
it("sets navigation if it is allowed", function () {
mockNavigationService.shouldNavigate.andReturn(true);
action.perform()
.then(waitForCall());
runs(function () {
expect(mockNavigationService.setNavigation)
mockNavigationService.shouldNavigate.and.returnValue(true);
return action.perform()
.then(function () {
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDomainObject, true);
});
});
});
it("does not set navigation if it is not allowed", function () {
mockNavigationService.shouldNavigate.andReturn(false);
mockNavigationService.shouldNavigate.and.returnValue(false);
var onSuccess = jasmine.createSpy('onSuccess');
action.perform()
.then(onSuccess, waitForCall());
runs(function () {
expect(onSuccess).not.toHaveBeenCalled();
expect(mockNavigationService.setNavigation)
.not
.toHaveBeenCalledWith(mockDomainObject);
});
return action.perform()
.then(onSuccess, function () {
expect(onSuccess).not.toHaveBeenCalled();
expect(mockNavigationService.setNavigation)
.not
.toHaveBeenCalledWith(mockDomainObject);
});
});
it("is only applicable when a domain object is in context", function () {

View File

@@ -69,7 +69,7 @@ define(
navigationService.addListener(callback);
navigationService.setNavigation(testObject);
navigationService.setNavigation(testObject);
expect(callback.calls.length).toEqual(1);
expect(callback.calls.count()).toEqual(1);
});
it("stops notifying listeners after removal", function () {

View File

@@ -65,34 +65,35 @@ define([
mockActionCapability = jasmine.createSpyObj('action', ['perform']);
mockEditor = jasmine.createSpyObj('editor', ['isEditContextRoot']);
mockThrottle.andCallFake(function (fn) {
mockThrottle.and.callFake(function (fn) {
var mockThrottledFn =
jasmine.createSpy('throttled-' + mockThrottledFns.length);
mockThrottledFn.andCallFake(fn);
mockThrottledFn.and.callFake(fn);
mockThrottledFns.push(mockThrottledFn);
return mockThrottledFn;
});
mockTopic.andReturn(mockMutationTopic);
mockDomainObject.getId.andReturn(testId);
mockDomainObject.getCapability.andCallFake(function (c) {
mockTopic.and.returnValue(mockMutationTopic);
mockDomainObject.getId.and.returnValue(testId);
mockDomainObject.getCapability.and.callFake(function (c) {
return {
context: mockContext,
editor: mockEditor
}[c];
});
mockDomainObject.hasCapability.andCallFake(function (c) {
mockDomainObject.hasCapability.and.callFake(function (c) {
return !!mockDomainObject.getCapability(c);
});
mockParentObject.getCapability.andCallFake(function (c) {
mockParentObject.getCapability.and.callFake(function (c) {
return {
action: mockActionCapability
}[c];
});
testParentComposition = [];
mockParentObject.useCapability.andReturn(Promise.resolve(testParentComposition));
mockContext.getParent.andReturn(mockParentObject);
mockNavigationService.getNavigation.andReturn(mockDomainObject);
mockEditor.isEditContextRoot.andReturn(false);
mockParentObject.useCapability.and.returnValue(Promise.resolve(testParentComposition));
mockContext.getParent.and.returnValue(mockParentObject);
mockNavigationService.getNavigation.and.returnValue(mockDomainObject);
mockEditor.isEditContextRoot.and.returnValue(false);
return new OrphanNavigationHandler(
mockThrottle,
@@ -106,7 +107,7 @@ define([
expect(mockMutationTopic.listen)
.toHaveBeenCalledWith(jasmine.any(Function));
expect(mockThrottledFns.indexOf(
mockMutationTopic.listen.mostRecentCall.args[0]
mockMutationTopic.listen.calls.mostRecent().args[0]
)).not.toEqual(-1);
});
@@ -114,7 +115,7 @@ define([
expect(mockNavigationService.addListener)
.toHaveBeenCalledWith(jasmine.any(Function));
expect(mockThrottledFns.indexOf(
mockNavigationService.addListener.mostRecentCall.args[0]
mockNavigationService.addListener.calls.mostRecent().args[0]
)).not.toEqual(-1);
});
@@ -134,28 +135,14 @@ define([
function itNavigatesAsExpected() {
if (isOrphan && !isEditRoot) {
it("navigates to the parent", function () {
var done = false;
waitsFor(function () {
return done;
});
setTimeout(function () {
done = true;
}, 5);
runs(function () {
return Promise.resolve().then(function () {
expect(mockActionCapability.perform)
.toHaveBeenCalledWith('navigate');
});
});
} else {
it("does nothing", function () {
var done = false;
waitsFor(function () {
return done;
});
setTimeout(function () {
done = true;
}, 5);
runs(function () {
return Promise.resolve().then(function () {
expect(mockActionCapability.perform)
.not.toHaveBeenCalled();
});
@@ -165,12 +152,12 @@ define([
describe(caseName, function () {
beforeEach(function () {
mockEditor.isEditContextRoot.andReturn(isEditRoot);
mockEditor.isEditContextRoot.and.returnValue(isEditRoot);
});
describe("when navigation changes", function () {
beforeEach(function () {
mockNavigationService.addListener.mostRecentCall
mockNavigationService.addListener.calls.mostRecent()
.args[0](mockDomainObject);
});
itNavigatesAsExpected();
@@ -178,7 +165,7 @@ define([
describe("when mutation occurs", function () {
beforeEach(function () {
mockMutationTopic.listen.mostRecentCall
mockMutationTopic.listen.calls.mostRecent()
.args[0](mockParentObject);
});

View File

@@ -49,8 +49,8 @@ define(
);
mockDocument = [{}];
mockDomainObject.getModel.andReturn({ name: 'Test name' });
mockNavigationService.getNavigation.andReturn(mockDomainObject);
mockDomainObject.getModel.and.returnValue({ name: 'Test name' });
mockNavigationService.getNavigation.and.returnValue(mockDomainObject);
titler = new WindowTitler(
mockNavigationService,
@@ -64,12 +64,12 @@ define(
jasmine.any(Function),
jasmine.any(Function)
);
expect(mockRootScope.$watch.mostRecentCall.args[0]())
expect(mockRootScope.$watch.calls.mostRecent().args[0]())
.toEqual('Test name');
});
it("sets the title to the name of the navigated object", function () {
mockRootScope.$watch.mostRecentCall.args[1]("Some name");
mockRootScope.$watch.calls.mostRecent().args[1]("Some name");
expect(mockDocument[0].title).toEqual("Some name");
});