How to keep protractor running? - javascript

I'm trying to access Db in protractor tests using a sql server driver for NodeJs (protractor is a nodejs application so this is no problem)
The idea is to check Db data in our e2e tests:
We can check whether some hidden things are written correctly in the Db that cannot be seen on the UI (e.x Logs,..)
We can isolate features in our e2e testing: we don't rely on another feature to display the data to check whether the feature writing the data works correctly.
The problem I'm having is whenever protractor finishes interacting with the browser, it will terminate. Therefore, my code to access the Db cannot verify the data retrieved (e.x expect(dataFromDb).toEqual('foo')) because requests to Db are asynchronous in NodeJs.
At the time when I retrieve the data via the callback, protractor has been terminated.
It looks to me that protractor is only aware of web browser promises and terminates when there are no outstanding browser promises.
Is there any solution to keeping protractor alive so that I can verify my Db data? Thanks.

Two things to keep in mind.
1) expect(dataFromDb).toEqual('foo')): Protractor wrapped expect to understand promises. However, it only understands webdriver.promise (i.e. no $q or any other promise). If you want to make assertions against non webdriver promises, you have to resolve the promise yourself like:
dataFromDb.then(function(resolvedData) {
expect(resolvedData).toEqual('foo')
})
2) Protractor does not "terminate". Protractor only helps you kick off your test using another test framework (i.e. jasmine, mocha); once it does that it is only a library of tools (i.e. locators, waitForAngular, etc) that you run on top of that test framework. It's that other framework you must prevent from terminating. I don't know what framework you're using, but I'll use jasmine as an example:
it('call db', function(done) { //notice the inclusion of `done`
browser.get('something'); //this is protractor
element(by.xyz).click(); //this is protractor
var data = queryDatabase(); // you must tell jasmine to wait for this.
data.then(function(resolvedData) {
expect(resolvedData).toBe('foo');
done(); // tell jasmine you're done.
})
})
Side note, protractor patched jasmine it to wait for webdriver commands to finish (just like how it patched expect) for user's convenience. However, if you don't use webdriver's promise you need to tell it when the test is done via the done callback

Related

jest testing pass variable to another test

I'm trying to assign a variable from one test to be accessed within another test. For example:
let user;
test('create new user', async () => {
const response = await createUser()
user = response
})
test('delete user', async () => {
const response = await deleteUser(user.id)
})
I understand that jest has a --runInBand option, however this still has user as undefined in "delete user". Any ideas how to accomplish this with jest? Thank you
Each test runs independently, and for good reason. Tests should be confirming isolated conditions, methods, and logic. All --runInBand does is run the tests in serially, but they still won't necessarily be able to share data objects the way you seem to be expecting.
Also, assuming these methods defer to a backend service of some kind, you're not going to easily be able to fully test the behavior of that system. It sounds like you want an end-to-end or integration testing framework, as opposed to a unit testing framework like Jest.
Keeping with Jest, you're likely going to need to mock whatever backend service is being called in createUser and deleteUser. Jest mocks can help replace external functions with new ones that create the types of conditions you want to test.
Alternatively or in addition, you might be able to stub your user object using beforeAll or beforeEach, creating sample data that allows you to test how deleteUser behaves when it's passed a particular object (likely bypassing whatever backend persistence with an aforementioned mock).

Finding the UI element in protractor is not consistent. Working with localhost and not with the server

Here is the code I am using expect(element(by.id('title')).getAttribute('value')).toMatch('Sample Title')
in local machine it is working perfectly fine and on server it is not with the following error.
Failed: Timed out waiting for asynchronous Angular tasks to finish after 11 seconds. This may be because the current page is not an Angular application. Please see the FAQ for more details: https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular
While waiting for element with locator - Locator: By(css selector, *[id="title"])
and surprisingly sometimes these tests are working on server when I execute them alone.
to add to the question. I observed that protractor is able to find only one element in the tests and all the remaining are ignored with the error as above.
what could be the solution for this?
That could be application issue. Sometimes it happens that angular never reports to protractor that all tasks are done, so you might get this timeout error that you have.
http://www.protractortest.org/#/timeouts
AngularJS If your AngularJS application continuously polls $timeout or
$http, Protractor will wait indefinitely and time out. You should use
the $interval for anything that polls continuously (introduced in
Angular 1.2rc3).
Angular For Angular apps, Protractor will wait until the Angular Zone
stabilizes. This means long running async operations will block your
test from continuing. To work around this, run these tasks outside the
Angular zone. For example:
this.ngZone.runOutsideAngular(() => { setTimeout(() => {
// Changes here will not propagate into your view.
this.ngZone.run(() => {
// Run inside the ngZone to trigger change detection.
}); }, REALLY_LONG_DELAY); }); As an alternative to either of these options, you could disable waiting for Angular, see below.
As said in the error, it seems your app is not an angular. Isn't it?
If so, you need to use it:
browser.waitForAngularEnabled(false);

Determining when karma-pact mock server has started

