11import { Competition , Person } from '@wca/helpers' ;
22import { WcaLiveCompetitorResult , WcaLiveRound } from '@/hooks/queries/useWcaLive' ;
33import { WcaCompetitionResult } from '@/lib/api' ;
4+ import { findPersonForApiResult } from './resultSources' ;
45import { getPersonalResultsFromSources , getRoundResultsFromSources } from './resultsProvider' ;
56
67jest . mock ( '@/lib/events' , ( ) => ( {
@@ -186,6 +187,8 @@ const liveRoundResult = (
186187 person : {
187188 id : '2' ,
188189 registrantId : 2 ,
190+ wcaUserId : 1002 ,
191+ wcaId : '2010BOBS01' ,
189192 name : 'Bob Solver' ,
190193 } ,
191194 ...overrides ,
@@ -222,6 +225,39 @@ const livePersonalResult = (
222225 ...overrides ,
223226} ) ;
224227
228+ describe ( 'findPersonForApiResult' , ( ) => {
229+ const duplicateNamePerson : Person = {
230+ ...persons [ 0 ] ,
231+ registrantId : 4 ,
232+ wcaUserId : 1004 ,
233+ wcaId : '2010ALIC02' ,
234+ } ;
235+
236+ it ( 'matches an exact WCA ID before considering duplicate names' , ( ) => {
237+ expect (
238+ findPersonForApiResult (
239+ [ ...persons , duplicateNamePerson ] ,
240+ apiResult ( { name : 'Alice Solver' , wca_id : '2010ALIC02' } ) ,
241+ ) ,
242+ ) . toBe ( duplicateNamePerson ) ;
243+ } ) ;
244+
245+ it ( 'does not fall back to a name when a WCA ID is present but unmatched' , ( ) => {
246+ expect (
247+ findPersonForApiResult ( persons , apiResult ( { name : 'Alice Solver' , wca_id : '2099MISS01' } ) ) ,
248+ ) . toBeUndefined ( ) ;
249+ } ) ;
250+
251+ it ( 'does not use an ambiguous name when the API result has no WCA ID' , ( ) => {
252+ expect (
253+ findPersonForApiResult (
254+ [ ...persons , duplicateNamePerson ] ,
255+ apiResult ( { name : 'Alice Solver' , wca_id : null } ) ,
256+ ) ,
257+ ) . toBeUndefined ( ) ;
258+ } ) ;
259+ } ) ;
260+
225261describe ( 'resultsProvider' , ( ) => {
226262 describe ( 'getRoundResultsFromSources' , ( ) => {
227263 it ( 'returns no round results without WCIF or a selected round' , ( ) => {
@@ -301,6 +337,8 @@ describe('resultsProvider', () => {
301337 average : 2200 ,
302338 round_type_id : '1' ,
303339 attempts : [ 2100 , 2200 , 2300 ] ,
340+ best_index : 2 ,
341+ worst_index : 0 ,
304342 regional_single_record : 'NR' ,
305343 regional_average_record : 'WR' ,
306344 } ) ,
@@ -326,6 +364,12 @@ describe('resultsProvider', () => {
326364 singleRecordTag : 'NR' ,
327365 averageRecordTag : 'WR' ,
328366 } ) ;
367+ expect ( results . find ( ( result ) => result . personId === 2 ) ) . not . toHaveProperty (
368+ 'bestAttemptIndex' ,
369+ ) ;
370+ expect ( results . find ( ( result ) => result . personId === 2 ) ) . not . toHaveProperty (
371+ 'worstAttemptIndex' ,
372+ ) ;
329373 expect ( results . find ( ( result ) => result . personId === 1 ) ) . toMatchObject ( {
330374 ranking : 1 ,
331375 best : 1200 ,
@@ -341,6 +385,98 @@ describe('resultsProvider', () => {
341385 } ) ;
342386 } ) ;
343387
388+ it ( 'matches live round results by WCA user id when registrant id is missing' , ( ) => {
389+ const results = getRoundResultsFromSources ( {
390+ wcif,
391+ selectedRound : selectedRound ( 0 ) ,
392+ wcaApiResults : [ ] ,
393+ wcaLiveRound : liveRound ( [
394+ liveRoundResult ( {
395+ id : 'live-alice' ,
396+ ranking : 4 ,
397+ best : 900 ,
398+ average : 1000 ,
399+ attempts : [ { result : 900 } , { result : 1000 } , { result : 1100 } ] ,
400+ person : {
401+ id : 'missing-registrant-id' ,
402+ registrantId : null ,
403+ wcaUserId : 1001 ,
404+ wcaId : '2010ALIC01' ,
405+ name : 'Alice Published Name' ,
406+ } ,
407+ } ) ,
408+ ] ) ,
409+ } ) ;
410+
411+ expect ( results ) . toHaveLength ( 3 ) ;
412+ expect ( results . filter ( ( result ) => result . personId === 1 ) ) . toHaveLength ( 1 ) ;
413+ expect ( results . find ( ( result ) => result . personId === 1 ) ) . toMatchObject ( {
414+ personName : 'Alice Published Name' ,
415+ ranking : 4 ,
416+ best : 900 ,
417+ average : 1000 ,
418+ attempts : [ { result : 900 } , { result : 1000 } , { result : 1100 } ] ,
419+ } ) ;
420+ } ) ;
421+
422+ it ( 'leaves a live result unlinked when its name is ambiguous and identifiers are missing' , ( ) => {
423+ const duplicateNamePerson : Person = {
424+ ...persons [ 0 ] ,
425+ registrantId : 4 ,
426+ wcaUserId : 1004 ,
427+ wcaId : '2010ALIC02' ,
428+ } ;
429+ const duplicateNameWcif = {
430+ ...wcif ,
431+ persons : [ ...persons , duplicateNamePerson ] ,
432+ } as Competition ;
433+ const results = getRoundResultsFromSources ( {
434+ wcif : duplicateNameWcif ,
435+ selectedRound : selectedRound ( 0 ) ,
436+ wcaApiResults : [ ] ,
437+ wcaLiveRound : liveRound ( [
438+ liveRoundResult ( {
439+ id : 'live-ambiguous-alice' ,
440+ person : {
441+ id : 'missing-identifiers' ,
442+ registrantId : null ,
443+ name : 'Alice Solver' ,
444+ } ,
445+ } ) ,
446+ ] ) ,
447+ } ) ;
448+
449+ expect ( results . find ( ( result ) => result . id === 'live-ambiguous-alice' ) ) . toMatchObject ( {
450+ personId : null ,
451+ personName : 'Alice Solver' ,
452+ } ) ;
453+ } ) ;
454+
455+ it ( 'does not override an unmatched live identity with a name match' , ( ) => {
456+ const results = getRoundResultsFromSources ( {
457+ wcif,
458+ selectedRound : selectedRound ( 0 ) ,
459+ wcaApiResults : [ ] ,
460+ wcaLiveRound : liveRound ( [
461+ liveRoundResult ( {
462+ id : 'live-conflicting-alice' ,
463+ person : {
464+ id : 'conflicting-identifiers' ,
465+ registrantId : null ,
466+ wcaUserId : 9999 ,
467+ wcaId : '2099MISS01' ,
468+ name : 'Alice Solver' ,
469+ } ,
470+ } ) ,
471+ ] ) ,
472+ } ) ;
473+
474+ expect ( results . find ( ( result ) => result . id === 'live-conflicting-alice' ) ) . toMatchObject ( {
475+ personId : null ,
476+ personName : 'Alice Solver' ,
477+ } ) ;
478+ } ) ;
479+
344480 it ( 'matches WCA API results by WCA ID before using the displayed name' , ( ) => {
345481 const results = getRoundResultsFromSources ( {
346482 wcif,
@@ -479,6 +615,23 @@ describe('resultsProvider', () => {
479615 ] ) ;
480616 } ) ;
481617
618+ it ( 'does not include a same-name API result with a conflicting WCA ID' , ( ) => {
619+ const results = getPersonalResultsFromSources ( {
620+ wcif,
621+ person : persons [ 0 ] ,
622+ wcaApiResults : [
623+ apiResult ( {
624+ id : 9201 ,
625+ name : 'Alice Solver' ,
626+ wca_id : '2010BOBS01' ,
627+ } ) ,
628+ ] ,
629+ wcaLiveResults : [ ] ,
630+ } ) ;
631+
632+ expect ( results [ 0 ] . rounds . map ( ( round ) => round . roundId ) ) . toEqual ( [ '333-r1' ] ) ;
633+ } ) ;
634+
482635 it ( 'sorts live personal events and rounds before merging them' , ( ) => {
483636 const secondRound = livePersonalResult ( {
484637 id : 'live-personal-333-r2' ,
0 commit comments