Problems using/understanding Jack - help needed

76 views
Skip to first unread message

Chris Chan

unread,
Oct 29, 2009, 6:33:49 PM10/29/09
to jack
Hi all:

I'm currently having trouble getting Jack to do what I want. I think
it has something to do with my understanding of how Jack works.
Anyway, I'm tyring to test a function within a Javascript file which
has a few functions that I would like to mock. Please see the code
below:

function taskNodeSelected()
{

var event = window.event ? window.event : event;
if (event == null) {
return;
}

var treeNodeElement = evt.srcElement;

if (treeNodeElement == null) {
return;
}

// the below method exists in the same js file and has tests for
it
changeCurrentElement(treeNodeElement);

// calls the server side function -- method exists in C# code
JS_getEditorURL(treeNodeElement.id, '');
}

I tried to use Jack to mock up the function and the functions within.
According to my understanding, I have to create a mock object using
the Jack.create() method. That method will return me a mocked object
which has the mocked changeCurrentElement and JS_getEditorURL
methods. Below is a snipet of what I've got in my test:

var mockObj = jack.create("taskNodeSelected", ['JS_getEditorURL',
'changeCurrentElement'];
jack.expect("taskNodeSelected.changeCurrentElement").withArguments
("abcdefg").exactly(1);
jack.expect("taskNodeSelected.JS_getEditorURL").withArguments
("abcdefghij").exactly(1);

Now heres the part which I get stuck... from my understanding, I have
to use mockObj in order to have the 2 methods to return mocked values,
which means I have to somehow use mockObj, say, pass it into a real
function at my unit tests. The problem here is that the real function
does not take such an object as a parameter. If I call the actual
method instead (i.e. taskNodeSelected()), the mocked methods do not
get called, which means no testing is performed.

I'm using JsTestDriver as the backbone and automated testing tool. I
originally have my js unit tests written in QUnit, but has since
converted to JsTestDriver tests, but if I can get Jack to work on my
tests, I can revert the tests back to QUnit format. I'm a javascript
novice so I probably have no ideas what I was doing.

Can anyone give me some advice on how to get my tests working with
Jack?

Thanks in advance.

Chris.

keronsen

unread,
Oct 29, 2009, 6:49:43 PM10/29/09
to jack
Hi Chris!

If I understand you correctly, you want to verify that the
"changeCurrentElement" and "JS_getEditorURL" functions get called.

You don't need to create a mock object for that. Instead you write:

jack(function() {
jack.expect("changeCurrentElement").withArguments("abcdefg").once
();
jack.expect("JS_getEditorURL").withArguments("abcdefghij").once();

taskNodeSelected() ;
});

Hope that helps!

Karl-Erik

Chris Chan

unread,
Oct 29, 2009, 7:26:07 PM10/29/09
to jack
Karl:

Thanks for the quick response.

I have actually tried the code you mentioned before. Here are a few
problems:

- In the code I provided, the functions changeCurrentElement and
JS_getEditorURL are not supposed to be called because the evt is null
(I've been trying to set it to some value to no avail, but thats a
different problem). However, when I say they are called once/twice as
per your test code, the test passed.

- In the test code, when I do jack.expect
("JS_getEditorURL").withArguments("abcdefghij").once(); , I get an
error saying JS_getEditorURL is undefined. This function is actually
not a javascript function. It is called by C# code via some lookup
method from classes and build file. Is there anyway that Jack can
mock it?

- how can I insert a jack.function()... code in QUnit or JsTestDriver
(and still gets called)?

Thanks!

Chris.
> > Chris.- Hide quoted text -
>
> - Show quoted text -

Karl-Erik Rønsen

unread,
Oct 30, 2009, 4:39:46 AM10/30/09
to jack-d...@googlegroups.com
Hi Chris!

First:

If you are not able to set window.event to a dummy value in your test,
you could try rewriting your code to take it in as a parameter:

function taskNodeSelected(event) {
  // ...
}

Then the test code would be:

jack(function() {
  var dummyNode = { id: "myDummyNode" };
  var dummyEvent = { srcElement: dummyNode; }

  jack.expect("changeCurrentElement")
    .withArguments(dummyNode)
    .once();
  jack.expect("JS_getEditorURL")
    .withArguments(dummyNode.id)
    .once();

  taskNodeSelected(dummyEvent) ;
});

Second:

If you get an error saying JS_getEditorURL is undefined, you need to
create a dummy for that to. You can do that manually:

window. JS_getEditorURL = function() { }

Do that on the first line of your test or in test setup code. The rest
of the Jack code remains the same.

Third:

You can find an example of how to use Jack with QUnit here:
http://github.com/keronsen/jack/tree/master/docs/examples/qunit


Karl-Erik

Message has been deleted

Chris Chan

unread,
Nov 3, 2009, 9:29:00 PM11/3/09
to jack
Hi Karl:

For the first problem I'll have to find another way to test it since I
am not allowed to change the code. For the second one, I added that
line of code in the test method, and yes it solved the compile
problem.

As to the third problem (the interesting one), I tried the example you
provided. Both tests passed. I tried on both IE 6 and firefox 3.5,
same result. If I'm not mistaken, the failing test is expecting a
call to myGlobalFunction, but it didn't happen, so shouldn't the test
fail?

Also, suppose I have the following code:

var ID = "idTreeView";

function doesTreeViewExist()
{
// jQuery code
if ($('#' + ID).length == 0)
{
return false;
{
else {
return true;
}
}

I have read on the web that it is possible to test a jQuery function
like the one above. But what if I have to mock it due to no
environment for the jQuery code? Is it possible to use Jack to mock
the above code?

Thanks!

Chris.
> > > - Show quoted text -- Hide quoted text -

Karl-Erik Rønsen

unread,
Nov 4, 2009, 5:37:55 AM11/4/09
to jack-d...@googlegroups.com
Hi Chris!

The example works for me. Are you sure you have an updated version of
jack.js? The qunit integration was added very recently.

And yes, you can use mocking in your jQuery example:
(Assuming you still use qunit)

// Test 1
jack(function() {
jack.expect("$").withArguments("#idTreeView").returnValue({length:0});
equals(doesTreeViewExist(), false);
}

// Test 2
jack(function() {
jack.expect("$").withArguments("#idTreeView").returnValue({length:1});
equals(doesTreeViewExist(), true);
}


Karl-Erik

Chris Chan

unread,
Nov 5, 2009, 1:08:17 AM11/5/09
to jack
Hi Karl:

I didn't realise that Jack had been upgraded. I have downloaded the
latest version of Jack (1.2) and it has solved the problem.

I came across a few more problems today:

1) Is it possible to test $(document).ready(function() {...}); ?

2) I am looking at testing the following code using Jack:

a) $('span [id=EXPAND_NODE]').each (function() {... // conditions,
more conditions, and more returns in conditions}

I'm thinking that I would be required to write a mock implementation
of the each (function() {...}) myself? So something like:

jack.expect("span [id=EXPAND_NODE]").exactly("x times").mock (function
() { ... });

b) $(this).remove();

As for that one I'm a bit lost, as I'm not sure how Jack will be
mocking the removing function. My guess is that I'll have to re-mock
the array with the specific item removed?

3) Another thing I found strange is that say for the below code and
test code:
function doSomething()
{
var ID = "id";
if($('#' + ID).length == 0)
{
return false;
}
else
{
return true;
}
}

// test code
jack.expect("$").withArguments("#id").exactly("5").returnValue
( {length:0} );
doSomething();

I was expecting the test to fail since I have only called doSomething
() once, but it passed instead. This doesnt make sense, because I
used the same trick in the test file you provided, and the test failed
as expected. Am I missing something/understood the wrong thing in my
test code?

Thanks!

Chris.


On Nov 4, 9:37 pm, Karl-Erik Rønsen <keron...@gmail.com> wrote:
> Hi Chris!
>

Karl-Erik Rønsen

unread,
Nov 9, 2009, 6:30:47 AM11/9/09
to jack-d...@googlegroups.com
Hi Chris!

Sorry for the late answer.

> 1) Is it possible to test $(document).ready(function() {...}); ?

