How to trigger scroll event in acceptance test - ember.js

I need to trigger window scroll event to test infinite scrolling, I've tried to use triggerEvent, but it seems that I missing something and it doesn't work. I'm using Ember 2.0 and list is rendered inside the component if it matters. Test fails on last 2 assertions, scroll position doesn't change after triggering event
test 'loads more items when scrolling', (assert) ->
visit '/locations/1'
andThen ->
assert.equal(find('.items-list li').length, 30)
find(window).scrollTop(10000)
triggerEvent(window, 'scroll')
andThen ->
assert.ok(find(window).scrollTop() > 0, 'window should scroll')
assert.ok(find('.items-list li').length > 30, 'should load more items after reaching threshold')
Has anyone successfully triggered scroll event in their tests?

Finally I could make it work! Used #ember-testing-container instead window.
The code below was what worked for me:
andThen(() => {
Ember.$('#ember-testing-container').scrollTop(10000);
});
triggerEvent(Ember.$('#ember-testing-container'), 'scroll');
andThen(() => {
assert.ok(Ember.$('#ember-testing-container').scrollTop() > 0, 'window should scroll')
});
With ember-infinity you also need to scroll down the body before starting the test:
Ember.$('body').scrollTop(2000);

I have an possible answer for this.
Try
triggerEvent('.skip-button', 'scroll', [{isInTestEnvironment:true}] ).then...
Say .skip-button is a selector within your ember app, but it could be any other one.
The scroll event is detected by the ember app, as if it actually doesn't scroll anything... this is why I pass a isInTestEnvironment:true param to indicate the ember app I simulated a user scroll.
Not an ideal solution, but far better than no test at all.

Related

Angular2 testing directive with dynamically added DOM

I have an attribute directive that adds hidden input after host element and displays it when clicked on host element, it also hide it when input lose focus (blur event). It is basically used to edit values of some models without need to create forms/inputs for every single field.
Code: Plunker
I have a problem with 1 test case:
click on host element should clear inline display style
blur should set display style to none
it('should display input when clicked and hide on blur', () => {
i.click();
fixture.detectChanges();
expect(input.style.display).not.toBe('none');
input.blur();
fixture.detectChanges();
expect(input.style.display).toBe('none');
});
While running karma locally this test sometimes passes and sometimes fails, it fills like .blur() have some async behavior. I tried with fakeAsync and tick but with no luck. Maybe I am doing it in a completely wrong way.

How can i simulate browser focus when testing using angular and jasmine?

I am trying to write a unit test that checks whether or not the effect of a focus event takes place. My actual test case is more complicated, but I have created a minimal reproduction with the following code:
it('testing input focus', async(() => {
let showDiv = false;
const template = `<div *ngIf="shouldShow" class='hidden-div'>
SHOW ME WHAT YOU GOT
</div>
<input (focus)="shouldShow = !shouldShow" name="input">`;
buildTestComponent(template, {shouldShow: showDiv}).then((fixture) => {
fixture.detectChanges();
const inputEl: HTMLInputElement = fixture.nativeElement.querySelector('input');
expect(fixture.nativeElement.querySelector('.hidden-div')).toBe(null);
inputEl.focus();
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('.hidden-div')).not.toBe(null);
});
}));
When I run this test with karma the test passes as long as I have focus on the chrome tab that is running the karma target. However, if the browser does not have focus the test fails (even if the browser is visible, but I click on another window) with error message:
Expected null not to be null.
I assume that when the Chrome tab doesn't have focus, the inputEl.focus() call doesn't actually get called but I don't know how to fix it. All other unit tests I have written pass regardless of browser focus. Has anyone run into this or have any ideas?
To trigger an event on an Angular element, you can use the built-in JavaScript ES6 method dispatchEvent with a subsequent call of Angular's change detection mechanism to get your DOM updated:
inputElement.dispatchEvent(new Event('focus'));
fixture.detectChanges();
A more elegant way to achieve the same thing is to use angular's wrapper method:
import { dispatchEvent } from '#angular/platform-browser/testing/src/browser_util'
dispatchEvent(inputElement, 'focus');
fixture.detectChanges();
An interesting one is when you want to set a value to your input element. You will need to first assign a string to the input's value property and then trigger an 'input' change event:
inputElement.value = 'abcd';
dispatchEvent(inputElement, 'input');
fixture.detectChanges();
Note: There are events that do not act the way you may expect. For example, dispatching a 'click' event will NOT give the focus to your input element! A workaround could be to first trigger a 'focus' event and then a 'click' event as follows:
dispatchEvent(inputElement, 'focus');
dispatchEvent(inputElement, 'input');
fixture.detectChanges();
All the available JavaScript events are here.

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

Ember - triggerEvent helper

I'm having trouble triggering a "change" event in an ember acceptance test.
I have a rangeslider with an observed 'value' property. On change, the slider sends an api request which updates the url with params based on the slider value.
I am able to change the value of the slider in my test using jQuery, which successfully updates the slider in the UI...
$("#slider").val(3.0).change();
...but the change event isn't fired, so no api call. This same setup is working fine for similar tests where I am able to use "click" or "fillIn" to trigger a request.
I've tried using both the run loop and the triggerEvent helper (see below) but am having no luck.
// 1. using the run loop -- updates UI, but no change event fired
Ember.run(function() {
$("#gpa-slider").val(3.0).change();
});
andThen(() => {
assert.equal(currentURL(), "/athletes?gpa=3.0")
});
//2. using triggerEvent helper --
// doesn't update UI, slider value, or trigger change event
triggerEvent('#gpa-slider', 'change', {value: 3.8} )
andThen(() => {
assert.equal(currentURL(), "/athletes?gpa=3.0")
});
Am I setting up triggerEvent() incorrectly? Is there a better way to handle this?
I was able to get the change event to fire by clicking on the slider handle.
click(Ember.$('.rangeslider__handle'));
andThen(() => {
assert.equal(currentURL(), '/athletes?gpa=3.0');
});
I still don't know what I was doing wrong with the triggerEvent() helper, but maybe this will help some poor soul in the future.

jQuery cycle2 and 'continueAuto'

I have a simple cycle2 slideshow with a pager. The slideshow proceeds automatically (ie. with set speed and timeout). What I want to achieve is, that once the user clicks a link in the pager, the slideshow becomes "manual" (the automatic transitioning stops) and from that point it is controllable solely by the pager.
The cycle2 API documentation says that there is the 'continueAuto' option which should serve the purpose. So I made a handler to the cycle-pager-activated event like this:
$('#fp_slideshow').on('cycle-pager-activated', function(event, opts ) {
$('#fp_slideshow').cycle({continueAuto: false});
});
The event gets called as I expect (upon clicking a link in the pager), but calling cycle({continueAuto: false}) does nothing and the slideshow goes on indefinetely.
What am I doing wrong?
The pause command might work better for you in this instance. I tried using the cycle-pager-activated event but couldn't get it to work consistently so instead attached a click handler directly to the pager links. Here's the JavaScript:
var $fp_slideshow = $('#fp_slideshow');
$fp_slideshow.cycle({
pager: '#fp_slideshow_pager',
pagerTemplate: '<li>Slide {{slideNum}}</li>'
});
$('a', '#fp_slideshow_pager').on('click', function() {
$fp_slideshow.cycle('pause');
});
And here's a fiddle: http://jsfiddle.net/N43KH/1/