We're using the karma-pact plugin to run our pact JS client tests, based on the example from https://github.com/pact-foundation/pact-js/blob/master/karma/mocha/client-spec.js .
In the example there's a timeout in the before(), I believe to ensure the mock service has started before running the tests (see comment "required for slower Travis CI builds").
I'm reluctant to set a fixed timeout in our tests as it'll either be too short or too long in different environments (e.g. CI vs local) and so I was looking for a way to check if the server has started.
I'd tried using the pact API https://github.com/pact-foundation/pact-node#check-if-a-mock-server-is-running , however this appears to start a new mock server which conflicts with the one started by the karma-pact plugin (an Error: kill ESRCH error is reported when trying to run pact.createServer().running from within a test).
Is there a way to determine if the mock server has started up e.g. by waiting for a URL to become available? Possibly there's a way to get a reference the mock server started by the karma-pact plugin in order to use the pact-node API?
Actually the simplest way is to wait for the port to be in use.
Karma Pact by default will start the Mock on port 1234 (and you can specify your own). Once the port is up, the service is running and you can proceed.
For example, you could use something like wait-for-host to detect the running mock service:
var waitForPort = require('wait-for-port');
waitForPort('localhost', 1234, function(err) {
if (err) throw new Error(err);
// ... Mock Service is up - now we can run the tests
});

External promises never finish in unit tests with ngMock

I'm trying to unit test the resolution/rejection of external promises.
The problem is that those promises are never finished when ngMock module is injected - which is mandatory, as I'm triggering HTTP requests and timeouts.
Take for example angular-pouchdb, which is a dependency of my project. As of v2.0.0, because PouchDB promises are used, the tests no longer finish when ngMock is injected.
Example code, adapted from angular-pouchdb tests:
var scope;
beforeEach(function() {
var $injector = angular.injector(['ng', 'ngMock', 'pouchdb']);
var pouchDB = $injector.get('pouchDB');
scope = $injector.get('$rootScope');
db = pouchDB('db');
});
it('should wrap destroy', function(done) {
db.destroy()
.then(shouldBeOK)
.catch(shouldNotBeCalled)
.finally(done);
// No matter what's used ($apply, $applySync, $timeout.flush, etc) -- the tests will never finish.
scope.$apply();
});
The log for the above test is the following:
C:\Users\Gustavo\Projetos\main\angular-pouchdb (master)
λ karma start
INFO [karma]: Karma v0.12.37 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
INFO [PhantomJS 1.9.8 (Windows 8 0.0.0)]: Connected on socket s1A7jIzmtcOxkGCtzYke with id 42899233
PhantomJS 1.9.8 (Windows 8 0.0.0) Angular-aware PouchDB public API should wrap destroy FAILED
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
So, my question boils down to: is there something I'm missing from unit testing Angular? Or is it an internal bug in ngMock?
This issue has been created in the angular-pouchdb repository as well.
Edit 8/25: So we have actually solved this issue but I am still looking into what caused it. I will have a more updated write up in a few days.
Alright after hitting at this problem in my spare time for a number of days I have narrowed this down to some sort of exception failure in a 3rd party promise from pouchDB where it hits a 10 second timeout and doesn't throw a clean error back. I am able to get this by updating my
jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;
If I got back through and tweak a custom build and put some logging in to pouchDB I can confirm that the promise is not getting returned correctly in there, I have been able to replicate this in 3.6 and 4.0 pouchDB. From my wrapped console logs around the call nothing ever comes out of the wrapped call. Around test 3 I get uncaught 409 errors so there is clearly something not being handled correctly in pouchDB.
Here is an example without ngMock turned on so you can see how far it gets without it.
I do not think it's ngMock issue, but I think it's because PhantomJS is not ready to support PouchDB yet.
https://github.com/ariya/phantomjs/issues/10992
https://github.com/pouchdb/pouchdb/blob/c55db55d7edbf0821538e027399536c260af5876/docs/adapters.md

Configuring Intern to setup/teardown my server mock

I am writing a test suite for a JavaScript widget using Intern.
I have written some pure-JavaScript tests and some in-page DOM tests, but I'm a little stuck on how to write functional tests for the Ajax functionality, which should talk to my simple Node.js mock server (which works a treat for manual tests).
Specifically, what I would like to do:
Start the Node.js mock server as part of the test suite's setup phase
Teardown the mock server when the test is over
(Bonus points) Be able to interrogate the mock server from my Intern tests, for example, checking on the contents of a POST request to the mock
I am stuck on all three - I can't find any documentation or example code from Intern on how to handle setup or teardown of a separate process (like a Node.js mock server) in the test suite.
I am using Intern with Sauce Labs (hosted Selenium) - I'm not sure if my problem needs to be solved on just the Intern side, or on the Sauce Labs side as well. Hopefully somebody has got this working and can advise.
If you want a server to start and stop for each suite, the setup and teardown methods would be the place to do this, something like:
var server;
registerSuite({
name: 'myTests',
setup: function () {
server = startServer();
},
teardown: function () {
server.close();
},
...
});
startServer would be whatever function you use to start your test server. Presumably it would return an object that would be used to interact with the server. Any tests within the suite would then have access to the server object.

Categories

Resources