How to mock a ref variable so that we can test conditions based on it? - unit-testing

I have an file input element which is bound to a ref variable. Based on the files uploaded, in the onChange event, the file contents are processed . Currently I am writing unit test cases to test this functionality.
App.js
export class Dashboard extends React.Component {
constructor(props) {
this.uploadFile = React.createRef();
//Constructing...
}
readFileContents() {
const files = this.uploadFile.current.files;
for (let key in files) {
if (files.hasOwnProperty(key)) {
const file = files[key];
const reader = new FileReader();
let settings;
// eslint-disable-next-line no-loop-func
reader.onload = e => {
const extension = file.name.split('.')[1];
//OnLoad Handler
};
console.log(this.uploadFile.current.files)
reader.readAsText(file); //TypeError: Failed to execute 'readAsText' on 'FileReader': parameter 1 is not of type 'Blob'.
}
}
};
render() {
return (
<div className="dashboard wrapper m-padding">
<div className="dashboard-header clearfix">
<input
type="file"
ref={this.uploadFile}
webkitdirectory="true"
mozdirectory="true"
hidden
onChange={this.readFileContents}
onClick={this.reset}
/>
<Button
outline
className="toggle-btn float-right"
onClick={this.openFileDialog}
>
Choose folder
</Button>
</div>
</div>
);
}
}
I started off with this stack overflow answer and was able to mock the FileReader.
I initially thought simulating the change event with the target files as below, will automatically reflect on the values for this.uploadFile .
const file = new Blob([fileContents], {type : 'application/json'});
var event = {"target": {"files": []}};
event.target.files.push(file);
DashboardWrapper.find('input').first().simulate('change', event);
But the behaviour wasnt as I expected and got the below error.
TypeError: Failed to execute 'readAsText' on 'FileReader': parameter 1 is not of type 'Blob'.
Following this I have been trying to change the files key in the ref variable directly from the test file, with no results and the same error.
I would like to first understand if my approach is right. If not, what is the right way to do it?

As far as I can understand, testing the actual file upload is not recommended in a unit test. After all, these inputs should be thoroughly tested already.
That being said, I had a similar requirement and I solved it like so (I am using VueJS and Jest, but the approach should be similar):
Code:
<img v-if="showLogo && currentFile" class="image-preview" :src="currentFile"/>
<input
class="file-input"
type="file"
ref="fileInput"
#change="handleFileUpload()"/>
Test:
it('should render the logo if it got uploaded', async () => {
const wrapper = shallowMount(ApplicationLogoUpload, {
store,
localVue,
propsData: {
showLogo: true
}
});
const fileInput = wrapper.find('.file-input');
const mockedGet = jest.fn();
mockedGet.mockReturnValue(['file1']);
Object.defineProperty(fileInput.element, 'files', {
get: mockedGet
});
fileInput.trigger('change');
const imagePreview = wrapper.find('.image-preview');
expect(imagePreview.attributes().src).toEqual('file1');
});
Most importantly, I mocked the uploaded files using
const mockedGet = jest.fn();
mockedGet.mockReturnValue(['file1']);
Object.defineProperty(fileInput.element, 'files', {
get: mockedGet
});
I trigger the upload by calling fileInput.trigger('change');
Afterwards, the assertion can be done: src being equal to the mocked file.

Related

How to replace `#computed` with setter returning new value with new native setters?