You could use a named function (for example startApplication) instead,
and run your tests against that. You would then change your code to
call that function: $(document).ready(startApplication);

It is probably also possible to mock ready(), but I don't think thats
the best option. This could work:

jack(function(){
var mockJQueryDocument = jack.create("mockJQueryDocument", ["ready"]);
jack.expect("$")
.whereArgument(0).is(document)
.returnValue(mockJQueryDocument);

// ... insert expectations for what should happen when document is ready.

mockJQueryDocument.ready();
});

> 2) I am looking at testing the following code using Jack:

[...]

You should avoid mocking the inner workings of jQuery. Instead you can
include jQuery to support things like $.ready when you write and run
tests, and only use mocking when you want to do interaction testing.

That way, your code coud call $.each(array) without you having to mock
$.each. You can still test what happens inside the each loop with
mocking.

> b) $(this).remove();
>
> As for that one I'm a bit lost, as I'm not sure how Jack will be
> mocking the removing function.  My guess is that I'll have to re-mock
> the array with the specific item removed?

Sometimes it is better to set up a DOM structure that you can run your
tests against, and then check it for side-effects, like an element
that should not exist any more. You could use jQuery for setting up
the DOM and checking for elements in your tests.

> 3) Another thing I found strange is that say for the below code and
> test code:
> function doSomething()
> {
>    var ID = "id";
>    if($('#' + ID).length == 0)
>    {
>        return false;
>    }
>    else
>    {
>        return true;
>    }
> }
>
> // test code
> jack.expect("$").withArguments("#id").exactly("5").returnValue
> ( {length:0} );
> doSomething();
>
> I was expecting the test to fail since I have only called doSomething
> () once, but it passed instead.  This doesnt make sense, because I
> used the same trick in the test file you provided, and the test failed
> as expected.  Am I missing something/understood the wrong thing in my
> test code?

