I've got some UI tests that are attempting to test that a click on an element makes something else appear. There's an existing check for all tests that looks to see if the DOM is Ready, however there's a small amount of time between that even firing and the app.controller() calls all completing where my test could jump in and wrongly determine that the click handler has not been added.
I can use angular.element('[ng-controller=myController]').scope() to determine if the scope is defined, however there is still a very small window where the test could run before the click handler is bound (a very, very small window).
<div ng-controller="myController">
<div ng-click="doWork()"></div>
</div>
Can anyone see a way to tell that the click handler has been added?
PS: There's an event that fires within a controller when the controller has loaded:$scope.$on('$viewContentLoaded', function(){ }); But that doesn't really help me unless I subscribe to it in the controller and flag a variable somewhere that I can check via Selenium.
PPS: A lot of these have classes that change when scope changes and they can be used to trigger the test, but many do not.
There is a specialized tool for testing AngularJS application - protractor. It is basically a wrapper around WebDriverJS - selenium javascript webdriver.
The main benefit of using protractor is that it knows when Angular is settled down and ready. It makes your tests flow in a natural way without having to use Explicit Waits:
You no longer need to add waits and sleeps to your test. Protractor
can automatically execute the next step in your test the moment the
webpage finishes pending tasks, so you don’t have to worry about
waiting for your test and webpage to sync.
It also provides several unique AngularJS-specific locators, like by.model, by.binding etc. And, in general, it provides a very convenient and well-designed API for end-to-end testing.
There are two issues to overcome here:
How do we know when Angular is done (with the sub issue of "what does done mean?"
How do we get that information to Selenium
Angular provides a method called "getTestability" that can be called with any element (assuming you've included it, it is optional). Usage:
angular.getTestability(angular.element('body')).whenStable(function(){/*Do things*/})
That seems to solve the first problem...
But, now what does Done mean in this case. Done means that anything that uses $browser.defer will have been executed. What does that mean? No idea, but in practice it at least verifies that there are no http requests in play when the callback is called.
Ok, now Selenium... You can ask it to execute JavaScript on the client and use the code above to set a variable. .whenStable(function(){window.someVar=true}) and then poll in the test until that variable is set.
Will this catch all cases of "Done"? Probably not, but it made my tests pass more consistently. As long as it works I'm not going to think any harder on the issue.
That said, I'm not marking this as the answer. It feels like a dirty solution.
Related
I use protractor to test an angular app and I have a weird problem. Occasionally or since recently, protractor has been stalling/slowing down considerably.
I narrowed down to the issue and can see that it's taking a long time for a simple someElement.getText().then(...) to resolve; so the .then(...) part never executes; however, putting an allScriptTimeOut: 500 000 waits untils that promise eventually resolves which takes about 6mins to resolve (very inconvenient!).
Again, waiting with allScriptTimeOut: 500 000 will eventually work but takes too long.
Another solution to this extreme slowdown is to tell protractor hey Protractor, don't wait for Angular to finish fufilling all promises and asynchronous background tasks and just go on, don't wait for angular and this would work with browser.ignoreSynchronization = true;
However setting this boolean to true is problematic because it basically treats your whole angular app as a NON-angular app and never waits for angular and thus causing all sort of issues with Protractor. Another complication is that our app is NOT entirely angular, some pages are non-angular; anyways; here's my question:
Is there a way to hook into the controlflow queue and basically poll or query the queue by asking hey controlflow queue tell me whenever any action that was enqueued is taking longer than 11sec? and if yes, set browser.ignoreSynchronization = true; a sudo-like code would look like this:
protractor.controlflow(function(delay){
if(delay > 11 sec){
browser.ignoreSynchronization = true;
}else{
browser.ignoreSynchronization = false;
}
});
This might not make sense syntactically but i'm more interested in the concept than properly written javascript;
Thanks again hopefully that's clear enough to understand my problem
UPDATES:
I checked again and basically, Protractor is able to click on most button, but then it gets to another button which was at the bottom of the screen, but I scrolled first to bring button into view, then tried to click on it and it's just taking 6mins then it finally clicks on that button.
Why is it taking this long before it finally successfully clicks on that button?
With respect to your question about changing ignoreSynchronization within a test, this is currently not possible (up through protractor 3.3.0) because the built-in waitForAngular function does not implement that variable within the context of the control flow (browser.ts:399 would have to be wrapped in control flow so that it would recognize when the variable is being changed). Hopefully that kind of changed can be patched into a future release, but it would introduce a breaking change from the existing behavior.
I have very simple AngularJs 1.4.8 Front-End:
When the form is filled and the OK button is pressed the new person is added to the table.
The form is in the addingPersonController and the table is in the allPersonsController, both are childs under the masterController.
When a user is added(OK clicked) the following happens:
a POST request is sent to the server in order to add the new person.
a personAddedEvent is emitted with $emit from the addingPersonController to the masterController
the masterController broadcasts an updatePersonsEvent to the allPersonsController
the allPersonsController sends a GET request to the server in order to get all the persons and update the table.
I have a protractor end to end test that exercises this case, the problem is that I can not figure out how to wait for the whole process to finish before to check the assertions and the test always fails.
The UI works when tested manually and I have tried to wait in the protractor test with:
browser.wait(function(){}, timeout);
browser.sleep(ms);
.click().then();
None of them worked.
Is there a way to wait for such a process to complete before checking the assertions?
Got some similiar issues with my e2e tests too. There are couple of work-arounds can be added. Depend on situations , mostly due to some sort of non-response timeout (lost synchronization between protractor/selenium and browser). It is like a hang of the PC, cause by lack of resource (either GPU/VRAM, RAM or CPU). And this cause the built-in "wait for angular works to be done" of protractor lost its tracking. And run the spec before it should be ran.
Here is the list I will suggest you to try:
use built-in wait for angular Quick and solve the problem most of the time. But it will have nothing to deal with the lost synchronization between protractor/selenium and browser.
browser.waitForAngular();
use ExpectedConditions with browser.wait() This is always the best because it will sure work for all case. Even outside angular environment. Bad thing about this is... it is quite long to type
browser.wait( ExpectedConditions.textToBePresentInElement( $('#someId'), "Person's Name"), 10000);
EDIT: typos and make answer more understandable
If my page is rendered using AJAX request should I execute something like
waitForElementToBeVisible('.todoListItem');
//that is my custom function that waits
//till element will be rendered
before making call:
element(by.model('todoList.todoText')).sendKeys('write first protractor test');
which sendKeys to element with CSS class .todoListItem?
If this is an AngularJS application under test, things should be handled naturally by protractor - it always works in sync with Angular. This is, though, theory.
In practice, this is not always the case - for instance, our test codebase has the browser.wait() calls here and there to make the tests flow the way we want them to work.
Note that disabling Angular animations and increasing the implicit wait timeout sometimes help too.
See also:
a custom waitReady() function to wait for element to be present and visible
protractor-flake package (rerun potentially flakey protractor tests before failing)
Let's say I have the following method:
function sendUserDataToServer(userData) {
// Do some configuration stuff
$.ajax('SomeEndpoint', userData);
}
When writing a unit test for this function, I could go one of two ways:
Create a spy around $.ajax and check that it was called with the expected parameters. An actual XHR request will not be sent.
Intercept the ajax request with a library like SinonJs and check the XHR object to make sure it was configured correctly.
Why I might go with option 1: It separates the functionality of $.ajax from my code. If $.ajax breaks due to a bug in jQuery, it won't create a false-negative in my unit test results.
Why I might go with option 2: If I decide I want to use another library besides jQuery to send XHRs, I won't have to change my unit tests to check for a different method. However, if there's a bug in that library, my unit tests will fail and I won't necessarily know it's the library and not my actual code right away.
Which approach is correct?
Your first option is correct. The purpose of your unit test is twofold
to verify your code contract
to verify that it communicates with other things it uses.
Your question is about the interaction with $.ajax, so the purpose of this test is to confirm it can talk correctly to its collaborators.
If you go with option 1, this is exactly what you are doing. If you go with option 2, you're testing the third party library and not that you're executing the communication protocol correctly.
You should make both tests though. The second test is probably fast enough to live with your unit tests, even though some people might call it an integration test. This test tells you that you're using the library correctly to create the object you intended to create. having both will let you differentiate between a bug in your code and the library, which will come in handy if there is a library bug that causes something else in your system to fail.
My opinion: option 1 is more correct within unit tests.
A unit test should test the unit of code only. In your case this would be the JavaScript under your control (e.g. logic within the function, within a class or namespace depending on the context of your function).
Your unit tests should mock the jQuery call and trust that it works correctly. Doing real AJAX calls is fine, but these would be part of integration tests.
See this answer regarding what is and what isn't a unit test.
As an aside, a third way would be to do the AJAX calls via a custom proxy class which can be mocked in tests but also allows you to switch the library you use.
I would use option 1 but go with the one that makes the tests easiest to understand.
You are depending on jQuery in your code, so you don't need to worry about it actually working as you point out. I have found that it makes the tests cleaner as you specify your parameters and the response and have your code process it. You can also specify which callback should be used (success or error) easily.
As for changing the library from jQuery. If you change the code your test should fail. You could argue that your behavior is now different. Yes, you are making an Ajax call but with a different dependency. And your test should be updated to reflect this change.
Both approaches are really correct. If you are creating your own wrapper for sending Ajax calls, it might make sense to intercept the XHR request or manually creating the request and sending it yourself. Choose the option that makes your test easiest to understand and maintain.
the most important thing is to test your own code. separate business logic from the IO code and your business logic. after that you should have methods without any logic that do the actual IO (exactly as in your example). and now: should you test that method? it depends. tests are to make you feel safer.
if you really worry that jQuery can fail and you can't afford such unlikely scenario than test it. but not with some mocking library but do full end-to-end integration tests
if you're not sure if you are using jQuery correctly then do the 'learning tests'. pass a parameters to it and check what kind of request it produces. mocking tests should be enough in this situation
if you need a documentation of a contract between frontend and backend then you may choose if you prefer to test if backend meets the contract, frontend or both
but if none of above applies to you then isn't it a waste of time to test external, well established framework? jquery guys for sure have tested it. still you will probably need some kind of integration tests (automatic or manual) to check if your frontend interacts with backend properly. and those tests will cover the network layer
I have seen this link: Implementing Mutual Exclusion in JavaScript.
On the other hand, I have read that there are no threads in javascript, but what exactly does that mean?
When events occur, where in the code can they interrupt?
And if there are no threads in JS, do I need to use mutexes in JS or not?
Specifically, I am wondering about the effects of using functions called by setTimeout() and XmlHttpRequest's onreadystatechange on globally accessible variables.
Javascript is defined as a reentrant language which means there is no threading exposed to the user, there may be threads in the implementation. Functions like setTimeout() and asynchronous callbacks need to wait for the script engine to sleep before they're able to run.
That means that everything that happens in an event must be finished before the next event will be processed.
That being said, you may need a mutex if your code does something where it expects a value not to change between when the asynchronous event was fired and when the callback was called.
For example if you have a data structure where you click one button and it sends an XmlHttpRequest which calls a callback the changes the data structure in a destructive way, and you have another button that changes the same data structure directly, between when the event was fired and when the call back was executed the user could have clicked and updated the data structure before the callback which could then lose the value.
While you could create a race condition like that it's very easy to prevent that in your code since each function will be atomic. It would be a lot of work and take some odd coding patterns to create the race condition in fact.
The answers to this question are a bit outdated though correct at the time they were given. And still correct if looking at a client-side javascript application that does NOT use webworkers.
Articles on web-workers:
multithreading in javascript using webworkers
Mozilla on webworkers
This clearly shows that javascript via web-workers has multithreading capabilities. As concerning to the question are mutexes needed in javascript? I am unsure of this. But this stackoverflow post seems relevant:
Mutual Exclusion for N Asynchronous Threads
Yes, mutexes can be required in Javascript when accessing resources that are shared between tabs/windows, like localStorage.
For example, if a user has two tabs open, simple code like the following is unsafe:
function appendToList(item) {
var list = localStorage["myKey"];
if (list) {
list += "," + item;
}
else {
list = item;
}
localStorage["myKey"] = list;
}
Between the time that the localStorage item is 'got' and 'set', another tab could have modified the value. It's generally unlikely, but possible - you'd need to judge for yourself the likelihood and risk associated with any contention in your particular circumstances.
See the following articles for a more detail:
Wait, Don't Touch That: Mutual Exclusion Locks & JavaScript - Medium Engineering
JavaScript concurrency and locking the HTML5 localStorage - Benjamin Dumke-von der Eh, Stackoverflow
As #william points out,
you may need a mutex if your code does something where it expects a
value not to change between when the asynchronous event was fired and
when the callback was called.
This can be generalised further - if your code does something where it expects exclusive control of a resource until an asynchronous request resolves, you may need a mutex.
A simple example is where you have a button that fires an ajax call to create a record in the back end. You might need a bit of code to protect you from trigger happy users clicking away and thereby creating multiple records. there are a number of approaches to this problem (e.g. disable the button, enable on ajax success). You could also use a simple lock:
var save_lock = false;
$('#save_button').click(function(){
if(!save_lock){
//lock
save_lock=true;
$.ajax({
success:function()
//unlock
save_lock = false;
}
});
}
}
I'm not sure if that's the best approach and I would be interested to see how others handle mutual exclusion in javascript, but as far as i'm aware that's a simple mutex and it is handy.
JavaScript is single threaded... though Chrome may be a new beast (I think it is also single threaded, but each tab has it's own JavaScript thread... I haven't looked into it in detail, so don't quote me there).
However, one thing you DO need to worry about is how your JavaScript will handle multiple ajax requests coming back in not the same order you send them. So, all you really need to worry about is make sure your ajax calls are handled in a way that they won't step on eachother's feet if the results come back in a different order than you sent them.
This goes for timeouts too...
When JavaScript grows multithreading, then maybe worry about mutexes and the like....
JavaScript, the language, can be as multithreaded as you want, but browser embeddings of the javascript engine only runs one callback (onload, onfocus, <script>, etc...) at a time (per tab, presumably). William's suggestion of using a Mutex for changes between registering and receiving a callback should not be taken too literally because of this, as you wouldn't want to block in the intervening callback since the callback that will unlock it will be blocked behind the current callback! (Wow, English sucks for talking about threading.) In this case, you probably want to do something along the lines of redispatching the current event if a flag is set, either literally or with the likes of setTimeout().
If you are using a different embedding of JS, and that executes multiple threads at once, it can get a bit more dicey, but due to the way JS can use callbacks so easily and locks objects on property access explicit locking is not nearly as necessary. However, I would be surprised if an embedding designed for general code (eg, game scripting) that used multi threading didn't also give some explicit locking primitives as well.
Sorry for the wall of text!
Events are signaled, but JavaScript execution is still single-threaded.
My understanding is that when event is signaled the engine stops what it is executing at the moment to run event handler. After the handler is finished, script execution is resumed. If event handler changed some shared variables then resumed code will see these changes appearing "out of the blue".
If you want to "protect" shared data, simple boolean flag should be sufficient.