Prevent onComplete exit in Jasmine - javascript

I would like to make multiple calls of test function, but after first time, that jasmine.onComplete is called, the programs exits. I already know, that I can't do multiple test in parallel, but I thought, that I may be able to queue them, but if the jasmine exit the node I am done. Therefor:
Is there a way to prevent jasmine to exit node?
const toCall = {}
jasmine.onComplete(function(passed) {
toCall[varReporter.last.name](passed, varReporter.last.result)
toCall[varReporter.last.name] = null
});
function test(folder, file, callback){
toCall[file] = callback
jasmine.execute(['JS/' + folder + '/tests/' + file + '.js'])
}
// User saves a file, a test get triggered.
test('prototype', 'Array', function(passed, result){
console.log(util.inspect(result, { colors: true, depth: null }))
})
// User saves an other file and an other test should get triggered, but can't.
My test will not be called in groups, but one after an other, based on users interactions with files. I need to run test after each save, so that I can determine whenever I should process them or not.

You could override jasmine exit option:
jasmine.exit = () => {};
But that causes various glitches.
I'd rather run whole script in another process:
run-test.js
const path = require('path'),
Jasmine = require('jasmine/lib/jasmine.js');
const jasmine = new Jasmine({ projectBaseDir: path.resolve() });
jasmine.execute(process.argv.slice(2));
watch-tests.js
const fork = require('child_process').fork;
function test(folder, file) {
fork('run-test.js', ['JS/' + folder + '/tests/' + file + '.js']);
}
// User saves a file, a test get triggered.
test('prototype', 'Array')
// User saves an other file and an other test should get triggered, but can't.

Related

How to run test suite in parallel but not the single tests

I'm using Playwright.dev to automate our UI tests. Currently I face the following issue:
In a single spec.ts file I have different test suites. Those test suites should run in parallel but not each test. I can not split those test suites into separate files because they are created dynamically. Why I want to run the tests of each test suite serial is, to reuse the existing page. Because it's much faster to just reuse the page without doing a complete refresh of the page the whole time. I'll try to explain my problem with some pseudo-code:
catalogs.forEach((objectIdsOfCatalog, catalogId) => {
// each suite could run in parallel because they do not
// depend on each other
test.describe('Test catalog "' + catalogId + '"', () => {
let newVersion: PageObject;
let actualVersion: PageObject;
test.beforeAll(async ({browser}) => {
console.log('New page for', catalogId);
const {actualUrl, newUrl} = getConfig();
const context = await browser.newContext();
actualVersion = new PageObject(await context.newPage(), actualUrl);
newVersion = new PageObject(await context.newPage(), newUrl);
});
test.afterAll(async () => {
console.log('Close page for', catalogId);
actualVersion.close();
newVersion.close();
actualVersion = null;
newVersion = null;
});
// those tests should ran serial because it's faster
// if we just navigate on the existing page due to the
// client side caching of the web app
for (const objectId of objectIdsOfCatalog) {
test('Testing "' + objectId + '"', async () => {
});
}
});
});
Is there some way to achieve the following behavior in Playwright or do I have to rethink my approach?
I don't know if multiple test.describe.serial blocks could be nested in a test.describe.parallel (and if that works), but maybe that's worth a try.
Another option could be to not generate real tests, but just to generate steps (test.step) inside tests inside a test.describe.parallel block.
And where do the catalogs come from? Maybe instead of generating describe blocks, you could generate projects in the playwright.config.ts? Projects run in parallel by default I think. But don't know if that approach would work if the data is coming from some async source.

How a gulp function can know that functions called inside it are finished?

