'no method expect' when using Protractor as a library - node.js

Using Protractor as a library
Unable to require a reference to Jasmine. Referencing the expect method returns output Cannot call method 'expect' of null.
Code updated to reflect comments:
var protractor = require('protractor');
require('protractor/node_modules/minijasminenode');
require('protractor/jasminewd'); // output: jasmine is undefined (this error can only be seen if the above line is commented out)
//expect(true).toBe(true); // output: Cannot call method 'expect' of null
var driver = new protractor.Builder()
.usingServer('http://localhost:4444/wd/hub')
.withCapabilities(protractor.Capabilities
.chrome()).build();
var ptor = protractor.wrapDriver(driver);
ptor.get('http://www.angularjs.org').then(function(){
ptor.element(protractor.By.model('yourName')).sendKeys('test')
.then(console.log('success')); // output: success
ptor.getCurrentUrl().then(function(url){
console.log(url); // output: http://www.angularjs.org
expect(url).toContain('angular'); // output: Cannot call method 'expect' of null
});
});
See https://github.com/angular/protractor/issues/21 for related information.

The global jasmine expect function is newly generated every time you step into jasmine's it function context.
What does that mean to your code ?
You cannot call expect outside of the it function.
example:
...
// somewhere in your code
...
// function expect doesn’t exist here
describe( 'your case', function() {
// expect doesn’t exist here either
it( 'should work', function() {
// horray - the global expect is available !!
// note : the expect function is generated before running your callback
// function to collect the expect'ed results for exactly this 'it' case
expect( true).toBe( true);
});
})

Quoting this post of Julie:
To make Jasmine automatically understand async testing, you'll need to require the jasmine-wd adapter with:
require('protractor/jasminewd');
(Just add the above line right after ... = require('protractor');.)

Related

Second sinon stub not called in async parallel

I am trying to test the following code:
var archive = function(callback){
call to this.archive() here...
}
var map = function(callback){
call to this.map() here...
}
async.parallel([map, archive], function(error){
handle errors here...
})
I am testing that the handle errors functionality is working by stubbing the archive and map functions so that one of them returns an error:
var mapStub = sinon.stub(MyClass.prototype, 'map').yields("mock error",null );
var archiveStub = sinon.stub(MyClass.prototype, 'archive').yields(null,null );
The problem I am having is that the archiveStub does not seem to be being used, as I am getting errors from a function which is called by that function (which would be expected if that function was called as I have not initialised variables for this test).
I have another test, where the archive function returns an error instead of the map function, and this test passes without seeming to call either of the stubbed methods instead of the stubs.
var mapStub = sinon.stub(MyClass.prototype, 'map').yields(null,null );
var archiveStub = sinon.stub(MyClass.prototype, 'archive').yields("mock error",null );
You want to use yieldsAsync instead of yields, otherwise the error is yielded prematurely (before all the parallel "tasks" have been started) and async.map() stops any further processing (using yields basically turns it into a synchronous operation).

Stub/mock process.platform sinon

I am working with process.platform and want to stub that string value to fake different OSes.
(this object is generated out of my reach, and I need to test against different values it can take on)
Is it possible to stub/fake this value?
I have tried the following without any luck:
stub = sinon.stub(process, "platform").returns("something")
I get the error TypeError: Attempted to wrap string property platform as function
The same thing happens if I try to use a mock like this:
mock = sinon.mock(process);
mock.expects("platform").returns("something");
You don't need Sinon to accomplish what you need. Although the process.platform process is not writable, it is configurable. So, you can temporarily redefine it and simply restore it when you're done testing.
Here's how I would do it:
var assert = require('assert');
describe('changing process.platform', function() {
before(function() {
// save original process.platform
this.originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
// redefine process.platform
Object.defineProperty(process, 'platform', {
value: 'any-platform'
});
});
after(function() {
// restore original process.platfork
Object.defineProperty(process, 'platform', this.originalPlatform);
});
it('should have any-platform', function() {
assert.equal(process.platform, 'any-platform');
});
});
sinon's stub supports a "value" function to set the new value for a stub now:
sinon.stub(process, 'platform').value('ANOTHER_OS');
...
sinon.restore() // when you finish the mocking
For details please check from https://sinonjs.org/releases/latest/stubs/

