From d0bdb190b418b72ea1dbca8ab95a554160591a1c Mon Sep 17 00:00:00 2001 From: Pete Johns Date: Sat, 13 May 2023 15:51:04 +1000 Subject: [PATCH 1/7] 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/7] 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/7] 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/7] 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/7] 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/7] 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/7] 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