/// Test for the Selectors API ported from
/// <https://github.com/w3c/web-platform-tests/tree/master/selectors-api>
library;

// Bit-mapped flags to indicate which tests the selector is suitable for
final int testQsaBaseline =
    0x01; // querySelector() and querySelectorAll() baseline tests
final int testQsaAdditional =
    0x02; // querySelector() and querySelectorAll() additional tests
final int testFindBaseline =
    0x04; // find() and findAll() baseline tests, may be unsuitable for querySelector[All]
final int testFindAdditional =
    0x08; // find() and findAll() additional tests, may be unsuitable for querySelector[All]
final int testMatchBaseline = 0x10; // matches() baseline tests
int testMatchAdditional = 0x20; // matches() additional tests

/*
 * All of these invalid selectors should result in a SyntaxError being thrown by the APIs.
 *
 *   name:     A descriptive name of the selector being tested
 *   selector: The selector to test
 */
final invalidSelectors = [
  {'name': 'Empty String', 'selector': ''},
  {'name': 'Invalid character', 'selector': '['},
  {'name': 'Invalid character', 'selector': ']'},
  {'name': 'Invalid character', 'selector': '('},
  {'name': 'Invalid character', 'selector': ')'},
  {'name': 'Invalid character', 'selector': '{'},
  {'name': 'Invalid character', 'selector': '}'},
  {'name': 'Invalid character', 'selector': '<'},
  {'name': 'Invalid character', 'selector': '>'},
  {'name': 'Invalid ID', 'selector': '#'},
  {'name': 'Invalid group of selectors', 'selector': 'div,'},
  {'name': 'Invalid class', 'selector': '.'},
  {'name': 'Invalid class', 'selector': '.5cm'},
  {'name': 'Invalid class', 'selector': '..test'},
  {'name': 'Invalid class', 'selector': '.foo..quux'},
  {'name': 'Invalid class', 'selector': '.bar.'},
  {'name': 'Invalid combinator', 'selector': 'div & address, p'},
  {'name': 'Invalid combinator', 'selector': 'div >> address, p'},
  {'name': 'Invalid combinator', 'selector': 'div ++ address, p'},
  {'name': 'Invalid combinator', 'selector': 'div ~~ address, p'},
  {'name': 'Invalid [att=value] selector', 'selector': '[*=test]'},
  {'name': 'Invalid [att=value] selector', 'selector': '[*|*=test]'},
  {
    'name': 'Invalid [att=value] selector',
    'selector': '[class= space unquoted ]'
  },
  {'name': 'Unknown pseudo-class', 'selector': 'div:example'},
  {'name': 'Unknown pseudo-class', 'selector': ':example'},
  {'name': 'Unknown pseudo-element', 'selector': 'div::example'},
  {'name': 'Unknown pseudo-element', 'selector': '::example'},
  {'name': 'Invalid pseudo-element', 'selector': ':::before'},
  {'name': 'Undeclared namespace', 'selector': 'ns|div'},
  {'name': 'Undeclared namespace', 'selector': ':not(ns|div)'},
  {'name': 'Invalid namespace', 'selector': '^|div'},
  {'name': 'Invalid namespace', 'selector': '\$|div'}
];

/*
 * All of these should be valid selectors, expected to match zero or more elements in the document.
 * None should throw any errors.
 *
 *   name:     A descriptive name of the selector being tested
 *   selector: The selector to test
 *   'expect':   A list of IDs of the elements expected to be matched. List must be given in tree order.
 *   'exclude':  An array of contexts to exclude from testing. The valid values are:
 *             ["document", "element", "fragment", "detached", "html", "xhtml"]
 *             The "html" and "xhtml" values represent the type of document being queried. These are useful
 *             for tests that are affected by differences between HTML and XML, such as case sensitivity.
 *   'level':    An integer indicating the CSS or Selectors level in which the selector being tested was introduced.
 *   'testType': A bit-mapped flag indicating the type of test.
 *
 * Note: Interactive pseudo-classes (:active :hover and :focus) have not been tested in this test suite.
 */
