Moving Protractor tests to async/await (leaving selenium control flow) - angularjs

I want to move appart from the selenium control flow in my Protractor tests.
Here are the steps and problems I went through so far:
1. Disable it test by test
My first idea was to use SELENIUM_PROMISE_MANAGER in order to move from selenium promises to async/await code.
Unfortunately, I found no way to put one test to SELENIUM_PROMISE_MANAGER=0 while keeping others to SELENIUM_PROMISE_MANAGER=1 in order to do the migration smoothly.
2. Keep it but use async/await too
So I thought about a code using async/await while keeping SELENIUM_PROMISE_MANAGER=1.
Unfortunately it seems not to be compatible: https://github.com/angular/protractor/tree/master/exampleTypescript/asyncAwait
There is nothing about such issue on Selenium side so I am wondering if this is an advice or a real it always fails.
3. Override promise.USE_PROMISE_MANAGER
Using protractor.promise.USE_PROMISE_MANAGER=false does not work for me (in beforeEach).
4. Call the control flow on async code
protractor.promise.controlFlow().execute(/* my async code*/);
For me it seems to mix async/await to control flow...
What is the right strategy?
I am wondering, what is the right strategy to move to async/await in Protractor tests?
I don't want to put everything in async/await in one change but to spread the change in multiple small changes

Incompatible, because
Read all about in this issue here.
As it's very technical, the way I (as relatively untechnical guy) understood it, is that jasminewd2, protractor and webDriver incl. ControlFlow are not designed to handle a mix of native promises and managed promises. It handle only managed promises and such are created by many jasminewd2-commands. However, async/await creates native promises and pushes it into the ControlFlow, which ends in a mix of both promises type and it all ends up with heavy timing issues. It can't be resolved as the ControlFlow works as expected and as it was designed for. The situation with async/await was never part of the ControlFlow design.
Switching off the ControlFlow to me means, managed promises get ignored. But because of async/await any managed promise would be wrapped inside a native promise and therefore it doesn't matter, that managed promises get ignored as you keep track of all asynchronous tasks already by tracking native promises only.
How to test both, migrated and not yet migrated test cases
Create two separate conf.js (or whatever your config file is named) and keep them separated. If you have common parts, i.e. helper functions, also migrate those and potentially keep the un-migrated as a duplicate as well. (create to .js-files or use a boolean-indicator to execute either or)
#DubZzz found a possible trick to move smoothly to async / await. His trick is to convert helpers using async / await and call them in protractor.promise.controlFlow().execute. Then move test by test and finally remove controlFlow execute and flag.
For Migration these links I can provide:
The official introduction and migration guide
A similar question witha well documented answer
A good blog about async/await and promises
The official thread about deprecate promise Manager. It also contains helpful information in how to make async/await work.

Related

Server-side rendering of CSS modules

I am going to import styles with CSS Module and make it work with server-side rendering. I tried the following methods but each one has its own caveat. What is the best possible way to require('.style.scss') if any side effects?
Using the css-modules-require-hook:
Advantage: Easy to configure. You just need to call the hook at the beginning of server code. You don't need to modify components.
Caveat: It modifies the require.extensions global object, which is deprecated.
Using the isomorphic-style-loader:
Advantage: No more hooks to require.extensions.
Caveat: Wrapping components with HOCs that uses the React Context, which is an experimental API and likely to break in future releases of React.
Using the webpack-isomorphic-tools:
Advantage: No dependency on require.extensions or Context (AFAIK).
Caveat: Wrapping server inside webpack-isomorphic-tools instance. And can we please get rid of webpack-assets.json?
Bundling server with Webpack:
Advantage: No more hooks or injections.
Caveat: In development, it is very cumbersome to bundle everything whenever the code changes and even makes it harder to debug in a large bundled .js file. Not sure - you may need to pass a bundled .js to test runner.
Disclaimer:
The advantages and caveats below are just my two cents, and actually I love all the libraries, plugins and approaches they took to solve the problem and really appreciate their efforts.
I am not a native English speaker, please correct me if I misrepresent myself.
In the end, I decided to hook the require.extensions in development. Probably it is not the best way, showing warning messages on console, like checksum mismatch, but in development mode, I can ignore it.

Dealing with Protractor.js' Asynchronous nature