I don't know why it does not work. If you have a similar example that
works, there is probably something that is different between them. Did
you forget the jack(function() { ... }) wrapper?

Karl-Erik

[... deleted previous discussion ...]

Chris Chan

unread,
Nov 10, 2009, 12:31:25 AM11/10/09
to jack
Hi Karl:

Yeah I didn't realise by mocking the .each() function, I would
actually be mocking the entire each function. There is a .find()
function within the .each function so by mocking the $('span
[id=EXPAND_NODE]') part of the .each, the .find would not work anymore
(returned undefined). It looks like I have to use DOM structure as
custom test data after all. I'll take a look at jQuery for that (I'm
still new to it).

In regards to the last problem: I ran my tests in JsTestDriver, not
QUnit. The format of the test looks like this:
-----------------------------------------
TestTree = TestCase("TestTree");

// I do not need to include prototype.js
TestTree.prototype.test_testMethodName = function() {
jack(function() {
jack.expect("$").exactly("10").withArguments
("#idTreeViewControl").returnVAlue( {length:0} );
var result = doesTreeViewExist();
assertEquals(false, result);
});
};
----------------------------------------
And here is the code (in js file):
----------------------------------------
var ID = "id";
function doesTreeViewExist()
{
if($('#' + ID).length = 0)
{
return false;
}
else
{
return true;
}
}
---------------------------------------
I was expecting the code to fail, but instead it passed. I tried
expecting 6, 7 or 8 times, same result. I did the same with other
unit tests. The result was the same... very consistent. However I
did the same thing in the example code you provided, and that worked
alright. I'm running against IE 6 on Windows Server 2003.

I have included jquery-1.3.2.min.js and qunit.js with my project (I
might use it in the future). Do you think the way JsTestDriver lay
out the tests is the cause of the exactly("x times") not working?

Chris.
> [... deleted previous discussion ...]- Hide quoted text -

Karl-Erik Rønsen

unread,
Nov 10, 2009, 5:17:16 AM11/10/09
to jack-d...@googlegroups.com
> In regards to the last problem: I ran my tests in JsTestDriver, not
> QUnit.  The format of the test looks like this:

There are a few typing errors in your examples that may cause you
trouble, but it would not make the test pass unexpectedly. (Its
returnValue(), not returnVAlue(). Also, there is a = where you
probably should have a ==)

I have tried to recreate the problem with JsTestDriver, but the tests
failed as expected.

If you want me to look further into this problem I suggest you isolate
it in a set of files and send it to me (kero...@gmail.com) so that I
can run exactly what you are running.

Karl-Erik

Chris Chan

unread,
Nov 11, 2009, 1:28:48 AM11/11/09
to jack
Hi Karl:

I have sent you the files. I hope the problem can be reproduced :)

Off topic: it sounds like mocking document.ready function using Jack
is not a good idea. Do you have any recommendations on how to test
it?

Thanks!

Chris.

On Nov 10, 9:17 pm, Karl-Erik Rønsen <keron...@gmail.com> wrote:
> > In regards to the last problem: I ran my tests in JsTestDriver, not
> > QUnit.  The format of the test looks like this:
>
> There are a few typing errors in your examples that may cause you
> trouble, but it would not make the test pass unexpectedly. (Its
> returnValue(), not returnVAlue(). Also, there is a = where you
> probably should have a ==)
>
> I have tried to recreate the problem with JsTestDriver, but the tests
> failed as expected.
>
> If you want me to look further into this problem I suggest you isolate
> it in a set of files and send it to me (keron...@gmail.com) so that I

Karl-Erik Rønsen

unread,
Nov 11, 2009, 9:36:23 AM11/11/09
to jack-d...@googlegroups.com
> Off topic: it sounds like mocking document.ready function using Jack
> is not a good idea.  Do you have any recommendations on how to test
> it?

There are two ways I can think of:

The first is outlined in an earlier reply: Create a normal, named
function that is the event handler for the document.ready event. You
can then call that function in your tests. You won't be testing the
event, but rather the application startup.

The other way is to create a html document that includes the js file
that has document.ready in it. Open an iframe with that document
during your test, and do assertions against the state of the document
to check that the event handler has been called. You should probably
only do a simple "smoke test".

I guess those two kinds of tests together would cover your needs.

Karl-Erik

Chris Chan

unread,
Nov 18, 2009, 9:34:04 PM11/18/09
to jack
Hi Karl:

Did you had a chance to look at the files I sent you to see if the
problem ("exactly" clause not verifying correctly) can be reproduced?

Thanks.

Chris.
Reply all
Reply to author
Forward
0 new messages