Unit testing React click outside component using Jest and react testing library - unit-testing

I found this implementation here but its using enzyme.
Unit testing React click outside component
Adding an event to window does not work either:
window.addEventListener('click', () => {
console.log('click on window');
});
Has anyone came across this issue above using jest and "#testing-library/react"?

as #Giorgio mentioned:
fireEvent.click(document)
//or
userEvent.click(document.body);

I'd like to provide an up-to-date answer which follows the same principle as what #eduardomoroni proposed.
The fireEvent hasn't worked for me and so I've managed to achieve it with the userEvent api.
userEvent.click(document.body);
Also, as typescript complains document cannot be passed to the click event handler. Instead, the body is a better solution.
Argument of type 'Document' is not assignable to parameter of type 'TargetElement'.

Related

Mocking PDFtron webviewer with jest in react application

Hi I am new to unit testing and I am trying to mock the 'annotationManager' of the PDFtron webviewer
I am using this below code in my test file
jest.mock('#pdftron/webviewer', () =>({
annotationManager: {
getAnnotationsList: jest.fn().mockReturnValue([]),
deleteAnnotations: jest.fn()
},
}));
In the code, I'm getting the list of annotations using 'getAnnotationsList' function and deleting it using 'deleteAnnotations' function.
In the log of the unit tests, I'm getting this following error
'cannot read the properties of undefined (reading 'getAnnotationsList')
Is this the correct way to doing things or am I missing something?
are you able to share an example of a test you are writing where you need to mock the annotation manager? Depending on how you are using the WebViewer package, mocking the annotation manager can be different. If you prefer to reach out to Apryse directly you can also reach out to them via their support form

ReferenceError: ga is not defined [Ionic 2.2 Unit Testing With Karma]

