Jasmine - Unble to get DOM elements - unit-testing

I am testing an angularjs directive that manipulates the DOM.
I am trying to get the element in my Jasmine spec, so that I can test the functionality of the directive. However, when I use document.getElementsByClassName or TagName or ID, it doesn't return anything. Does anyone have ideas about this?
html = document.getElementsByClassName('analog');
console.dir(html);

If you create a test in headless browser/chrome etc., you could append a dummy object, for example JQuery node, then remove that node in afterEach.
E.g.
beforeEach(() => {
var mockHtml = $('<div class="form-group" style="position: absolute;left: -10000px;"><input class="testInput" id="some_input"></div>');
$('body').append(mockHtml);
});
afterEach(() => {
$('.form-group').remove();
});

Related

stView.el is undefined while testing Backbone view with jasmine

I'm using Jasmine for unit testing to test an application with Backbone.js (and it's the first time that I'm working with them both so I'm a little bit stuck :/ )
Here is my Backbone view
define(['jquery','backbone','underscore','handelbars','models/story','text!templates/story.html',
'controllers/storyController'],
function($, Backbone, _,handelbars, story,storyTemplate,ctrl){
var View = Backbone.View.extend({
el: '#main',
events:{
'click .close-story' : 'closeStory',
}
// Some functions
});
return View;
});
and the spec of Jasmine
define(['views/storyView'],function (storyView) {
describe("Testing the Story View ",function () {
var stView;
beforeEach(function(){
stView=new storyView({id:1});
stView.render();
})
it("Test if el is defined and trigger the click ",function () {
expect(stView.el).toBeDefined();
})
})
})
Thank you :)
You have hardcode el: '#main' in the view constructor.
This will evaluate when the AMD module is loaded.
And when you run jasmine unit tests, I don't think this element of your application is available in Jasmine test page, unless you have mocked it somehow. You can test this via putting a break point on the constructor and inspecting the DOM.
For the existing code to work, you should attach a dummy element on whatever DOM jasmine is using to run your tests before loading the module containing view definition.
On the other hand, It's better to remove the hardcoded el: '#main' (You can tell the developer that it's a very bad coding practice) and pass the element reference while creating view instance, so you can do
new storyView({id:1, el : $('<div/>'}); // dummy element for test

React Highcharts Jest testing error: `InvalidCharacterError`

I'm running into an issue while trying to do some basic smoke testing for React components that use react-highcharts. My typical method with basic Jest yields an error:
it('renders without crashing', () => {
const div = document.createElement('div');
render(<MyComponent {...props} />, div);
});
—>
InvalidCharacterError
at exports.name (node_modules/jest-environmentjsdom/node_modules/jsdom/lib/jsdom/living/helpers/validate-names.js:10:11)
at a.createElement (node_modules/highcharts/highcharts.js:17:221)
at Object.a.svg.z.init (node_modules/highcharts/highcharts.js:92:155)
at Object.z.createElement (node_modules/highcharts/highcharts.js:63:3)
at Object.a.svg.z.createElement (node_modules/highcharts/highcharts.js:107:525)
at Object.a.svg.z.init (node_modules/highcharts/highcharts.js:101:44)
at Object.a.svg.a.VMLRenderer.B (node_modules/highcharts/highcharts.js:109:320)
at Object.N.getContainer (node_modules/highcharts/highcharts.js:252:329)
From some interwebs sleuthing, it seems that this is an inherent problem with rendering <ReactHighcharts /> as a child component. How can I get around this without restructuring my component or complicating my testing?
Since the problem is rendering <ReactHighcharts /> as a child component, and we're just trying to make sure the parent component doesn't blow up, we can use Enzyme's shallow method to render only that parent component without the children:
it('renders without crashing', () => {
expect(shallow(<MyComponent {...props} />).exists()).toBeTruthy();
});

Angular 2 + Jasmine - Test whether an element is visible

I'm testing a web app made using Angular (2+), I'm using Jasmine + Karma as testing environment.
I've searched a lot but I'm not able to test whether an element is visible or not, I thought I'd find a canned matcher or some utility method from Angular, but I didn't.
I tried using classList property of HTMLElement, testing for :visible, but that's not working.
I feel I'm missing something basic, since it should be something basic to achieve.
So, in the example below, how I can test that the div with id header-menu-dropdown-button is visible ?
Here's the test method I'm struggling with:
Template
<div id="header-menu-dropdown-button" class="dropdown-closing-level" [hidden]="!showUserMenu" (click)="showMenu($event)"></div>
<ul [hidden]="!showUserMenu" class="dropdown-menu" aria-labelledby="dropdown">
<li class="dropdown-item">Account</li>
<li class="dropdown-item">Logout</li>
</ul>
Test
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule, TranslationsModule],
declarations: [ AppHeaderComponent ], // declare the test component
})
}));
beforeEach(() => {
fixture = TestBed.createComponent(AppHeaderComponent);
comp = fixture.componentInstance;
menuDropDownButtonDe = fixture.debugElement.query(By.css('#header-menu-dropdown-button'));
menuDropDownButtonEl = menuDropDownButtonDe.nativeElement;
});
it('menu should be closed by default', () => {
//Here I want to check the visibility of the menuDropDownButtonEl element
expect(menuDropDownButtonEl.classList.contains(":visible")).toBe(false); // <-- not working
});
NOTE: showMenu method simply toggles the showUserMenu boolean value.
I unit test it by checking for the existence of the hidden attribute.
expect(menuDropDownButtonEl.hasAttribute('hidden')).toEqual(true);

Angular2 Component: Testing form input value change

