Adding batches asynchronously to a Vows suite - node.js

I've got some code like this. The idea is that I'm reading fixture data from files and using the data from each file to add a batch:
// test.js
var vows = require('vows')
, async = require('async')
, suite;
exports.suite = suite = vows.describe('My tests');
function run_tests() {
set_up = [
find_tests(tests_path) // gets test data
];
async.series(set_up, function(errs, tests) {
tests = tests.pop();
tests.forEach(function(test) {
var batch = make_batch(test); // makes a batch
suite.addBatch(batch);
})
});
}
run_tests();
Obviously vows test.js doesn't find any tests because the batches are added asynchronously. I've got no idea how to make this work though. I want to use vows to be able to use reporters.

Related

run onPrepare function synchronously in Jasmine, before executing specs

Hello stackoverflow community,
The task
I'm running Jasmine tests programmatically using jasmine.execute(). My task is to run onPrepare function, where I do some setup work like setting up reporters etc, and I need that function to be synchronous (has to be finished before running specs)
Approach #1
The first approach I tried was to just declare an async onPrepare function, which also includes the code for specifying reporters, and then do
await onPrepare();
await jasmine.execute();
Problem
In the result I get jasmine.getEnv() is not a function. I assume because getEnv() becomes available as .execute() is ran. So I understand this won't work
Approach #2
The next thing I tried was to create a helper file with my sync code, specify it in the config and run jasmine.execute();.
So, if simplified, I have
// conf.js
(async () => {
let Jasmine = require('jasmine');
let jasmine = new Jasmine();
let variables = require("./variables.json");
let {spawn} = require("child_process");
let childProcess = spawn(variables.webdriver);
console.log(`Webdriver started, pid: ${childProcess.pid}`);
jasmine.exitOnCompletion = false;
jasmine.loadConfig({
'spec_files': ['specs/*.spec.js'],
'helpers': ['on-jasmine-prepare.js'],
'stopSpecOnExpectationFailure': false,
'random': false,
})
const result = await jasmine.execute();
console.log('Test status:', result.overallStatus);
console.log('Closing library and webdriver process');
await library.close();
await childProcess.kill();
console.log('webdriver killed:', childProcess.killed);
})()
// on-jasmine-prepare.js
(async () => {
const {SpecReporter} = require("jasmine-spec-reporter");
const library = require("./library/library");
const variables = require("./variables.json");
const errorHandler = require("./modules/on-error-handler");
jasmine.getEnv().clearReporters();
jasmine.DEFAULT_TIMEOUT_INTERVAL = 3 * 60 * 1000;
jasmine.getEnv().addReporter(new SpecReporter({}))
global.library = new library.Library(variables.IP);
console.log('library instantiated')
await library.deleteSessions();
console.log('sessions deleted')
await library.launch(library.home);
console.log('home page launched')
jasmine.getEnv().addReporter(
errorHandler(library)
)
console.log('debugger reporter added' )
})();
Problem
The problem that I noticed that the helper file is executed asynchronously with the specs and I get a spec error before the helper function finishes (basically because of race condition). Below the output example, where you can see some console.log from onPrepare was ran after spec started
Webdriver started, pid: 40745
library instantiated
Jasmine started
sessions deleted
Example
✗ App is loaded (7 secs)
- Error: Session already exist
home page launched
debugger reporter added
The question
How do I run onPrepare function synchronously, before specs? Preferably natively (using only jasmine capabilities). Otherwise maybe using third party packages. I know it's possible because #protractor had this feature, however I couldn't back-engineer it
MacOS
node v16.13.2
jasmine v4.1.0
Thank you

Nodejs required variable undefined if script file not run directly?

