I am new for unit test and TDD method so could you help me please.
function calculate(a, b) {
var sum = a + b;
var sub = a - b;
return { sum: sum, sub: sub };
}
With jest you can do it like this :
describe('calculation', ()=> {
let result
beforEach(()=>{
result = calculate(2, 3)
})
it('returns the correct sum', (){
expect(result.sum).toBe(5)
})
it('returns the correct sub', (){
expect(result.sub).toBe(-1)
})
})
it('checks calculations', function() {
var calculate = require('./example.js');
expect(calculate(1, -1).sum).toBe(0);
expect(calculate(1, -1).sub).toBe(2);
});
Save the file as a .js and use npm test.
I am assuming that you are using jestjs.
You can definitely add other test conditions depending upon your understanding of the function.
A very different answer here: the huge problem with testing such code manually is the fact that it is hard to tell when you wrote enough tests covering different cases.
An alternative approach here: instead of specifying only expected results you step back and identify the contracts that your method under test should adhere to.
And then you use one of the quickcheck-based frameworks, such as JSVerify. You give those rules to the tool - and then the tool creates random data and runs test cases. And it case it finds violations of the contract, it will then try to "minimize" the test input - so that you, in the end receive a message "when you use this data x,y,z then rule A is violated".
It is a very different approach compared to "normal" TDD and unit testing, but especially for such kind of functionality it can be a very effective additional thing to do.
In my Protractor framework, I am using a POM model, so a lot of code resides in different .js files, which are then called into , at necessary junctions, to have the e2e tests.
I have a CompleteProfile.js file (dummy name), where I have a condition,
if profile_flag ===100,
then do nothing
else
complete profile (includes a lot of forms)
For the else portion, I have the code in a differentfillCustomerForms.js file, whose code is something like this
var completeprofile = function(){
this.locator = element(by.css('some_css_locator'));
this.locator.click();
browser.sleep(2000);
}
module.exports={
profileComplete1 = completeprofile
}
I'm using this from fillCustomerForms.js in my CompleteProfile.js as
var Profile = require('./fillCustomerForms.js');
var c_profile = new Profile.profileComplete1();
var compl_profile = function(){
this.someFunction= function(){
profile_flag = "90"
if profile_flag ==="100"{
then do nothing;
}else{
c_profile.completeprofile();
}
}
}
module.exports={
finalExp = compl_profile
}
Inside my spec.js, I am calling the CompleteProfile.js as
var Profile = require('./CompleteProfile.js');
var co_profile = new Profile.finalExp();
describe("Modules",()=>{
it('Modules that load other things',()=>{
//do other things neccessary
});
});
describe("Module",()=>{
it("should do something,"()=>{
co_profile.someFunction();
});
});
The first describe block is the one that loads the browser and checks for the URL and other test cases. My issue is when if I add the second describe block, then the URL that is sent in first describe block is rendered empty i.e. Chrome loads without any URL, and errors out due to timeout error. I have checked the code and it seems fine. What did I do wrong here.
I'm guessing this might have to do with some basics of JS, that I might have overlooked, but right now I'm not able to figure this one out.
You have a syntax error in your second testcase (the it function). Every callback of each testcase in Mocha requires to be resolved or rejected. e.g:
it('should ...', done => {
/* assertion */
done(/* passing a new instance of Error will reject the testcase*/);
});`.
The called function doesn't not return anything in the provided code snippet, I don't really see what you're trying to test for.
I'm writing some functional tests using Intern/Leadfoot. These tests are end-to-end tests (called also stories) and between them there kind of data dependency. With that I mean that a test (ie. test2) will fail if the previous test (test1) did not complete successfully. So in order to avoid running tests that fail for sure I want to skip them (or part of them). Thus, I wonder if there a way to achieve that.
Consider that all test.js files are like the one below:
define([
"require",
"intern",
"intern!object",
"../../support/executor/executor"],
function(require, intern, registerSuite, Executor) {
var executor;
var steps = [
// set of actions,
// like login, click this button,
// then assert that ....
];
registerSuite(function() {
return {
setup: function() {
executor = new Executor(this.remote, steps.slice(0));
},
"Test 1": function() {
return executor.run();
},
};
});
});
This means that each js file is a suite that contains only one test. In other words, it's like I wanna skip all remaining suites, if a previous one failed.
The Intern docs specify a this.skip method that is available for unit tests (https://theintern.io/docs.html#Intern/4/docs/docs%2Fwriting_tests.md/skipping-tests-at-runtime) which also works for functional/e2e tests.
"skipped test":function(){
this.skip('skipping this');
}
They also specify a grep-regex option for skipping tests via the config (https://theintern.io/docs.html#Intern/4/docs/docs%2Fwriting_tests.md/skipping-tests-at-runtime).
I've set up Cucumber-JS and Grunt-JS within my solution.
My folder structure looks like this:
+ Project
+ features
- Search.feature
+ step_definitions
- Search_steps.js
+ support
- world.js
- package.json
- gruntfile.js
I've added a Cucumber-JS task in gruntfile.js:
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
cucumberjs: {
src: 'features',
options: {
steps: 'features/step_definitions',
format: 'pretty'
}
}
});
grunt.loadNpmTasks('grunt-cucumber');
grunt.registerTask('default', ['cucumberjs']);
And I've written out my feature file:
Feature: Search
As a user of the website
I want to search
So that I can view items
Scenario: Searching for items
Given I am on the website
When I go to the homepage
Then I should see a location search box
And my step definition file:
var SearchSteps = module.exports = function () {
this.World = require('../support/world').World;
this.Given('I am on the website', function(callback) {
callback.pending();
});
this.When('I go to the homepage', function (callback) {
callback.pending();
});
this.Then('I should see a location search box', function (callback) {
callback.pending();
});
};
And my world.js file:
var World = function (callback) {
callback(this);
};
exports.World = World;
But when I run grunt at the command-line, while it seems to see my features, it never seems to run any of the steps.
All I get is this:
Running "cucumberjs:src" (cucumberjs) task
Feature: Search
Scenario: Searching for items
Given I am on the website
When I go to the homepage
Then I should see a location search box
1 scenario (1 pending)
3 steps (1 pending, 2 skipped)
Done, without errors.
Cucumber doesn't seem to pay any attention to what I put inside the tests.
Even if I put some obvious logical bug in, e.g.:
this.Given('I am on the website', function(callback) {
var x = 0 / 0;
callback.pending();
});
It just ignores it and prints the above message.
The only way I can seem to get any error out of Cucumber is to put an outright syntax error in the step file. E.g. remove a closing bracket. Then I get something like this:
Running "cucumberjs:src" (cucumberjs) task
C:\dev\Project\features\step_definitions\Search_steps.js:14
};
^
Warning: Unexpected token ; Use --force to continue.
Aborted due to warnings.
What am I missing here?
As I said in my comments, everything is working as expected. Calling callback.pending() tells Cucumber your step definition is not ready yet and the rest of the scenario should be ignored for now.
Change that to callback() to tell Cucumber to move to the next step in the scenario. If you want to notify Cucumber of a failure, pass an error to that callback or throw an exception (I don't recommend that though):
callback(new Error('This is a failure'));
HTH.
Have you tried this?
this.World = require("../support/world.js").World;
I currently have this JS statement everywhere in my code:
window.console && console.log("Foo");
I am wondering if this is costly at all, or has any negative side-effects in production.
Am I free to leave client-side logging in, or should it go?
EDIT: In the end, I suppose the best argument I (and anyone else?) can come up with is that there is a possibly non-negligible amount of extra data transferred between the server and the client by leaving logging messages left in. If production code is to be fully optimized, logging will have to be removed to reduce the size of javascript being sent to the client.
Another way of dealing with this is to 'stub' out the console object when it isn't defined so no errors are thrown in contexts that do not have the console i.e.
if (!window.console) {
var noOp = function(){}; // no-op function
console = {
log: noOp,
warn: noOp,
error: noOp
}
}
you get the idea... there are a lot of functions defined on the various implementations of the console, so you could stub them all or just the ones you use (e.g. if you only ever use console.log and never used console.profile, console.time etc...)
This for me is a better alternative in development than adding conditionals in front of every call, or not using them.
see also: Is it a bad idea to leave "console.log()" calls in your producton JavaScript code?
You should not add development tools to a production page.
To answer the other question: The code cannot have a negative side-effect:
window.console will evaluate to false if console is not defined
console.log("Foo") will print the message to the console when it's defined (provided that the page does not overwrite console.log by a non-function).
UglifyJS2
If you are using this minifier, you can set drop_console option:
Pass true to discard calls to console.* functions
So I would suggest to leave console.log calls as they are for a most trickiest part of the codebase.
If minification is part of your build process, you may use it to strip out debug code, as explained here with Google closure compiler: Exclude debug JavaScript code during minification
if (DEBUG) {
console.log("Won't be logged if compiled with --define='DEBUG=false'")
}
If you compile with advanced optimizations, this code will even be identified as dead and removed entirely
Yes. console.log will throw an exception in browsers that don't have support for it (console object will not be found).
Generally yes, its not a great idea to expose log messages in your production code.
Ideally, you should remove such log messages with a build script before deployment; but many (most) people do not use a build process (including me).
Here's a short snippet of some code I've been using lately to solve this dilemma. It fixes errors caused by an undefined console in old IE, as well as disabling logging if in "development_mode".
// fn to add blank (noOp) function for all console methods
var addConsoleNoOp = function (window) {
var names = ["log", "debug", "info", "warn", "error",
"assert", "dir", "dirxml", "group", "groupEnd", "time",
"timeEnd", "count", "trace", "profile", "profileEnd"],
i, l = names.length,
noOp = function () {};
window.console = {};
for (i = 0; i < l; i = i + 1) {
window.console[names[i]] = noOp;
}
};
// call addConsoleNoOp() if console is undefined or if in production
if (!window.console || !window.development_mode) {
this.addConsoleNoOp(window);
}
I'm pretty sure I took much of the above addConsoleNoOp f'n from another answer on SO, but cannot find right now. I'll add a reference later if I find it.
edit: Not the post I was thinking of, but here's a similar approach: https://github.com/paulmillr/console-polyfill/blob/master/index.js
var AppLogger = (function () {
var debug = false;
var AppLogger = function (isDebug) {
debug = isDebug;
}
AppLogger.conlog = function (data) {
if (window.console && debug) {
console.log(data);
}
}
AppLogger.prototype = {
conlog: function (data) {
if (window.console && debug) {
console.log(data);
}
}
};
return AppLogger;
})();
Usage:
var debugMode=true;
var appLogger = new AppLogger(debugMode);
appLogger.conlog('test');
Don't overcomplicate things! I personally use console.log all the time during development, it's just such a timesaver. For production i just add a single line of code (in the "production profile" in my case) that disable all logs:
window.console.log = () => {};
done ;)
This monkey patches window.console and replace the log function with an empty function, disabling the output.
This is good enough for me in most cases. If you want to go "all the way" and remove console.logs from your code to decrease bundle size, you have to change the way your js is bundled (e.g. drop console.logs with minifier or something)
Also I think you CAN actually make a strong point for leaving them in - even in production. It doesn't change anything for a normal user but can really speed up understanding weird "exotic-browser" problems. It's not like it's backend-logs that may contain critical information. It's all on the frontend anyway, not showing a log message because you are scared to reveal something a user shouldn't know really is only "security by obscurity" and should make you think why this information is even available on the frontend in the first place. Just my opinion.
Yes, its good practice to use console.log for javascript debugging purpose, but it needs to be removed from the production server or if needed can be added on production server with some key points to be taken into consideration:
**var isDebugEnabled="Get boolean value from Configuration file to check whether debug is enabled or not".**
if (window.console && isDebugEnabled) {
console.log("Debug Message");
}
Above code block has to be used everywhere for logging in order to first verify whether the console is supported for the current browser and whether debug is enabled or not.
isDebugEnabled has to be set as true or false based on our
environment.
TL;DR
Idea: Logging objects precludes them from being Garbage Collected.
Details
If you pass objects to console.log then these objects are accessible by reference from console of DevTools. You may check it by logging object, mutating it and finding that old messages reflect later changes of the object.
If logs are too long old messages do get deleted in Chrome.
If logs are short then old messages are not removed, if these messages reference objects then these objects are not Garbage Collected.
It's just an idea: I checked points 1 and 2 but not 3.
Solution
If you want to keep logs for sake of client-side troubleshooting or other needs then:
['log', 'warn', 'error'].forEach( (meth) => {
const _meth = window.console[meth].bind(console);
window.console[meth] = function(...args) { _meth(...args.map((arg) => '' + arg)) }
});
If the workflow is done using the right tools such as parcel/webpack then it's no longer a headache, because with the production build console.log is being dropped. Even few years earlier with Gulp/Grunt it could've been automated as well.
Many of the modern frameworks such as Angular, React, Svelte, Vue.js come with that setup out-of-the-box. Basically, you don't have to do anything, as long as you deploy the correct build, i.e. production one, not development which will still have console.log.
I basically overwrite the console.log function with the one what has knowledge of where the code is being run. Thus i can keep using console.log as I do always. It automatically knows that I am in dev/qa mode or in production. There is also a way to force it.
Here is a working fiddle.
http://jsfiddle.net/bsurela/Zneek/
Here is the snippet as stack overflow is intimated by people posting jsfiddle
log:function(obj)
{
if(window.location.hostname === domainName)
{
if(window.myLogger.force === true)
{
window.myLogger.original.apply(this,arguments);
}
}else {
window.myLogger.original.apply(this,arguments);
}
},
I know this is quite an old question and hasn't had much activity in a while. I just wanted to add my solution that I came up with which seems to work quite well for me.
/**
* Logger For Console Logging
*/
Global.loggingEnabled = true;
Global.logMode = 'all';
Global.log = (mode, string) => {
if(Global.loggingEnabled){
switch(mode){
case 'debug':
if(Global.logMode == 'debug' || Global.logMode == 'all'){
console.log('Debug: '+JSON.stringify(string));
}
break;
case 'error':
if(Global.logMode == 'error' || Global.logMode == 'all'){
console.log('Error: '+JSON.stringify(string));
}
break;
case 'info':
if(Global.logMode == 'info' || Global.logMode == 'all'){
console.log('Info: '+JSON.stringify(string));
}
break;
}
}
}
Then I typically create a function in my scripts like this or you could make it available in a global script:
Something.fail = (message_string, data, error_type, function_name, line_number) => {
try{
if(error_type == undefined){
error_type = 'error';
}
Global.showErrorMessage(message_string, true);
Global.spinner(100, false);
Global.log(error_type, function_name);
Global.log(error_type, 'Line: '+line_number);
Global.log(error_type, 'Error: '+data);
}catch(error){
if(is_global){
Global.spinner(100, false);
Global.log('error', 'Error: '+error);
Global.log('error', 'Undefined Error...');
}else{
console.log('Error:'+error);
console.log('Global Not Loaded!');
}
}
}
And then I just use that instead of console.log like this:
try{
// To Do Somehting
Something.fail('Debug Something', data, 'debug', 'myFunc()', new Error().lineNumber);
}catch(error){
Something.fail('Something Failed', error, 'error', 'myFunc()', new Error().lineNumber);
}