text: "use strict";
  const path = require("path");
  const fs = require("fs");
  const jsYAML = require("js-yaml");
  const { Minimatch } = require("minimatch");
  const { describe, specify, before } = require("mocha-sugar-free");
  const { readManifest, getPossibleTestFilePaths, stripPrefix } = require("./wpt-manifest-utils.js");
  const startWPTServer = require("./start-wpt-server.js");
  
  const validReasons = new Set([
    "fail",
    "fail-slow",
    "timeout",
    "flaky",
    "mutates-globals",
    "needs-node10",
    "needs-node11"
  ]);
  
  const hasNode10 = Number(process.versions.node.split(".")[0]) >= 10;
  const hasNode11 = Number(process.versions.node.split(".")[0]) >= 11;
  
  const manifestFilename = path.resolve(__dirname, "wpt-manifest.json");
  const manifest = readManifest(manifestFilename);
  const possibleTestFilePaths = getPossibleTestFilePaths(manifest);
  
  const toRunFilename = path.resolve(__dirname, "to-run.yaml");
  const toRunString = fs.readFileSync(toRunFilename, { encoding: "utf-8" });
  const toRunDocs = jsYAML.safeLoadAll(toRunString, { filename: toRunFilename });
  
  const minimatchers = new Map();
  
  checkToRun();
  
  let wptServerURL;
  const runSingleWPT = require("./run-single-wpt.js")(() => wptServerURL);
  before({ timeout: 30 * 1000 }, () => {
    return startWPTServer({ toUpstream: false }).then(url => {
      wptServerURL = url;
    });
  });
  
  describe("web-platform-tests", () => {
    for (const toRunDoc of toRunDocs) {
      describe(toRunDoc.DIR, () => {
        for (const testFilePath of possibleTestFilePaths) {
          if (testFilePath.startsWith(toRunDoc.DIR + "/")) {
            const matchingPattern = expectationsInDoc(toRunDoc).find(pattern => {
              const matcher = minimatchers.get(toRunDoc.DIR + "/" + pattern);
              return matcher.match(testFilePath);
            });
  
            const testFile = stripPrefix(testFilePath, toRunDoc.DIR + "/");
            const reason = matchingPattern && toRunDoc[matchingPattern][0];
            const shouldSkip = ["fail-slow", "timeout", "flaky", "mutates-globals"].includes(reason);
            const expectFail = (reason === "fail") ||
                               (reason === "needs-node10" && !hasNode10) ||
                               (reason === "needs-node11" && !hasNode11);
  
            if (matchingPattern && shouldSkip) {
              specify.skip(`[${reason}] ${testFile}`);
            } else if (expectFail) {
              runSingleWPT(testFilePath, `[expected fail] ${testFile}`, expectFail);
            } else {
              runSingleWPT(testFilePath, testFile, expectFail);
            }
          }
        }
      });
    }
  });
  
  function checkToRun() {
    let lastDir = "";
    for (const doc of toRunDocs) {
      if (doc.DIR.startsWith("/")) {
        throw new Error(`DIR entries must not start with a slash: saw "${doc.DIR}"`);
      }
      if (doc.DIR.endsWith("/")) {
        throw new Error(`DIR entries must not end with a slash: saw "${doc.DIR}"`);
      }
  
      if (!fs.existsSync(path.resolve(__dirname, "tests", doc.DIR))) {
        throw new Error(`The directory "${doc.DIR}" does not exist`);
      }
  
      if (doc.DIR < lastDir) {
        throw new Error(`Bad lexicographical directory sorting in to-run.yaml: ${doc.DIR} should come before ${lastDir}`);
      }
      lastDir = doc.DIR;
  
      let lastPattern = "";
      for (const pattern of expectationsInDoc(doc)) {
        if (pattern.startsWith("/")) {
          throw new Error(`Expectation patterns must not start with a slash: saw "${pattern}"`);
        }
  
        if (pattern < lastPattern) {
          throw new Error("Bad lexicographical expectation pattern sorting in to-run.yaml: " + pattern +
                          " should come before " + lastPattern);
        }
        lastPattern = pattern;
  
        const reason = doc[pattern][0];
        if (!validReasons.has(reason)) {
          throw new Error(`Bad reason "${reason}" for expectation ${pattern}`);
        }
  
        const matcher = new Minimatch(doc.DIR + "/" + pattern);
        if (!possibleTestFilePaths.some(filename => matcher.match(filename))) {
          throw new Error(`Expectation pattern "${pattern}" does not match any test files`);
        }
        minimatchers.set(doc.DIR + "/" + pattern, matcher);
      }
    }
  }
  
  function expectationsInDoc(doc) {
    const keys = Object.keys(doc);
    keys.shift(); // get rid of the DIR key
    return keys;
  }
  