Angular service not injected in unit test - javascript

Hi I have this simple test:
define(["angular", "angularMocks", "app", "normalizer"], function(angular, mocks, app) {
describe("service: normalizer", function () {
var normalizerService;
beforeEach(module("ADB"));
beforeEach(inject(function(_normalizer_) {
normalizerService = _normalizer_;
}));
var params = {};
var metadata = {};
var data = {};
var response = normalizerService.topLanguagesHybrid(metadata, data, params);
var type = typeof response;
expect(type).toEqual("object");
});
});
The issue is that the normalizer service is never being set, and in cmd I see the following error:
TypeError: 'undefined' is not an object (evaluating 'normalizerService.topLanguagesHybrid')
Note: I am using requirejs in this project and I can see that normalizer service file is being loaded into the browser (with all of its dependencies). It seems that it just not injected.
What did I do wrong?
Link to error

When you defining services, you forgot to define normalizer, so the correct syntax for the same is
define(["angular", "angularMocks", "app", "normalizer"], function(angular, mocks, app, normalizerService) {
describe("service: normalizer", function () {
var normalizerService;
beforeEach(module("ADB"));
var params = {};
var metadata = {};
var data = {};
var response = normalizerService.topLanguagesHybrid(metadata, data, params);
var type = typeof response;
expect(type).toEqual("object");
});
});

You forgot to define the it, for the test scenario, beforeEach runs before each "it" function.
define(["angular", "angularMocks", "app", "normalizer"], function(angular, mocks, app) {
describe("service: normalizer", function () {
var normalizerService;
beforeEach(module("ADB"));
beforeEach(inject(function(_normalizer_) {
normalizerService = _normalizer_;
}));
it('should define topLanguageHybrid method', function() {
var params = {};
var metadata = {};
var data = {};
var response = normalizerService.topLanguagesHybrid(metadata, data, params);
var type = typeof response;
expect(type).toEqual("object");
});
});
});
More info on jasmine: jasmine docs

Related

Loading multiple files with require statement on JS

The execution returns the following error when trying to load multiple js:
TypeError: Cannot read property 'get' of undefined
The solution that I am implementing has a login_steps.js:
var LoginSteps = function() {
var LoginSteps = require("../pages/pages.js");
browser.ignoreSynchronization = true;
this.World = function MyWorld() {
this.page = new LoginSteps();
};
this.Given(/^the page is open$/, function (callback) {
this.page.login_page.get();
callback();
});
};
module.exports = LoginSteps;
A page.js where I want to include all the modules that I need.
var Pages = function() {
module.exports = {
shipments_page: require('./shipments_page.js'),
login_page: require('./login_page.js'),
};
};
module.exports = Pages;
And the modules login_page.js:
var chai = require('chai').use(require('chai-as-promised'));
var expect = chai.expect;
this.get = function() {
browser.get('https://aaa/login');
};
this.setEmail = function(value) {
element(by.id('login-email')).sendKeys(value);
};
this.setPassword = function(value) {
element(by.id('login-password')).sendKeys(value);
};
this.clickAccede = function() {
element(by.id('login-submit')).click()
};
shipment_page.js:
var chai = require('chai').use(require('chai-as-promised'));
var expect = chai.expect;
this.pageIsLoaded = function() {
browser.waitForAngular();
expect(browser.getTitle()).to.be.eventually.equals('title');
};
Then when I execute the test the log shows
Failures:
1) Scenario: User login - features/login.feature:3
Step: Given the page is open - features/login.feature:4
Step Definition: features/steps/login_steps.js:16
Message:
TypeError: Cannot read property 'get' of undefined
at MyWorld.<anonymous> (/Users/mj/IdeaProjects/atpro/features/steps/login_steps.js:17:30)
at process._tickCallback (internal/process/next_tick.js:61:11)
1 scenario (1 failed)
5 steps (1 failed, 4 skipped)
Here is the code that you can try. Its works for me. I modified based on your code snippet. I won't use this pattern in my tests though.You may not want to write protractor-cucumber test using the pattern you are following. One should always use validation/assertions in step definition code. if you do validation in page object, even your validation fails, your test still will show passed.
login_steps.js
var LoginSteps = function() {
var LoginSteps = require("../pages/pages.js");
browser.ignoreSynchronization = true;
this.World = function MyWorld() {
this.page = LoginSteps;
};
this.Given(/^the page is open$/, function (callback) {
this.page.login_page.get();
callback();
});
};
module.exports = LoginSteps;
pages.js:
module.exports = {
shipments_page: require('./shipments_page.js'),
login_page: require('./login_page.js'),
};
If I interpreted correctly this is what you want. You have only to change page.js a little.
module.exports = function() {
this.shipments_page = require('./shipments_page.js');
this.login_page = require('./login_page.js');
};
Please try this. I cannot test at the moment :=)