Problem
I've often used this kind of computed properties where the setter simply returns the new value :
#computed('args.myValue')
get myValue() {
return this.args.myValue;
}
set myValue(newValue) {
return newValue; // <==== this is no longer valid with native setter
}
This does few things :
Set initial value to args.myValue
Allow to change the value (typically through an <Input #value={{this.myValue}} />)
Restore the default value when args.myValue changes
The problem comes with native setters which can't return any value.
Notice I could probably find a "hackish" solution but I'd like to have code that follows new EmberJS conventions in order to avoid painfull later updates.
Things I tried
Manual caching
#tracked _myValue = null;
get myValue() {
return this._myValue || this.args.myValue;
}
set myValue(newValue) {
this._myValue = newValue;
}
This does not work because _myValue is always set after the first myValue=(newValue).
In order to make it work, there should be some kind of observer which resets it to null on args.myValue change.
Sadly, observers are no longer part of EmberJS with native classes.
{{unbound}} helper
<Input #value={{unbound this.myValue}} />
As expected, it does not work because it just doesn't update myValue.
{{unbound}} helper combined with event.target.value handling
<Input #value={{unbound this.myValue}} {{on "keyup" this.keyPressed}} />
get myValue() {
return this.args.myValue;
}
#action keyPressed(event) {
this.doStuffThatWillUpdateAtSomeTimeMyValue(event.target.value);
}
But the Input is still not updated when the args.myValue changes.
Initial code
Here is a more concrete use example :
Component
// app/components/my-component.js
export default class MyComponent extends Component {
#computed('args.projectName')
get projectName() {
return this.args.projectName;
}
set projectName(newValue) {
return newValue; // <==== this is no longer valid with native setter
}
#action
searchProjects() {
/* event key stuff omitted */
const query = this.projectName;
this.args.queryProjects(query);
}
}
{{! app/components/my-component.hbs }}
<Input #value={{this.projectName}} {{on "keyup" this.searchProjects}} />
Controller
// app/controllers/index.js
export default class IndexController extends Controller {
get entry() {
return this.model.entry;
}
get entryProjectName() {
return this.entry.get('project.name');
}
#tracked queriedProjects = null;
#action queryProjects(query) {
this.store.query('project', { filter: { query: query } })
.then((projects) => this.queriedProjects = projects);
}
#action setEntryProject(project) {
this.entry.project = project;
}
}
{{! app/templates/index.hbs }}
<MyComponent
#projectName={{this.entryProjectName}}
#searchProjects={{this.queryProjects}} />
When the queriedProjects are set in the controller, the component displays them.
When one of those search results is clicked, the controller updates the setEntryProject is called.
According to this Ember.js discussion :
Net, my own view here is that for exactly this reason, it’s often better to use a regular <input> instead of the <Input> component, and to wire up your own event listeners. That will make you responsible to set the item.quantity value in the action, but it also eliminates that last problem of having two different ways of setting the same value, and it also gives you a chance to do other things with the event handling.
I found a solution for this problem by using standard <input>, which seems to be the "right way" to solve it (I'll really appreciate any comment that tells me a better way) :
{{! app/components/my-component.hbs }}
<input value={{this.projectName}} {{on "keyup" this.searchProjects}} />
// app/components/my-component.js
#action
searchProjects(event) {
/* event key stuff omitted */
const query = event.target.value;
this.args.queryProjects(query);
}
If I needed to keep the input value as a property, I could have done this :
{{! app/components/my-component.hbs }}
<input value={{this.projectName}}
{{on "input" this.setProjectQuery}}
{{on "keyup" this.searchProjects}} />
// app/components/my-component.js
#action setProjectQuery(event) {
this._projectQuery = event.target.value;
}
#action
searchProjects( {
/* event key stuff omitted */
const query = this._projectQuery;
this.args.queryProjects(query);
}
EDIT
Notice the following solution has one downside : it does not provide a simple way to reset the input value to the this.projectName when it does not change, for example after a focusout.
In order to fix this, I've added some code :
{{! app/components/my-component.hbs }}
<input value={{or this.currentInputValue this.projectName}}
{{on "focusin" this.setCurrentInputValue}}
{{on "focusout" this.clearCurrentInputValue}}
{{on "input" this.setProjectQuery}}
{{on "keyup" this.searchProjects}} />
// app/components/my-component.js
// previous code omitted
#tracked currentInputValue = null;
#action setCurrentInputValue() {
this.currentInputValue = this.projectName;
}
#action clearCurrentInputValue() {
this.currentInputValue = null;
}
There is a quite generic and concise approach to this 2-source binding scenario with any interactive input element and beyond.
Considering your first attempt (»Manual Caching«):
we have a functional feedback loop through the getter and setter; no return value from the setter is required since it unconditionally triggers a bound getter (this._myValue doesn't need to be tracked)
a switch is needed to let a changing external preset value (this.args.myValue) inject into this loop
this is accomplished by a GUID hashmap based on the preset value that establishes a transient scope for the interactive input; thus, changing preset value injections and interative inputs overwrite each other:
// app/components/my-component.js
import Component from '#glimmer/component';
import { guidFor } from '#ember/object/internals';
export default class extends Component {
// external preset value by #stringArg
_myValue = new Map();
get myValue() {
let currentArg = this.args.stringArg || null;
let guid = guidFor(currentArg);
if (this._myValue.has(guid)) {
return this._myValue.get(guid)
}
else {
this._myValue.clear(); // (optional) avoid subsequent GUID reuse of primitive types (Strings)
return currentArg;
}
}
set myValue(value) {
this._myValue.set(guidFor(this.args.stringArg || null), value);
}
}
// app/components/my-component.hbs
<Input #value={{mut this.myValue}} />
https://ember-twiddle.com/a72fa70c472dfc54d03d040f0d849d17

Enzyme - How to access and set <input> value?

I'm confused about how to access <input> value when using mount. Here's what I've got as my test:
it('cancels changes when user presses esc', done => {
const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input');
console.log(input.render().attr('value'));
input.simulate('focus');
done();
});
The console prints out undefined. But if I slightly modify the code, it works:
it('cancels changes when user presses esc', done => {
const wrapper = render(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input');
console.log(input.val());
input.simulate('focus');
done();
});
Except, of course, the input.simulate line fails since I'm using render now. I need both to work properly. How do I fix this?
EDIT:
I should mention, <EditableText /> is not a controlled component. But when I pass defaultValue into <input />, it seems to set the value. The second code block above does print out the value, and likewise if I inspect the input element in Chrome and type $0.value in the console, it shows the expected value.
I think what you want is:
input.simulate('change', { target: { value: 'Hello' } })
Here's my source.
You shouldn't need to use render() anywhere to set the value. And just FYI, you are using two different render()'s. The one in your first code block is from Enzyme, and is a method on the wraper object mount and find give you. The second one, though it's not 100% clear, is probably the one from react-dom. If you're using Enzyme, just use shallow or mount as appropriate and there's no need for render from react-dom.
With Enzyme 3, if you need to change an input value but don't need to fire the onChange function you can just do this (node property has been removed):
wrapper.find('input').instance().value = "foo";
You can use wrapper.find('input').simulate("change", { target: { value: "foo" }}) to invoke onChange if you have a prop for that (ie, for controlled components).
Got it. (updated/improved version)
it('cancels changes when user presses esc', done => {
const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input');
input.simulate('focus');
input.simulate('change', { target: { value: 'Changed' } });
input.simulate('keyDown', {
which: 27,
target: {
blur() {
// Needed since <EditableText /> calls target.blur()
input.simulate('blur');
},
},
});
expect(input.get(0).value).to.equal('Hello');
done();
});
So lots of different opinions here. The only thing that worked for me was none of the above, it was using input.props().value. I hope that helps.
I'm using react with TypeScript and the following worked for me
wrapper.find('input').getDOMNode<HTMLInputElement>().value = 'Hello';
wrapper.find('input').simulate('change');
Setting the value directly
wrapper.find('input').instance().value = 'Hello'`
was causing me a compile warning.
I am using create-react-app which comes with jest by default and enzyme 2.7.0.
This worked for me:
const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input')[index]; // where index is the position of the input field of interest
input.node.value = 'Change';
input.simulate('change', input);
done();
None of the above worked for me. This is what worked for me on Enzyme ^3.1.1:
input.instance().props.onChange(({ target: { value: '19:00' } }));
Here is the rest of the code for context:
const fakeHandleChangeValues = jest.fn();
const fakeErrors = {
errors: [{
timePeriod: opHoursData[0].timePeriod,
values: [{
errorIndex: 2,
errorTime: '19:00',
}],
}],
state: true,
};
const wrapper = mount(<AccessibleUI
handleChangeValues={fakeHandleChangeValues}
opHoursData={opHoursData}
translations={translationsForRendering}
/>);
const input = wrapper.find('#input-2').at(0);
input.instance().props.onChange(({ target: { value: '19:00' } }));
expect(wrapper.state().error).toEqual(fakeErrors);
In case anyone is struggling, I found the following working for me
const wrapper = mount(<NewTask {...props} />); // component under test
const textField = wrapper.find(TextField);
textField.props().onChange({ target: { value: 'New Task 2' } })
textField.simulate('change');
// wrapper.update() didn't work for me, need to find element again
console.log(wrapper.find(TextField).props()); // New Task 2
It seems that you need to define what happens in the change event first and then simulate it (instead of simulating the change event with data)
This works for me using enzyme 2.4.1:
const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input');
console.log(input.node.value);
None of the solutions above worked for me because I was using Formik and I needed to mark the field "touched" along with changing the field value. Following code worked for me.
const emailField = orderPageWrapper.find('input[name="email"]')
emailField.simulate('focus')
emailField.simulate('change', { target: { value: 'test#example.com', name: 'email' } })
emailField.simulate('blur')
In my case i was using ref callbacks,
<input id="usuario" className="form-control" placeholder="Usuario"
name="usuario" type="usuario"
onKeyUp={this._validateMail.bind(this)}
onChange={()=> this._validateMail()}
ref={(val) =>{ this._username = val}}
>
To obtain the value.
So enzyme will not change the value of this._username.
So i had to:
login.node._username.value = "mario#com.com";
user.simulate('change');
expect(login.state('mailValid')).toBe(true);
To be able to set the value then call change . And then assert.
here is my code..
const input = MobileNumberComponent.find('input')
// when
input.props().onChange({target: {
id: 'mobile-no',
value: '1234567900'
}});
MobileNumberComponent.update()
const Footer = (loginComponent.find('Footer'))
expect(Footer.find('Buttons').props().disabled).equals(false)
I have update my DOM with componentname.update()
And then checking submit button validation(disable/enable) with length 10 digit.
I solved in a very simple way:
Set the value from props:
const wrapper: ShallowWrapper = shallow(<ProfileViewClass name: 'Sample Name' />);
Html code:
<input type='text' defaultValue={props.name} className='edituser-name' />
Access the attribute from wrapper.find(element).props().attribute-name:
it('should render user name', () => {
expect(wrapper.find('.edituser-name').props().defaultValue).toContain(props.name);
});
Cheers
This worked for me:
let wrapped = mount(<Component />);
expect(wrapped.find("input").get(0).props.value).toEqual("something");
I use Wrapper's setValue[https://vue-test-utils.vuejs.org/api/wrapper/#setvalue-value] method to set value.
inputA = wrapper.findAll('input').at(0)
inputA.setValue('123456')
.simulate() doesn't work for me somehow, I got it working with just accessing the node.value without needing to call .simulate(); in your case:
const wrapper = mount(<EditableText defaultValue="Hello" />);
const input = wrapper.find('input').at(0);
// Get the value
console.log(input.node.value); // Hello
// Set the value
input.node.value = 'new value';
// Get the value
console.log(input.node.value); // new value
Hope this helps for others!

React/Jasmine/Karma/Phantom Unit Test: findDOMNode and renderIntoDocument not working as expected

I'm trying to write a simple unit test and can't seem to figure it out. I want to test a bootstrap modal to ensure it displays the correct contents when I pass certain object properties to it. Here's what my modal code looks like:
import React, { Component, PropTypes } from 'react';
import { Button, Modal } from 'react-bootstrap';
class ModalBox extends Component {
render() {
const { modalBox } = this.props;
let content;
if (modalBox.contentBody) {
content = modalBox.contentBody;
} else {
content = (
<span>
<Modal.Header closeButton onHide={this.close.bind(this)}>
<Modal.Title>{modalBox.title}</Modal.Title>
</Modal.Header>
<Modal.Body>
{modalBox.message}
</Modal.Body>
{modalBox.isConfirm &&
<Modal.Footer>
<Button onClick={modalBox.onCancel} className="modal-button cancel">{modalBox.cancelText || 'Cancel'}</Button>
<Button onClick={modalBox.onConfirm} className="modal-button confirm">{modalBox.confirmText || 'Confirm'}</Button>
</Modal.Footer>
}
</span>
);
}
return (
<Modal show={typeof modalBox != 'undefined'} onHide={this.close.bind(this)} dialogClassName={modalBox.dialogClassName || ''} backdrop={modalBox.backdrop || true}>
{content}
</Modal>
);
}
}
So for a test, I want to make sure that if I pass the prop modalBox containing the contentBody field that it just returns the contentBody for the modal body. Here's an example of what I'm trying to test:
it("renders only contentBody when provided", () => {
let modalBoxObj = {
contentBody: <div className="test-content-body">This is a test.</div>
};
let element = React.createElement(ModalBox, {modalBox: modalBoxObj});
let component = TestUtils.renderIntoDocument(element);
let modalWrapper = TestUtils.scryRenderedDOMComponentsWithClass(component, 'modal');
// modalWrapper returns an empty array, so this returns "Expected 0 to be 1"
expect(modalWrapper.length).toBe(1);
let testBody = TestUtils.scryRenderedDOMComponentsWithClass(component, 'test-content-body');
// testBody returns an empty array, so this returns "Expected 0 to be 1"
expect(testBody.length).toBe(1);
// this returns "TypeError: 'undefined' is not an object (evaluating 'testBody[0].innerHTML')"
expect(testBody[0].innerHTML).toEqual("This is a test.");
}
I've also tried doing shallow rendering with TestUtils.createRenderer and trying that approach, but had no luck with it. Based on the examples I've seen online and previous testing experience with react <0.14, I feel this test should work. I just don't know what I'm missing or misunderstanding. In the past, I did something like below and just looked at the componentNode object to find elements and such, but componentNode is returning null.
let component = TestUtils.renderIntoDocument(element);
let componentNode = findDOMNode(component);
Thanks for your help!
The solution ended up being to add a ref to the ModalBox component. Once added, we were able to target the node like this:
let component = TestUtils.renderIntoDocument(<ModalBox modalBox={modalBoxObj} />);
let componentNode = findDOMNode(component.refs.modalBox._modal);

angularjs not responding the GET method

i am relatively new in django and angualarJs.The problem is that angularJs is not responding the get method properly.I have a webpage developed by django where i have a search field.For the execution of search i use a angularJs functionality that is ng-submit and write angularJs code to return value using get method.May be i made a mistake here.you can see my code... here is my template which containing the angularJs also...
<div class="navbar navbar-default " ng-controller="NavCtrl">
<form action="" class="navbar-form navbar-right" ng-submit="search()">
<input class="form-control col-lg-8" type="text" placeholder="Search" ng-model="term"></input>
</form>
</div>
<script>
app.controller("NavCtrl", ['$scope', '$http', '$location', '$q', '$timeout',
function NavCtrl($scope, $http, $location, $q, $timeout) {
$scope.results = ["Test"];
$scope.term = "";
$scope.reqs = "5";
$scope.pics = "45";
$scope.ddata = "asdasd";
$scope.ddata = $http.post("{% url 'get-nav-info' %}").success(
function (result) {
//$scope.reqs = result.data.data.num_request;
//$scope.pics = result.data.data.num_photo;
return result.data;
}
);
//$scope.reqs = $scope.ddata.num_request;
//$scope.pics = $scope.ddata.num_photo;
$scope.search = function () {
//alert("test");
//$location.absUrl("{% url 'search-term-show' %}").search({'term':$scope.term}).apply();
//$location.path("{% url 'search-term-show' %}").search({'term':$scope.term}).apply();
$http.get("{% url 'search-term-show' %}?term=" + $scope.term).success(function (result) {
return result.data;
});
//$scope.$apply();
}
}
]);
</script>
now the problem is that while i press enter ,there is no result,but if i manually write this URL which is http://www.kothay.com/searchphoto/?term=a in the address bar then the result is showing .In mention,this url is the that url which should be appear in the address bar when i press the enter to search my photos.But with the enter press its not appearing in the address bar and that's why the results are not showing.I hope you can understand what i am trying to say.May be there is a mistake in my code.Please help me to fix this problem.
You are doing thing wrong.
1st, the success is a defer of get, so return result.data and returns it to the get deferred and there it goes to the heaven. So if you would like to keep the current architecture it should look more like this
$scope.search = [];
getsearch = function () {
$http.get("{% url 'search-term-show' %}?term=" + $scope.term).success(function (result) {
$scope.search = result.data;
});
};
getsearch();
2nd that can still not update your UI cuz if the ctrl function is over and the digest is over before your response it wont update your UI cuz its in another scope (not $scope, but the programmatically term scope). The solution to this is to put your data in a service and in your ctr just do.
function ctrl($scope, myservice){
$scope.data = myservice;
}
ng-repeat="x in data.results"
Here is a full tutorial http://bresleveloper.blogspot.co.il/2013/08/breslevelopers-angularjs-tutorial.html
And last thing its just a good practice to always have .error(...)

How can I simulate blur when testing directives in angularjs?

The problem
I am trying to test some directives (code for both below). One of them is an "email" (called "epost" in the code(norwegian)) directive. The solution to this should work for all of them, so I am keeping it to this one for now.
Technologies: Angularjs, Jasmine, Requirejs, (grunt & karma running in Chrome)
The directive validates email addresses in two ways; on upshift and on blur. I can test the upshift without problems as you can see in the test below, but I can't figure out how to simulate a blur so the bind('blur') in the directive runs.
What I have done
I have tried to catch the compiled element like this:
elem = angular.element(html);
element = $compile(elem)($scope);
And then in the test i tried several permutations to trigger the blur with a console log just inside the bind function in the directive. None of the below works. It does not trigger.
elem.trigger('blur');
element.trigger('blur');
elem.triggerHandler('blur');
element.triggerHandler('blur');
element.blur();
elem.blur();
I based the injection and setup on this: To test a custom validation angularjs directive
The email directive in angularjs wrapped in requirejs
define(function() {
var Directive = function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
var pattern = /^[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/;
elem.bind('blur', function() {
scope.$apply(function () {
if (!elem.val() || pattern.test(elem.val())) {
ctrl.$setValidity('epost', true);
} else {
ctrl.$setValidity('epost', false);
}
});
});
ctrl.$parsers.unshift(function(viewValue) {
if (pattern.test(viewValue)) {
ctrl.$setValidity('epost', true);
return viewValue;
} else {
return undefined;
}
});
}
};
};
return Directive;
});
The test (using jasmine and requirejs)
define([
'Angular',
'AngularMocks',
], function () {
describe('Directives', function () {
var $scope;
var form;
beforeEach(module('common'));
beforeEach(function () {
var html = '<form name="form">';
html += '<input type="text" id="epost" name="epost" epost="" ng-model="model.epost"/>';
html += '</form>';
inject(function ($compile, $rootScope) {
$scope = $rootScope.$new();
$scope.model = {
epost: null
};
// Compile the element, run digest cycle
var elem = angular.element(html);
$compile(elem)($scope);
$scope.$digest();
form = $scope.form;
});
});
describe('(epost) Given an input field hooked up with the email directive', function () {
var validEmail = 'a#b.no';
var invalidEmail = 'asdf#asdf';
it('should bind data to model and be valid when email is valid on upshift', function () {
form.epost.$setViewValue(validEmail);
expect($scope.model.epost).toBe(validEmail);
expect(form.epost.$valid).toBe(true);
});
});
});
});
I have been able to figure out where I went wrong after some breakpoint debugging.
The "element" item I get out using the approach described in the top of the question is not actually the directive it self. It's an object which wraps the form and the directive.
Like this
{ 0: // The form
{ 0: // The directive (input element)
{
}
}
}
To actually simulate a blur on the directive it self, I did something like this
var directiveElement = $(element[0][0]);
directiveElement.blur();
After getting the element I wanted, and wrapping it in a jQuery object (may be optional), it worked like a charm. I then used the approach like in the test in the question with $setViewValue and checked the model value like this.
form.epost.$setViewValue('a#b.no');
directiveElement.blur();
expect($scope.model.epost).toBe('a#b.no');
expect($scope.form.epost.$valid).toBeTruthy();
Hope this could be of help to others trying to figure the directive testing out.
I too ran into a similar problem and it mystified me. My solution was to use JQuery to get the input and then use angular.element(input).triggerHandler('blur') to make it work. This is odd to me because I do not have to do this with the click event.
spyOn(controller, 'setRevenueIsInvalid');
var sugarRow = $(element).find('tr#ve_id_5')[0];
var amount = $(sugarRow).find('input.amount')[0];
angular.element(amount).triggerHandler('blur');
expect(controller.setRevenueIsInvalid).toHaveBeenCalled();