diff --git a/index.js b/index.js index bad8385c..b35c5261 100644 --- a/index.js +++ b/index.js @@ -37,7 +37,7 @@ const createClient = (profile, userAgent, opt = {}) => { throw new TypeError('userAgent must be a string'); } - const _stationBoard = (station, type, parse, opt = {}) => { + const _stationBoard = async (station, type, parse, opt = {}) => { if (isObj(station)) station = profile.formatStation(station.id) else if ('string' === typeof station) station = profile.formatStation(station) else throw new TypeError('station must be an object or a string.') @@ -73,25 +73,23 @@ const createClient = (profile, userAgent, opt = {}) => { const req = profile.formatStationBoardReq({profile, opt}, station, type) + const {res, common} = await profile.request({profile, opt}, userAgent, req) + if (!Array.isArray(res.jnyL)) return [] + + const ctx = {profile, opt, common, res} // todo [breaking]: return object with realtimeDataUpdatedAt - return profile.request({profile, opt}, userAgent, req) - .then(({res, common}) => { - if (!Array.isArray(res.jnyL)) return [] - - const ctx = {profile, opt, common, res} - return res.jnyL.map(res => parse(ctx, res)) - .sort((a, b) => new Date(a.when) - new Date(b.when)) // todo - }) + return res.jnyL.map(res => parse(ctx, res)) + .sort((a, b) => new Date(a.when) - new Date(b.when)) // todo } - const departures = (station, opt = {}) => { - return _stationBoard(station, 'DEP', profile.parseDeparture, opt) + const departures = async (station, opt = {}) => { + return await _stationBoard(station, 'DEP', profile.parseDeparture, opt) } - const arrivals = (station, opt = {}) => { - return _stationBoard(station, 'ARR', profile.parseArrival, opt) + const arrivals = async (station, opt = {}) => { + return await _stationBoard(station, 'ARR', profile.parseArrival, opt) } - const journeys = (from, to, opt = {}) => { + const journeys = async (from, to, opt = {}) => { from = profile.formatLocation(profile, from, 'from') to = profile.formatLocation(profile, to, 'to') @@ -210,30 +208,28 @@ const createClient = (profile, userAgent, opt = {}) => { if (opt.results !== null) query.numF = opt.results if (profile.journeysOutFrwd) query.outFrwd = outFrwd - return profile.request({profile, opt}, userAgent, { + const {res, common} = await profile.request({profile, opt}, userAgent, { cfg: {polyEnc: 'GPA'}, meth: 'TripSearch', req: profile.transformJourneysQuery({profile, opt}, query) }) - .then(({res, common}) => { - if (!Array.isArray(res.outConL)) return [] - // todo: outConGrpL + if (!Array.isArray(res.outConL)) return [] + // todo: outConGrpL - const ctx = {profile, opt, common, res} - const journeys = res.outConL - .map(j => profile.parseJourney(ctx, j)) + const ctx = {profile, opt, common, res} + const journeys = res.outConL + .map(j => profile.parseJourney(ctx, j)) - return { - earlierRef: res.outCtxScrB, - laterRef: res.outCtxScrF, - journeys, - // todo [breaking]: rename to realtimeDataUpdatedAt - realtimeDataFrom: res.planrtTS ? parseInt(res.planrtTS) : null, - } - }) + return { + earlierRef: res.outCtxScrB, + laterRef: res.outCtxScrF, + journeys, + // todo [breaking]: rename to realtimeDataUpdatedAt + realtimeDataFrom: res.planrtTS ? parseInt(res.planrtTS) : null, + } } - const refreshJourney = (refreshToken, opt = {}) => { + const refreshJourney = async (refreshToken, opt = {}) => { if ('string' !== typeof refreshToken || !refreshToken) { throw new TypeError('refreshToken must be a non-empty string.') } @@ -250,23 +246,22 @@ const createClient = (profile, userAgent, opt = {}) => { const req = profile.formatRefreshJourneyReq({profile, opt}, refreshToken) - return profile.request({profile, opt}, userAgent, req) - .then(({res, common}) => { - if (!Array.isArray(res.outConL) || !res.outConL[0]) { - const err = new Error('invalid response') - // technically this is not a HAFAS error - // todo: find a different flag with decent DX - err.isHafasError = true - throw err - } + const {res, common} = await profile.request({profile, opt}, userAgent, req) + if (!Array.isArray(res.outConL) || !res.outConL[0]) { + const err = new Error('invalid response') + // technically this is not a HAFAS error + // todo: find a different flag with decent DX + err.isHafasError = true + throw err + } - const ctx = {profile, opt, common, res} - return { - // todo [breaking]: rename to realtimeDataUpdatedAt - realtimeDataFrom: res.planrtTS ? parseInt(res.planrtTS) : null, - ...profile.parseJourney(ctx, res.outConL[0]) - } - }) + const ctx = {profile, opt, common, res} + + return { + // todo [breaking]: rename to realtimeDataUpdatedAt + realtimeDataFrom: res.planrtTS ? parseInt(res.planrtTS) : null, + ...profile.parseJourney(ctx, res.outConL[0]) + } } // Although the DB Navigator app passes the *first* stopover of the trip @@ -392,7 +387,7 @@ const createClient = (profile, userAgent, opt = {}) => { }) } - const locations = (query, opt = {}) => { + const locations = async (query, opt = {}) => { if (!isNonEmptyString(query)) { throw new TypeError('query must be a non-empty string.') } @@ -409,16 +404,14 @@ const createClient = (profile, userAgent, opt = {}) => { const req = profile.formatLocationsReq({profile, opt}, query) - return profile.request({profile, opt}, userAgent, req) - .then(({res, common}) => { - if (!res.match || !Array.isArray(res.match.locL)) return [] + const {res, common} = await profile.request({profile, opt}, userAgent, req) + if (!res.match || !Array.isArray(res.match.locL)) return [] - const ctx = {profile, opt, common, res} - return res.match.locL.map(loc => profile.parseLocation(ctx, loc)) - }) + const ctx = {profile, opt, common, res} + return res.match.locL.map(loc => profile.parseLocation(ctx, loc)) } - const stop = (stop, opt = {}) => { + const stop = async (stop, opt = {}) => { if ('object' === typeof stop) stop = profile.formatStation(stop.id) else if ('string' === typeof stop) stop = profile.formatStation(stop) else throw new TypeError('stop must be an object or a string.') @@ -432,25 +425,23 @@ const createClient = (profile, userAgent, opt = {}) => { const req = profile.formatStopReq({profile, opt}, stop) - return profile.request({profile, opt}, userAgent, req) - .then(({res, common}) => { - if (!res || !Array.isArray(res.locL) || !res.locL[0]) { - // todo: proper stack trace? - // todo: DRY with lib/request.js - const err = new Error('response has no stop') - // technically this is not a HAFAS error - // todo: find a different flag with decent DX - err.isHafasError = true - err.code = INVALID_REQUEST - throw err - } + const {res, common} = await profile.request({profile, opt}, userAgent, req) + if (!res || !Array.isArray(res.locL) || !res.locL[0]) { + // todo: proper stack trace? + // todo: DRY with lib/request.js + const err = new Error('response has no stop') + // technically this is not a HAFAS error + // todo: find a different flag with decent DX + err.isHafasError = true + err.code = INVALID_REQUEST + throw err + } - const ctx = {profile, opt, res, common} - return profile.parseLocation(ctx, res.locL[0]) - }) + const ctx = {profile, opt, res, common} + return profile.parseLocation(ctx, res.locL[0]) } - const nearby = (location, opt = {}) => { + const nearby = async (location, opt = {}) => { validateLocation(location, 'location') opt = Object.assign({ @@ -465,19 +456,18 @@ const createClient = (profile, userAgent, opt = {}) => { const req = profile.formatNearbyReq({profile, opt}, location) - return profile.request({profile, opt}, userAgent, req) - .then(({common, res}) => { - if (!Array.isArray(res.locL)) return [] + const {res, common} = await profile.request({profile, opt}, userAgent, req) + if (!Array.isArray(res.locL)) return [] - // todo: parse `.dur` – walking duration? - const ctx = {profile, opt, common, res} - const results = res.locL.map(loc => profile.parseNearby(ctx, loc)) - return Number.isInteger(opt.results) ? results.slice(0, opt.results) : results - }) + // todo: parse `.dur` – walking duration? + const ctx = {profile, opt, common, res} + const results = res.locL.map(loc => profile.parseNearby(ctx, loc)) + return Number.isInteger(opt.results) + ? results.slice(0, opt.results) + : results } - const trip = (id, lineName, opt = {}) => { - // todo [breaking]: remove lineName param, not needed anymore + const trip = async (id, lineName, opt = {}) => { if (!isNonEmptyString(id)) { throw new TypeError('id must be a non-empty string.') } @@ -495,16 +485,15 @@ const createClient = (profile, userAgent, opt = {}) => { const req = profile.formatTripReq({profile, opt}, id, lineName) + const {res, common} = await profile.request({profile, opt}, userAgent, req) + const ctx = {profile, opt, common, res} + // todo [breaking]: return object with realtimeDataUpdatedAt - return profile.request({profile, opt}, userAgent, req) - .then(({common, res}) => { - const ctx = {profile, opt, common, res} - return profile.parseTrip(ctx, res.journey) - }) + return profile.parseTrip(ctx, res.journey) } // todo [breaking]: rename to trips()? - const tripsByName = (lineNameOrFahrtNr = '*', opt = {}) => { + const tripsByName = async (lineNameOrFahrtNr = '*', opt = {}) => { if (!isNonEmptyString(lineNameOrFahrtNr)) { throw new TypeError('lineNameOrFahrtNr must be a non-empty string.') } @@ -572,20 +561,19 @@ const createClient = (profile, userAgent, opt = {}) => { } req.jnyFltrL = [...req.jnyFltrL, ...opt.additionalFilters] - // todo [breaking]: return object with realtimeDataUpdatedAt - return profile.request({profile, opt}, userAgent, { + const {res, common} = await profile.request({profile, opt}, userAgent, { cfg: {polyEnc: 'GPA'}, meth: 'JourneyMatch', req, }) // todo [breaking]: catch `NO_MATCH` errors, return [] - .then(({res, common}) => { - const ctx = {profile, opt, common, res} - return res.jnyL.map(t => profile.parseTrip(ctx, t)) - }) + const ctx = {profile, opt, common, res} + + // todo [breaking]: return object with realtimeDataUpdatedAt + return res.jnyL.map(t => profile.parseTrip(ctx, t)) } - const radar = ({north, west, south, east}, opt) => { + const radar = async ({north, west, south, east}, opt) => { if ('number' !== typeof north) throw new TypeError('north must be a number.') if ('number' !== typeof west) throw new TypeError('west must be a number.') if ('number' !== typeof south) throw new TypeError('south must be a number.') @@ -608,14 +596,12 @@ const createClient = (profile, userAgent, opt = {}) => { const req = profile.formatRadarReq({profile, opt}, north, west, south, east) - // todo [breaking]: return object with realtimeDataUpdatedAt - return profile.request({profile, opt}, userAgent, req) - .then(({res, common}) => { - if (!Array.isArray(res.jnyL)) return [] + const {res, common} = await profile.request({profile, opt}, userAgent, req) + if (!Array.isArray(res.jnyL)) return [] + const ctx = {profile, opt, common, res} - const ctx = {profile, opt, common, res} - return res.jnyL.map(m => profile.parseMovement(ctx, m)) - }) + // todo [breaking]: return object with realtimeDataUpdatedAt + return res.jnyL.map(m => profile.parseMovement(ctx, m)) } const reachableFrom = async (address, opt = {}) => { diff --git a/test/e2e/bvg.js b/test/e2e/bvg.js index b44a1e3a..8b221159 100644 --- a/test/e2e/bvg.js +++ b/test/e2e/bvg.js @@ -114,8 +114,8 @@ tap.test('journeys – only subway', async (t) => { t.end() }) -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: spichernstr, diff --git a/test/e2e/cfl.js b/test/e2e/cfl.js index 3e4a55fb..c65d48f0 100644 --- a/test/e2e/cfl.js +++ b/test/e2e/cfl.js @@ -92,8 +92,8 @@ tap.test('journeys – Ettelbruck to Luxembourg', async (t) => { // todo: journeys, only one product -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: ettelbruck, diff --git a/test/e2e/cmta.js b/test/e2e/cmta.js index 8606bef2..e0df75f7 100644 --- a/test/e2e/cmta.js +++ b/test/e2e/cmta.js @@ -58,8 +58,8 @@ tap.test('journeys – Broadie Oaks to Domain', async (t) => { // todo: journeys, only one product -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: broadieOaks, diff --git a/test/e2e/db.js b/test/e2e/db.js index d27e346c..f46809f3 100644 --- a/test/e2e/db.js +++ b/test/e2e/db.js @@ -104,8 +104,8 @@ tap.test('journeys – Berlin Schwedter Str. to München Hbf', async (t) => { // todo: journeys, only one product -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: blnSchwedterStr, diff --git a/test/e2e/hvv.js b/test/e2e/hvv.js index 866f89fd..6428846d 100644 --- a/test/e2e/hvv.js +++ b/test/e2e/hvv.js @@ -60,8 +60,8 @@ tap.skip('journeys – Hamburg Tiefstack to Hamburg Barmbek', async (t) => { // todo: journeys, only one product -tap.skip('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.skip('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: tiefstack, diff --git a/test/e2e/insa.js b/test/e2e/insa.js index 0b58b9db..cabbf2c7 100644 --- a/test/e2e/insa.js +++ b/test/e2e/insa.js @@ -79,8 +79,8 @@ tap.test('journeys – Magdeburg Hbf to Magdeburg-Buckau', async (t) => { // todo: journeys, only one product -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: magdeburgHbf, diff --git a/test/e2e/invg.js b/test/e2e/invg.js index 34368f20..643f5d84 100644 --- a/test/e2e/invg.js +++ b/test/e2e/invg.js @@ -78,8 +78,8 @@ tap.test('journeys – Ingolstadt Hbf to Audi Parkplatz', async (t) => { // todo: journeys, only one product -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: ingolstadtHbf, diff --git a/test/e2e/lib/earlier-later-journeys.js b/test/e2e/lib/earlier-later-journeys.js index 2b20321e..a8fb04a3 100644 --- a/test/e2e/lib/earlier-later-journeys.js +++ b/test/e2e/lib/earlier-later-journeys.js @@ -21,33 +21,25 @@ const testEarlierLaterJourneys = async (cfg) => { t.ok(model.laterRef) // departure/arrival and earlierThan/laterThan should be mutually exclusive - t.throws(() => { - fetchJourneys(fromId, toId, { + await t.rejects(async () => { + await fetchJourneys(fromId, toId, { departure: when, earlierThan: model.earlierRef }) - // silence rejections, we're only interested in exceptions - .catch(() => {}) }) - t.throws(() => { - fetchJourneys(fromId, toId, { + await t.rejects(async () => { + await fetchJourneys(fromId, toId, { departure: when, laterThan: model.laterRef }) - // silence rejections, we're only interested in exceptions - .catch(() => {}) }) - t.throws(() => { - fetchJourneys(fromId, toId, { + await t.rejects(async () => { + await fetchJourneys(fromId, toId, { arrival: when, earlierThan: model.earlierRef }) - // silence rejections, we're only interested in exceptions - .catch(() => {}) }) - t.throws(() => { - fetchJourneys(fromId, toId, { + await t.rejects(async () => { + await fetchJourneys(fromId, toId, { arrival: when, laterThan: model.laterRef }) - // silence rejections, we're only interested in exceptions - .catch(() => {}) }) let earliestDep = Infinity, latestDep = -Infinity diff --git a/test/e2e/lib/journeys-fails-with-no-product.js b/test/e2e/lib/journeys-fails-with-no-product.js index 052b0643..3a2dae85 100644 --- a/test/e2e/lib/journeys-fails-with-no-product.js +++ b/test/e2e/lib/journeys-fails-with-no-product.js @@ -1,6 +1,6 @@ 'use strict' -const journeysFailsWithNoProduct = (cfg) => { +const journeysFailsWithNoProduct = async (cfg) => { const { test: t, fetchJourneys, @@ -13,11 +13,9 @@ const journeysFailsWithNoProduct = (cfg) => { const noProducts = Object.create(null) for (let p of products) noProducts[p.id] = false - t.throws(() => { - fetchJourneys(fromId, toId, {departure: when, products: noProducts}) - // silence rejections, we're only interested in exceptions - .catch(() => {}) - }, 'no products used') + await t.rejects(async () => { + await fetchJourneys(fromId, toId, {departure: when, products: noProducts}) + }) } module.exports = journeysFailsWithNoProduct diff --git a/test/e2e/mobiliteit-lu.js b/test/e2e/mobiliteit-lu.js index 1a4cd2ca..14ada800 100644 --- a/test/e2e/mobiliteit-lu.js +++ b/test/e2e/mobiliteit-lu.js @@ -96,8 +96,8 @@ tap.test('journeys – Ettelbruck to Luxembourg', async (t) => { // todo: journeys, only one product -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: ettelbruck, diff --git a/test/e2e/nahsh.js b/test/e2e/nahsh.js index 81a4281d..25745346 100644 --- a/test/e2e/nahsh.js +++ b/test/e2e/nahsh.js @@ -101,8 +101,8 @@ tap.test('journeys – Kiel Hbf to Flensburg', async (t) => { // todo: journeys, only one product -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: kielHbf, diff --git a/test/e2e/nvv.js b/test/e2e/nvv.js index c786600b..482adfae 100644 --- a/test/e2e/nvv.js +++ b/test/e2e/nvv.js @@ -60,8 +60,8 @@ tap.test('journeys – Kassel Scheidemannplatz to Kassel Auestadion', async (t) // todo: journeys, only one product -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: scheidemannplatz, diff --git a/test/e2e/oebb.js b/test/e2e/oebb.js index d71c90a0..283b80fc 100644 --- a/test/e2e/oebb.js +++ b/test/e2e/oebb.js @@ -89,8 +89,8 @@ tap.test('journeys – Salzburg Hbf to Wien Westbahnhof', async (t) => { // todo: journeys, only one product -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: salzburgHbf, diff --git a/test/e2e/rejseplanen.js b/test/e2e/rejseplanen.js index f4e99c70..a253ea2d 100644 --- a/test/e2e/rejseplanen.js +++ b/test/e2e/rejseplanen.js @@ -52,8 +52,8 @@ tap.test('journeys – Næstved to Aalborg', async (t) => { // todo: journeys, only one product -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: næstved, diff --git a/test/e2e/saarfahrplan.js b/test/e2e/saarfahrplan.js index 4ad28079..8f8842ec 100644 --- a/test/e2e/saarfahrplan.js +++ b/test/e2e/saarfahrplan.js @@ -69,8 +69,8 @@ const thomasMannStr = { // @todo prices/tickets // @todo journeys, only one product -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: saarbrueckenHbf, diff --git a/test/e2e/sbahn-muenchen.js b/test/e2e/sbahn-muenchen.js index cb9b451d..64939adc 100644 --- a/test/e2e/sbahn-muenchen.js +++ b/test/e2e/sbahn-muenchen.js @@ -80,8 +80,8 @@ tap.test('journeys – Mittersendling to Karl-Theodor-Straße', async (t) => { // todo: journeys, only one product -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: mittersendling, diff --git a/test/e2e/vbb.js b/test/e2e/vbb.js index 3417ccc8..4e1d18b7 100644 --- a/test/e2e/vbb.js +++ b/test/e2e/vbb.js @@ -110,8 +110,8 @@ tap.test('journeys – only subway', async (t) => { // todo: journeys – with arrival time -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: spichernstr, diff --git a/test/e2e/vrn.js b/test/e2e/vrn.js index 0a4084e1..24cfea26 100644 --- a/test/e2e/vrn.js +++ b/test/e2e/vrn.js @@ -56,8 +56,8 @@ tap.test('journeys – Ludwigshafen to Meckesheim', async (t) => { // todo: journeys, only one product -tap.test('journeys – fails with no product', (t) => { - journeysFailsWithNoProduct({ +tap.test('journeys – fails with no product', async (t) => { + await journeysFailsWithNoProduct({ test: t, fetchJourneys: client.journeys, fromId: ludwigshafen,