I'm writing a gulp task that copy sass files into a tmp folder and then create css.
function copy_sass(done) {
var conponments = setup.conponments;
var sassList = config.conponments.sass;
var mainPath = config.path.src.sass.main;
var rootPath = config.path.src.sass.root;
var source = getPaths(conponments, sassList, mainPath);// get a filtered list of path
var destination = config.path.tmp.sass_tmp;
copyPath(mainPath + 'mixin/**', destination + 'main/mixin/');
copyPath(mainPath + 'settings/**', destination + 'main/settings/');
copyPath(rootPath + 'style.scss', destination);
copyPath(source, destination + 'main/conponment/');
done();
};
function css_build(done) {
var source = config.path.tmp.sass_tmp + '**/*.scss';
var destination = config.path.tmp.css.root;
return src(source)
.pipe(bulkSass())
.pipe(sass())
.pipe(csscomb())
.pipe(cssbeautify({indent: ' '}))
.pipe(autoprefixer())
.pipe(gulp.dest(destination));
done();
};
function copyPath(source, destination) {
return src(source)
.pipe(dest(destination));
};
exports.getcss = series(
copy_sass,
css_build
);
exports.filter = filter_tmp_sass;
exports.css = css_build;
When I call functions in series with the task getcss, gulp don't seem to wait before the copy task is finished and css_build do nothing because the paths are not already copied.
When I launch the copy task and then the css task manually, all is working. So I think that the problem is that the copy_sass function is considered as finished before the end of the copyPath functions, and then css_build is launched before the paths are copied.
What I expect is that the getcss task wait until the copy_sass function and the copyPath function inside it are finished before launch css_build.
Node libraries handle asynchronicity in a variety of ways.
The Gulp file streams (usually started with src()) work asynchronously. This means, that they start some kind of work, but instantly return when being called. This is the reason why you always need to return the stream from the task, so that Gulp knows when the actual work of the task is finished, as you can read in the Gulp documentation:
When a stream, promise, event emitter, child process, or observable is returned from a task, the success or error informs gulp whether to continue or end.
Regarding your specific example, in your task copy_sass you call copyPath multiple times. The copying is started, but the methods instantly return without waiting for completion. Afterwards, the done callback is called telling Gulp that the task is done.
To ensure task completion, you need to return every single stream to Gulp. In your example, you could create a separate task for each copy operation and aggregate them via series() or even parallel():
function copyMixin() {
return src('...').pipe(dest(...))
}
function copySettings() {
return src('...').pipe(dest(...))
}
// ...
var copySass = parallel(copyMixin, copySettings, ...)

Test immediately invoke function

I'm looking to create a test suite for a javascript file that contains an immediately invoked function. Eg.:
(function(context) {
context.setVariable("a") = context.getVariable("a") + 1
})(context);
I am not able to change the file to be tested.
My current attempt is using jest and the following:
context = null
test('test1', () => {
context = new context_mock();
context.setVariable("a", "1");
require("./My-Javascript");
// Check result
helper.check(context.getVariable("a"), 2);
});
test('test2', () => {
context = new context_mock();
context.setVariable("a", "2");
require("./My-Javascript");
// Check result
helper.check(context.getVariable("a"), 3);
});
In this case, test 2 always fails. I assume it's because the javascript file can't be required twice.
Edit: Yes context is a global variable that is operated on when the script is required. I'm aware this is an ugly solution but I'm unable to change the original file.
Any suggestions are appreciated.
jest has an extra level of caching the modules which is preventing the require from running multiple times.
Adding the following to clear the modules cache prior to calls allows the script to run multiple times:
beforeEach(() => {
jest.resetModules()
});

In Node.js, asking for a value using Prompt, and using that value in a main js file

