text: const DomUtils = require("domutils");
  const helper = require("../tools/helper.js");
  const { CSSselect } = helper;
  const assert = require("assert");
  const { throws: raises, equal, ok } = assert;
  const testInit = require("./data/testinit.js");
  const { q, t, createWithFriesXML } = testInit;
  let document = testInit.loadDoc();
  const expect = () => {};
  const test = it;
  const decircularize = require("../decircularize");
  
  function deepEqual(e, a, m) {
      return assert.deepEqual(decircularize(e), decircularize(a), m);
  }
  
  function Sizzle(str, doc = document) {
      return CSSselect(str, doc);
  }
  
  Sizzle.matches = (selector, elements) =>
      elements.filter(CSSselect.compile(selector));
  
  Sizzle.matchesSelector = CSSselect.is;
  
  function jQuery(dom) {
      if (typeof dom === "string") dom = helper.getDOM(dom);
      const ret = {
          appendTo(elem) {
              if (typeof elem === "string") [elem] = Sizzle(elem);
              dom.forEach((child) => {
                  DomUtils.appendChild(elem, child);
              });
              return this;
          },
          remove() {
              dom.forEach(DomUtils.removeElement);
              return this;
          },
          prev() {
              dom = dom.map((elem) => elem.prev);
              return this;
          },
          before(str) {
              dom.forEach((elem) => {
                  helper.getDOM(str).forEach((child) => {
                      DomUtils.prepend(elem, child);
                  });
              });
              return this;
          },
      };
  
      dom.forEach((elem, i) => {
          ret[i] = elem;
      });
  
      return ret;
  }
  
  beforeEach(() => {
      document = testInit.loadDoc();
  });
  
  // #### NOTE: ####
  // jQuery should not be used in this module
  // except for DOM manipulation
  // If jQuery is mandatory for the selection, move the test to jquery/test/unit/selector.js
  // Use t() or Sizzle()
  // ###############
  
  /*
  	======== QUnit Reference ========
  	http://docs.jquery.com/QUnit
  
  	Test methods:
  		expect(numAssertions)
  		stop()
  		start()
  			note: QUnit's eventual addition of an argument to stop/start is ignored in this test suite
  			so that start and stop can be passed as callbacks without worrying about
  				their parameters
  	Test assertions:
  		ok(value, [message])
  		equal(actual, expected, [message])
  		notEqual(actual, expected, [message])
  		deepEqual(actual, expected, [message])
  		notDeepEqual(actual, expected, [message])
  		strictEqual(actual, expected, [message])
  		notStrictEqual(actual, expected, [message])
  		raises(block, [expected], [message])
  
  	======== testinit.js reference ========
  	See data/testinit.js
  
  	q(...);
  		Returns an array of elements with the given IDs
  		@example q("main", "foo", "bar") => [<div id="main">, <span id="foo">, <input id="bar">]
  
  	t( testName, selector, [ "array", "of", "ids" ] );
  		Asserts that a select matches the given IDs
  		@example t("Check for something", "//[a]", ["foo", "baar"]);
  
  	url( "some/url.php" );
  		Add random number to url to stop caching
  		@example url("data/test.html") => "data/test.html?10538358428943"
  		@example url("data/test.php?foo=bar") => "data/test.php?foo=bar&10538358345554"
  */
  
  test("element", () => {
      expect(38);
  
      equal(Sizzle("").length, 0, "Empty selector returns an empty array");
      deepEqual(
          Sizzle("div", document.createTextNode("")),
          [],
          "Text element as context fails silently"
      );
      const form = document.getElementById("form");
      ok(
          !Sizzle.matchesSelector(form, ""),
          "Empty string passed to matchesSelector does not match"
      );
      equal(Sizzle(" ").length, 0, "Empty selector returns an empty array");
      equal(Sizzle("\t").length, 0, "Empty selector returns an empty array");
  
      ok(Sizzle("*").length >= 30, "Select all");
      const all = Sizzle("*");
      let good = true;
      for (let i = 0; i < all.length; i++) {
          if (all[i].nodeType === 8) {
              good = false;
          }
      }
      ok(good, "Select all elements, no comment nodes");
      t("Element Selector", "html", ["html"]);
      t("Element Selector", "body", ["body"]);
      t("Element Selector", "#qunit-fixture p", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
  
      t("Leading space", " #qunit-fixture p", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t("Leading tab", "\t#qunit-fixture p", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t("Leading carriage return", "\r#qunit-fixture p", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t("Leading line feed", "\n#qunit-fixture p", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t("Leading form feed", "\f#qunit-fixture p", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t("Trailing space", "#qunit-fixture p ", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t("Trailing tab", "#qunit-fixture p\t", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t("Trailing carriage return", "#qunit-fixture p\r", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t("Trailing line feed", "#qunit-fixture p\n", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t("Trailing form feed", "#qunit-fixture p\f", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
  
      t("Parent Element", "dl ol", ["empty", "listWithTabIndex"]);
      t("Parent Element (non-space descendant combinator)", "dl\tol", [
          "empty",
          "listWithTabIndex",
      ]);
      const obj1 = document.getElementById("object1");
      equal(Sizzle("param", obj1).length, 2, "Object/param as context");
  
      deepEqual(
          Sizzle("select", form),
          q("select1", "select2", "select3", "select4", "select5"),
          "Finding selects with a context."
      );
  
      // Check for unique-ness and sort order
      deepEqual(
          Sizzle("p, div p"),
          Sizzle("p"),
          "Check for duplicates: p, div p"
      );
  
      t("Checking sort order", "h2, h1", [
          "qunit-header",
          "qunit-banner",
          "qunit-userAgent",
      ]);
      //  t( "Checking sort order", "h2:first, h1:first", ["qunit-header", "qunit-banner"] );
      t("Checking sort order", "#qunit-fixture p, #qunit-fixture p a", [
          "firstp",
          "simon1",
          "ap",
          "google",
          "groups",
          "anchor1",
          "mark",
          "sndp",
          "en",
          "yahoo",
          "sap",
          "anchor2",
          "simon",
          "first",
      ]);
  
      // Test Conflict ID
      const lengthtest = document.getElementById("lengthtest");
      deepEqual(
          Sizzle("#idTest", lengthtest),
          q("idTest"),
          "Finding element with id of ID."
      );
      deepEqual(
          Sizzle("[name='id']", lengthtest),
          q("idTest"),
          "Finding element with id of ID."
      );
      deepEqual(
          Sizzle("input[id='idTest']", lengthtest),
          q("idTest"),
          "Finding elements with id of ID."
      );
  
      const siblingTest = document.getElementById("siblingTest"); // TODO
      deepEqual(
          Sizzle("div em", siblingTest),
          [],
          "Element-rooted QSA does not select based on document context"
      );
      deepEqual(
          Sizzle("div em, div em, div em:not(div em)", siblingTest),
          [],
          "Element-rooted QSA does not select based on document context"
      );
      deepEqual(
          Sizzle("div em, em\\,", siblingTest),
          [],
          "Escaped commas do not get treated with an id in element-rooted QSA"
      );
  
      const iframe = document.getElementById("iframe");
      //iframeDoc.open();
      iframe.children = helper.getDOM("<body><p id='foo'>bar</p></body>");
      iframe.children.forEach((e) => {
          e.parent = iframe;
      });
      //iframeDoc.close();
      deepEqual(
          Sizzle("p:contains(bar)", iframe),
          [DomUtils.getElementById("foo", iframe.children)],
          "Other document as context"
      );
      iframe.children = [];
  
      let html = "";
      for (let i = 0; i < 100; i++) {
          html = `<div>${html}</div>`;
      }
      html = jQuery(html).appendTo(document.body);
      ok(
          !!Sizzle("body div div div").length,
          "No stack or performance problems with large amounts of descendents"
      );
      ok(
          !!Sizzle("body>div div div").length,
          "No stack or performance problems with large amounts of descendents"
      );
      html.remove();
  
      // Real use case would be using .watch in browsers with window.watch (see Issue #157)
      const elem = document.createElement("tostring");
      elem.attribs.id = "toString";
      const siblings = q("qunit-fixture")[0].children;
      siblings.push(elem);
      t("Element name matches Object.prototype property", "tostring#toString", [
          "toString",
      ]);
      siblings.pop();
  });
  
  test("XML Document Selectors", () => {
      let xml = createWithFriesXML();
      expect(11);
  
      equal(Sizzle("foo_bar", xml).length, 1, "Element Selector with underscore");
      equal(Sizzle(".component", xml).length, 1, "Class selector");
      equal(
          Sizzle("[class*=component]", xml).length,
          1,
          "Attribute selector for class"
      );
      equal(
          Sizzle("property[name=prop2]", xml).length,
          1,
          "Attribute selector with name"
      );
      equal(
          Sizzle("[name=prop2]", xml).length,
          1,
          "Attribute selector with name"
      );
      equal(Sizzle("#seite1", xml).length, 1, "Attribute selector with ID");
      equal(
          Sizzle("component#seite1", xml).length,
          1,
          "Attribute selector with ID"
      );
      equal(
          Sizzle.matches("#seite1", Sizzle("component", xml)).length,
          1,
          "Attribute selector filter with ID"
      );
      equal(
          Sizzle("meta property thing", xml).length,
          2,
          "Descendent selector and dir caching"
      );
      ok(
          Sizzle.matchesSelector(xml.lastChild, "soap\\:Envelope", {
              xmlMode: true,
          }),
          "Check for namespaced element"
      );
  
      xml = helper.getDOM(
          "<?xml version='1.0' encoding='UTF-8'?><root><elem id='1'/></root>",
          {
              xmlMode: true,
          }
      );
      equal(
          Sizzle("elem:not(:has(*))", xml).length,
          1,
          "Non-qSA path correctly handles numeric ids (jQuery #14142)"
      );
  });
  
  test("broken", () => {
      expect(26);
  
      const broken = (name, selector) => {
          raises(
              () => {
                  // Setting context to null here somehow avoids QUnit's window.error handling
                  // making the e & e.message correct
                  // For whatever reason, without this,
                  // Sizzle.error will be called but no error will be seen in oldIE
                  Sizzle.call(null, selector);
              },
              Error,
              `${name}: ${selector}`
          );
      };
  
      broken("Broken Selector", "[");
      broken("Broken Selector", "(");
      broken("Broken Selector", "{");
      //  broken( "Broken Selector", "<" );
      broken("Broken Selector", "()");
      //  broken( "Broken Selector", "<>" );
      broken("Broken Selector", "{}");
      broken("Broken Selector", ",");
      broken("Broken Selector", ",a");
      broken("Broken Selector", "a,");
      // Hangs on IE 9 if regular expression is inefficient
      broken("Broken Selector", "[id=012345678901234567890123456789");
      broken("Doesn't exist", ":visble");
      broken("Nth-child", ":nth-child");
      // Sigh again. IE 9 thinks this is also a real selector
      // not super critical that we fix this case
      broken("Nth-child", ":nth-child(-)");
      // Sigh. WebKit thinks this is a real selector in qSA
      // They've already fixed this and it'll be coming into
      // current browsers soon. Currently, Safari 5.0 still has this problem
      broken("Nth-child", ":nth-child(asdf)", []);
      broken("Nth-child", ":nth-child(2n+-0)");
      broken("Nth-child", ":nth-child(2+0)");
      broken("Nth-child", ":nth-child(- 1n)");
      broken("Nth-child", ":nth-child(-1 n)");
      broken("First-child", ":first-child(n)");
      broken("Last-child", ":last-child(n)");
      broken("Only-child", ":only-child(n)");
      broken("Nth-last-last-child", ":nth-last-last-child(1)");
      broken("First-last-child", ":first-last-child");
      broken("Last-last-child", ":last-last-child");
      broken("Only-last-child", ":only-last-child");
  
      // Make sure attribute value quoting works correctly. See: #6093
      jQuery(
          "<input type='hidden' value='2' name='foo.baz' id='attrbad1'/><input type='hidden' value='2' name='foo[baz]' id='attrbad2'/>"
      ).appendTo("#qunit-fixture");
  
      broken("Attribute not escaped", "input[name=foo.baz]", []);
      // Shouldn't be matching those inner brackets
      broken("Attribute not escaped", "input[name=foo[baz]]", []);
  });
  
  test("id", () => {
      expect(34);
  
      t("ID Selector", "#body", ["body"]);
      t("ID Selector w/ Element", "body#body", ["body"]);
      t("ID Selector w/ Element", "ul#first", []);
      t("ID selector with existing ID descendant", "#firstp #simon1", ["simon1"]);
      t("ID selector with non-existant descendant", "#firstp #foobar", []);
      t("ID selector using UTF8", "#台北Táiběi", ["台北Táiběi"]);
      t("Multiple ID selectors using UTF8", "#台北Táiběi, #台北", [
          "台北Táiběi",
          "台北",
      ]);
      t("Descendant ID selector using UTF8", "div #台北", ["台北"]);
      t("Child ID selector using UTF8", "form > #台北", ["台北"]);
  
      t("Escaped ID", "#foo\\:bar", ["foo:bar"]);
      t("Escaped ID with descendent", "#foo\\:bar span:not(:input)", [
          "foo_descendent",
      ]);
      t("Escaped ID", "#test\\.foo\\[5\\]bar", ["test.foo[5]bar"]);
      t("Descendant escaped ID", "div #foo\\:bar", ["foo:bar"]);
      t("Descendant escaped ID", "div #test\\.foo\\[5\\]bar", ["test.foo[5]bar"]);
      t("Child escaped ID", "form > #foo\\:bar", ["foo:bar"]);
      t("Child escaped ID", "form > #test\\.foo\\[5\\]bar", ["test.foo[5]bar"]);
  
      const fiddle = jQuery(
          "<div id='fiddle\\Foo'><span id='fiddleSpan'></span></div>"
      ).appendTo("#qunit-fixture");
      //  deepEqual( Sizzle( "> span", Sizzle("#fiddle\\\\Foo")[0] ), q([ "fiddleSpan" ]), "Escaped ID as context" );
      fiddle.remove();
  
      t("ID Selector, child ID present", "#form > #radio1", ["radio1"]); // bug #267
      t("ID Selector, not an ancestor ID", "#form #first", []);
      t("ID Selector, not a child ID", "#form > #option1a", []);
  
      t("All Children of ID", "#foo > *", ["sndp", "en", "sap"]);
      t("All Children of ID with no children", "#firstUL > *", []);
  
      equal(
          Sizzle("#tName1")[0].attribs.id,
          "tName1",
          "ID selector with same value for a name attribute"
      );
      t("ID selector non-existing but name attribute on an A tag", "#tName2", []);
      t(
          "Leading ID selector non-existing but name attribute on an A tag",
          "#tName2 span",
          []
      );
      t("Leading ID selector existing, retrieving the child", "#tName1 span", [
          "tName1-span",
      ]);
      equal(
          Sizzle("div > div #tName1")[0].attribs.id,
          Sizzle("#tName1-span")[0].parent.attribs.id,
          "Ending with ID"
      );
  
      jQuery("<a id='backslash\\foo'></a>").appendTo("#qunit-fixture");
      t("ID Selector contains backslash", "#backslash\\\\foo", [
          "backslash\\foo",
      ]);
  
      t(
          "ID Selector on Form with an input that has a name of 'id'",
          "#lengthtest",
          ["lengthtest"]
      );
  
      t("ID selector with non-existant ancestor", "#asdfasdf #foobar", []); // bug #986
  
      deepEqual(
          Sizzle("div#form", document.body),
          [],
          "ID selector within the context of another element"
      );
  
      t("Underscore ID", "#types_all", ["types_all"]);
      t("Dash ID", "#qunit-fixture", ["qunit-fixture"]);
  
      t("ID with weird characters in it", "#name\\+value", ["name+value"]);
  });
  
  test("class", () => {
      expect(26);
  
      t("Class Selector", ".blog", ["mark", "simon"]);
      t("Class Selector", ".GROUPS", ["groups"]);
      t("Class Selector", ".blog.link", ["simon"]);
      t("Class Selector w/ Element", "a.blog", ["mark", "simon"]);
      t("Parent Class Selector", "p .blog", ["mark", "simon"]);
  
      t("Class selector using UTF8", ".台北Táiběi", ["utf8class1"]);
      t("Class selector using UTF8", ".台北", ["utf8class1", "utf8class2"]);
      t("Class selector using UTF8", ".台北Táiběi.台北", ["utf8class1"]);
      t("Class selector using UTF8", ".台北Táiběi, .台北", [
          "utf8class1",
          "utf8class2",
      ]);
      t("Descendant class selector using UTF8", "div .台北Táiběi", [
          "utf8class1",
      ]);
      t("Child class selector using UTF8", "form > .台北Táiběi", ["utf8class1"]);
  
      t("Escaped Class", ".foo\\:bar", ["foo:bar"]);
      t("Escaped Class", ".test\\.foo\\[5\\]bar", ["test.foo[5]bar"]);
      t("Descendant escaped Class", "div .foo\\:bar", ["foo:bar"]);
      t("Descendant escaped Class", "div .test\\.foo\\[5\\]bar", [
          "test.foo[5]bar",
      ]);
      t("Child escaped Class", "form > .foo\\:bar", ["foo:bar"]);
      t("Child escaped Class", "form > .test\\.foo\\[5\\]bar", [
          "test.foo[5]bar",
      ]);
  
      let div = document.createElement("div");
      div.children = helper.getDOM(
          "<div class='test e'></div><div class='test'></div>"
      );
      div.children.forEach((e) => {
          e.parent = div;
      });
      deepEqual(Sizzle(".e", div), [div.children[0]], "Finding a second class.");
  
      const lastChild = div.children[div.children.length - 1];
      lastChild.attribs.class = "e";
  
      deepEqual(
          Sizzle(".e", div),
          [div.children[0], lastChild],
          "Finding a modified class."
      );
  
      ok(
          !Sizzle.matchesSelector(div, ".null"),
          ".null does not match an element with no class"
      );
      ok(
          !Sizzle.matchesSelector(div.children[0], ".null div"),
          ".null does not match an element with no class"
      );
      div.attribs.class = "null";
      ok(
          Sizzle.matchesSelector(div, ".null"),
          ".null matches element with class 'null'"
      );
      ok(
          Sizzle.matchesSelector(div.children[0], ".null div"),
          "caching system respects DOM changes"
      );
      ok(
          !Sizzle.matchesSelector(document, ".foo"),
          "testing class on document doesn't error"
      );
      //ok( !Sizzle.matchesSelector( window, ".foo" ), "testing class on window doesn't error" );
  
      lastChild.attribs.class += " hasOwnProperty toString";
      deepEqual(
          Sizzle(".e.hasOwnProperty.toString", div),
          [lastChild],
          "Classes match Object.prototype properties"
      );
  
      div = jQuery(
          "<div><svg width='200' height='250' version='1.1' xmlns='http://www.w3.org/2000/svg'><rect x='10' y='10' width='30' height='30' class='foo'></rect></svg></div>"
      )[0];
      equal(Sizzle(".foo", div).length, 1, "Class selector against SVG");
  });
  
  test("name", () => {
      expect(13);
  
      let form;
  
      t("Name selector", "input[name=action]", ["text1"]);
      t("Name selector with single quotes", "input[name='action']", ["text1"]);
      t("Name selector with double quotes", 'input[name="action"]', ["text1"]);
  
      t("Name selector non-input", "[name=example]", ["name-is-example"]);
      t("Name selector non-input", "[name=div]", ["name-is-div"]);
      t("Name selector non-input", "*[name=iframe]", ["iframe"]);
  
      t("Name selector for grouped input", "input[name='types[]']", [
          "types_all",
          "types_anime",
          "types_movie",
      ]);
  
      form = document.getElementById("form");
      deepEqual(
          Sizzle("input[name=action]", form),
          q("text1"),
          "Name selector within the context of another element"
      );
      deepEqual(
          Sizzle("input[name='foo[bar]']", form),
          q("hidden2"),
          "Name selector for grouped form element within the context of another element"
      );
  
      form = jQuery("<form><input name='id'/></form>").appendTo("body");
      equal(
          Sizzle("input", form[0]).length,
          1,
          "Make sure that rooted queries on forms (with possible expandos) work."
      );
  
      form.remove();
  
      t("Find elements that have similar IDs", "[name=tName1]", ["tName1ID"]);
      t("Find elements that have similar IDs", "[name=tName2]", ["tName2ID"]);
      t("Find elements that have similar IDs", "#tName2ID", ["tName2ID"]);
  });
  
  test("multiple", () => {
      expect(6);
  
      t("Comma Support", "h2, #qunit-fixture p", [
          "qunit-banner",
          "qunit-userAgent",
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t("Comma Support", "h2 , #qunit-fixture p", [
          "qunit-banner",
          "qunit-userAgent",
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t("Comma Support", "h2 , #qunit-fixture p", [
          "qunit-banner",
          "qunit-userAgent",
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t("Comma Support", "h2,#qunit-fixture p", [
          "qunit-banner",
          "qunit-userAgent",
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t("Comma Support", "h2,#qunit-fixture p ", [
          "qunit-banner",
          "qunit-userAgent",
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t("Comma Support", "h2\t,\r#qunit-fixture p\n", [
          "qunit-banner",
          "qunit-userAgent",
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
  });
  
  test("child and adjacent", () => {
      expect(42);
  
      t("Child", "p > a", [
          "simon1",
          "google",
          "groups",
          "mark",
          "yahoo",
          "simon",
      ]);
      t("Child", "p> a", [
          "simon1",
          "google",
          "groups",
          "mark",
          "yahoo",
          "simon",
      ]);
      t("Child", "p >a", [
          "simon1",
          "google",
          "groups",
          "mark",
          "yahoo",
          "simon",
      ]);
      t("Child", "p>a", ["simon1", "google", "groups", "mark", "yahoo", "simon"]);
      t("Child w/ Class", "p > a.blog", ["mark", "simon"]);
      t("All Children", "code > *", ["anchor1", "anchor2"]);
      t("All Grandchildren", "p > * > *", ["anchor1", "anchor2"]);
      t("Adjacent", "#qunit-fixture a + a", ["groups", "tName2ID"]);
      t("Adjacent", "#qunit-fixture a +a", ["groups", "tName2ID"]);
      t("Adjacent", "#qunit-fixture a+ a", ["groups", "tName2ID"]);
      t("Adjacent", "#qunit-fixture a+a", ["groups", "tName2ID"]);
      t("Adjacent", "p + p", ["ap", "en", "sap"]);
      t("Adjacent", "p#firstp + p", ["ap"]);
      t("Adjacent", "p[lang=en] + p", ["sap"]);
      t("Adjacent", "a.GROUPS + code + a", ["mark"]);
      t("Comma, Child, and Adjacent", "#qunit-fixture a + a, code > a", [
          "groups",
          "anchor1",
          "anchor2",
          "tName2ID",
      ]);
      t("Element Preceded By", "#qunit-fixture p ~ div", [
          "foo",
          "nothiddendiv",
          "moretests",
          "tabindex-tests",
          "liveHandlerOrder",
          "siblingTest",
      ]);
      t("Element Preceded By", "#first ~ div", [
          "moretests",
          "tabindex-tests",
          "liveHandlerOrder",
          "siblingTest",
      ]);
      t("Element Preceded By", "#groups ~ a", ["mark"]);
      t("Element Preceded By", "#length ~ input", ["idTest"]);
      t("Element Preceded By", "#siblingfirst ~ em", [
          "siblingnext",
          "siblingthird",
      ]);
      t("Element Preceded By (multiple)", "#siblingTest em ~ em ~ em ~ span", [
          "siblingspan",
      ]);
      t(
          "Element Preceded By, Containing",
          "#liveHandlerOrder ~ div em:contains('1')",
          ["siblingfirst"]
      );
  
      const siblingFirst = document.getElementById("siblingfirst");
  
      deepEqual(
          Sizzle("~ em", siblingFirst),
          q("siblingnext", "siblingthird"),
          "Element Preceded By with a context."
      );
      deepEqual(
          Sizzle("+ em", siblingFirst),
          q("siblingnext"),
          "Element Directly Preceded By with a context."
      );
      //deepEqual( Sizzle("~ em:first", siblingFirst), q("siblingnext"), "Element Preceded By positional with a context." );
  
      const en = document.getElementById("en");
      deepEqual(
          Sizzle("+ p, a", en),
          q("yahoo", "sap"),
          "Compound selector with context, beginning with sibling test."
      );
      deepEqual(
          Sizzle("a, + p", en),
          q("yahoo", "sap"),
          "Compound selector with context, containing sibling test."
      );
  
      t("Multiple combinators selects all levels", "#siblingTest em *", [
          "siblingchild",
          "siblinggrandchild",
          "siblinggreatgrandchild",
      ]);
      t("Multiple combinators selects all levels", "#siblingTest > em *", [
          "siblingchild",
          "siblinggrandchild",
          "siblinggreatgrandchild",
      ]);
      t(
          "Multiple sibling combinators doesn't miss general siblings",
          "#siblingTest > em:first-child + em ~ span",
          ["siblingspan"]
      );
      t(
          "Combinators are not skipped when mixing general and specific",
          "#siblingTest > em:contains('x') + em ~ span",
          []
      );
  
      equal(
          Sizzle("#listWithTabIndex").length,
          1,
          "Parent div for next test is found via ID (#8310)"
      );
      //equal( Sizzle("#listWithTabIndex li:eq(2) ~ li").length, 1, "Find by general sibling combinator (#8310)" );
      equal(
          Sizzle("#__sizzle__").length,
          0,
          "Make sure the temporary id assigned by sizzle is cleared out (#8310)"
      );
      equal(
          Sizzle("#listWithTabIndex").length,
          1,
          "Parent div for previous test is still found via ID (#8310)"
      );
  
      t("Verify deep class selector", "div.blah > p > a", []);
  
      t("No element deep selector", "div.foo > span > a", []);
  
      //deepEqual( Sizzle("> :first", nothiddendiv), q("nothiddendivchild"), "Verify child context positional selector" );
      //deepEqual( Sizzle("> :eq(0)", nothiddendiv), q("nothiddendivchild"), "Verify child context positional selector" );
      //deepEqual( Sizzle("> *:first", nothiddendiv), q("nothiddendivchild"), "Verify child context positional selector" );
  
      t("Non-existant ancestors", ".fototab > .thumbnails > a", []);
      deepEqual(
          CSSselect.selectOne(
              ":scope > label",
              CSSselect.selectOne("#scopeTest", document)
          ),
          CSSselect.selectOne("#scopeTest--child", document),
          "Child of scope"
      );
  });
  
  test("attributes", () => {
      expect(76);
  
      t("Attribute Exists", "#qunit-fixture a[title]", ["google"]);
      t("Attribute Exists (case-insensitive)", "#qunit-fixture a[TITLE]", [
          "google",
      ]);
      t("Attribute Exists", "#qunit-fixture *[title]", ["google"]);
      t("Attribute Exists", "#qunit-fixture [title]", ["google"]);
      t("Attribute Exists", "#qunit-fixture a[ title ]", ["google"]);
  
      t("Boolean attribute exists", "#select2 option[selected]", ["option2d"]);
      t("Boolean attribute equals", "#select2 option[selected='selected']", [
          "option2d",
      ]);
  
      t("Attribute Equals", "#qunit-fixture a[rel='bookmark']", ["simon1"]);
      t("Attribute Equals", "#qunit-fixture a[rel='bookmark']", ["simon1"]);
      t("Attribute Equals", "#qunit-fixture a[rel=bookmark]", ["simon1"]);
      t("Attribute Equals", "#qunit-fixture a[href='http://www.google.com/']", [
          "google",
      ]);
      t("Attribute Equals", "#qunit-fixture a[ rel = 'bookmark' ]", ["simon1"]);
      t("Attribute Equals Number", "#qunit-fixture option[value=1]", [
          "option1b",
          "option2b",
          "option3b",
          "option4b",
          "option5c",
      ]);
      t("Attribute Equals Number", "#qunit-fixture li[tabIndex=-1]", [
          "foodWithNegativeTabIndex",
      ]);
  
      document.getElementById("anchor2").href = "#2";
      t("href Attribute", "p a[href^=#]", ["anchor2"]);
      t("href Attribute", "p a[href*=#]", ["simon1", "anchor2"]);
  
      t("for Attribute", "form label[for]", ["label-for"]);
      t("for Attribute in form", "#form [for=action]", ["label-for"]);
  
      t("Attribute containing []", "input[name^='foo[']", ["hidden2"]);
      t("Attribute containing []", "input[name^='foo[bar]']", ["hidden2"]);
      t("Attribute containing []", "input[name*='[bar]']", ["hidden2"]);
      t("Attribute containing []", "input[name$='bar]']", ["hidden2"]);
      t("Attribute containing []", "input[name$='[bar]']", ["hidden2"]);
      t("Attribute containing []", "input[name$='foo[bar]']", ["hidden2"]);
      t("Attribute containing []", "input[name*='foo[bar]']", ["hidden2"]);
  
      deepEqual(
          Sizzle("input[data-comma='0,1']"),
          [document.getElementById("el12087")],
          "Without context, single-quoted attribute containing ','"
      );
      deepEqual(
          Sizzle('input[data-comma="0,1"]'),
          [document.getElementById("el12087")],
          "Without context, double-quoted attribute containing ','"
      );
      deepEqual(
          Sizzle("input[data-comma='0,1']", document.getElementById("t12087")),
          [document.getElementById("el12087")],
          "With context, single-quoted attribute containing ','"
      );
      deepEqual(
          Sizzle('input[data-comma="0,1"]', document.getElementById("t12087")),
          [document.getElementById("el12087")],
          "With context, double-quoted attribute containing ','"
      );
  
      t(
          "Multiple Attribute Equals",
          "#form input[type='radio'], #form input[type='hidden']",
          ["radio1", "radio2", "hidden1"]
      );
      t(
          "Multiple Attribute Equals",
          "#form input[type='radio'], #form input[type=\"hidden\"]",
          ["radio1", "radio2", "hidden1"]
      );
      t(
          "Multiple Attribute Equals",
          "#form input[type='radio'], #form input[type=hidden]",
          ["radio1", "radio2", "hidden1"]
      );
  
      t("Attribute selector using UTF8", "span[lang=中文]", ["台北"]);
  
      t("Attribute Begins With", "a[href ^= 'http://www']", ["google", "yahoo"]);
      t("Attribute Ends With", "a[href $= 'org/']", ["mark"]);
      t("Attribute Contains", "a[href *= 'google']", ["google", "groups"]);
      t("Attribute Is Not Equal", "#ap a[hreflang!='en']", [
          "google",
          "groups",
          "anchor1",
      ]);
  
      const opt = document.getElementById("option1a");
      opt.attribs.test = "";
  
      ok(
          Sizzle.matchesSelector(opt, "[id*=option1][type!=checkbox]"),
          "Attribute Is Not Equal Matches"
      );
      ok(
          Sizzle.matchesSelector(opt, "[id*=option1]"),
          "Attribute With No Quotes Contains Matches"
      );
      ok(
          Sizzle.matchesSelector(opt, "[test=]"),
          "Attribute With No Quotes No Content Matches"
      );
      ok(
          !Sizzle.matchesSelector(opt, "[test^='']"),
          "Attribute with empty string value does not match startsWith selector (^=)"
      );
      ok(
          Sizzle.matchesSelector(opt, "[id=option1a]"),
          "Attribute With No Quotes Equals Matches"
      );
      ok(
          Sizzle.matchesSelector(document.getElementById("simon1"), "a[href*=#]"),
          "Attribute With No Quotes Href Contains Matches"
      );
  
      t("Empty values", "#select1 option[value='']", ["option1a"]);
      t("Empty values", "#select1 option[value!='']", [
          "option1b",
          "option1c",
          "option1d",
      ]);
  
      t("Select options via :selected", "#select1 option:selected", ["option1a"]);
      t("Select options via :selected", "#select2 option:selected", ["option2d"]);
      t("Select options via :selected", "#select3 option:selected", [
          "option3b",
          "option3c",
      ]);
      t(
          "Select options via :selected",
          "select[name='select2'] option:selected",
          ["option2d"]
      );
  
      t("Grouped Form Elements", "input[name='foo[bar]']", ["hidden2"]);
  
      const input = document.getElementById("text1");
      input.attribs.title = "Don't click me";
  
      ok(
          Sizzle.matchesSelector(input, 'input[title="Don\'t click me"]'),
          "Quote within attribute value does not mess up tokenizer"
      );
  
      // Uncomment if the boolHook is removed
      // var check2 = document.getElementById("check2");
      // check2.checked = true;
      // ok( !Sizzle.matches("[checked]", [ check2 ] ), "Dynamic boolean attributes match when they should with Sizzle.matches (#11115)" );
  
      // jQuery #12303
      input.attribs["data-pos"] = ":first";
      ok(
          Sizzle.matchesSelector(input, "input[data-pos=\\:first]"),
          "POS within attribute value is treated as an attribute value"
      );
      ok(
          Sizzle.matchesSelector(input, "input[data-pos=':first']"),
          "POS within attribute value is treated as an attribute value"
      );
      ok(
          Sizzle.matchesSelector(input, ":input[data-pos=':first']"),
          "POS within attribute value after pseudo is treated as an attribute value"
      );
      delete input.attribs["data-pos"];
  
      // Make sure attribute value quoting works correctly. See jQuery #6093; #6428; #13894
      // Use seeded results to bypass querySelectorAll optimizations
      const attrbad = jQuery(
          "<input type='hidden' id='attrbad_space' name='foo bar'/>" +
              "<input type='hidden' id='attrbad_dot' value='2' name='foo.baz'/>" +
              "<input type='hidden' id='attrbad_brackets' value='2' name='foo[baz]'/>" +
              "<input type='hidden' id='attrbad_injection' data-attr='foo_baz&#39;]'/>" +
              "<input type='hidden' id='attrbad_quote' data-attr='&#39;'/>" +
              "<input type='hidden' id='attrbad_backslash' data-attr='&#92;'/>" +
              "<input type='hidden' id='attrbad_backslash_quote' data-attr='&#92;&#39;'/>" +
              "<input type='hidden' id='attrbad_backslash_backslash' data-attr='&#92;&#92;'/>" +
              "<input type='hidden' id='attrbad_unicode' data-attr='&#x4e00;'/>"
      ).appendTo("#qunit-fixture");
  
      t("Underscores don't need escaping", "input[id=types_all]", ["types_all"]);
  
      deepEqual(
          Sizzle("input[name=foo\\ bar]"),
          q("attrbad_space"),
          "Escaped space"
      );
      deepEqual(Sizzle("input[name=foo\\.baz]"), q("attrbad_dot"), "Escaped dot");
      deepEqual(
          Sizzle("input[name=foo\\[baz\\]]"),
          q("attrbad_brackets"),
          "Escaped brackets"
      );
      //  deepEqual( Sizzle( "input[data-attr='foo_baz\\']']"), q("attrbad_injection"),
      //	"Escaped quote + right bracket" );
  
      //  deepEqual( Sizzle( "input[data-attr='\\'']"), q("attrbad_quote"),
      //	"Quoted quote" );
      //  deepEqual( Sizzle( "input[data-attr='\\\\']"), q("attrbad_backslash"),
      //	"Quoted backslash" );
      //  deepEqual( Sizzle( "input[data-attr='\\\\\\'']"), q("attrbad_backslash_quote"),
      //	"Quoted backslash quote" );
      //  deepEqual( Sizzle( "input[data-attr='\\\\\\\\']"), q("attrbad_backslash_backslash"),
      //	"Quoted backslash backslash" );
  
      //  deepEqual( Sizzle( "input[data-attr='\\5C\\\\']"), q("attrbad_backslash_backslash"),
      //	"Quoted backslash backslash (numeric escape)" );
      //  deepEqual( Sizzle( "input[data-attr='\\5C \\\\']"), q("attrbad_backslash_backslash"),
      //	"Quoted backslash backslash (numeric escape with trailing space)" );
      //  deepEqual( Sizzle( "input[data-attr='\\5C\t\\\\']"), q("attrbad_backslash_backslash"),
      //	"Quoted backslash backslash (numeric escape with trailing tab)" );
      //  deepEqual( Sizzle( "input[data-attr='\\04e00']"), q("attrbad_unicode"),
      //	"Long numeric escape (BMP)" );*/
      document.getElementById("attrbad_unicode").attribs["data-attr"] =
          "\uD834\uDF06A";
      // It was too much code to fix Safari 5.x Supplemental Plane crashes (see ba5f09fa404379a87370ec905ffa47f8ac40aaa3)
      deepEqual(
          Sizzle("input[data-attr='\\01D306A']"),
          q("attrbad_unicode"),
          "Long numeric escape (non-BMP)"
      );
  
      attrbad.remove();
  
      t("input[type=text]", "#form input[type=text]", [
          "text1",
          "text2",
          "hidden2",
          "name",
      ]);
      t("input[type=search]", "#form input[type=search]", ["search"]);
      t("script[src] (jQuery #13777)", "#moretests script[src]", ["script-src"]);
  
      // #3279
      let div = document.createElement("div");
      div.children = helper.getDOM("<div id='foo' xml:test='something'></div>");
  
      deepEqual(
          Sizzle("[xml\\:test]", div),
          [div.children[0]],
          "Finding by attribute with escaped characters."
      );
  
      div = document.getElementById("foo");
      t(
          'Object.prototype property "constructor" (negative)',
          "[constructor]",
          []
      );
      t('Gecko Object.prototype property "watch" (negative)', "[watch]", []);
      div.attribs.constructor = "foo";
      div.attribs.watch = "bar";
      t('Object.prototype property "constructor"', "[constructor='foo']", [
          "foo",
      ]);
      t('Gecko Object.prototype property "watch"', "[watch='bar']", ["foo"]);
  
      t("Value attribute is retrieved correctly", "input[value=Test]", [
          "text1",
          "text2",
      ]);
  });
  
  test("pseudo - (parent|empty)", () => {
      expect(3);
      t("Empty", "ul:empty", ["firstUL"]);
      t("Empty with comment node", "ol:empty", ["empty"]);
      t("Is A Parent", "#qunit-fixture p:parent", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
  });
  
  test("pseudo - (first|last|only)-(child|of-type)", () => {
      expect(12);
  
      t("First Child", "p:first-child", ["firstp", "sndp"]);
      t("First Child (leading id)", "#qunit-fixture p:first-child", [
          "firstp",
          "sndp",
      ]);
      t("First Child (leading class)", ".nothiddendiv div:first-child", [
          "nothiddendivchild",
      ]);
      t("First Child (case-insensitive)", "#qunit-fixture p:FIRST-CHILD", [
          "firstp",
          "sndp",
      ]);
  
      t("Last Child", "p:last-child", ["sap"]);
      t("Last Child (leading id)", "#qunit-fixture a:last-child", [
          "simon1",
          "anchor1",
          "mark",
          "yahoo",
          "anchor2",
          "simon",
          "liveLink1",
          "liveLink2",
      ]);
  
      t("Only Child", "#qunit-fixture a:only-child", [
          "simon1",
          "anchor1",
          "yahoo",
          "anchor2",
          "liveLink1",
          "liveLink2",
      ]);
  
      t("First-of-type", "#qunit-fixture > p:first-of-type", ["firstp"]);
      t("Last-of-type", "#qunit-fixture > p:last-of-type", ["first"]);
      t("Only-of-type", "#qunit-fixture > :only-of-type", [
          "name+value",
          "firstUL",
          "empty",
          "floatTest",
          "iframe",
          "table",
      ]);
  
      // Verify that the child position isn't being cached improperly
      const secondChildren = jQuery(Sizzle("p:nth-child(2)")).before(
          "<div></div>"
      );
  
      t("No longer second child", "p:nth-child(2)", []);
      secondChildren.prev().remove();
      t("Restored second child", "p:nth-child(2)", ["ap", "en"]);
  });
  
  test("pseudo - nth-child", () => {
      expect(30);
  
      t("Nth-child", "p:nth-child(1)", ["firstp", "sndp"]);
      t("Nth-child (with whitespace)", "p:nth-child( 1 )", ["firstp", "sndp"]);
      t("Nth-child (case-insensitive)", "#select1 option:NTH-child(3)", [
          "option1c",
      ]);
      t("Not nth-child", "#qunit-fixture p:not(:nth-child(1))", [
          "ap",
          "en",
          "sap",
          "first",
      ]);
  
      t("Nth-child(2)", "#qunit-fixture form#form > *:nth-child(2)", ["text1"]);
      t("Nth-child(2)", "#qunit-fixture form#form > :nth-child(2)", ["text1"]);
  
      t("Nth-child(-1)", "#select1 option:nth-child(-1)", []);
      t("Nth-child(3)", "#select1 option:nth-child(3)", ["option1c"]);
      //  t( "Nth-child(0n+3)", "#select1 option:nth-child(0n+3)", ["option1c"] );
      t("Nth-child(1n+0)", "#select1 option:nth-child(1n+0)", [
          "option1a",
          "option1b",
          "option1c",
          "option1d",
      ]);
      t("Nth-child(1n)", "#select1 option:nth-child(1n)", [
          "option1a",
          "option1b",
          "option1c",
          "option1d",
      ]);
      t("Nth-child(n)", "#select1 option:nth-child(n)", [
          "option1a",
          "option1b",
          "option1c",
          "option1d",
      ]);
      t("Nth-child(even)", "#select1 option:nth-child(even)", [
          "option1b",
          "option1d",
      ]);
      t("Nth-child(odd)", "#select1 option:nth-child(odd)", [
          "option1a",
          "option1c",
      ]);
      t("Nth-child(2n)", "#select1 option:nth-child(2n)", [
          "option1b",
          "option1d",
      ]);
      t("Nth-child(2n+1)", "#select1 option:nth-child(2n+1)", [
          "option1a",
          "option1c",
      ]);
      t("Nth-child(2n + 1)", "#select1 option:nth-child(2n + 1)", [
          "option1a",
          "option1c",
      ]);
      t("Nth-child(+2n + 1)", "#select1 option:nth-child(+2n + 1)", [
          "option1a",
          "option1c",
      ]);
      t("Nth-child(3n)", "#select1 option:nth-child(3n)", ["option1c"]);
      t("Nth-child(3n+1)", "#select1 option:nth-child(3n+1)", [
          "option1a",
          "option1d",
      ]);
      t("Nth-child(3n+2)", "#select1 option:nth-child(3n+2)", ["option1b"]);
      t("Nth-child(3n+3)", "#select1 option:nth-child(3n+3)", ["option1c"]);
      t("Nth-child(3n-1)", "#select1 option:nth-child(3n-1)", ["option1b"]);
      t("Nth-child(3n-2)", "#select1 option:nth-child(3n-2)", [
          "option1a",
          "option1d",
      ]);
      t("Nth-child(3n-3)", "#select1 option:nth-child(3n-3)", ["option1c"]);
      t("Nth-child(3n+0)", "#select1 option:nth-child(3n+0)", ["option1c"]);
      t("Nth-child(-1n+3)", "#select1 option:nth-child(-1n+3)", [
          "option1a",
          "option1b",
          "option1c",
      ]);
      t("Nth-child(-n+3)", "#select1 option:nth-child(-n+3)", [
          "option1a",
          "option1b",
          "option1c",
      ]);
      t("Nth-child(-1n + 3)", "#select1 option:nth-child(-1n + 3)", [
          "option1a",
          "option1b",
          "option1c",
      ]);
  
      //  deepEqual( Sizzle( ":nth-child(n)", null, null, [ document.createElement("a") ].concat( q("ap") ) ), q("ap"), "Seeded nth-child" );
  });
  
  test("pseudo - nth-last-child", () => {
      expect(30);
  
      t("Nth-last-child", "form:nth-last-child(5)", ["testForm"]);
      t("Nth-last-child (with whitespace)", "form:nth-last-child( 5 )", [
          "testForm",
      ]);
      t(
          "Nth-last-child (case-insensitive)",
          "#select1 option:NTH-last-child(3)",
          ["option1b"]
      );
      t("Not nth-last-child", "#qunit-fixture p:not(:nth-last-child(1))", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "first",
      ]);
  
      t("Nth-last-child(-1)", "#select1 option:nth-last-child(-1)", []);
      t("Nth-last-child(3)", "#select1 :nth-last-child(3)", ["option1b"]);
      t("Nth-last-child(3)", "#select1 *:nth-last-child(3)", ["option1b"]);
      t("Nth-last-child(3)", "#select1 option:nth-last-child(3)", ["option1b"]);
      //  t( "Nth-last-child(0n+3)", "#select1 option:nth-last-child(0n+3)", ["option1b"] );
      t("Nth-last-child(1n+0)", "#select1 option:nth-last-child(1n+0)", [
          "option1a",
          "option1b",
          "option1c",
          "option1d",
      ]);
      t("Nth-last-child(1n)", "#select1 option:nth-last-child(1n)", [
          "option1a",
          "option1b",
          "option1c",
          "option1d",
      ]);
      t("Nth-last-child(n)", "#select1 option:nth-last-child(n)", [
          "option1a",
          "option1b",
          "option1c",
          "option1d",
      ]);
      t("Nth-last-child(even)", "#select1 option:nth-last-child(even)", [
          "option1a",
          "option1c",
      ]);
      t("Nth-last-child(odd)", "#select1 option:nth-last-child(odd)", [
          "option1b",
          "option1d",
      ]);
      t("Nth-last-child(2n)", "#select1 option:nth-last-child(2n)", [
          "option1a",
          "option1c",
      ]);
      t("Nth-last-child(2n+1)", "#select1 option:nth-last-child(2n+1)", [
          "option1b",
          "option1d",
      ]);
      t("Nth-last-child(2n + 1)", "#select1 option:nth-last-child(2n + 1)", [
          "option1b",
          "option1d",
      ]);
      t("Nth-last-child(+2n + 1)", "#select1 option:nth-last-child(+2n + 1)", [
          "option1b",
          "option1d",
      ]);
      t("Nth-last-child(3n)", "#select1 option:nth-last-child(3n)", ["option1b"]);
      t("Nth-last-child(3n+1)", "#select1 option:nth-last-child(3n+1)", [
          "option1a",
          "option1d",
      ]);
      t("Nth-last-child(3n+2)", "#select1 option:nth-last-child(3n+2)", [
          "option1c",
      ]);
      t("Nth-last-child(3n+3)", "#select1 option:nth-last-child(3n+3)", [
          "option1b",
      ]);
      t("Nth-last-child(3n-1)", "#select1 option:nth-last-child(3n-1)", [
          "option1c",
      ]);
      t("Nth-last-child(3n-2)", "#select1 option:nth-last-child(3n-2)", [
          "option1a",
          "option1d",
      ]);
      t("Nth-last-child(3n-3)", "#select1 option:nth-last-child(3n-3)", [
          "option1b",
      ]);
      t("Nth-last-child(3n+0)", "#select1 option:nth-last-child(3n+0)", [
          "option1b",
      ]);
      t("Nth-last-child(-1n+3)", "#select1 option:nth-last-child(-1n+3)", [
          "option1b",
          "option1c",
          "option1d",
      ]);
      t("Nth-last-child(-n+3)", "#select1 option:nth-last-child(-n+3)", [
          "option1b",
          "option1c",
          "option1d",
      ]);
      t("Nth-last-child(-1n + 3)", "#select1 option:nth-last-child(-1n + 3)", [
          "option1b",
          "option1c",
          "option1d",
      ]);
  
      //  deepEqual( Sizzle( ":nth-last-child(n)", null, null, [ document.createElement("a") ].concat( q("ap") ) ), q("ap"), "Seeded nth-last-child" );
  });
  
  test("pseudo - nth-of-type", () => {
      expect(9);
      t("Nth-of-type(-1)", ":nth-of-type(-1)", []);
      t("Nth-of-type(3)", "#ap :nth-of-type(3)", ["mark"]);
      t("Nth-of-type(n)", "#ap :nth-of-type(n)", [
          "google",
          "groups",
          "code1",
          "anchor1",
          "mark",
      ]);
      t("Nth-of-type(0n+3)", "#ap :nth-of-type(0n+3)", ["mark"]);
      t("Nth-of-type(2n)", "#ap :nth-of-type(2n)", ["groups"]);
      t("Nth-of-type(even)", "#ap :nth-of-type(even)", ["groups"]);
      t("Nth-of-type(2n+1)", "#ap :nth-of-type(2n+1)", [
          "google",
          "code1",
          "anchor1",
          "mark",
      ]);
      t("Nth-of-type(odd)", "#ap :nth-of-type(odd)", [
          "google",
          "code1",
          "anchor1",
          "mark",
      ]);
      t("Nth-of-type(-n+2)", "#qunit-fixture > :nth-of-type(-n+2)", [
          "firstp",
          "ap",
          "foo",
          "nothiddendiv",
          "name+value",
          "firstUL",
          "empty",
          "form",
          "floatTest",
          "iframe",
          "lengthtest",
          "table",
      ]);
  });
  
  test("pseudo - nth-last-of-type", () => {
      expect(9);
      t("Nth-last-of-type(-1)", ":nth-last-of-type(-1)", []);
      t("Nth-last-of-type(3)", "#ap :nth-last-of-type(3)", ["google"]);
      t("Nth-last-of-type(n)", "#ap :nth-last-of-type(n)", [
          "google",
          "groups",
          "code1",
          "anchor1",
          "mark",
      ]);
      t("Nth-last-of-type(0n+3)", "#ap :nth-last-of-type(0n+3)", ["google"]);
      t("Nth-last-of-type(2n)", "#ap :nth-last-of-type(2n)", ["groups"]);
      t("Nth-last-of-type(even)", "#ap :nth-last-of-type(even)", ["groups"]);
      t("Nth-last-of-type(2n+1)", "#ap :nth-last-of-type(2n+1)", [
          "google",
          "code1",
          "anchor1",
          "mark",
      ]);
      t("Nth-last-of-type(odd)", "#ap :nth-last-of-type(odd)", [
          "google",
          "code1",
          "anchor1",
          "mark",
      ]);
      t("Nth-last-of-type(-n+2)", "#qunit-fixture > :nth-last-of-type(-n+2)", [
          "ap",
          "name+value",
          "first",
          "firstUL",
          "empty",
          "floatTest",
          "iframe",
          "table",
          "name-tests",
          "testForm",
          "liveHandlerOrder",
          "siblingTest",
      ]);
  });
  
  test("pseudo - has", () => {
      expect(3);
  
      t("Basic test", "p:has(a)", ["firstp", "ap", "en", "sap"]);
      t("Basic test (irrelevant whitespace)", "p:has( a )", [
          "firstp",
          "ap",
          "en",
          "sap",
      ]);
      t(
          "Nested with overlapping candidates",
          "#qunit-fixture div:has(div:has(div:not([id])))",
          ["moretests", "t2037"]
      );
  });
  
  test("pseudo - misc", () => {
      expect(39);
  
      t("Headers", ":header", [
          "qunit-header",
          "qunit-banner",
          "qunit-userAgent",
      ]);
      t("Headers(case-insensitive)", ":Header", [
          "qunit-header",
          "qunit-banner",
          "qunit-userAgent",
      ]);
      t(
          "Multiple matches with the same context (cache check)",
          "#form select:has(option:first-child:contains('o'))",
          ["select1", "select2", "select3", "select4"]
      );
  
      ok(
          Sizzle("#qunit-fixture :not(:has(:has(*)))").length,
          "All not grandparents"
      );
  
      const select = document.getElementById("select1");
      ok(Sizzle.matchesSelector(select, ":has(option)"), "Has Option Matches");
  
      ok(Sizzle("a:contains('')").length, "Empty string contains");
      t("Text Contains", "a:contains(Google)", ["google", "groups"]);
      t("Text Contains", "a:contains(Google Groups)", ["groups"]);
  
      t("Text Contains", "a:contains('Google Groups (Link)')", ["groups"]);
      t("Text Contains", 'a:contains("(Link)")', ["groups"]);
      t("Text Contains", "a:contains(Google Groups (Link))", ["groups"]);
      t("Text Contains", "a:contains((Link))", ["groups"]);
  
      let tmp = document.createElement("div");
      tmp.attribs.id = "tmp_input";
      document.body.children.push(tmp);
  
      ["button", "submit", "reset"].forEach((type) => {
          const els = jQuery(
              "<input id='input_%' type='%'/><button id='button_%' type='%'>test</button>".replace(
                  /%/g,
                  type
              )
          ).appendTo(tmp);
  
          t(`Input Buttons :${type}`, `#tmp_input :${type}`, [
              `input_${type}`,
              `button_${type}`,
          ]);
  
          ok(
              Sizzle.matchesSelector(els[0], `:${type}`),
              `Input Matches :${type}`
          );
          ok(
              Sizzle.matchesSelector(els[1], `:${type}`),
              `Button Matches :${type}`
          );
      });
  
      document.body.children.pop();
  
      // Recreate tmp
      tmp = document.createElement("div");
      tmp.attribs.id = "tmp_input";
      tmp.children = helper.getDOM("<span>Hello I am focusable.</span>");
      // Setting tabIndex should make the element focusable
      // http://dev.w3.org/html5/spec/single-page.html#focus-management
      document.body.children.push(tmp);
      tmp.tabIndex = 0;
      //tmp.focus();
      if (
          document.activeElement !== tmp ||
          (document.hasFocus && !document.hasFocus()) ||
          (document.querySelectorAll &&
              !document.querySelectorAll("div:focus").length)
      ) {
          ok(true, "The div was not focused. Skip checking the :focus match.");
          ok(true, "The div was not focused. Skip checking the :focus match.");
      } else {
          t("tabIndex element focused", ":focus", ["tmp_input"]);
          ok(
              Sizzle.matchesSelector(tmp, ":focus"),
              ":focus matches tabIndex div"
          );
      }
  
      // Blur tmp
      //tmp.blur();
      //document.body.focus();
      //ok( !Sizzle.matchesSelector( tmp, ":focus" ), ":focus doesn't match tabIndex div" );
      document.body.children.pop();
  
      // Input focus/active
      const input = document.createElement("input");
      input.attribs.type = "text";
      input.attribs.id = "focus-input";
  
      document.body.children.push(input);
      //input.focus();
  
      // Inputs can't be focused unless the document has focus
      if (
          document.activeElement !== input ||
          (document.hasFocus && !document.hasFocus()) ||
          (document.querySelectorAll &&
              !document.querySelectorAll("input:focus").length)
      ) {
          ok(true, "The input was not focused. Skip checking the :focus match.");
          ok(true, "The input was not focused. Skip checking the :focus match.");
      } else {
          t("Element focused", "input:focus", ["focus-input"]);
          ok(Sizzle.matchesSelector(input, ":focus"), ":focus matches");
      }
  
      //input.blur();
  
      // When IE is out of focus, blur does not work. Force it here.
      if (document.activeElement === input) {
          document.body.focus();
      }
  
      //ok( !Sizzle.matchesSelector( input, ":focus" ), ":focus doesn't match" );
      document.body.children.pop();
  
      deepEqual(
          Sizzle(
              "[id='select1'] *:not(:last-child), [id='select2'] *:not(:last-child)",
              q("qunit-fixture")[0]
          ),
          q(
              "option1a",
              "option1b",
              "option1c",
              "option2a",
              "option2b",
              "option2c"
          ),
          "caching system tolerates recursive selection"
      );
  
      // Tokenization edge cases
      t("Sequential pseudos", "#qunit-fixture p:has(:contains(mark)):has(code)", [
          "ap",
      ]);
      t(
          "Sequential pseudos",
          "#qunit-fixture p:has(:contains(mark)):has(code):contains(This link)",
          ["ap"]
      );
  
      t("Pseudo argument containing ')'", "p:has(>a.GROUPS[src!=')'])", ["ap"]);
      t("Pseudo argument containing ')'", "p:has(>a.GROUPS[src!=')'])", ["ap"]);
      t(
          "Pseudo followed by token containing ')'",
          'p:contains(id="foo")[id!=\\)]',
          ["sndp"]
      );
      t(
          "Pseudo followed by token containing ')'",
          "p:contains(id=\"foo\")[id!=')']",
          ["sndp"]
      );
  
      t("Multi-pseudo", "#ap:has(*), #ap:has(*)", ["ap"]);
      //t( "Multi-positional", "#ap:gt(0), #ap:lt(1)", ["ap"] );
      t(
          "Multi-pseudo with leading nonexistent id",
          "#nonexistent:has(*), #ap:has(*)",
          ["ap"]
      );
      //t( "Multi-positional with leading nonexistent id", "#nonexistent:gt(0), #ap:lt(1)", ["ap"] );
  
      t(
          "Tokenization stressor",
          "a[class*=blog]:not(:has(*, :contains(!)), :contains(!)), br:contains(]), p:contains(]), :not(:empty):not(:parent)",
          ["ap", "mark", "yahoo", "simon"]
      );
  });
  
  test("pseudo - :not", () => {
      expect(43);
  
      t("Not", "a.blog:not(.link)", ["mark"]);
      //t( ":not() with :first", "#foo p:not(:first) .link", ["simon"] );
  
      t(
          "Not - multiple",
          "#form option:not(:contains(Nothing),#option1b,:selected)",
          [
              "option1c",
              "option1d",
              "option2b",
              "option2c",
              "option3d",
              "option3e",
              "option4e",
              "option5b",
              "option5c",
          ]
      );
      t("Not - recursive", "#form option:not(:not(:selected))[id^='option3']", [
          "option3b",
          "option3c",
      ]);
  
      t(":not() failing interior", "#qunit-fixture p:not(.foo)", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t(":not() failing interior", "#qunit-fixture p:not(div.foo)", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t(":not() failing interior", "#qunit-fixture p:not(p.foo)", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t(":not() failing interior", "#qunit-fixture p:not(#blargh)", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t(":not() failing interior", "#qunit-fixture p:not(div#blargh)", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t(":not() failing interior", "#qunit-fixture p:not(p#blargh)", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
  
      t(":not Multiple", "#qunit-fixture p:not(a)", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t(":not Multiple", "#qunit-fixture p:not( a )", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t(":not Multiple", "#qunit-fixture p:not( p )", []);
      t(":not Multiple", "#qunit-fixture p:not(a, b)", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t(":not Multiple", "#qunit-fixture p:not(a, b, div)", [
          "firstp",
          "ap",
          "sndp",
          "en",
          "sap",
          "first",
      ]);
      t(":not Multiple", "p:not(p)", []);
      t(":not Multiple", "p:not(a,p)", []);
      t(":not Multiple", "p:not(p,a)", []);
      t(":not Multiple", "p:not(a,p,b)", []);
      t(":not Multiple", ":input:not(:image,:input,:submit)", []);
      t(":not Multiple", "#qunit-fixture p:not(:has(a), :nth-child(1))", [
          "first",
      ]);
  
      t("No element not selector", ".container div:not(.excluded) div", []);
  
      t(":not() Existing attribute", "#form select:not([multiple])", [
          "select1",
          "select2",
          "select5",
      ]);
      t(":not() Equals attribute", "#form select:not([name=select1])", [
          "select2",
          "select3",
          "select4",
          "select5",
      ]);
      t(":not() Equals quoted attribute", "#form select:not([name='select1'])", [
          "select2",
          "select3",
          "select4",
          "select5",
      ]);
  
      t(":not() Multiple Class", "#foo a:not(.blog)", ["yahoo", "anchor2"]);
      t(":not() Multiple Class", "#foo a:not(.link)", ["yahoo", "anchor2"]);
      t(":not() Multiple Class", "#foo a:not(.blog.link)", ["yahoo", "anchor2"]);
  
      t(
          ":not chaining (compound)",
          "#qunit-fixture div[id]:not(:has(div, span)):not(:has(*))",
          ["nothiddendivchild", "divWithNoTabIndex"]
      );
      t(
          ":not chaining (with attribute)",
          "#qunit-fixture form[id]:not([action$='formaction']):not(:button)",
          ["lengthtest", "name-tests", "testForm"]
      );
      t(
          ":not chaining (colon in attribute)",
          "#qunit-fixture form[id]:not([action='form:action']):not(:button)",
          ["form", "lengthtest", "name-tests", "testForm"]
      );
      t(
          ":not chaining (colon in attribute and nested chaining)",
          "#qunit-fixture form[id]:not([action='form:action']:button):not(:input)",
          ["form", "lengthtest", "name-tests", "testForm"]
      );
      t(
          ":not chaining",
          "#form select:not(.select1):contains(Nothing) > option:not(option)",
          []
      );
  
      /*
  	t( "positional :not()", "#foo p:not(:last)", ["sndp", "en"] );
  	t( "positional :not() prefix", "#foo p:not(:last) a", ["yahoo"] );
  	t( "compound positional :not()", "#foo p:not(:first, :last)", ["en"] );
  	t( "compound positional :not()", "#foo p:not(:first, :even)", ["en"] );
  	t( "compound positional :not()", "#foo p:not(:first, :odd)", ["sap"] );
  	t( "reordered compound positional :not()", "#foo p:not(:odd, :first)", ["sap"] );
  
  	t( "positional :not() with pre-filter", "#foo p:not([id]:first)", ["en", "sap"] );
  	t( "positional :not() with post-filter", "#foo p:not(:first[id])", ["en", "sap"] );
  	t( "positional :not() with pre-filter", "#foo p:not([lang]:first)", ["sndp", "sap"] );
  	t( "positional :not() with post-filter", "#foo p:not(:first[lang])", ["sndp", "en", "sap"] );
  	*/
  });
  
  /*
  test("pseudo - position", function() {
  	expect( 33 );
  
  	t( "First element", "div:first", ["qunit"] );
  	t( "First element(case-insensitive)", "div:fiRst", ["qunit"] );
  	t( "nth Element", "#qunit-fixture p:nth(1)", ["ap"] );
  	t( "First Element", "#qunit-fixture p:first", ["firstp"] );
  	t( "Last Element", "p:last", ["first"] );
  	t( "Even Elements", "#qunit-fixture p:even", ["firstp","sndp","sap"] );
  	t( "Odd Elements", "#qunit-fixture p:odd", ["ap","en","first"] );
  	t( "Position Equals", "#qunit-fixture p:eq(1)", ["ap"] );
  	t( "Position Equals (negative)", "#qunit-fixture p:eq(-1)", ["first"] );
  	t( "Position Greater Than", "#qunit-fixture p:gt(0)", ["ap","sndp","en","sap","first"] );
  	t( "Position Less Than", "#qunit-fixture p:lt(3)", ["firstp","ap","sndp"] );
  
  	t( "Check position filtering", "div#nothiddendiv:eq(0)", ["nothiddendiv"] );
  	t( "Check position filtering", "div#nothiddendiv:last", ["nothiddendiv"] );
  	t( "Check position filtering", "div#nothiddendiv:not(:gt(0))", ["nothiddendiv"] );
  	t( "Check position filtering", "#foo > :not(:first)", ["en", "sap"] );
  	t( "Check position filtering", "#qunit-fixture select > :not(:gt(2))", ["option1a", "option1b", "option1c"] );
  	t( "Check position filtering", "#qunit-fixture select:lt(2) :not(:first)", ["option1b", "option1c", "option1d", "option2a", "option2b", "option2c", "option2d"] );
  	t( "Check position filtering", "div.nothiddendiv:eq(0)", ["nothiddendiv"] );
  	t( "Check position filtering", "div.nothiddendiv:last", ["nothiddendiv"] );
  	t( "Check position filtering", "div.nothiddendiv:not(:lt(0))", ["nothiddendiv"] );
  
  	t( "Check element position", "#qunit-fixture div div:eq(0)", ["nothiddendivchild"] );
  	t( "Check element position", "#select1 option:eq(3)", ["option1d"] );
  	t( "Check element position", "#qunit-fixture div div:eq(10)", ["names-group"] );
  	t( "Check element position", "#qunit-fixture div div:first", ["nothiddendivchild"] );
  	t( "Check element position", "#qunit-fixture div > div:first", ["nothiddendivchild"] );
  	t( "Check element position", "#dl div:first div:first", ["foo"] );
  	t( "Check element position", "#dl div:first > div:first", ["foo"] );
  	t( "Check element position", "div#nothiddendiv:first > div:first", ["nothiddendivchild"] );
  	t( "Chained pseudo after a pos pseudo", "#listWithTabIndex li:eq(0):contains(Rice)", ["foodWithNegativeTabIndex"] );
  
  	t( "Check sort order with POS and comma", "#qunit-fixture em>em>em>em:first-child,div>em:first", ["siblingfirst", "siblinggreatgrandchild"] );
  
  	t( "Isolated position", ":last", ["last"] );
  
  	deepEqual( Sizzle( "*:lt(2) + *", null, [], Sizzle("#qunit-fixture > p") ), q("ap"), "Seeded pos with trailing relative" );
  
  	// jQuery #12526
  	var context = jQuery("#qunit-fixture").append("<div id='jquery12526'></div>")[0];
  	deepEqual( Sizzle( ":last", context ), q("jquery12526"), "Post-manipulation positional" );
  });
  */
  
  test("pseudo - form", () => {
      expect(10);
  
      const extraTexts = jQuery(
          '<input id="impliedText"/><input id="capitalText" type="TEXT">'
      ).appendTo("#form");
  
      t("Form element :input", "#form :input", [
          "text1",
          "text2",
          "radio1",
          "radio2",
          "check1",
          "check2",
          "hidden1",
          "hidden2",
          "name",
          "search",
          "button",
          "area1",
          "select1",
          "select2",
          "select3",
          "select4",
          "select5",
          "impliedText",
          "capitalText",
      ]);
      t("Form element :radio", "#form :radio", ["radio1", "radio2"]);
      t("Form element :checkbox", "#form :checkbox", ["check1", "check2"]);
      t("Form element :text", "#form :text", [
          "text1",
          "text2",
          "hidden2",
          "name",
          "impliedText",
          "capitalText",
      ]);
      t("Form element :radio:checked", "#form :radio:checked", ["radio2"]);
      t("Form element :checkbox:checked", "#form :checkbox:checked", ["check1"]);
      t(
          "Form element :radio:checked, :checkbox:checked",
          "#form :radio:checked, #form :checkbox:checked",
          ["radio2", "check1"]
      );
  
      t("Selected Option Element", "#form option:selected", [
          "option1a",
          "option2d",
          "option3b",
          "option3c",
          "option4b",
          "option4c",
          "option4d",
          "option5a",
      ]);
      t("Selected Option Element are also :checked", "#form option:checked", [
          "option1a",
          "option2d",
          "option3b",
          "option3c",
          "option4b",
          "option4c",
          "option4d",
          "option5a",
      ]);
      t(
          "Hidden inputs should be treated as enabled. See QSA test.",
          "#hidden1:enabled",
          ["hidden1"]
      );
  
      extraTexts.remove();
  });
  
  test("pseudo - :target and :root", () => {
      expect(2);
      /* // TODO add shim from qwery tests
  	// Target
  	var oldHash,
  	$link = jQuery("<a/>").attr({
  		href: "#",
  		id: "new-link"
  	}).appendTo("#qunit-fixture");
  
  	oldHash = window.location.hash;
  	window.location.hash = "new-link";
  
  	t( ":target", ":target", ["new-link"] );
  
  	$link.remove();
  	window.location.hash = oldHash;*/
  
      // Root
      equal(Sizzle(":root")[0], document.documentElement, ":root selector");
  });
  
  /*
  // TODO
  test("pseudo - :lang", function() {
  	expect( 105 );
  
  	var docElem = document.documentElement,
  		docXmlLang = docElem.getAttribute("xml:lang"),
  		docLang = docElem.lang,
  		foo = document.getElementById("foo"),
  		anchor = document.getElementById("anchor2"),
  		xml = createWithFriesXML(),
  		testLang = function( text, elem, container, lang, extra ) {
  			var message,
  				full = lang + "-" + extra;
  
  			message = "lang=" + lang + " " + text;
  			container.setAttribute( container.ownerDocument.documentElement.nodeName === "HTML" ? "lang" : "xml:lang", lang );
  			assertMatch( message, elem, ":lang(" + lang + ")" );
  			assertMatch( message, elem, ":lang(" + mixCase(lang) + ")" );
  			assertNoMatch( message, elem, ":lang(" + full + ")" );
  			assertNoMatch( message, elem, ":lang(" + mixCase(full) + ")" );
  			assertNoMatch( message, elem, ":lang(" + lang + "-)" );
  			assertNoMatch( message, elem, ":lang(" + full + "-)" );
  			assertNoMatch( message, elem, ":lang(" + lang + "glish)" );
  			assertNoMatch( message, elem, ":lang(" + full + "glish)" );
  
  			message = "lang=" + full + " " + text;
  			container.setAttribute( container.ownerDocument.documentElement.nodeName === "HTML" ? "lang" : "xml:lang", full );
  			assertMatch( message, elem, ":lang(" + lang + ")" );
  			assertMatch( message, elem, ":lang(" + mixCase(lang) + ")" );
  			assertMatch( message, elem, ":lang(" + full + ")" );
  			assertMatch( message, elem, ":lang(" + mixCase(full) + ")" );
  			assertNoMatch( message, elem, ":lang(" + lang + "-)" );
  			assertNoMatch( message, elem, ":lang(" + full + "-)" );
  			assertNoMatch( message, elem, ":lang(" + lang + "glish)" );
  			assertNoMatch( message, elem, ":lang(" + full + "glish)" );
  		},
  		mixCase = function( str ) {
  			var ret = str.split(""),
  				i = ret.length;
  			while ( i-- ) {
  				if ( i & 1 ) {
  					ret[i] = ret[i].toUpperCase();
  				}
  			}
  			return ret.join("");
  		},
  		assertMatch = function( text, elem, selector ) {
  			ok( Sizzle.matchesSelector( elem, selector ), text + " match " + selector );
  		},
  		assertNoMatch = function( text, elem, selector ) {
  			ok( !Sizzle.matchesSelector( elem, selector ), text + " fail " + selector );
  		};
  
  	// Prefixing and inheritance
  	ok( Sizzle.matchesSelector( docElem, ":lang(" + docElem.lang + ")" ), "starting :lang" );
  	testLang( "document", anchor, docElem, "en", "us" );
  	testLang( "grandparent", anchor, anchor.parentNode.parentNode, "yue", "hk" );
  	ok( !Sizzle.matchesSelector( anchor, ":lang(en), :lang(en-us)" ),
  		":lang does not look above an ancestor with specified lang" );
  	testLang( "self", anchor, anchor, "es", "419" );
  	ok( !Sizzle.matchesSelector( anchor, ":lang(en), :lang(en-us), :lang(yue), :lang(yue-hk)" ),
  		":lang does not look above self with specified lang" );
  
  	// Searching by language tag
  	anchor.parentNode.parentNode.lang = "arab";
  	anchor.parentNode.lang = anchor.parentNode.id = "ara-sa";
  	anchor.lang = "ara";
  	deepEqual( Sizzle( ":lang(ara)", foo ), [ anchor.parentNode, anchor ], "Find by :lang" );
  
  	// Selector validity
  	anchor.parentNode.lang = "ara";
  	anchor.lang = "ara\\b";
  	deepEqual( Sizzle( ":lang(ara\\b)", foo ), [], ":lang respects backslashes" );
  	deepEqual( Sizzle( ":lang(ara\\\\b)", foo ), [ anchor ], ":lang respects escaped backslashes" );
  	raises(function() {
  		Sizzle.call( null, "dl:lang(c++)" );
  	}, function( e ) {
  		return e.message.indexOf("Syntax error") >= 0;
  	}, ":lang value must be a valid identifier" );
  
  	// XML
  	foo = jQuery( "response", xml )[0];
  	anchor = jQuery( "#seite1", xml )[0];
  	testLang( "XML document", anchor, xml.documentElement, "en", "us" );
  	testLang( "XML grandparent", anchor, foo, "yue", "hk" );
  	ok( !Sizzle.matchesSelector( anchor, ":lang(en), :lang(en-us)" ),
  		"XML :lang does not look above an ancestor with specified lang" );
  	testLang( "XML self", anchor, anchor, "es", "419" );
  	ok( !Sizzle.matchesSelector( anchor, ":lang(en), :lang(en-us), :lang(yue), :lang(yue-hk)" ),
  		"XML :lang does not look above self with specified lang" );
  
  	// Cleanup
  	if ( docXmlLang == null ) {
  		docElem.removeAttribute("xml:lang");
  	} else {
  		docElem.setAttribute( "xml:lang", docXmlLang );
  	}
  	docElem.lang = docLang;
  });
  */
  
  test("caching", () => {
      expect(1);
      Sizzle(":not(code)", document.getElementById("ap"));
      deepEqual(
          Sizzle(":not(code)", document.getElementById("foo")),
          q("sndp", "en", "yahoo", "sap", "anchor2", "simon"),
          "Reusing selector with new context"
      );
  });
  /*
  asyncTest( "Iframe dispatch should not affect Sizzle, see jQuery #13936", 1, function() {
  	var i = 0,
  		thrown = false,
  		iframe = document.getElementById("iframe"),
  		iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
  
  	jQuery( iframe ).on( "load", function() {
  		var doc;
  
  		try {
  			i++;
  			doc = this.contentDocument || this.contentWindow.document;
  			Sizzle( "form", doc ).pop().submit();
  
  		} catch ( e ) {
  			thrown = true;
  		}
  
  		if ( i === 2 ) {
  			jQuery( this ).off("load");
  			ok( !thrown, "Iframe reload should not affect Sizzle, see jQuery #13936" );
  			start();
  		}
  	});
  
  	iframeDoc.open();
  	iframeDoc.write("<body><form></form></body>");
  	iframeDoc.close();
  });
  */
  