Getting database information from other file

I have 3 different files called: app.js, ServerManager.js and Users.js.
To start everything, I run app.js which runs my ServerManager.
Running ServerManager in App.js:
var ServerManager = require('./modules/ServerManager.js');
var serverManager = new ServerManager({
app: app,
path: __dirname
});
Then serverManager is called and I can do stuff in there, then I'm trying to send stuff to Users.js from ServerManager but it seems like it doesn't work.
ServerManager.js
var config = require('../config.js');
var express = require('express');
var colors = require('colors');
var DatabaseManager = require('../modules/DatabaseManager.js');
var RouteManager = require('../modules/RouteManager.js');
var Users = require('../data/users.js');
module.exports = function(options){
return new ServerManager(options);
}
var ServerManager = function (options) {
var self = this;
this.app = options.app;
this.options = options;
this.dbManager = new DatabaseManager();
this.dbManager.use();
this.RoutesManager = new RouteManager(this.app);
this.RoutesManager.use();
this.usersManager = new Users(this);
}
ServerManager.prototype.getDatabase = function () {
return this.dbManager();
}
Users.js - Marked in code what it can't find.
module.exports = function (ServerManager) {
return new Users(ServerManager);
};
var Users = function (ServerManager) {
var self = this;
this.serverManager = ServerManager;
};
Users.prototype.createUser = function (username, email, password) {
this.serverManager.getDatabase(); <--- Can't find getDatabase()
};
I think that you should change your Users.js code to:
// This is the Users object
// and this function is its constructor
// that can create users instances
var Users = function (ServerManager) {
var self = this; this.serverManager = ServerManager;
};
// We define a method for the user object
Users.prototype.createUser = function (username, email, password) {
this.serverManager.getDatabase();
};
// We export the user object
module.exports = Users;
Now the then you do
var Users = require('../data/users.js');
you get the User object.
And so, you can do new Users(...).
The same thing has to be done for the ServerManager.
If you want to use your code as it is, you don't have to use the new keyword on the imported object.

How to expose a variable from one method within a controller.js to another controller.js with javascript express node

I have an Mongo, Express, Angular, Node application. I am trying to pass a variable that is a response of a method in 1 file to a different method in a different file.
So during a series of user actions it triggers a method exports.test inside the test.controller.js file
looks like this:
exports.test = function(req, res) {
var query = 'crazy query'
var params = { key:value }
var cb = function(err,stuff) {
});
res.json(stuff);
var testOutput = res.json(stuff);
return testOutput;
}
sendToServer(query,params,cb);
}
Notice how I have set testOutput equal to the response from the server. And I have returned testOutput, from the method.
Now I was curious, I have another controller actions.controller.js. And inside of this file I have a method called exports.actions
looks like this:
exports.actions = function(req, res, testOutput) {
console.log(testOutput);
var query = 'crazy query'
var params = { key:value }
var cb = function(err,stuff) {
});
res.json(stuff);
}
sendToServer(query,params,cb);
}
I am trying to expose var testOutput from test.controller.js to actions.controller.js, so I can pass testOutput as an argument into the exports.actions method. Is this possible?
You cannot directly expose any variable to other controllers. Communication between controllers can happen via services.
Define a service to update and save the value of testOutput:
angular.module('myApp',[])
.factory('myService',function(){
var init = {};
init.update = function(newVal) {
init.testOutput = newVal;
};
return init;
}]);
Your controllers:
angular.module('myApp')
.controller('Ctrl1',['myService',function(myService){
exports.test = function(req, res) {
var query = 'crazy query'
var params = { key:value }
var cb = function(err,stuff) {
});
res.json(stuff);
var testOutput = res.json(stuff);
myService.update(testOutput);
}
sendToServer(query,params,cb);
}
}]);
angular.module('myApp')
.controller('Ctrl2',['myService',function(myService){
exports.actions = function(req, res) {
console.log(mapService.testOutput); //use the variable as u like
var query = 'crazy query'
var params = { key:value }
var cb = function(err,stuff) {
});
res.json(stuff);
}
sendToServer(query,params,cb);
}
}]);