I'm pretty new to node.js and it seems fairly easy to use but when it comes to getting a value using the command line and returning that value to be used in another package or .js, it seems harder than I expected.
Long story short, I've used a npm package (akamai-ccu-purge), to enter a file to purge on the akamai network successfully.
I want to make it more dynamic though by prompting the user to enter the file they want purged and then using that in the akamai package.
After making a few tries using var stdin = process.openStdin(); I actually found another npm package called Prompt that seemed to be easier. Both ways seem to have the same problem though.
Node doesn't seem to want to stop for the input. It seems to want to automatically make the purge without waiting for input even though I've called that module first. It actually gets to the point where I should enter the file but it doesn't wait.
I am definitely missing something in my understanding or usage here, what am I doing wrong?
My code so far is:
var purgeUrl = require('./getUrl2');
var PurgerFactory = require('../../node_modules/akamai-ccu-purge/index'); // this is the directory where the index.js of the node module was installed
// area where I placed the authentication tokens
var config = {
clientToken: //my tokens and secrets akamai requires
};
// area where urls are placed. More than one can be listed with comma separated values
var objects = [
purgeUrl // I am trying to pull this from the getUrl2 module
];
// Go for it!
var Purger = PurgerFactory.create(config);
Purger.purgeObjects(objects, function(err, res) {
console.log('------------------------');
console.log('Purge Result:', res.body);
console.log('------------------------');
Purger.checkPurgeStatus(res.body.progressUri, function(err, res) {
console.log('Purge Status', res.body);
console.log('------------------------');
Purger.checkQueueLength(function(err, res) {
console.log('Queue Length', res.body);
console.log('------------------------');
});
});
});
The getUrl2 module looks like this:
var prompt = require('../../node_modules/prompt');
//
// Start the prompt
//
prompt.start();
//
// Get property from the user
//
prompt.get(['newUrl'], function (err, result) {
//
// Log the results.
//
console.log('Command-line input received:');
console.log(' http://example.com/custom/' + result.newUrl);
var purgeUrl = 'http://example.com/custom/' + result.newUrl;
console.log(purgeUrl);
module.exports = purgeUrl;
});
Thanks again for the help!
I would probably just allow getURL2 to expose a method that will be invoked in the main module. For example:
// getURL2
var prompt = require('../../node_modules/prompt');
module.exports = {
start: function(callback) {
prompt.start();
prompt.get(['newUrl'], function (err, result) {
// the callback is defined in your main module
return callback('http://example.com/custom/' + result.newUrl);
});
}
}
Then in your main module:
require('./getUrl2').start(function(purgeURL) {
// do stuff with the purgeURL defined in the other module
});
The implementation may differ, but conceptually, you need to make your second module, which requires some sort of input from the user, happen as a result of that input. Callbacks are a common way to do this (as are Promises). However, as prompt is not necessarily exposing a method that would necessitate a Promise, you can do it with plain old callbacks.
You might also want to search around for articles on writing command line tools (sometimes referenced as CLIs) or command line apps with Node. I found the following article to be helpful when trying to figure this out myself:
http://javascriptplayground.com/blog/2015/03/node-command-line-tool/
Also, the command-line-args module worked well for me (though there's a number of other modules out there to choose from):
https://www.npmjs.com/package/command-line-args
Good luck!

Nodejs set command line argument as constant

I want to get an argv from my command line when I am going to start my server and then I want to set it as a constant for a module.
For example I want to define my log file path from commandline:
My starter.js looks like:
var optimist = require("optimist");
var server = require("./start_server");
var argv = optimist.describe('logpath', 'logptah for info').argv;
server.init({logpath:argv.logpath});
My start_server.js looks like:
var restify = require('restify');
var server = restify.createServer({
name: 'dummy-project'
});
module.exports.logpath = null;
function init(args){
server.listen(1234, function() {
console.log("inside logs");
console.log(args.logpath);
module.exports.logpath = args.logpath;
console.log('%s listening at %s', server.name, server.url);
});
};
module.exports.init = init;
var fun = require('./common/loghandler');
My loghandler.js looks like:
var server = require('./../start_server');
console.log("inside log handler");
var LOGPATH = server.logpath;
console.log(LOGPATH);
When I am running node starter.js --logpath='../../custom/info.txt'
I am not getting the logpath inside my loghandler.
Seems logpath handler is called before the server.listen.
The console output looks like:
node starter.js --logpath='../../custom/info.txt'
inside log handler
null
inside log handler
../../custom/info.txt
dummy-project listening at http://0.0.0.0:1234
How I can overcome it and pass my log path as command line argument?
Thanks in advance.
Your init() function is executed after starter.js uses require('./start_server'). When you use require(), the file and all its dependencies are loaded. That means during this process, you also executed require('./common/loghandler'), which completes before server.init() is run in starter.js. Since server.logpath hasn't been set by this time, you get a null value.
Aside from that, module.exports is set at require time and changing the values later have no effect. To fix the problems you're having, you should avoid using functions before your application has fully loaded, and put return values in your modules.

Categories

Resources