diff --git a/app/directives/tc-file-input/tc-file-input.directive.js b/app/directives/tc-file-input/tc-file-input.directive.js index a7cb39c21..bc4a18554 100644 --- a/app/directives/tc-file-input/tc-file-input.directive.js +++ b/app/directives/tc-file-input/tc-file-input.directive.js @@ -28,8 +28,8 @@ var fileInput = $(element[0]).find('.none'); var fileNameInput = $(element[0]).find('input[type=text]'); - fileInput.bind('change', function() { - var file = fileInput[0].files[0]; + fileInput.bind('change', function(event) { + var file = event.target.files[0]; // About 1 in 20 times, the file is undefined (must be race condition) // Return early in this case so no errors are thrown diff --git a/app/directives/tc-file-input/tc-file-input.spec.js b/app/directives/tc-file-input/tc-file-input.spec.js index 3f2b398aa..ef1917cc8 100644 --- a/app/directives/tc-file-input/tc-file-input.spec.js +++ b/app/directives/tc-file-input/tc-file-input.spec.js @@ -1,19 +1,148 @@ /* jshint -W117, -W030 */ describe('Topcoder File Input Directive', function() { - var scope; - - // USE AS TEMPLATE FOR DIRECTIVES + var scope, element, isolateScope, fileInput; beforeEach(function() { - bard.appModule('tcUIComponents'); + bard.appModule('topcoder'); bard.inject(this, '$compile', '$rootScope'); + scope = $rootScope.$new(); + + var html = '' + + '<form>' + + '<tc-file-input ' + + 'label-text="Preview Image"' + + 'field-id="DESIGN_COVER"' + + 'button-text="Add File"' + + 'file-type="jpg,jpeg,png"' + + 'placeholder="Image file as .jpg or .png"' + + 'mandatory="true"' + + 'set-file-reference="vm.setFileReference(file, fieldId)"' + + 'ng-model="vm.submissionForm.submissionZip"' + + ' />' + + '</form>'; + var form = angular.element(html); + element = form.find('tc-file-input'); + var formElement = $compile(form)(scope); + scope.$digest(); + + isolateScope = element.isolateScope(); + }); + + beforeEach(function() { + fileInput = $(element).find('.none')[0]; + }); + + afterEach(function() { + scope.$destroy(); + fileInput = undefined; }); bard.verifyNoOutstandingHttpRequests(); - xdescribe('', function() { - beforeEach(function() {}); + describe('selectFile', function() { + it('triggers a click on the file input', function() { + var mockClick = sinon.spy(fileInput, 'click'); + + isolateScope.selectFile(); + scope.$digest(); + + expect(mockClick).calledOnce; + }); + }); + + describe('a change event on the file input', function() { + var fileNameInput, fileList, mockSetFileReference; + + beforeEach(function() { + fileNameInput = $(element).find('input[type=text]')[0]; + fileList = { + 0: { + name: 'test.png', + size: 50, + type: 'image/png' + }, + length: 1, + item: function (index) { return file; } + }; + + mockSetFileReference = sinon.spy(isolateScope, 'setFileReference'); + }); + + afterEach(function() { + fileNameInput = undefined; + fileList = undefined; + mockSetFileReference = undefined; + }); + + it('sets the value of the fileNameInput with the name of the file', function() { + $(fileInput).triggerHandler({ + type: 'change', + target: { files: fileList } + }); + + expect(fileNameInput.value).to.equal('test.png'); + }); + + describe('with a valid file', function() { + beforeEach(function() { + $(fileInput).triggerHandler({ + type: 'change', + target: { files: fileList } + }); + }); + + it('calls setFileReference', function() { + expect(mockSetFileReference).calledOnce; + }); + + it('has ng-valid-filesize class', function() { + expect($(fileInput).hasClass('ng-valid-filesize')).to.be.true; + }); + + it('has ng-valid-required class', function() { + expect($(fileInput).hasClass('ng-valid-required')).to.be.true; + }); + }); + + describe('with a file that\'s greater than 500MB', function() { + beforeEach(function() { + fileList[0].size = 500000001; + + $(fileInput).triggerHandler({ + type: 'change', + target: { files: fileList } + }); + }); + + it('does not call setFileReference', function() { + expect(mockSetFileReference).not.calledOnce; + }); + + it('has ng-touched and ng-invalid-filesize classes', function() { + expect($(fileInput).hasClass('ng-invalid-filesize')).to.be.true; + expect($(fileInput).hasClass('ng-touched')).to.be.true; + }); + }); + + describe('with a file type that\'s not in the list of fileTypes given to the directive', function() { + beforeEach(function() { + fileList[0].type = 'application/zip'; + + $(fileInput).triggerHandler({ + type: 'change', + target: { files: fileList } + }); + }); + + it('does not call setFileReference', function() { + expect(mockSetFileReference).not.calledOnce; + }); + + it('has ng-touched and ng-invalid-required classes', function() { + expect($(fileInput).hasClass('ng-invalid-required')).to.be.true; + expect($(fileInput).hasClass('ng-touched')).to.be.true; + }); + }); - it('', function() {}); }); }); diff --git a/app/directives/tc-form-fonts/tc-form-fonts.spec.js b/app/directives/tc-form-fonts/tc-form-fonts.spec.js index 8f0c5de95..8b7019756 100644 --- a/app/directives/tc-form-fonts/tc-form-fonts.spec.js +++ b/app/directives/tc-form-fonts/tc-form-fonts.spec.js @@ -15,6 +15,10 @@ describe('Topcoder Form Fonts Directive', function() { isolateScope = element.isolateScope(); }); + afterEach(function() { + scope.$destroy(); + }); + bard.verifyNoOutstandingHttpRequests(); describe('is initialized with', function() { diff --git a/app/directives/tc-form-stockart/tc-form-stockart.spec.js b/app/directives/tc-form-stockart/tc-form-stockart.spec.js index ccdf6d1c6..ed4429ce4 100644 --- a/app/directives/tc-form-stockart/tc-form-stockart.spec.js +++ b/app/directives/tc-form-stockart/tc-form-stockart.spec.js @@ -15,6 +15,10 @@ describe('Topcoder Form Stockart Directive', function() { isolateScope = element.isolateScope(); }); + afterEach(function() { + scope.$destroy(); + }); + bard.verifyNoOutstandingHttpRequests(); describe('is initialized with', function() { diff --git a/app/directives/tc-input/tc-input.spec.js b/app/directives/tc-input/tc-input.spec.js index 56e369efe..d7e481353 100644 --- a/app/directives/tc-input/tc-input.spec.js +++ b/app/directives/tc-input/tc-input.spec.js @@ -11,6 +11,10 @@ describe('Topcoder Input Directive', function() { scope.$digest(); }); + afterEach(function() { + scope.$destroy(); + }); + bard.verifyNoOutstandingHttpRequests(); it('should set inputType to text if no inputType given', function() { diff --git a/app/specs.html b/app/specs.html index 1c1199ee6..eb19c8329 100644 --- a/app/specs.html +++ b/app/specs.html @@ -270,6 +270,7 @@ <h1><a href="specs.html">Spec Runner</a></h1> <script src="/app/my-dashboard/my-dashboard.spec.js"></script> <script src="/app/my-srms/my-srms.spec.js"></script> <script src="/app/profile/profile.controller.spec.js"></script> + <script src="/app/settings/settings.spec.js"></script> <script src="/app/services/authToken.service.spec.js"></script> <script src="/app/services/challenge.service.spec.js"></script> <script src="/app/services/externalAccounts.service.spec.js"></script> @@ -280,12 +281,11 @@ <h1><a href="specs.html">Spec Runner</a></h1> <script src="/app/services/tcAuth.service.spec.js"></script> <script src="/app/services/user.service.spec.js"></script> <script src="/app/services/userStats.service.spec.js"></script> - <script src="/app/settings/settings.spec.js"></script> <script src="/app/skill-picker/skill-picker.spec.js"></script> <script src="/app/submissions/submissions.spec.js"></script> <script src="/app/account/login/login.spec.js"></script> - <script src="/app/account/register/register.spec.js"></script> <script src="/app/account/logout/logout.controller.spec.js"></script> + <script src="/app/account/register/register.spec.js"></script> <script src="/app/account/reset-password/reset-password.spec.js"></script> <script src="/app/blocks/exception/exception-handler.provider.spec.js"></script> <script src="/app/directives/badges/badge-tooltip.spec.js"></script>