Is there a way to get mocha print the error object instead of error message?

Let me take an example.
before(function (done)
{
...
testUtils.someInitWork(done);
});
testUtils = {
someInitWork: function (done)
{
...
if (e)
// wrap the error into another error object and add contextual information.
e2 = errorManager.getError('myerror', e, { context: "more context for the error });
}
};
when test initialization code fails deep down a util function, it passes required contextual information into the error object. This error object is passed to before's done callback eventually. mocha prints the error message on console (I am using reporter spec). Instead if I can get it to print util.inspect(e) - that information will be more useful to debug the issue.
Of course, I can modify the test code to print it. but is there a way to modify how mocha reports the error (passed to before callback) on console?

this.async() in yeoman-generator

I am learning how to write a yeoman-generator. I have a question regarding the code below. It says by adding var done = this.async(); and call the method later in callback, we can make the function askFor() a asynchronized function. Could someone please explain why?
askFor: function() {
var done = this.async();
// Have Yeoman greet the user.
this.log(yosay('Welcome to the marvelous Myblog generator!'));
var prompts = [{
name: 'blogName',
message: 'What do you want to call your blog?',
default: 'myblog'
}];
this.prompt(prompts, function(props) {
this.blogName = props.blogName;
done();
}.bind(this));
}
Here is the code of this.async
this.async = function() {
return function() {};
}
Just fell on this question by pure coincidence searching for something else.
Actually, this.async is overwritten on each method during the run phase to either delay execution until completion or run synchronously.
You can read the relevant code line here:
https://github.com/yeoman/generator/blob/master/lib/base.js#L372-L393
So basically, behind the scenes Yeoman always call a callback. When you call this.async() we keep a reference variable and return the callback. If you don't call it, we take care of calling the callback manually after the function end.

Assertion in event brake down Mocha when run programmatically

I have problem with Mocha.
If i run this programmaticaly from Jake Mocha brakes down and don't show nothing more than some errors stuff like:
AssertionError: There is a code 200 in response
at Socket.<anonymous> (/home/X/Y/Z/test/test_Server.js:70:4)
at Socket.EventEmitter.emit (events.js:93:17)
at TCP.onread (net.js:418:51)
Runned from command line gives more expected results. That is:
19 passing (30ms)
7 failing
1) RTDB accepts connection with package and response with code 200 if correct package was send:
Uncaught AssertionError: There is a code 200 in response
at Socket.<anonymous> (/X/Y/Z/test/test_Server.js:70:4)
at Socket.EventEmitter.emit (events.js:93:17)
at TCP.onread (net.js:418:51)
2) XYZ should be able to store GHJ for IJS:
Error: expected f...
...
The problem is following code:
test('accepts connection with package and response with code 400 ' +
'if wrong package was send', function (done) {
console.log('client connecting to server');
var message = '';
var client = net.connect(8122, 'localhost', function () {
client.write('Hello');
client.end();
} );
client.setEncoding('utf8');
client.on('data', function (data) {
message += data;
} );
client.on('end', function (data) {
assert(message.indexOf('400') !== -1, 'There is a code 400 in response');
done();
});
client.on('error', function(e) {
throw new Error('Client error: ' + e);
});
});
If I do
assert(message.indexOf('400') !== -1, 'There is a code 400 in response');
just after
var message = '';
Mocha fails correctly (I mean displaying errors etc.), So this is fault of asynch assertion done on event. How can I correct that? Thats real problem Because this test is first, and I get no clue where to look for source of problem (If there is any). Should I somehow catch this assertion error and pass it to Mocha?
EDIT:
Answer to comment how is Jake running Mocha - just like that:
var Mocha = require('mocha');
...
task("test", [], function() {
// First, you need to instantiate a Mocha instance.
var mocha = new Mocha({
ui: 'tdd',
reporter: 'dot'
});
// Then, you need to use the method "addFile" on the mocha
// object for each file.
var dir = 'test';
fs.readdirSync(dir).filter(function(file){
// Only keep the .js files
return file.substr(-3) === '.js';
}).forEach(function(file){
// Use the method "addFile" to add the file to mocha
mocha.addFile(
path.join(dir, file)
);
});
// Now, you can run the tests.
mocha.run(function(failures){
if(failures){
fail("Mocha test failed");
} else {
complete();
}
});
}, {async: true});
I'm assuming since you say "programmatically" that your Jakefile issues require("mocha") and then creates a Mocha object on which it calls the run method.
If this is the case, then the reason it does not work is because Jake and Mocha are working at cross purposes. When Mocha executes a test, it traps unhandled exceptions. Schematically, (omitting details that are not important) it is something like:
try {
test.run();
}
catch (ex) {
recordFailure();
}
It is at the call to test.run that the test is executed. For tests that are purely synchronous, no problem. When a test is asynchronous, the asynchronous callback which is part of the test cannot execute inside the try... catch block Mocha establishes. The test will launch the asynchronous operation and return immediately. At some point in the future, the asynchronous operation calls the callback. When this happens, Mocha is not able to catch the exception in the asynchronous operation with a try... catch block. How does it catch such exceptions then? It listens to uncaughtException events.
Now, the problem when Mocha is run in the same execution context as Jake is that Jake also wants to trap uncaught exceptions. Jake sometimes has to launch asynchronous operations and wants to trap cases where these operations fail, so it listens to uncaughtException too. It installs its listener first. So when an asynchronous Mocha test fails with a exception, Jake's listener's is called, which cause Jake to immediately stop execution. Mocha never gets a chance to act.
I don't see a clear way to make both Jake and Mocha cooperate when run in the same execution context. There might be a way to fiddle with the handlers but I doubt that there is a robust way to make it work. (By "robust" I mean a way which will ensure that every single error is trapped and attributed to the correct source.) The vm module might help segregate their contexts while keeping them in the same OS process.
Based on this answer: https://stackoverflow.com/a/9132271/2024650
In few words: I remove listener on uncaughtException in Jake. This allow Mocha to handle this uncaughtExceptions. At the end I add back this listener.
This solves my answer for now:
task("test", [], function() {
var originalExeption = process.listeners('uncaughtException').pop();
//!!!in node 0.10.X you should also check if process.removeListener isn't necessary!!!
console.log(originalExeption);
// First, you need to instantiate a Mocha instance.
var mocha = new Mocha({
ui: 'tdd',
reporter: 'dot'
});
// Then, you need to use the method "addFile" on the mocha
// object for each file.
var dir = 'test';
fs.readdirSync(dir).filter(function(file){
// Only keep the .js files
return file.substr(-3) === '.js';
}).forEach(function(file){
// Use the method "addFile" to add the file to mocha
mocha.addFile(
path.join(dir, file)
);
});
// Now, you can run the tests.
mocha.run(function(failures){
if(failures){
fail("Mocha test failed");
} else {
complete();
}
process.listeners('uncaughtException').push(originalExeption);
});
}, {async: true});
it seems that you are testing a HTTP server by connecting with TCP to it, (correct if i'm wrong) if thats the case here, you should just drop your current test, and use appropriate module to test an HTTP server or REST API there are plenty modules like Superagent .
You should try call client.end() after you have received your first data event, this way it will call assert after first header is received.
if you want to continuously send and test requests, have all you assert in the data event and call correct assert each time it receives the header you want to test, just remember that you must call done() when its supposed to finish, and that it can't be delayed for a long period of time, the request must be one after another.
Other than that you can use async module if you want to test chained requests ( one request depends on another and another and so on..), in some case its useful to raise the mocha timeout to more than 10000 (10secs) to give the async part some time to complete.

Resources