How to mock http.ServerResponse and http.IncomingMessage for express.static

I've had no trouble testing my own route handlers but in this case I want to test express's static handler. I can't for the life of me figure out why it's hanging. Clearly there's some callback I'm missing or some event I need to emit.
I tried to make the smallest example I could.
var events = require('events');
var express = require('express');
var stream = require('stream');
var util = require('util');
function MockResponse(callback) {
stream.Writable.call(this);
this.headers = {};
this.statusCode = -1;
this.body = undefined;
this.setHeader = function(key, value) {
this.headers[key] = value;
}.bind(this);
this.on('finish', function() {
console.log("finished response");
callback();
});
};
util.inherits(MockResponse, stream.Writable);
MockResponse.prototype._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};
function createRequest(req) {
var emitter = new events.EventEmitter();
req.on = emitter.on.bind(emitter);
req.once = emitter.once.bind(emitter);
req.addListener = emitter.addListener.bind(emitter);
req.emit = emitter.emit.bind(emitter);
return req;
};
describe('test', function() {
var app;
before(function() {
app = express();
app.use(express.static(__dirname));
});
it('gets test.js', function(done) {
var req = createRequest({
url: "http://foo.com/test.js",
method: 'GET',
headers: {
},
});
var res = new MockResponse(responseDone);
app(req, res);
function responseDone() {
console.log("done");
done();
}
});
});
Setup,
mkdir foo
cd foo
mkdir test
cat > test/test.js # copy and paste code above
^D
npm install express
npm install mocha
node node_modules/mocha/bin/mocha --recursive
it just times out.
What am I missing?
I also tried making the request a Readable stream. No change
var events = require('events');
var express = require('express');
var stream = require('stream');
var util = require('util');
function MockResponse(callback) {
stream.Writable.call(this);
this.headers = {};
this.statusCode = -1;
this.body = undefined;
this.setHeader = function(key, value) {
this.headers[key] = value;
}.bind(this);
this.on('finish', function() {
console.log("finished response");
callback();
});
};
util.inherits(MockResponse, stream.Writable);
MockResponse.prototype._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};
function MockMessage(req) {
stream.Readable.call(this);
var self = this;
Object.keys(req).forEach(function(key) {
self[key] = req[key];
});
}
util.inherits(MockMessage, stream.Readable);
MockMessage.prototype._read = function() {
this.push(null);
};
describe('test', function() {
var app;
before(function() {
app = express();
app.use(express.static(__dirname));
});
it('gets test.js', function(done) {
var req = new MockMessage({
url: "http://foo.com/test.js",
method: 'GET',
headers: {
},
});
var res = new MockResponse(responseDone);
app(req, res);
function responseDone() {
console.log("done");
done();
}
});
});
I've still been digging. Look inside static-server I see it creates a Readable stream by calling fs.createReadStream. It does effectively
var s = fs.createReadStream(filename);
s.pipe(res);
So trying that myself works just fine
it('test stream', function(done) {
var s = fs.createReadStream(__dirname + "/test.js");
var res = new MockResponse(responseDone);
s.pipe(res);
function responseDone() {
console.log("done");
done();
}
});
I thought maybe it's something about express waiting for the input stream to finish but that doesn't seem to be it either. If I consume the mock input stream with the response it works just fine
it('test msg->res', function(done) {
var req = new MockMessage({});
var res = new MockResponse(responseDone);
req.pipe(res);
function responseDone() {
console.log("done");
done();
}
});
Any insight what I might be missing would be helpful
Note: while suggestions for 3rd party mocking libraries are appreciated I'm still really looking to understand what I'm missing to do it myself. Even if I eventually switch to some library I still want to know why this isn't working.
I found two issues that prevent the finish callback from being executed.
serve-static uses send module which is used to create file readstream from the path and pipe it to res object. But that module uses on-finished module which checks if finished attribute is set to false in response object, otherwise it destroys the file readstream. So filestream never gets a chance to emit data event.
express initialization overwrites the response object prototype. So the default stream methods like end() method is overwritten by http response prototype:
exports.init = function(app){
return function expressInit(req, res, next){
...
res.__proto__ = app.response;
..
};
};
To prevent this, I added another middleware right before static middleware to reset it back to MockResponse prototype:
app.use(function(req, res, next){
res.__proto__ = MockResponse.prototype; //change it back to MockResponse prototype
next();
});
Here are the changes made to make it work with MockResponse:
...
function MockResponse(callback) {
...
this.finished = false; // so `on-finished` module doesn't emit finish event prematurely
//required because of 'send' module
this.getHeader = function(key) {
return this.headers[key];
}.bind(this);
...
};
...
describe('test', function() {
var app;
before(function() {
app = express();
//another middleware to reset the res object
app.use(function(req, res, next){
res.__proto__ = MockResponse.prototype;
next();
});
app.use(express.static(__dirname));
});
...
});
EDIT:
As #gman pointed out, it is possible to use direct property instead of prototype method. In that case the extra middleware to overwrite prototype isn't necessary:
function MockResponse(callback) {
...
this.finished = false; // so `on-finished` module doesn't emit finish event prematurely
//required because of 'send' module
this.getHeader = function(key) {
return this.headers[key];
}.bind(this);
...
//using direct property for _write, write, end - since all these are changed when prototype is changed
this._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};
this.write = stream.Writable.prototype.write;
this.end = stream.Writable.prototype.end;
};
It appears my answer is not complete. For some reason the app works only if the file is not found. First thing to debug is do the following in your shell (or cmd):
export DEBUG=express:router,send
then run the test, you'll get more info.
Meanwhile I am still looking into this, for now, ignore my answer below.
----------- ignore this till I verify that it does work -----------
It seems like express static does not favor the absolute path you give it (__dirname).
Try:
app.use(express.static('.'));
and it will work. Note that your current dir for the mocha runner is 'test/'
I have to admit this is quite a mistery. I tried 'fulling' it by doing:
app.use(express.static(__dirname + '/../test')
but still it didn't work. Even specifying a full path did not solve this. Strange.

Prototype handler not initiating on custom emitter

In the following code I'm expecting console.log to output the data that is passed along with the custom emitter 'output' but that's not occurring. From what I can tell Looper.prototype.output is called properly from withing the server handler but it's not responding to the emitter 'output' event that's defined in Looper.prototype.run. Why isn't my output event handler recognizing these events?
var express = require('express');
var http = require('http');
var spawn = require('child_process').spawn;
var util = require('util');
var fs = require('fs');
var EventEmitter = require("events").EventEmitter;
var sys = require("sys");
function Looper(req) {
this.req = req;
EventEmitter.call(this);
}
sys.inherits(Looper, EventEmitter);
Looper.prototype.run = function() {
var cmd = spawn('./flow',[this.req]); // <-- script that outputs req every second
cmd.stdout.setEncoding('utf8');
cmd.stdout.on('data', function(data) {
this.emit('output',data);
});
}
Looper.prototype.output = function(callback) {
this.on('output', function(data) {
return callback(data.trim());
});
}
var looper = new Looper('blah');
looper.run();
var app = express();
var webServer = http.createServer(app);
app.use(express.static(__dirname + '/public'));
app.get('/', function(req, res) {
res.send(
"<h1>hello world</h1>"
);
looper.output(function(res) {
console.log('blah');
console.log(res);
});
});
webServer.listen(3000);
Looper.prototype.run = function() {
var cmd = spawn('./flow',[this.req]); // <-- script that outputs req every second
cmd.stdout.setEncoding('utf8');
cmd.stdout.on('data', function(data) {
this.emit('output',data);
// ^ not what you think it is.
});
}
I think that this is not what you think it is in that callback. You need to capture the value of this outside of the callback first.
Looper.prototype.run = function() {
var self = this; // save this
var cmd = spawn('./flow',[this.req]); // <-- script that outputs req every second
cmd.stdout.setEncoding('utf8');
cmd.stdout.on('data', function(data) {
self.emit('output',data); // use previously saved value of this
});
}
Otherwise, this would default to the global object, and when the global object emits an event, noone is listening to it.

Categories