How to create QUnit tests with reference to another class?
Asked Answered
M

5

8

I'm trying to add unit testing for JavaScript into my web site. I use VS2013 and my project is an ASP.NET web site.

Based on recommendations (http://www.rhyous.com/2013/02/20/creating-a-qunit-test-project-in-visual-studio-2010/) I've done so far:

  1. Created new ASP.NET app
  2. Imported QUnit (using NuGet)
  3. Into "Scripts" added links to js-file in my original web site (files PlayerSkill.js - containts PlayerSkill class and trainings.js - contains Trainer and some other classes)
  4. Created new folder "TestScripts"
  5. Added TrainingTests.js file
  6. Wrote simple test:

     test( "Trainer should have non-empty group", function () {
        var group = "group";
        var trainer = new Trainer(123, "Name123", group, 123);
        EQUAL(trainer.getTrainerGroup(), group);
     });
    

Notice: my trainings.js file among others contains

function Trainer(id, name, group, level) {
    ... 
    var _group = group;
    this.getTrainerGroup = function () { return _group ; }
};

When I execute my test I see error: Trainer is not defined.

It looks like reference to my class is not recognized. I feel like linking file is not enough, but what did I miss?

Please help add reference to the original file with class and run unit test.

Thank you.

P.S. Question 2: Can I add reference to 2 files (my unit test will require one more class which is in another file)? How?

Mavismavra answered 5/6, 2015 at 3:46 Comment(1)
Please add clarification how exactly do you execute tests. You may either open browser and html page or use command line and this difference is essential.Shedevil
C
3

You should add all the relevant logic of your application to your unit testing file so they all execute before you run your tests

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>QUnit Test Results</title>
        <link rel="stylesheet" href="/Content/qunit.css">
    </head>
    <body>
        <div id="qunit"></div>
        <div id="qunit-fixture"></div>
        <script src="/Scripts/qunit.js"></script>
        <script src="/Scripts/PlayerSkill.js"></script>
        <script src="/Scripts/trainings.js"></script>
        <script src="/TestScripts/TrainingTests.js"></script>
    </body>
</html>

You should not use linked files because they will not exist physically in the script folder.

If you really want to use them you should let the Visual Studio intellisense resolve the physical path of the file like this.

  1. Type the script tag <script src=""></script>
  2. Place the cursor inside the quotes in the src attribute and press CTRL + SPACE
  3. Search your files and let the resolved path untouched
  4. If your project location changes you must update the linked files and also the script references.

{Edit1}

Solution 2:

You could also use an MVC Controller and a Razor View to create your unit testing page and the linked files will work as expected with the only issue that you will have an extra controller in your project but this is not bad at all if for example you want to test the loading of content using ajax that is by default blocked by the browser if they are run from a local file.

Solution 3:

You can also setup a new MVC project just for your javascript unit testing just as you usually setup a new project for any server side code and this will help to prevent your testing to interfere with your production code

{Edit 2}

Solution 4:

As part of the javascript ecosystem you could use grunt or gulp to automate the copy of your scripts from anywhere to your project before running the tests. You could write a gulpfile.js like this

var sourcefiles = [/*you project file paths*/];
gulp.task('default', function () {
    return gulp.src(sourcefiles).pipe(gulp.dest('Scripts'));
});

And then run it opening a console and running the command gulp or gulp default

Cylindrical answered 18/6, 2015 at 17:26 Comment(10)
Regarding 1st part of the comment: hitting Ctrl+Space with in the "" doesn't help: VS doesn't allow to choose the file out of the current web site.Mavismavra
Regarding 2nd part: Do you advise to create MVC controller and Razor View in my original project? I clearly want to avoid this. But if I create them in Test-project... how that will resolve the problem? I still cannot reference external files. Do you recommend to load external JS-files dynamically?Mavismavra
@Mavismavra About the first part VS will resolve the path if you add the file as linked, if not you havn't added it yet. I already tested and is working. About the second part people usually create separate projects for unit testings so you could create a separate MVC project for javascript, it depends on the size of the project and the ammount of unit testing. IMHO the right way is to create a gulp task and copy your script files before testing but this can be complicated for very simple projects.Cylindrical
Yes, I did create a separate project, but the JS file with class to be tested was not copied. Dunno why, maybe I did some stupid mistake, but that is really simple to add a link so I'm wondering how could I do something wrong. Anyway thank you for your help. First time heard about gulp, now I feel sorry i didn't accept your answer and you got only half of the bonusMavismavra
@Mavismavra The trick here is that you create a separate MVC project and in the scripts folder you add all the .js files but instead of adding the standard way(which makes a copy) you add it as linked. The reason for this is that as you are using razor(don't use an html file) to build the QUnit test page so when VS finds the linked file it search for the real file wherever it is and serve it always from a predictable location, that is <script src="~/scripts/training.js"></script>Cylindrical
The other alternative is to automate the copy of the script that can be achieved with gulp or powershell. If you are not versed in the javascript enviroment you can give powershell a try. In none of the cases is recomendable to copy the files manually because this is error prone and tedious. There is really no need for that.Cylindrical
How do you do it in command line without having a need to run a browser? There is already qunit command provided by the framework, but it doesn't seem to work when I need to "include" my js fileShedevil
@TheGodfather Why the downvote? This is the right answer for this question. Yours is a completely different one. You should open a new question if you need help instead of downvoting because you asked your question in the wrong place.Cylindrical
@Cylindrical that's the same question. Your main answer covers only case running from a browser, while the edits are not detailed and require to install additional stuff (like gulp). However it can be done easier without additional dependencies as shown in Shaun Wilson's answer.Shedevil
@TheGodfather You obviously don't understand how this works. No matter how you run it, it will always run in a browser or node because they are the only ones that can execute javascript code. You want to add a file to the cli use --require or ask a new question on how to add a file using the command line in the site or open a new issue in the github repo. Any of this options will be better than angry downvoting.Cylindrical
G
3

Looks like trainings.js is not defined when calling TrainingTests.js . See this question for more details regarding why this happens! Once that is fixed it does work. And yes similar to trainings.js you can have any number of files in any folder as long as you reference them properly. I have created a sample fiddle accessible @ http://plnkr.co/edit/PnqVebOzmPpGu7x2qWLs?p=preview

<body>
  <div id="qunit"></div>
  <div id="qunit-fixture"></div>
  <script src="http://code.jquery.com/qunit/qunit-1.18.0.js"></script>
  <script src="trainings.js"></script>
  <script src="TrainingTests.js"></script>
</body>
Gyrate answered 23/6, 2015 at 20:35 Comment(2)
Thank you, but I do want to reference file. Attempts to reference JS of one web-site from another don't work. I believe VS and IIS just prevent that.Mavismavra
Okay but your question didn't mention anything about the need to reference js file from another server :)Gyrate
D
1

In my case I wanted to run my tests from within my ASP.NET web application, and also on a CI server. In addition to the other information here I needed the following, otherwise I experienced the same error as the OP on my CI server:

  1. Add one or more require() calls to test scripts.
  2. Set the NODE_PATH environment variable to the root of my application.

Example of require()

Within my test scripts I include a requires block, the conditional allows me to use this script from a web browser without needing to adopt a third-party equivalent such as requirejs (which is convenient.)

if (typeof(require) !== 'undefined') {
    require('lib/3rdparty/dist/3p.js');
    require('js/my.js');
    require('js/app.js');
}

Example of setting NODE_PATH

Below, 'wwwroot' is the path of where /lib/ and other application files are located. My test files are located within /tests/.

Using bash

#!/bin/bash
cd 'wwwroot'
export NODE_PATH=`pwd`
qunit tests

Using powershell

#!/usr/bin/pwsh
cd 'wwwroot'
$env:NODE_PATH=(pwd)
qunit tests

This allowed me to run tests both within my ASP.NET web application, and also from a CI server using a script.

HTH.

Depart answered 8/4, 2018 at 6:39 Comment(2)
NOTE: As an alternative to setting NODE_PATH you could use relative paths in your require() calls, such as require('../lib/3rdparty/dist/3p.js').Depart
It doesn't really work for me.. I put require("project.js") to my tests.js code and trying to run qunit, but it gives me error that my function from project.js is not defined...Shedevil
S
1

If you're wondering how to make your tests see your code when running from command line (not from browser!), here is a bit expanded version of Shaun Wilson's answer (which doesn't work out-of-the-box, but contains a good idea where to start)

Having following structure:

project
│   index.js <--- Your script with logic
└───test
        tests.html <--- QUnit tests included in standard HTML page for "running" locally
        tests.js <--- QUnit test code

And let's imagine that in your index.js you have following:

function doSomething(arg) {
  // do smth
  return arg;
}

And the test code in tests.js (not that it can be the whole content of the file - you don't need anything else to work):

QUnit.test( "test something", function( assert ) {
  assert.ok(doSomething(true));
});

Running from command line

To make your code accessible from the tests you need to add two things to the scripts.

First is to explicitly "import" your script from tests. Since JS doesn't have sunch a functionality out-of-the box, we'll need to use require coming from NPM. And to keep our tests working from HTML (when you run it from browser, require is undefined) add simple check:

// Add this in the beginning of tests.js
// Use "require" only if run from command line
if (typeof(require) !== 'undefined') {
    // It's important to define it with the very same name in order to have both browser and CLI runs working with the same test code
    doSomething = require('../index.js').doSomething;
}

But if index.js does not expose anything, nothing will be accessible. So it's required to expose functions you want to test explicitly (read more about exports). Add this to index.js:

//This goes to the very bottom of index.js
if (typeof module !== 'undefined' && module.exports) {
  exports.doSomething = doSomething; 
}

When it's done, just type

qunit

And the output should be like

TAP version 13
ok 1 Testing index.js > returnTrue returns true
1..1
# pass 1
# skip 0
# todo 0
# fail 0
Shedevil answered 22/8, 2018 at 14:54 Comment(0)
M
0

Well, due to help of two answers I did localize that problem indeed was in inability of VS to copy needed file into test project.

This can be probably resolved by multiple ways, I found one, idea copied from: http://www.javascriptkit.com/javatutors/loadjavascriptcss.shtml

Solution is simple: add tag dynamically

In order to achieve this, I've added the following code into tag:

<script>
    var fileref = document.createElement('script');
    fileref.setAttribute("type", "text/javascript");
    var path = 'path'; // here is an absolute address to JS-file on my web site
    fileref.setAttribute("src", path);
    document.getElementsByTagName("head")[0].appendChild(fileref);

    loadjscssfile(, "js") //dynamically load and add this .js file
</script>

And moved my tests into (required also reference to jquery before)

    $(document).ready(function () {
        QUnit.test("Test #1 description", function () { ... });
    });

Similar approach also works for pure test files.

Mavismavra answered 24/6, 2015 at 3:39 Comment(3)
This is an overkill for a very simple task. It's exactly the same to include the script tag with the absolute path of the file, the only difference is that is added later wich at some point could be a problem for the unit tests because you need to wait for this scripts to load. Also have one main problem, you can not reference linked files with this method or files outside your website. You have to copy them first wich could be easily automated with a gulp task, either way is not a good solution.Cylindrical
I'm poor in JavaScript and configuration/build tools, so if I have any solution which works (especially if I passed a LONG way to have it working) I sometimes stop with this.Mavismavra
The problem is that in your case you have to write boilerplate code to make sure the scripts are loaded when you run the tests. The result of not doing so is that as soon the project grows you end up with undeterministics tests. Sometime you will have test that fail for no apparent reason and the reason is that your tests execute and the script was finished loading a few milliseconds later. You have to remove all factors that can potentially make the testing fail. This is why adding javascript dynamically is not a good idea unless is really justified or it's also part of the test.Cylindrical

© 2022 - 2024 — McMap. All rights reserved.