Repository: osmlab/maproulette3
Pull request #1287 (2020-06-23 15:31:39)

Upgrade to node v12


Patch:
diff --git a/.nvmrc b/.nvmrc
index 571500f8..48082f72 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1,1 +1,1 @@
-nvm use 10
+12
diff --git a/.travis.yml b/.travis.yml
index 57c31e3e..2716afeb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,8 @@
 language: node_js
 sudo: false
 node_js:
-  - "10"
+  - 10
+  - 12
 env:
   - NODE_OPTIONS="--max-old-space-size=4096"
 cache:
diff --git a/README.md b/README.md
index 5d36b3e4..ab60d576 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ not use the production server for development purposes.**
 
 ### Basic Dependencies:
 
-* [Node 10 LTS](https://nodejs.org/)
+* [Node 12 LTS](https://nodejs.org/)
 * [yarn](https://yarnpkg.com/)
 * [jq](https://stedolan.github.io/jq/)
 * [curl](https://curl.haxx.se/)
diff --git a/src/components/HOCs/WithCurrentTask/WithCurrentTask.js b/src/components/HOCs/WithCurrentTask/WithCurrentTask.js
index 12900505..64abab0a 100644
--- a/src/components/HOCs/WithCurrentTask/WithCurrentTask.js
+++ b/src/components/HOCs/WithCurrentTask/WithCurrentTask.js
@@ -178,7 +178,7 @@ export const mapDispatchToProps = (dispatch, ownProps) => {
             nextRequestedTask(dispatch, ownProps, requestedNextTask) :
             nextRandomTask(dispatch, ownProps, taskId, taskLoadBy)
 
-          loadNextTask.then(newTask =>
+          return loadNextTask.then(newTask =>
             visitNewTask(dispatch, ownProps, taskId, newTask)
           ).catch(error => {
             ownProps.history.push(`/browse/challenges/${challengeId}`)
@@ -359,16 +359,18 @@ export const visitNewTask = function(dispatch, props, currentTaskId, newTask) {
       const challengeId = challengeIdFromRoute(props, props.challengeId)
       props.history.push(`/challenge/${challengeId}/task/${newTask.id}`)
     }
+    return Promise.resolve()
   }
   else {
     // If challenge is complete, redirect home with note to congratulate user
     if (_isFinite(props.virtualChallengeId)) {
       // We don't get a status for virtual challenges, so just assume we're done
       props.history.push('/browse/challenges', {congratulate: true, warn: false})
+      return Promise.resolve()
     }
     else {
       const challengeId = challengeIdFromRoute(props, props.challengeId)
-      dispatch(fetchChallenge(challengeId)).then( normalizedResults => {
+      return dispatch(fetchChallenge(challengeId)).then(normalizedResults => {
         const challenge = normalizedResults.entities.challenges[normalizedResults.result]
         if (challenge.status === CHALLENGE_STATUS_FINISHED) {
           props.history.push('/browse/challenges', {congratulate: true, warn: false})
diff --git a/src/lang/en-US.json b/src/lang/en-US.json
index 48943cf6..8e6bf6c9 100644
--- a/src/lang/en-US.json
+++ b/src/lang/en-US.json
@@ -146,7 +146,7 @@
   "Admin.EditChallenge.form.step1.label": "General",
   "Admin.EditChallenge.form.step2.description": "\nEvery Task in MapRoulette basically consists of a geometry: a point, line or\npolygon indicating on the map what it is that you want the mapper to evaluate.\nThis screen lets you define the Tasks for your Challenge by telling MapRoulette\nabout the geometries.\n\nThere are three ways to feed geometries into your challenge: via an Overpass\nquery, via a GeoJSON file on your computer, or via a URL pointing to a GeoJSON\nfile on the internet.\n\n#### Via Overpass\n\nThe Overpass API is a powerful querying interface for OpenStreetMap data. It\ndoes not work on the live OSM database, but the data you get from Overpass is\nusually just a few minutes old. Using\n[Overpass QL](https://wiki.openstreetmap.org/wiki/Overpass_API/Language_Guide),\nthe Overpass Query Language, you can define exactly which OSM objects you want\nto load into your Challenge as Tasks.\n[Learn more on the wiki](https://github.com/osmlab/maproulette3/wiki/Using-Overpass-queries-to-create-Challenges).\n\n#### Via Local GeoJSON File\n\nThe other option is to use a GeoJSON file you already have. This could be great\nif you have an approved source of external data you would like to manually add\nto OSM. Tools like\n[QGIS](https://gis.stackexchange.com/questions/91812/convert-shapefiles-to-geojson)\nand [gdal](http://www.gdal.org/drv_geojson.html) can convert things like\nShapefiles to GeoJSON.  When you convert, make sure that you use unprojected\nlon/lat on the WGS84 datum (EPSG:4326), because this is what MapRoulette uses\ninternally.\n\n> Note: for challenges with a large number of tasks, we recommend using a\n[line-by-line](https://github.com/osmlab/maproulette3/wiki/Line-by-Line-GeoJSON-Format)\nformat instead, which is much less memory-intensive to process.\n\n#### Via Remote GeoJSON URL\n\nThe only difference between using a local GeoJSON file and a URL is where you\ntell MapRoulette to get it from. If you use a URL, make sure you point to the\nraw GeoJSON file, not a page that contains a link to the file, or MapRoulette\nwill not be able to make sense of it.\n    ",
   "Admin.EditChallenge.form.step2.label": "GeoJSON Source",
-  "Admin.EditChallenge.form.step3.description": "The priority of tasks can be defined as High, Medium and Low. All high priority tasks will be offered to users first when working through a challenge, followed by medium and finally low priority tasks. Each task’s priority is assigned automatically based on the rules you specify below, each of which is evaluated against the task’s feature properties (OSM tags if you are using an Overpass query, otherwise whatever properties youve chosen to include in your GeoJSON). Tasks that don’t pass any rules will be assigned the default priority.",
+  "Admin.EditChallenge.form.step3.description": "The priority of tasks can be defined as High, Medium and Low. All high priority tasks will be offered to users first when working through a challenge, followed by medium and finally low priority tasks. Each task’s priority is assigned automatically based on the rules you specify below, each of which is evaluated against the task’s feature properties (OSM tags if you are using an Overpass query, otherwise whatever properties you’ve chosen to include in your GeoJSON). Tasks that don’t pass any rules will be assigned the default priority.",
   "Admin.EditChallenge.form.step3.label": "Priorities",
   "Admin.EditChallenge.form.step4.description": "Extra information that can be optionally set to give a better mapping experience specific to the requirements of the challenge",
   "Admin.EditChallenge.form.step4.label": "Extra",
@@ -849,7 +849,6 @@
   "Metrics.reviewedTasksTitle": "Review Status",
   "Metrics.reviewedTasksTitle.asReviewer": "Tasks Reviewed by {username}",
   "Metrics.reviewedTasksTitle.asReviewer.you": "Tasks Reviewed by You",
-  "Metrics.tasks.evaluatedByUser.label": "Tasks Evaluated by Users",
   "Metrics.totalCompletedTasksTitle": "Total Completed Tasks",
   "Metrics.userOptedOut": "This user has opted out of public display of their stats.",
   "Metrics.userSince": "User since:",


Test patch:
diff --git a/src/components/HOCs/WithCurrentTask/WithCurrentTask.test.js b/src/components/HOCs/WithCurrentTask/WithCurrentTask.test.js
index ce515db7..bd8e4b02 100644
--- a/src/components/HOCs/WithCurrentTask/WithCurrentTask.test.js
+++ b/src/components/HOCs/WithCurrentTask/WithCurrentTask.test.js
@@ -10,7 +10,10 @@ import { taskDenormalizationSchema,
          completeTask } from '../../../services/Task/Task'
 import { TaskLoadMethod }
        from '../../../services/Task/TaskLoadMethod/TaskLoadMethod'
-import { fetchChallengeActions } from '../../../services/Challenge/Challenge'
+import { fetchChallengeActions, fetchChallenge }
+       from '../../../services/Challenge/Challenge'
+import { CHALLENGE_STATUS_READY, CHALLENGE_STATUS_FINISHED }
+       from '../../../services/Challenge/ChallengeStatus/ChallengeStatus'
 
 jest.mock('normalizr')
 jest.mock('../../../services/Task/Task')
@@ -194,6 +197,17 @@ test("completeTask routes the user to challenge page if the next task isn't new"
 
   completeTask.mockReturnValueOnce(Promise.resolve())
   loadRandomTaskFromChallenge.mockReturnValueOnce(Promise.resolve(nextTask))
+  fetchChallenge.mockReturnValueOnce(Promise.resolve({
+    entities: {
+      challenges: {
+        "123": {
+          id: 123,
+          status: CHALLENGE_STATUS_READY,
+        }
+      },
+    },
+    result: "123",
+  }))
   const dispatch = jest.fn(value => value)
   const history = {
     push: jest.fn(),
@@ -202,12 +216,23 @@ test("completeTask routes the user to challenge page if the next task isn't new"
   const mappedProps = mapDispatchToProps(dispatch, {history})
 
   await mappedProps.completeTask(task, challenge.id, completionStatus, null, null, TaskLoadMethod.random)
-  expect(history.push).toBeCalledWith(`/browse/challenges/${challenge.id}`)
+  expect(history.push).toHaveBeenCalledWith('/browse/challenges', {warn: true, congratulate: false})
 })
 
 test("completeTask routes the user to challenge page if there is no next task", async () => {
   completeTask.mockReturnValueOnce(Promise.resolve())
   loadRandomTaskFromChallenge.mockReturnValueOnce(Promise.resolve(null))
+  fetchChallenge.mockReturnValueOnce(Promise.resolve({
+    entities: {
+      challenges: {
+        "123": {
+          id: 123,
+          status: CHALLENGE_STATUS_READY,
+        }
+      },
+    },
+    result: "123",
+  }))
   const dispatch = jest.fn(value => value)
   const history = {
     push: jest.fn(),
@@ -216,5 +241,5 @@ test("completeTask routes the user to challenge page if there is no next task",
   const mappedProps = mapDispatchToProps(dispatch, {history})
 
   await mappedProps.completeTask(task, challenge.id, completionStatus, null, null, TaskLoadMethod.random)
-  expect(history.push).toBeCalledWith(`/browse/challenges/${challenge.id}`)
+  expect(history.push).toHaveBeenCalledWith('/browse/challenges', {warn: true, congratulate: false})
 })