@@ -51,7 +51,26 @@ function makeUser(login: string, name: string) {
5151 } ;
5252}
5353
54- function makeScore ( finalScore : number ) {
54+ function makeLanguageScores ( finalScore : number ) {
55+ return {
56+ selectedLanguages : [ "TypeScript" ] ,
57+ repoScore : 0 ,
58+ prScore : 0 ,
59+ contributionScore : 0 ,
60+ finalScore,
61+ normalizedRepoScore : 0 ,
62+ normalizedPRScore : 0 ,
63+ normalizedContributionScore : 0 ,
64+ normalizedFinalScore : 0 ,
65+ topRepos : [ ] ,
66+ topPullRequests : [ ] ,
67+ } ;
68+ }
69+
70+ function makeScore (
71+ finalScore : number ,
72+ languageScores ?: ReturnType < typeof makeLanguageScores > ,
73+ ) {
5574 return {
5675 repoScore : 10 ,
5776 prScore : 20 ,
@@ -64,7 +83,7 @@ function makeScore(finalScore: number) {
6483 topRepos : [ ] ,
6584 topPullRequests : [ ] ,
6685 topCommunityContributions : [ ] ,
67- languageScores : undefined ,
86+ languageScores,
6887 signals : {
6988 reposAnalyzed : 1 ,
7089 pullRequestsAnalyzed : 1 ,
@@ -188,6 +207,77 @@ describe("GET /api/compare", () => {
188207 expect ( body . winner ?. username ) . toBe ( "user-a" ) ;
189208 } ) ;
190209
210+ test ( "returns null percentage when the losing final score is zero" , async ( ) => {
211+ mocks . getUserData . mockResolvedValueOnce ( {
212+ data : makeUser ( "user-a" , "User A" ) ,
213+ metrics : { duration : 0 , errors : [ ] } ,
214+ } ) ;
215+ mocks . getUserData . mockResolvedValueOnce ( {
216+ data : makeUser ( "user-b" , "User B" ) ,
217+ metrics : { duration : 0 , errors : [ ] } ,
218+ } ) ;
219+
220+ mocks . calculateUserScore . mockReturnValueOnce ( makeScore ( 20 ) ) ;
221+ mocks . calculateUserScore . mockReturnValueOnce ( makeScore ( 0 ) ) ;
222+
223+ const response = await GET (
224+ makeRequest ( {
225+ username : [ "user-a" , "user-b" ] ,
226+ } ) ,
227+ ) ;
228+ const body = ( await response . json ( ) ) as {
229+ winner ?: {
230+ username : string ;
231+ finalScoreDifference : number ;
232+ percentageDifference : number | null ;
233+ } ;
234+ } ;
235+
236+ expect ( response . status ) . toBe ( 200 ) ;
237+ expect ( body . winner ) . toEqual ( {
238+ username : "user-a" ,
239+ finalScoreDifference : 20 ,
240+ percentageDifference : null ,
241+ } ) ;
242+ } ) ;
243+
244+ test ( "returns null language winner percentage when language loser score is zero" , async ( ) => {
245+ mocks . getUserData . mockResolvedValueOnce ( {
246+ data : makeUser ( "user-a" , "User A" ) ,
247+ metrics : { duration : 0 , errors : [ ] } ,
248+ } ) ;
249+ mocks . getUserData . mockResolvedValueOnce ( {
250+ data : makeUser ( "user-b" , "User B" ) ,
251+ metrics : { duration : 0 , errors : [ ] } ,
252+ } ) ;
253+
254+ mocks . calculateUserScore . mockReturnValueOnce ( makeScore ( 20 , makeLanguageScores ( 12 ) ) ) ;
255+ mocks . calculateUserScore . mockReturnValueOnce ( makeScore ( 10 , makeLanguageScores ( 0 ) ) ) ;
256+
257+ const response = await GET (
258+ makeRequest ( {
259+ username : [ "user-a" , "user-b" ] ,
260+ selectedLanguage : "TypeScript" ,
261+ } ) ,
262+ ) ;
263+ const body = ( await response . json ( ) ) as {
264+ languageWinner ?: {
265+ username : string ;
266+ finalScoreDifference : number ;
267+ percentageDifference : number | null ;
268+ selectedLanguages : string [ ] ;
269+ } ;
270+ } ;
271+
272+ expect ( response . status ) . toBe ( 200 ) ;
273+ expect ( body . languageWinner ) . toEqual ( {
274+ username : "user-a" ,
275+ finalScoreDifference : 12 ,
276+ percentageDifference : null ,
277+ selectedLanguages : [ "TypeScript" ] ,
278+ } ) ;
279+ } ) ;
280+
191281 test ( "returns targeted username for not-found errors" , async ( ) => {
192282 mocks . getUserData . mockRejectedValueOnce ( new Error ( "User not found" ) ) ;
193283
0 commit comments