How to provide mock files to change event of <input type='file'> for unit testing

前端 未结 4 428
死守一世寂寞
死守一世寂寞 2021-01-03 21:21

I\'m having difficulties with a unit test in which I want to verify the processing of a file, which would usually be selected in the view via

相关标签:
4条回答
  • 2021-01-03 21:31

    UPDATE: Thanks to @PeteBD,

    Since angularjs version 1.2.22, the jqLite are now support passing a custom event object to triggerHandler(). See: d262378b


    If you are using only jqLite,

    the triggerHandler() will never work as it will pass a dummy event object to handlers.

    The dummy event object look like this (copied from jqLite.js#L962)

    {
      preventDefault: noop,
      stopPropagation: noop
    }
    

    As you can see, it doesn't even have a target property.

    If you are using jQuery,

    you could trigger an event with a custom event object like this:

    input.triggerHandler({
      type: 'change',
      target: {
        files: fileList
      }
    });
    

    and the evt.target.files will be the fileList as you are expecting.

    Hope this helps.

    0 讨论(0)
  • 2021-01-03 21:33

    Your file change handler should probably be a function directly on your controller. You can bind that function to the change event either from the HTML or a directive. That way you can call your handler function directly without worrying about triggering an event. This egghead.io video covers a couple ways you can do that: https://egghead.io/lessons/angularjs-file-uploads

    There are a lot of things you need to worry about when rolling your own file uploader with Angular so I would just use one of the existing libraries out there that takes care of it. e.g. angular-file-upload

    0 讨论(0)
  • 2021-01-03 21:47

    Let's rethink AngularJS, DOM must be handled in a directive

    We should not deal with DOM element in a controller, i.e. element.on('change', .., especially for testing purpose. In a controller, You talk to data, not to DOM.

    Thus, those onchange should be a directive like the following

    <input type="file" name='file' ng-change="fileChanged()" /> <br/>
    

    However, unfortunately, ng-change does not work well with type="file". I am not sure that the future version works with this or not. We still can apply the same method though.

    <input type="file" 
      onchange="angular.element(this).scope().fileChanged(this.files)" />
    

    and in the controller, we just simply define a method

    $scope.fileChanged = function(files) {
      return files.0.length < 500000;
    };
    

    Now, everything is just a normal controller test. No more dealing with angular.element, $compile, triggers, etc.! :)

    describe(‘MyCtrl’, function() {
      it('does check files', inject(
        function($rootScope, $controller) {
          scope = $rootScope.new();
          ctrl = $controller(‘UploadCtrl’, {‘$scope’: scope});
    
          var files = { 0: {name:'foo', size: 500001} };
          expect(scope.fileChanged(files)).toBe(true);
        }
      ));
    });
    

    http://plnkr.co/edit/1J7ETus0etBLO18FQDhK?p=preview

    0 讨论(0)
  • 2021-01-03 21:51

    Here is an example spec for input file/image using angular2+.

    it('should call showError on toastService Api on call of onSaveOfImage() method', () => {
    
        spyOn(component.commonFacade.fileIOApi, 'uploadFile');
        let file = new File([new ArrayBuffer(2e+5)], 'test-file.jpg', { lastModified: null, type: 'image/jpeg' });
        let fileInput={ files: [file] };
        component['onSaveOfImage'](fileInput,"",null,"","");
        expect(component.commonFacade.fileIOApi.uploadFile).toHaveBeenCalledTimes(1);
        expect(component.uploadedFileData).toBeUndefined();
        expect(component.commonFacade.employeeApi.toastService.showError).toHaveBeenCalledTimes(1);
      })
    
    0 讨论(0)
提交回复
热议问题