📜 ⬆️ ⬇️

test.it - ​​not again, but again

Good afternoon Habr.
After my article on test.it , an eternity week passed. And as I did not plan to stretch this period for at least a month, but it was time for a new publication.
Picture to attract attention:

Since that time, the library (thanks in large part to habravchanam) has acquired a new functionality.
And in view of the fact that the syntax given in the last article does not fully work in the current version, I do not have the right to postpone this article for another 3 weeks.

Who doesn’t like a lot of words ? Website where you can see the code in action, GitHub , Wiki

Chain calls appeared
test.it(some) .comment('comment to test') .callback(function(){alert('test has been passed')}) .arguments(); // -> [some] test.group('group', function(){ ... }) .comment('comment to group') .result(); // -> true/false 

and the new nesting mechanism
 test.group('first group',function(){ ... test.group('second group', function(){ ... }); ... }); test.group('first group').group('second group',function(){ ... }); 

New way to display errors
error

And two additional methods test.typeof () and test.trace () .
')
And also 3 Wiki pages.

And now about all this in more detail.


So. Let's look at the wiki example:

While we have not started the tests, we will use the test.typeof () method.
 console.log( test.typeof(1) ,test.typeof("text") ,test.typeof([1,2,3]) ,test.typeof({a:1,b:2}) ,test.typeof() ,test.typeof(document) ,test.typeof(document.getElementsByTagName("body")) ,test.typeof(window) ,test.typeof(/yes it is RegExp/) // and many many more ... ); 
test.typeof () - determines the type of the value passed to it.

It can distinguish: Array , Boolean , Date , Error ( EvalError , RangeError , ReferenceError , SyntaxError , TypeError , UriError ), Function , NaN and Number , Object , RegExp , String , Window , HTML , NodeList . And it will also define an empty variable as 'undefined', but unlike the standard typeof, it will not be able to get an undeclared variable as an argument. For that, he will answer 'undefined' to a non-existent property of the declared and non-empty object. But this is the specifics of the language.

If we refresh the page, the line will appear in the console:
typeof

Now take a look at the test.trace () method.
 (function firstFunction() { (function secondFunction() { (function lastFunction() { console.log(test.trace()); })(); })(); })(); 
test.trace () - returns a list (compiled into strings separated by "\ n") lines of code that were executed to call this method.

In fact, this is not a real trace () (which, unfortunately , is not present in JavaScript) , because all references to the calls inside the library were cut out of it.

The output to the console is now added:
trace
Hereinafter, the non-significant parts of the console output on the screenshots will be omitted so as not to increase the meaningless size of the images.

Let's get down to the tests.


First, create an object for tests, a variable with an integer value, and an empty variable.
 var Family = { name: "Desiderio", pet: { type: "dog", name: "google" }, members: [ { name: "Titulus", age: 23 }, { name: "Dude", age: Infinity } ] } var myIQ = 100; var Nothing; 
I think there should be no questions about this code.

Let's go further.

The next step is the first test.

Test for non-falsity.


It's all as before.
 test.it("hello world"); test.done(); 
test.it (value) - creates a new test, checking value for non-falsity.
test.done () - completes the tests and outputs the result to the console.
Further it will be assumed that test.done () is the last line of our code. In the examples I will omit it.

In the console, we see:
root
Where:

If you open this group, you can see a list of tests / groups in it.
root expanded
Before analyzing our only test, let's open it:
test expanded
So:

Let's try to use the chain mechanism.


The most elementary case is adding a comment:
 test.it(2+2==5) .comment("i badly taught algebra at school"); 
.comment (text) - adds a comment to the test / group in whose chain it was called. At the same time continuing the chain, but more on that later.

This code could be written in the form:
 test.it(2+2==5).comment("i badly taught algebra at school"); 
But, for cases with longer chains, writing to the bar is more convenient and clearer.

Now root (opened automatically, because it contains a failed test) looks like this:
2 tests
In the counters in the first line, you can notice an increase in the second number from 0 to 1, which means an increase in the number of failed tests / groups.

We turn our attention to the default disclosure (because it was not passed) , the test.
It differs from the previous one only in the status of fail - meaning that the test failed, and the comment “i badly taught algebra at school”, which we added.

Obviously, not only strings, but also variables, expressions, function calls, etc., can be passed to test.it (value) . In principle, whatever we pass on, it will be executed first, the result will be obtained, and this result will already go to the test. This is JavaScript.

Check what has just been said. Test the expression:
 test.it(Infinity>Infinity-1) .comment("philosophically is not it?"); 
You can think about this expression over a glass of coffee, we are here for another gathered. The test result looks like the result of the previous one, which is obvious.
infinity

Until we have gone into the jungle of chained calls, we will definitely leave, look at the other test.tit () test.

Equality test


Let's compare the previously declared variable with a different value.
 test.it(myIQ,"genious") .comment("is I'm genious?"); test.it(myIQ,(1+10)*12 - 34 + 5*5*5 - 123) .comment("check my IQ to be a normal"); 
test.it (value1, value2) - checks the equality of the two values ​​passed to it.

In the console, these 2 tests will look like this:
Iq
Nothing unusual, but you should pay attention to the description of the first (failed) test. " arguments has different types " - this text contains a hint explaining to us why the test was failed - passed arguments of different types.

And now let's try more complex chains.
Let's do some action, depending on the test result.
 if (test.it(Family) .comment("Is Family exist? Is it not empty?") .result()) { console.info("by if: ","Yep! Here it is!"); } else { console.warn("by if: ","ALARM! there are no Family"); } 
.result () - ends the chain and returns the test result.

In this code, we check Family for non-falsity, and depending on the result we output various phrases to the console.
The console output now looks like this:
by if

True, this task is preferable to perform with the help of another chain call:
 test.it(Nothing) .comment("Is Nothing exist? Is it not empty?") .callback( function(){console.info("by callback: ","Yep! Here it is!");} ,function(){console.warn("by callback: ","ALARM! there are no Nothing");}); 
.callback (function () {/ * funcIfpass * /} [, function () {/ * funcIffail * /} [, function () {/ * funcIferror * /}]]) - performs one of three functions, depending on result of passing the test or group. At the same time continuing the chain.
As a result, we see in the console:
by callback
This design is preferable because it does not complete the chain.

Groups


Now create the first group.
 test.group("Empty group",function(){}); 
test.group (name, function () {...}) - creates a new group or refers to an existing one , and fills it with tests that are in the function passed in the second argument.

But since the tests were transferred to the en, the group is created empty, but with the pass status - because there is no test failed in it.
empty group
Before taking a screenshot, I opened the group - this can be seen from the turn of the down arrow, and to two gray pixels, meaning its end. But since the group is empty, it looks almost like a closed one.

Well. We proceed to more meaningful action. Create a group with two tests inside and a comment.
 test.group('Family tests',function(){ test.it(Family.name,"Zukerberg") .comment("Are we test Zukerberg's family?"); test.it(Family.name,"Desiderio") .comment("Or Desiderio's?"); }).comment("unite!"); 
You see - nothing complicated!
group with tests
Here it is worth paying attention to the unite comment added by us ! - in the group header.

And now let's turn the feint over with our ears, and add a few tests to the already created group. And not just tests, but tests that initiate new tests depending on their result.
Add the following code:
 test.group("Family tests",function(){ test.it(Family.pet) .comment("Do we have a pet?") .callback(function(){ // I add test in your test, so you can test while you testing test.it(Family.pet,{type:"dog", name:"google"}) .comment("Is it right pet?"); }); test.it(Family.house) .comment("Do we have a House?") .callback(function(){ // next test will not be executed test.it(Family.pet,{type:"Huge", color:"green"}) .comment("Is it right House?"); }); }); 
Considering the past 2 tests in this group and, described just now, 4 more tests, in total there will be = 5 (sic!). You can check on the calculator.
additional tests
Vaughn see in the title? 3 passed, 2 failed - only 5.

New tests


It's time to take a look at a couple of unusual tests. To begin with, in the “here comes tests” group we will create the following two tests:
 test.them([Family.pet, Family.members]) .comment("There must be memebers with pet, to call it a 'Family'"); test.types([Family.pet.name, Family.name],"string") .comment("Is names are string type"); 
test.them (values) is an analogue of test.it (value) , only takes an array as the first argument, in which it already checks elements for non-false.
test.types (values ​​[, type]) - just like test.them (values) checks the elements of the array passed in by the first argument. But it checks them for a type match, and if the second type argument is passed, it takes this type as a pattern.
This test has a simplified analog, but about it a little bit later.

This is how they look in the console:
them and types
I opened the tests together with their arrays of arguments for clarity, but something seems to me, the visibility from this only diminished.

And here's another chain magic:
 var numberOfMembers = test.type(Family.members,"Array") .comment("Is it a several members, nor a single member?") .arguments()[0].length; test.it(numberOfMembers>5) .comment("Is it big family?"); 
.arguments () - ends the call chain and returns the arguments passed to the test ( not to the group! ).
arguments
I will explain - the first test, checked the value of Family.members for non-falsity. Since this is an array of two elements - the test is passed.
arguments () [0] == Family.members . Therefore, the numberOfMembers variable is entered into the number of elements in the Family.members array , that is 2. The second test fails because 2 is not greater than 5.

Nesting


You still remember that we are in the " here comes strange tests " group?
Add another group here, and immediately use the for construct to create several tests of the same type.
 test.group("Members age",function(){ for (i=0;i<numberOfMembers;i++) { test.it(Family.members[i].age>25) .comment("Is "+Family.members[i].name+" older then 25?"); } }); 
members age
Now this new group " Members age " is located in the old " here comes strange tests ".

Errors


Add one more test to the same group " Members age ":
 test.it() .comment("yep, here is error"); 
Such code will lead to an error, because test.it () expects to receive from 1 to 2 arguments.
error
In the error header:

Then comes the test.trace () result to make it easier to find it in the code. And the error object itself, in this case RangeError , is if someone wants to delve deeper into it.

Links to groups


Let's go back to root level.
Just in case, let me remind you that the " here comes strange tests " group now looks like this:
big group
There is another group " Members age " in it. Here we will add the test to it now.
 test.group("here comes strange tests").group("Members age",function(){ test.it("bye") .comment("good"); }); 
test.group (name) - returns a link to the group, after which it can be used as the beginning of a chain, to add a new group of tests, or to add tests to an already existing subgroup.
Here's the last thing we just did. Now we see in the console:
good bye

And lastly, to consolidate all of the above:
full listing with all output in the console
 console.log( // look how do test.typeof() work test.typeof(1) ,test.typeof("text") ,test.typeof([1,2,3]) ,test.typeof({a:1,b:2}) ,test.typeof() ,test.typeof(document) ,test.typeof(document.getElementsByTagName("body")) ,test.typeof(window) ,test.typeof(/yes it is RegExp/)); (function firstFunction() { // look how do test.trace() work (function secondFunction() { (function lastFunction() { console.log(test.trace()); })(); })(); })(); var Family = { // Here some complex object name: "Desiderio", pet: { type: "dog", name: "google" }, members: [ { name: "Titulus", age: 23 }, { name: "Dude", age: Infinity } ] } var myIQ = 100; // and value var Nothing; // and empty value test.it("hello world"); // Let"s add some simple tests test.it(2+2==5).comment("i badly taught algebra at school"); // with comment test.it(Infinity>Infinity-1).comment("philosophically is not it?"); // with expression // check equalence test.it(myIQ,"genious").comment("is I'm genious?"); test.it(myIQ,(1+10)*12 - 34 + 5*5*5 - 123).comment("check my IQ to be a normal"); // try some chain staff if (test.it(Family).comment("Is Family exist? Is it not empty?").result()) { console.info("by if: ","Yep! Here it is!"); } else { console.warn("by if: ","ALARM! there are no Family"); } // do it again in better way test.it(Nothing).comment("Is Nothing exist? Is it not empty?").callback( function(){console.info("by callback: ","Yep! Here it is!");} ,function(){console.warn("by callback: ","ALARM! there are no Nothing");}); test.group("Empty group",function(){}); // try to make a group test.group('Family tests',function(){ // let's unite it! test.it(Family.name,"Zukerberg").comment("Are we test Zukerberg's family?"); test.it(Family.name,"Desiderio").comment("Or Desiderio's?"); }).comment("unite!"); test.group("Family tests",function(){ // and add some test after test.it(Family.pet).comment("Do we have a pet?") .callback(function(){ // I add test in your test, so you can test while you testing test.it(Family.pet,{type:"dog", name:"google"}).comment("Is it right pet?"); }); test.it(Family.house).comment("Do we have a House?") .callback(function(){ // next test will not be executed test.it(Family.pet,{type:"Huge", color:"green"}).comment("Is it right House?"); }); }); test.group("here comes strange tests",function(){ // test existance of most important Family properties test.them([Family.pet, Family.members]) .comment("There must be memebers with pet, to call it a 'Family'"); // test types of names test.types([Family.pet.name, Family.name],"string") .comment("Is names are string type"); // here some magic var numberOfMembers = test.type(Family.members,"Array") .comment("Is it a several members, nor a single member?") .arguments()[0].length; test.it(numberOfMembers>5).comment("Is it big family?"); // So if we know how many members there, lets check their age test.group("Members age",function(){ for (i=0;i<numberOfMembers;i++) { test.it(Family.members[i].age>25) .comment("Is "+Family.members[i].name+" older then 25?"); } test.it().comment("yep, here is error"); // add some error to see the trace }); }); // add final test deep in group test.group("here comes strange tests").group("Members age",function(){ test.it("bye").comment("good"); }); test.done(); 

full


root


Oh yes. test.root is still in place. Its all can also be used to create new options for displaying results. It is slightly simpler (in groups the counters stopped separating groups and tests).
An empty root looks like this:
 { "type": "group", "name": "root", "time": 0, "result": { "pass": 0, "fail": 0, "error": 0, "total": 0 }, "stack": [] } 


Conclusion


I would really like to thank:


Still remained cons given in the last article. But there are already very interesting thoughts on the methods of their solutions.

The site where you can see all the above code in action, GitHub , Wiki

Source: https://habr.com/ru/post/189216/


All Articles