ts_web_test & karma fixes for Windows

Closes #162

PiperOrigin-RevId: 191444855
diff --git a/WORKSPACE b/WORKSPACE
index 96dfa15..921a976 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -14,15 +14,11 @@
 
 workspace(name = "build_bazel_rules_typescript")
 
-# Using a pre-release snapshot to pick up a commit that makes all nodejs_binary
-# programs produce source-mapped stack traces.
-RULES_NODEJS_VERSION = "926349cea4cd360afcd5647ccdd09d2d2fb471aa"
-
 http_archive(
     name = "build_bazel_rules_nodejs",
-    url = "https://github.com/bazelbuild/rules_nodejs/archive/%s.zip" % RULES_NODEJS_VERSION,
-    strip_prefix = "rules_nodejs-%s" % RULES_NODEJS_VERSION,
-    sha256 = "5ba3c8c209078c2e3f0c6aa4abd01a1a561f92a5bfda04e25604af5f4734d69d",
+    url = "https://github.com/bazelbuild/rules_nodejs/archive/0.5.3.zip",
+    strip_prefix = "rules_nodejs-0.5.3",
+    sha256 = "17a5515f59777b00cb25dbc710017a14273f825029b2ec60e0969d28914870be",
 )
 
 load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories")
diff --git a/internal/karma/index.ts b/internal/karma/index.ts
index 8ae1809..7c47734 100644
--- a/internal/karma/index.ts
+++ b/internal/karma/index.ts
@@ -41,7 +41,8 @@
         // Preserve all non-JS that were there in the included list.
         included.push(file);
       } else {
-        const relativePath = path.relative(basePath, file.originalPath);
+        const relativePath =
+            path.relative(basePath, file.originalPath).replace(/\\/g, '/');
 
         // Remove 'use strict'.
         let content = file.content.replace(/('use strict'|"use strict");?/,
diff --git a/internal/karma/karma.conf.js b/internal/karma/karma.conf.js
index fc69bfb..d5f45a6 100644
--- a/internal/karma/karma.conf.js
+++ b/internal/karma/karma.conf.js
@@ -1,5 +1,65 @@
 // Karma configuration
 // GENERATED BY Bazel
+const path = require('path');
+const fs = require('fs');
+const tmp = require('tmp');
+
+// When karma is configured to use Chrome it will look for a CHROME_BIN
+// environment variable. This line points Karma to use puppeteer instead.
+// See
+// https://github.com/karma-runner/karma-chrome-launcher/blob/master/README.md#headless-chromium-with-puppeteer
+process.env.CHROME_BIN = require('puppeteer').executablePath();
+
+let files = [
+  TMPL_files
+];
+
+// On Windows, runfiles will not be in the runfiles folder but inteaad
+// there is a MANIFEST file which maps the runfiles for the test
+// to their location on disk. Bazel provides a TEST_SRCDIR environment
+// variable which is set to the runfiles folder during test execution.
+// If a MANIFEST file is found, we remap the test files to their
+// location on disk using the MANIFEST file.
+const manifestFile = path.join(process.env.TEST_SRCDIR, 'MANIFEST');
+if (fs.existsSync(manifestFile)) {
+  // MANIFEST file contains the one runfile mapping per line seperated
+  // a space. For example:
+  // rxjs/operators.js /private/var/tmp/.../external/rxjs/operators.js
+  // The file is parsed here into a map of for easy lookup
+  const manifest = {};
+  for (l of fs.readFileSync(manifestFile, 'utf8').split('\n')) {
+    const m = l.split(' ');
+    manifest[m[0]] = m[1];
+  }
+  files = files.map(f => {
+    const manifestFile = manifest[f];
+    if (!manifestFile) {
+      throw new Error(`File not found in MANIFEST: ${f}`);
+    }
+    return manifestFile;
+  });
+}
+
+var requireConfigContent = `
+// A simplified version of Karma's requirejs.config.tpl.js for use with Karma under Bazel.
+// This does an explicit \`require\` on each script in the files, otherwise nothing will be loaded.
+(function(){
+  var allFiles = ${JSON.stringify([TMPL_files])};
+  var allTestFiles = [];
+  allFiles.forEach(function (file) {
+    if (/(spec|test)\\.js$/i.test(file)) {
+      allTestFiles.push(file.replace(/\\.js$/, ''))
+    }
+  });
+  require(allTestFiles, window.__karma__.start);
+})();
+`;
+
+const requireConfigFile = tmp.fileSync(
+    {keep: false, postfix: '.js', dir: process.env['TEST_TMPDIR']});
+fs.writeFileSync(requireConfigFile.name, requireConfigContent);
+files.push(requireConfigFile.name);
+
 module.exports = function(config) {
   if (process.env['IBAZEL_NOTIFY_CHANGES'] === 'y') {
     // Tell karma to only listen for ibazel messages on stdin rather than watch all the input files
@@ -49,8 +109,7 @@
 
     // base path that will be used to resolve all patterns (eg. files, exclude)
     basePath: 'TMPL_runfiles_path',
-    files: [
-TMPL_files
-    ]
+
+    files,
   })
 }
diff --git a/internal/karma/package.json b/internal/karma/package.json
index 26b0047..52d0091 100644
--- a/internal/karma/package.json
+++ b/internal/karma/package.json
@@ -6,6 +6,7 @@
     "karma-chrome-launcher": "2.2.0",
     "karma-jasmine": "1.1.1",
     "karma-requirejs": "1.1.0",
+    "puppeteer": "1.1.0",
     "requirejs": "2.3.5",
     "tmp": "0.0.33"
   }
