<!DOCTYPE HTML>
<meta charset="UTF-8">
<title>CSS Toggles: creation of toggles</title>
<link rel="author" title="L. David Baron" href="https://dbaron.org/">
<link rel="author" title="Google" href="http://www.google.com/">
<link rel="help" href="https://tabatkins.github.io/css-toggle/#checked-pseudoclass">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../support/parsing-testcommon.js"></script>
<script src="support/toggle-helpers.js"></script>

<body>

<div id="container"></div>

<script>

test_valid_selector(":toggle(my-toggle)");
test_valid_selector(":toggle(my-toggle 0)");
test_valid_selector(":toggle(my-toggle 1)");
test_valid_selector(":toggle( my-toggle 1 )", ":toggle(my-toggle 1)");
test_valid_selector(":toggle(my-toggle named-state)");
test_valid_selector(":toggle( my-toggle named-state )", ":toggle(my-toggle named-state)");
test_invalid_selector(":toggle(my-toggle, 0)");
test_invalid_selector(":toggle(my-toggle, named-state)");
test_invalid_selector(":toggle(my-toggle named-state 0)");

// In these tests, the following class attributes lead to markup creation:
// class=toggle, class=toggle-self, class=variant-toggle,
// class=variant-toggle-self.  These all lead to the creation of a toggle
// called "markup-test".  If "-self" is present then the toggle has narrow
// scope (otherwise wide scope).  If "variant-" is present then the toggle has
// a value different from what the primary test assertions target (otherwise
// it is what the test assertions target).
//
// The following class attributes lead to test assertions:
//   class=assert-match: Assert the :toggle() selector matches the toggle
//   class=assert-no-match: Assert the :toggle() selector does not match the
//     toggle.
//   class=assert-variant-match: Assert the :toggle() selector matches the
//     variant toggle.
let scope_search_tests = [
  `
    <div>
      <div class="assert-no-match"></div>
      <div class="toggle assert-match">
        <div class="assert-match"></div>
      </div>
      <div class="assert-match"></div>
    </div>
    <div class="assert-no-match"></div>
  `,
  `
    <div>
      <div class="assert-no-match"></div>
      <div class="toggle-self assert-match">
        <div class="assert-match"></div>
      </div>
      <div class="assert-no-match"></div>
    </div>
    <div class="assert-no-match"></div>
  `,
  `
    <div class="toggle"></div>
    <div class="variant-toggle-self">
      <div class="assert-variant-match"></div>
    </div>
    <div class="assert-match"></div>
  `,
  `
    <div class="toggle"></div>
    <div class="assert-match"></div>
    <div class="variant-toggle">
      <div class="assert-variant-match"></div>
    </div>
    <div class="assert-variant-match"></div>
  `,
];

for (let t of scope_search_tests) {
  promise_test(async function() {
    container.innerHTML = t;
    for (let e of container.querySelectorAll(".toggle")) {
      e.style.toggleRoot = "scope-test 10 at 3";
    }
    for (let e of container.querySelectorAll(".toggle-self")) {
      e.style.toggleRoot = "scope-test 10 at 3 self";
    }
    for (let e of container.querySelectorAll(".variant-toggle")) {
      e.style.toggleRoot = "scope-test 10 at 8";
    }
    for (let e of container.querySelectorAll(".variant-toggle-self")) {
      e.style.toggleRoot = "scope-test 10 at 8 self";
    }
    for (let e of container.querySelectorAll(
           ".toggle, .toggle-self, .variant-toggle, .variant-toggle-self")) {
      await wait_for_toggle_creation(e);
    }

    let assert_match = (e, selector) => {
      assert_true(e.matches(selector),
                  `matches ${selector} (class ${e.className})`);
    };
    let assert_nomatch = (e, selector) => {
      assert_false(e.matches(selector),
                   `does not match ${selector} (class ${e.className})`);
    };
    for (let e of container.querySelectorAll(".assert-match")) {
      assert_match(e, ":toggle(scope-test)");
      assert_match(e, ":toggle(scope-test 3)");
      assert_nomatch(e, ":toggle(scope-test 8)");
    }
    for (let e of container.querySelectorAll(".assert-variant-match")) {
      assert_match(e, ":toggle(scope-test)");
      assert_nomatch(e, ":toggle(scope-test 3)");
      assert_match(e, ":toggle(scope-test 8)");
    }
    for (let e of container.querySelectorAll(".assert-no-match")) {
      assert_nomatch(e, ":toggle(scope-test)");
      assert_nomatch(e, ":toggle(scope-test 3)");
      assert_nomatch(e, ":toggle(scope-test 8)");
    }
  }, `scope search test for markup ${t}`);
}