I'm adding unit tests to an Ionic 2.2.0 app I manage, but my Components crash at test-time when they encounter Google Analytics code. I'm using Ionic's official unit testing example as a basis, and my current progress can be seen on our public repo.
My project uses Google Analytics, which is added to the HTML and downloaded at runtime (because we have different keys for development vs production).
The code that initializes Analytics is in my main.ts, and it sets a global variable ga, which is subsequently available throughout the application.
I'm beginning the tests for the app's first page, which uses Analytics. When I run the tests, I'm met with the following error
Component should be created FAILED
ReferenceError: ga is not defined
at new MyBusesComponent (webpack:///src/pages/my-buses/my-buses.component.ts:33:6 <- karma-test-shim.js:138419:9)
at new Wrapper_MyBusesComponent (/DynamicTestModule/MyBusesComponent/wrapper.ngfactory.js:7:18)
at CompiledTemplate.proxyViewClass.View_MyBusesComponent_Host0.createInternal (/DynamicTestModule/MyBusesComponent/host.ngfactory.js:15:32)
........
This is because main.ts doesn't seem to be loaded or executed, and I assume TestBed is doing that purposefully. It's certainly better that I don't have the actual Google Analytics object, but the Component does need a function called ga.
My question, therefore, is as follows: how can I create Google Analytics' ga variable in my test configuration such that it's passed through to my components at test-time?
I've tried exporting a function from my mocks file and adding it to either the imports or providers arrays in my spec file, but to no avail.
I appreciate any advice! Feel free to check my code at our repo I linked to above and ask any followups you need. Thanks!
You declare the var ga but that is just to make TypeScript happy. At runtime, the ga is made global from some external script. But this script is not included in the test.
What you could do is just add the (mock) function to the window for the tests. You could probably do this in your karma-test-shim.js.
window.ga = function() {}
Or if you wanted to test that the component is calling the function with the correct arguments, you could just add the function separately in each test that uses the function. For example
beforeEach(() => {
(<any>window).ga = jasmine.createSpy('ga');
});
afterEach(() => {
(<any>window).ga = undefined;
})
Then in your test
it('..', () => {
const fixture = TestBed.creatComponent(MyBusesComponent);
expect(window.ga.calls.allArgs()).toEqual([
['set', 'page', '/my-buses.html'],
['send', 'pageview']
]);
})
Since you're making multiple calls to ga in the constructor, the Spy.calls will get the argument of all each call and put them in separate arrays.

Unit testing ag-grid in Angular 2

Has someone worked on unit testing ag-grid components in Angular 2?
For me, this.gridOptions.api remains undefined when the test cases run.
Sorry to be a little late to the party but I was looking for an answer to this just a couple of days ago so wanted to leave an answer for anyone else that ends up here. As mentioned by Minh above, the modern equivalent of $digest does need to be run in order for ag-grid api's to be available.
This is because after the onGridReady() has run you have access to the api's via the parameter, looking like so. This is run automatically when a component with a grid is initialising. Providing it is defined in the grid (gridReady)="onGridReady($event)"
public onGridReady(params)
{
this.gridOptions = params;
}
This now means you could access this.gridOptions.api and it would be defined, you need to re-create this in your test by running detectChanges(). Here is how I got it working for my project.
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
fixture.detectChanges(); // This will ensure the onGridReady(); is called
This should inturn result in .api being defined when running tests. This was Angular 6.
Occasionally the test may have to perform an await or a tick:
it('should test the grid', fakeAsync( async () => {
// also try tick(ms) if a lot of data is being tested
// try to keep test rows as short as possible
// this line seems essential at times for onGridReady to be processed.
await fixture.whenStable();
// perform your expects...after the await
}));
If you are using ag-grid enterprise make sure to include in your test file import 'ag-grid-enterprise'; otherwise you will see console errors and gridReady will never be called:
Row Model "Server Side" not found. Please ensure the ag-Grid Enterprise Module #ag-grid-enterprise/server-side-row-model is registered.';
It remains undefined because the event onGridReady is not invoked yet. Im not sure about Angular 2 because im using angularjs and have to do $digest in order to invoke onGridReady.

angular2 test, how to test event is bound to an element

I am writing an angular2 unit test for a component.
With fully using JQuery it's possible to find what event is bound to an element. However in Angular2, I am not sure it's possible or not
For example, the following code has a click event, which is a public function of a component
<button (click)="doLogin()" [disabled]="myDisabled">Login</button>
By reading DOM element, I can make it sure all properties and data binding is correct by running a test. Only thing that I don't know is, "event binding is correct or not" because the generated html is like the following
<button>Login</button>
I want to make it sure someone does not delete this event binding in the future by writing a test for it.
In summary, how do I know event is properly bound to DOM element?
EDIT:
Is there a way to know there is click event without actually clicking it?
You could use the approach below (calling the click:
it('should render list', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
return tcb.createAsync(MyList).then((componentFixture: ComponentFixture) => {
const element = componentFixture.nativeElement;
componentFixture.detectChanges();
expect(element.querySelectorAll('li').length).toBe(5);
document.getElementById('test').click();
});
}));
See this question for more details:
How can I trigger a JavaScript event click

AngularJs : triggering an event to simulate user action when unit testing a directive

I have seen that in order to simulate user action on the DOM generated by a directive, there are two approaches, both trigering an event:
How to trigger ng-change in directive test in AngularJS
The first approach uses jquery and the second one a function called browserTrigger defined in angular-scenario.js. The second one is supposed to be better as jquery would have a bug on event triggering (which I believe, I am not arguing :) ).
Using the angular-scenario means e2e testing for me. but I have seen egghead video and he seems to do unit testing. How is this possible ?
I guess he just copied the function ?
I think I am going to test directives as e2e tests, it makes more sense as unit test is more fore pure functions.
Well, I just found that browserTrigger is something internal not supposed to be used directly : https://github.com/angular/angular.js/issues/5178
Thanks!
As of 1.3.15 you can use triggerHandler to trigger a event as shown below,
it('should click the element',function(){
element.triggerHandler('click') ;
expect($scope.clicked).toBe(true);
});
simple and it works, example, in unit test env:
spyOn(self, 'updateTransactionPrice');
var el = compile('<form name="form" latest novalidate json-schema="main.schema_discount" json-schema-model="main._data"><input type="text" ng-model="main._data.reverse_discount" ng-class="{ \'form-invalid\': form.reverse_discount.$invalid }" ng-change="main.transactionPrice(form);" name="reverse_discount" class="form-control-basic" placeholder="" ng-disabled="!main.selectedProduct.total_price"></form>')(scope);
el.find('input').triggerHandler('change');
expect(self.updateTransactionPrice).toHaveBeenCalled();