This is the first of a two part blog on cross project TypeScript (TS) and unit testing with Chutzpah. This post will focus on the cross project aspect, more specifically how to write Typescript with dependencies over two Visual Studio projects.
Let’s consider the following simple example. I have “Project A” which contains a “Scripts/typings” folder and several TS files inside the “Areas” folders.
In “Project B” I have the same “Areas” folder structure, containing test files for each TS file (I like my test project to mirror the project they are testing). If I open one of the test files you will see that it will not compile because it cannot find any of the references it requires.
This is because the files being refereed to are in Project A. The old typescript referencing method of adding comment references to the top of the file would solve this issue. However, TS have removed the need for these within a single project because the number of references can quickly become unmanageable, for this reason I looked for an alternative.
I identified two reliable ways of allowing cross project referencing. The first is to compile the TS from Project A into a single file in Project B, the second and my preferred option is to link the files from Project A into B.
Link Referencing
The basic idea behind this is that if you link a TS file from Project A into B then it can be used with the built in automatic referencing.
This can be achieved by creating a folder to hold your references, I like to name this “_referencesTS”, the folder will contain all of the links to files from Project A. This can be done individually but would become very cumbersome if it had to be done for each new TS file. Linking a folder however will link all of the files beneath it, this can be done by editing the csproj file.
To edit the file right click Project B and click “Unload Project”, then right click the project and click “Edit ProjectB.csproj”. Navigate to the <ItemGroup> that contains the <TypeScriptCompile> tags and insert the code below:
<TypeScriptCompile Include="..\ProjectA\Areas\**\*.ts"> <Link>_referencesTS\Areas\%(RecursiveDir)%(FileName)</Link> </TypeScriptCompile> <TypeScriptCompile Include="..\ProjectA\Scripts\typings\**\*.ts"> <Link>_referencesTS\Scripts\typings\%(RecursiveDir)%(FileName)</Link> </TypeScriptCompile>
Replace the relative path to the location of your TS files in Project A, this uses the wildcarding (*) to link all .ts files (dictated by the *.ts) within all sub folders (dictated by the \**\). It is possible to add multiple entries for more than one folder, such as the typings folder in this example.
The TS files within these folders will now appear linked within Project B, allowing for automatic typescript referencing.
Note: The only downside to this approach is that when a new file is added to Project A within a linked folder, the user has to unload and load the project or close and open the solution for it to appear in Project B.
Compile to Single File
The second solution to this problem is to use the TS compiler to generate a single JavaScript and definitely typed file.
This can be achieved by creating the same “_referencesTS” folder in Project B. Then right click Project A, click “Properties” and select “TypeScript Build”. Add the file path to the _referencesTS folder along with a file name under “Combine JavaScript output into file”, and then check to “Generate declaration files”.
In Project B you must now include this generated file in the solution, automatic referencing will now work because all of the code from Project A is repeated in B within the ProjectA.d.ts and ProjectA.js.
The downsides to this approach are:
- The definitely typed files for external libraries must be added to both projects.
- If you F12 from within Project B you will be taken to the generated definitely typed file (ProjectA.d.ts) and not the original Typescript file.
- You must build Project A to update the reference in Project B.
Look forward to part 2 of this post that will look at how cross project referencing works with Chutzpah TS unit testing.
Interesting post,
I’m working with VS2012, I installed TypeScript from nuget and I also installed Chutzpah test runner. I followed “Link referencing” method. Both projects compile succesfully but when I run test with Chutzpah I have a Javascript runtime error: “Could not find symbol ‘Greeter'”
AD
That is correct and the reason this has happened because Chutzpah will not work by default. I have now finished Part 2 which will fix the issue you have experienced.
Hello there… Thanks for your article. I haven’t yet used TS in Visual Studio environment, but I can imagine this issue being a pain. You solution for linking files seems like a very clean solution. I’m wondering however if you’ve tried clicking on the refresh button in Solution Explorer while Project B selected to refresh the references for newly added TS files. If that works, it would be simpler than actually unloading + loading Project B or closing + opening the solution file.
– Ash
You are welcome, thanks for taking the time to read it. Sadly the refresh button does not work.
Hi, I have tried your approach of linked folders but it is not working for me. It compiles fine, but when I run the app I get an error:
0x800a1391 – JavaScript runtime error: ‘ClassOne’ is undefined
I am using VS 2013 Update 3.
Do you have any idea what could be the issue?
Hi, I missed this comment back in 2014 but thought it was worth replying for others with the issue. This appears to me to be a missing d.ts file or an incorrect version. If you did ever solve the issue and can remember the issue / fix the please feel free to comment.
[…] Cross Project TypeScript Unit Testing – Part 1 Cross Project TypeScript Unit Testing – Part 2 […]
HI Martyn
Thanks for this. You are doing what I am trying to do – have my TS unit tests in a separate project. I have followed your instructions and I now have the files from my main project showing up under _referencesTS in my unit test project. I have a test file under ProjectB/Scripts/Api/greeterTests.ts. In this test file, I have a single line: import g = require(“Api/greeter”);. This is the same line I use in my application to include the greeter component so I can use it. However, with this setup, the compiler is telling me it can’t find the module Api/greeter. I have also tried referencing it as _referencesTS/Scripts/Api/greeter but it still can’t find it.
I notice that in this post and in part 2 you don’t mention requireJS at all. Are you using requireJS? I am trying to move to requireJS and this is all part of it. I think I can get my main application working properly with requireJS now, but the last part, the part that drew me to your posts was getting Chutzpah to work in this world of requireJS rather than the unwieldy ///reference directives.
Can you think of anything that you might have done with your project to be able to reference these linked TS files in Project B? I notice in your test TS file you don’t have any reference to the class under test so I am wondering how the compiler knows where to find your class under test.
Thanks
Greg