diff --git a/packages/core-utils/src/__tests__/__snapshots__/query.js.snap b/packages/core-utils/src/__tests__/__snapshots__/query.js.snap index 8d52797df..76b93a2e2 100644 --- a/packages/core-utils/src/__tests__/__snapshots__/query.js.snap +++ b/packages/core-utils/src/__tests__/__snapshots__/query.js.snap @@ -60,6 +60,58 @@ Object { } `; +exports[`query getRoutingParams should create repaired routing params for broken flex query 1`] = ` +Object { + "arriveBy": false, + "date": "2020-08-24", + "fromPlace": "Steamer Lane, Santa Cruz, CA, 95060, USA::36.95471026341096,-122.0248185852425", + "ignoreRealtimeUpdates": false, + "maxWalkDistance": 1207, + "mode": "WALK,FLEX_EGRESS,FLEX_ACCESS,FLEX_DIRECT,TRANSIT", + "numItineraries": 3, + "optimize": "QUICK", + "otherThanPreferredRoutesPenalty": 900, + "showIntermediateStops": true, + "time": "21:53", + "toPlace": "Municipal Wharf St, Santa Cruz, CA, 95060, USA::36.961843106786766,-122.02402657342725", + "walkSpeed": 1.34, +} +`; + +exports[`query getRoutingParams should create repaired routing params for very broken flex query 1`] = ` +Object { + "arriveBy": false, + "date": "2020-08-24", + "fromPlace": "Steamer Lane, Santa Cruz, CA, 95060, USA::36.95471026341096,-122.0248185852425", + "ignoreRealtimeUpdates": false, + "mode": "FLEX_EGRESS,FLEX_ACCESS,FLEX_DIRECT,WALK,BIKE", + "numItineraries": 3, + "otherThanPreferredRoutesPenalty": 900, + "showIntermediateStops": true, + "time": "21:53", + "toPlace": "Municipal Wharf St, Santa Cruz, CA, 95060, USA::36.961843106786766,-122.02402657342725", + "walkSpeed": 1.34, +} +`; + +exports[`query getRoutingParams should create repaired routing params for very broken flex query 2`] = ` +Object { + "arriveBy": false, + "date": "2020-08-24", + "fromPlace": "Steamer Lane, Santa Cruz, CA, 95060, USA::36.95471026341096,-122.0248185852425", + "ignoreRealtimeUpdates": false, + "maxWalkDistance": 1207, + "mode": "FLEX_EGRESS,FLEX_ACCESS,FLEX_DIRECT,WALK,BIKE,WALK,TRANSIT,BUS", + "numItineraries": 3, + "optimize": "QUICK", + "otherThanPreferredRoutesPenalty": 900, + "showIntermediateStops": true, + "time": "21:53", + "toPlace": "Municipal Wharf St, Santa Cruz, CA, 95060, USA::36.961843106786766,-122.02402657342725", + "walkSpeed": 1.34, +} +`; + exports[`query getRoutingParams should create routing params for car rental query 1`] = ` Object { "arriveBy": false, @@ -80,6 +132,21 @@ Object { } `; +exports[`query getRoutingParams should create routing params for flex-only query 1`] = ` +Object { + "arriveBy": false, + "date": "2020-08-24", + "fromPlace": "Steamer Lane, Santa Cruz, CA, 95060, USA::36.95471026341096,-122.0248185852425", + "ignoreRealtimeUpdates": false, + "mode": "FLEX_EGRESS,FLEX_ACCESS,FLEX_DIRECT", + "numItineraries": 3, + "otherThanPreferredRoutesPenalty": 900, + "showIntermediateStops": true, + "time": "21:53", + "toPlace": "Municipal Wharf St, Santa Cruz, CA, 95060, USA::36.961843106786766,-122.02402657342725", +} +`; + exports[`query getRoutingParams should create routing params for intermediate places query 1`] = ` Object { "arriveBy": false, @@ -124,6 +191,39 @@ Object { } `; +exports[`query getRoutingParams should create routing params for standard flex query 1`] = ` +Object { + "arriveBy": false, + "date": "2020-08-24", + "fromPlace": "Steamer Lane, Santa Cruz, CA, 95060, USA::36.95471026341096,-122.0248185852425", + "ignoreRealtimeUpdates": false, + "maxWalkDistance": 1207, + "mode": "WALK,TRANSIT,FLEX_EGRESS,FLEX_ACCESS,FLEX_DIRECT", + "numItineraries": 3, + "optimize": "QUICK", + "otherThanPreferredRoutesPenalty": 900, + "showIntermediateStops": true, + "time": "21:53", + "toPlace": "Municipal Wharf St, Santa Cruz, CA, 95060, USA::36.961843106786766,-122.02402657342725", + "walkSpeed": 1.34, +} +`; + +exports[`query getRoutingParams should create routing params for standard flex query 2`] = ` +Object { + "arriveBy": false, + "date": "2020-08-24", + "fromPlace": "Steamer Lane, Santa Cruz, CA, 95060, USA::36.95471026341096,-122.0248185852425", + "ignoreRealtimeUpdates": false, + "mode": "FLEX_EGRESS,FLEX_ACCESS,FLEX_DIRECT", + "numItineraries": 3, + "otherThanPreferredRoutesPenalty": 900, + "showIntermediateStops": true, + "time": "21:53", + "toPlace": "Municipal Wharf St, Santa Cruz, CA, 95060, USA::36.961843106786766,-122.02402657342725", +} +`; + exports[`query getRoutingParams should create routing params for transit query 1`] = ` Object { "arriveBy": false, diff --git a/packages/core-utils/src/__tests__/query-params.js b/packages/core-utils/src/__tests__/query-params.js index 1ad5d7b93..3be578a84 100644 --- a/packages/core-utils/src/__tests__/query-params.js +++ b/packages/core-utils/src/__tests__/query-params.js @@ -1,3 +1,4 @@ +import { reduceOtpFlexModes } from "../query"; import queryParams, { getCustomQueryParams } from "../query-params"; const customWalkDistanceOptions = [ @@ -38,3 +39,55 @@ describe("query-params", () => { }); }); }); + +describe("flex-reducer", () => { + it("should not touch a query that doesn't include flex modes", () => { + expect(reduceOtpFlexModes(["WALK", "TRANSIT", "BIKE"])).toStrictEqual([ + "WALK", + "TRANSIT", + "BIKE" + ]); + }); + it("should modify a query that includes some flex modes", () => { + expect( + reduceOtpFlexModes(["WALK", "TRANSIT", "BIKE", "FLEX_DIRECT"]) + ).toStrictEqual(["WALK", "TRANSIT", "BIKE", "FLEX"]); + }); + it("should modify a query that includes all flex modes", () => { + expect( + reduceOtpFlexModes([ + "WALK", + "TRANSIT", + "BIKE", + "FLEX_DIRECT", + "FLEX_ACCESS", + "FLEX_EGRESS" + ]) + ).toStrictEqual(["WALK", "TRANSIT", "BIKE", "FLEX"]); + expect( + reduceOtpFlexModes([ + "FLEX_DIRECT", + "BIKE", + "FLEX_ACCESS", + "WALK", + "FLEX_EGRESS", + "TRANSIT" + ]) + ).toStrictEqual(["FLEX", "BIKE", "WALK", "TRANSIT"]); + }); + it("should modify a query that includes only flex modes", () => { + expect( + reduceOtpFlexModes(["FLEX_DIRECT", "FLEX_ACCESS", "FLEX_EGRESS"]) + ).toStrictEqual(["FLEX"]); + }); + it("should modify a query that includes duplicate flex modes", () => { + expect( + reduceOtpFlexModes([ + "FLEX_DIRECT", + "FLEX_DIRECT", + "FLEX_ACCESS", + "FLEX_EGRESS" + ]) + ).toStrictEqual(["FLEX"]); + }); +}); diff --git a/packages/core-utils/src/__tests__/query.js b/packages/core-utils/src/__tests__/query.js index 0dbaf6c05..ebc217257 100644 --- a/packages/core-utils/src/__tests__/query.js +++ b/packages/core-utils/src/__tests__/query.js @@ -102,6 +102,58 @@ describe("query", () => { }) ).toMatchSnapshot(); }); + + it("should create routing params for standard flex query", () => { + expect( + getRoutingParams(fakeConfig, { + ...makeBaseTestQuery(), + mode: "WALK,TRANSIT,FLEX" + }) + ).toMatchSnapshot(); + }); + + it("should create repaired routing params for broken flex query", () => { + expect( + getRoutingParams(fakeConfig, { + ...makeBaseTestQuery(), + mode: "WALK,FLEX_DIRECT,TRANSIT,FLEX" + }) + ).toMatchSnapshot(); + }); + + it("should create routing params for flex-only query", () => { + expect( + getRoutingParams(fakeConfig, { + ...makeBaseTestQuery(), + mode: "FLEX" + }) + ).toMatchSnapshot(); + }); + + it("should create routing params for standard flex query", () => { + expect( + getRoutingParams(fakeConfig, { + ...makeBaseTestQuery(), + mode: "FLEX_EGRESS,FLEX_ACCESS,FLEX_DIRECT" + }) + ).toMatchSnapshot(); + }); + + it("should create repaired routing params for very broken flex query", () => { + expect( + getRoutingParams(fakeConfig, { + ...makeBaseTestQuery(), + mode: "FLEX_EGRESS,FLEX_ACCESS,FLEX_DIRECT,FLEX,WALK,BIKE" + }) + ).toMatchSnapshot(); + expect( + getRoutingParams(fakeConfig, { + ...makeBaseTestQuery(), + mode: + "FLEX_EGRESS,FLEX,FLEX_EGRESS,FLEX_ACCESS,FLEX_DIRECT,FLEX,WALK,BIKE,WALK,TRANSIT,BUS" + }) + ).toMatchSnapshot(); + }); }); describe("isNotDefaultQuery", () => { diff --git a/packages/core-utils/src/query.js b/packages/core-utils/src/query.js index 1f1d8432d..9fe6e41dc 100644 --- a/packages/core-utils/src/query.js +++ b/packages/core-utils/src/query.js @@ -182,6 +182,28 @@ export function reduceOtpFlexModes(modes) { }, []); } +/** + * Helper method to process a mode string, replacing all instances of FLEX + * with the full set of FLEX modes used by otp-2 + * @param {*} mode a mode String, not an array + * @returns a mode String, not an array (with flex modes expanded) + */ +export function expandOtpFlexMode(mode) { + const modes = reduceOtpFlexModes(mode.split(",")); + return modes + .map(m => { + // If both the expanded and shrunk modes are included, remove the exapnded one + if (m === "FLEX_EGRESS" || m === "FLEX_ACCESS" || m === "FLEX_DIRECT") { + if (mode.includes("FLEX")) return ""; + } + if (m === "FLEX") { + return "FLEX_EGRESS,FLEX_ACCESS,FLEX_DIRECT"; + } + return m; + }) + .join(","); +} + /** * Determines whether the specified query differs from the default query, i.e., * whether the user has modified any trip options (including mode) from their @@ -466,8 +488,8 @@ export function getRoutingParams(config, currentQuery, ignoreRealtimeUpdates) { // Replace FLEX placeholder with OTP flex modes if (params.mode) { // Ensure query is in reduced format to avoid replacing twice - const mode = reduceOtpFlexModes(params.mode.split(",")).join(","); - params.mode = mode.replace("FLEX", "FLEX_EGRESS,FLEX_ACCESS,FLEX_DIRECT"); + const reducedMode = reduceOtpFlexModes(params.mode.split(",")).join(","); + params.mode = expandOtpFlexMode(reducedMode); } return params;