github.com/web-platform-tests/wpt.fyi@v0.0.0-20240530210107-70cf978996f1/webapp/components/test/test-search.html (about)

     1  <!doctype html>
     2  <html>
     3  <head>
     4    <meta charset="utf-8">
     5    <script src="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
     6    <script src="../../node_modules/wct-browser-legacy/browser.js"></script>
     7  
     8    <script type="module" src="../test-search.js"></script>
     9  </head>
    10  <body>
    11    <test-fixture id="test-search-fixture">
    12      <template>
    13        <test-search></test-search>
    14      </template>
    15    </test-fixture>
    16  
    17    <script type="module">
    18  import { AllBrowserNames } from '../product-info.js';
    19  import { TestSearch } from '../test-search.js';
    20  
    21  suite('<test-search>', () => {
    22    suite('Parser/interpreter', () => {
    23      const assertQueryParse = (query, structuredQuery) => {
    24        const G = TestSearch.QUERY_GRAMMAR;
    25        const S = TestSearch.QUERY_SEMANTICS;
    26        const p = G.match(query);
    27        assert.isTrue(p.succeeded(), p.message);
    28        assert.deepEqual(structuredQuery, S(p).eval());
    29      };
    30  
    31      const assertQueryFail = (query) => {
    32        const G = TestSearch.QUERY_GRAMMAR;
    33        const p = G.match(query);
    34        assert.isFalse(p.succeeded(), p.message);
    35      };
    36  
    37      test('empty pattern', () => {
    38        assertQueryParse('', {exists: [{pattern: ''}]});
    39      });
    40  
    41      test('simple pattern', () => {
    42        assertQueryParse('2dcontext', {exists: [{pattern: '2dcontext'}]});
    43        assertQueryParse(
    44          '/2dcontext/building-paths/canvas_complexshapes_arcto_001.htm',
    45          {exists: [{pattern: '/2dcontext/building-paths/canvas_complexshapes_arcto_001.htm'}]}
    46        );
    47      });
    48  
    49      suite('quoted pattern', () => {
    50        test('basic', () => {
    51          assertQueryParse('"foo"', {exists: [{pattern: 'foo'}]});
    52          assertQueryParse('"/foo.html"', {exists: [{pattern: '/foo.html'}]});
    53        });
    54        test('complex', () => {
    55          assertQueryParse('"/foo.html?exclude=(Document|window|HTML.*)"', {exists: [{pattern: '/foo.html?exclude=(Document|window|HTML.*)'}]});
    56        });
    57      });
    58  
    59      test('subtest', () => {
    60        assertQueryParse('subtest:idl_test', {exists: [{subtest: 'idl_test'}]});
    61      });
    62  
    63      test('subtest_quoted', () => {
    64        assertQueryParse('subtest:"idl_test setup"', {exists: [{subtest: 'idl_test setup'}]});
    65      });
    66  
    67      test('path', () => {
    68        assertQueryParse('path:/dom/', {exists: [{path: '/dom/'}]});
    69      });
    70  
    71      test('path quoted', () => {
    72        assertQueryParse('path:"/foo.html?exclude=(Document|window|HTML.*)"', {exists: [{path: '/foo.html?exclude=(Document|window|HTML.*)'}]});
    73      });
    74  
    75      test('versioned browser', () => {
    76        assertQueryParse('chrome-64:fail', {exists: [{product: 'chrome-64', status: 'FAIL'}]});
    77      });
    78  
    79      test('test status', () => {
    80        assertQueryParse('status:missing', {exists: [{status: 'UNKNOWN'}]});
    81        assertQueryParse('status:!missing', {exists: [{status: {not: 'UNKNOWN'}}]});
    82        assertQueryParse('sTaTuS:UnKnOwN', {exists: [{status: 'UNKNOWN'}]});
    83      });
    84  
    85      test('test status eq', () => {
    86        assertQueryParse('sTaTuS:oK', {exists: [{status: 'OK'}]});
    87      });
    88  
    89      test('test status neq', () => {
    90        assertQueryParse('StAtUs:!FaIl', {exists: [{status: {not: 'FAIL'}}]});
    91      });
    92  
    93      test('browser test status eq', () => {
    94        // All known browsers.
    95        for (const browser of AllBrowserNames) {
    96          assertQueryParse(browser + ':ok', {exists: [{product: browser, status: 'OK'}]});
    97        }
    98  
    99        // Make sure unknown ones don't parse.
   100        assertQueryFail('darkmatter:ok');
   101  
   102        // Comparisons are case-insensitive.
   103        assertQueryParse('cHrOmE:oK', {exists: [{product: 'chrome', status: 'OK'}]});
   104      });
   105  
   106      test('browser test status neq', () => {
   107        assertQueryParse('sAfArI:!FaIl', {exists: [{product: 'safari', status: {not: 'FAIL'}}]});
   108      });
   109  
   110      test('pattern + test status', () => {
   111        assertQueryParse('cssom firefox:timeout', {
   112          exists: [
   113            {pattern: 'cssom'},
   114            {product: 'firefox', status: 'TIMEOUT'},
   115          ],
   116        });
   117  
   118        assertQueryParse('cssom AND firefox:timeout', {
   119          exists: [{
   120            and: [
   121              {pattern: 'cssom'},
   122              {product: 'firefox', status: 'TIMEOUT'},
   123            ]
   124          }],
   125        });
   126  
   127        assertQueryParse('cssom & firefox:timeout', {
   128          exists: [{
   129            and: [
   130              {pattern: 'cssom'},
   131              {product: 'firefox', status: 'TIMEOUT'},
   132            ]
   133          }],
   134        });
   135      });
   136  
   137      test('pattern | test status', () => {
   138        assertQueryParse('cssom or firefox:timeout', {
   139          exists: [{
   140            or: [
   141              {pattern: 'cssom'},
   142              {product: 'firefox', status: 'TIMEOUT'},
   143            ]
   144          }],
   145        });
   146      });
   147  
   148      test('implicit and, or', () => {
   149        assertQueryParse('a b or c', {
   150          exists: [
   151            {pattern: 'a'},
   152            {
   153              or: [
   154                {pattern: 'b'},
   155                {pattern: 'c'},
   156              ],
   157            },
   158          ],
   159        });
   160      });
   161  
   162      test('explicit and, or', () => {
   163        assertQueryParse('a and b or c', {
   164          exists: [{
   165            or: [
   166              {
   167                and: [
   168                  {pattern: 'a'},
   169                  {pattern: 'b'},
   170                ],
   171              },
   172              {pattern: 'c'},
   173            ],
   174          }]
   175        });
   176      });
   177  
   178      test('parens', () => {
   179        assertQueryParse('a and ( b or c )', {
   180          exists: [{
   181            and: [
   182              {pattern: 'a'},
   183              {
   184                or: [
   185                  {pattern: 'b'},
   186                  {pattern: 'c'},
   187                ],
   188              },
   189            ],
   190          }]
   191        });
   192  
   193        assertQueryParse('a or ( b and c )', {
   194          exists: [{
   195            or: [
   196              {pattern: 'a'},
   197              {
   198                and: [
   199                  {pattern: 'b'},
   200                  {pattern: 'c'},
   201                ],
   202              },
   203            ],
   204          }],
   205        });
   206      });
   207  
   208      test('nested or/and/not', () => {
   209        assertQueryParse('(chrome:pass or edge:pass) (firefox:!pass and firefox:!ok)', {
   210          exists: [
   211            {
   212              or: [
   213                {product: 'chrome', status: 'PASS'},
   214                {product: 'edge', status: 'PASS'},
   215              ]
   216            },
   217            {
   218              and: [
   219                {product: 'firefox', status: { not: 'PASS'} },
   220                {product: 'firefox', status: { not: 'OK'} },
   221              ],
   222            },
   223          ]
   224        });
   225        assertQueryParse(
   226          'chrome:pass (!(firefox:pass or firefox:ok) and !(safari:pass or safari:ok) and !(edge:pass or edge:ok))',
   227          {
   228            exists: [
   229              {product: 'chrome', status: 'PASS'},
   230              {
   231                and: ['firefox','safari','edge'].map(b => {
   232                  return {
   233                    not: {
   234                      or: [
   235                        {product: b, status: 'PASS'},
   236                        {product: b, status: 'OK'},
   237                      ]
   238                    }
   239                  };
   240                })
   241              },
   242            ]
   243          }
   244        );
   245      });
   246  
   247      test('or of and of and', () => {
   248        assertQueryParse('firefox:pass a | chrome:fail and ( b & c )', {
   249          exists: [
   250            {product: 'firefox', status: 'PASS'},
   251            {
   252              or: [
   253                {pattern: 'a'},
   254                {
   255                  and: [
   256                    {product: 'chrome', status: 'FAIL'},
   257                    {
   258                      and: [
   259                        {pattern: 'b'},
   260                        {pattern: 'c'},
   261                      ],
   262                    },
   263                  ],
   264                },
   265              ],
   266            },
   267          ]
   268        });
   269      });
   270  
   271      test('exists', () => {
   272        assertQueryParse('exists(status:PASS)', {
   273          exists: [{status: 'PASS'}],
   274        });
   275      });
   276  
   277      test('all', () => {
   278        assertQueryParse('all(status:!PASS status:!OK)', {
   279          all: [
   280            {status: {not: 'PASS'} },
   281            {status: {not: 'OK'} },
   282          ],
   283        });
   284      });
   285  
   286      test('none', () => {
   287        assertQueryParse('none(status:PASS or status:OK)', {
   288          none: [{
   289            or: [
   290              {status: 'PASS'},
   291              {status: 'OK'},
   292            ]
   293          }],
   294        });
   295      });
   296  
   297      test('sequential', () => {
   298        // Canon: flip-flopping, which is usually flakiness:
   299        // A pass turning into a fail on the next run, and a non-pass turning to a pass on the next run.
   300        assertQueryParse('seq(status:PASS status:!PASS)', {
   301          sequential: [
   302            {status: 'PASS'},
   303            {status: {not: 'PASS'} },
   304          ]
   305        });
   306        // Canon: flip-flopping, which is usually flakiness:
   307        // A pass turning into a fail on the next run, and a non-pass turning to a pass on the next run.
   308        assertQueryParse('seq((status:!PASS and status:!OK) (status:PASS or status:OK)) seq((status:PASS or status:OK) (status:!PASS and status:!OK))', {
   309          and: [
   310            { sequential: [
   311              {
   312                and: [
   313                  {status: {not: 'PASS'}},
   314                  {status: {not: 'OK'}},
   315                ],
   316              },
   317              { or: [{status: 'PASS'}, {status: 'OK'}] },
   318            ]},
   319            { sequential: [
   320              { or: [{status: 'PASS'}, {status: 'OK'}] },
   321              {
   322                and: [
   323                  {status: {not: 'PASS'}},
   324                  {status: {not: 'OK'}},
   325                ],
   326              },
   327            ]},
   328          ],
   329        });
   330      });
   331  
   332      test('is', () => {
   333        assertQueryParse('is:different', {
   334          exists: [{ is: 'different' }]
   335        });
   336        assertQueryParse('is:tentative', {
   337          exists: [{ is: 'tentative' }]
   338        });
   339        assertQueryParse('is:optional', {
   340          exists: [{ is: 'optional' }]
   341        });
   342      });
   343  
   344      test('count', () => {
   345        assertQueryParse('count:5(status:PASS or status:OK)', {
   346          count: 5,
   347          where: {
   348            or: [{status: 'PASS'}, {status: 'OK'}],
   349          },
   350        });
   351        for (const [atom, count] of [['three', 3], ['two', 2], ['one', 1]]) {
   352          assertQueryParse(`${atom}(status:!PASS and status:!OK)`, {
   353            count,
   354            where: {
   355              and: [{status: {not: 'PASS'}}, {status: {not: 'OK'}}],
   356            },
   357          });
   358        }
   359        assertQueryParse('count=5(status:PASS)', { count: 5, where: {status: 'PASS' }});
   360        assertQueryParse('count>1(status:PASS)', { moreThan: 1, where: {status: 'PASS' }});
   361        assertQueryParse('count>=2(status:PASS)', { moreThan: 1, where: {status: 'PASS' }});
   362        assertQueryParse('count<3(status:PASS)', { lessThan: 3, where: {status: 'PASS' }});
   363        assertQueryParse('count<=2(status:PASS)', { lessThan: 3, where: {status: 'PASS' }});
   364  
   365        assertQueryParse('count:=5(status:PASS)', { count: 5, where: {status: 'PASS' }});
   366        assertQueryParse('count:>1(status:PASS)', { moreThan: 1, where: {status: 'PASS' }});
   367        assertQueryParse('count:>=2(status:PASS)', { moreThan: 1, where: {status: 'PASS' }});
   368        assertQueryParse('count:<3(status:PASS)', { lessThan: 3, where: {status: 'PASS' }});
   369        assertQueryParse('count:<=2(status:PASS)', { lessThan: 3, where: {status: 'PASS' }});
   370      });
   371  
   372      test('simple link search', () => {
   373        assertQueryParse('link:2dcontext', {exists: [{link: '2dcontext'}]});
   374        assertQueryParse(
   375          'link:bugs.chromium.org/p/chromium/issues/detail',
   376          {exists: [{link: 'bugs.chromium.org/p/chromium/issues/detail'}]}
   377        );
   378      });
   379  
   380      test('test status | link', () => {
   381        assertQueryParse('firefox:timeout link:chromium.bug', {
   382          exists: [
   383            {product: 'firefox', status: 'TIMEOUT'},
   384            {link: 'chromium.bug'},
   385          ],
   386        });
   387  
   388        assertQueryParse('link:chromium.bug firefox:timeout', {
   389          exists: [
   390            {link: 'chromium.bug'},
   391            {product: 'firefox', status: 'TIMEOUT'},
   392          ],
   393        });
   394      });
   395  
   396      test('test status and not link', () => {
   397        assertQueryParse('firefox:timeout & not link:chromium.bug', {
   398          exists: [
   399            {
   400              and: [
   401                { product: 'firefox', status: 'TIMEOUT' },
   402                {
   403                  not:
   404                    { link: 'chromium.bug' },
   405                },
   406              ],
   407            }],
   408        });
   409      });
   410  
   411      test('simple triaged search', () => {
   412        assertQueryParse('triaged:chrome', { exists: [{ triaged: 'chrome' }] });
   413      });
   414  
   415      test('test status and triaged', () => {
   416        assertQueryParse('firefox:timeout triaged:firefox', {
   417          exists: [
   418            { product: 'firefox', status: 'TIMEOUT' },
   419            { triaged: 'firefox' },
   420          ],
   421        });
   422      });
   423  
   424      test('test-level triaged search', () => {
   425        assertQueryParse('triaged:test-issue', { exists: [{ triaged: '' }] });
   426      });
   427  
   428      test('metadata label search', () => {
   429        assertQueryParse('label:interop123', { exists: [{ label: 'interop123' }] });
   430      });
   431  
   432      test('web feature search', () => {
   433        assertQueryParse('feature:grid', { exists: [{ feature: 'grid' }] });
   434      });
   435  
   436      test('multi-root', () => {
   437        assertQueryParse('none(status:missing) count>0(status:!pass)', {
   438          and: [
   439            { none: [{ status: 'UNKNOWN' }] },
   440            { moreThan: 0, where: { status: { not: 'PASS' } } },
   441          ]
   442        });
   443        assertQueryParse('all(status:pass) or none(status:pass)', {
   444          or: [
   445            { all: [{ status: 'PASS' }] },
   446            { none: [{ status: 'PASS' }] },
   447          ]
   448        });
   449        assertQueryParse('idlharness all(status:fail)', {
   450          and: [
   451            { exists: [{ pattern: 'idlharness' }] },
   452            { all: [{ status: 'FAIL' }] },
   453          ]
   454        });
   455        assertQueryParse('2dcontext and all(status:fail)', {
   456          and: [
   457            { exists: [{ pattern: '2dcontext' }] },
   458            { all: [{ status: 'FAIL' }] },
   459          ]
   460        });
   461      });
   462    });
   463  });
   464  </script>
   465  </body>
   466  </html>