Reputation: 80744
When I write tests for my in-browser TS code, I hit the following problem. My "test" code files are located in a separate folder from the "application" code files (an arrangement that I am not willing to give up). Therefore, in order to import my "app" modules, I have to do this:
// tests/TS/SubComponent/Module.Test.ts
import m = module("../../Web/Scripts/SubComponent/Module");
This compiles just fine. But when loaded in browser, it will obviously not work, because from the standpoint of RequireJS running in the browser, the module is located at "app/SubComponent/Module" (after being remapped through web server and RequireJS config).
With TS 0.8.3 I was able to pull off this clever trick, but in 0.9.0 it no longer works, because now the compiler doesn't let me treat a module as an interface.
So the question is: how do you test your client-side code? Clearly, I can't be the only person to be doing it, can I? :-)
Upvotes: 5
Views: 3904
Reputation: 80744
So here's ultimately what I've done: it turns out that Karma can handle/watch/serve files that are not within the base directory, and it makes them look to the browser in the form of "/absolute/C:/dir/folder/blah/file.js". This happens whenever files -> pattern starts with "../".
This feature can be used to make RequireJS see the whole directory structure exactly as it exists on the file system, thus allowing the tests to import app modules in the form of "../../Web/App/Module.ts".
files = [
// App files:
{ pattern: '../../Web/App/**/*', watched: true, served: true, included: false },
// Test files:
{ pattern: '../js/test/**/*.js', watched: true, served: true, included: false }
];
Reference (version 0.8): http://karma-runner.github.io/0.8/config/files.html
Upvotes: 1
Reputation: 34288
I am in the middle of a project where I have to migrate parts of a large javascript project to typescript and this is how I managed to keep the tests running:
Use grunt-typescript task to watch and compile all my .ts
files from the source to a tmp
folder (with their source-maps). If you only have to deal with typescript files, then you can use the tsc
in watch mode to do it as well. The latter would be faster, but the former allowed me to simultaneous edit javascript and typescript files with livereload.
Include the .ts
files in karma.conf
but don't watch them or include them:
// list of files / patterns to load in the browser
files = [
JASMINE,
JASMINE_ADAPTER,
// ...
// We want the *.js to appear in in the window.__karma__.files list
{ pattern: 'app/**/*.ts', included: false, watched: false, served: true },
{ pattern: 'app/**/*.js', included: false },
// We do watch the folder where the typescript files are compiled
{ pattern: 'tmp/**/*.js', included: false },
// ...
// Finally, the test-main file.
'tests/test-main.js'
];
Finally, in the test-main.js
file, I mangle the names of typescript files and declare them as require modules with the correct paths (to the corresponding .js
file) in test-main.js
:
var dynPaths = {
'jquery' : 'lib/jquery.min',
'text' : 'lib/text'
};
var baseUrl = 'base/app/',
compilePathUrl = '../tmp/';
Object.keys(window.__karma__.files)
.forEach(function (file) {
if ((/\.ts$/).test(file)) {
// For a typescript file, include compiled file's path
var fileName = file.match(/(.*)\.ts$/)[1].substr(1),
moduleName = fileName.substr(baseUrl.length);
dynPaths[moduleName] = compilePathUrl +
fileName.substr(baseUrl.length);
}
});
require({
// Karma serves files from '/base'
baseUrl: '/' + baseUrl,
paths: dynPaths,
shim: { /* ... */ },
deps: [ /* tests */ ],
// start test run, once requirejs is done
callback: function () {
window.__karma__.start();
}
});
Then as I edit the typescript files, they are compiled and put in the tmp
folder as javascript files. These trigger karma
's auto watch and it reruns the tests. In the tests, the require
calls resolve correctly since we have explicitly overwritten the paths to the typescript files.
I realise that this is a bit hacky, but I had to jump through similar hoops while trying to include all my tests with REQUIRE_ADAPTER
. So I assumed that there is no cleaner way of doing it.
Hopefully, if typescript becomes more prevalent, we will see better support for testing.
Upvotes: 1
Reputation: 2002
Might be that I misunderstood your question - can't comment yet...
The runtime of the browser does not need any typescript information. So your test script should import the compiled ts files the same way as any other javascript files they need. Might be that you have to copy them to a subfolder of your test-project before you run your script.
I assume the bigger problem is that you have no interface information. Why do you want to import these informations instead of referencing them? Especially since importing them will also occur in the browser.
The Reference will only take place in the IDE , so it does not matter in which folders the interface-files are located.
/// <reference path="../../Web/Scripts/SubComponent/Module/References.ts" />
Upvotes: 0
Reputation: 30066
Since the typescript code is compiled to Javascript you can use all Javascript test frameworks.
I am using Jasmine: https://github.com/pivotal/jasmine/wiki
You can write your tests in Typescript with the .d.ts file here: https://github.com/borisyankov/DefinitelyTyped/blob/master/jasmine/jasmine.d.ts
But my client code is rather small and compiled to one output file, so I don't have the module issues that you describe.
Upvotes: 0
Reputation: 250922
I can't tell if you are using Visual Studio - this next bit is Visual Studio specific...
This is how I do it:
In my test project, I created a folder named "ReferencedScripts" and referenced the scripts from the project being tested (add existing item > add as link). Set the file to copy to the output folder.
Source: Include JavaScript and TypeScript tests in Visual Studio.
Using add-as-link makes the scripts available in your test project.
Not using Visual Studio? I recommend creating a task / job / batch file to copy the files into the test folder. You could even use tsc
to do this task for you.
Upvotes: 2