final List<Map<String, dynamic>> validSelectors = [
  // Type Selector
  {
    'name': 'Type selector, matching html element',
    'selector': 'html',
    'expect': ['html'],
    'exclude': ['element', 'fragment', 'detached'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'Type selector, matching html element',
    'selector': 'html',
    'expect': <String>[] /*no matches*/,
    'exclude': ['document'],
    'level': 1,
    'testType': testQsaBaseline
  },
  {
    'name': 'Type selector, matching body element',
    'selector': 'body',
    'expect': ['body'],
    'exclude': ['element', 'fragment', 'detached'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'Type selector, matching body element',
    'selector': 'body',
    'expect': <String>[] /*no matches*/,
    'exclude': ['document'],
    'level': 1,
    'testType': testQsaBaseline
  },

  // Universal Selector
  // Testing "*" for entire an entire context node is handled separately.
  {
    'name':
        'Universal selector, matching all children of element with specified ID',
    'selector': '#universal>*',
    'expect': [
      'universal-p1',
      'universal-hr1',
      'universal-pre1',
      'universal-p2',
      'universal-address1'
    ],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Universal selector, matching all grandchildren of element with specified ID',
    'selector': '#universal>*>*',
    'expect': [
      'universal-code1',
      'universal-span1',
      'universal-a1',
      'universal-code2'
    ],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Universal selector, matching all children of empty element with specified ID',
    'selector': '#empty>*',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        'Universal selector, matching all descendants of element with specified ID',
    'selector': '#universal *',
    'expect': [
      'universal-p1',
      'universal-code1',
      'universal-hr1',
      'universal-pre1',
      'universal-span1',
      'universal-p2',
      'universal-a1',
      'universal-address1',
      'universal-code2',
      'universal-a2'
    ],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },

  // Attribute Selectors
  // - presence                  [att]
  {
    'name': 'Attribute presence selector, matching align attribute with value',
    'selector': '.attr-presence-div1[align]',
    'expect': ['attr-presence-div1'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute presence selector, matching align attribute with empty value',
    'selector': '.attr-presence-div2[align]',
    'expect': ['attr-presence-div2'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute presence selector, matching title attribute, case insensitivity',
    'selector': '#attr-presence [TiTlE]',
    'expect': ['attr-presence-a1', 'attr-presence-span1'],
    'exclude': ['xhtml'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute presence selector, not matching title attribute, case sensitivity',
    'selector': '#attr-presence [TiTlE]',
    'expect': <String>[],
    'exclude': ['html'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'Attribute presence selector, matching custom data-* attribute',
    'selector': '[data-attr-presence]',
    'expect': ['attr-presence-pre1', 'attr-presence-blockquote1'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute presence selector, not matching attribute with similar name',
    'selector': '.attr-presence-div3[align], .attr-presence-div4[align]',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        'Attribute presence selector, matching attribute with non-ASCII characters',
    'selector': 'ul[data-中文]',
    'expect': ['attr-presence-ul1'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute presence selector, not matching default option without selected attribute',
    'selector': '#attr-presence-select1 option[selected]',
    'expect': <String>[] /* no matches */,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        'Attribute presence selector, matching option with selected attribute',
    'selector': '#attr-presence-select2 option[selected]',
    'expect': ['attr-presence-select2-option4'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute presence selector, matching multiple options with selected attributes',
    'selector': '#attr-presence-select3 option[selected]',
    'expect': [
      'attr-presence-select3-option2',
      'attr-presence-select3-option3'
    ],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },

  // - value                     [att=val]
  {
    'name': 'Attribute value selector, matching align attribute with value',
    'selector': '#attr-value [align="center"]',
    'expect': ['attr-value-div1'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute value selector, matching align attribute with empty value',
    'selector': '#attr-value [align=""]',
    'expect': ['attr-value-div2'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute value selector, not matching align attribute with partial value',
    'selector': '#attr-value [align="c"]',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        'Attribute value selector, not matching align attribute with incorrect value',
    'selector': '#attr-value [align="centera"]',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        'Attribute value selector, matching custom data-* attribute with unicode escaped value',
    'selector': '[data-attr-value="\\e9"]',
    'expect': ['attr-value-div3'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute value selector, matching custom data-* attribute with escaped character',
    'selector': '[data-attr-value_foo="\\e9"]',
    'expect': ['attr-value-div4'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute value selector with single-quoted value, matching multiple inputs with type attributes',
    'selector':
        "#attr-value input[type='hidden'],#attr-value input[type='radio']",
    'expect': [
      'attr-value-input3',
      'attr-value-input4',
      'attr-value-input6',
      'attr-value-input8',
      'attr-value-input9'
    ],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute value selector with double-quoted value, matching multiple inputs with type attributes',
    'selector':
        "#attr-value input[type=\"hidden\"],#attr-value input[type='radio']",
    'expect': [
      'attr-value-input3',
      'attr-value-input4',
      'attr-value-input6',
      'attr-value-input8',
      'attr-value-input9'
    ],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute value selector with unquoted value, matching multiple inputs with type attributes',
    'selector': '#attr-value input[type=hidden],#attr-value input[type=radio]',
    'expect': [
      'attr-value-input3',
      'attr-value-input4',
      'attr-value-input6',
      'attr-value-input8',
      'attr-value-input9'
    ],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute value selector, matching attribute with value using non-ASCII characters',
    'selector': '[data-attr-value=中文]',
    'expect': ['attr-value-div5'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },

  // - whitespace-separated list [att~=val]
  {
    'name':
        'Attribute whitespace-separated list selector, matching class attribute with value',
    'selector': '#attr-whitespace [class~="div1"]',
    'expect': ['attr-whitespace-div1'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute whitespace-separated list selector, not matching class attribute with empty value',
    'selector': '#attr-whitespace [class~=""]',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        'Attribute whitespace-separated list selector, not matching class attribute with partial value',
    'selector': '[data-attr-whitespace~="div"]',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        'Attribute whitespace-separated list selector, matching custom data-* attribute with unicode escaped value',
    'selector': '[data-attr-whitespace~="\\0000e9"]',
    'expect': ['attr-whitespace-div4'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute whitespace-separated list selector, matching custom data-* attribute with escaped character',
    'selector': '[data-attr-whitespace_foo~="\\e9"]',
    'expect': ['attr-whitespace-div5'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute whitespace-separated list selector with single-quoted value, matching multiple links with rel attributes',
    'selector':
        "#attr-whitespace a[rel~='bookmark'],  #attr-whitespace a[rel~='nofollow']",
    'expect': [
      'attr-whitespace-a1',
      'attr-whitespace-a2',
      'attr-whitespace-a3',
      'attr-whitespace-a5',
      'attr-whitespace-a7'
    ],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute whitespace-separated list selector with double-quoted value, matching multiple links with rel attributes',
    'selector':
        "#attr-whitespace a[rel~=\"bookmark\"],#attr-whitespace a[rel~='nofollow']",
    'expect': [
      'attr-whitespace-a1',
      'attr-whitespace-a2',
      'attr-whitespace-a3',
      'attr-whitespace-a5',
      'attr-whitespace-a7'
    ],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute whitespace-separated list selector with unquoted value, matching multiple links with rel attributes',
    'selector':
        '#attr-whitespace a[rel~=bookmark],    #attr-whitespace a[rel~=nofollow]',
    'expect': [
      'attr-whitespace-a1',
      'attr-whitespace-a2',
      'attr-whitespace-a3',
      'attr-whitespace-a5',
      'attr-whitespace-a7'
    ],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute whitespace-separated list selector with double-quoted value, not matching value with space',
    'selector': '#attr-whitespace a[rel~="book mark"]',
    'expect': <String>[] /* no matches */,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        'Attribute whitespace-separated list selector, matching title attribute with value using non-ASCII characters',
    'selector': '#attr-whitespace [title~=中文]',
    'expect': ['attr-whitespace-p1'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },

  // - hyphen-separated list     [att|=val]
  {
    'name':
        'Attribute hyphen-separated list selector, not matching unspecified lang attribute',
    'selector': '#attr-hyphen-div1[lang|="en"]',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        'Attribute hyphen-separated list selector, matching lang attribute with exact value',
    'selector': '#attr-hyphen-div2[lang|="fr"]',
    'expect': ['attr-hyphen-div2'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute hyphen-separated list selector, matching lang attribute with partial value',
    'selector': '#attr-hyphen-div3[lang|="en"]',
    'expect': ['attr-hyphen-div3'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Attribute hyphen-separated list selector, not matching incorrect value',
    'selector': '#attr-hyphen-div4[lang|="es-AR"]',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },

  // - substring begins-with     [att^=val] (Level 3)
  {
    'name':
        'Attribute begins with selector, matching href attributes beginning with specified substring',
    'selector': '#attr-begins a[href^="http://www"]',
    'expect': ['attr-begins-a1', 'attr-begins-a3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute begins with selector, matching lang attributes beginning with specified substring, ',
    'selector': '#attr-begins [lang^="en-"]',
    'expect': ['attr-begins-div2', 'attr-begins-div4'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute begins with selector, not matching class attribute not beginning with specified substring',
    'selector': '#attr-begins [class^=apple]',
    'expect': <String>[] /*no matches*/,
    'level': 3,
    'testType': testQsaAdditional
  },
  {
    'name':
        'Attribute begins with selector with single-quoted value, matching class attribute beginning with specified substring',
    'selector': "#attr-begins [class^=' apple']",
    'expect': ['attr-begins-p1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute begins with selector with double-quoted value, matching class attribute beginning with specified substring',
    'selector': '#attr-begins [class^=" apple"]',
    'expect': ['attr-begins-p1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute begins with selector with unquoted value, not matching class attribute not beginning with specified substring',
    'selector': '#attr-begins [class^= apple]',
    'expect': <String>[] /*no matches*/,
    'level': 3,
    'testType': testQsaAdditional
  },

  // - substring ends-with       [att\$=val] (Level 3)
  {
    'name':
        'Attribute ends with selector, matching href attributes ending with specified substring',
    'selector': '#attr-ends a[href\$=".org"]',
    'expect': ['attr-ends-a1', 'attr-ends-a3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute ends with selector, matching lang attributes ending with specified substring, ',
    'selector': '#attr-ends [lang\$="-CH"]',
    'expect': ['attr-ends-div2', 'attr-ends-div4'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute ends with selector, not matching class attribute not ending with specified substring',
    'selector': '#attr-ends [class\$=apple]',
    'expect': <String>[] /*no matches*/,
    'level': 3,
    'testType': testQsaAdditional
  },
  {
    'name':
        'Attribute ends with selector with single-quoted value, matching class attribute ending with specified substring',
    'selector': "#attr-ends [class\$='apple ']",
    'expect': ['attr-ends-p1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute ends with selector with double-quoted value, matching class attribute ending with specified substring',
    'selector': '#attr-ends [class\$="apple "]',
    'expect': ['attr-ends-p1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute ends with selector with unquoted value, not matching class attribute not ending with specified substring',
    'selector': '#attr-ends [class\$=apple ]',
    'expect': <String>[] /*no matches*/,
    'level': 3,
    'testType': testQsaAdditional
  },

  // - substring contains        [att*=val] (Level 3)
  {
    'name':
        'Attribute contains selector, matching href attributes beginning with specified substring',
    'selector': '#attr-contains a[href*="http://www"]',
    'expect': ['attr-contains-a1', 'attr-contains-a3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute contains selector, matching href attributes ending with specified substring',
    'selector': '#attr-contains a[href*=".org"]',
    'expect': ['attr-contains-a1', 'attr-contains-a2'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute contains selector, matching href attributes containing specified substring',
    'selector': '#attr-contains a[href*=".example."]',
    'expect': ['attr-contains-a1', 'attr-contains-a3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute contains selector, matching lang attributes beginning with specified substring, ',
    'selector': '#attr-contains [lang*="en-"]',
    'expect': ['attr-contains-div2', 'attr-contains-div6'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute contains selector, matching lang attributes ending with specified substring, ',
    'selector': '#attr-contains [lang*="-CH"]',
    'expect': ['attr-contains-div3', 'attr-contains-div5'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute contains selector with single-quoted value, matching class attribute beginning with specified substring',
    'selector': "#attr-contains [class*=' apple']",
    'expect': ['attr-contains-p1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute contains selector with single-quoted value, matching class attribute ending with specified substring',
    'selector': "#attr-contains [class*='orange ']",
    'expect': ['attr-contains-p1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute contains selector with single-quoted value, matching class attribute containing specified substring',
    'selector': "#attr-contains [class*='ple banana ora']",
    'expect': ['attr-contains-p1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute contains selector with double-quoted value, matching class attribute beginning with specified substring',
    'selector': '#attr-contains [class*=" apple"]',
    'expect': ['attr-contains-p1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute contains selector with double-quoted value, matching class attribute ending with specified substring',
    'selector': '#attr-contains [class*="orange "]',
    'expect': ['attr-contains-p1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute contains selector with double-quoted value, matching class attribute containing specified substring',
    'selector': '#attr-contains [class*="ple banana ora"]',
    'expect': ['attr-contains-p1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute contains selector with unquoted value, matching class attribute beginning with specified substring',
    'selector': '#attr-contains [class*= apple]',
    'expect': ['attr-contains-p1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute contains selector with unquoted value, matching class attribute ending with specified substring',
    'selector': '#attr-contains [class*=orange ]',
    'expect': ['attr-contains-p1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'Attribute contains selector with unquoted value, matching class attribute containing specified substring',
    'selector': '#attr-contains [class*= banana ]',
    'expect': ['attr-contains-p1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // Pseudo-classes
  // - :root                 (Level 3)
  {
    'name': ':root pseudo-class selector, matching document root element',
    'selector': ':root',
    'expect': ['html'],
    'exclude': ['element', 'fragment', 'detached'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name': ':root pseudo-class selector, not matching document root element',
    'selector': ':root',
    'expect': <String>[] /*no matches*/,
    'exclude': ['document'],
    'level': 3,
    'testType': testQsaAdditional
  },

  // - :nth-child(n)         (Level 3)
  {
    'name': ':nth-child selector, matching the third child element',
    'selector': '#pseudo-nth-table1 :nth-child(3)',
    'expect': [
      'pseudo-nth-td3',
      'pseudo-nth-td9',
      'pseudo-nth-tr3',
      'pseudo-nth-td15'
    ],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name': ':nth-child selector, matching every third child element',
    'selector': '#pseudo-nth li:nth-child(3n)',
    'expect': [
      'pseudo-nth-li3',
      'pseudo-nth-li6',
      'pseudo-nth-li9',
      'pseudo-nth-li12'
    ],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':nth-child selector, matching every second child element, starting from the fourth',
    'selector': '#pseudo-nth li:nth-child(2n+4)',
    'expect': [
      'pseudo-nth-li4',
      'pseudo-nth-li6',
      'pseudo-nth-li8',
      'pseudo-nth-li10',
      'pseudo-nth-li12'
    ],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':nth-child selector, matching every fourth child element, starting from the third',
    'selector': '#pseudo-nth-p1 :nth-child(4n-1)',
    'expect': ['pseudo-nth-em2', 'pseudo-nth-span3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // - :nth-last-child       (Level 3)
  {
    'name': ':nth-last-child selector, matching the third last child element',
    'selector': '#pseudo-nth-table1 :nth-last-child(3)',
    'expect': [
      'pseudo-nth-tr1',
      'pseudo-nth-td4',
      'pseudo-nth-td10',
      'pseudo-nth-td16'
    ],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':nth-last-child selector, matching every third child element from the end',
    'selector': '#pseudo-nth li:nth-last-child(3n)',
    'expect': [
      'pseudo-nth-li1',
      'pseudo-nth-li4',
      'pseudo-nth-li7',
      'pseudo-nth-li10'
    ],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':nth-last-child selector, matching every second child element from the end, starting from the fourth last',
    'selector': '#pseudo-nth li:nth-last-child(2n+4)',
    'expect': [
      'pseudo-nth-li1',
      'pseudo-nth-li3',
      'pseudo-nth-li5',
      'pseudo-nth-li7',
      'pseudo-nth-li9'
    ],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':nth-last-child selector, matching every fourth element from the end, starting from the third last',
    'selector': '#pseudo-nth-p1 :nth-last-child(4n-1)',
    'expect': ['pseudo-nth-span2', 'pseudo-nth-span4'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // - :nth-of-type(n)       (Level 3)
  {
    'name': ':nth-of-type selector, matching the third em element',
    'selector': '#pseudo-nth-p1 em:nth-of-type(3)',
    'expect': ['pseudo-nth-em3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':nth-of-type selector, matching every second element of their type',
    'selector': '#pseudo-nth-p1 :nth-of-type(2n)',
    'expect': [
      'pseudo-nth-em2',
      'pseudo-nth-span2',
      'pseudo-nth-span4',
      'pseudo-nth-strong2',
      'pseudo-nth-em4'
    ],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':nth-of-type selector, matching every second elemetn of their type, starting from the first',
    'selector': '#pseudo-nth-p1 span:nth-of-type(2n-1)',
    'expect': ['pseudo-nth-span1', 'pseudo-nth-span3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // - :nth-last-of-type(n)  (Level 3)
  {
    'name': ':nth-last-of-type selector, matching the thrid last em element',
    'selector': '#pseudo-nth-p1 em:nth-last-of-type(3)',
    'expect': ['pseudo-nth-em2'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':nth-last-of-type selector, matching every second last element of their type',
    'selector': '#pseudo-nth-p1 :nth-last-of-type(2n)',
    'expect': [
      'pseudo-nth-span1',
      'pseudo-nth-em1',
      'pseudo-nth-strong1',
      'pseudo-nth-em3',
      'pseudo-nth-span3'
    ],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':nth-last-of-type selector, matching every second last element of their type, starting from the last',
    'selector': '#pseudo-nth-p1 span:nth-last-of-type(2n-1)',
    'expect': ['pseudo-nth-span2', 'pseudo-nth-span4'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // - :first-of-type        (Level 3)
  {
    'name': ':first-of-type selector, matching the first em element',
    'selector': '#pseudo-nth-p1 em:first-of-type',
    'expect': ['pseudo-nth-em1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':first-of-type selector, matching the first of every type of element',
    'selector': '#pseudo-nth-p1 :first-of-type',
    'expect': ['pseudo-nth-span1', 'pseudo-nth-em1', 'pseudo-nth-strong1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':first-of-type selector, matching the first td element in each table row',
    'selector': '#pseudo-nth-table1 tr :first-of-type',
    'expect': ['pseudo-nth-td1', 'pseudo-nth-td7', 'pseudo-nth-td13'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // - :last-of-type         (Level 3)
  {
    'name': ':last-of-type selector, matching the last em elemnet',
    'selector': '#pseudo-nth-p1 em:last-of-type',
    'expect': ['pseudo-nth-em4'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':last-of-type selector, matching the last of every type of element',
    'selector': '#pseudo-nth-p1 :last-of-type',
    'expect': ['pseudo-nth-span4', 'pseudo-nth-strong2', 'pseudo-nth-em4'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':last-of-type selector, matching the last td element in each table row',
    'selector': '#pseudo-nth-table1 tr :last-of-type',
    'expect': ['pseudo-nth-td6', 'pseudo-nth-td12', 'pseudo-nth-td18'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // - :first-child
  {
    'name':
        ':first-child pseudo-class selector, matching first child div element',
    'selector': '#pseudo-first-child div:first-child',
    'expect': ['pseudo-first-child-div1'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        ":first-child pseudo-class selector, doesn't match non-first-child elements",
    'selector':
        '.pseudo-first-child-div2:first-child, .pseudo-first-child-div3:first-child',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        ':first-child pseudo-class selector, matching first-child of multiple elements',
    'selector': '#pseudo-first-child span:first-child',
    'expect': [
      'pseudo-first-child-span1',
      'pseudo-first-child-span3',
      'pseudo-first-child-span5'
    ],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },

  // - :last-child           (Level 3)
  {
    'name':
        ':last-child pseudo-class selector, matching last child div element',
    'selector': '#pseudo-last-child div:last-child',
    'expect': ['pseudo-last-child-div3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ":last-child pseudo-class selector, doesn't match non-last-child elements",
    'selector':
        '.pseudo-last-child-div1:last-child, .pseudo-last-child-div2:first-child',
    'expect': <String>[] /*no matches*/,
    'level': 3,
    'testType': testQsaAdditional
  },
  {
    'name':
        ':last-child pseudo-class selector, matching first-child of multiple elements',
    'selector': '#pseudo-last-child span:last-child',
    'expect': [
      'pseudo-last-child-span2',
      'pseudo-last-child-span4',
      'pseudo-last-child-span6'
    ],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // - :only-child           (Level 3)
  {
    'name':
        ':pseudo-only-child pseudo-class selector, matching all only-child elements',
    'selector': '#pseudo-only :only-child',
    'expect': ['pseudo-only-span1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':pseudo-only-child pseudo-class selector, matching only-child em elements',
    'selector': '#pseudo-only em:only-child',
    'expect': <String>[] /*no matches*/,
    'level': 3,
    'testType': testQsaAdditional
  },

  // - :only-of-type         (Level 3)
  {
    'name':
        ':pseudo-only-of-type pseudo-class selector, matching all elements with no siblings of the same type',
    'selector': '#pseudo-only :only-of-type',
    'expect': ['pseudo-only-span1', 'pseudo-only-em1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        ':pseudo-only-of-type pseudo-class selector, matching em elements with no siblings of the same type',
    'selector': '#pseudo-only em:only-of-type',
    'expect': ['pseudo-only-em1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // - :empty                (Level 3)
  {
    'name': ':empty pseudo-class selector, matching empty p elements',
    'selector': '#pseudo-empty p:empty',
    'expect': ['pseudo-empty-p1', 'pseudo-empty-p2'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name': ':empty pseudo-class selector, matching all empty elements',
    'selector': '#pseudo-empty :empty',
    'expect': ['pseudo-empty-p1', 'pseudo-empty-p2', 'pseudo-empty-span1'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // - :link and :visited
  // Implementations may treat all visited links as unvisited, so these cannot be tested separately.
  // The only guarantee is that ":link,:visited" matches the set of all visited and unvisited links and that they are individually mutually exclusive sets.
  {
    'name':
        ':link and :visited pseudo-class selectors, matching a and area elements with href attributes',
    'selector': '#pseudo-link :link, #pseudo-link :visited',
    'expect': ['pseudo-link-a1', 'pseudo-link-a2', 'pseudo-link-area1'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        ':link and :visited pseudo-class selectors, matching link elements with href attributes',
    'selector': '#head :link, #head :visited',
    'expect': ['pseudo-link-link1', 'pseudo-link-link2'],
    'exclude': ['element', 'fragment', 'detached'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        ':link and :visited pseudo-class selectors, not matching link elements with href attributes',
    'selector': '#head :link, #head :visited',
    'expect': <String>[] /*no matches*/,
    'exclude': ['document'],
    'level': 1,
    'testType': testQsaBaseline
  },
  {
    'name':
        ':link and :visited pseudo-class selectors, chained, mutually exclusive pseudo-classes match nothing',
    'selector': ':link:visited',
    'expect': <String>[] /*no matches*/,
    'exclude': ['document'],
    'level': 1,
    'testType': testQsaBaseline
  },

  // - :target               (Level 3)
  {
    'name':
        ':target pseudo-class selector, matching the element referenced by the URL fragment identifier',
    'selector': ':target',
    'expect': <String>[] /*no matches*/,
    'exclude': ['document', 'element'],
    'level': 3,
    'testType': testQsaAdditional
  },
  {
    'name':
        ':target pseudo-class selector, matching the element referenced by the URL fragment identifier',
    'selector': ':target',
    'expect': ['target'],
    'exclude': ['fragment', 'detached'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // - :lang()
  {
    'name': ':lang pseudo-class selector, matching inherited language',
    'selector': '#pseudo-lang-div1:lang(en)',
    'expect': ['pseudo-lang-div1'],
    'exclude': ['detached', 'fragment'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        ':lang pseudo-class selector, not matching element with no inherited language',
    'selector': '#pseudo-lang-div1:lang(en)',
    'expect': <String>[] /*no matches*/,
    'exclude': ['document', 'element'],
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        ':lang pseudo-class selector, matching specified language with exact value',
    'selector': '#pseudo-lang-div2:lang(fr)',
    'expect': ['pseudo-lang-div2'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        ':lang pseudo-class selector, matching specified language with partial value',
    'selector': '#pseudo-lang-div3:lang(en)',
    'expect': ['pseudo-lang-div3'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': ':lang pseudo-class selector, not matching incorrect language',
    'selector': '#pseudo-lang-div4:lang(es-AR)',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },

  // - :enabled              (Level 3)
  {
    'name':
        ':enabled pseudo-class selector, matching all enabled form controls',
    'selector': '#pseudo-ui :enabled',
    'expect': [
      'pseudo-ui-input1',
      'pseudo-ui-input2',
      'pseudo-ui-input3',
      'pseudo-ui-input4',
      'pseudo-ui-input5',
      'pseudo-ui-input6',
      'pseudo-ui-input7',
      'pseudo-ui-input8',
      'pseudo-ui-input9',
      'pseudo-ui-textarea1',
      'pseudo-ui-button1'
    ],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // - :disabled             (Level 3)
  {
    'name':
        ':enabled pseudo-class selector, matching all disabled form controls',
    'selector': '#pseudo-ui :disabled',
    'expect': [
      'pseudo-ui-input10',
      'pseudo-ui-input11',
      'pseudo-ui-input12',
      'pseudo-ui-input13',
      'pseudo-ui-input14',
      'pseudo-ui-input15',
      'pseudo-ui-input16',
      'pseudo-ui-input17',
      'pseudo-ui-input18',
      'pseudo-ui-textarea2',
      'pseudo-ui-button2'
    ],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // - :checked              (Level 3)
  {
    'name':
        ':checked pseudo-class selector, matching checked radio buttons and checkboxes',
    'selector': '#pseudo-ui :checked',
    'expect': [
      'pseudo-ui-input4',
      'pseudo-ui-input6',
      'pseudo-ui-input13',
      'pseudo-ui-input15'
    ],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // - :not(s)               (Level 3)
  {
    'name': ':not pseudo-class selector, matching ',
    'selector': '#not>:not(div)',
    'expect': ['not-p1', 'not-p2', 'not-p3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name': ':not pseudo-class selector, matching ',
    'selector': '#not * :not(:first-child)',
    'expect': ['not-em1', 'not-em2', 'not-em3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name': ':not pseudo-class selector, matching nothing',
    'selector': ':not(*)',
    'expect': <String>[] /* no matches */,
    'level': 3,
    'testType': testQsaAdditional
  },
  {
    'name': ':not pseudo-class selector, matching nothing',
    'selector': ':not(*|*)',
    'expect': <String>[] /* no matches */,
    'level': 3,
    'testType': testQsaAdditional
  },

  // Pseudo-elements
  // - ::first-line
  {
    'name':
        ':first-line pseudo-element (one-colon syntax) selector, not matching any elements',
    'selector': '#pseudo-element:first-line',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        '::first-line pseudo-element (two-colon syntax) selector, not matching any elements',
    'selector': '#pseudo-element::first-line',
    'expect': <String>[] /*no matches*/,
    'level': 3,
    'testType': testQsaAdditional
  },

  // - ::first-letter
  {
    'name':
        ':first-letter pseudo-element (one-colon syntax) selector, not matching any elements',
    'selector': '#pseudo-element:first-letter',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        '::first-letter pseudo-element (two-colon syntax) selector, not matching any elements',
    'selector': '#pseudo-element::first-letter',
    'expect': <String>[] /*no matches*/,
    'level': 3,
    'testType': testQsaAdditional
  },

  // - ::before
  {
    'name':
        ':before pseudo-element (one-colon syntax) selector, not matching any elements',
    'selector': '#pseudo-element:before',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        '::before pseudo-element (two-colon syntax) selector, not matching any elements',
    'selector': '#pseudo-element::before',
    'expect': <String>[] /*no matches*/,
    'level': 3,
    'testType': testQsaAdditional
  },

  // - ::after
  {
    'name':
        ':after pseudo-element (one-colon syntax) selector, not matching any elements',
    'selector': '#pseudo-element:after',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        '::after pseudo-element (two-colon syntax) selector, not matching any elements',
    'selector': '#pseudo-element::after',
    'expect': <String>[] /*no matches*/,
    'level': 3,
    'testType': testQsaAdditional
  },

  // Class Selectors
  {
    'name': 'Class selector, matching element with specified class',
    'selector': '.class-p',
    'expect': ['class-p1', 'class-p2', 'class-p3'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Class selector, chained, matching only elements with all specified classes',
    'selector': '#class .apple.orange.banana',
    'expect': [
      'class-div1',
      'class-div2',
      'class-p4',
      'class-div3',
      'class-p6',
      'class-div4'
    ],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'Class Selector, chained, with type selector',
    'selector': 'div.apple.banana.orange',
    'expect': ['class-div1', 'class-div2', 'class-div3', 'class-div4'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  // Caution: If copying and pasting the folowing non-ASCII classes, ensure unicode normalisation is not performed in the process.
  {
    'name':
        'Class selector, matching element with class value using non-ASCII characters',
    'selector': '.台北Táiběi',
    'expect': ['class-span1'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Class selector, matching multiple elements with class value using non-ASCII characters',
    'selector': '.台北',
    'expect': ['class-span1', 'class-span2'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Class selector, chained, matching element with multiple class values using non-ASCII characters',
    'selector': '.台北Táiběi.台北',
    'expect': ['class-span1'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Class selector, matching element with class with escaped character',
    'selector': '.foo\\:bar',
    'expect': ['class-span3'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Class selector, matching element with class with escaped character',
    'selector': '.test\\.foo\\[5\\]bar',
    'expect': ['class-span4'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },

  // ID Selectors
  {
    'name': 'ID selector, matching element with specified id',
    'selector': '#id #id-div1',
    'expect': ['id-div1'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'ID selector, chained, matching element with specified id',
    'selector': '#id-div1, #id-div1',
    'expect': ['id-div1'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'ID selector, chained, matching element with specified id',
    'selector': '#id-div1, #id-div2',
    'expect': ['id-div1', 'id-div2'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'ID Selector, chained, with type selector',
    'selector': 'div#id-div1, div#id-div2',
    'expect': ['id-div1', 'id-div2'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'ID selector, not matching non-existent descendant',
    'selector': '#id #none',
    'expect': <String>[] /*no matches*/,
    'level': 1,
    'testType': testQsaBaseline
  },
  {
    'name': 'ID selector, not matching non-existent ancestor',
    'selector': '#none #id-div1',
    'expect': <String>[] /*no matches*/,
    'level': 1,
    'testType': testQsaBaseline
  },
  {
    'name': 'ID selector, matching multiple elements with duplicate id',
    'selector': '#id-li-duplicate',
    'expect': [
      'id-li-duplicate',
      'id-li-duplicate',
      'id-li-duplicate',
      'id-li-duplicate'
    ],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },

  // Caution: If copying and pasting the folowing non-ASCII IDs, ensure unicode normalisation is not performed in the process.
  {
    'name': 'ID selector, matching id value using non-ASCII characters',
    'selector': '#台北Táiběi',
    'expect': ['台北Táiběi'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'ID selector, matching id value using non-ASCII characters',
    'selector': '#台北',
    'expect': ['台北'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'ID selector, matching id values using non-ASCII characters',
    'selector': '#台北Táiběi, #台北',
    'expect': ['台北Táiběi', '台北'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },

  // XXX runMatchesTest() in level2-lib.js can't handle this because obtaining the expected nodes requires escaping characters when generating the selector from 'expect' values
  {
    'name': 'ID selector, matching element with id with escaped character',
    'selector': '#\\#foo\\:bar',
    'expect': ['#foo:bar'],
    'level': 1,
    'testType': testQsaBaseline
  },
  {
    'name': 'ID selector, matching element with id with escaped character',
    'selector': '#test\\.foo\\[5\\]bar',
    'expect': ['test.foo[5]bar'],
    'level': 1,
    'testType': testQsaBaseline
  },

  // Namespaces
  // XXX runMatchesTest() in level2-lib.js can't handle these because non-HTML elements don't have a recognised id
  {
    'name': 'Namespace selector, matching element with any namespace',
    'selector': '#any-namespace *|div',
    'expect': [
      'any-namespace-div1',
      'any-namespace-div2',
      'any-namespace-div3',
      'any-namespace-div4'
    ],
    'level': 3,
    'testType': testQsaBaseline
  },
  {
    'name': 'Namespace selector, matching div elements in no namespace only',
    'selector': '#no-namespace |div',
    'expect': ['no-namespace-div3'],
    'level': 3,
    'testType': testQsaBaseline
  },
  {
    'name': 'Namespace selector, matching any elements in no namespace only',
    'selector': '#no-namespace |*',
    'expect': ['no-namespace-div3'],
    'level': 3,
    'testType': testQsaBaseline
  },

  // Combinators
  // - Descendant combinator ' '
  {
    'name':
        'Descendant combinator, matching element that is a descendant of an element with id',
    'selector': '#descendant div',
    'expect': [
      'descendant-div1',
      'descendant-div2',
      'descendant-div3',
      'descendant-div4'
    ],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Descendant combinator, matching element with id that is a descendant of an element',
    'selector': 'body #descendant-div1',
    'expect': ['descendant-div1'],
    'exclude': ['detached', 'fragment'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Descendant combinator, matching element with id that is a descendant of an element',
    'selector': 'div #descendant-div1',
    'expect': ['descendant-div1'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Descendant combinator, matching element with id that is a descendant of an element with id',
    'selector': '#descendant #descendant-div2',
    'expect': ['descendant-div2'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Descendant combinator, matching element with class that is a descendant of an element with id',
    'selector': '#descendant .descendant-div2',
    'expect': ['descendant-div2'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Descendant combinator, matching element with class that is a descendant of an element with class',
    'selector': '.descendant-div1 .descendant-div3',
    'expect': ['descendant-div3'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Descendant combinator, not matching element with id that is not a descendant of an element with id',
    'selector': '#descendant-div1 #descendant-div4',
    'expect': <String>[] /*no matches*/,
    'level': 1,
    'testType': testQsaBaseline
  },
  {
    'name': 'Descendant combinator, whitespace characters',
    'selector': '#descendant\t\r\n#descendant-div2',
    'expect': ['descendant-div2'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },

  // - Child combinator '>'
  {
    'name':
        'Child combinator, matching element that is a child of an element with id',
    'selector': '#child>div',
    'expect': ['child-div1', 'child-div4'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Child combinator, matching element with id that is a child of an element',
    'selector': 'div>#child-div1',
    'expect': ['child-div1'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Child combinator, matching element with id that is a child of an element with id',
    'selector': '#child>#child-div1',
    'expect': ['child-div1'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Child combinator, matching element with id that is a child of an element with class',
    'selector': '#child-div1>.child-div2',
    'expect': ['child-div2'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Child combinator, matching element with class that is a child of an element with class',
    'selector': '.child-div1>.child-div2',
    'expect': ['child-div2'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Child combinator, not matching element with id that is not a child of an element with id',
    'selector': '#child>#child-div3',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        'Child combinator, not matching element with id that is not a child of an element with class',
    'selector': '#child-div1>.child-div3',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name':
        'Child combinator, not matching element with class that is not a child of an element with class',
    'selector': '.child-div1>.child-div3',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name': 'Child combinator, surrounded by whitespace',
    'selector': '#child-div1\t\r\n>\t\r\n#child-div2',
    'expect': ['child-div2'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'Child combinator, whitespace after',
    'selector': '#child-div1>\t\r\n#child-div2',
    'expect': ['child-div2'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'Child combinator, whitespace before',
    'selector': '#child-div1\t\r\n>#child-div2',
    'expect': ['child-div2'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'Child combinator, no whitespace',
    'selector': '#child-div1>#child-div2',
    'expect': ['child-div2'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },

  // - Adjacent sibling combinator '+'
  {
    'name':
        'Adjacent sibling combinator, matching element that is an adjacent sibling of an element with id',
    'selector': '#adjacent-div2+div',
    'expect': ['adjacent-div4'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element',
    'selector': 'div+#adjacent-div4',
    'expect': ['adjacent-div4'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element with id',
    'selector': '#adjacent-div2+#adjacent-div4',
    'expect': ['adjacent-div4'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with id',
    'selector': '#adjacent-div2+.adjacent-div4',
    'expect': ['adjacent-div4'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with class',
    'selector': '.adjacent-div2+.adjacent-div4',
    'expect': ['adjacent-div4'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Adjacent sibling combinator, matching p element that is an adjacent sibling of a div element',
    'selector': '#adjacent div+p',
    'expect': ['adjacent-p2'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name':
        'Adjacent sibling combinator, not matching element with id that is not an adjacent sibling of an element with id',
    'selector': '#adjacent-div2+#adjacent-p2, #adjacent-div2+#adjacent-div1',
    'expect': <String>[] /*no matches*/,
    'level': 2,
    'testType': testQsaBaseline
  },
  {
    'name': 'Adjacent sibling combinator, surrounded by whitespace',
    'selector': '#adjacent-p2\t\r\n+\t\r\n#adjacent-p3',
    'expect': ['adjacent-p3'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'Adjacent sibling combinator, whitespace after',
    'selector': '#adjacent-p2+\t\r\n#adjacent-p3',
    'expect': ['adjacent-p3'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'Adjacent sibling combinator, whitespace before',
    'selector': '#adjacent-p2\t\r\n+#adjacent-p3',
    'expect': ['adjacent-p3'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'Adjacent sibling combinator, no whitespace',
    'selector': '#adjacent-p2+#adjacent-p3',
    'expect': ['adjacent-p3'],
    'level': 2,
    'testType': testQsaBaseline | testMatchBaseline
  },

  // - General sibling combinator ~ (Level 3)
  {
    'name':
        'General sibling combinator, matching element that is a sibling of an element with id',
    'selector': '#sibling-div2~div',
    'expect': ['sibling-div4', 'sibling-div6'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'General sibling combinator, matching element with id that is a sibling of an element',
    'selector': 'div~#sibling-div4',
    'expect': ['sibling-div4'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'General sibling combinator, matching element with id that is a sibling of an element with id',
    'selector': '#sibling-div2~#sibling-div4',
    'expect': ['sibling-div4'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'General sibling combinator, matching element with class that is a sibling of an element with id',
    'selector': '#sibling-div2~.sibling-div',
    'expect': ['sibling-div4', 'sibling-div6'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'General sibling combinator, matching p element that is a sibling of a div element',
    'selector': '#sibling div~p',
    'expect': ['sibling-p2', 'sibling-p3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name':
        'General sibling combinator, not matching element with id that is not a sibling after a p element',
    'selector': '#sibling>p~div',
    'expect': <String>[] /*no matches*/,
    'level': 3,
    'testType': testQsaAdditional
  },
  {
    'name':
        'General sibling combinator, not matching element with id that is not a sibling after an element with id',
    'selector': '#sibling-div2~#sibling-div3, #sibling-div2~#sibling-div1',
    'expect': <String>[] /*no matches*/,
    'level': 3,
    'testType': testQsaAdditional
  },
  {
    'name': 'General sibling combinator, surrounded by whitespace',
    'selector': '#sibling-p2\t\r\n~\t\r\n#sibling-p3',
    'expect': ['sibling-p3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name': 'General sibling combinator, whitespace after',
    'selector': '#sibling-p2~\t\r\n#sibling-p3',
    'expect': ['sibling-p3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name': 'General sibling combinator, whitespace before',
    'selector': '#sibling-p2\t\r\n~#sibling-p3',
    'expect': ['sibling-p3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },
  {
    'name': 'General sibling combinator, no whitespace',
    'selector': '#sibling-p2~#sibling-p3',
    'expect': ['sibling-p3'],
    'level': 3,
    'testType': testQsaAdditional | testMatchBaseline
  },

  // Group of selectors (comma)
  {
    'name': 'Syntax, group of selectors separator, surrounded by whitespace',
    'selector': '#group em\t\r \n,\t\r \n#group strong',
    'expect': ['group-em1', 'group-strong1'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'Syntax, group of selectors separator, whitespace after',
    'selector': '#group em,\t\r\n#group strong',
    'expect': ['group-em1', 'group-strong1'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'Syntax, group of selectors separator, whitespace before',
    'selector': '#group em\t\r\n,#group strong',
    'expect': ['group-em1', 'group-strong1'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
  {
    'name': 'Syntax, group of selectors separator, no whitespace',
    'selector': '#group em,#group strong',
    'expect': ['group-em1', 'group-strong1'],
    'level': 1,
    'testType': testQsaBaseline | testMatchBaseline
  },
];
