From d0bdb190b418b72ea1dbca8ab95a554160591a1c Mon Sep 17 00:00:00 2001 From: Pete Johns Date: Sat, 13 May 2023 15:51:04 +1000 Subject: [PATCH 1/9] Ensures web-ext is installed --- build/extension-firefox/build.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/extension-firefox/build.sh b/build/extension-firefox/build.sh index d20011d4..6eb9a5df 100755 --- a/build/extension-firefox/build.sh +++ b/build/extension-firefox/build.sh @@ -1,5 +1,9 @@ #!/bin/bash -xe +if ! type -p web-ext &>/dev/null; then + npm install --global web-ext +fi + # Set up version variables source build/version.sh # Set up tools variables From 87798212c5ed63442bcf307b983f3cb65922e014 Mon Sep 17 00:00:00 2001 From: Pete Johns Date: Sat, 13 May 2023 20:05:42 +1000 Subject: [PATCH 2/9] Documents running local unit tests --- browser-extensions/common/js/README.md | 58 ++++++++++++++++++-------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/browser-extensions/common/js/README.md b/browser-extensions/common/js/README.md index dcc74ffa..a3e3e8ac 100644 --- a/browser-extensions/common/js/README.md +++ b/browser-extensions/common/js/README.md @@ -1,31 +1,55 @@ -To run the tests locally you will need a number of Docker containers that are running Selenium in order to run those tests. +# Testing Running Challenges -You can run them all at once: +## Unit testing + +This project uses [Mocha] for unit testing. + +To run the unit tests locally: + +```sh +cd browser-extensions/common/js/tests +npm install +npm npm run test-with-coverage ``` -docker run --name selenium-firefox -d -p 4444:4444 -p 7900:7900 selenium/standalone-chrome + +## Automated browser testing + +This project uses [Selenium] for automated browser testing. + +To run the tests locally you will need a number of Docker containers running Selenium. You can run them all at once: + +```sh +docker run --name selenium-chrome -d -p 4444:4444 -p 7900:7900 selenium/standalone-chrome docker run --name selenium-firefox -d -p 4445:4444 -p 7901:7900 selenium/standalone-firefox +docker run --name selenium-edge -d -p 4446:4444 -p 7902:7900 selenium/standalone-edge ``` -These "latest" tagged images appear to be the latest in the 3.x line - which I assume is selenium, -rather than any bearing on the browser version -I assume this will work too: -``` -docker run --name selenium-firefox -d -p 4446:4444 -p 7902:7900 selenium/standalone-edge -``` +These "latest" tagged images are the latest in [Selenium Grid releases], not in particular browser versions. -When run in Github Actions we can define the port to be constant, or for it to be dynamically -generated at runtime, and pick it up from a variable. This is probably preferable +When run in the [Extension Builder] workflow in [GitHub Actions], we can define the port to be constant, or for it to be dynamically +generated at runtime, and pick it up from a variable. This is probably preferable. -You need to set the value of EXTENSION_ZIP to point to a built extension, on Windows you do it like: -``` +You need to set the value of `EXTENSION_ZIP` to point to a built extension. On Windows you do it like: + +```dos $Env:EXTENSION_ZIP="C:\\Users\\andre\\Downloads\\running_challenges-chrome-1.1.4.26.zip" ``` -If you want you can set the browser, but it will default to chrome - although perhaps we could derrive this from the zip name?: -``` +If you want you can set the browser, but it will default to chrome - although perhaps we could derive this from the zip name?: + +```dos $Env:EXTENSION_BROWSER="firefox" ``` + The port defaults to 4444, but you can override it with: -``` + +```dos $Env:SELENIUM_PORT="4445" -``` \ No newline at end of file +``` + + +[Extension Builder]: https://github.com/fraz3alpha/running-challenges/actions/workflows/build-extension.yml +[GitHub Actions]: https://github.com/actions +[Mocha]: https://mochajs.org +[Selenium Grid releases]: https://github.com/SeleniumHQ/docker-selenium/releases +[Selenium]: https://www.selenium.dev From 1abb567da768bf85c8bf644f4bfe7a1cf1ce7ece Mon Sep 17 00:00:00 2001 From: Pete Johns Date: Sat, 13 May 2023 20:21:03 +1000 Subject: [PATCH 3/9] First test --- .../common/js/tests/test/test_challenges.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/browser-extensions/common/js/tests/test/test_challenges.js b/browser-extensions/common/js/tests/test/test_challenges.js index 0e7da5a6..06389c54 100644 --- a/browser-extensions/common/js/tests/test/test_challenges.js +++ b/browser-extensions/common/js/tests/test/test_challenges.js @@ -317,6 +317,18 @@ describe("challenges.js", function() { }) + describe("generate_stat_longest_tourism_streak", () => { + const generate_stat_longest_tourism_streak = challenges.__get__('generate_stat_longest_tourism_streak'); + + describe("given no results", () => { + const parkrunResults = []; + it("is expected to be zero", () => { + const r = generate_stat_longest_tourism_streak(parkrunResults) + assert.equal(r.value, '0 parkruns (achieved 0)') + }) + }) + }) + }) describe("challenges", function() { From 2c7922fa0cec6821a79dec7d566c88516e1acab9 Mon Sep 17 00:00:00 2001 From: Pete Johns Date: Sat, 13 May 2023 23:08:47 +1000 Subject: [PATCH 4/9] Allows tests to set any field --- .../common/js/tests/test/test_challenges.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/browser-extensions/common/js/tests/test/test_challenges.js b/browser-extensions/common/js/tests/test/test_challenges.js index 06389c54..060214dd 100644 --- a/browser-extensions/common/js/tests/test/test_challenges.js +++ b/browser-extensions/common/js/tests/test/test_challenges.js @@ -141,7 +141,7 @@ function getNextParkrunDate() { } function createParkrunResult(specificData) { - parkrunResult = { + return { name: "Fell Foot", eventlink: "Fell Foot", date: "22/11/2014", @@ -150,13 +150,9 @@ function createParkrunResult(specificData) { event_number: "6", position: "44", time: "26:19", - pb: false - } - // If we have been given a name, find it in the geodata - if (specificData.name !== undefined) { - parkrunResult.name = specificData.name + pb: false, + ...specificData } - return parkrunResult } var geoData = getGeoData() From de779d419bbcac70c048ceac5664df396127b08b Mon Sep 17 00:00:00 2001 From: Pete Johns Date: Sat, 13 May 2023 23:11:57 +1000 Subject: [PATCH 5/9] Tests existing behaviour --- .../common/js/tests/test/test_challenges.js | 115 +++++++++++++++++- 1 file changed, 113 insertions(+), 2 deletions(-) diff --git a/browser-extensions/common/js/tests/test/test_challenges.js b/browser-extensions/common/js/tests/test/test_challenges.js index 060214dd..6a747a32 100644 --- a/browser-extensions/common/js/tests/test/test_challenges.js +++ b/browser-extensions/common/js/tests/test/test_challenges.js @@ -320,11 +320,122 @@ describe("challenges.js", function() { const parkrunResults = []; it("is expected to be zero", () => { const r = generate_stat_longest_tourism_streak(parkrunResults) - assert.equal(r.value, '0 parkruns (achieved 0)') + assert.strictEqual(r.value, '0 parkruns (achieved 0)') + }) + }) + + describe("given one result", () => { + const parkrunResults = [ + createParkrunResult({ name: "A", datelink: "date1", eventlink: "eventa" }) + ]; + it("is expected to be one", () => { + const r = generate_stat_longest_tourism_streak(parkrunResults) + assert.strictEqual(r.value, "1 parkruns (achieved eventa date1)") + }) + }) + + describe("given two identical results", () => { + const parkrunResults = [ + createParkrunResult({ name: "A", datelink: "date1", eventlink: "eventa" }), + createParkrunResult({ name: "A", datelink: "date2", eventlink: "eventa" }) + ]; + it("is expected to be the latest one", () => { + const r = generate_stat_longest_tourism_streak(parkrunResults) + assert.strictEqual(r.value, "1 parkruns (achieved eventa date2)") + }) + }) + + describe("given two different results", () => { + const parkrunResults = [ + createParkrunResult({ name: "A", datelink: "date1", eventlink: "eventa" }), + createParkrunResult({ name: "B", datelink: "date2", eventlink: "eventb" }) + ]; + it("is expected to be two", () => { + const r = generate_stat_longest_tourism_streak(parkrunResults) + assert.strictEqual(r.value, "2 parkruns (achieved eventb date2)") + }) + }) + + describe("a third result the same as the first", () => { + const parkrunResults = [ + createParkrunResult({ name: "A", datelink: "date1", eventlink: "eventa" }), + createParkrunResult({ name: "B", datelink: "date2", eventlink: "eventb" }), + createParkrunResult({ name: "A", datelink: "date3", eventlink: "eventa" }) + ]; + it("is expected to remove the first event from the streak", () => { + const r = generate_stat_longest_tourism_streak(parkrunResults) + assert.strictEqual(r.value, "2 parkruns (achieved eventa date3)") + }) + }) + + describe("a third result the same as the second", () => { + const parkrunResults = [ + createParkrunResult({ name: "A", datelink: "date1", eventlink: "eventa" }), + createParkrunResult({ name: "B", datelink: "date2", eventlink: "eventb" }), + createParkrunResult({ name: "B", datelink: "date3", eventlink: "eventb" }) + ]; + it("is expected to end the streak", () => { + const r = generate_stat_longest_tourism_streak(parkrunResults) + assert.strictEqual(r.value, "2 parkruns (achieved eventb date2)") + }) + }) + + describe("a third unique result", () => { + const parkrunResults = [ + createParkrunResult({ name: "A", datelink: "date1", eventlink: "eventa" }), + createParkrunResult({ name: "B", datelink: "date2", eventlink: "eventb" }), + createParkrunResult({ name: "C", datelink: "date3", eventlink: "eventc" }) + ]; + it("is expected to extend the streak", () => { + const r = generate_stat_longest_tourism_streak(parkrunResults) + assert.strictEqual(r.value, "3 parkruns (achieved eventc date3)") + }) + }) + + describe("two identical streaks", () => { + const parkrunResults = [ + createParkrunResult({ name: "A", datelink: "date1", eventlink: "eventa" }), + createParkrunResult({ name: "B", datelink: "date2", eventlink: "eventb" }), + createParkrunResult({ name: "A", datelink: "date3", eventlink: "eventa" }), + createParkrunResult({ name: "B", datelink: "date4", eventlink: "eventb" }), + ]; + it("is expected to be the second streak", () => { + const r = generate_stat_longest_tourism_streak(parkrunResults) + assert.strictEqual(r.value, "2 parkruns (achieved eventb date4)") }) }) - }) + describe("overlapping streaks (ABC, BCAD, ADCE)", ()=> { + const parkrunResults = [ + createParkrunResult({ name: "A", datelink: "date1", eventlink: "eventa" }), + createParkrunResult({ name: "B", datelink: "date2", eventlink: "eventb" }), + createParkrunResult({ name: "C", datelink: "date3", eventlink: "eventc" }), + createParkrunResult({ name: "A", datelink: "date4", eventlink: "eventa" }), + createParkrunResult({ name: "D", datelink: "date5", eventlink: "eventd" }), + createParkrunResult({ name: "C", datelink: "date6", eventlink: "eventc" }), + createParkrunResult({ name: "E", datelink: "date7", eventlink: "evente" }) + ]; + it("is expected to be the latest, longest streak", () => { + const r = generate_stat_longest_tourism_streak(parkrunResults) + assert.strictEqual(r.value, "4 parkruns (achieved evente date7)") + }) + }) + + describe("A long streak followed by a shorter one (ABCD, DC)", () => { + const parkrunResults = [ + createParkrunResult({ name: "A", datelink: "date1", eventlink: "eventA" }), + createParkrunResult({ name: "B", datelink: "date2", eventlink: "eventB" }), + createParkrunResult({ name: "C", datelink: "date3", eventlink: "eventC" }), + createParkrunResult({ name: "D", datelink: "date4", eventlink: "eventD" }), + createParkrunResult({ name: "C", datelink: "date5", eventlink: "eventC" }) + ]; + + it("is expected to be the longer streak", () => { + const r = generate_stat_longest_tourism_streak(parkrunResults) + assert.strictEqual(r.value, "4 parkruns (achieved eventD date4)") + }) + }) + }) }) describe("challenges", function() { From 4e3e9208e9e524739b299604bbc29a4ac336185e Mon Sep 17 00:00:00 2001 From: Pete Johns Date: Sun, 14 May 2023 13:07:57 +1000 Subject: [PATCH 6/9] Reports the start and finish events (and dates) for a tourism streak --- .../common/js/lib/challenges.js | 68 +++++++++---------- .../common/js/tests/test/test_challenges.js | 23 ++++--- 2 files changed, 45 insertions(+), 46 deletions(-) diff --git a/browser-extensions/common/js/lib/challenges.js b/browser-extensions/common/js/lib/challenges.js index 2b428d5e..e6df160f 100644 --- a/browser-extensions/common/js/lib/challenges.js +++ b/browser-extensions/common/js/lib/challenges.js @@ -881,49 +881,47 @@ function generate_stat_tourist_quotient(parkrun_results) { } } -// Maximum number of consecutive different parkrun events function generate_stat_longest_tourism_streak(parkrun_results) { - var t_streak = 0 - var t_date = 0 - var t_last = "" - let event_streak = [] - - parkrun_results.forEach(function (parkrun_event, index) { - - // If we get a duplicate parkrun, chop off the start of the streak - // up until the streak becomes unique again. - // - // e.g. - // [1,2,3,4] - going to add [1] - // will chop off the first element with splice(0,1) - // [1,2,3,4,5,6] - going to add [3] - // will chop off the first 3 elements - if (event_streak.includes(parkrun_event.name)) { - - var f = 0 - var filteredElements = event_streak.some(function(item, index) { - f = index; return item == parkrun_event.name - }) + const display_name = "Longest tourism streak" + const help = "The highest number of consecutive different events attended." + var longest_start = 0, longest_finish = 0, start_index = 0, finish_index = 0; + + function has_run_event_in_streak(start, finish, event_name) { + for (var i = start; i < finish; ++i) { + if (parkrun_results[i].name === event_name) { + return i + } + } + return null + } - event_streak.splice(0,f+1) + function longest_streak() { + return longest_finish - longest_start + 1 + } + for (; finish_index < parkrun_results.length; finish_index++) { + previous_visit = has_run_event_in_streak(start_index, finish_index, parkrun_results[finish_index].name) + + if (previous_visit !== null) { + // If a participant has visited an event multiple times, + // a streak must start after their previous visit. + start_index = previous_visit + 1 } - // Add the new parkrun in - it will be unique in the list as we removed the - // existing entries in the list above. - event_streak.push(parkrun_event.name) - if (event_streak.length >= t_streak) { - t_date = parkrun_event.datelink - t_last = parkrun_event.eventlink - t_streak = event_streak.length + if ((finish_index - start_index + 1) >= longest_streak()) { + // We have a new long streak, store the start and finish indexes. + longest_start = start_index + longest_finish = finish_index } + } - }) - return { - "display_name": "Longest tourism streak", - "help": "The highest number of consecutive different events attended.", - "value": t_streak + " parkruns (achieved " + t_last + " " + t_date + ")" + var value = "No parkruns: Yet to start (let's go!)" + if (parkrun_results.length > 0 && longest_streak() == 1) { + value = `1 parkrun: ${parkrun_results[longest_finish].eventlink} (${parkrun_results[longest_finish].datelink})` + } else if (longest_streak() > 1) { + value = `${longest_streak()} parkruns: ${parkrun_results[longest_start].eventlink} (${parkrun_results[longest_start].datelink}) - ${parkrun_results[longest_finish].eventlink} (${parkrun_results[longest_finish].datelink})` } + return { display_name, help, value } } function generate_stat_runs_this_year(parkrun_results) { diff --git a/browser-extensions/common/js/tests/test/test_challenges.js b/browser-extensions/common/js/tests/test/test_challenges.js index 6a747a32..a4fe52e0 100644 --- a/browser-extensions/common/js/tests/test/test_challenges.js +++ b/browser-extensions/common/js/tests/test/test_challenges.js @@ -320,7 +320,7 @@ describe("challenges.js", function() { const parkrunResults = []; it("is expected to be zero", () => { const r = generate_stat_longest_tourism_streak(parkrunResults) - assert.strictEqual(r.value, '0 parkruns (achieved 0)') + assert.strictEqual(r.value, "No parkruns: Yet to start (let's go!)") }) }) @@ -330,7 +330,7 @@ describe("challenges.js", function() { ]; it("is expected to be one", () => { const r = generate_stat_longest_tourism_streak(parkrunResults) - assert.strictEqual(r.value, "1 parkruns (achieved eventa date1)") + assert.strictEqual(r.value, "1 parkrun: eventa (date1)") }) }) @@ -341,7 +341,7 @@ describe("challenges.js", function() { ]; it("is expected to be the latest one", () => { const r = generate_stat_longest_tourism_streak(parkrunResults) - assert.strictEqual(r.value, "1 parkruns (achieved eventa date2)") + assert.strictEqual(r.value, "1 parkrun: eventa (date2)") }) }) @@ -352,7 +352,7 @@ describe("challenges.js", function() { ]; it("is expected to be two", () => { const r = generate_stat_longest_tourism_streak(parkrunResults) - assert.strictEqual(r.value, "2 parkruns (achieved eventb date2)") + assert.strictEqual(r.value, "2 parkruns: eventa (date1) - eventb (date2)") }) }) @@ -364,7 +364,7 @@ describe("challenges.js", function() { ]; it("is expected to remove the first event from the streak", () => { const r = generate_stat_longest_tourism_streak(parkrunResults) - assert.strictEqual(r.value, "2 parkruns (achieved eventa date3)") + assert.strictEqual(r.value, "2 parkruns: eventb (date2) - eventa (date3)") }) }) @@ -376,7 +376,7 @@ describe("challenges.js", function() { ]; it("is expected to end the streak", () => { const r = generate_stat_longest_tourism_streak(parkrunResults) - assert.strictEqual(r.value, "2 parkruns (achieved eventb date2)") + assert.strictEqual(r.value, "2 parkruns: eventa (date1) - eventb (date2)") }) }) @@ -388,7 +388,7 @@ describe("challenges.js", function() { ]; it("is expected to extend the streak", () => { const r = generate_stat_longest_tourism_streak(parkrunResults) - assert.strictEqual(r.value, "3 parkruns (achieved eventc date3)") + assert.strictEqual(r.value, "3 parkruns: eventa (date1) - eventc (date3)") }) }) @@ -401,11 +401,11 @@ describe("challenges.js", function() { ]; it("is expected to be the second streak", () => { const r = generate_stat_longest_tourism_streak(parkrunResults) - assert.strictEqual(r.value, "2 parkruns (achieved eventb date4)") + assert.strictEqual(r.value, "2 parkruns: eventa (date3) - eventb (date4)") }) }) - describe("overlapping streaks (ABC, BCAD, ADCE)", ()=> { + describe("overlapping streaks (ABC, BCAD, ADCE)", () => { const parkrunResults = [ createParkrunResult({ name: "A", datelink: "date1", eventlink: "eventa" }), createParkrunResult({ name: "B", datelink: "date2", eventlink: "eventb" }), @@ -417,7 +417,7 @@ describe("challenges.js", function() { ]; it("is expected to be the latest, longest streak", () => { const r = generate_stat_longest_tourism_streak(parkrunResults) - assert.strictEqual(r.value, "4 parkruns (achieved evente date7)") + assert.strictEqual(r.value, "4 parkruns: eventa (date4) - evente (date7)") }) }) @@ -432,9 +432,10 @@ describe("challenges.js", function() { it("is expected to be the longer streak", () => { const r = generate_stat_longest_tourism_streak(parkrunResults) - assert.strictEqual(r.value, "4 parkruns (achieved eventD date4)") + assert.strictEqual(r.value, "4 parkruns: eventA (date1) - eventD (date4)") }) }) + }) }) From a046f05d4c94afcba458252b60732c3bb3937a49 Mon Sep 17 00:00:00 2001 From: Pete Johns Date: Sun, 14 May 2023 13:15:26 +1000 Subject: [PATCH 7/9] Tyop --- browser-extensions/common/js/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser-extensions/common/js/README.md b/browser-extensions/common/js/README.md index a3e3e8ac..e16e8ae2 100644 --- a/browser-extensions/common/js/README.md +++ b/browser-extensions/common/js/README.md @@ -9,7 +9,7 @@ To run the unit tests locally: ```sh cd browser-extensions/common/js/tests npm install -npm npm run test-with-coverage +npm run test-with-coverage ``` ## Automated browser testing From 78226eb309a046d416999b84abf1295f2a9c69af Mon Sep 17 00:00:00 2001 From: Pete Johns Date: Sun, 14 May 2023 19:28:15 +1000 Subject: [PATCH 8/9] New stat: Current tourism streak --- .../common/js/lib/challenges.js | 36 +++++++++++++++- .../common/js/tests/test/test_challenges.js | 43 +++++++++++++++++++ website/_data/stats.yml | 10 ++++- 3 files changed, 86 insertions(+), 3 deletions(-) diff --git a/browser-extensions/common/js/lib/challenges.js b/browser-extensions/common/js/lib/challenges.js index e6df160f..c3e91991 100644 --- a/browser-extensions/common/js/lib/challenges.js +++ b/browser-extensions/common/js/lib/challenges.js @@ -924,6 +924,39 @@ function generate_stat_longest_tourism_streak(parkrun_results) { return { display_name, help, value } } +function generate_stat_current_tourism_streak(parkrun_results) { + const display_name = "Current tourism streak" + const help = "The number of consecutive different events attended up until the most recent event." + + var finish_index = parkrun_results.length - 1 + var start_index = finish_index + + function has_run_event_in_streak(start, finish, event_name) { + for (var i = start; i <= finish; ++i) { + if (parkrun_results[i].name === event_name) { + return i + } + } + return null + } + + for (;start_index > 0; start_index--) { + if (has_run_event_in_streak(start_index, finish_index, parkrun_results[start_index - 1].name) !== null) { + break + } + } + + const streak = finish_index - start_index + 1 + var value = "No parkruns: Yet to start (let's go!)" + if (parkrun_results.length > 0 && streak == 1) { + value = `1 parkrun: ${parkrun_results[start_index].eventlink} (${parkrun_results[start_index].datelink})` + } else if (streak > 1) { + value = `${streak} parkruns: ${parkrun_results[start_index].eventlink} (${parkrun_results[start_index].datelink}) - ${parkrun_results[finish_index].eventlink} (${parkrun_results[finish_index].datelink})` + } + + return { display_name, help, value } +} + function generate_stat_runs_this_year(parkrun_results) { // Find those parkrun events that have been completed var runs_this_year = 0 @@ -1265,7 +1298,8 @@ function generate_stats(data) { stats['years_parkrunning'] = generate_stat_years_parkrunning(data.parkrun_results) stats['events_run'] = generate_stat_events_run(data.parkrun_results) stats['tourist_quotient'] = generate_stat_tourist_quotient(data.parkrun_results) - stats['tourism_streak'] = generate_stat_longest_tourism_streak(data.parkrun_results) + stats['longest_tourism_streak'] = generate_stat_longest_tourism_streak(data.parkrun_results) + stats['current_tourism_streak'] = generate_stat_current_tourism_streak(data.parkrun_results) } // Stats that need a list of parkruns, and additional geo data to determine where they are diff --git a/browser-extensions/common/js/tests/test/test_challenges.js b/browser-extensions/common/js/tests/test/test_challenges.js index a4fe52e0..4b9c5a90 100644 --- a/browser-extensions/common/js/tests/test/test_challenges.js +++ b/browser-extensions/common/js/tests/test/test_challenges.js @@ -435,7 +435,50 @@ describe("challenges.js", function() { assert.strictEqual(r.value, "4 parkruns: eventA (date1) - eventD (date4)") }) }) + }) + + describe("generate_stat_current_tourism_streak", () => { + const generate_stat_current_tourism_streak = challenges.__get__('generate_stat_current_tourism_streak'); + + describe("given no results", () => { + const parkrunResults = []; + it("is expected to be zero", () => { + const r = generate_stat_current_tourism_streak(parkrunResults) + assert.strictEqual(r.value, "No parkruns: Yet to start (let's go!)") + }) + }) + describe("given one result", () => { + const parkrunResults = [ + createParkrunResult({ name: "A", datelink: "date1", eventlink: "eventa" }) + ]; + it("is expected to be one", () => { + const r = generate_stat_current_tourism_streak(parkrunResults) + assert.strictEqual(r.value, "1 parkrun: eventa (date1)") + }) + }) + + describe("given two identical results", () => { + const parkrunResults = [ + createParkrunResult({ name: "A", datelink: "date1", eventlink: "eventa" }), + createParkrunResult({ name: "A", datelink: "date2", eventlink: "eventa" }) + ]; + it("is expected to be the latest one", () => { + const r = generate_stat_current_tourism_streak(parkrunResults) + assert.strictEqual(r.value, "1 parkrun: eventa (date2)") + }) + }) + + describe("given two different results", () => { + const parkrunResults = [ + createParkrunResult({ name: "A", datelink: "date1", eventlink: "eventa" }), + createParkrunResult({ name: "B", datelink: "date2", eventlink: "eventb" }) + ]; + it("is expected to be two", () => { + const r = generate_stat_current_tourism_streak(parkrunResults) + assert.strictEqual(r.value, "2 parkruns: eventa (date1) - eventb (date2)") + }) + }) }) }) diff --git a/website/_data/stats.yml b/website/_data/stats.yml index 616c54f4..2f93d109 100644 --- a/website/_data/stats.yml +++ b/website/_data/stats.yml @@ -74,12 +74,18 @@ stats: If you never repeat a parkrun event it will be 100%, if you never tourist at all it will tend towards 0%. - - shortname: tourism_streak - name: Tourism streak + - shortname: longest_tourism_streak + name: Longest tourism streak description: >- The longest unbroken run of different events visited. If this happens to include your 'home' parkrun, this still counts in the calculation. + - shortname: current_tourism_streak + name: Current tourism streak + description: >- + The current unbroken run of different events visited. Useful for those + looking to improve on their Longest tourism streak. + - shortname: parkruns_this_year name: parkruns this year description: >- From 528af1410436d51663a49a173da8387a383bbc72 Mon Sep 17 00:00:00 2001 From: Pete Johns Date: Sun, 14 May 2023 19:42:14 +1000 Subject: [PATCH 9/9] Extracts visit_to_event_in_streak() --- .../common/js/lib/challenges.js | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/browser-extensions/common/js/lib/challenges.js b/browser-extensions/common/js/lib/challenges.js index c3e91991..03bdb3cc 100644 --- a/browser-extensions/common/js/lib/challenges.js +++ b/browser-extensions/common/js/lib/challenges.js @@ -886,21 +886,12 @@ function generate_stat_longest_tourism_streak(parkrun_results) { const help = "The highest number of consecutive different events attended." var longest_start = 0, longest_finish = 0, start_index = 0, finish_index = 0; - function has_run_event_in_streak(start, finish, event_name) { - for (var i = start; i < finish; ++i) { - if (parkrun_results[i].name === event_name) { - return i - } - } - return null - } - function longest_streak() { return longest_finish - longest_start + 1 } for (; finish_index < parkrun_results.length; finish_index++) { - previous_visit = has_run_event_in_streak(start_index, finish_index, parkrun_results[finish_index].name) + previous_visit = visit_to_event_in_streak(start_index, finish_index - 1, parkrun_results[finish_index].name, parkrun_results) if (previous_visit !== null) { // If a participant has visited an event multiple times, @@ -931,17 +922,8 @@ function generate_stat_current_tourism_streak(parkrun_results) { var finish_index = parkrun_results.length - 1 var start_index = finish_index - function has_run_event_in_streak(start, finish, event_name) { - for (var i = start; i <= finish; ++i) { - if (parkrun_results[i].name === event_name) { - return i - } - } - return null - } - for (;start_index > 0; start_index--) { - if (has_run_event_in_streak(start_index, finish_index, parkrun_results[start_index - 1].name) !== null) { + if (visit_to_event_in_streak(start_index, finish_index, parkrun_results[start_index - 1].name, parkrun_results) !== null) { break } } @@ -957,6 +939,15 @@ function generate_stat_current_tourism_streak(parkrun_results) { return { display_name, help, value } } +function visit_to_event_in_streak(start, finish, event_name, parkrun_results) { + for (var i = start; i <= finish; ++i) { + if (parkrun_results[i].name === event_name) { + return i + } + } + return null +} + function generate_stat_runs_this_year(parkrun_results) { // Find those parkrun events that have been completed var runs_this_year = 0