I apologise for the phrasing of the question - it's a bit difficult to sum up as a question - please feel free to edit it if you can clarify. Also, as this quite a complex and long query - thank you to all those who are putting in the time to read through it!
I have 4 files (listed with directory tree from project root) as part of a project I'm building which aims to scrape blockchains and take advantage of multiple cores do get the job done:
./main.js
./scraper.js
./api/api.js
./api/litecoin_api.js
main.js
const { scraper } = require('./scraper.js')
const blockchainCli = process.env.BLOCKSCRAPECLI || 'litecoin-cli'
const client = (args) => {
// create child process which returns a promise which resolves after
// data has finished buffering from locally hosted node using cli
let child = spawn(`${blockchainCli} ${args.join(' ')}`, {
shell: true
})
// ... wrap command in a promise here, etc
}
const main = () => {
// count cores, spawn a worker per core using node cluster, add
// message handlers, then begin scraping blockchain with each core...
scraper(blockHeight)
}
main()
module.exports = {
client,
blockchainCli
}
scraper.js
const api = require('./api/api.js')
const scraper = async (blockHeight) => {
try {
let blockHash = await api.getBlockHashByHeight(blockHeight)
let block = await api.getBlock(blockHash)
// ... etc, scraper tested and working, writes to shared writeStream
}
module.exports = {
scraper
}
api.js
const { client, blockchainCli } = require('../main.js')
const litecoin = require('./litecoin_api')
let blockchain = undefined
if (blockchainCli === 'litecoin-cli' || blockchainCli === 'bitcoin-cli') {
blockchain = litecoin
}
// PROBLEM HERE: blockchainCli (and client) are both undefined if and
// only if running scraper from main.js (but not if running scraper
// from scraper.js)
const decodeRawTransaction = (txHash) => {
return client([blockchain.decodeRawTransaction, txHash])
}
const getBlock = (blockhash) => {
return client([blockchain.getBlock, blockhash])
}
const getBlockHashByHeight = (height) => {
return client([blockchain.getBlockHash, height])
}
const getInfo = () => {
return client([blockchain.getInfo])
}
const getRawTransaction = (txHash, verbose = true) => {
return client([blockchain.getRawTransaction, txHash, verbose])
}
module.exports = {
decodeRawTransaction,
getBlock,
getBlockHashByHeight,
getInfo,
getRawTransaction
}
So, I've taken out most the noise in the files which I don't think is necessary but it's open source so if you need more take a look here.
The problem is that, if I start the scraper from inside scraper.js by doing, say, something like this: scraper(1234567) it works like a charm and outputs the expected data to a csv file.
However if I start the scraper from inside the main.js file, I get this error:
Cannot read property 'getBlockHash' of undefined
at Object.getBlockHashByHeight (/home/grayedfox/github/blockscrape/api/api.js:19:29)
at scraper (/home/grayedfox/github/blockscrape/scraper.js:53:31)
at Worker.messageHandler (/home/grayedfox/github/blockscrape/main.js:81:5)
I don't know why, when launching the scraper from main.js, the blockchain is undefined. I thought it might be from the destructuring, but removing the curly braces from around the first line in the example main.js file doesn't change anything (same error).
Things are a bit messy at the moment (in the middle of developing this branch) - but the essential problem now is that it's not clear to me why the require would fail (cannot see variables inside main.js) if it's used in the following way:
main.js (execute scraper()) > scraper.js > api.js
But not fail (can see variables inside main.js) if it's run like this:
scraper.js (execute scraper()) > api.js
Thank you very much for your time!
You have a circular dependency between main and api, each requiring in the other. main requires api through scraper and api directly requires main. That causes things not to work.
You have to remove the circular dependency by putting common shared code into its own module that can be included by both, but doesn't include others that include it. It just needs better modularity.

can mocha tests load reuqirements once?

I think every spec files first load by mocha and mocha runs them at least describe part if "it"s wasn't selected with "only".
// Lines before first "it" will run for every spec files
// even if I don't mark them with ".only" word
var db = require("../../node/server/db"),
should = require('should')
...;
describe("main describe...", function () {
var user = {},
apiRootUrl = "http://127.0.0.1:3000";
user.nameSurname = "Cem Topkaya";
kullanici = schema.AJV.validate(schema_name, user);
describe("child describe", function () {
it(....)
it.only(....)
it(....)
}
}
I want to run only one spec file not others. Is there any way to prevent this?
If you give to Mocha the full path of your test file, it will just load that file and no other file:
$ mocha path/to/test.js

Unit test for node js

I am new to nodejs, and need to write unit test for a node project. I try to learn mocha and there are two questions:
when I write unit test for function A, in A it also use function B, so how can I mock an output for B?
how can I unit test these endpoints in app.js. like app.get, app.put.
can someone give me some suggestions or simple examples?
Can someone also give me some advice on writing unit test for nodejs, thanks so much.
Thanks so much everyone.
Answering Q1,
If the output of b method is used in a metheod, then you can make the test of b method first.
Otherwise you can prepare result of b in before section of your test method and use it in a method.
It depends on your approach of testing.
Answering Q2 -
You can use superagent for sending get or post request ...
Some code examples ...
require('should');
var assert = require("assert");
var request = require('superagent');
var expect = require('expect.js');
then,
describe('yourapp', function(){
before(function(){
// function start
start your server code
// function end
})
describe('server', function(){
describe('some-description', function(){
it('should return json in response', function(done){
request.post('http path')
.send(JSON.parse("your json"))
.end(function(res){
expect(res).to.exist;
expect(res.status).to.equal(200);
expect(res.text).to.contain('ok');
done();
});
})
});
})
after(function(){
//stop your server
})
});
Here done is an important aspect in a unit testing component for asynchronous method testing.
Some reference -
superagent
this blog post
Hope this will help you,
Thanks
Answering Q1,
If the funcitons in different modules,
You can use a mock tool : fremock
Using freemock You can do this:
your code
//function a exports in the module named mA
function a(){
return "1";
}
//function a exports in the module named mB
function b(){
a();
}
test code
var freemock = require('freemock');
freemock.start()
var mock_b = freemock.getMock('mB');
mock_b.setMethod({
"a":{
willReturn:"1"
}
})
freemock.end();
Some advice:
Mocha is good test framework for node.js .
For example,
Assert tool: should.js
Code coverage tool:istanbul
...
Mocha combines all this tools;
Here is a demo using Mocha:
your code(filename:mA.js)
//in the module named mA
function a(){
return true;
}
test code(filename:testmA.js)
var should = require('should');
beforeEach(function(){
//do something before testing
});
afterEach(function(){
//do something after testing
});
describe("test",function(){
describe("test1",function(){
it("if true",function(){
var mA = require('./mA');
var result = mA.a();
should.ok(result);
});
it("if false",function(){
//other test
});
});
describe("test2",function(){
it("test2-1",function(){
//other test
})
})
})
We should need run.js to start the test:
//run.js
var Mocha = require('mocha');
var mocha = new Mocha;
mocha.addFile(__dirname+'/test/testmA.js')
mocha.run();
The project dir tree is:
|- run.js
|
|- mA.js
|
|- test - testMA.js
Finally
Run this command:
istanbul cover run.js
Hope you enjoy!
I am recently involved in a node project where I have to run unit tests.
Eventually I wrote a small script runner for karma using NW.JS
This allowed me to access all node modules and run my tests on the server itself. I uploaded this project to github, Narma.
Right now it was only tested on a Mac

Mocha and ZombieJS

I'm starting a nodejs project and would like to do BDD with Mocha and Zombiejs. Unfortunately I'm new to just about every buzzword in that sentence. I can get Mocha and Zombiejs running tests fine, but I can't seem to integrate the two - is it possible to use Mocha to run Zombiejs tests, and if so, how would that look?
Just looking for "hello world" to get me started, but a tutorial/example would be even better.
Thanks!
Assuming you already have installed mocha, zombie and expect.js according to instructions, this should work for you:
// Put below in a file in your *test* folder, ie: test/sampletest.js:
var expect = require('expect.js'),
Browser = require('zombie'),
browser = new Browser();
describe('Loads pages', function(){
it('Google.com', function(done){
browser.visit("http://www.google.com", function () {
expect(browser.text("title")).to.equal('Google');
done();
});
});
});
Then you should be able to run the mocha command from your root application folder:
# mocha -R spec
Loads pages
✓ Google.com (873ms)
✔ 1 tests complete (876ms)
Note: If your tests keep failing due to timeouts, it helps to increase mocha's timeout setting a bit by using the -t argument. Check out mocha's documentation for complete details.
I wrote a lengthy reply to this question explaining important gotchas about asynchronous tests, good practices ('before()', 'after()', TDD, ...), and illustrated by a real world example.
http://redotheweb.com/2013/01/15/functional-testing-for-nodejs-using-mocha-and-zombie-js.html
if you want to use cucumber-js for your acceptance tests and mocha for your "unit" tests for a page, you can use cuked-zombie (sorry for the advertising).
Install it like described in the readme on github, but place your world config in a file called world-config.js
`/* globals __dirname */
var os = require('os');
var path = require('path');
module.exports = {
cli: null,
domain: 'addorange-macbook': 'my-testing-domain.com',
debug: false
};
Then use mocha with zombie in your unit tests like this:
var chai = require('chai'), expect = chai.expect;
var cukedZombie = require('cuked-zombie');
describe('Apopintments', function() {
describe('ArrangeFormModel', function() {
before(function(done) { // execute once
var that = this;
cukedZombie.infectWorld(this, require('../world-config'));
this.world = new this.World(done);
// this inherits the whole world api to your test
_.merge(this, this.world);
});
describe("display", function() {
before(function(done) { // executed once before all tests are run in the discribe display block
var test = this;
this.browser.authenticate().basic('maxmustermann', 'Ux394Ki');
this.visitPage('/someurl', function() {
test.helper = function() {
};
done();
});
});
it("something on the /someurl page is returned", function() {
expect(this.browser.html()).not.to.be.empty;
});

Resources