@@ -331,192 +331,3 @@ describe('Confluence plain search ranking', () => {
331331 expect ( own . nextCursor ) . toBe ( 'page-2' )
332332 } )
333333} )
334-
335- describe ( 'Jira plain search ranking' , ( ) => {
336- const search = '/ex/jira/cloud/rest/api/3/search/jql'
337- /** `outsideMatch`: the issue lacks a query term, so a `text ~` all-terms clause drops it. */
338- type Issue = string | { key : string ; summary : string ; outsideMatch ?: boolean }
339- /**
340- * Answers the all-terms query with `exact`, the all-terms summary query with `titled`, and the
341- * half-the-terms summary query with `half`, or their failures.
342- */
343- function jira (
344- exact : { ids : string [ ] ; more : boolean } ,
345- titled : Issue [ ] | ( ( ) => never ) ,
346- half : Issue [ ] | ( ( ) => never ) = [ ]
347- ) {
348- const toRow = ( row : Issue ) : Exclude < Issue , string > =>
349- typeof row === 'string' ? { key : row , summary : row } : row
350- const issues = ( rows : Issue [ ] ) =>
351- rows . map ( toRow ) . map ( ( { key, summary } ) => ( { key, fields : { summary } } ) )
352- const json = vi . fn (
353- async ( path : string , options ?: { body ?: { jql ?: string ; maxResults ?: number } } ) => {
354- if ( path === '/oauth/token/accessible-resources' ) return [ SITE ]
355- if ( path !== search ) throw new Error ( `Unexpected request: ${ path } ` )
356- const jql = options ?. body ?. jql ?? ''
357- if ( jql . includes ( 'summary ~' ) ) {
358- const rows = jql . includes ( ' OR ' ) ? half : titled
359- const picked = ( typeof rows === 'function' ? rows ( ) : rows )
360- . map ( toRow )
361- . filter ( ( row ) => ! ( row . outsideMatch && jql . includes ( 'text ~' ) ) )
362- return { issues : issues ( picked ) . slice ( 0 , options ?. body ?. maxResults ) }
363- }
364- return { issues : issues ( exact . ids ) , ...( exact . more ? { nextPageToken : 'page-2' } : { } ) }
365- }
366- )
367- return { json, text : vi . fn ( ) , bytes : vi . fn ( ) } satisfies NativeClient
368- }
369- const query = { query : 'merged results pipelines' , limit : 3 , scopes : [ ] }
370- const overflowing = { ids : [ 'NEW-3' , 'NEW-2' , 'NEW-1' ] , more : true }
371-
372- it ( 'leads an all-terms match too large for one page with issues whose summary holds every term' , async ( ) => {
373- const api = jira ( overflowing , [ 'TOP-1' , 'NEW-2' ] )
374- const page = await searchAtlassian ( api , 'jira' , query )
375- expect ( page . documents . map ( ( document ) => document . id ) ) . toEqual ( [ 'TOP-1' , 'NEW-2' , 'NEW-3' ] )
376- expect ( page . hasMore ) . toBe ( true )
377- expect ( page . partial ) . toBe ( true )
378- expect ( page . nextCursor ) . toBeUndefined ( )
379- } )
380-
381- it ( 'keeps the all-terms page and its cursor when no summary holds every term' , async ( ) => {
382- const page = await searchAtlassian ( jira ( overflowing , [ ] ) , 'jira' , query )
383- expect ( page . documents . map ( ( document ) => document . id ) ) . toEqual ( [ 'NEW-3' , 'NEW-2' , 'NEW-1' ] )
384- expect ( page . nextCursor ) . toBe ( 'page-2' )
385- expect ( page . partial ) . toBe ( false )
386- } )
387-
388- it . each ( [
389- [ 'a provider refusal' , new NativeSearchError ( 'rate_limited' , 'Rate limited.' , 30 ) ] ,
390- [ 'a request timeout' , new Error ( 'Request timed out after 10000ms' ) ] ,
391- ] ) (
392- 'keeps the all-terms page and its cursor when the summary search fails on %s' ,
393- async ( _ , failure ) => {
394- const api = jira ( overflowing , ( ) => {
395- throw failure
396- } )
397- const page = await searchAtlassian ( api , 'jira' , query )
398- expect ( page . documents . map ( ( document ) => document . id ) ) . toEqual ( [ 'NEW-3' , 'NEW-2' , 'NEW-1' ] )
399- expect ( page . nextCursor ) . toBe ( 'page-2' )
400- }
401- )
402-
403- it ( 'propagates a cancellation during the summary search' , async ( ) => {
404- const caller = new AbortController ( )
405- const reason = new DOMException ( 'Search cancelled' , 'AbortError' )
406- const api = jira ( overflowing , ( ) => {
407- caller . abort ( reason )
408- throw reason
409- } )
410- await expect ( searchAtlassian ( api , 'jira' , { ...query , signal : caller . signal } ) ) . rejects . toBe (
411- reason
412- )
413- } )
414-
415- it ( 'keeps an all-terms match that fits on one page without a summary search' , async ( ) => {
416- const api = jira ( { ids : [ 'ONLY-1' ] , more : false } , [ 'TOP-1' ] )
417- const page = await searchAtlassian ( api , 'jira' , query )
418- expect ( page . documents . map ( ( document ) => document . id ) ) . toEqual ( [ 'ONLY-1' ] )
419- expect ( api . json ) . toHaveBeenCalledTimes ( 2 )
420- } )
421-
422- it ( 'keeps date order, native queries and any-term matches on their own page' , async ( ) => {
423- for ( const input of [
424- { ...query , filters : { sortBy : 'newest' as const } } ,
425- { ...query , native : { provider : 'jira' as const , query : 'text ~ "merged results"' } } ,
426- { ...query , textMatch : 'any' as const } ,
427- ] ) {
428- const api = jira ( { ids : [ 'NEW-3' , 'NEW-2' ] , more : true } , [ 'TOP-1' ] )
429- const page = await searchAtlassian ( api , 'jira' , input )
430- expect ( page . documents . map ( ( document ) => document . id ) ) . not . toContain ( 'TOP-1' )
431- expect ( api . json ) . toHaveBeenCalledTimes ( 2 )
432- }
433- } )
434-
435- it ( 'leads with issues whose summary holds at least half the terms when none holds them all' , async ( ) => {
436- const api = jira (
437- overflowing ,
438- [ ] ,
439- [
440- { key : 'LOOSE-1' , summary : 'Pipelines dashboard' } ,
441- { key : 'HALF-1' , summary : 'Merged results broke the dashboard' } ,
442- ]
443- )
444- const page = await searchAtlassian ( api , 'jira' , query )
445- expect ( page . documents . map ( ( document ) => document . id ) ) . toEqual ( [ 'HALF-1' , 'NEW-3' , 'NEW-2' ] )
446- expect ( page . nextCursor ) . toBeUndefined ( )
447- } )
448-
449- it ( 'keeps a two-term query to summaries holding every term' , async ( ) => {
450- const api = jira ( overflowing , [ ] , [ { key : 'HALF-1' , summary : 'Merged pipelines' } ] )
451- const page = await searchAtlassian ( api , 'jira' , { ...query , query : 'merged pipelines' } )
452- expect ( page . documents . map ( ( document ) => document . id ) ) . toEqual ( [ 'NEW-3' , 'NEW-2' , 'NEW-1' ] )
453- expect ( api . json ) . toHaveBeenCalledTimes ( 3 )
454- } )
455-
456- it ( 'keeps the all-terms page and its cursor when the half-the-terms summary search fails' , async ( ) => {
457- const api = jira ( overflowing , [ ] , ( ) => {
458- throw new NativeSearchError ( 'rate_limited' , 'Rate limited.' , 30 )
459- } )
460- const page = await searchAtlassian ( api , 'jira' , query )
461- expect ( page . documents . map ( ( document ) => document . id ) ) . toEqual ( [ 'NEW-3' , 'NEW-2' , 'NEW-1' ] )
462- expect ( page . nextCursor ) . toBe ( 'page-2' )
463- } )
464-
465- it ( 'counts a word and its plural as one term before allowing the half-the-terms fallback' , async ( ) => {
466- const api = jira ( overflowing , [ ] , [ { key : 'ONE-1' , summary : 'Rotation schedule' } ] )
467- const page = await searchAtlassian ( api , 'jira' , { ...query , query : 'token tokens rotation' } )
468- expect ( page . documents . map ( ( document ) => document . id ) ) . toEqual ( [ 'NEW-3' , 'NEW-2' , 'NEW-1' ] )
469- } )
470-
471- it ( 'orders half-the-terms summaries by how many terms they hold' , async ( ) => {
472- const api = jira (
473- overflowing ,
474- [ ] ,
475- [
476- { key : 'TWO-1' , summary : 'Merged results dashboard' } ,
477- { key : 'THREE-1' , summary : 'Merged results in release pipelines' } ,
478- ]
479- )
480- const page = await searchAtlassian ( api , 'jira' , {
481- ...query ,
482- query : 'merged results release pipelines' ,
483- } )
484- expect ( page . documents . map ( ( document ) => document . id ) ) . toEqual ( [ 'THREE-1' , 'TWO-1' , 'NEW-3' ] )
485- } )
486-
487- it ( 'finds half-the-terms summaries beyond the first page of pair matches' , async ( ) => {
488- const pairs = Array . from ( { length : 10 } , ( _ , index ) => ( {
489- key : `PAIR-${ index } ` ,
490- summary : 'Pipelines dashboard' ,
491- } ) )
492- const api = jira ( overflowing , [ ] , [ ...pairs , { key : 'HALF-9' , summary : 'Merged pipelines' } ] )
493- const page = await searchAtlassian ( api , 'jira' , query )
494- expect ( page . documents . map ( ( document ) => document . id ) [ 0 ] ) . toBe ( 'HALF-9' )
495- } )
496-
497- it ( 'follows summaries holding every term with those holding half of them' , async ( ) => {
498- const api = jira (
499- { ids : [ 'NEW-3' , 'NEW-2' , 'NEW-1' ] , more : true } ,
500- [ 'ALL-1' ] ,
501- [
502- { key : 'ALL-1' , summary : 'Merged results pipelines' } ,
503- { key : 'HALF-1' , summary : 'Merged results dashboard' } ,
504- ]
505- )
506- const page = await searchAtlassian ( api , 'jira' , query )
507- expect ( page . documents . map ( ( document ) => document . id ) ) . toEqual ( [ 'ALL-1' , 'HALF-1' , 'NEW-3' ] )
508- } )
509-
510- it ( 'keeps half-the-terms summaries to issues that match every term somewhere' , async ( ) => {
511- const api = jira (
512- overflowing ,
513- [ ] ,
514- [
515- { key : 'OUTSIDE-1' , summary : 'Merged results dashboard' , outsideMatch : true } ,
516- { key : 'INSIDE-1' , summary : 'Merged results broke the dashboard' } ,
517- ]
518- )
519- const page = await searchAtlassian ( api , 'jira' , query )
520- expect ( page . documents . map ( ( document ) => document . id ) ) . toEqual ( [ 'INSIDE-1' , 'NEW-3' , 'NEW-2' ] )
521- } )
522- } )
0 commit comments