diff --git a/package.json b/package.json index 4794816..d40bf08 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,8 @@ "start": "npm run build && NODE_ENV=development webpack-dev-server --host 0.0.0.0 --open --hot --config build/webpack.config.js", "build": "npm --prefix admin run build && NODE_ENV=production webpack --config build/webpack.config.js", "serve": "cd src/server && NODE_ENV=development node app.js", - "lint": "eslint ." + "lint": "eslint .", + "test": "node --test \"test/**/*.test.js\"" }, "husky": { "hooks": { diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..ab94c72 --- /dev/null +++ b/test/README.md @@ -0,0 +1,26 @@ +# Regression tests + +This directory holds automated regression tests for stable leaderboard behavior. + +`leaderboard-e2e.test.js` starts the current server code against a fixed Rocket.Chat snapshot and verifies that `/stats`, `/rank`, and selected `/contributor` and `/rank?username=` responses still match the checked-in expected output. + +Node version used: + +- Node.js `v25.4.0` + +Fixtures: + +- `../contrib/rocketchat/gsoc/2025/gsoc2025final.json` is the canonical snapshot used as the fixed leaderboard input. +- `fixtures/gsoc2025final.expected.json` is the checked-in golden output generated from the current stable ranking logic and used for regression comparisons. + +Run from the repo root: + +```bash +npm i +npm --prefix src/server install +npm test +``` + +Note: `npm i` at the repo root installs only root dependencies. The regression test boots `src/server/app.js`, so `src/server` dependencies must also be installed before running `npm test`. + +The test itself uses the env/path override support already available in the upstream dotenv-based server setup (`CONFIG_PATH`, `DATA_PATH`, `LOG_PATH`, `ADMINDATA_PATH`, `CONFIG_BACKUP_PATH`, `SERVER_PORT`) and does not require additional source changes under `src/server`. diff --git a/test/fixtures/gsoc2025final.config.json b/test/fixtures/gsoc2025final.config.json new file mode 100644 index 0000000..9a1a65c --- /dev/null +++ b/test/fixtures/gsoc2025final.config.json @@ -0,0 +1,12 @@ +{ + "organization": "RocketChat", + "organizationHomepage": "https://rocket.chat/", + "organizationGithubUrl": "https://github.com/RocketChat", + "authToken": "", + "adminPassword": "123456", + "delay": "10", + "serverPort": "62050", + "contributors": [], + "startDate": "2024-12-01", + "includedRepositories": [] +} diff --git a/test/fixtures/gsoc2025final.expected.json b/test/fixtures/gsoc2025final.expected.json new file mode 100644 index 0000000..8fdf995 --- /dev/null +++ b/test/fixtures/gsoc2025final.expected.json @@ -0,0 +1,799 @@ +{ + "stats": { + "totalContributors": 251, + "totalOpenPRs": 167, + "totalMergedPRs": 77, + "totalIssues": 339 + }, + "ranks": { + "mergedprs": [ + "Rohit3523", + "dhairyashiil", + "jjinendra3", + "thepiyush-303", + "SinghaAnirban005", + "4shb0rne", + "AyushKumar123456789", + "abirc8010", + "sushen123", + "not-meet", + "r3yc0n1c", + "edcedcedcedc", + "adaniel105", + "yogesh-aggarwal", + "jasim0021", + "Jasim0021", + "devanshkansagra", + "Anxhul10", + "Kishan-Patel-dev", + "darshanlahamage", + "samir0607", + "sem22-dev", + "Amarta113", + "hexronuspi", + "Saaxena", + "Ansh-dS", + "priyanshuharshbodhi1", + "Abbas-Askari", + "KrishnaShuk", + "smritidoneria", + "schourasia750", + "ishanmitra", + "aryanranderiya", + "Raushankumar-prog", + "amitkumarashutosh", + "naman22a", + "ThanishaDewangan", + "connectshruti", + "Stpriyasharma", + "jannatkhandev", + "himgaur2004", + "utkarshh7", + "xmaxlad", + "ppl-call-me-tima", + "Rithvickkr", + "curious-goblin", + "kasimlohar", + "dasankush", + "Kaif9999", + "moyrsd", + "sugalipravallikabai", + "TripleCamellya", + "A-01-hub", + "Pratik-050", + "ramizik", + "PavanTaddi9", + "rahulrangers", + "ahmed12-dev", + "danielnabil", + "Nikunj00170", + "gschandrasekhar", + "sezallagwal", + "Niharika5100", + "DEVAANSH001", + "Pasta-coder", + "hardik-singh1087", + "anubhav-ray", + "Shashank8521", + "AmitGiriDev", + "Sanchit-100", + "0xDesirArman", + "ahmedbilal008", + "AST0008", + "GriffinAnnshual", + "vishesh-1111", + "brijeshpatolia", + "vaishvi2811", + "roy-abir05", + "ayush-jha123", + "aayushagarwal2003", + "pawan1117", + "Rupa-Rd", + "Mukesh-ghildiyal", + "PraverBajaj", + "CODEAbhinav-art", + "YoussefShaban6", + "Suraj370", + "dev-mohit06", + "dawit2123", + "tanishqbhadouria", + "akash205sharma", + "pran2535", + "moodyadi2006", + "ubonisrael", + "BasmaElhoseny01", + "Shivanshu840", + "jahnvisahni31", + "jenyyy4", + "AbhinavaReddy-hub", + "aryan19926", + "Saksham1o", + "adiVIT", + "rishijainn", + "MOHAMMED-IQRAMUL", + "Ravi3727", + "Kaushik035", + "PRAteek-singHWY", + "Ranbir5ingh", + "hs094", + "Utkarsh-Mauryaa", + "Jagrut25", + "adya-jha", + "hasanravda", + "ladrin", + "durgeshhhhhhh", + "gopal172002", + "siddhantpardhi", + "pranav150604", + "sakshi900600", + "saurav-sinha-3141", + "adityai0", + "AustinPardosi", + "WorkWithJaspreet", + "he-patrick", + "samueldharma", + "Rishidubey15", + "meenakshiiyer2531", + "aadarshx22", + "y-pranav", + "bharath2634", + "SarthakJain10", + "AllenHsm", + "Gannu456", + "6cobi", + "gauraviiitg", + "purrate", + "vivekchavan14", + "ditsus", + "RudraCodesForU", + "syedMahmood777", + "Adwait1609", + "VanshikaBhadani7", + "Strxangxl", + "samarcastic47", + "alokdangre", + "2753Farhan", + "sudharsan3110", + "shihabshahrier", + "Kishan-Agarwal-28", + "Vijay-Khantwal", + "HarshMethwani", + "RISHIREDDDY", + "omaraymanatia", + "Redi22", + "agnirudrasil", + "SRIVAISHNAVI-6", + "reema-s1", + "heavenlycreature", + "Divo1803", + "LAWSA07", + "jalpp", + "AlenHsiaoWeiLun", + "ZilongXue ", + "kvansh7", + "Amr-Shams", + "kanchana404", + "shashi-79", + "PTUsumit", + "kasmya", + "Lucifer4255", + "Swarup012", + "Alssymathews", + "Dhanraj30", + "2015pushkar", + "RishCode", + "sagarregmi2056", + "monishkumardvs", + "ashfaqjani916", + "Ruchit-Kumar44", + "celse13", + "NamVr", + "kush34", + "prakhar585", + "harneetsahi", + "Yash-Jadaun", + "keeeeeliu", + "lenguyenduyphuc", + "7uyash", + "rahul-software-dev", + "ayanchavand", + "indra55", + "vaishnavi887", + "zaselalk", + "AshishNamdeo14", + "Himanshu-Dangwal", + "Vansh2410", + "TapItNinja", + "boeing23", + "KrrishKumar125", + "mlasitsa", + "ayershov777", + "Dhakshinraghav", + "mursalin101", + "mo-sameh1", + "rushichavda", + "fzh075", + "Poonam-dew", + "Rudro4038", + "gal-actic", + "g-s01", + "aakashsingh04", + "Satyaprakashkadarla", + "GivenBY", + "Metalblade46", + "jfeng3206", + "99chandrasagar", + "Mayank5112", + "Ghislaib", + "gaurav0140", + "patelaryan0914", + "Vasita27", + "saurabhcoded", + "CocoTapi", + "Raghavnadiminti", + "qutequbit", + "Rohit-1301", + "fasakinhenry", + "Amanchaurasia17", + "ArnavMandal", + "07Abjth", + "SonaliK7654", + "irfiacre", + "capricorn-32", + "maheshwari522", + "AyushBurde", + "MohanRajRV", + "yohabay", + "Saadmrp1038", + "abhitrueprogrammer", + "GLITCHINvision", + "felixjoseph1", + "Mallick-Shrutik", + "renqingcm", + "mochi22", + "val2021-svg", + "dishapure", + "chifrica", + "juanjg05", + "akashkhedar", + "vishalpatel011", + "sanyaxx" + ], + "openprs": [ + "thepiyush-303", + "Rohit3523", + "dhairyashiil", + "SinghaAnirban005", + "jasim0021", + "Jasim0021", + "AyushKumar123456789", + "Ansh-dS", + "priyanshuharshbodhi1", + "Abbas-Askari", + "devanshkansagra", + "KrishnaShuk", + "jjinendra3", + "abirc8010", + "r3yc0n1c", + "Anxhul10", + "smritidoneria", + "schourasia750", + "ishanmitra", + "4shb0rne", + "aryanranderiya", + "sushen123", + "not-meet", + "edcedcedcedc", + "Raushankumar-prog", + "amitkumarashutosh", + "naman22a", + "ThanishaDewangan", + "adaniel105", + "Kishan-Patel-dev", + "connectshruti", + "Stpriyasharma", + "jannatkhandev", + "himgaur2004", + "utkarshh7", + "xmaxlad", + "ppl-call-me-tima", + "Rithvickkr", + "curious-goblin", + "kasimlohar", + "dasankush", + "yogesh-aggarwal", + "darshanlahamage", + "samir0607", + "sem22-dev", + "Amarta113", + "hexronuspi", + "Saaxena", + "Kaif9999", + "moyrsd", + "sugalipravallikabai", + "TripleCamellya", + "A-01-hub", + "Pratik-050", + "ramizik", + "PavanTaddi9", + "rahulrangers", + "ahmed12-dev", + "danielnabil", + "Nikunj00170", + "gschandrasekhar", + "sezallagwal", + "Niharika5100", + "DEVAANSH001", + "Pasta-coder", + "hardik-singh1087", + "anubhav-ray", + "Shashank8521", + "AmitGiriDev", + "Sanchit-100", + "0xDesirArman", + "ahmedbilal008", + "AST0008", + "GriffinAnnshual", + "vishesh-1111", + "brijeshpatolia", + "vaishvi2811", + "roy-abir05", + "ayush-jha123", + "aayushagarwal2003", + "pawan1117", + "Rupa-Rd", + "Mukesh-ghildiyal", + "PraverBajaj", + "CODEAbhinav-art", + "YoussefShaban6", + "Suraj370", + "dev-mohit06", + "dawit2123", + "tanishqbhadouria", + "akash205sharma", + "pran2535", + "moodyadi2006", + "ubonisrael", + "BasmaElhoseny01", + "Shivanshu840", + "jahnvisahni31", + "jenyyy4", + "AbhinavaReddy-hub", + "aryan19926", + "Saksham1o", + "adiVIT", + "rishijainn", + "MOHAMMED-IQRAMUL", + "Ravi3727", + "Kaushik035", + "PRAteek-singHWY", + "Ranbir5ingh", + "hs094", + "Utkarsh-Mauryaa", + "Jagrut25", + "adya-jha", + "hasanravda", + "ladrin", + "durgeshhhhhhh", + "gopal172002", + "siddhantpardhi", + "pranav150604", + "sakshi900600", + "saurav-sinha-3141", + "adityai0", + "AustinPardosi", + "WorkWithJaspreet", + "he-patrick", + "samueldharma", + "Rishidubey15", + "meenakshiiyer2531", + "aadarshx22", + "y-pranav", + "bharath2634", + "SarthakJain10", + "AllenHsm", + "Gannu456", + "6cobi", + "gauraviiitg", + "purrate", + "vivekchavan14", + "ditsus", + "RudraCodesForU", + "syedMahmood777", + "Adwait1609", + "VanshikaBhadani7", + "Strxangxl", + "samarcastic47", + "alokdangre", + "2753Farhan", + "sudharsan3110", + "shihabshahrier", + "Kishan-Agarwal-28", + "Vijay-Khantwal", + "HarshMethwani", + "RISHIREDDDY", + "omaraymanatia", + "Redi22", + "agnirudrasil", + "SRIVAISHNAVI-6", + "reema-s1", + "heavenlycreature", + "Divo1803", + "LAWSA07", + "jalpp", + "AlenHsiaoWeiLun", + "ZilongXue ", + "kvansh7", + "Amr-Shams", + "kanchana404", + "shashi-79", + "PTUsumit", + "kasmya", + "Lucifer4255", + "Swarup012", + "Alssymathews", + "Dhanraj30", + "2015pushkar", + "RishCode", + "sagarregmi2056", + "monishkumardvs", + "ashfaqjani916", + "Ruchit-Kumar44", + "celse13", + "NamVr", + "kush34", + "prakhar585", + "harneetsahi", + "Yash-Jadaun", + "keeeeeliu", + "lenguyenduyphuc", + "7uyash", + "rahul-software-dev", + "ayanchavand", + "indra55", + "vaishnavi887", + "zaselalk", + "AshishNamdeo14", + "Himanshu-Dangwal", + "Vansh2410", + "TapItNinja", + "boeing23", + "KrrishKumar125", + "mlasitsa", + "ayershov777", + "Dhakshinraghav", + "mursalin101", + "mo-sameh1", + "rushichavda", + "fzh075", + "Poonam-dew", + "Rudro4038", + "gal-actic", + "g-s01", + "aakashsingh04", + "Satyaprakashkadarla", + "GivenBY", + "Metalblade46", + "jfeng3206", + "99chandrasagar", + "Mayank5112", + "Ghislaib", + "gaurav0140", + "patelaryan0914", + "Vasita27", + "saurabhcoded", + "CocoTapi", + "Raghavnadiminti", + "qutequbit", + "Rohit-1301", + "fasakinhenry", + "Amanchaurasia17", + "ArnavMandal", + "07Abjth", + "SonaliK7654", + "irfiacre", + "capricorn-32", + "maheshwari522", + "AyushBurde", + "MohanRajRV", + "yohabay", + "Saadmrp1038", + "abhitrueprogrammer", + "GLITCHINvision", + "felixjoseph1", + "Mallick-Shrutik", + "renqingcm", + "mochi22", + "val2021-svg", + "dishapure", + "chifrica", + "juanjg05", + "akashkhedar", + "vishalpatel011", + "sanyaxx" + ], + "issues": [ + "dhairyashiil", + "SinghaAnirban005", + "thepiyush-303", + "abirc8010", + "jjinendra3", + "smritidoneria", + "Anxhul10", + "Ansh-dS", + "AyushKumar123456789", + "jasim0021", + "Jasim0021", + "sushen123", + "KrishnaShuk", + "priyanshuharshbodhi1", + "r3yc0n1c", + "Abbas-Askari", + "devanshkansagra", + "schourasia750", + "not-meet", + "connectshruti", + "Kaif9999", + "darshanlahamage", + "Stpriyasharma", + "moyrsd", + "4shb0rne", + "yogesh-aggarwal", + "ishanmitra", + "Raushankumar-prog", + "jannatkhandev", + "himgaur2004", + "sugalipravallikabai", + "TripleCamellya", + "Rohit3523", + "samir0607", + "sem22-dev", + "aryanranderiya", + "amitkumarashutosh", + "utkarshh7", + "xmaxlad", + "ppl-call-me-tima", + "Rithvickkr", + "A-01-hub", + "Pratik-050", + "ramizik", + "edcedcedcedc", + "adaniel105", + "Kishan-Patel-dev", + "Amarta113", + "hexronuspi", + "Saaxena", + "naman22a", + "ThanishaDewangan", + "curious-goblin", + "kasimlohar", + "dasankush", + "PavanTaddi9", + "rahulrangers", + "ahmed12-dev", + "danielnabil", + "Nikunj00170", + "gschandrasekhar", + "sezallagwal", + "Niharika5100", + "DEVAANSH001", + "Pasta-coder", + "hardik-singh1087", + "anubhav-ray", + "Shashank8521", + "AmitGiriDev", + "Sanchit-100", + "0xDesirArman", + "ahmedbilal008", + "AST0008", + "GriffinAnnshual", + "vishesh-1111", + "brijeshpatolia", + "vaishvi2811", + "roy-abir05", + "ayush-jha123", + "aayushagarwal2003", + "pawan1117", + "Rupa-Rd", + "Mukesh-ghildiyal", + "PraverBajaj", + "CODEAbhinav-art", + "YoussefShaban6", + "Suraj370", + "dev-mohit06", + "dawit2123", + "tanishqbhadouria", + "akash205sharma", + "pran2535", + "moodyadi2006", + "ubonisrael", + "BasmaElhoseny01", + "Shivanshu840", + "jahnvisahni31", + "jenyyy4", + "AbhinavaReddy-hub", + "aryan19926", + "Saksham1o", + "adiVIT", + "rishijainn", + "MOHAMMED-IQRAMUL", + "Ravi3727", + "Kaushik035", + "PRAteek-singHWY", + "Ranbir5ingh", + "hs094", + "Utkarsh-Mauryaa", + "Jagrut25", + "adya-jha", + "hasanravda", + "ladrin", + "durgeshhhhhhh", + "gopal172002", + "siddhantpardhi", + "pranav150604", + "sakshi900600", + "saurav-sinha-3141", + "adityai0", + "AustinPardosi", + "WorkWithJaspreet", + "he-patrick", + "samueldharma", + "Rishidubey15", + "meenakshiiyer2531", + "aadarshx22", + "y-pranav", + "bharath2634", + "SarthakJain10", + "AllenHsm", + "Gannu456", + "6cobi", + "gauraviiitg", + "purrate", + "vivekchavan14", + "ditsus", + "RudraCodesForU", + "syedMahmood777", + "Adwait1609", + "VanshikaBhadani7", + "Strxangxl", + "samarcastic47", + "alokdangre", + "2753Farhan", + "sudharsan3110", + "shihabshahrier", + "Kishan-Agarwal-28", + "Vijay-Khantwal", + "HarshMethwani", + "RISHIREDDDY", + "omaraymanatia", + "Redi22", + "agnirudrasil", + "SRIVAISHNAVI-6", + "reema-s1", + "heavenlycreature", + "Divo1803", + "LAWSA07", + "jalpp", + "AlenHsiaoWeiLun", + "ZilongXue ", + "kvansh7", + "Amr-Shams", + "kanchana404", + "shashi-79", + "PTUsumit", + "kasmya", + "Lucifer4255", + "Swarup012", + "Alssymathews", + "Dhanraj30", + "2015pushkar", + "RishCode", + "sagarregmi2056", + "monishkumardvs", + "ashfaqjani916", + "Ruchit-Kumar44", + "celse13", + "NamVr", + "kush34", + "prakhar585", + "harneetsahi", + "Yash-Jadaun", + "keeeeeliu", + "lenguyenduyphuc", + "7uyash", + "rahul-software-dev", + "ayanchavand", + "indra55", + "vaishnavi887", + "zaselalk", + "AshishNamdeo14", + "Himanshu-Dangwal", + "Vansh2410", + "TapItNinja", + "boeing23", + "KrrishKumar125", + "mlasitsa", + "ayershov777", + "Dhakshinraghav", + "mursalin101", + "mo-sameh1", + "rushichavda", + "fzh075", + "Poonam-dew", + "Rudro4038", + "gal-actic", + "g-s01", + "aakashsingh04", + "Satyaprakashkadarla", + "GivenBY", + "Metalblade46", + "jfeng3206", + "99chandrasagar", + "Mayank5112", + "Ghislaib", + "gaurav0140", + "patelaryan0914", + "Vasita27", + "saurabhcoded", + "CocoTapi", + "Raghavnadiminti", + "qutequbit", + "Rohit-1301", + "fasakinhenry", + "Amanchaurasia17", + "ArnavMandal", + "07Abjth", + "SonaliK7654", + "irfiacre", + "capricorn-32", + "maheshwari522", + "AyushBurde", + "MohanRajRV", + "yohabay", + "Saadmrp1038", + "abhitrueprogrammer", + "GLITCHINvision", + "felixjoseph1", + "Mallick-Shrutik", + "renqingcm", + "mochi22", + "val2021-svg", + "dishapure", + "chifrica", + "juanjg05", + "akashkhedar", + "vishalpatel011", + "sanyaxx" + ] + }, + "rankLookups": { + "dhairyashiil": { + "mergedprs": 2, + "openprs": 3, + "issues": 1 + }, + "SinghaAnirban005": { + "mergedprs": 5, + "openprs": 4, + "issues": 2 + }, + "PavanTaddi9": { + "mergedprs": 56, + "openprs": 56, + "issues": 56 + } + }, + "topContributorByMergedPrs": { + "username": "Rohit3523", + "contributor": { + "home": "https://github.com/Rohit3523", + "avatarUrl": "https://avatars.githubusercontent.com/u/40559587?v=4", + "openPRsNumber": 13, + "openPRsLink": "https://github.com/search?q=type:pr+author:Rohit3523+is:open+created:>=2024-12-01+repo:RocketChat/Rocket.Chat+repo:RocketChat/Rocket.Chat.Electron+repo:RocketChat/Docker.Official.Image+repo:RocketChat/Rocket.Chat.ReactNative+repo:RocketChat/Rocket.Chat.js.SDK+repo:RocketChat/Rocket.Chat.py.SDK+repo:RocketChat/Rocket.Chat.Livechat+repo:RocketChat/Rocket.Chat.Embedded.arm64+repo:RocketChat/Rocket.Chat.Embedded.armhf+repo:RocketChat/alexa-rocketchat+repo:RocketChat/Opensource-Contribution-Leaderboard+repo:RocketChat/Apps.GitHub+repo:RocketChat/fuselage+repo:RocketChat/alexa-rocketchat-notification+repo:RocketChat/alexa-rocketchat-flashbriefing+repo:RocketChat/alexa-news-publisher+repo:RocketChat/alexa-rc-multiserver-client+repo:RocketChat/Apps.Rasa+repo:RocketChat/Apps.Dialogflow+repo:RocketChat/RC4Github+repo:RocketChat/rocket.chat.app-poll+repo:RocketChat/developer-docs+repo:RocketChat/RC4Community+repo:RocketChat/RC4Conferences+repo:RocketChat/Apps.Github22+repo:RocketChat/EmbeddedChat+repo:RocketChat/Rocket.Chat.Demo.App+repo:RocketChat/docs+repo:RocketChat/GSoC-Community-Hub+repo:RocketChat/Apps.Notion+repo:RocketChat/Apps.Whiteboard+repo:RocketChat/google-summer-of-code+repo:RocketChat/Apps.Chat.Summarize+repo:RocketChat/Apps.QuickReplies+repo:RocketChat/Apps.AI.Codebase.Assistant+repo:RocketChat/AgileBot+repo:RocketChat/RC.Guided.Tours+repo:RocketChat/ruqola+repo:RocketChat/Apps.Receipts.Processor+-label:chore", + "mergedPRsNumber": 14, + "mergedPRsLink": "https://github.com/search?q=type:pr+author:Rohit3523+is:merged+created:>=2024-12-01+repo:RocketChat/Rocket.Chat+repo:RocketChat/Rocket.Chat.Electron+repo:RocketChat/Docker.Official.Image+repo:RocketChat/Rocket.Chat.ReactNative+repo:RocketChat/Rocket.Chat.js.SDK+repo:RocketChat/Rocket.Chat.py.SDK+repo:RocketChat/Rocket.Chat.Livechat+repo:RocketChat/Rocket.Chat.Embedded.arm64+repo:RocketChat/Rocket.Chat.Embedded.armhf+repo:RocketChat/alexa-rocketchat+repo:RocketChat/Opensource-Contribution-Leaderboard+repo:RocketChat/Apps.GitHub+repo:RocketChat/fuselage+repo:RocketChat/alexa-rocketchat-notification+repo:RocketChat/alexa-rocketchat-flashbriefing+repo:RocketChat/alexa-news-publisher+repo:RocketChat/alexa-rc-multiserver-client+repo:RocketChat/Apps.Rasa+repo:RocketChat/Apps.Dialogflow+repo:RocketChat/RC4Github+repo:RocketChat/rocket.chat.app-poll+repo:RocketChat/developer-docs+repo:RocketChat/RC4Community+repo:RocketChat/RC4Conferences+repo:RocketChat/Apps.Github22+repo:RocketChat/EmbeddedChat+repo:RocketChat/Rocket.Chat.Demo.App+repo:RocketChat/docs+repo:RocketChat/GSoC-Community-Hub+repo:RocketChat/Apps.Notion+repo:RocketChat/Apps.Whiteboard+repo:RocketChat/google-summer-of-code+repo:RocketChat/Apps.Chat.Summarize+repo:RocketChat/Apps.QuickReplies+repo:RocketChat/Apps.AI.Codebase.Assistant+repo:RocketChat/AgileBot+repo:RocketChat/RC.Guided.Tours+repo:RocketChat/ruqola+repo:RocketChat/Apps.Receipts.Processor+-label:chore", + "issuesNumber": 1, + "issuesLink": "https://github.com/search?q=type:issue+author:Rohit3523+created:>=2024-12-01+repo:RocketChat/Rocket.Chat+repo:RocketChat/Rocket.Chat.Electron+repo:RocketChat/Docker.Official.Image+repo:RocketChat/Rocket.Chat.ReactNative+repo:RocketChat/Rocket.Chat.js.SDK+repo:RocketChat/Rocket.Chat.py.SDK+repo:RocketChat/Rocket.Chat.Livechat+repo:RocketChat/Rocket.Chat.Embedded.arm64+repo:RocketChat/Rocket.Chat.Embedded.armhf+repo:RocketChat/alexa-rocketchat+repo:RocketChat/Opensource-Contribution-Leaderboard+repo:RocketChat/Apps.GitHub+repo:RocketChat/fuselage+repo:RocketChat/alexa-rocketchat-notification+repo:RocketChat/alexa-rocketchat-flashbriefing+repo:RocketChat/alexa-news-publisher+repo:RocketChat/alexa-rc-multiserver-client+repo:RocketChat/Apps.Rasa+repo:RocketChat/Apps.Dialogflow+repo:RocketChat/RC4Github+repo:RocketChat/rocket.chat.app-poll+repo:RocketChat/developer-docs+repo:RocketChat/RC4Community+repo:RocketChat/RC4Conferences+repo:RocketChat/Apps.Github22+repo:RocketChat/EmbeddedChat+repo:RocketChat/Rocket.Chat.Demo.App+repo:RocketChat/docs+repo:RocketChat/GSoC-Community-Hub+repo:RocketChat/Apps.Notion+repo:RocketChat/Apps.Whiteboard+repo:RocketChat/google-summer-of-code+repo:RocketChat/Apps.Chat.Summarize+repo:RocketChat/Apps.QuickReplies+repo:RocketChat/Apps.AI.Codebase.Assistant+repo:RocketChat/AgileBot+repo:RocketChat/RC.Guided.Tours+repo:RocketChat/ruqola+repo:RocketChat/Apps.Receipts.Processor+-label:chore" + } + } +} diff --git a/test/leaderboard-e2e.test.js b/test/leaderboard-e2e.test.js new file mode 100644 index 0000000..b91cdd5 --- /dev/null +++ b/test/leaderboard-e2e.test.js @@ -0,0 +1,180 @@ +const { after, before, test } = require('node:test') +const assert = require('assert') +const childProcess = require('child_process') +const fs = require('fs') +const http = require('http') +const nodeHttp = require('http') +const path = require('path') +const net = require('net') + +const fixturesDir = path.resolve(__dirname, 'fixtures') +const dataPath = path.resolve( + __dirname, + '../contrib/rocketchat/gsoc/2025/gsoc2025final.json' +) +const expectedPath = path.join(fixturesDir, 'gsoc2025final.expected.json') +const configPath = path.join(fixturesDir, 'gsoc2025final.config.json') +const logPath = path.join(fixturesDir, 'gsoc2025final.log.json') +const admindataPath = path.join(fixturesDir, 'gsoc2025final.admindata.json') +const configBackupPath = path.join(fixturesDir, 'gsoc2025final.configBackup.json') + +let server +let baseUrl +let expected +const originalCreateServer = nodeHttp.createServer +const originalSpawn = childProcess.spawn + +function getOpenPort() { + return new Promise((resolve, reject) => { + const probe = net.createServer() + probe.on('error', reject) + probe.listen(0, () => { + const { port } = probe.address() + probe.close((err) => { + if (err) { + reject(err) + return + } + resolve(port) + }) + }) + }) +} + +function requestJson(requestPath) { + return new Promise((resolve, reject) => { + const req = http.get(baseUrl + requestPath, (res) => { + let body = '' + + res.on('data', (chunk) => { + body += chunk.toString() + }) + + res.on('end', () => { + try { + resolve(JSON.parse(body)) + } catch (err) { + reject(err) + } + }) + }) + + req.on('error', reject) + }) +} + +before(async () => { + if (fs.existsSync(admindataPath)) { + fs.unlinkSync(admindataPath) + } + + if (fs.existsSync(configBackupPath)) { + fs.unlinkSync(configBackupPath) + } + + const port = await getOpenPort() + + process.env.NODE_ENV = 'development' + process.env.SERVER_PORT = String(port) + process.env.CONFIG_PATH = configPath + process.env.DATA_PATH = dataPath + process.env.LOG_PATH = logPath + process.env.ADMINDATA_PATH = admindataPath + process.env.CONFIG_BACKUP_PATH = configBackupPath + + expected = JSON.parse(fs.readFileSync(expectedPath, 'utf8')) + + childProcess.spawn = function (command, args) { + if (command === 'node' && Array.isArray(args) && args[0] === 'refresh.js') { + return { + kill() {}, + } + } + + return originalSpawn.apply(this, arguments) + } + + nodeHttp.createServer = function () { + server = originalCreateServer.apply(this, arguments) + return server + } + + const appPath = path.resolve(__dirname, '../src/server/app.js') + delete require.cache[appPath] + require(appPath) + + baseUrl = `http://127.0.0.1:${port}` + + if (!server.listening) { + await new Promise((resolve) => { + server.once('listening', resolve) + }) + } +}) + +after(async () => { + if (server && server.listening) { + await new Promise((resolve, reject) => { + server.close((err) => { + if (err) { + reject(err) + return + } + resolve() + }) + }) + } + + nodeHttp.createServer = originalCreateServer + childProcess.spawn = originalSpawn + + if (fs.existsSync(admindataPath)) { + fs.unlinkSync(admindataPath) + } + + if (fs.existsSync(configBackupPath)) { + fs.unlinkSync(configBackupPath) + } + + delete process.env.SERVER_PORT + delete process.env.CONFIG_PATH + delete process.env.DATA_PATH + delete process.env.LOG_PATH + delete process.env.ADMINDATA_PATH + delete process.env.CONFIG_BACKUP_PATH +}) + +test('stable leaderboard stats and rankings match the golden snapshot', async () => { + const stats = await requestJson('/stats') + assert.deepStrictEqual(stats, expected.stats) + + const mergedRanks = await requestJson('/rank') + const openRanks = await requestJson('/rank?parameter=openprs') + const issueRanks = await requestJson('/rank?parameter=issues') + + assert.deepStrictEqual(mergedRanks, { ranks: expected.ranks.mergedprs }) + assert.deepStrictEqual(openRanks, { ranks: expected.ranks.openprs }) + assert.deepStrictEqual(issueRanks, { ranks: expected.ranks.issues }) + assert.strictEqual(mergedRanks.ranks.length, stats.totalContributors) +}) + +test('stable leaderboard rank lookups and top contributor match the golden snapshot', async () => { + const dhairyashiilRank = await requestJson('/rank?username=dhairyashiil') + const singhaRank = await requestJson('/rank?username=SinghaAnirban005') + const pavanRank = await requestJson('/rank?username=PavanTaddi9') + const topContributor = await requestJson('/contributor?rank=1¶meter=mergedprs') + + assert.deepStrictEqual(dhairyashiilRank, { + username: 'dhairyashiil', + rank: expected.rankLookups.dhairyashiil.mergedprs, + }) + assert.deepStrictEqual(singhaRank, { + username: 'SinghaAnirban005', + rank: expected.rankLookups.SinghaAnirban005.mergedprs, + }) + assert.deepStrictEqual(pavanRank, { + username: 'PavanTaddi9', + rank: expected.rankLookups.PavanTaddi9.mergedprs, + }) + assert.deepStrictEqual(topContributor, expected.topContributorByMergedPrs.contributor) +})