19

I'm new to the Testacular(now Karma). But I found it is really powerful and great for automatic cross-browser JS testing. So I want to know if it is possible to use it as part of TFS building procedure to conduct automatic JS code unit testing? If anyone has previous experience, could you please let us know what to notice so that we are not going to take the wrong way.

Regards, Jun

bigbearzhu
  • 2,381
  • 6
  • 29
  • 44
  • I'd be very intested in reading feedbacks about that. I too would like to run Karma tests during TFS Build. Have you made any progress on this ? – Sam Aug 06 '13 at 16:41
  • Yeah, sure. At this moment, I have a web project in C# for back end and Html/JS for front end. I just created a test runner class for running the Karma on TFS server. See my answer to my self for the details. – bigbearzhu Sep 02 '13 at 23:57

2 Answers2

9

Here is my pseudo code to run the karma in TFS using C# helper class. The basic idea is:

  1. Use C# unit test to test your js files using Karma.
  2. Capture the output of Karma to show that in your build log.
  3. Use separate process to run Karma.
  4. Pack all Karma files into a zip file, extract that into temporary folder for each build, so that builds with different version of karma wouldn't conflict with each other.
  5. Clean the temp folder after build.

-

namespace Test.Javascript.CrossBrowserTests
{
    public class KarmaTestRunner : IDisposable
    {
        private const string KarmaPath = @".\node_modules\karma\bin\karma";

        private string NodeBasePath { get; set; }
        private string NodeFullPath { get { return NodeBasePath + @"\node\node.exe"; } }
        private string NpmFullPath { get { return NodeBasePath + @"\node\npm.cmd"; } }

        public KarmaTestRunner()
        {
            ExtractKarmaZip();
            LinkGlobalKarma();
        }

        public int Execute(params string[] arguments)
        {
            Process consoleProcess = RunKarma(arguments);
            return consoleProcess.ExitCode;
        }

        public void Dispose()
        {
            UnlinkGlobalKarma();
            RemoveTempKarmaFiles();
        }

        private void ExtractKarmaZip()
        {
            NodeBasePath = Path.GetTempPath() + Path.GetRandomFileName();
            byte[] resourceBytes = Assembly.GetExecutingAssembly().GetEmbeddedResourceBytes(typeof(KarmaTestRunner).Namespace + "." + "karma0.9.4.zip");

            ZipFile file = ZipFile.Read(resourceBytes);
            file.ExtractAll(NodeBasePath);
        }

        private void LinkGlobalKarma()
        {
            ExecuteConsoleProcess(NpmFullPath, "link", "karma");
        }

        private Process RunKarma(IEnumerable<string> arguments)
        {
            return ExecuteConsoleProcess(NodeFullPath, new[] { KarmaPath }.Concat(arguments).ToArray());
        }

        private static Process ExecuteConsoleProcess(string path, params string[] arguments)
        {
            //Create a process to run karma with arguments
            //Hook up the OutputDataReceived envent handler on the process
        }

        static void OnOutputLineReceived(string message)
        {
            if (message != null)
                Console.WriteLine(message);
        }

        private void UnlinkGlobalKarma()
        {
            ExecuteConsoleProcess(NpmFullPath, "uninstall", "karma");
        }

        private void RemoveTempKarmaFiles()
        {
            Directory.Delete(NodeBasePath, true);
        }
    }
}

Then use it like this:

namespace Test.Javascript.CrossBrowserTests
{
    [TestClass]
    public class CrossBrowserJSUnitTests
    {
        [TestMethod]
        public void JavascriptTestsPassForAllBrowsers()
        {
            using (KarmaTestRunner karmaRunner = new KarmaTestRunner())
            {
                int exitCode = karmaRunner.Execute("start", @".\Test.Project\Javascript\Karma\karma.conf.js");
                exitCode.ShouldBe(0);
            }
        }
    }
}
bigbearzhu
  • 2,381
  • 6
  • 29
  • 44
  • Thanks, that's very interesting. You do not show however how you check if your unit test has passed. I mean what if one of the Karma tests has failed, how do you make sure that your build is going to fail ? – Sam Sep 03 '13 at 06:21
  • In any case any Karma tests failed, I think KarmaTestRunner would not return 0 exit code. Then the unit test would fail and hence the whole build. – bigbearzhu Sep 03 '13 at 22:05
  • What is the content of the ExecuteConsoleProcess method? – Marius Sep 06 '13 at 10:49
  • @Marius sorry for late reply, it is just creating a console process located in the path using System.Diagnostics.Process and pass in necessary parameters for Karma, e.g. --remote-debugger-port etc. Remember you need hook up the OutputDataReceived handler with the OutputDataReceived function in the code above. – bigbearzhu Nov 18 '13 at 04:04
  • @bigbearzhu -- Thanks for the answer. I tried running a bat file and am able to get the output. 0 -All tests are passed, 1 -- some tests failed. But I would also like to know what tests failed, it will give the developer an idea of which code needs to be fixed. Can this be done? Thanks. – Bala May 18 '14 at 04:28
  • @Bala, you can utilize the Process.OutputDataReceived event on your process and link that to OnOutputLineReceived function in the example. When javascript tests pass/fail, output the result to console.log(), then you can get the result in your MSTest result. Javascript testing frameworks can be easily modified for this purpose, for example, you may want to try this on Jasmine, http://stackoverflow.com/questions/7157999/output-jasmine-test-results-to-the-console – bigbearzhu May 19 '14 at 10:52
  • @Bala, I used basil https://github.com/xwipeoutx/basil, a very similar testing framework to Jasmine. However, it requires a little bit more work to make it work with Karma. Hope that helps. – bigbearzhu May 19 '14 at 11:01
1

A lot has changed since the original question and answer.

However, we've gotten Karma to run in our TFS build by running a Grunt task (I'm sure the same is possible with Gulp/whatever task runner you have). We were using C# before, but recently changed.

  1. Have a grunt build task run.
  2. Add a Grunt task after that
  3. point the file path to your gruntfile.js and run your test task. This task will run karma:single. The grunt-cli location may be node_modules/grunt-cli/bin/grunt.

    grunt.registerTask('test', [ 'karma:single' ]);

  4. Add a Publish Test Results step. Test Results Files = **/*.trx

More information about publishing Karma Test Results

AlignedDev
  • 8,102
  • 9
  • 56
  • 91