I have a text input and i'm listening for the changes.
mycomponent.ts
ngOnInit() {
this.searchInput = new Control();
this.searchInput.valueChanges
.distinctUntilChanged()
.subscribe(newValue => this.search(newValue))
}
search(query) {
// do something to search
}
mycomponent.html
<search-box>
<input type="text" [ngFormControl]="searchInput" >
</search-box>
Running the application everything works fine, but i want to unit-test it.
So here's what i tried
mycomponent.spec.ts
beforeEach(done => {
createComponent().then(fix => {
cmpFixture = fix
mockResponse()
instance = cmpFixture.componentInstance
cmpFixture.detectChanges();
done();
})
})
describe('on searching on the list', () => {
let compiled, input
beforeEach(() => {
cmpFixture.detectChanges();
compiled = cmpFixture.debugElement.nativeElement;
spyOn(instance, 'search').and.callThrough()
input = compiled.querySelector('search-box > input')
input.value = 'fake-search-query'
cmpFixture.detectChanges();
})
it('should call the .search() method', () => {
expect(instance.search).toHaveBeenCalled()
})
})
Test fails as the .search() method is not called.
I guess i have to set the value in another way to have the test realize of the change but i really don't know how.
Anyone has ideas?
It might be a little bit late, but it seems that your code is not dispatching input event after setting input element value:
// ...
input.value = 'fake-search-query';
input.dispatchEvent(new Event('input'));
cmpFixture.detectChanges();
// ...
Updating input html field from within an Angular 2 test
Triggering the value change of FormControl is as simple as:
cmpFixture.debugElement.componentInstance.searchInput.setValue(newValue);
Custom component with #input, subscriptions, two way data binding
If you got a custom component you would need further changes in your application to be able to successfully unit test your application
have a look at the gist here this will give you some idea
https://gist.github.com/AikoPath/050ad0ffb91d628d4b10ef81736af386/raw/846c7bcfc54be8cce78eba8d12015bf749b91eee/#ViewChild(ComponentUnderTestComponent).js
More over complete reading over here carefully otherwise you can easily get confused again -
https://betterprogramming.pub/testing-angular-components-with-input-3bd6c07cfaf6

Unit testing React Bootstrap modal dialog

I'm trying to unit test React Bootstrap modal dialog using Jasmine. But it is not working as expected.
Here is jsfiddle link using latest versions of React, React Bootstrap, Jasmine.: http://jsfiddle.net/30qmcLyf/3/
Test which fails:
line# 27-28
// This test fails. Find DOM Node.
var instanceDomNode = ReactDOM.findDOMNode(instance);
expect(instanceDomNode).not.toBe(null);
line# 39-40
//This test fails. Find modal header.
var headerComponents = TestUtils.scryRenderedComponentsWithType(component, ReactBootstrap.Modal.Header);
expect(headerComponents.length).not.toBe(0);
Also what is wrong with line#35-36. If I uncomment lines I get error shown in comments.
// Error: Did not find exactly one match for componentType:function ModalHeader()...
//var headerComponent = TestUtils.findRenderedComponentWithType(component, ReactBootstrap.Modal.Header);
//expect(headerComponent).not.toBe(null);
As per latest official documentation for test utilities (link), you are supposed to pass ReactComponent as first argument.
Can somebody tell me what is wrong?
Check out how the react-bootstrap team writes tests for this. The modal is rendered into a different subtree which is how it gets rendered to the document body and not directly as a child of its parent. In other words your srcying fails because the component is not in that Component tree.
You can use refs on the modal or look for the DOM nodes directly in the document.
React-Bootstrap modal can be unit tested using mount of enzyme
it(componentToTest.title + 'renders Modal component', () => {
expect(wrapper.find(UVModal).length).toEqual(1);
});
it(componentToTest.title + 'renders major html elements', () => {
// Test whether modal-content element has 3 html children elements.
expect(wrapper.find('.modal-content').length).toEqual(1);
expect(wrapper.find('.modal-content').children()).toHaveLength(3);
// Test whether modal-header element has 2 html children elements.
expect(wrapper.find('.modal-header').length).toEqual(1);
expect(wrapper.find('.modal-header').children()).toHaveLength(2);
// Test whether modal-body element has 1 html child element.
expect(wrapper.find('.modal-body').length).toEqual(1);
expect(wrapper.find('.modal-body').children()).toHaveLength(1);
// Test whether modal-footer element has 1 html child element.
expect(wrapper.find('.modal-footer').length).toEqual(1);
expect(wrapper.find('.modal-footer').children()).toHaveLength(1);
elementToSearch = <p>Lannisters always pay their debt</p>;
expect(wrapper.contains(elementToSearch)).toEqual(false);
});
Check following blog for details:
https://medium.com/#yuvi1422/unit-test-react-bootstrap-modal-a37bf59732ab
In case you are using an older version of Enzyme, you can pass the container element to mount where you want your Modal to be rendered, like this:
Actual Code:
------------
import React from 'react'
import { Modal } from 'reactstrap'
export default MyModal = () => {
return (
<Modal isOpen={props.isOpen}>
<ModalHeader>Header</ModalHeader>
<ModalBody>Body</ModalBody>
</Modal>
);
}
Unit Test:
----------
import React from 'react'
import MyModal from './MyModal'
import { mount } from 'enzyme'
describe(() => {
let wrapper;
beforeEach(() => {
const container = document.createElement("div");
document.body.appendChild(container);
wrapper = mount( <MyModal isOpen={true}/> , {attachTo: container});
});
it('renders correctly', () => {
expect(wrapper).toMatchSnapshot();
expect(wrapper.find('ModalHeader')).toHaveLength(1);
expect(wrapper.find('ModalBody')).toHaveLength(1);
});
})