I'm struggling dealing with Protractor's asynchronous nature.
On different connections or browsers, it seems that elements are sometimes found, sometimes not, depending on my connection speed.
Short of using .then() callbacks, what options are available to me within Protractor to deal with it's Async issues to make sure elements are fully loaded before moving onto the next action?
Thanks!
I had many problems like that.. to resolve it, if a element depends of a asynchronous call to be showed, I always put a browser wait before.
browser.wait(protractor.ExpectedConditions.elementToBeClickable(element(by.id('elementId'))), 3000);
element(by.id('elementId').click()
Based on your other question, it would seem you're testing a non-angular application. Hence, you will want to use ignoreSynchronization.
And thus, you'll need to handle async and all it's quirks yourself. Eg. using then() callbacks, and ExpectedConditions and the like.

Dynamically override angular service?

Use case:
I'm writing system tests using Geb/Selenium (so outside of angular).
I want to decorate $http to log all requests/responses at run time.
and here's the catch: without touching the source code.
Before you rush to answer "use $provide#decorator", for example,
http://blog.xebia.com/2014/08/08/extending-angularjs-services-with-the-decorate-method/
That solution for this use case means adding a test hook into production code... that's normally a bad thing I want to avoid if possible.
Update: Geb allows you to run Javascript in the browser window. So just for the heck of it I ran the tutorial code to decorate $http. Unfortunately, it didn't work because apparently you can't re-config the app after it's been loaded. But even if it did work, this brings up another interesting point---I need to override $http before any modules have had a chance to use it.
Since decorating $http service would be the cleanest way of doing this, you can avoid polluting production code by using something like ng-constants and gulp/grunt to only add decoration code for a 'test' environment.
See related Q/A here: How do I configure different environments in Angular.js?
If you are inclined on changing this at runtime(where runtime takes place in a test environment), you may need to go 'closer to the metal' and deal with XMLHttpRequests: Add a "hook" to all AJAX requests on a page

Testing a controller in Angular with several dependencies

I am learning to write unit tests for my angular app. My controller has several dependencies upon Resources, factories, services etc
angular.module('app').controller('Ctrl1',['$scope','Factory1','Factory2','Resource1','Resource2' ... and so on
The Resource1, Resource2, etc of course fetch data from the server. Several of these resources are used to fetch data from the server and initialize $scope.
After reading innumerous tutorials all over the net, I have a few queries on the right way to write my jasmine tests
In the beforeEach section of the jasmine test, am I suppose to provide all dependencies right away or should I provide only the ones I care about testing
What I want to test is that Resource1 gets called and fetches some data and intializes some part of $scope then Resource2 gets called and fetches some data and initializes some other part of scope etc
What is the right way to perform the above. I mean am I actually suppose to fetch the data in the test or should I be using some mock http service. I know tutorials mention that we should use mock http service but then how will this test my controller since I am not actually fetching the right data.
This part is really confusing and I have yet to find a blog/article that explains this clearly (I might just write one once I figure things out.. I am sure others are confused too)
Where to Provide Dependencies
You should provide all of your dependencies in your first beforeEach statement. I mock/fake mine with SinonJs. This helps you take advantage of angular's dependency injection to isolate each piece of your application. You should never call a dependency and expect an actual instance of it to return data in a unit test, as that would increase the coupling of your code and make it far more brittle.
Mocking Resource Calls
For resource calls, I simply create a fake resource object with promises and whatnot included. You can then resolve or reject those promises and provide fake data to test your controller logic.
In the plunk below, I've essentially mocked out a whole promise chain. You simply tell your tests to either reject or resolve those promises, faking a successful or failure call to the resource. You then have to make sure your scope cycles with scope.$apply(). I actually forgot to do this which caused me quite a bit of trouble just now.
Conclusion
Here is the Plunk. Let me know if you need to see how I test the actual resource code in my repositories. In those services I have to actually mock out the HTTP calls, which Angular makes extremely easy.
I'm not sure any of this is "Best Practice" but it has worked for me. I learned the basics from looking at other people's source code and watching this Pluralsite video AngularJS Fundamentals which has a very small section on testing.
Useful Resources
Testing AngularJS Directives. This is the hardest thing to test and understand in Angular. Or at least it was for me.
This one is on Dependency Injection in Angular. I have it marked
about where they start talking about unit testing.
This Plural Sight Course got me started with testing JavaScript in general. Very helpful for learning Jasmine if you are new to it.
AngularJS Github repo is very useful if you want to see Jasmine tests in action. Here is a set of tests that simulates a HTTP Backend.

Testing RequireJS application with FluentAutomation?

I'm attempting to write some UI tests for a RequireJS-based Backbone application, utilizing FluentAutomation.SeleniumWebDriver and NUnit. The HTML page in question contains a typical data-main attribute for loading the RequireJS module for the application. My struggle is in properly detecting when the application is fully loaded with these tools; the only thing I've gotten to work consistently so far is using an explicit wait in seconds, like so:
I.Open("http://myapp")
.Wait(5)
.Enter("foo").In("input[name=username]")
.Enter("bar").In("input[name=password]")
.Click("button")
.Wait(5)
.Expect.Text("Welcome").In("#welcome");
This is less than ideal -- my test as written above will always take at least 10 seconds to run, when in reality the app might be "ready" much faster than that. What I'd like to be able to do is something like this:
I.Open("http://myapp")
.WaitUntil(() => I.Assert.Exists("input[name=username]"))
.Enter("foo").In("input[name=username]")
.Enter("bar").In("input[name=password]")
.Click("button")
.WaitUntil(() => I.Assert.Exists("#welcome"))
.Expect.Text("Welcome").In("#welcome");
However, this doesn't work -- using WaitUntil here actually seems to prevent the app from loading, for reasons unclear to me, as I simply receive timeout exceptions after the default wait period (30 seconds), stating that it was unable to locate the element in question within that timeframe.
I see that Selenium 2 provides a WebDriverWait for this kind of scenario, and possibly that would work here, but am unsure how I would use this within FluentAutomation (and a quick search of the FluentAutomation code on GitHub doesn't seem to indicate it's in use within the library).
What can I use in FluentAutomation to properly wait for a RequireJS module (or DOM loaded by it) to be ready?
Additional details:
This might not be a RequireJS compatibility problem at all. I've looked further into the app and found that what's happening after the Click("button") is actually a window.location.replace -- not a RequireJS async module load. It's the one place in the app that this is occurring, apparently. So, is a window.location redirect a known scenario that would cause problems with WaitUntil, and is there an alternate approach (aside from a simple Wait(5)) that would properly handle this?

Resources