Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 41 additions & 17 deletions browser-extensions/common/js/README.md
Original file line number Diff line number Diff line change
@@ -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 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"
```
```

<!-- Links for this document -->
[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
95 changes: 59 additions & 36 deletions browser-extensions/common/js/lib/challenges.js
Original file line number Diff line number Diff line change
Expand Up @@ -880,49 +880,71 @@ 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 longest_streak() {
return longest_finish - longest_start + 1
}

event_streak.splice(0,f+1)
for (; finish_index < parkrun_results.length; finish_index++) {
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,
// 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_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

for (;start_index > 0; start_index--) {
if (visit_to_event_in_streak(start_index, finish_index, parkrun_results[start_index - 1].name, parkrun_results) !== 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 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) {
Expand Down Expand Up @@ -1266,7 +1288,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
Expand Down
177 changes: 170 additions & 7 deletions browser-extensions/common/js/tests/test/test_challenges.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ function getNextParkrunDate() {
}

function createParkrunResult(specificData) {
parkrunResult = {
return {
name: "Fell Foot",
eventlink: "<a href\"https://www.parkrun.org.uk/fellfoot/results\">Fell Foot</a>",
date: "22/11/2014",
Expand All @@ -145,13 +145,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()
Expand Down Expand Up @@ -312,6 +308,173 @@ 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.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_longest_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_longest_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_longest_tourism_streak(parkrunResults)
assert.strictEqual(r.value, "2 parkruns: eventa (date1) - 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: eventb (date2) - 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: eventa (date1) - 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: eventa (date1) - 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: eventa (date3) - 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: eventa (date4) - 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: 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)")
})
})
})
})

describe("challenges", function() {
Expand Down
4 changes: 4 additions & 0 deletions build/extension-firefox/build.sh
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Loading