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/
Related
import ManagerDaoStub from '../salesforce/__test__/ManagerDaoStub';
import criticalMerchants from '../criticalMerchants';
describe('criticalMerchants Unit Tests', () => {
before(() => {
ManagerDaoStub.initStubs();
});
after(() => {
ManagerDaoStub.restoreStubs();
});
it('assert the arguments of stubbed method', (done)=>{
let load = criticalMerchants.createCases(MERCHANT, DEVICE_ID, KEY, {});
return done();
});
})
This is the test file written in node criticalMerchants.test.js. The method i want to test which is createCases uses a method in ManagerDao, which has been stubbed in ManagerDaoStub as below.
import ManagerDao from '../ManagerDao';
class ManagerDaoStub {
constructor() {
this.sandbox = sinon.sandbox.create();
}
initStubs(sandbox) {
this.sandbox = sandbox || this.sandbox;
this.restoreStubs();
this.initFindOpenCases();
}
restoreStubs() {
this.sandbox.restore();
}
initFindOpenCases() {
let findOpenCases = this.sandbox.stub(ManagerDao, "findOpenCases");
findOpenCases
.withArgs(DEVICE_ID, KEY, match.func)
.callsArgWith(2, new Error("Test error"));
}
}
I want to assert whether this stubbed method initFindOpenCases was called with the right arguments (DEVICE_ID,KEY,null). I used
sinon.assert.calledWith(ManagerDaoStub.initFindOpenCases, DEVICE_ID, KEY, null) and this gives the following error:
AssertError: initFindOpenCases() is not stubbed.
Can someone suggest a proper way to do this?
First off, if ManagerDao.initFindOpenCases is an instance method (I'm unsure since you haven't shared its definition), then you can't stub it on the constructor like you've done here:
let findOpenCases = this.sandbox.stub(ManagerDao, "findOpenCases")
You need to either create an instance first-- then stub it on that instance-- or stub it on the prototype itself like so:
let findOpenCases = this.sandbox.stub(ManagerDao.prototype, "findOpenCases");
Secondly, you're making the same mistake again in your assertion, combined with another:
sinon.assert.calledWith(ManagerDaoStub.initFindOpenCases, DEVICE_ID, KEY, null)
ManagerDaoStub is the constructor, and it does not have an initFindOpenCases property. Its prototype does, and thus its instances do as well. On top of that, ManagerDaoStub.prototype.initFindOpenCases is still not a stub. It's a method you're calling to create a stub, but it is not itself a stub. More plainly, you're getting ManagerDao mixed up with ManagerDaoStub.
Assuming you make example change above, you can make your assertion work like this:
sinon.assert.calledWith(ManagerDao.prototype.initFindOpenCases, DEVICE_ID, KEY, null)
However, this isn't all I would recommend changing. This latter mixup is arising largely because you're vastly over-complicating the setup code of your test. You don't need to make an entire class to stub one method of ManagerDao.
Instead, just replace your before and after calls with these:
beforeEach(() => {
// Create the stub on the prototype.
sinon.stub(ManagerDao.prototype, 'findOpenCases')
.withArgs(DEVICE_ID, KEY, sinon.match.func)
.callsArgWith(2, newError('Test Error'));
});
afterEach(() => {
// As of sinon 5.0.0, the sinon object *is* a sandbox, so you can
// easily restore every fake you've made like so:
sinon.restore();
});
Aside from that, I recommend looking deeply into the difference between properties on a constructor and properties on its prototype. That knowledge will make stuff like this much easier for you. Best place to start is probably here on MDN.
Although there are posts regarding this , I could not fix it using before, after functions and restoring the objects. Posting the code below:-
var Log = sinon.stub(hello, 'someEvent', function(type, name){
var obj = {};
obj.addData = function(data){
return;
};
obj.complete = function(){
return;
}
return obj;
}),
someVar = sinon.stub(servicecore, 'some'),
The error I get is:-
Attempted to wrap someEvent which is already wrapped.
And
Attempted to wrap some which is already wrapped.
Can someone help with this?
Edited below
I even tried with before and after functions as suggested:-
var Log,someVar;
before(function(){
Log = sinon.stub(hello, 'someEvent', function(type, name){
var obj = {};
obj.addData = function(data){
return;
};
obj.complete = function(){
return;
}
return obj;
});
someVar = sinon.stub(servicecore, 'some');
});
after(function(){
Log.restore();
someVar.restore();
});
Tried even with beforeEach and afterEach functions but same error.
From the sinon documentation:
var stub = sinon.stub(object, "method"); Replaces object.method with a
stub function. The original function can be restored by calling
object.method.restore(); (or stub.restore();). An exception is thrown
if the property is not already a function, to help avoid typos when
stubbing methods.
The stub is normally restored after the test is complete using the after or afterEach hooks.
after(function() {
// runs before all tests in this block
someVar.restore();
});
afterEach(function() {
// runs before each test in this block
someVar.restore();
});
you are stubbing someVar.some not someVar itself
so you need to restore its method:
someVar.some.restore();
If you still have problems, then try to stub using the following method.
someVar.some = sinon.stub();
Looks like the same but it is not :) (discovered after hours of swearing)
Anyway let's try the sandbox in sinon to stub from it and just restore the sandbox at the end
https://sinonjs.org/releases/v1.17.7/sandbox/
I'm currently writing a NodeJS app and I'd like to write a test for a function. SinonJS seems to be the spy/stub/mock library of choice, but I can't seem to figure out how to stub a method on a function. For instance:
Lets say that I'm using a library called ExecSync. I want to stub the sh() method on that library from within my Spec, but it doesn't seem to work correctly. Would someone be kind enough to provide an example of stubbing a library method, from inside of a separate spec file?
To be clearer:
spec.js - This is where I'm writing my test.
util.js - This is where the method I'm testing exists. The method calls execSync.sh() and is included via npm and require().
Any help would be greatly appreciated.
Some code would be good, but usually this can be achieved like this (using mocha)
describe('A test', function() {
beforeEach(function() {
// what you want to stub is passed as a string
sinon.stub(ExecSync, 'sh').yields(null,40);
});
afterEach(function() {
ExecSync.restore();
});
it('has behaviour', function() {
ExecSync.sh(function(err, res) {
// err = null, res = 40
});
});
});
Another common practice when you cannot stub a dependency, is to write that dependency onto your module under test, such as
mymodule.ExecSync = function(arg) {
ExecSync.sh(arg);
};
Then you can simply stub ExecSync on your module and never have to call the dependency at all.
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');.)
I'm trying to unit test a CouchDB design doc (written using couchapp.js), example:
var ddoc = {
_id: '_design/example',
views: {
example: {
map: function(doc) {
emit(doc.owner.id, contact);
}
}
}
}
module.exports = contacts
I can then require this file into a mocha test very easily.
The problem is CouchDB exposes a few global functions that the map functions use ("emit" function above) which are unavailable outside of CouchDB (i.e. in these unit tests).
I attempted to declare a global function in each test, for example:
var ddoc = require('../example.js')
describe('views', function() {
describe('example', function() {
it('should return the id and same doc', function() {
var doc = {
owner: {
id: 'a123456789'
}
}
// Globally-scoped mocks of unavailable couchdb 'emit' function
emit = function(id, doc) {
assert.equal(contact.owner.id, id);
assert.equal(contact, doc);
}
ddoc.views.example.map(doc);
})
})
})
But Mocha fails with complaints of global leak.
All of this together started to "smells wrong", so wondering if there's better/simpler approach via any libraries, even outside of Mocha?
Basically I'd like to make mock implementations available per test which I can call asserts from.
Any ideas?
I'd use sinon to stub and spy the tests. http://sinonjs.org/ and https://github.com/domenic/sinon-chai
Globals are well, undesirable but hard to eliminate. I'm doing some jQuery related testing right now and have to use --globals window,document,navigator,jQuery,$ at the end of my mocha command line so... yeah.
You aren't testing CouchDb's emit, so you should stub it since a) you assume that it works and b) you know what it will return
global.emit = sinon.stub().returns(42);
// run your tests etc
// assert that the emit was called
This part of the sinon docs might be helpful:
it("makes a GET request for todo items", function () {
sinon.stub(jQuery, "ajax");
getTodos(42, sinon.spy());
assert(jQuery.ajax.calledWithMatch({ url: "/todo/42/items" }));
});
Hope that helps.