let selector_match_tests = [
  {
    specifier: [ "my-toggle 2 at 1" ],
    matching_selectors: [
      ":toggle(my-toggle)",
      ":toggle(my-toggle 1)",
    ],
    not_matching_selectors: [
      ":toggle(my-toggle 0)",
      ":toggle(my-toggle 2)",
      ":toggle(my-toggle named-state)",
    ],
  },
  {
    specifier: [ "my-toggle 2 at 0" ],
    matching_selectors: [
      ":toggle(my-toggle 0)",
    ],
    not_matching_selectors: [
      ":toggle(my-toggle)",
      ":toggle(my-toggle 1)",
      ":toggle(my-toggle 2)",
      ":toggle(my-toggle named-state)",
    ],
  },
  {
    specifier: [ "my-toggle 2 at named-state" ],
    matching_selectors: [
      ":toggle(my-toggle)",
      ":toggle(my-toggle named-state)",
    ],
    not_matching_selectors: [
      ":toggle(my-toggle 0)",
      ":toggle(my-toggle 1)",
      ":toggle(my-toggle 2)",
      ":toggle(my-toggle infinite)",
      ":toggle(my-toggle infinity)",
    ],
  },
  {
    specifier: [
      "my-toggle [a b c d] at 0",
      "my-toggle [a b c d] at a",
    ],
    matching_selectors: [
      ":toggle(my-toggle 0)",
      ":toggle(my-toggle a)",
    ],
    not_matching_selectors: [
      ":toggle(my-toggle)",
      ":toggle(my-toggle 1)",
      ":toggle(my-toggle 2)",
      ":toggle(my-toggle b)",
      ":toggle(my-toggle d)",
      ":toggle(my-toggle named-state)",
    ],
  },
  {
    specifier: [
      "my-toggle [a b c d] at 1",
      "my-toggle [a b c d] at b",
    ],
    matching_selectors: [
      ":toggle(my-toggle)",
      ":toggle(my-toggle 1)",
      ":toggle(my-toggle b)",
    ],
    not_matching_selectors: [
      ":toggle(my-toggle 0)",
      ":toggle(my-toggle a)",
      ":toggle(my-toggle 2)",
      ":toggle(my-toggle d)",
      ":toggle(my-toggle named-state)",
    ],
  },
  {
    specifier: [
      "my-toggle [a b c d] at unnamed-state",
    ],
    matching_selectors: [
      ":toggle(my-toggle)",
      ":toggle(my-toggle unnamed-state)",
    ],
    not_matching_selectors: [
      ":toggle(my-toggle 0)",
      ":toggle(my-toggle a)",
      ":toggle(my-toggle 1)",
      ":toggle(my-toggle c)",
      ":toggle(my-toggle 3)",
    ],
  },
];

for (let t of selector_match_tests) {
  for (let specifier of t.specifier) {
    promise_test(async function() {
      container.innerHTML = `<div style="toggle-root: ${specifier}"></div>`;
      let e = container.firstChild;
      await wait_for_toggle_creation(e);
      for (let sel of t.matching_selectors) {
        assert_true(e.matches(sel), `${sel} matches`);
      }
      for (let sel of t.not_matching_selectors) {
        assert_false(e.matches(sel), `${sel} does not match`);
      }
    }, `:toggle() selector matching tests for ${specifier}`);
  }
}

</script>
