From fef1d356ec8bacf125eaa04e8b1808fe7905f8e8 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Tue, 1 Sep 2020 16:55:44 -0500 Subject: [PATCH] Fix tests failures that only fail on github travis-ci. Also add initial standard test files. --- ...viceDetailFeatureProposalListController.js | 26 +- app/repo/userRepo.js | 12 +- karma.conf.js | 4 + tests/core/mocks/mockAbstractCoreModel.js | 112 +++++++ tests/core/mocks/mockAbstractCoreRepo.js | 308 ++++++++++++++++++ tests/core/mocks/mockAbstractCoreService.js | 15 + tests/core/utility/coreUtility.js | 127 ++++++++ tests/core/utility/testUtility.js | 3 + tests/mocks/repo/mockUserRepo.js | 22 +- tests/testSetup.js | 4 +- 10 files changed, 613 insertions(+), 20 deletions(-) create mode 100644 tests/core/mocks/mockAbstractCoreModel.js create mode 100644 tests/core/mocks/mockAbstractCoreRepo.js create mode 100644 tests/core/mocks/mockAbstractCoreService.js create mode 100644 tests/core/utility/coreUtility.js create mode 100644 tests/core/utility/testUtility.js diff --git a/app/controllers/detail/service/serviceDetailFeatureProposalListController.js b/app/controllers/detail/service/serviceDetailFeatureProposalListController.js index 078c50c9..8bdc44b2 100644 --- a/app/controllers/detail/service/serviceDetailFeatureProposalListController.js +++ b/app/controllers/detail/service/serviceDetailFeatureProposalListController.js @@ -32,17 +32,19 @@ app.controller('ServiceDetailFeatureProposalListController', function ($controll }, 500); }); - if (!$scope.isAnonymous()) { - UserRepo.getUser().then(function (res) { - var apiRes = angular.fromJson(res.body); - if (apiRes.meta.status === 'SUCCESS') { - $scope.user = apiRes.payload.User; - $scope.hasVoted = function (fp) { - return fp.voters.map(function(v) { return v.id; }).indexOf($scope.user.id) >= 0; - }; - } - }); - } + UserRepo.ready().then(function () { + if (!$scope.isAnonymous()) { + UserRepo.getUser().then(function (res) { + var apiRes = angular.fromJson(res.body); + if (apiRes.meta.status === 'SUCCESS') { + $scope.user = apiRes.payload.User; + $scope.hasVoted = function (fp) { + return fp.voters.map(function(v) { return v.id; }).indexOf($scope.user.id) >= 0; + }; + } + }); + } + }); $scope.isVotingOpen = function (featureProposal) { return !$scope.isAnonymous() && featureProposal.state === FeatureProposalState.ACTIVE.value; @@ -58,4 +60,4 @@ app.controller('ServiceDetailFeatureProposalListController', function ($controll }); }; -}); \ No newline at end of file +}); diff --git a/app/repo/userRepo.js b/app/repo/userRepo.js index babc40bf..1d831849 100644 --- a/app/repo/userRepo.js +++ b/app/repo/userRepo.js @@ -1,9 +1,11 @@ app.repo("UserRepo", function UserRepo(WsApi) { - this.getUser = function () { - return WsApi.fetch(this.mapping.getUser); - }; + var userRepo = this; - return this; + userRepo.getUser = function () { + return WsApi.fetch(this.mapping.getUser); + }; -}); \ No newline at end of file + return userRepo; + +}); diff --git a/karma.conf.js b/karma.conf.js index fe23f93b..7a138773 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -118,6 +118,10 @@ module.exports = function (config) { 'app/repo/**/*.js', + 'app/views/**/*.html', + + 'tests/core/**/*.js', + 'tests/mocks/**/*.js', 'tests/unit/**/*.js' diff --git a/tests/core/mocks/mockAbstractCoreModel.js b/tests/core/mocks/mockAbstractCoreModel.js new file mode 100644 index 00000000..b1ddcf2f --- /dev/null +++ b/tests/core/mocks/mockAbstractCoreModel.js @@ -0,0 +1,112 @@ +var mockModel = function (modelName, $q, mockDataObj) { + var model = {}; + var shadow = {}; + var combinationOperation = ""; + + model.isDirty = false; + model.isValid = false; + + model.mock = function (toMock) { + if (typeof toMock === "object") { + var keys = Object.keys(toMock); + for (var i in keys) { + model[keys[i]] = toMock[keys[i]]; + } + } else if (toMock === undefined || toMock === null) { + model = null; + } + }; + + model.mockShadow = function (toMock) { + shadow = toMock; + }; + + model.acceptPendingUpdate = function () { + }; + + model.acceptPendingDelete = function () { + }; + + model.before = function () { + }; + + model.clearListens = function () { + var payload = {}; + return payloadPromise($q.defer(), payload); + }; + + model.clearValidationResults = function () { + }; + + model.delete = function () { + return payloadPromise($q.defer(), true); + }; + + model.dirty = function (boolean) { + if (boolean !== undefined) { + model.isDirty = boolean; + } + + return model.isDirty; + }; + + model.enableMergeCombinationOperation = function () { + combinationOperation = "merge"; + }; + + model.enableExtendCombinationOperation = function () { + combinationOperation = "extend"; + }; + + model.fetch = function () { + return payloadPromise($q.defer(), mockDataObj); + }; + + model.getCombinationOperation = function () { + return combinationOperation; + }; + + model.getEntityName = function () { + return modelName; + }; + + model.getValidations = function () { + return null; + }; + + model.init = function (data, apiMapping) { + }; + + model.listen = function () { + }; + + model.ready = function () { + var defer = $q.defer(); + defer.resolve(); + return defer.promise; + }; + + model.refresh = function () { + angular.extend(model, shadow); + }; + + model.reload = function () { + var defer = $q.defer(); + defer.resolve(model); + return defer.promise; + }; + + model.save = function () { + return payloadPromise($q.defer(), true); + }; + + model._syncShadow = function () { + model.isDirty = false; + shadow = angular.copy(model); + }; + + model.mock(mockDataObj); + model._syncShadow(); + + return model; +}; diff --git a/tests/core/mocks/mockAbstractCoreRepo.js b/tests/core/mocks/mockAbstractCoreRepo.js new file mode 100644 index 00000000..747c0668 --- /dev/null +++ b/tests/core/mocks/mockAbstractCoreRepo.js @@ -0,0 +1,308 @@ +var mockRepo = function (repoName, $q, mockModelCtor, mockDataArray) { + var repo = {}; + + var validations = {}; + + var validationResults = {}; + + var originalList; + + // set to TRUE to enable mocked models to be returned as the original object instead of a copy. + repo.mockSpyAssist = false; + + repo.mockedList = []; + + repo.mock = function (toMock) { + repo.mockedList = []; + originalList = []; + + if (typeof mockModelCtor === "function" && typeof toMock === "object") { + for (var i in toMock) { + var model = repo.mockModel(toMock[i]); + repo.mockedList.push(model); + originalList.push(model); + } + } + }; + + repo.mockCopy = function (toCopy) { + if (repo.mockSpyAssist) { + return toCopy; + } + + return angular.copy(toCopy); + }; + + repo.mockModel = function (toMock) { + if (typeof mockModelCtor === "function") { + var mocked = new mockModelCtor($q); + mocked.mock(toMock); + return mocked; + } + + return toMock; + }; + + repo.mockValidations = function (toMock) { + if (typeof toMock === "object") { + validations = toMock; + } else { + validations = {}; + } + }; + + repo.mock(mockDataArray); + + repo.scaffold = {}; + + repo.acceptChangesPending = function () { + }; + + repo.add = function (modelJson) { + if (!repo.contains(modelJson)) { + repo.mockedList.push(modelJson); + } + }; + + repo.addAll = function (modelJsons) { + for (var i in modelJsons) { + repo.add(modelJsons[i]); + } + }; + + repo.changesPending = function () { + return false; + }; + + repo.clearValidationResults = function () { + validationResults = {}; + }; + + repo.create = function (model) { + if (repo.mockedList === undefined) { + repo.mockedList = []; + } + + model.id = repo.mockedList.length + 1; + repo.mockedList.push(repo.mockCopy(model)); + return payloadPromise($q.defer(), model); + }; + + repo.contains = function (model) { + var found = false; + for (var i in repo.mockedList) { + if (repo.mockedList[i].id === model.id) { + found = true; + break; + } + } + return found; + }; + + repo.count = function () { + return repo.mockedList.length; + }; + + repo.delete = function (model) { + for (var i in repo.mockedList) { + if (repo.mockedList[i].id === model.id) { + repo.mockedList.splice(i, 1); + break; + } + } + + return payloadPromise($q.defer()); + }; + + repo.deleteById = function (id) { + for (var i in repo.mockedList) { + if (repo.mockedList[i].id === id) { + repo.mockedList.splice(i, 1); + break; + } + } + + return payloadPromise($q.defer()); + }; + + repo.empty = function () { + repo.list.length = 0; + }; + + repo.fetch = function () { + return payloadPromise($q.defer(), mockDataArray); + }; + + repo.findById = function (id) { + var found; + for (var i in repo.mockedList) { + if (repo.mockedList[i].id == id) { + found = repo.mockCopy(repo.mockedList[i]); + } + } + + return found; + }; + + repo.getAll = function () { + return repo.mockCopy(repo.mockedList); + }; + + repo.getAllFiltered = function (predicate) { + var filteredData = []; + + angular.forEach(repo.list, function (datum) { + if (predicate(datum)) { + filteredData.push(datum); + } + }); + + return filteredData; + }; + + repo.getScaffold = function (defaults) { + var updatedScaffold = repo.scaffold; + + if (!defaults) defaults = {}; + angular.extend(updatedScaffold, defaults); + + return updatedScaffold; + }; + + repo.isInScaffold = function (property) { + var propertyFound = false; + var scaffoldKeys = Object.keys(repo.scaffold); + + for (var i in scaffoldKeys) { + var scaffoldProperty = scaffoldKeys[i]; + if (scaffoldProperty === property) { + propertyFound = true; + break; + } + } + + return propertyFound; + }; + + repo.getContents = function () { + return repo.mockCopy(repo.mockedList); + }; + + repo.getEntityName = function () { + return repoName; + }; + + repo.getValidations = function () { + return repo.mockCopy(validations); + }; + + repo.getValidationResults = function () { + return repo.mockCopy(validationResults); + }; + + repo.listen = function (cbOrActionOrActionArray, cb) { + if (typeof cbOrActionOrActionArray === "function") { + var apiRes = { + meta: { + status: "SUCCESS", + message: "" + }, + status: 200 + }; + cbOrActionOrActionArray(apiRes); + } else if (Array.isArray(cbOrActionOrActionArray)) { + for (var cbAction in cbOrActionOrActionArray) { + if (typeof cbAction === "function") { + cbAction(); + } + } + } else if (typeof cb === "function") { + cb(); + } + + return payloadPromise($q.defer()); + }; + + repo.ready = function () { + return payloadPromise($q.defer(), mockDataArray); + }; + + repo.remove = function (modelToRemove) { + if (typeof modelToRemove === "object") { + for (var i in repo.mockedList) { + if (repo.mockedList[i].id === modelToRemove.id) { + repo.mockedList.splice(i, 1); + break; + } + } + } + }; + + repo.reorder = function (src, dest) { + var payload = {}; + return payloadPromise($q.defer(), payload); + }; + + repo.reset = function () { + repo.mockedList = repo.originalList; + return payloadPromise($q.defer()); + }; + + repo.save = function (modelToSave) { + if (typeof modelToSave === "object") { + var isNew = true; + var savedModel = repo.mockModel(modelToSave); + + for (var i in repo.mockedList) { + if (repo.mockedList[i].id === modelToSave.id) { + angular.extend(repo.mockedList[i], savedModel); + isNew = false; + break; + } + } + + if (isNew) { + repo.mockedList[repo.mockedList.length] = savedModel; + } + + return payloadPromise($q.defer(), savedModel); + } + + return rejectPromise($q.defer()); + }; + + repo.saveAll = function () { + angular.forEach(repo.mockedList, function (model) { + repo.save(model); + }); + }; + + repo.setToDelete = function (id) { + }; + + repo.setToUpdate = function (id) { + }; + + repo.sort = function (guarantor, facet) { + var payload = {}; + return payloadPromise($q.defer(), payload); + }; + + repo.unshift = function (modelJson) { + }; + + repo.update = function (model) { + var updated; + for (var i in repo.mockedList) { + if (repo.mockedList[i].id === model.id) { + angular.extend(repo.mockedList[i], model); + updated = repo.mockCopy(repo.mockedList[i]); + break; + } + } + + return payloadPromise($q.defer(), updated); + }; + + return repo; +}; diff --git a/tests/core/mocks/mockAbstractCoreService.js b/tests/core/mocks/mockAbstractCoreService.js new file mode 100644 index 00000000..3dc3ed94 --- /dev/null +++ b/tests/core/mocks/mockAbstractCoreService.js @@ -0,0 +1,15 @@ +var mockService = function ($q, mockModelCtor) { + var service = {}; + + service.mockModel = function (toMock) { + if (typeof mockModelCtor === "function") { + var mocked = new mockModelCtor($q); + mocked.mock(toMock); + return mocked; + } + + return toMock; + }; + + return service; +}; diff --git a/tests/core/utility/coreUtility.js b/tests/core/utility/coreUtility.js new file mode 100644 index 00000000..ac1798f9 --- /dev/null +++ b/tests/core/utility/coreUtility.js @@ -0,0 +1,127 @@ +// provide common helper methods to be used by mocks. + +var buildPayloadPromiseBody = function (payload, messageStatus, httpStatus, action) { + var body = { + meta: { + status: messageStatus ? messageStatus : "SUCCESS", + }, + payload: payload, + status: httpStatus ? httpStatus : 200 + }; + + if (action) { + body.meta.action = action; + } + + return body; +}; + +var buildMessagePromiseBody = function (message, messageStatus, httpStatus, action) { + var body = { + meta: { + status: messageStatus ? messageStatus : "SUCCESS", + }, + message: message, + status: httpStatus ? httpStatus : 200 + }; + + if (action) { + body.meta.action = action; + } + + return body; +}; + +var messagePromise = function (defer, message, messageStatus, httpStatus, action) { + defer.resolve({ + body: angular.toJson(buildMessagePromiseBody(message, messageStatus, httpStatus, action)) + }); + + return defer.promise; +}; + +var valuePromise = function (defer, model, type, timeout) { + if (type === "reject") { + defer.reject(model); + } else if (type === "notify") { + timeout(function () { + defer.notify(model); + }, 0); + } else { + defer.resolve(model); + } + + return defer.promise; +}; + +var payloadPromise = function (defer, payload, messageStatus, httpStatus, action) { + defer.resolve({ + body: angular.toJson(buildPayloadPromiseBody(payload, messageStatus, httpStatus, action)) + }); + + return defer.promise; +}; + +var dataPromise = function (defer, payload, messageStatus, httpStatus, action) { + defer.resolve({ + data: buildPayloadPromiseBody(payload, messageStatus, httpStatus, action) + }); + + return defer.promise; +}; + +var rejectPromise = function (defer, payload, messageStatus, httpStatus, action) { + defer.reject({ + body: angular.toJson(buildPayloadPromiseBody(payload, messageStatus ? messageStatus : "INVALID", httpStatus ? httpStatus : 200, action)) + }); + + return defer.promise; +}; + +var failurePromise = function (defer, payload, messageStatus, httpStatus, action) { + defer.reject({ + data: buildPayloadPromiseBody(payload, messageStatus ? messageStatus : "INVALID", httpStatus ? httpStatus : 500, action) + }); + + return defer.promise; +}; + +var notifyPromise = function (timeout, defer, payload, messageStatus, httpStatus, action) { + timeout(function () { + defer.notify({ + body: angular.toJson(buildPayloadPromiseBody(payload, messageStatus, httpStatus, action ? action : "BROADCAST")) + }); + }, 0); + + return defer.promise; +}; + +var mockParameterModel = function ($q, mockModel) { + return function (toMock) { + var model = new mockModel($q); + model.mock(toMock); + return model; + }; +}; + +var mockParameterConstructor = function (mockConstructor) { + return function () { return mockConstructor; }; +}; + +var mockWindow = function () { + return { + location: { + href: "", + replace: function () {} + } + }; +}; + +var mockForms = function () { + return { + $pristine: true, + $untouched: true, + $setPristine: function (value) { this.$pristine = value; }, + $setUntouched: function (value) { this.$untouched = value; } + }; +}; diff --git a/tests/core/utility/testUtility.js b/tests/core/utility/testUtility.js new file mode 100644 index 00000000..e85fe4fe --- /dev/null +++ b/tests/core/utility/testUtility.js @@ -0,0 +1,3 @@ +// provide tests or parts of tests that are commonly performed. + +var testUtility = {}; diff --git a/tests/mocks/repo/mockUserRepo.js b/tests/mocks/repo/mockUserRepo.js index 9a9f955e..0519f8f9 100644 --- a/tests/mocks/repo/mockUserRepo.js +++ b/tests/mocks/repo/mockUserRepo.js @@ -68,5 +68,25 @@ var mockUserRepo3 = { }; angular.module('mock.userRepo', []).service('UserRepo', function ($q) { - return this; + var userRepo = this; + var defer; + + var payloadResponse = function (payload) { + return defer.resolve({ + body: angular.toJson({ + meta: { + status: 'SUCCESS' + }, + payload: payload + }) + }); + }; + + userRepo.ready = function () { + defer = $q.defer(); + payloadResponse(); + return defer.promise; + }; + + return userRepo; }); diff --git a/tests/testSetup.js b/tests/testSetup.js index 83fbf7a6..876093dc 100644 --- a/tests/testSetup.js +++ b/tests/testSetup.js @@ -1,3 +1,3 @@ function setUpApp(bootstrapApp) { - bootstrapApp(); -} \ No newline at end of file + bootstrapApp(); +}