diff --git a/internal/karma/ts_web_test.bzl b/internal/karma/ts_web_test.bzl
index 4b5833c..ec38259 100644
--- a/internal/karma/ts_web_test.bzl
+++ b/internal/karma/ts_web_test.bzl
@@ -55,7 +55,6 @@
   files_entries += [
     "build_bazel_rules_typescript_karma_deps/node_modules/requirejs/require.js",
     "build_bazel_rules_typescript_karma_deps/node_modules/karma-requirejs/lib/adapter.js",
-    "build_bazel_rules_typescript_karma_deps/node_modules/karma/requirejs.config.tpl.js",
   ]
   # Finally we load the user's srcs and deps
   files_entries += [
@@ -77,12 +76,29 @@
           "TMPL_headlessbrowser": "%sHeadless" % _BROWSER,
       })
 
+  karma_executable_path = ctx.executable._karma.short_path
+  if karma_executable_path.startswith('..'):
+    karma_executable_path = "external" + karma_executable_path[2:]
+
   ctx.actions.write(
       output = ctx.outputs.executable,
       is_executable = True,
       content = """#!/usr/bin/env bash
-readonly KARMA={TMPL_karma}
-readonly CONF={TMPL_conf}
+MANIFEST="$TEST_SRCDIR/MANIFEST"
+if [ -e "$MANIFEST" ]; then
+  while read line; do
+    declare -a PARTS=($line)
+    if [ "${{PARTS[0]}}" == "build_bazel_rules_typescript/{TMPL_karma}" ]; then
+      readonly KARMA=${{PARTS[1]}}
+    elif [ "${{PARTS[0]}}" == "build_bazel_rules_typescript/{TMPL_conf}" ]; then
+      readonly CONF=${{PARTS[1]}}
+    fi
+  done < $MANIFEST
+else
+  readonly KARMA={TMPL_karma}
+  readonly CONF={TMPL_conf}
+fi
+
 export HOME=$(mktemp -d)
 ARGV=( "start" $CONF )
 
@@ -93,7 +109,7 @@
 fi
 
 $KARMA ${{ARGV[@]}}
-""".format(TMPL_karma = ctx.executable._karma.short_path,
+""".format(TMPL_karma = karma_executable_path,
            TMPL_conf = conf.short_path))
   return [DefaultInfo(
       runfiles = ctx.runfiles(
diff --git a/internal/karma/yarn.lock b/internal/karma/yarn.lock
index 003e760..7a576fe 100644
--- a/internal/karma/yarn.lock
+++ b/internal/karma/yarn.lock
@@ -28,6 +28,12 @@
     extend "~3.0.0"
     semver "~5.0.1"
 
+agent-base@^4.1.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.0.tgz#9838b5c3392b962bad031e6a4c5e1024abec45ce"
+  dependencies:
+    es6-promisify "^5.0.0"
+
 ajv@^4.9.1:
   version "4.11.8"
   resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536"
@@ -375,6 +381,14 @@
   version "0.0.1"
   resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
 
+concat-stream@1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
+  dependencies:
+    inherits "^2.0.3"
+    readable-stream "^2.2.2"
+    typedarray "^0.0.6"
+
 connect@^3.6.0:
   version "3.6.5"
   resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.5.tgz#fb8dde7ba0763877d0ec9df9dac0b4b40e72c7da"
@@ -434,7 +448,7 @@
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/date-format/-/date-format-1.2.0.tgz#615e828e233dd1ab9bb9ae0950e0ceccfa6ecad8"
 
-debug@2, debug@2.6.9, debug@^2.2.0, debug@~2.6.4, debug@~2.6.6, debug@~2.6.9:
+debug@2, debug@2.6.9, debug@^2.2.0, debug@^2.6.8, debug@~2.6.4, debug@~2.6.6, debug@~2.6.9:
   version "2.6.9"
   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
   dependencies:
@@ -562,6 +576,16 @@
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d"
 
+es6-promise@^4.0.3:
+  version "4.2.4"
+  resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"
+
+es6-promisify@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
+  dependencies:
+    es6-promise "^4.0.3"
+
 escape-html@~1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@@ -634,6 +658,15 @@
   dependencies:
     is-extglob "^1.0.0"
 
+extract-zip@^1.6.5:
+  version "1.6.6"
+  resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c"
+  dependencies:
+    concat-stream "1.6.0"
+    debug "2.6.9"
+    mkdirp "0.5.0"
+    yauzl "2.4.1"
+
 extsprintf@1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
@@ -654,6 +687,12 @@
   version "2.0.6"
   resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
 
+fd-slicer@~1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65"
+  dependencies:
+    pend "~1.2.0"
+
 file-uri-to-path@1:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
@@ -980,6 +1019,13 @@
     debug "2"
     extend "3"
 
+https-proxy-agent@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.1.1.tgz#a7ce4382a1ba8266ee848578778122d491260fd9"
+  dependencies:
+    agent-base "^4.1.0"
+    debug "^3.1.0"
+
 iconv-lite@0.4.15:
   version "0.4.15"
   resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
@@ -1007,7 +1053,7 @@
     once "^1.3.0"
     wrappy "1"
 
-inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
+inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
 
@@ -1380,6 +1426,12 @@
   version "0.0.10"
   resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
 
+mkdirp@0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12"
+  dependencies:
+    minimist "0.0.8"
+
 "mkdirp@>=0.5 0", mkdirp@^0.5.1:
   version "0.5.1"
   resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
@@ -1628,6 +1680,10 @@
   dependencies:
     inflection "~1.3.0"
 
+pend@~1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
+
 performance-now@^0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
@@ -1658,6 +1714,14 @@
   version "1.0.7"
   resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
 
+process-nextick-args@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
+
+progress@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f"
+
 proxy-agent@~2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-2.0.0.tgz#57eb5347aa805d74ec681cb25649dba39c933499"
@@ -1671,6 +1735,10 @@
     pac-proxy-agent "1"
     socks-proxy-agent "2"
 
+proxy-from-env@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee"
+
 pseudomap@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
@@ -1679,6 +1747,19 @@
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
 
+puppeteer@1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.1.0.tgz#97fbc2fbbf9ab659e7e202a68ac1ba54b8bc0a25"
+  dependencies:
+    debug "^2.6.8"
+    extract-zip "^1.6.5"
+    https-proxy-agent "^2.1.0"
+    mime "^1.3.4"
+    progress "^2.0.0"
+    proxy-from-env "^1.0.0"
+    rimraf "^2.6.1"
+    ws "^3.0.0"
+
 q@~1.4.0:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e"
@@ -1749,6 +1830,18 @@
     string_decoder "~1.0.3"
     util-deprecate "~1.0.1"
 
+readable-stream@^2.2.2:
+  version "2.3.4"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.4.tgz#c946c3f47fa7d8eabc0b6150f4a12f69a4574071"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.3"
+    isarray "~1.0.0"
+    process-nextick-args "~2.0.0"
+    safe-buffer "~5.1.1"
+    string_decoder "~1.0.3"
+    util-deprecate "~1.0.1"
+
 readable-stream@~2.0.5:
   version "2.0.6"
   resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
@@ -2181,6 +2274,10 @@
     media-typer "0.3.0"
     mime-types "~2.1.15"
 
+typedarray@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+
 uid-number@^0.0.6:
   version "0.0.6"
   resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
@@ -2260,7 +2357,7 @@
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
 
-ws@~3.3.1:
+ws@^3.0.0, ws@~3.3.1:
   version "3.3.3"
   resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"
   dependencies:
@@ -2284,6 +2381,12 @@
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
 
+yauzl@2.4.1:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005"
+  dependencies:
+    fd-slicer "~1.0.1"
+
 yeast@0.1.2:
   version "0.1.2"
   resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"