mirror of
https://github.com/public-transport/db-vendo-client.git
synced 2025-02-23 07:09:35 +02:00
merge #57: rewrite the tests
This commit is contained in:
commit
47155cdb83
20 changed files with 1468 additions and 1752 deletions
|
@ -62,7 +62,11 @@ const createParseJourney = (profile, stations, lines, remarks, polylines) => {
|
|||
) {
|
||||
const tariff = j.trfRes.fareSetL[0].fareL[0]
|
||||
if (tariff.prc >= 0) { // wat
|
||||
res.price = {amount: tariff.prc / 100, hint: null}
|
||||
res.price = {
|
||||
amount: tariff.prc / 100,
|
||||
currency: 'EUR',
|
||||
hint: null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
"tap-spec": "^4.1.1",
|
||||
"tape": "^4.8.0",
|
||||
"tape-promise": "^3.0.0",
|
||||
"validate-fptf": "^1.2.1",
|
||||
"validate-fptf": "^2.0.1",
|
||||
"vbb-stations-autocomplete": "^3.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
420
test/db.js
420
test/db.js
|
@ -1,83 +1,55 @@
|
|||
'use strict'
|
||||
|
||||
const getStations = require('db-stations').full
|
||||
const stations = require('db-stations/full.json')
|
||||
const a = require('assert')
|
||||
const tapePromise = require('tape-promise').default
|
||||
const tape = require('tape')
|
||||
const isRoughlyEqual = require('is-roughly-equal')
|
||||
|
||||
const co = require('./co')
|
||||
const {createWhen} = require('./lib/util')
|
||||
const co = require('./lib/co')
|
||||
const createClient = require('..')
|
||||
const dbProfile = require('../p/db')
|
||||
const allProducts = require('../p/db/products')
|
||||
const products = require('../p/db/products')
|
||||
const {
|
||||
assertValidStation,
|
||||
assertValidPoi,
|
||||
assertValidAddress,
|
||||
assertValidLocation,
|
||||
assertValidLine,
|
||||
assertValidStopover,
|
||||
createWhen, assertValidWhen
|
||||
} = require('./util.js')
|
||||
station: createValidateStation,
|
||||
journeyLeg: createValidateJourneyLeg
|
||||
} = require('./lib/validators')
|
||||
const createValidate = require('./lib/validate-fptf-with')
|
||||
const testJourneysStationToStation = require('./lib/journeys-station-to-station')
|
||||
const testJourneysStationToAddress = require('./lib/journeys-station-to-address')
|
||||
const testJourneysStationToPoi = require('./lib/journeys-station-to-poi')
|
||||
const testEarlierLaterJourneys = require('./lib/earlier-later-journeys')
|
||||
const journeysFailsWithNoProduct = require('./lib/journeys-fails-with-no-product')
|
||||
const testDepartures = require('./lib/departures')
|
||||
const testJourneysWithDetour = require('./lib/journeys-with-detour')
|
||||
|
||||
const isObj = o => o !== null && 'object' === typeof o && !Array.isArray(o)
|
||||
|
||||
const when = createWhen('Europe/Berlin', 'de-DE')
|
||||
|
||||
const assertValidStationProducts = (t, p) => {
|
||||
t.ok(p)
|
||||
t.equal(typeof p.nationalExp, 'boolean')
|
||||
t.equal(typeof p.national, 'boolean')
|
||||
t.equal(typeof p.regionalExp, 'boolean')
|
||||
t.equal(typeof p.regional, 'boolean')
|
||||
t.equal(typeof p.suburban, 'boolean')
|
||||
t.equal(typeof p.bus, 'boolean')
|
||||
t.equal(typeof p.ferry, 'boolean')
|
||||
t.equal(typeof p.subway, 'boolean')
|
||||
t.equal(typeof p.tram, 'boolean')
|
||||
t.equal(typeof p.taxi, 'boolean')
|
||||
const cfg = {
|
||||
when,
|
||||
stationCoordsOptional: false,
|
||||
products
|
||||
}
|
||||
|
||||
const findStation = (id) => new Promise((yay, nay) => {
|
||||
const stations = getStations()
|
||||
stations
|
||||
.once('error', nay)
|
||||
.on('data', (s) => {
|
||||
if (
|
||||
s.id === id ||
|
||||
(s.additionalIds && s.additionalIds.includes(id))
|
||||
) {
|
||||
yay(s)
|
||||
stations.destroy()
|
||||
}
|
||||
})
|
||||
.once('end', yay)
|
||||
})
|
||||
|
||||
const isJungfernheide = (s) => {
|
||||
return s.type === 'station' &&
|
||||
(s.id === '008011167' || s.id === jungfernh) &&
|
||||
s.name === 'Berlin Jungfernheide' &&
|
||||
s.location &&
|
||||
isRoughlyEqual(.0005, s.location.latitude, 52.530408) &&
|
||||
isRoughlyEqual(.0005, s.location.longitude, 13.299424)
|
||||
}
|
||||
|
||||
const assertIsJungfernheide = (t, s) => {
|
||||
t.equal(s.type, 'station')
|
||||
t.ok(s.id === '008011167' || s.id === jungfernh, 'id should be 8011167')
|
||||
t.equal(s.name, 'Berlin Jungfernheide')
|
||||
t.ok(s.location)
|
||||
t.ok(isRoughlyEqual(.0005, s.location.latitude, 52.530408))
|
||||
t.ok(isRoughlyEqual(.0005, s.location.longitude, 13.299424))
|
||||
}
|
||||
|
||||
// todo: DRY with assertValidStationProducts
|
||||
// todo: DRY with other tests
|
||||
const assertValidProducts = (t, p) => {
|
||||
for (let product of allProducts) {
|
||||
product = product.id
|
||||
t.equal(typeof p[product], 'boolean', 'product ' + p + ' must be a boolean')
|
||||
const _validateStation = createValidateStation(cfg)
|
||||
const validateStation = (validate, s, name) => {
|
||||
_validateStation(validate, s, name)
|
||||
const match = stations.some(station => (
|
||||
station.id === s.id ||
|
||||
(station.additionalIds && station.additionalIds.includes(s.id))
|
||||
))
|
||||
if (!match) {
|
||||
console.error(name + `.id: unknown ID "${s.id}"`)
|
||||
}
|
||||
}
|
||||
|
||||
const validate = createValidate(cfg, {
|
||||
station: validateStation
|
||||
})
|
||||
|
||||
const assertValidPrice = (t, p) => {
|
||||
t.ok(p)
|
||||
if (p.amount !== null) {
|
||||
|
@ -93,226 +65,167 @@ const assertValidPrice = (t, p) => {
|
|||
const test = tapePromise(tape)
|
||||
const client = createClient(dbProfile)
|
||||
|
||||
const jungfernh = '8011167'
|
||||
const berlinHbf = '8011160'
|
||||
const münchenHbf = '8000261'
|
||||
const hannoverHbf = '8000152'
|
||||
const jungfernheide = '8011167'
|
||||
const blnSchwedterStr = '732652'
|
||||
const westhafen = '008089116'
|
||||
const wedding = '008089131'
|
||||
const württembergallee = '731084'
|
||||
const regensburgHbf = '8000309'
|
||||
|
||||
test('Berlin Jungfernheide to München Hbf', co(function* (t) {
|
||||
const journeys = yield client.journeys(jungfernh, münchenHbf, {
|
||||
departure: when, passedStations: true
|
||||
test('journeys – Berlin Schwedter Str. to München Hbf', co(function* (t) {
|
||||
const journeys = yield client.journeys(blnSchwedterStr, münchenHbf, {
|
||||
results: 3, departure: when, passedStations: true
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.ok(journeys.length > 0, 'no journeys')
|
||||
yield testJourneysStationToStation({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: blnSchwedterStr,
|
||||
toId: münchenHbf
|
||||
})
|
||||
// todo: find a journey where there pricing info is always available
|
||||
for (let journey of journeys) {
|
||||
t.equal(journey.type, 'journey')
|
||||
|
||||
t.ok(Array.isArray(journey.legs))
|
||||
t.ok(journey.legs.length > 0, 'no legs')
|
||||
const leg = journey.legs[0] // todo: all legs
|
||||
|
||||
assertValidStation(t, leg.origin)
|
||||
assertValidStationProducts(t, leg.origin.products)
|
||||
if (!(yield findStation(leg.origin.id))) {
|
||||
console.error('unknown station', leg.origin.id, leg.origin.name)
|
||||
}
|
||||
assertValidWhen(t, leg.departure, when)
|
||||
t.equal(typeof leg.departurePlatform, 'string')
|
||||
|
||||
assertValidStation(t, leg.destination)
|
||||
assertValidStationProducts(t, leg.origin.products)
|
||||
if (!(yield findStation(leg.destination.id))) {
|
||||
console.error('unknown station', leg.destination.id, leg.destination.name)
|
||||
}
|
||||
assertValidWhen(t, leg.arrival, when)
|
||||
t.equal(typeof leg.arrivalPlatform, 'string')
|
||||
|
||||
assertValidLine(t, leg.line)
|
||||
|
||||
t.ok(Array.isArray(leg.passed))
|
||||
for (let stopover of leg.passed) assertValidStopover(t, stopover)
|
||||
|
||||
if (journey.price) assertValidPrice(t, journey.price)
|
||||
}
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('Berlin Jungfernheide to Torfstraße 17', co(function* (t) {
|
||||
const journeys = yield client.journeys(jungfernh, {
|
||||
type: 'location', address: 'Torfstraße 17',
|
||||
latitude: 52.5416823, longitude: 13.3491223
|
||||
}, {departure: when})
|
||||
// todo: journeys, only one product
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.ok(journeys.length >= 1, 'no journeys')
|
||||
const journey = journeys[0]
|
||||
const leg = journey.legs[journey.legs.length - 1]
|
||||
test('journeys – fails with no product', (t) => {
|
||||
journeysFailsWithNoProduct({
|
||||
test: t,
|
||||
fetchJourneys: client.journeys,
|
||||
fromId: blnSchwedterStr,
|
||||
toId: münchenHbf,
|
||||
when,
|
||||
products
|
||||
})
|
||||
t.end()
|
||||
})
|
||||
|
||||
assertValidStation(t, leg.origin)
|
||||
assertValidStationProducts(t, leg.origin.products)
|
||||
if (!(yield findStation(leg.origin.id))) {
|
||||
console.error('unknown station', leg.origin.id, leg.origin.name)
|
||||
test('Berlin Schwedter Str. to Torfstraße 17', co(function* (t) {
|
||||
const torfstr = {
|
||||
type: 'location',
|
||||
address: 'Torfstraße 17',
|
||||
latitude: 52.5416823,
|
||||
longitude: 13.3491223
|
||||
}
|
||||
if (leg.origin.products) assertValidProducts(t, leg.origin.products)
|
||||
assertValidWhen(t, leg.departure, when)
|
||||
assertValidWhen(t, leg.arrival, when)
|
||||
|
||||
const d = leg.destination
|
||||
assertValidAddress(t, d)
|
||||
t.equal(d.address, 'Torfstraße 17')
|
||||
t.ok(isRoughlyEqual(.0001, d.latitude, 52.5416823))
|
||||
t.ok(isRoughlyEqual(.0001, d.longitude, 13.3491223))
|
||||
const journeys = yield client.journeys(blnSchwedterStr, torfstr, {
|
||||
results: 3,
|
||||
departure: when
|
||||
})
|
||||
|
||||
yield testJourneysStationToAddress({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: blnSchwedterStr,
|
||||
to: torfstr
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('Berlin Jungfernheide to ATZE Musiktheater', co(function* (t) {
|
||||
const journeys = yield client.journeys(jungfernh, {
|
||||
type: 'location', id: '991598902', name: 'ATZE Musiktheater',
|
||||
latitude: 52.542417, longitude: 13.350437
|
||||
}, {departure: when})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.ok(journeys.length >= 1, 'no journeys')
|
||||
const journey = journeys[0]
|
||||
const leg = journey.legs[journey.legs.length - 1]
|
||||
|
||||
assertValidStation(t, leg.origin)
|
||||
assertValidStationProducts(t, leg.origin.products)
|
||||
if (!(yield findStation(leg.origin.id))) {
|
||||
console.error('unknown station', leg.origin.id, leg.origin.name)
|
||||
test('Berlin Schwedter Str. to ATZE Musiktheater', co(function* (t) {
|
||||
const atze = {
|
||||
type: 'location',
|
||||
id: '991598902',
|
||||
name: 'ATZE Musiktheater',
|
||||
latitude: 52.542417,
|
||||
longitude: 13.350437
|
||||
}
|
||||
if (leg.origin.products) assertValidProducts(t, leg.origin.products)
|
||||
assertValidWhen(t, leg.departure, when)
|
||||
assertValidWhen(t, leg.arrival, when)
|
||||
|
||||
const d = leg.destination
|
||||
assertValidPoi(t, d)
|
||||
t.equal(d.name, 'ATZE Musiktheater')
|
||||
t.ok(isRoughlyEqual(.0001, d.latitude, 52.542399))
|
||||
t.ok(isRoughlyEqual(.0001, d.longitude, 13.350402))
|
||||
const journeys = yield client.journeys(blnSchwedterStr, atze, {
|
||||
results: 3,
|
||||
departure: when
|
||||
})
|
||||
|
||||
yield testJourneysStationToPoi({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: blnSchwedterStr,
|
||||
to: atze
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('journeys: via works – with detour', co(function* (t) {
|
||||
// Going from Westhafen to Wedding via Württembergalle without detour
|
||||
// is currently impossible. We check if the routing engine computes a detour.
|
||||
const westhafen = '008089116'
|
||||
const wedding = '008089131'
|
||||
const württembergallee = '731084'
|
||||
const [journey] = yield client.journeys(westhafen, wedding, {
|
||||
const journeys = yield client.journeys(westhafen, wedding, {
|
||||
via: württembergallee,
|
||||
results: 1,
|
||||
departure: when,
|
||||
passedStations: true
|
||||
})
|
||||
|
||||
t.ok(journey)
|
||||
|
||||
const l = journey.legs.some(l => l.passed && l.passed.some(p => p.station.id === württembergallee))
|
||||
t.ok(l, 'Württembergalle is not being passed')
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('journeys: via works – without detour', co(function* (t) {
|
||||
// When going from Ruhleben to Zoo via Kastanienallee, there is *no need*
|
||||
// to change trains / no need for a "detour".
|
||||
const ruhleben = '000731058'
|
||||
const zoo = '008010406'
|
||||
const kastanienallee = '730983'
|
||||
const [journey] = yield client.journeys(ruhleben, zoo, {
|
||||
via: kastanienallee,
|
||||
results: 1,
|
||||
departure: when,
|
||||
passedStations: true
|
||||
yield testJourneysWithDetour({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
detourIds: [württembergallee]
|
||||
})
|
||||
|
||||
t.ok(journey)
|
||||
|
||||
const l = journey.legs.some(l => l.passed && l.passed.some(p => p.station.id === kastanienallee))
|
||||
t.ok(l, 'Kastanienallee is not being passed')
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
// todo: without detour
|
||||
|
||||
test('earlier/later journeys, Jungfernheide -> München Hbf', co(function* (t) {
|
||||
const model = yield client.journeys(jungfernh, münchenHbf, {
|
||||
results: 3, departure: when
|
||||
yield testEarlierLaterJourneys({
|
||||
test: t,
|
||||
fetchJourneys: client.journeys,
|
||||
validate,
|
||||
fromId: jungfernheide,
|
||||
toId: münchenHbf
|
||||
})
|
||||
|
||||
t.equal(typeof model.earlierRef, 'string')
|
||||
t.ok(model.earlierRef)
|
||||
t.equal(typeof model.laterRef, 'string')
|
||||
t.ok(model.laterRef)
|
||||
|
||||
// when and earlierThan/laterThan should be mutually exclusive
|
||||
t.throws(() => {
|
||||
client.journeys(jungfernh, münchenHbf, {
|
||||
departure: when, earlierThan: model.earlierRef
|
||||
})
|
||||
})
|
||||
t.throws(() => {
|
||||
client.journeys(jungfernh, münchenHbf, {
|
||||
departure: when, laterThan: model.laterRef
|
||||
})
|
||||
})
|
||||
|
||||
let earliestDep = Infinity, latestDep = -Infinity
|
||||
for (let j of model) {
|
||||
const dep = +new Date(j.legs[0].departure)
|
||||
if (dep < earliestDep) earliestDep = dep
|
||||
else if (dep > latestDep) latestDep = dep
|
||||
}
|
||||
|
||||
const earlier = yield client.journeys(jungfernh, münchenHbf, {
|
||||
results: 3,
|
||||
// todo: single journey ref?
|
||||
earlierThan: model.earlierRef
|
||||
})
|
||||
for (let j of earlier) {
|
||||
t.ok(new Date(j.legs[0].departure) < earliestDep)
|
||||
}
|
||||
|
||||
const later = yield client.journeys(jungfernh, münchenHbf, {
|
||||
results: 3,
|
||||
// todo: single journey ref?
|
||||
laterThan: model.laterRef
|
||||
})
|
||||
for (let j of later) {
|
||||
t.ok(new Date(j.legs[0].departure) > latestDep)
|
||||
}
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('departures at Berlin Jungfernheide', co(function* (t) {
|
||||
const deps = yield client.departures(jungfernh, {
|
||||
test('journey leg details', co(function* (t) {
|
||||
const journeys = yield client.journeys(berlinHbf, münchenHbf, {
|
||||
results: 1, departure: when
|
||||
})
|
||||
|
||||
const p = journeys[0].legs[0]
|
||||
t.ok(p.id, 'precondition failed')
|
||||
t.ok(p.line.name, 'precondition failed')
|
||||
const leg = yield client.journeyLeg(p.id, p.line.name, {when})
|
||||
|
||||
const validateJourneyLeg = createValidateJourneyLeg(cfg)
|
||||
const validate = createValidate(cfg, {
|
||||
journeyLeg: (validate, leg, name) => {
|
||||
if (!leg.direction) leg.direction = 'foo' // todo, see #49
|
||||
validateJourneyLeg(validate, leg, name)
|
||||
}
|
||||
})
|
||||
validate(t, leg, 'journeyLeg', 'leg')
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('departures at Berlin Schwedter Str.', co(function* (t) {
|
||||
const departures = yield client.departures(blnSchwedterStr, {
|
||||
duration: 5, when
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(deps))
|
||||
for (let dep of deps) {
|
||||
assertValidStation(t, dep.station)
|
||||
assertValidStationProducts(t, dep.station.products)
|
||||
if (!(yield findStation(dep.station.id))) {
|
||||
console.error('unknown station', dep.station.id, dep.station.name)
|
||||
}
|
||||
if (dep.station.products) assertValidProducts(t, dep.station.products)
|
||||
assertValidWhen(t, dep.when, when)
|
||||
}
|
||||
|
||||
yield testDepartures({
|
||||
test: t,
|
||||
departures,
|
||||
validate,
|
||||
id: blnSchwedterStr
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('departures with station object', co(function* (t) {
|
||||
yield client.departures({
|
||||
const deps = yield client.departures({
|
||||
type: 'station',
|
||||
id: jungfernh,
|
||||
id: jungfernheide,
|
||||
name: 'Berlin Jungfernheide',
|
||||
location: {
|
||||
type: 'location',
|
||||
|
@ -321,7 +234,7 @@ test('departures with station object', co(function* (t) {
|
|||
}
|
||||
}, {when})
|
||||
|
||||
t.ok('did not fail')
|
||||
validate(t, deps, 'departures', 'departures')
|
||||
t.end()
|
||||
}))
|
||||
|
||||
|
@ -334,17 +247,18 @@ test('nearby Berlin Jungfernheide', co(function* (t) {
|
|||
results: 2, distance: 400
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(nearby))
|
||||
validate(t, nearby, 'locations', 'nearby')
|
||||
|
||||
t.equal(nearby.length, 2)
|
||||
|
||||
assertIsJungfernheide(t, nearby[0])
|
||||
t.ok(nearby[0].distance >= 0)
|
||||
t.ok(nearby[0].distance <= 100)
|
||||
|
||||
for (let n of nearby) {
|
||||
if (n.type === 'station') assertValidStation(t, n)
|
||||
else assertValidLocation(t, n)
|
||||
}
|
||||
const s0 = nearby[0]
|
||||
// todo: trim IDs
|
||||
t.ok(s0.id === '008011167' || s0.id === jungfernheide)
|
||||
t.equal(s0.name, 'Berlin Jungfernheide')
|
||||
t.ok(isRoughlyEqual(.0005, s0.location.latitude, 52.530408))
|
||||
t.ok(isRoughlyEqual(.0005, s0.location.longitude, 13.299424))
|
||||
t.ok(s0.distance >= 0)
|
||||
t.ok(s0.distance <= 100)
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
@ -354,29 +268,21 @@ test('locations named Jungfernheide', co(function* (t) {
|
|||
results: 10
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(locations))
|
||||
t.ok(locations.length > 0)
|
||||
validate(t, locations, 'locations', 'locations')
|
||||
t.ok(locations.length <= 10)
|
||||
|
||||
for (let l of locations) {
|
||||
if (l.type === 'station') assertValidStation(t, l)
|
||||
else assertValidLocation(t, l)
|
||||
}
|
||||
t.ok(locations.some(isJungfernheide))
|
||||
t.ok(locations.some((l) => {
|
||||
// todo: trim IDs
|
||||
return l.id === '008011167' || l.id === jungfernheide
|
||||
}), 'Jungfernheide not found')
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('station', co(function* (t) {
|
||||
const loc = yield client.station(regensburgHbf)
|
||||
const s = yield client.station(regensburgHbf)
|
||||
|
||||
assertValidStation(t, loc)
|
||||
t.equal(loc.id, regensburgHbf)
|
||||
|
||||
t.ok(Array.isArray(loc.lines))
|
||||
if (Array.isArray(loc.lines)) {
|
||||
for (let line of loc.lines) assertValidLine(t, line)
|
||||
}
|
||||
validate(t, s, 'station', 'station')
|
||||
t.equal(s.id, regensburgHbf)
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
|
434
test/insa.js
434
test/insa.js
|
@ -3,374 +3,244 @@
|
|||
const tapePromise = require('tape-promise').default
|
||||
const tape = require('tape')
|
||||
const isRoughlyEqual = require('is-roughly-equal')
|
||||
const validateFptf = require('validate-fptf')
|
||||
|
||||
const co = require('./co')
|
||||
const {createWhen} = require('./lib/util')
|
||||
const co = require('./lib/co')
|
||||
const createClient = require('..')
|
||||
const insaProfile = require('../p/insa')
|
||||
const allProducts = require('../p/insa/products')
|
||||
const {
|
||||
assertValidStation,
|
||||
assertValidPoi,
|
||||
assertValidAddress,
|
||||
assertValidLocation,
|
||||
assertValidLine,
|
||||
assertValidStopover,
|
||||
hour,
|
||||
createWhen,
|
||||
assertValidWhen
|
||||
} = require('./util.js')
|
||||
const products = require('../p/insa/products')
|
||||
const createValidate = require('./lib/validate-fptf-with')
|
||||
const testJourneysStationToStation = require('./lib/journeys-station-to-station')
|
||||
const testJourneysStationToAddress = require('./lib/journeys-station-to-address')
|
||||
const testJourneysStationToPoi = require('./lib/journeys-station-to-poi')
|
||||
const testEarlierLaterJourneys = require('./lib/earlier-later-journeys')
|
||||
const journeysFailsWithNoProduct = require('./lib/journeys-fails-with-no-product')
|
||||
const testDepartures = require('./lib/departures')
|
||||
const testJourneysWithDetour = require('./lib/journeys-with-detour')
|
||||
|
||||
const isObj = o => o !== null && 'object' === typeof o && !Array.isArray(o)
|
||||
|
||||
const when = createWhen('Europe/Berlin', 'de-DE')
|
||||
|
||||
const assertValidStationProducts = (t, p) => {
|
||||
t.ok(p)
|
||||
t.equal(typeof p.nationalExp, 'boolean')
|
||||
t.equal(typeof p.national, 'boolean')
|
||||
t.equal(typeof p.regional, 'boolean')
|
||||
t.equal(typeof p.suburban, 'boolean')
|
||||
t.equal(typeof p.tram, 'boolean')
|
||||
t.equal(typeof p.bus, 'boolean')
|
||||
t.equal(typeof p.tourismTrain, 'boolean')
|
||||
const cfg = {
|
||||
when,
|
||||
stationCoordsOptional: false,
|
||||
products
|
||||
}
|
||||
|
||||
const isMagdeburgHbf = s => {
|
||||
return (
|
||||
s.type === 'station' &&
|
||||
(s.id === '8010224' || s.id === '008010224') &&
|
||||
s.name === 'Magdeburg Hbf' &&
|
||||
s.location &&
|
||||
isRoughlyEqual(.001, s.location.latitude, 52.130352) &&
|
||||
isRoughlyEqual(.001, s.location.longitude, 11.626891)
|
||||
)
|
||||
}
|
||||
|
||||
const assertIsMagdeburgHbf = (t, s) => {
|
||||
t.equal(s.type, 'station')
|
||||
t.ok(s.id === '8010224' || s.id === '008010224', 'id should be 8010224')
|
||||
t.equal(s.name, 'Magdeburg Hbf')
|
||||
t.ok(s.location)
|
||||
t.ok(isRoughlyEqual(.001, s.location.latitude, 52.130352))
|
||||
t.ok(isRoughlyEqual(.001, s.location.longitude, 11.626891))
|
||||
}
|
||||
|
||||
// todo: DRY with assertValidStationProducts
|
||||
// todo: DRY with other tests
|
||||
const assertValidProducts = (t, p) => {
|
||||
for (let product of allProducts) {
|
||||
product = product.id
|
||||
t.equal(typeof p[product], 'boolean', 'product ' + p + ' must be a boolean')
|
||||
}
|
||||
}
|
||||
const validate = createValidate(cfg, {})
|
||||
|
||||
const test = tapePromise(tape)
|
||||
const client = createClient(insaProfile)
|
||||
|
||||
test('Magdeburg Hbf to Magdeburg-Buckau', co(function*(t) {
|
||||
const magdeburgHbf = '8010224'
|
||||
const magdeburgBuckau = '8013456'
|
||||
const magdeburgHbf = '8010224'
|
||||
const magdeburgBuckau = '8013456'
|
||||
const leiterstr = '7464'
|
||||
const hasselbachplatzSternstrasse = '000006545'
|
||||
const stendal = '008010334'
|
||||
const dessau = '008010077'
|
||||
|
||||
test('journeys – Magdeburg Hbf to Magdeburg-Buckau', co(function* (t) {
|
||||
const journeys = yield client.journeys(magdeburgHbf, magdeburgBuckau, {
|
||||
results: 3,
|
||||
departure: when,
|
||||
passedStations: true
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.ok(journeys.length > 0, 'no journeys')
|
||||
for (let journey of journeys) {
|
||||
t.ok(Array.isArray(journey.legs))
|
||||
t.ok(journey.legs.length > 0, 'no legs')
|
||||
const leg = journey.legs[0] // todo: all legs
|
||||
|
||||
assertValidStation(t, leg.origin)
|
||||
assertValidStationProducts(t, leg.origin.products)
|
||||
assertValidWhen(t, leg.departure, when)
|
||||
t.equal(typeof leg.departurePlatform, 'string')
|
||||
|
||||
assertValidStation(t, leg.destination)
|
||||
assertValidStationProducts(t, leg.origin.products)
|
||||
assertValidWhen(t, leg.arrival, when)
|
||||
t.equal(typeof leg.arrivalPlatform, 'string')
|
||||
|
||||
assertValidLine(t, leg.line)
|
||||
|
||||
t.ok(Array.isArray(leg.passed))
|
||||
for (let stopover of leg.passed) assertValidStopover(t, stopover)
|
||||
}
|
||||
|
||||
yield testJourneysStationToStation({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: magdeburgHbf,
|
||||
toId: magdeburgBuckau
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
// todo: journeys, only one product
|
||||
|
||||
test('journeys – fails with no product', (t) => {
|
||||
journeysFailsWithNoProduct({
|
||||
test: t,
|
||||
fetchJourneys: client.journeys,
|
||||
fromId: magdeburgHbf,
|
||||
toId: magdeburgBuckau,
|
||||
when,
|
||||
products
|
||||
})
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Magdeburg Hbf to 39104 Magdeburg, Sternstr. 10', co(function*(t) {
|
||||
const magdeburgHbf = '8010224'
|
||||
const sternStr = {
|
||||
type: 'location',
|
||||
address: 'Magdeburg - Altenstadt, Sternstraße 10',
|
||||
latitude: 52.118414,
|
||||
longitude: 11.422332,
|
||||
address: 'Magdeburg - Altenstadt, Sternstraße 10'
|
||||
longitude: 11.422332
|
||||
}
|
||||
|
||||
const journeys = yield client.journeys(magdeburgHbf, sternStr, {
|
||||
results: 3,
|
||||
departure: when
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.ok(journeys.length >= 1, 'no journeys')
|
||||
const journey = journeys[0]
|
||||
const firstLeg = journey.legs[0]
|
||||
const lastLeg = journey.legs[journey.legs.length - 1]
|
||||
|
||||
assertValidStation(t, firstLeg.origin)
|
||||
assertValidStationProducts(t, firstLeg.origin.products)
|
||||
if (firstLeg.origin.products)
|
||||
assertValidProducts(t, firstLeg.origin.products)
|
||||
assertValidWhen(t, firstLeg.departure, when)
|
||||
assertValidWhen(t, firstLeg.arrival, when)
|
||||
assertValidWhen(t, lastLeg.departure, when)
|
||||
assertValidWhen(t, lastLeg.arrival, when)
|
||||
|
||||
const d = lastLeg.destination
|
||||
assertValidAddress(t, d)
|
||||
t.equal(d.address, 'Magdeburg - Altenstadt, Sternstraße 10')
|
||||
t.ok(isRoughlyEqual(0.0001, d.latitude, 52.118414))
|
||||
t.ok(isRoughlyEqual(0.0001, d.longitude, 11.422332))
|
||||
|
||||
yield testJourneysStationToAddress({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: magdeburgHbf,
|
||||
to: sternStr
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('Kloster Unser Lieben Frauen to Magdeburg Hbf', co(function*(t) {
|
||||
test('Magdeburg Hbf to Kloster Unser Lieben Frauen', co(function*(t) {
|
||||
const kloster = {
|
||||
type: 'location',
|
||||
latitude: 52.127601,
|
||||
longitude: 11.636437,
|
||||
id: '970012223',
|
||||
name: 'Magdeburg, Kloster Unser Lieben Frauen (Denkmal)',
|
||||
id: '970012223'
|
||||
latitude: 52.127601,
|
||||
longitude: 11.636437
|
||||
}
|
||||
const magdeburgHbf = '8010224'
|
||||
const journeys = yield client.journeys(kloster, magdeburgHbf, {
|
||||
const journeys = yield client.journeys(magdeburgHbf, kloster, {
|
||||
results: 3,
|
||||
departure: when
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.ok(journeys.length >= 1, 'no journeys')
|
||||
const journey = journeys[0]
|
||||
const firstLeg = journey.legs[0]
|
||||
const lastLeg = journey.legs[journey.legs.length - 1]
|
||||
|
||||
const o = firstLeg.origin
|
||||
assertValidPoi(t, o)
|
||||
t.equal(o.name, 'Magdeburg, Kloster Unser Lieben Frauen (Denkmal)')
|
||||
t.ok(isRoughlyEqual(0.0001, o.latitude, 52.127601))
|
||||
t.ok(isRoughlyEqual(0.0001, o.longitude, 11.636437))
|
||||
|
||||
assertValidWhen(t, firstLeg.departure, when)
|
||||
assertValidWhen(t, firstLeg.arrival, when)
|
||||
assertValidWhen(t, lastLeg.departure, when)
|
||||
assertValidWhen(t, lastLeg.arrival, when)
|
||||
|
||||
assertValidStation(t, lastLeg.destination)
|
||||
assertValidStationProducts(t, lastLeg.destination.products)
|
||||
if (lastLeg.destination.products)
|
||||
assertValidProducts(t, lastLeg.destination.products)
|
||||
|
||||
yield testJourneysStationToPoi({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: magdeburgHbf,
|
||||
to: kloster
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('journeys: via works – with detour', co(function* (t) {
|
||||
// Going from Magdeburg, Hasselbachplatz (Sternstr.) (Tram/Bus) to Stendal via Dessau without detour
|
||||
// is currently impossible. We check if the routing engine computes a detour.
|
||||
const hasselbachplatzSternstrasse = '000006545'
|
||||
const stendal = '008010334'
|
||||
const dessau = '008010077'
|
||||
const dessauPassed = '8010077'
|
||||
const [journey] = yield client.journeys(hasselbachplatzSternstrasse, stendal, {
|
||||
// Going from Magdeburg, Hasselbachplatz (Sternstr.) (Tram/Bus) to Stendal
|
||||
// via Dessau without detour is currently impossible. We check if the routing
|
||||
// engine computes a detour.
|
||||
const journeys = yield client.journeys(hasselbachplatzSternstrasse, stendal, {
|
||||
via: dessau,
|
||||
results: 1,
|
||||
departure: when,
|
||||
passedStations: true
|
||||
})
|
||||
|
||||
t.ok(journey)
|
||||
|
||||
const l = journey.legs.some(l => l.passed && l.passed.some(p => p.station.id === dessauPassed))
|
||||
t.ok(l, 'Dessau is not being passed')
|
||||
|
||||
yield testJourneysWithDetour({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
detourIds: ['8010077', dessau] // todo: trim IDs
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('journeys: via works – without detour', co(function* (t) {
|
||||
// When going from Magdeburg, Hasselbachplatz (Sternstr.) (Tram/Bus) to Magdeburg, Universität via Magdeburg, Breiter Weg, there is *no need*
|
||||
// to change trains / no need for a "detour".
|
||||
const hasselbachplatzSternstrasse = '000006545'
|
||||
const universitaet = '000019686'
|
||||
const breiterWeg = '000013519'
|
||||
const breiterWegPassed = '13519'
|
||||
// todo: without detour
|
||||
|
||||
const [journey] = yield client.journeys(hasselbachplatzSternstrasse, universitaet, {
|
||||
via: breiterWeg,
|
||||
results: 1,
|
||||
departure: when,
|
||||
passedStations: true
|
||||
test('earlier/later journeys', co(function* (t) {
|
||||
yield testEarlierLaterJourneys({
|
||||
test: t,
|
||||
fetchJourneys: client.journeys,
|
||||
validate,
|
||||
fromId: magdeburgHbf,
|
||||
toId: magdeburgBuckau
|
||||
})
|
||||
|
||||
t.ok(journey)
|
||||
|
||||
const l = journey.legs.some(l => l.passed && l.passed.some(p => p.station.id === breiterWegPassed))
|
||||
t.ok(l, 'Magdeburg, Breiter Weg is not being passed')
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('departures at Magdeburg Hbf', co(function*(t) {
|
||||
const magdeburgHbf = '8010224'
|
||||
const deps = yield client.departures(magdeburgHbf, {
|
||||
duration: 5,
|
||||
when
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(deps))
|
||||
for (let dep of deps) {
|
||||
assertValidStation(t, dep.station)
|
||||
assertValidStationProducts(t, dep.station.products)
|
||||
if (dep.station.products) {
|
||||
assertValidProducts(t, dep.station.products)
|
||||
}
|
||||
assertValidWhen(t, dep.when, when)
|
||||
}
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('nearby Magdeburg Hbf', co(function*(t) {
|
||||
const magdeburgHbfPosition = {
|
||||
type: 'location',
|
||||
latitude: 52.130352,
|
||||
longitude: 11.626891
|
||||
}
|
||||
const nearby = yield client.nearby(magdeburgHbfPosition, {
|
||||
results: 2,
|
||||
distance: 400
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(nearby))
|
||||
t.equal(nearby.length, 2)
|
||||
|
||||
assertIsMagdeburgHbf(t, nearby[0])
|
||||
t.ok(nearby[0].distance >= 0)
|
||||
t.ok(nearby[0].distance <= 100)
|
||||
|
||||
for (let n of nearby) {
|
||||
if (n.type === 'station') assertValidStation(t, n)
|
||||
else assertValidLocation(t, n)
|
||||
}
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('journey leg details', co(function* (t) {
|
||||
const magdeburgHbf = '8010224'
|
||||
const magdeburgBuckau = '8013456'
|
||||
const [journey] = yield client.journeys(magdeburgHbf, magdeburgBuckau, {
|
||||
const journeys = yield client.journeys(magdeburgHbf, magdeburgBuckau, {
|
||||
results: 1, departure: when
|
||||
})
|
||||
|
||||
const p = journey.legs[0]
|
||||
t.ok(p, 'missing legs[0]')
|
||||
t.ok(p.id, 'missing legs[0].id')
|
||||
t.ok(p.line, 'missing legs[0].line')
|
||||
t.ok(p.line.name, 'missing legs[0].line.name')
|
||||
const p = journeys[0].legs[0]
|
||||
t.ok(p.id, 'precondition failed')
|
||||
t.ok(p.line.name, 'precondition failed')
|
||||
const leg = yield client.journeyLeg(p.id, p.line.name, {when})
|
||||
|
||||
t.equal(typeof leg.id, 'string')
|
||||
t.ok(leg.id)
|
||||
|
||||
assertValidLine(t, leg.line)
|
||||
|
||||
t.equal(typeof leg.direction, 'string')
|
||||
t.ok(leg.direction)
|
||||
|
||||
t.ok(Array.isArray(leg.passed))
|
||||
for (let passed of leg.passed) assertValidStopover(t, passed)
|
||||
|
||||
validate(t, leg, 'journeyLeg', 'leg')
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('departures at Magdeburg Leiterstr.', co(function*(t) {
|
||||
const departures = yield client.departures(leiterstr, {
|
||||
duration: 5, when
|
||||
})
|
||||
|
||||
yield testDepartures({
|
||||
test: t,
|
||||
departures,
|
||||
validate,
|
||||
id: leiterstr
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('departures with station object', co(function* (t) {
|
||||
const deps = yield client.departures({
|
||||
type: 'station',
|
||||
id: magdeburgHbf,
|
||||
name: 'Magdeburg Hbf',
|
||||
location: {
|
||||
type: 'location',
|
||||
latitude: 1.23,
|
||||
longitude: 2.34
|
||||
}
|
||||
}, {when})
|
||||
|
||||
validate(t, deps, 'departures', 'departures')
|
||||
t.end()
|
||||
}))
|
||||
|
||||
// todo: nearby
|
||||
|
||||
test('locations named Magdeburg', co(function*(t) {
|
||||
const locations = yield client.locations('Magdeburg', {
|
||||
results: 10
|
||||
results: 20
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(locations))
|
||||
t.ok(locations.length > 0)
|
||||
t.ok(locations.length <= 10)
|
||||
validate(t, locations, 'locations', 'locations')
|
||||
t.ok(locations.length <= 20)
|
||||
|
||||
for (let l of locations) {
|
||||
if (l.type === 'station') assertValidStation(t, l)
|
||||
else assertValidLocation(t, l)
|
||||
}
|
||||
t.ok(locations.some(isMagdeburgHbf))
|
||||
t.ok(locations.find(s => s.type === 'station'))
|
||||
t.ok(locations.find(s => s.id && s.name)) // POIs
|
||||
t.ok(locations.some((loc) => {
|
||||
return (
|
||||
loc.id === '008010224' || // todo: trim IDs
|
||||
loc.id === magdeburgHbf
|
||||
)
|
||||
}))
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('station', co(function*(t) {
|
||||
const magdeburgBuckau = '8013456'
|
||||
const loc = yield client.station(magdeburgBuckau)
|
||||
test('station Magdeburg-Buckau', co(function* (t) {
|
||||
const s = yield client.station(magdeburgBuckau)
|
||||
|
||||
assertValidStation(t, loc)
|
||||
t.equal(loc.id, magdeburgBuckau)
|
||||
validate(t, s, 'station', 'station')
|
||||
t.equal(s.id, magdeburgBuckau)
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('radar', co(function* (t) {
|
||||
const north = 52.148364
|
||||
const west = 11.600826
|
||||
const south = 52.108486
|
||||
const east = 11.651451
|
||||
const vehicles = yield client.radar({north, west, south, east}, {
|
||||
const vehicles = yield client.radar({
|
||||
north: 52.148364,
|
||||
west: 11.600826,
|
||||
south: 52.108486,
|
||||
east: 11.651451
|
||||
}, {
|
||||
duration: 5 * 60, when, results: 10
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(vehicles))
|
||||
t.ok(vehicles.length > 0)
|
||||
for (let v of vehicles) {
|
||||
assertValidLine(t, v.line)
|
||||
const customCfg = Object.assign({}, cfg, {
|
||||
stationCoordsOptional: true, // see #28
|
||||
})
|
||||
const validate = createValidate(customCfg, {})
|
||||
validate(t, vehicles, 'movements', 'vehicles')
|
||||
|
||||
t.equal(typeof v.location.latitude, 'number')
|
||||
t.ok(v.location.latitude <= 57, 'vehicle is too far away')
|
||||
t.ok(v.location.latitude >= 47, 'vehicle is too far away')
|
||||
t.equal(typeof v.location.longitude, 'number')
|
||||
t.ok(v.location.longitude >= 8, 'vehicle is too far away')
|
||||
t.ok(v.location.longitude <= 14, 'vehicle is too far away')
|
||||
|
||||
t.ok(Array.isArray(v.nextStops))
|
||||
for (let st of v.nextStops) {
|
||||
assertValidStopover(t, st, true)
|
||||
|
||||
if (st.arrival) {
|
||||
t.equal(typeof st.arrival, 'string')
|
||||
const arr = +new Date(st.arrival)
|
||||
// note that this can be an ICE train
|
||||
t.ok(isRoughlyEqual(14 * hour, +when, arr))
|
||||
}
|
||||
if (st.departure) {
|
||||
t.equal(typeof st.departure, 'string')
|
||||
const dep = +new Date(st.departure)
|
||||
// note that this can be an ICE train
|
||||
t.ok(isRoughlyEqual(14 * hour, +when, dep))
|
||||
}
|
||||
}
|
||||
|
||||
t.ok(Array.isArray(v.frames))
|
||||
for (let f of v.frames) {
|
||||
// see #28
|
||||
// todo: check if this works by now
|
||||
assertValidStation(t, f.origin, true)
|
||||
assertValidStationProducts(t, f.origin.products)
|
||||
assertValidStation(t, f.destination, true)
|
||||
assertValidStationProducts(t, f.destination.products)
|
||||
t.equal(typeof f.t, 'number')
|
||||
}
|
||||
}
|
||||
t.end()
|
||||
}))
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
'use strict'
|
||||
|
||||
// https://github.com/babel/babel/blob/3c8d831fe41f502cbe2459a271d19c7329ffe369/packages/babel-helpers/src/helpers.js#L242-L270
|
||||
const co = (fn) => {
|
||||
return function run () {
|
21
test/lib/departures.js
Normal file
21
test/lib/departures.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
'use strict'
|
||||
|
||||
const co = require('./co')
|
||||
|
||||
const testDepartures = co(function* (cfg) {
|
||||
const {test: t, departures: deps, validate, id} = cfg
|
||||
|
||||
validate(t, deps, 'departures', 'departures')
|
||||
t.ok(deps.length > 0, 'must be >0 departures')
|
||||
for (let i = 0; i < deps.length; i++) {
|
||||
const dep = deps[i]
|
||||
const name = `deps[${i}]`
|
||||
|
||||
t.equal(dep.station.id, id, name + '.station.id is invalid')
|
||||
}
|
||||
|
||||
// todo: move into deps validator
|
||||
t.deepEqual(deps, deps.sort((a, b) => t.when > b.when))
|
||||
})
|
||||
|
||||
module.exports = testDepartures
|
82
test/lib/earlier-later-journeys.js
Normal file
82
test/lib/earlier-later-journeys.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
'use strict'
|
||||
|
||||
const co = require('./co')
|
||||
|
||||
const testEarlierLaterJourneys = co(function* (cfg) {
|
||||
const {
|
||||
test: t,
|
||||
fetchJourneys,
|
||||
fromId,
|
||||
toId,
|
||||
when,
|
||||
// todo: validate
|
||||
} = cfg
|
||||
|
||||
const model = yield fetchJourneys(fromId, toId, {
|
||||
results: 3, departure: when
|
||||
})
|
||||
|
||||
// todo: move to journeys validator?
|
||||
t.equal(typeof model.earlierRef, 'string')
|
||||
t.ok(model.earlierRef)
|
||||
t.equal(typeof model.laterRef, 'string')
|
||||
t.ok(model.laterRef)
|
||||
|
||||
// departure/arrival and earlierThan/laterThan should be mutually exclusive
|
||||
t.throws(() => {
|
||||
fetchJourneys(fromId, toId, {
|
||||
departure: when, earlierThan: model.earlierRef
|
||||
})
|
||||
// silence rejections, we're only interested in exceptions
|
||||
.catch(() => {})
|
||||
})
|
||||
t.throws(() => {
|
||||
fetchJourneys(fromId, toId, {
|
||||
departure: when, laterThan: model.laterRef
|
||||
})
|
||||
// silence rejections, we're only interested in exceptions
|
||||
.catch(() => {})
|
||||
})
|
||||
t.throws(() => {
|
||||
fetchJourneys(fromId, toId, {
|
||||
arrival: when, earlierThan: model.earlierRef
|
||||
})
|
||||
// silence rejections, we're only interested in exceptions
|
||||
.catch(() => {})
|
||||
})
|
||||
t.throws(() => {
|
||||
fetchJourneys(fromId, toId, {
|
||||
arrival: when, laterThan: model.laterRef
|
||||
})
|
||||
// silence rejections, we're only interested in exceptions
|
||||
.catch(() => {})
|
||||
})
|
||||
|
||||
let earliestDep = Infinity, latestDep = -Infinity
|
||||
for (let j of model) {
|
||||
if (j.legs[0].departure === null) continue
|
||||
const dep = +new Date(j.legs[0].departure)
|
||||
if (dep < earliestDep) earliestDep = dep
|
||||
else if (dep > latestDep) latestDep = dep
|
||||
}
|
||||
|
||||
const earlier = yield fetchJourneys(fromId, toId, {
|
||||
results: 3,
|
||||
// todo: single journey ref?
|
||||
earlierThan: model.earlierRef
|
||||
})
|
||||
for (let j of earlier) {
|
||||
t.ok(new Date(j.legs[0].departure) < earliestDep)
|
||||
}
|
||||
|
||||
const later = yield fetchJourneys(fromId, toId, {
|
||||
results: 3,
|
||||
// todo: single journey ref?
|
||||
laterThan: model.laterRef
|
||||
})
|
||||
for (let j of later) {
|
||||
t.ok(new Date(j.legs[0].departure) > latestDep)
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = testEarlierLaterJourneys
|
23
test/lib/journeys-fails-with-no-product.js
Normal file
23
test/lib/journeys-fails-with-no-product.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
'use strict'
|
||||
|
||||
const journeysFailsWithNoProduct = (cfg) => {
|
||||
const {
|
||||
test: t,
|
||||
fetchJourneys,
|
||||
fromId,
|
||||
toId,
|
||||
when,
|
||||
products
|
||||
} = cfg
|
||||
|
||||
const productsObj = Object.create(null)
|
||||
for (let p of products) productsObj[p.id] = false
|
||||
|
||||
t.throws(() => {
|
||||
client.journeys(fromId, toId, {departure: when, products})
|
||||
// silence rejections, we're only interested in exceptions
|
||||
.catch(() => {})
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = journeysFailsWithNoProduct
|
29
test/lib/journeys-station-to-address.js
Normal file
29
test/lib/journeys-station-to-address.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
'use strict'
|
||||
|
||||
const isRoughlyEqual = require('is-roughly-equal')
|
||||
|
||||
const co = require('./co')
|
||||
|
||||
const testJourneysStationToAddress = co(function* (cfg) {
|
||||
const {test: t, journeys, validate, fromId} = cfg
|
||||
const {address, latitude, longitude} = cfg.to
|
||||
|
||||
validate(t, journeys, 'journeys', 'journeys')
|
||||
t.strictEqual(journeys.length, 3)
|
||||
for (let i = 0; i < journeys.length; i++) {
|
||||
const j = journeys[i]
|
||||
|
||||
const firstLeg = j.legs[0]
|
||||
t.strictEqual(firstLeg.origin.id, fromId)
|
||||
|
||||
const d = j.legs[j.legs.length - 1].destination
|
||||
const n = `journeys[0].legs[${i}].destination`
|
||||
|
||||
t.strictEqual(d.type, 'location', n + '.type is invalid')
|
||||
t.strictEqual(d.address, address, n + '.address is invalid')
|
||||
t.ok(isRoughlyEqual(.0001, d.latitude, latitude), n + '.latitude is invalid')
|
||||
t.ok(isRoughlyEqual(.0001, d.longitude, longitude), n + '.longitude is invalid')
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = testJourneysStationToAddress
|
30
test/lib/journeys-station-to-poi.js
Normal file
30
test/lib/journeys-station-to-poi.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
'use strict'
|
||||
|
||||
const isRoughlyEqual = require('is-roughly-equal')
|
||||
|
||||
const co = require('./co')
|
||||
|
||||
const testJourneysStationToPoi = co(function* (cfg) {
|
||||
const {test: t, journeys, validate, fromId} = cfg
|
||||
const {id, name, latitude, longitude} = cfg.to
|
||||
|
||||
validate(t, journeys, 'journeys', 'journeys')
|
||||
t.strictEqual(journeys.length, 3)
|
||||
for (let i = 0; i < journeys.length; i++) {
|
||||
const j = journeys[i]
|
||||
|
||||
const firstLeg = j.legs[0]
|
||||
t.strictEqual(firstLeg.origin.id, fromId)
|
||||
|
||||
const d = j.legs[j.legs.length - 1].destination
|
||||
const n = `journeys[0].legs[${i}].destination`
|
||||
|
||||
t.strictEqual(d.type, 'location', n + '.type is invalid')
|
||||
t.strictEqual(d.id, id, n + '.id is invalid')
|
||||
t.strictEqual(d.name, name, n + '.name is invalid')
|
||||
t.ok(isRoughlyEqual(.0001, d.latitude, latitude), n + '.latitude is invalid')
|
||||
t.ok(isRoughlyEqual(.0001, d.longitude, longitude), n + '.longitude is invalid')
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = testJourneysStationToPoi
|
20
test/lib/journeys-station-to-station.js
Normal file
20
test/lib/journeys-station-to-station.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
'use strict'
|
||||
|
||||
const co = require('./co')
|
||||
|
||||
const testJourneysStationToStation = co(function* (cfg) {
|
||||
const {test: t, journeys, validate, fromId, toId} = cfg
|
||||
|
||||
validate(t, journeys, 'journeys', 'journeys')
|
||||
t.strictEqual(journeys.length, 3)
|
||||
for (let i = 0; i < journeys.length; i++) {
|
||||
const j = journeys[i]
|
||||
|
||||
const firstLeg = j.legs[0]
|
||||
const lastLeg = j.legs[j.legs.length - 1]
|
||||
t.strictEqual(firstLeg.origin.id, fromId)
|
||||
t.strictEqual(lastLeg.destination.id, toId)
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = testJourneysStationToStation
|
21
test/lib/journeys-with-detour.js
Normal file
21
test/lib/journeys-with-detour.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
'use strict'
|
||||
|
||||
const co = require('./co')
|
||||
|
||||
const testJourneysWithDetour = co(function* (cfg) {
|
||||
const {test: t, journeys, validate, detourIds} = cfg
|
||||
|
||||
// We assume that going from A to B via C *without* detour is currently
|
||||
// impossible. We check if the routing engine computes a detour.
|
||||
|
||||
validate(t, journeys, 'journeys', 'journeys')
|
||||
|
||||
const leg = journeys[0].legs.some((leg) => {
|
||||
return leg.passed && leg.passed.some((passed) => {
|
||||
return detourIds.includes(passed.station.id)
|
||||
})
|
||||
})
|
||||
t.ok(leg, detourIds.join('/') + ' is not being passed')
|
||||
})
|
||||
|
||||
module.exports = testJourneysWithDetour
|
28
test/lib/util.js
Normal file
28
test/lib/util.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
'use strict'
|
||||
|
||||
const isRoughlyEqual = require('is-roughly-equal')
|
||||
const {DateTime} = require('luxon')
|
||||
const a = require('assert')
|
||||
|
||||
const hour = 60 * 60 * 1000
|
||||
const day = 24 * hour
|
||||
const week = 7 * day
|
||||
|
||||
// next Monday 10 am
|
||||
const createWhen = (timezone, locale) => {
|
||||
return DateTime.fromMillis(Date.now(), {
|
||||
zone: timezone,
|
||||
locale,
|
||||
}).startOf('week').plus({weeks: 1, hours: 10}).toJSDate()
|
||||
}
|
||||
|
||||
const assertValidWhen = (actual, expected, name) => {
|
||||
const ts = +new Date(actual)
|
||||
a.ok(!Number.isNaN(ts), name + ' is not parsable by Date')
|
||||
// the timestamps might be from long-distance trains
|
||||
a.ok(isRoughlyEqual(day, +expected, ts), name + ' is out of range')
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hour, createWhen, assertValidWhen
|
||||
}
|
30
test/lib/validate-fptf-with.js
Normal file
30
test/lib/validate-fptf-with.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
'use strict'
|
||||
|
||||
const {defaultValidators} = require('validate-fptf')
|
||||
const anyOf = require('validate-fptf/lib/any-of')
|
||||
|
||||
const validators = require('./validators')
|
||||
|
||||
const create = (cfg, customValidators = {}) => {
|
||||
const val = Object.assign({}, defaultValidators)
|
||||
for (let key of Object.keys(validators)) {
|
||||
val[key] = validators[key](cfg)
|
||||
}
|
||||
Object.assign(val, customValidators)
|
||||
|
||||
const validateFptfWith = (t, item, allowedTypes, name) => {
|
||||
try {
|
||||
if ('string' === typeof allowedTypes) {
|
||||
val[allowedTypes](val, item, name)
|
||||
} else {
|
||||
anyOf(allowedTypes, val, item, name)
|
||||
}
|
||||
t.pass(name + ' is valid')
|
||||
} catch (err) {
|
||||
t.ifError(err) // todo: improve error logging
|
||||
}
|
||||
}
|
||||
return validateFptfWith
|
||||
}
|
||||
|
||||
module.exports = create
|
306
test/lib/validators.js
Normal file
306
test/lib/validators.js
Normal file
|
@ -0,0 +1,306 @@
|
|||
'use strict'
|
||||
|
||||
const a = require('assert')
|
||||
const {defaultValidators} = require('validate-fptf')
|
||||
const anyOf = require('validate-fptf/lib/any-of')
|
||||
|
||||
const {assertValidWhen} = require('./util')
|
||||
|
||||
const isObj = o => o !== null && 'object' === typeof o && !Array.isArray(o)
|
||||
const is = val => val !== null && val !== undefined
|
||||
|
||||
const createValidateStation = (cfg) => {
|
||||
const validateStation = (val, s, name = 'station') => {
|
||||
defaultValidators.station(val, s, name)
|
||||
|
||||
if (!cfg.stationCoordsOptional) {
|
||||
a.ok(is(s.location), `missing ${name}.location`)
|
||||
}
|
||||
a.ok(isObj(s.products), name + '.products must be an object')
|
||||
for (let product of cfg.products) {
|
||||
const msg = name + `.products[${product.id}] must be a boolean`
|
||||
a.strictEqual(typeof s.products[product.id], 'boolean', msg)
|
||||
}
|
||||
|
||||
if ('lines' in s) {
|
||||
a.ok(Array.isArray(s.lines), name + `.lines must be an array`)
|
||||
for (let i = 0; i < s.lines.length; i++) {
|
||||
val.line(val, s.lines[i], name + `.lines[${i}]`)
|
||||
}
|
||||
}
|
||||
}
|
||||
return validateStation
|
||||
}
|
||||
|
||||
const validatePoi = (val, poi, name = 'location') => {
|
||||
defaultValidators.location(val, poi, name)
|
||||
val.ref(val, poi.id, name + '.id')
|
||||
a.ok(poi.name, name + '.name must not be empty')
|
||||
}
|
||||
|
||||
const validateAddress = (val, addr, name = 'location') => {
|
||||
defaultValidators.location(val, addr, name)
|
||||
a.strictEqual(typeof addr.address, 'string', name + '.address must be a string')
|
||||
a.ok(addr.address, name + '.address must not be empty')
|
||||
}
|
||||
|
||||
const validateLocation = (val, loc, name = 'location') => {
|
||||
a.ok(isObj(loc), name + ' must be an object')
|
||||
if (loc.type === 'station') val.station(val, loc, name)
|
||||
else if ('id' in loc) validatePoi(val, loc, name)
|
||||
else if (!('name' in loc) && ('address' in loc)) {
|
||||
validateAddress(val, loc, name)
|
||||
} else defaultValidators.location(val, loc, name)
|
||||
}
|
||||
|
||||
const validateLocations = (val, locs, name = 'locations') => {
|
||||
a.ok(Array.isArray(locs), name + ' must be an array')
|
||||
a.ok(locs.length > 0, name + ' must not be empty')
|
||||
for (let i = 0; i < locs.length; i++) {
|
||||
val.location(val, locs[i], name + `[${i}]`)
|
||||
}
|
||||
}
|
||||
|
||||
const createValidateLine = (cfg) => {
|
||||
const validLineModes = []
|
||||
for (let product of cfg.products) {
|
||||
if (!validLineModes.includes(product.mode)) {
|
||||
validLineModes.push(product.mode)
|
||||
}
|
||||
}
|
||||
|
||||
const validateLine = (val, line, name = 'line') => {
|
||||
defaultValidators.line(val, line, name)
|
||||
a.ok(validLineModes.includes(line.mode), name + '.mode is invalid')
|
||||
}
|
||||
return validateLine
|
||||
}
|
||||
|
||||
const createValidateStopover = (cfg) => {
|
||||
const validateStopover = (val, s, name = 'stopover') => {
|
||||
if (is(s.arrival)) {
|
||||
val.date(val, s.arrival, name + '.arrival')
|
||||
assertValidWhen(s.arrival, cfg.when, name)
|
||||
}
|
||||
if (is(s.departure)) {
|
||||
val.date(val, s.departure, name + '.departure')
|
||||
assertValidWhen(s.departure, cfg.when, name)
|
||||
}
|
||||
if (!is(s.arrival) && !is(s.departure)) {
|
||||
a.fail(name + ' contains neither arrival nor departure')
|
||||
}
|
||||
|
||||
if (is(s.arrivalDelay)) {
|
||||
const msg = name + '.arrivalDelay must be a number'
|
||||
a.strictEqual(typeof s.arrivalDelay, 'number', msg)
|
||||
}
|
||||
if (is(s.departureDelay)) {
|
||||
const msg = name + '.departureDelay must be a number'
|
||||
a.strictEqual(typeof s.departureDelay, 'number', msg)
|
||||
}
|
||||
|
||||
val.station(val, s.station, name + '.station')
|
||||
}
|
||||
return validateStopover
|
||||
}
|
||||
|
||||
const validateTicket = (val, ti, name = 'ticket') => {
|
||||
a.strictEqual(typeof ti.name, 'string', name + '.name must be a string')
|
||||
a.ok(ti.name, name + '.name must not be empty')
|
||||
|
||||
if (is(ti.price)) {
|
||||
a.strictEqual(typeof ti.price, 'number', name + '.price must be a number')
|
||||
a.ok(ti.price > 0, name + '.price must be >0')
|
||||
}
|
||||
if (is(ti.amount)) {
|
||||
a.strictEqual(typeof ti.amount, 'number', name + '.amount must be a number')
|
||||
a.ok(ti.amount > 0, name + '.amount must be >0')
|
||||
}
|
||||
|
||||
// todo: move to VBB tests
|
||||
if ('bike' in ti) {
|
||||
a.strictEqual(typeof ti.bike, 'boolean', name + '.bike must be a boolean')
|
||||
}
|
||||
if ('shortTrip' in ti) {
|
||||
a.strictEqual(typeof ti.shortTrip, 'boolean', name + '.shortTrip must be a boolean')
|
||||
}
|
||||
if ('group' in ti) {
|
||||
a.strictEqual(typeof ti.group, 'boolean', name + '.group must be a boolean')
|
||||
}
|
||||
if ('fullDay' in ti) {
|
||||
a.strictEqual(typeof ti.fullDay, 'boolean', name + '.fullDay must be a boolean')
|
||||
}
|
||||
if ('tariff' in ti) {
|
||||
a.strictEqual(typeof ti.tariff, 'string', name + '.tariff must be a string')
|
||||
a.ok(ti.tariff, name + '.tariff must not be empty')
|
||||
}
|
||||
if ('coverage' in ti) {
|
||||
a.strictEqual(typeof ti.coverage, 'string', name + '.coverage must be a string')
|
||||
a.ok(ti.coverage, name + '.coverage must not be empty')
|
||||
}
|
||||
if ('variant' in ti) {
|
||||
a.strictEqual(typeof ti.variant, 'string', name + '.variant must be a string')
|
||||
a.ok(ti.variant, name + '.variant must not be empty')
|
||||
}
|
||||
}
|
||||
|
||||
const createValidateJourneyLeg = (cfg) => {
|
||||
const validateJourneyLeg = (val, leg, name = 'journeyLeg') => {
|
||||
const withFakeScheduleAndOperator = Object.assign({
|
||||
schedule: 'foo', // todo: let hafas-client parse a schedule ID
|
||||
operator: 'bar' // todo: let hafas-client parse the operator
|
||||
}, leg)
|
||||
defaultValidators.journeyLeg(val, withFakeScheduleAndOperator, name)
|
||||
|
||||
if (leg.arrival !== null) {
|
||||
assertValidWhen(leg.arrival, cfg.when, name + '.arrival')
|
||||
}
|
||||
if (leg.departure !== null) {
|
||||
assertValidWhen(leg.departure, cfg.when, name + '.departure')
|
||||
}
|
||||
// todo: leg.arrivalPlatform !== null
|
||||
if (is(leg.arrivalPlatform)) {
|
||||
const msg = name + '.arrivalPlatform must be a string'
|
||||
a.strictEqual(typeof leg.arrivalPlatform, 'string', msg)
|
||||
a.ok(leg.arrivalPlatform, name + '.arrivalPlatform must not be empty')
|
||||
}
|
||||
// todo: leg.departurePlatform !== null
|
||||
if (is(leg.departurePlatform)) {
|
||||
const msg = name + '.departurePlatform must be a string'
|
||||
a.strictEqual(typeof leg.departurePlatform, 'string', msg)
|
||||
a.ok(leg.departurePlatform, name + '.departurePlatform must not be empty')
|
||||
}
|
||||
|
||||
if ('passed' in leg) {
|
||||
a.ok(Array.isArray(leg.passed), name + '.passed must be an array')
|
||||
a.ok(leg.passed.length > 0, name + '.passed must not be empty')
|
||||
|
||||
for (let i = 0; i < leg.passed.length; i++) {
|
||||
val.stopover(val, leg.passed[i], name + `.passed[${i}]`)
|
||||
}
|
||||
}
|
||||
|
||||
if (leg.mode !== 'walking') {
|
||||
const msg = name + '.direction must be a string'
|
||||
a.strictEqual(typeof leg.direction, 'string', msg)
|
||||
a.ok(leg.direction, name + '.direction must not be empty')
|
||||
}
|
||||
}
|
||||
return validateJourneyLeg
|
||||
}
|
||||
|
||||
const validateJourney = (val, j, name = 'journey') => {
|
||||
const withFakeId = Object.assign({
|
||||
id: 'foo' // todo: let hafas-client parse a journey ID
|
||||
}, j)
|
||||
defaultValidators.journey(val, withFakeId, name)
|
||||
|
||||
if ('tickets' in j) {
|
||||
a.ok(Array.isArray(j.tickets), name + '.tickets must be an array')
|
||||
a.ok(j.tickets.length > 0, name + '.tickets must not be empty')
|
||||
|
||||
for (let i = 0; i < j.tickets.length; i++) {
|
||||
val.ticket(val, j.tickets[i], name + `.tickets[${i}]`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const validateJourneys = (val, js, name = 'journeys') => {
|
||||
a.ok(Array.isArray(js), name + ' must be an array')
|
||||
a.ok(js.length > 0, name + ' must not be empty')
|
||||
for (let i = 0; i < js.length; i++) {
|
||||
val.journey(val, js[i], name + `[${i}]`)
|
||||
}
|
||||
}
|
||||
|
||||
const createValidateDeparture = (cfg) => {
|
||||
const validateDeparture = (val, dep, name = 'departure') => {
|
||||
a.ok(isObj(dep), name + ' must be an object')
|
||||
// todo: let hafas-client add a .type field
|
||||
|
||||
a.strictEqual(typeof dep.journeyId, 'string', name + '.journeyId must be a string')
|
||||
a.ok(dep.journeyId, name + '.journeyId must not be empty')
|
||||
a.strictEqual(typeof dep.trip, 'number', name + '.trip must be a number')
|
||||
|
||||
val.station(val, dep.station, name + '.station')
|
||||
|
||||
assertValidWhen(dep.when, cfg.when, name)
|
||||
if (dep.delay !== null) {
|
||||
const msg = name + '.delay must be a number'
|
||||
a.strictEqual(typeof dep.delay, 'number', msg)
|
||||
}
|
||||
|
||||
val.line(val, dep.line, name + '.line')
|
||||
a.strictEqual(typeof dep.direction, 'string', name + '.direction must be a string')
|
||||
a.ok(dep.direction, name + '.direction must not be empty')
|
||||
}
|
||||
return validateDeparture
|
||||
}
|
||||
|
||||
const validateDepartures = (val, deps, name = 'departures') => {
|
||||
a.ok(Array.isArray(deps), name + ' must be an array')
|
||||
a.ok(deps.length > 0, name + ' must not be empty')
|
||||
for (let i = 0; i < deps.length; i++) {
|
||||
val.departure(val, deps[i], name + `[${i}]`)
|
||||
}
|
||||
}
|
||||
|
||||
const validateMovement = (val, m, name = 'movement') => {
|
||||
a.ok(isObj(m), name + ' must be an object')
|
||||
// todo: let hafas-client add a .type field
|
||||
|
||||
val.line(val, m.line, name + '.line')
|
||||
a.strictEqual(typeof m.direction, 'string', name + '.direction must be a string')
|
||||
a.ok(m.direction, name + '.direction must not be empty')
|
||||
|
||||
const lName = name + '.location'
|
||||
val.location(val, m.location, lName)
|
||||
a.ok(m.location.latitude <= 55, lName + '.latitude is too small')
|
||||
a.ok(m.location.latitude >= 45, lName + '.latitude is too large')
|
||||
a.ok(m.location.longitude >= 9, lName + '.longitude is too small')
|
||||
a.ok(m.location.longitude <= 15, lName + '.longitude is too small')
|
||||
|
||||
a.ok(Array.isArray(m.nextStops), name + '.nextStops must be an array')
|
||||
for (let i = 0; i < m.nextStops.length; i++) {
|
||||
const st = m.nextStops[i]
|
||||
val.stopover(val, m.nextStops[i], name + `.nextStops[${i}]`)
|
||||
}
|
||||
|
||||
a.ok(Array.isArray(m.frames), name + '.frames must be an array')
|
||||
a.ok(m.frames.length > 0, name + '.frames must not be empty')
|
||||
for (let i = 0; i < m.frames.length; i++) {
|
||||
const f = m.frames[i]
|
||||
const fName = name + `.frames[${i}]`
|
||||
|
||||
a.ok(isObj(f), fName + ' must be an object')
|
||||
anyOf(['location', 'station'], val, f.origin, fName + '.origin')
|
||||
anyOf(['location', 'station'], val, f.destination, fName + '.destination')
|
||||
a.strictEqual(typeof f.t, 'number', fName + '.frames must be a number')
|
||||
}
|
||||
}
|
||||
|
||||
const validateMovements = (val, ms, name = 'movements') => {
|
||||
a.ok(Array.isArray(ms), name + ' must be an array')
|
||||
a.ok(ms.length > 0, name + ' must not be empty')
|
||||
for (let i = 0; i < ms.length; i++) {
|
||||
val.movement(val, ms[i], name + `[${i}]`)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
station: createValidateStation,
|
||||
location: () => validateLocation,
|
||||
locations: () => validateLocations,
|
||||
poi: () => validatePoi,
|
||||
address: () => validateAddress,
|
||||
line: createValidateLine,
|
||||
stopover: createValidateStopover,
|
||||
ticket: () => validateTicket,
|
||||
journeyLeg: createValidateJourneyLeg,
|
||||
journey: () => validateJourney,
|
||||
journeys: () => validateJourneys,
|
||||
departure: createValidateDeparture,
|
||||
departures: () => validateDepartures,
|
||||
movement: () => validateMovement,
|
||||
movements: () => validateMovements
|
||||
}
|
506
test/nahsh.js
506
test/nahsh.js
|
@ -1,69 +1,49 @@
|
|||
'use strict'
|
||||
|
||||
// todo
|
||||
// const getStations = require('db-stations').full
|
||||
const tapePromise = require('tape-promise').default
|
||||
const tape = require('tape')
|
||||
const isRoughlyEqual = require('is-roughly-equal')
|
||||
const validateFptf = require('validate-fptf')
|
||||
|
||||
const validateLineWithoutMode = require('./validate-line-without-mode')
|
||||
|
||||
const co = require('./co')
|
||||
const {createWhen} = require('./lib/util')
|
||||
const co = require('./lib/co')
|
||||
const createClient = require('..')
|
||||
const nahshProfile = require('../p/nahsh')
|
||||
const allProducts = require('../p/nahsh/products')
|
||||
const products = require('../p/nahsh/products')
|
||||
const {
|
||||
assertValidStation,
|
||||
assertValidPoi,
|
||||
assertValidAddress,
|
||||
assertValidLocation,
|
||||
assertValidStopover,
|
||||
hour, createWhen, assertValidWhen
|
||||
} = require('./util.js')
|
||||
line: createValidateLine,
|
||||
station: createValidateStation
|
||||
} = require('./lib/validators')
|
||||
const createValidate = require('./lib/validate-fptf-with')
|
||||
const testJourneysStationToStation = require('./lib/journeys-station-to-station')
|
||||
const testJourneysStationToAddress = require('./lib/journeys-station-to-address')
|
||||
const testJourneysStationToPoi = require('./lib/journeys-station-to-poi')
|
||||
const testEarlierLaterJourneys = require('./lib/earlier-later-journeys')
|
||||
const journeysFailsWithNoProduct = require('./lib/journeys-fails-with-no-product')
|
||||
const testDepartures = require('./lib/departures')
|
||||
|
||||
const when = createWhen('Europe/Berlin', 'de-DE')
|
||||
|
||||
const assertValidStationProducts = (t, p) => {
|
||||
t.ok(p)
|
||||
t.equal(typeof p.nationalExp, 'boolean')
|
||||
t.equal(typeof p.national, 'boolean')
|
||||
t.equal(typeof p.interregional, 'boolean')
|
||||
t.equal(typeof p.regional, 'boolean')
|
||||
t.equal(typeof p.suburban, 'boolean')
|
||||
t.equal(typeof p.bus, 'boolean')
|
||||
t.equal(typeof p.ferry, 'boolean')
|
||||
t.equal(typeof p.subway, 'boolean')
|
||||
t.equal(typeof p.tram, 'boolean')
|
||||
t.equal(typeof p.onCall, 'boolean')
|
||||
const cfg = {
|
||||
when,
|
||||
stationCoordsOptional: false,
|
||||
products
|
||||
}
|
||||
|
||||
const isKielHbf = (s) => {
|
||||
return s.type === 'station' &&
|
||||
(s.id === '8000199') &&
|
||||
s.name === 'Kiel Hbf' &&
|
||||
s.location &&
|
||||
isRoughlyEqual(.0005, s.location.latitude, 54.314982) &&
|
||||
isRoughlyEqual(.0005, s.location.longitude, 10.131976)
|
||||
}
|
||||
|
||||
const assertIsKielHbf = (t, s) => {
|
||||
t.equal(s.type, 'station')
|
||||
t.ok(s.id === '8000199', 'id should be 8000199')
|
||||
t.equal(s.name, 'Kiel Hbf')
|
||||
t.ok(s.location)
|
||||
t.ok(isRoughlyEqual(.0005, s.location.latitude, 54.314982))
|
||||
t.ok(isRoughlyEqual(.0005, s.location.longitude, 10.131976))
|
||||
}
|
||||
|
||||
// todo: DRY with assertValidStationProducts
|
||||
// todo: DRY with other tests
|
||||
const assertValidProducts = (t, products) => {
|
||||
for (let p of allProducts) {
|
||||
t.equal(typeof products[p.id], 'boolean', `product ${p.id} must be a boolean`)
|
||||
const _validateLine = createValidateLine(cfg)
|
||||
const validateLine = (validate, l, name) => {
|
||||
if (l && l.product === 'onCall') {
|
||||
// skip line validation
|
||||
// https://github.com/derhuerst/hafas-client/issues/8#issuecomment-355839965
|
||||
l = Object.assign({}, l)
|
||||
l.mode = 'taxi'
|
||||
}
|
||||
_validateLine(validate, l, name)
|
||||
}
|
||||
|
||||
const validate = createValidate(cfg, {
|
||||
line: validateLine
|
||||
})
|
||||
|
||||
const assertValidPrice = (t, p) => {
|
||||
t.ok(p)
|
||||
if (p.amount !== null) {
|
||||
|
@ -76,18 +56,6 @@ const assertValidPrice = (t, p) => {
|
|||
}
|
||||
}
|
||||
|
||||
const assertValidLine = (t, l) => { // with optional mode
|
||||
const validators = Object.assign({}, validateFptf.defaultValidators, {
|
||||
line: validateLineWithoutMode
|
||||
})
|
||||
const recurse = validateFptf.createRecurse(validators)
|
||||
try {
|
||||
recurse(['line'], l, 'line')
|
||||
} catch (err) {
|
||||
t.ifError(err)
|
||||
}
|
||||
}
|
||||
|
||||
const test = tapePromise(tape)
|
||||
const client = createClient(nahshProfile)
|
||||
|
||||
|
@ -97,192 +65,125 @@ const luebeckHbf = '8000237'
|
|||
const husum = '8000181'
|
||||
const schleswig = '8005362'
|
||||
|
||||
test('Kiel Hbf to Flensburg', co(function* (t) {
|
||||
test('journeys – Kiel Hbf to Flensburg', co(function* (t) {
|
||||
const journeys = yield client.journeys(kielHbf, flensburg, {
|
||||
departure: when, passedStations: true
|
||||
results: 3,
|
||||
departure: when,
|
||||
passedStations: true
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.ok(journeys.length > 0, 'no journeys')
|
||||
for (let journey of journeys) {
|
||||
t.equal(journey.type, 'journey')
|
||||
yield testJourneysStationToStation({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: kielHbf,
|
||||
toId: flensburg
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(journey.legs))
|
||||
t.ok(journey.legs.length > 0, 'no legs')
|
||||
const leg = journey.legs[0] // todo: all legs
|
||||
|
||||
assertValidStation(t, leg.origin)
|
||||
assertValidStationProducts(t, leg.origin.products)
|
||||
// todo
|
||||
// if (!(yield findStation(leg.origin.id))) {
|
||||
// console.error('unknown station', leg.origin.id, leg.origin.name)
|
||||
// }
|
||||
assertValidWhen(t, leg.departure, when)
|
||||
t.equal(typeof leg.departurePlatform, 'string')
|
||||
|
||||
assertValidStation(t, leg.destination)
|
||||
assertValidStationProducts(t, leg.origin.products)
|
||||
// todo
|
||||
// if (!(yield findStation(leg.destination.id))) {
|
||||
// console.error('unknown station', leg.destination.id, leg.destination.name)
|
||||
// }
|
||||
assertValidWhen(t, leg.arrival, when)
|
||||
t.equal(typeof leg.arrivalPlatform, 'string')
|
||||
|
||||
assertValidLine(t, leg.line)
|
||||
|
||||
t.ok(Array.isArray(leg.passed))
|
||||
for (let stopover of leg.passed) assertValidStopover(t, stopover)
|
||||
|
||||
if (journey.price) assertValidPrice(t, journey.price)
|
||||
for (let i = 0; i < journeys.length; i++) {
|
||||
const j = journeys[i]
|
||||
// todo: find a journey where there pricing info is always available
|
||||
if (j.price) assertValidPrice(t, j.price, `journeys[${i}].price`)
|
||||
}
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
// todo: journeys, only one product
|
||||
|
||||
test('journeys – fails with no product', (t) => {
|
||||
journeysFailsWithNoProduct({
|
||||
test: t,
|
||||
fetchJourneys: client.journeys,
|
||||
fromId: kielHbf,
|
||||
toId: flensburg,
|
||||
when,
|
||||
products
|
||||
})
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Kiel Hbf to Husum, Zingel 10', co(function* (t) {
|
||||
const zingel = {
|
||||
type: 'location',
|
||||
address: 'Husum, Zingel 10',
|
||||
latitude: 54.475359,
|
||||
longitude: 9.050798,
|
||||
address: 'Husum, Zingel 10'
|
||||
longitude: 9.050798
|
||||
}
|
||||
|
||||
const journeys = yield client.journeys(kielHbf, zingel, {departure: when})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.ok(journeys.length >= 1, 'no journeys')
|
||||
const journey = journeys[0]
|
||||
const firstLeg = journey.legs[0]
|
||||
const lastLeg = journey.legs[journey.legs.length - 1]
|
||||
|
||||
assertValidStation(t, firstLeg.origin)
|
||||
assertValidStationProducts(t, firstLeg.origin.products)
|
||||
// todo
|
||||
// if (!(yield findStation(leg.origin.id))) {
|
||||
// console.error('unknown station', leg.origin.id, leg.origin.name)
|
||||
// }
|
||||
if (firstLeg.origin.products) assertValidProducts(t, firstLeg.origin.products)
|
||||
assertValidWhen(t, firstLeg.departure, when)
|
||||
assertValidWhen(t, firstLeg.arrival, when)
|
||||
assertValidWhen(t, lastLeg.departure, when)
|
||||
assertValidWhen(t, lastLeg.arrival, when)
|
||||
|
||||
const d = lastLeg.destination
|
||||
assertValidAddress(t, d)
|
||||
t.equal(d.address, 'Husum, Zingel 10')
|
||||
t.ok(isRoughlyEqual(.0001, d.latitude, 54.475359))
|
||||
t.ok(isRoughlyEqual(.0001, d.longitude, 9.050798))
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('Holstentor to Kiel Hbf', co(function* (t) {
|
||||
const holstentor = {
|
||||
type: 'location',
|
||||
latitude: 53.866321,
|
||||
longitude: 10.679976,
|
||||
name: 'Hansestadt Lübeck, Holstentor (Denkmal)',
|
||||
id: '970003547'
|
||||
}
|
||||
const journeys = yield client.journeys(holstentor, kielHbf, {departure: when})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.ok(journeys.length >= 1, 'no journeys')
|
||||
const journey = journeys[0]
|
||||
const firstLeg = journey.legs[0]
|
||||
const lastLeg = journey.legs[journey.legs.length - 1]
|
||||
|
||||
const o = firstLeg.origin
|
||||
assertValidPoi(t, o)
|
||||
t.equal(o.name, 'Hansestadt Lübeck, Holstentor (Denkmal)')
|
||||
t.ok(isRoughlyEqual(.0001, o.latitude, 53.866321))
|
||||
t.ok(isRoughlyEqual(.0001, o.longitude, 10.679976))
|
||||
|
||||
assertValidWhen(t, firstLeg.departure, when)
|
||||
assertValidWhen(t, firstLeg.arrival, when)
|
||||
assertValidWhen(t, lastLeg.departure, when)
|
||||
assertValidWhen(t, lastLeg.arrival, when)
|
||||
|
||||
assertValidStation(t, lastLeg.destination)
|
||||
assertValidStationProducts(t, lastLeg.destination.products)
|
||||
if (lastLeg.destination.products) assertValidProducts(t, lastLeg.destination.products)
|
||||
// todo
|
||||
// if (!(yield findStation(leg.destination.id))) {
|
||||
// console.error('unknown station', leg.destination.id, leg.destination.name)
|
||||
// }
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('Husum to Lübeck Hbf with stopover at Husum', co(function* (t) {
|
||||
const [journey] = yield client.journeys(husum, luebeckHbf, {
|
||||
via: kielHbf,
|
||||
results: 1,
|
||||
const journeys = yield client.journeys(kielHbf, zingel, {
|
||||
results: 3,
|
||||
departure: when
|
||||
})
|
||||
|
||||
const i1 = journey.legs.findIndex(leg => leg.destination.id === kielHbf)
|
||||
t.ok(i1 >= 0, 'no leg with Kiel Hbf as destination')
|
||||
yield testJourneysStationToAddress({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: kielHbf,
|
||||
to: zingel
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
const i2 = journey.legs.findIndex(leg => leg.origin.id === kielHbf)
|
||||
t.ok(i2 >= 0, 'no leg with Kiel Hbf as origin')
|
||||
t.ok(i2 > i1, 'leg with Kiel Hbf as origin must be after leg to it')
|
||||
test('Kiel Hbf to Holstentor', co(function* (t) {
|
||||
const holstentor = {
|
||||
type: 'location',
|
||||
id: '970003547',
|
||||
name: 'Hansestadt Lübeck, Holstentor (Denkmal)',
|
||||
latitude: 53.866321,
|
||||
longitude: 10.679976
|
||||
}
|
||||
const journeys = yield client.journeys(kielHbf, holstentor, {
|
||||
results: 3,
|
||||
departure: when
|
||||
})
|
||||
|
||||
yield testJourneysStationToPoi({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: kielHbf,
|
||||
to: holstentor
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('Husum to Lübeck Hbf with stopover at Kiel Hbf', co(function* (t) {
|
||||
const journeys = yield client.journeys(husum, luebeckHbf, {
|
||||
via: kielHbf,
|
||||
results: 1,
|
||||
departure: when,
|
||||
passedStations: true
|
||||
})
|
||||
|
||||
validate(t, journeys, 'journeys', 'journeys')
|
||||
|
||||
const leg = journeys[0].legs.some((leg) => {
|
||||
return leg.passed && leg.passed.some((passed) => {
|
||||
return passed.station.id === kielHbf
|
||||
})
|
||||
})
|
||||
t.ok(leg, 'Kiel Hbf is not being passed')
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('earlier/later journeys, Kiel Hbf -> Flensburg', co(function* (t) {
|
||||
const model = yield client.journeys(kielHbf, flensburg, {
|
||||
results: 3, departure: when
|
||||
yield testEarlierLaterJourneys({
|
||||
test: t,
|
||||
fetchJourneys: client.journeys,
|
||||
validate,
|
||||
fromId: kielHbf,
|
||||
toId: flensburg
|
||||
})
|
||||
|
||||
t.equal(typeof model.earlierRef, 'string')
|
||||
t.ok(model.earlierRef)
|
||||
t.equal(typeof model.laterRef, 'string')
|
||||
t.ok(model.laterRef)
|
||||
|
||||
// when and earlierThan/laterThan should be mutually exclusive
|
||||
t.throws(() => {
|
||||
client.journeys(kielHbf, flensburg, {
|
||||
departure: when, earlierThan: model.earlierRef
|
||||
})
|
||||
})
|
||||
t.throws(() => {
|
||||
client.journeys(kielHbf, flensburg, {
|
||||
departure: when, laterThan: model.laterRef
|
||||
})
|
||||
})
|
||||
|
||||
let earliestDep = Infinity, latestDep = -Infinity
|
||||
for (let j of model) {
|
||||
const dep = +new Date(j.legs[0].departure)
|
||||
if (dep < earliestDep) earliestDep = dep
|
||||
else if (dep > latestDep) latestDep = dep
|
||||
}
|
||||
|
||||
const earlier = yield client.journeys(kielHbf, flensburg, {
|
||||
results: 3,
|
||||
// todo: single journey ref?
|
||||
earlierThan: model.earlierRef
|
||||
})
|
||||
for (let j of earlier) {
|
||||
t.ok(new Date(j.legs[0].departure) < earliestDep)
|
||||
}
|
||||
|
||||
const later = yield client.journeys(kielHbf, flensburg, {
|
||||
results: 3,
|
||||
// todo: single journey ref?
|
||||
laterThan: model.laterRef
|
||||
})
|
||||
for (let j of later) {
|
||||
t.ok(new Date(j.legs[0].departure) > latestDep)
|
||||
}
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('leg details for Flensburg to Husum', co(function* (t) {
|
||||
// todo: with detour test
|
||||
// todo: without detour test
|
||||
|
||||
test('journey leg details for Flensburg to Husum', co(function* (t) {
|
||||
const journeys = yield client.journeys(flensburg, husum, {
|
||||
results: 1, departure: when
|
||||
})
|
||||
|
@ -292,37 +193,39 @@ test('leg details for Flensburg to Husum', co(function* (t) {
|
|||
t.ok(p.line.name, 'precondition failed')
|
||||
const leg = yield client.journeyLeg(p.id, p.line.name, {when})
|
||||
|
||||
t.equal(typeof leg.id, 'string')
|
||||
t.ok(leg.id)
|
||||
|
||||
assertValidLine(t, leg.line)
|
||||
|
||||
t.equal(typeof leg.direction, 'string')
|
||||
t.ok(leg.direction)
|
||||
|
||||
t.ok(Array.isArray(leg.passed))
|
||||
for (let passed of leg.passed) assertValidStopover(t, passed)
|
||||
|
||||
validate(t, leg, 'journeyLeg', 'leg')
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('departures at Kiel Hbf', co(function* (t) {
|
||||
const deps = yield client.departures(kielHbf, {
|
||||
test('departures at Kiel Räucherei', co(function* (t) {
|
||||
const kielRaeucherei = '3440091'
|
||||
|
||||
const departures = yield client.departures(kielRaeucherei, {
|
||||
duration: 30, when
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(deps))
|
||||
for (let dep of deps) {
|
||||
assertValidStation(t, dep.station)
|
||||
assertValidStationProducts(t, dep.station.products)
|
||||
// todo
|
||||
// if (!(yield findStation(dep.station.id))) {
|
||||
// console.error('unknown station', dep.station.id, dep.station.name)
|
||||
// }
|
||||
if (dep.station.products) assertValidProducts(t, dep.station.products)
|
||||
assertValidWhen(t, dep.when, when)
|
||||
}
|
||||
yield testDepartures({
|
||||
test: t,
|
||||
departures,
|
||||
validate,
|
||||
id: kielRaeucherei
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('departures with station object', co(function* (t) {
|
||||
const deps = yield client.departures({
|
||||
type: 'station',
|
||||
id: kielHbf,
|
||||
name: 'Kiel Hbf',
|
||||
location: {
|
||||
type: 'location',
|
||||
latitude: 1.23,
|
||||
longitude: 2.34
|
||||
}
|
||||
}, {when})
|
||||
|
||||
validate(t, deps, 'departures', 'departures')
|
||||
t.end()
|
||||
}))
|
||||
|
||||
|
@ -336,77 +239,44 @@ test('nearby Kiel Hbf', co(function* (t) {
|
|||
results: 2, distance: 400
|
||||
})
|
||||
|
||||
validate(t, nearby, 'locations', 'nearby')
|
||||
|
||||
t.ok(Array.isArray(nearby))
|
||||
t.equal(nearby.length, 2)
|
||||
|
||||
assertIsKielHbf(t, nearby[0])
|
||||
t.equal(nearby[0].id, kielHbf)
|
||||
t.equal(nearby[0].name, 'Kiel Hbf')
|
||||
t.ok(nearby[0].distance >= 0)
|
||||
t.ok(nearby[0].distance <= 100)
|
||||
|
||||
for (let n of nearby) {
|
||||
if (n.type === 'station') assertValidStation(t, n)
|
||||
else assertValidLocation(t, n)
|
||||
}
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('locations named Kiel', co(function* (t) {
|
||||
const locations = yield client.locations('Kiel', {
|
||||
results: 10
|
||||
results: 20
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(locations))
|
||||
t.ok(locations.length > 0)
|
||||
t.ok(locations.length <= 10)
|
||||
validate(t, locations, 'locations', 'locations')
|
||||
t.ok(locations.length <= 20)
|
||||
|
||||
for (let l of locations) {
|
||||
if (l.type === 'station') assertValidStation(t, l)
|
||||
else assertValidLocation(t, l)
|
||||
}
|
||||
t.ok(locations.some(isKielHbf))
|
||||
t.ok(locations.find(s => s.type === 'station'))
|
||||
t.ok(locations.find(s => s.id && s.name)) // POIs
|
||||
t.ok(locations.some(l => l.id === kielHbf))
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('station', co(function* (t) {
|
||||
const loc = yield client.station(schleswig)
|
||||
const s = yield client.station(kielHbf)
|
||||
|
||||
assertValidStation(t, loc)
|
||||
t.equal(loc.id, schleswig)
|
||||
validate(t, s, 'station', 'station')
|
||||
t.equal(s.id, kielHbf)
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('radar Kiel', co(function* (t) {
|
||||
const fakeStation = (s) => {
|
||||
const fake = Object.assign({
|
||||
products: {
|
||||
nationalExp: true,
|
||||
national: false,
|
||||
interregional: true,
|
||||
regional: false,
|
||||
suburban: true,
|
||||
bus: false,
|
||||
ferry: true,
|
||||
subway: false,
|
||||
tram: true,
|
||||
onCall: false
|
||||
}
|
||||
}, s)
|
||||
if (s.name === null) fake.name = 'foo'
|
||||
return fake
|
||||
}
|
||||
const _assertValidStation = (t, s, coordsOptional = false) => {
|
||||
assertValidStation(t, fakeStation(s), coordsOptional)
|
||||
}
|
||||
const _assertValidStopover = (t, s, coordsOptional = false) => {
|
||||
const fake = Object.assign({}, s, {
|
||||
station: fakeStation(s.station)
|
||||
})
|
||||
assertValidStopover(t, fake, coordsOptional)
|
||||
}
|
||||
|
||||
test('radar', co(function* (t) {
|
||||
const vehicles = yield client.radar({
|
||||
north: 54.4,
|
||||
west: 10.0,
|
||||
|
@ -416,51 +286,19 @@ test('radar Kiel', co(function* (t) {
|
|||
duration: 5 * 60, when
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(vehicles))
|
||||
t.ok(vehicles.length > 0)
|
||||
for (let v of vehicles) {
|
||||
|
||||
// todo
|
||||
// t.ok(findStation(v.direction))
|
||||
assertValidLine(t, v.line)
|
||||
|
||||
t.equal(typeof v.location.latitude, 'number')
|
||||
t.ok(v.location.latitude <= 57, 'vehicle is too far away')
|
||||
t.ok(v.location.latitude >= 51, 'vehicle is too far away')
|
||||
t.equal(typeof v.location.longitude, 'number')
|
||||
t.ok(v.location.longitude >= 7, 'vehicle is too far away')
|
||||
t.ok(v.location.longitude <= 13, 'vehicle is too far away')
|
||||
|
||||
t.ok(Array.isArray(v.nextStops))
|
||||
for (let st of v.nextStops) {
|
||||
_assertValidStopover(t, st, true)
|
||||
|
||||
if (st.arrival) {
|
||||
t.equal(typeof st.arrival, 'string')
|
||||
const arr = +new Date(st.arrival)
|
||||
// note that this can be an ICE train
|
||||
t.ok(isRoughlyEqual(14 * hour, +when, arr))
|
||||
}
|
||||
if (st.departure) {
|
||||
t.equal(typeof st.departure, 'string')
|
||||
const dep = +new Date(st.departure)
|
||||
t.ok(isRoughlyEqual(14 * hour, +when, dep))
|
||||
}
|
||||
// todo: cfg.stationProductsOptional option
|
||||
const allProducts = products.reduce((acc, p) => (acc[p.id] = true, acc), {})
|
||||
const validateStation = createValidateStation(cfg)
|
||||
const validate = createValidate(cfg, {
|
||||
station: (validate, s, name) => {
|
||||
s = Object.assign({
|
||||
products: allProducts // todo: fix station.products
|
||||
}, s)
|
||||
if (!s.name) s.name = 'foo' // todo, see #34
|
||||
validateStation(validate, s, name)
|
||||
}
|
||||
})
|
||||
validate(t, vehicles, 'movements', 'vehicles')
|
||||
|
||||
t.ok(Array.isArray(v.frames))
|
||||
for (let f of v.frames) {
|
||||
// todo: see #34
|
||||
_assertValidStation(t, f.origin, true)
|
||||
if (f.origin.products) {
|
||||
assertValidStationProducts(t, f.origin.products)
|
||||
}
|
||||
_assertValidStation(t, f.destination, true)
|
||||
if (f.destination.products) {
|
||||
assertValidStationProducts(t, f.destination.products)
|
||||
}
|
||||
t.equal(typeof f.t, 'number')
|
||||
}
|
||||
}
|
||||
t.end()
|
||||
}))
|
||||
|
|
520
test/oebb.js
520
test/oebb.js
|
@ -1,86 +1,39 @@
|
|||
'use strict'
|
||||
|
||||
// todo
|
||||
// const getStations = require('db-stations').full
|
||||
const tapePromise = require('tape-promise').default
|
||||
const tape = require('tape')
|
||||
const isRoughlyEqual = require('is-roughly-equal')
|
||||
const validateFptf = require('validate-fptf')
|
||||
const validateLine = require('validate-fptf/line')
|
||||
|
||||
const validateLineWithoutMode = require('./validate-line-without-mode')
|
||||
|
||||
const co = require('./co')
|
||||
const {createWhen} = require('./lib/util')
|
||||
const co = require('./lib/co')
|
||||
const createClient = require('..')
|
||||
const oebbProfile = require('../p/oebb')
|
||||
const allProducts = require('../p/oebb/products')
|
||||
const products = require('../p/oebb/products')
|
||||
const {
|
||||
assertValidStation,
|
||||
assertValidPoi,
|
||||
assertValidAddress,
|
||||
assertValidLocation,
|
||||
assertValidStopover,
|
||||
hour, createWhen, assertValidWhen
|
||||
} = require('./util.js')
|
||||
station: createValidateStation
|
||||
} = require('./lib/validators')
|
||||
const createValidate = require('./lib/validate-fptf-with')
|
||||
const testJourneysStationToStation = require('./lib/journeys-station-to-station')
|
||||
const testJourneysStationToAddress = require('./lib/journeys-station-to-address')
|
||||
const testJourneysStationToPoi = require('./lib/journeys-station-to-poi')
|
||||
const testEarlierLaterJourneys = require('./lib/earlier-later-journeys')
|
||||
const journeysFailsWithNoProduct = require('./lib/journeys-fails-with-no-product')
|
||||
const testJourneysWithDetour = require('./lib/journeys-with-detour')
|
||||
|
||||
const when = createWhen('Europe/Vienna', 'de-AT')
|
||||
|
||||
const assertValidStationProducts = (t, p) => {
|
||||
t.ok(p)
|
||||
t.equal(typeof p.nationalExp, 'boolean')
|
||||
t.equal(typeof p.national, 'boolean')
|
||||
t.equal(typeof p.interregional, 'boolean')
|
||||
t.equal(typeof p.regional, 'boolean')
|
||||
t.equal(typeof p.suburban, 'boolean')
|
||||
t.equal(typeof p.bus, 'boolean')
|
||||
t.equal(typeof p.ferry, 'boolean')
|
||||
t.equal(typeof p.subway, 'boolean')
|
||||
t.equal(typeof p.tram, 'boolean')
|
||||
t.equal(typeof p.onCall, 'boolean')
|
||||
const cfg = {
|
||||
when,
|
||||
stationCoordsOptional: false,
|
||||
products
|
||||
}
|
||||
|
||||
// todo
|
||||
// const findStation = (id) => new Promise((yay, nay) => {
|
||||
// const stations = getStations()
|
||||
// stations
|
||||
// .once('error', nay)
|
||||
// .on('data', (s) => {
|
||||
// if (
|
||||
// s.id === id ||
|
||||
// (s.additionalIds && s.additionalIds.includes(id))
|
||||
// ) {
|
||||
// yay(s)
|
||||
// stations.destroy()
|
||||
// }
|
||||
// })
|
||||
// .once('end', yay)
|
||||
// })
|
||||
// todo validateDirection: search list of stations for direction
|
||||
|
||||
const isSalzburgHbf = (s) => {
|
||||
return s.type === 'station' &&
|
||||
(s.id === '008100002' || s.id === '8100002') &&
|
||||
s.name === 'Salzburg Hbf' &&
|
||||
s.location &&
|
||||
isRoughlyEqual(.0005, s.location.latitude, 47.812851) &&
|
||||
isRoughlyEqual(.0005, s.location.longitude, 13.045604)
|
||||
}
|
||||
|
||||
const assertIsSalzburgHbf = (t, s) => {
|
||||
t.equal(s.type, 'station')
|
||||
t.ok(s.id === '008100002' || s.id === '8100002', 'id should be 8100002')
|
||||
t.equal(s.name, 'Salzburg Hbf')
|
||||
t.ok(s.location)
|
||||
t.ok(isRoughlyEqual(.0005, s.location.latitude, 47.812851))
|
||||
t.ok(isRoughlyEqual(.0005, s.location.longitude, 13.045604))
|
||||
}
|
||||
|
||||
// todo: DRY with assertValidStationProducts
|
||||
// todo: DRY with other tests
|
||||
const assertValidProducts = (t, p) => {
|
||||
for (let product of allProducts) {
|
||||
product = product.id
|
||||
t.equal(typeof p[product], 'boolean', 'product ' + p + ' must be a boolean')
|
||||
}
|
||||
}
|
||||
const validate = createValidate(cfg, {
|
||||
line: validateLine // bypass line validator in lib/validators
|
||||
})
|
||||
|
||||
const assertValidPrice = (t, p) => {
|
||||
t.ok(p)
|
||||
|
@ -94,145 +47,95 @@ const assertValidPrice = (t, p) => {
|
|||
}
|
||||
}
|
||||
|
||||
// todo: fix this upstream
|
||||
// see https://github.com/public-transport/hafas-client/blob/c6e558be217667f1bcdac4a605898eb75ea80374/p/oebb/products.js#L71
|
||||
const assertValidLine = (t, l) => { // with optional mode
|
||||
const validators = Object.assign({}, validateFptf.defaultValidators, {
|
||||
line: validateLineWithoutMode
|
||||
})
|
||||
const recurse = validateFptf.createRecurse(validators)
|
||||
try {
|
||||
recurse(['line'], l, 'line')
|
||||
} catch (err) {
|
||||
t.ifError(err)
|
||||
}
|
||||
}
|
||||
|
||||
const test = tapePromise(tape)
|
||||
const client = createClient(oebbProfile)
|
||||
|
||||
const salzburgHbf = '8100002'
|
||||
const wienWestbahnhof = '1291501'
|
||||
const wienFickeystr = '911014'
|
||||
const wien = '1190100'
|
||||
const wienWestbahnhof = '1291501'
|
||||
const klagenfurtHbf = '8100085'
|
||||
const muenchenHbf = '8000261'
|
||||
const grazHbf = '8100173'
|
||||
const wienRenngasse = '1390186'
|
||||
|
||||
test('Salzburg Hbf to Wien Westbahnhof', co(function* (t) {
|
||||
const journeys = yield client.journeys(salzburgHbf, wienWestbahnhof, {
|
||||
departure: when, passedStations: true
|
||||
test.skip('journeys – Salzburg Hbf to Wien Westbahnhof', co(function* (t) {
|
||||
const journeys = yield client.journeys(salzburgHbf, wienFickeystr, {
|
||||
results: 3,
|
||||
departure: when,
|
||||
passedStations: true
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.ok(journeys.length > 0, 'no journeys')
|
||||
for (let journey of journeys) {
|
||||
t.equal(journey.type, 'journey')
|
||||
yield testJourneysStationToStation({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: salzburgHbf,
|
||||
toId: wienFickeystr
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(journey.legs))
|
||||
t.ok(journey.legs.length > 0, 'no legs')
|
||||
const leg = journey.legs[0] // todo: all legs
|
||||
|
||||
assertValidStation(t, leg.origin)
|
||||
assertValidStationProducts(t, leg.origin.products)
|
||||
// todo
|
||||
// if (!(yield findStation(leg.origin.id))) {
|
||||
// console.error('unknown station', leg.origin.id, leg.origin.name)
|
||||
// }
|
||||
assertValidWhen(t, leg.departure, when)
|
||||
t.equal(typeof leg.departurePlatform, 'string')
|
||||
|
||||
assertValidStation(t, leg.destination)
|
||||
assertValidStationProducts(t, leg.origin.products)
|
||||
// todo
|
||||
// if (!(yield findStation(leg.destination.id))) {
|
||||
// console.error('unknown station', leg.destination.id, leg.destination.name)
|
||||
// }
|
||||
assertValidWhen(t, leg.arrival, when)
|
||||
t.equal(typeof leg.arrivalPlatform, 'string')
|
||||
|
||||
assertValidLine(t, leg.line)
|
||||
|
||||
t.ok(Array.isArray(leg.passed))
|
||||
for (let stopover of leg.passed) assertValidStopover(t, stopover)
|
||||
|
||||
if (journey.price) assertValidPrice(t, journey.price)
|
||||
for (let i = 0; i < journeys.length; i++) {
|
||||
const j = journeys[i]
|
||||
if (j.price) assertValidPrice(t, j.price, `journeys[${i}].price`)
|
||||
}
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
// todo: journeys, only one product
|
||||
|
||||
test('journeys – fails with no product', (t) => {
|
||||
journeysFailsWithNoProduct({
|
||||
test: t,
|
||||
fetchJourneys: client.journeys,
|
||||
fromId: salzburgHbf,
|
||||
toId: wienFickeystr,
|
||||
when,
|
||||
products
|
||||
})
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Salzburg Hbf to 1220 Wien, Wagramer Straße 5', co(function* (t) {
|
||||
const wagramerStr = {
|
||||
type: 'location',
|
||||
address: '1220 Wien, Wagramer Straße 5',
|
||||
latitude: 48.236216,
|
||||
longitude: 16.425863,
|
||||
address: '1220 Wien, Wagramer Straße 5'
|
||||
longitude: 16.425863
|
||||
}
|
||||
const journeys = yield client.journeys(salzburgHbf, wagramerStr, {
|
||||
results: 3,
|
||||
departure: when
|
||||
})
|
||||
|
||||
const journeys = yield client.journeys(salzburgHbf, wagramerStr, {departure: when})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.ok(journeys.length >= 1, 'no journeys')
|
||||
const journey = journeys[0]
|
||||
const firstLeg = journey.legs[0]
|
||||
const lastLeg = journey.legs[journey.legs.length - 1]
|
||||
|
||||
assertValidStation(t, firstLeg.origin)
|
||||
assertValidStationProducts(t, firstLeg.origin.products)
|
||||
// todo
|
||||
// if (!(yield findStation(leg.origin.id))) {
|
||||
// console.error('unknown station', leg.origin.id, leg.origin.name)
|
||||
// }
|
||||
if (firstLeg.origin.products) assertValidProducts(t, firstLeg.origin.products)
|
||||
assertValidWhen(t, firstLeg.departure, when)
|
||||
assertValidWhen(t, firstLeg.arrival, when)
|
||||
assertValidWhen(t, lastLeg.departure, when)
|
||||
assertValidWhen(t, lastLeg.arrival, when)
|
||||
|
||||
const d = lastLeg.destination
|
||||
assertValidAddress(t, d)
|
||||
t.equal(d.address, '1220 Wien, Wagramer Straße 5')
|
||||
t.ok(isRoughlyEqual(.0001, d.latitude, 48.236216))
|
||||
t.ok(isRoughlyEqual(.0001, d.longitude, 16.425863))
|
||||
|
||||
yield testJourneysStationToAddress({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: salzburgHbf,
|
||||
to: wagramerStr
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('Albertina to Salzburg Hbf', co(function* (t) {
|
||||
test('Salzburg Hbf to Albertina', co(function* (t) {
|
||||
const albertina = {
|
||||
type: 'location',
|
||||
latitude: 48.204699,
|
||||
longitude: 16.368404,
|
||||
id: '975900003',
|
||||
name: 'Albertina',
|
||||
id: '975900003'
|
||||
latitude: 48.204699,
|
||||
longitude: 16.368404
|
||||
}
|
||||
const journeys = yield client.journeys(albertina, salzburgHbf, {departure: when})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.ok(journeys.length >= 1, 'no journeys')
|
||||
const journey = journeys[0]
|
||||
const firstLeg = journey.legs[0]
|
||||
const lastLeg = journey.legs[journey.legs.length - 1]
|
||||
|
||||
const o = firstLeg.origin
|
||||
assertValidPoi(t, o)
|
||||
t.equal(o.name, 'Albertina')
|
||||
t.ok(isRoughlyEqual(.0001, o.latitude, 48.204699))
|
||||
t.ok(isRoughlyEqual(.0001, o.longitude, 16.368404))
|
||||
|
||||
assertValidWhen(t, firstLeg.departure, when)
|
||||
assertValidWhen(t, firstLeg.arrival, when)
|
||||
assertValidWhen(t, lastLeg.departure, when)
|
||||
assertValidWhen(t, lastLeg.arrival, when)
|
||||
|
||||
assertValidStation(t, lastLeg.destination)
|
||||
assertValidStationProducts(t, lastLeg.destination.products)
|
||||
if (lastLeg.destination.products) assertValidProducts(t, lastLeg.destination.products)
|
||||
// todo
|
||||
// if (!(yield findStation(leg.destination.id))) {
|
||||
// console.error('unknown station', leg.destination.id, leg.destination.name)
|
||||
// }
|
||||
const journeys = yield client.journeys(salzburgHbf, albertina, {
|
||||
results: 3, departure: when
|
||||
})
|
||||
|
||||
yield testJourneysStationToPoi({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: salzburgHbf,
|
||||
to: albertina
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
|
@ -243,91 +146,66 @@ test('journeys: via works – with detour', co(function* (t) {
|
|||
const schottenring = '001390163'
|
||||
const donauinsel = '001392277'
|
||||
const donauinselPassed = '922001'
|
||||
const [journey] = yield client.journeys(stephansplatz, schottenring, {
|
||||
const journeys = yield client.journeys(stephansplatz, schottenring, {
|
||||
via: donauinsel,
|
||||
results: 1,
|
||||
departure: when,
|
||||
passedStations: true
|
||||
})
|
||||
|
||||
t.ok(journey)
|
||||
|
||||
const l = journey.legs.some(l => l.passed && l.passed.some(p => p.station.id === donauinselPassed))
|
||||
t.ok(l, 'Donauinsel is not being passed')
|
||||
|
||||
yield testJourneysWithDetour({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
detourIds: [donauinsel, donauinselPassed]
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('journeys: via works – without detour', co(function* (t) {
|
||||
// When going from Karlsplatz to Praterstern via Museumsquartier, there is *no need*
|
||||
// to change trains / no need for a "detour".
|
||||
// When going from Karlsplatz to Praterstern via Museumsquartier, there is
|
||||
// *no need* to change trains / no need for a "detour".
|
||||
const karlsplatz = '001390461'
|
||||
const praterstern = '001290201'
|
||||
const museumsquartier = '001390171'
|
||||
const museumsquartierPassed = '901014'
|
||||
|
||||
const [journey] = yield client.journeys(karlsplatz, praterstern, {
|
||||
const journeys = yield client.journeys(karlsplatz, praterstern, {
|
||||
via: museumsquartier,
|
||||
results: 1,
|
||||
departure: when,
|
||||
passedStations: true
|
||||
})
|
||||
|
||||
t.ok(journey)
|
||||
validate(t, journeys, 'journeys', 'journeys')
|
||||
|
||||
const l = journey.legs.some(l => l.passed && l.passed.some(p => p.station.id === museumsquartierPassed))
|
||||
t.ok(l, 'Weihburggasse is not being passed')
|
||||
const l1 = journeys[0].legs.some((leg) => {
|
||||
return (
|
||||
leg.destination.id === museumsquartier ||
|
||||
leg.destination.id === museumsquartierPassed
|
||||
)
|
||||
})
|
||||
t.notOk(l1, 'transfer at Museumsquartier')
|
||||
|
||||
const l2 = journeys[0].legs.some((leg) => {
|
||||
return leg.passed && leg.passed.some((passed) => {
|
||||
return passed.station.id === museumsquartierPassed
|
||||
})
|
||||
})
|
||||
t.ok(l2, 'Museumsquartier is not being passed')
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('earlier/later journeys, Salzburg Hbf -> Wien Westbahnhof', co(function* (t) {
|
||||
const model = yield client.journeys(salzburgHbf, wienWestbahnhof, {
|
||||
results: 3, departure: when
|
||||
yield testEarlierLaterJourneys({
|
||||
test: t,
|
||||
fetchJourneys: client.journeys,
|
||||
validate,
|
||||
fromId: salzburgHbf,
|
||||
toId: wienWestbahnhof
|
||||
})
|
||||
|
||||
t.equal(typeof model.earlierRef, 'string')
|
||||
t.ok(model.earlierRef)
|
||||
t.equal(typeof model.laterRef, 'string')
|
||||
t.ok(model.laterRef)
|
||||
|
||||
// when and earlierThan/laterThan should be mutually exclusive
|
||||
t.throws(() => {
|
||||
client.journeys(salzburgHbf, wienWestbahnhof, {
|
||||
departure: when, earlierThan: model.earlierRef
|
||||
})
|
||||
})
|
||||
t.throws(() => {
|
||||
client.journeys(salzburgHbf, wienWestbahnhof, {
|
||||
departure: when, laterThan: model.laterRef
|
||||
})
|
||||
})
|
||||
|
||||
let earliestDep = Infinity, latestDep = -Infinity
|
||||
for (let j of model) {
|
||||
const dep = +new Date(j.legs[0].departure)
|
||||
if (dep < earliestDep) earliestDep = dep
|
||||
else if (dep > latestDep) latestDep = dep
|
||||
}
|
||||
|
||||
const earlier = yield client.journeys(salzburgHbf, wienWestbahnhof, {
|
||||
results: 3,
|
||||
// todo: single journey ref?
|
||||
earlierThan: model.earlierRef
|
||||
})
|
||||
for (let j of earlier) {
|
||||
t.ok(new Date(j.legs[0].departure) < earliestDep)
|
||||
}
|
||||
|
||||
const later = yield client.journeys(salzburgHbf, wienWestbahnhof, {
|
||||
results: 3,
|
||||
// todo: single journey ref?
|
||||
laterThan: model.laterRef
|
||||
})
|
||||
for (let j of later) {
|
||||
t.ok(new Date(j.legs[0].departure) > latestDep)
|
||||
}
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
|
@ -341,144 +219,136 @@ test('leg details for Wien Westbahnhof to München Hbf', co(function* (t) {
|
|||
t.ok(p.line.name, 'precondition failed')
|
||||
const leg = yield client.journeyLeg(p.id, p.line.name, {when})
|
||||
|
||||
t.equal(typeof leg.id, 'string')
|
||||
t.ok(leg.id)
|
||||
validate(t, leg, 'journeyLeg', 'leg')
|
||||
t.end()
|
||||
}))
|
||||
|
||||
assertValidLine(t, leg.line)
|
||||
test('departures at Wien Leibenfrostgasse', co(function* (t) {
|
||||
const wienLeibenfrostgasse = '1390469'
|
||||
const ids = [
|
||||
wienLeibenfrostgasse, // station
|
||||
'904029', // stop "Wien Leibenfrostgasse (Phorusgasse)s"
|
||||
'904030' // stop "Wien Leibenfrostgasse (Ziegelofengasse)"
|
||||
]
|
||||
|
||||
t.equal(typeof leg.direction, 'string')
|
||||
t.ok(leg.direction)
|
||||
const deps = yield client.departures(wienLeibenfrostgasse, {
|
||||
duration: 15, when
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(leg.passed))
|
||||
for (let passed of leg.passed) assertValidStopover(t, passed)
|
||||
validate(t, deps, 'departures', 'departures')
|
||||
t.ok(deps.length > 0, 'must be >0 departures')
|
||||
// todo: move into deps validator
|
||||
t.deepEqual(deps, deps.sort((a, b) => t.when > b.when))
|
||||
|
||||
for (let i = 0; i < deps.length; i++) {
|
||||
const dep = deps[i]
|
||||
const msg = `deps[${i}].station.id is invalid`
|
||||
t.ok(ids.includes(dep.station.id, msg))
|
||||
}
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('departures at Salzburg Hbf', co(function* (t) {
|
||||
const deps = yield client.departures(salzburgHbf, {
|
||||
duration: 5, when
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(deps))
|
||||
for (let dep of deps) {
|
||||
assertValidStation(t, dep.station)
|
||||
assertValidStationProducts(t, dep.station.products)
|
||||
// todo
|
||||
// if (!(yield findStation(dep.station.id))) {
|
||||
// console.error('unknown station', dep.station.id, dep.station.name)
|
||||
// }
|
||||
if (dep.station.products) assertValidProducts(t, dep.station.products)
|
||||
assertValidWhen(t, dep.when, when)
|
||||
}
|
||||
test('departures with station object', co(function* (t) {
|
||||
const deps = yield client.departures({
|
||||
type: 'station',
|
||||
id: salzburgHbf,
|
||||
name: 'Salzburg Hbf',
|
||||
location: {
|
||||
type: 'location',
|
||||
latitude: 1.23,
|
||||
longitude: 2.34
|
||||
}
|
||||
}, {when})
|
||||
|
||||
validate(t, deps, 'departures', 'departures')
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('nearby Salzburg Hbf', co(function* (t) {
|
||||
const salzburgHbfPosition = {
|
||||
const nearby = yield client.nearby({
|
||||
type: 'location',
|
||||
longitude: 13.045604,
|
||||
latitude: 47.812851
|
||||
}
|
||||
const nearby = yield client.nearby(salzburgHbfPosition, {
|
||||
results: 2, distance: 400
|
||||
}, {
|
||||
results: 5, distance: 400
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(nearby))
|
||||
t.equal(nearby.length, 2)
|
||||
validate(t, nearby, 'locations', 'nearby')
|
||||
t.equal(nearby.length, 5)
|
||||
|
||||
assertIsSalzburgHbf(t, nearby[0])
|
||||
t.ok(nearby[0].distance >= 0)
|
||||
t.ok(nearby[0].distance <= 100)
|
||||
|
||||
for (let n of nearby) {
|
||||
if (n.type === 'station') assertValidStation(t, n)
|
||||
else assertValidLocation(t, n)
|
||||
}
|
||||
const s = nearby[0]
|
||||
t.ok(s.id === '008100002' || s.id === '8100002', 'id should be 8100002')
|
||||
t.equal(s.name, 'Salzburg Hbf')
|
||||
t.ok(isRoughlyEqual(.0005, s.location.latitude, 47.812851))
|
||||
t.ok(isRoughlyEqual(.0005, s.location.longitude, 13.045604))
|
||||
t.ok(s.distance >= 0)
|
||||
t.ok(s.distance <= 100)
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('locations named Salzburg', co(function* (t) {
|
||||
const locations = yield client.locations('Salzburg', {
|
||||
results: 10
|
||||
results: 20
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(locations))
|
||||
t.ok(locations.length > 0)
|
||||
t.ok(locations.length <= 10)
|
||||
validate(t, locations, 'locations', 'locations')
|
||||
t.ok(locations.length <= 20)
|
||||
|
||||
for (let l of locations) {
|
||||
if (l.type === 'station') assertValidStation(t, l)
|
||||
else assertValidLocation(t, l)
|
||||
}
|
||||
t.ok(locations.some(isSalzburgHbf))
|
||||
t.ok(locations.find(s => s.type === 'station'))
|
||||
t.ok(locations.find(s => s.id && s.name)) // POIs
|
||||
t.ok(locations.some(s => s.id === '008100002' || s.id === '8100002'))
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('station', co(function* (t) {
|
||||
const loc = yield client.station(grazHbf)
|
||||
const loc = yield client.station(wienRenngasse)
|
||||
|
||||
assertValidStation(t, loc)
|
||||
t.equal(loc.id, grazHbf)
|
||||
// todo: find a way to always get products from the API
|
||||
// todo: cfg.stationProductsOptional option
|
||||
const allProducts = products.reduce((acc, p) => (acc[p.id] = true, acc), {})
|
||||
const validateStation = createValidateStation(cfg)
|
||||
const validate = createValidate(cfg, {
|
||||
station: (validate, s, name) => {
|
||||
const withFakeProducts = Object.assign({products: allProducts}, s)
|
||||
validateStation(validate, withFakeProducts, name)
|
||||
}
|
||||
})
|
||||
validate(t, loc, 'station', 'station')
|
||||
|
||||
t.equal(loc.id, wienRenngasse)
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('radar Salzburg', co(function* (t) {
|
||||
const vehicles = yield client.radar({
|
||||
let vehicles = yield client.radar({
|
||||
north: 47.827203,
|
||||
west: 13.001261,
|
||||
south: 47.773278,
|
||||
east: 13.07562
|
||||
}, {
|
||||
duration: 5 * 60, when
|
||||
duration: 5 * 60,
|
||||
// when
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(vehicles))
|
||||
t.ok(vehicles.length > 0)
|
||||
for (let v of vehicles) {
|
||||
// todo: find a way to always get frames from the API
|
||||
vehicles = vehicles.filter(m => m.frames && m.frames.length > 0)
|
||||
|
||||
// todo
|
||||
// t.ok(findStation(v.direction))
|
||||
assertValidLine(t, v.line)
|
||||
// todo: find a way to always get products from the API
|
||||
// todo: cfg.stationProductsOptional option
|
||||
const allProducts = products.reduce((acc, p) => (acc[p.id] = true, acc), {})
|
||||
const validateStation = createValidateStation(cfg)
|
||||
const validate = createValidate(cfg, {
|
||||
station: (validate, s, name) => {
|
||||
const withFakeProducts = Object.assign({products: allProducts}, s)
|
||||
validateStation(validate, withFakeProducts, name)
|
||||
},
|
||||
line: validateLine
|
||||
})
|
||||
validate(t, vehicles, 'movements', 'vehicles')
|
||||
|
||||
t.equal(typeof v.location.latitude, 'number')
|
||||
t.ok(v.location.latitude <= 52, 'vehicle is too far away')
|
||||
t.ok(v.location.latitude >= 42, 'vehicle is too far away')
|
||||
t.equal(typeof v.location.longitude, 'number')
|
||||
t.ok(v.location.longitude >= 10, 'vehicle is too far away')
|
||||
t.ok(v.location.longitude <= 16, 'vehicle is too far away')
|
||||
|
||||
t.ok(Array.isArray(v.nextStops))
|
||||
for (let st of v.nextStops) {
|
||||
assertValidStopover(t, st, true)
|
||||
|
||||
if (st.arrival) {
|
||||
t.equal(typeof st.arrival, 'string')
|
||||
const arr = +new Date(st.arrival)
|
||||
// note that this can be an ICE train
|
||||
t.ok(isRoughlyEqual(14 * hour, +when, arr))
|
||||
}
|
||||
if (st.departure) {
|
||||
t.equal(typeof st.departure, 'string')
|
||||
const dep = +new Date(st.departure)
|
||||
t.ok(isRoughlyEqual(14 * hour, +when, dep))
|
||||
}
|
||||
}
|
||||
|
||||
t.ok(Array.isArray(v.frames))
|
||||
for (let f of v.frames) {
|
||||
assertValidStation(t, f.origin, true)
|
||||
// can contain stations in germany which don't have a products property, would break
|
||||
// assertValidStationProducts(t, f.origin.products)
|
||||
assertValidStation(t, f.destination, true)
|
||||
// can contain stations in germany which don't have a products property, would break
|
||||
// assertValidStationProducts(t, f.destination.products)
|
||||
t.equal(typeof f.t, 'number')
|
||||
}
|
||||
}
|
||||
t.end()
|
||||
}))
|
||||
|
|
158
test/util.js
158
test/util.js
|
@ -1,158 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
const validateFptf = require('validate-fptf')
|
||||
const isRoughlyEqual = require('is-roughly-equal')
|
||||
const {DateTime} = require('luxon')
|
||||
const isValidWGS84 = require('is-coordinates')
|
||||
|
||||
const validateFptfWith = (t, item, allowedTypes, name) => {
|
||||
try {
|
||||
validateFptf.recurse(allowedTypes, item, name)
|
||||
} catch (err) {
|
||||
t.ifError(err)
|
||||
}
|
||||
}
|
||||
|
||||
const assertValidStation = (t, s, coordsOptional = false) => {
|
||||
validateFptfWith(t, s, ['station'], 'station')
|
||||
|
||||
if (!coordsOptional || (s.location !== null && s.location !== undefined)) {
|
||||
t.ok(s.location)
|
||||
assertValidLocation(t, s.location, coordsOptional)
|
||||
}
|
||||
}
|
||||
|
||||
const assertValidPoi = (t, p) => {
|
||||
assertValidLocation(t, p, true)
|
||||
|
||||
t.equal(typeof p.id, 'string')
|
||||
t.equal(typeof p.name, 'string')
|
||||
if (p.address !== null && p.address !== undefined) {
|
||||
t.equal(typeof p.address, 'string')
|
||||
t.ok(p.address)
|
||||
}
|
||||
}
|
||||
|
||||
const assertValidAddress = (t, a) => {
|
||||
assertValidLocation(t, a, true)
|
||||
|
||||
t.equal(typeof a.address, 'string')
|
||||
}
|
||||
|
||||
const assertValidLocation = (t, l, coordsOptional = false) => {
|
||||
t.equal(l.type, 'location')
|
||||
if (l.name !== null && l.name !== undefined) {
|
||||
t.equal(typeof l.name, 'string')
|
||||
t.ok(l.name)
|
||||
}
|
||||
|
||||
if (l.address !== null && l.address !== undefined) {
|
||||
t.equal(typeof l.address, 'string')
|
||||
t.ok(l.address)
|
||||
}
|
||||
|
||||
const hasLatitude = l.latitude !== null && l.latitude !== undefined
|
||||
const hasLongitude = l.longitude !== null && l.longitude !== undefined
|
||||
if (!coordsOptional && hasLatitude) t.equal(typeof l.latitude, 'number')
|
||||
if (!coordsOptional && hasLongitude) t.equal(typeof l.longitude, 'number')
|
||||
if ((hasLongitude && !hasLatitude) || (hasLatitude && !hasLongitude)) {
|
||||
t.fail('should have both .latitude and .longitude')
|
||||
}
|
||||
if (hasLatitude && hasLongitude) isValidWGS84([l.longitude, l.latitude])
|
||||
|
||||
if (!coordsOptional && l.altitude !== null && l.altitude !== undefined) {
|
||||
t.equal(typeof l.altitude, 'number')
|
||||
}
|
||||
}
|
||||
|
||||
const validLineModes = [
|
||||
'train', 'bus', 'watercraft', 'taxi', 'gondola', 'aircraft',
|
||||
'car', 'bicycle', 'walking'
|
||||
]
|
||||
|
||||
const assertValidLine = (t, l) => {
|
||||
validateFptfWith(t, l, ['line'], 'line')
|
||||
}
|
||||
|
||||
const isValidDateTime = (w) => {
|
||||
return !Number.isNaN(+new Date(w))
|
||||
}
|
||||
|
||||
const assertValidStopover = (t, s, coordsOptional = false) => {
|
||||
if ('arrival' in s) t.ok(isValidDateTime(s.arrival))
|
||||
if ('departure' in s) t.ok(isValidDateTime(s.departure))
|
||||
if (s.arrivalDelay !== null && s.arrivalDelay !== undefined) {
|
||||
t.equal(typeof s.arrivalDelay, 'number')
|
||||
}
|
||||
if (s.departureDelay !== null && s.departureDelay !== undefined) {
|
||||
t.equal(typeof s.departureDelay, 'number')
|
||||
}
|
||||
if (!('arrival' in s) && !('departure' in s)) {
|
||||
t.fail('stopover doesn\'t contain arrival or departure')
|
||||
}
|
||||
t.ok(s.station)
|
||||
assertValidStation(t, s.station, coordsOptional)
|
||||
}
|
||||
|
||||
const hour = 60 * 60 * 1000
|
||||
const week = 7 * 24 * hour
|
||||
|
||||
// next Monday 10 am
|
||||
const createWhen = (timezone, locale) => {
|
||||
return DateTime.fromMillis(Date.now(), {
|
||||
zone: timezone,
|
||||
locale,
|
||||
}).startOf('week').plus({weeks: 1, hours: 10}).toJSDate()
|
||||
}
|
||||
const isValidWhen = (actual, expected) => {
|
||||
const ts = +new Date(actual)
|
||||
if (Number.isNaN(ts)) return false
|
||||
return isRoughlyEqual(12 * hour, +expected, ts)
|
||||
}
|
||||
|
||||
const assertValidWhen = (t, actual, expected) => {
|
||||
t.ok(isValidWhen(actual, expected), 'invalid when')
|
||||
}
|
||||
|
||||
const assertValidTicket = (t, ti) => {
|
||||
t.strictEqual(typeof ti.name, 'string')
|
||||
t.ok(ti.name.length > 0)
|
||||
if (ti.price !== null) {
|
||||
t.strictEqual(typeof ti.price, 'number')
|
||||
t.ok(ti.price > 0)
|
||||
}
|
||||
if (ti.amount !== null) {
|
||||
t.strictEqual(typeof ti.amount, 'number')
|
||||
t.ok(ti.amount > 0)
|
||||
}
|
||||
|
||||
if ('bike' in ti) t.strictEqual(typeof ti.bike, 'boolean')
|
||||
if ('shortTrip' in ti) t.strictEqual(typeof ti.shortTrip, 'boolean')
|
||||
if ('group' in ti) t.strictEqual(typeof ti.group, 'boolean')
|
||||
if ('fullDay' in ti) t.strictEqual(typeof ti.fullDay, 'boolean')
|
||||
|
||||
if (ti.tariff !== null) {
|
||||
t.strictEqual(typeof ti.tariff, 'string')
|
||||
t.ok(ti.tariff.length > 0)
|
||||
}
|
||||
if (ti.coverage !== null) {
|
||||
t.strictEqual(typeof ti.coverage, 'string')
|
||||
t.ok(ti.coverage.length > 0)
|
||||
}
|
||||
if (ti.variant !== null) {
|
||||
t.strictEqual(typeof ti.variant, 'string')
|
||||
t.ok(ti.variant.length > 0)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
assertValidStation,
|
||||
assertValidPoi,
|
||||
assertValidAddress,
|
||||
assertValidLocation,
|
||||
assertValidLine,
|
||||
isValidDateTime,
|
||||
assertValidStopover,
|
||||
hour, createWhen, isValidWhen, assertValidWhen,
|
||||
assertValidTicket
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
const a = require('assert')
|
||||
const is = require('@sindresorhus/is')
|
||||
|
||||
const validateItem = require('validate-fptf/lib/item')
|
||||
const validateReference = require('validate-fptf/lib/reference')
|
||||
|
||||
// todo: this is copied code, DRY this up!
|
||||
// see https://github.com/public-transport/validate-fptf/blob/373b4847ec9668c4a9ec9b0dbd50f8a70ffbe127/line.js
|
||||
const validateLineWithoutMode = (validate, line, name) => {
|
||||
validateItem(line, name)
|
||||
|
||||
a.strictEqual(line.type, 'line', name + '.type must be `line`')
|
||||
|
||||
validateReference(line.id, name + '.id')
|
||||
|
||||
a.strictEqual(typeof line.name, 'string', name + '.name must be a string')
|
||||
a.ok(line.name.length > 0, name + '.name can\'t be empty')
|
||||
|
||||
// skipping line validation here
|
||||
// see https://github.com/public-transport/hafas-client/issues/8#issuecomment-355839965
|
||||
if (is.undefined(line.mode) || is.null(line.mode)) {
|
||||
console.error(`ÖBB: Missing \`mode\` for line ${line.name} (at ${name}).`)
|
||||
}
|
||||
|
||||
if (!is.undefined(line.subMode)) {
|
||||
a.fail(name + '.subMode is reserved an should not be used for now')
|
||||
}
|
||||
|
||||
// todo: routes
|
||||
|
||||
if (!is.null(line.operator) && !is.undefined(line.operator)) {
|
||||
validate(['operator'], line.operator, name + '.operator')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = validateLineWithoutMode
|
544
test/vbb.js
544
test/vbb.js
|
@ -1,55 +1,103 @@
|
|||
'use strict'
|
||||
|
||||
const a = require('assert')
|
||||
const isRoughlyEqual = require('is-roughly-equal')
|
||||
const stations = require('vbb-stations-autocomplete')
|
||||
const a = require('assert')
|
||||
const shorten = require('vbb-short-station-name')
|
||||
const tapePromise = require('tape-promise').default
|
||||
const tape = require('tape')
|
||||
const shorten = require('vbb-short-station-name')
|
||||
const isRoughlyEqual = require('is-roughly-equal')
|
||||
|
||||
const co = require('./co')
|
||||
const {createWhen} = require('./lib/util')
|
||||
const co = require('./lib/co')
|
||||
const createClient = require('..')
|
||||
const vbbProfile = require('../p/vbb')
|
||||
const products = require('../p/vbb/products')
|
||||
const {
|
||||
assertValidStation: _assertValidStation,
|
||||
assertValidPoi,
|
||||
assertValidAddress,
|
||||
assertValidLocation,
|
||||
assertValidLine: _assertValidLine,
|
||||
assertValidStopover,
|
||||
hour, createWhen,
|
||||
assertValidWhen,
|
||||
assertValidTicket
|
||||
} = require('./util')
|
||||
station: createValidateStation,
|
||||
line: createValidateLine,
|
||||
journeyLeg: createValidateJourneyLeg,
|
||||
departure: createValidateDeparture,
|
||||
movement: _validateMovement
|
||||
} = require('./lib/validators')
|
||||
const createValidate = require('./lib/validate-fptf-with')
|
||||
const testJourneysStationToStation = require('./lib/journeys-station-to-station')
|
||||
const testJourneysStationToAddress = require('./lib/journeys-station-to-address')
|
||||
const testJourneysStationToPoi = require('./lib/journeys-station-to-poi')
|
||||
const testEarlierLaterJourneys = require('./lib/earlier-later-journeys')
|
||||
const journeysFailsWithNoProduct = require('./lib/journeys-fails-with-no-product')
|
||||
const testDepartures = require('./lib/departures')
|
||||
const testJourneysWithDetour = require('./lib/journeys-with-detour')
|
||||
|
||||
const when = createWhen('Europe/Berlin', 'de-DE')
|
||||
|
||||
const assertValidStation = (t, s, coordsOptional = false) => {
|
||||
_assertValidStation(t, s, coordsOptional)
|
||||
t.equal(s.name, shorten(s.name))
|
||||
const cfg = {
|
||||
when,
|
||||
stationCoordsOptional: false,
|
||||
products
|
||||
}
|
||||
|
||||
const assertValidStationProducts = (t, p) => {
|
||||
t.ok(p)
|
||||
t.equal(typeof p.suburban, 'boolean')
|
||||
t.equal(typeof p.subway, 'boolean')
|
||||
t.equal(typeof p.tram, 'boolean')
|
||||
t.equal(typeof p.bus, 'boolean')
|
||||
t.equal(typeof p.ferry, 'boolean')
|
||||
t.equal(typeof p.express, 'boolean')
|
||||
t.equal(typeof p.regional, 'boolean')
|
||||
const validateDirection = (dir, name) => {
|
||||
if (!stations(dir, true, false)[0]) {
|
||||
console.error(name + `: station "${dir}" is unknown`)
|
||||
}
|
||||
}
|
||||
|
||||
const assertValidLine = (t, l) => {
|
||||
_assertValidLine(t, l)
|
||||
if (l.symbol !== null) t.equal(typeof l.symbol, 'string')
|
||||
if (l.nr !== null) t.equal(typeof l.nr, 'number')
|
||||
if (l.metro !== null) t.equal(typeof l.metro, 'boolean')
|
||||
if (l.express !== null) t.equal(typeof l.express, 'boolean')
|
||||
if (l.night !== null) t.equal(typeof l.night, 'boolean')
|
||||
// todo: coordsOptional = false
|
||||
const _validateStation = createValidateStation(cfg)
|
||||
const validateStation = (validate, s, name) => {
|
||||
_validateStation(validate, s, name)
|
||||
// todo: find station by ID
|
||||
a.equal(s.name, shorten(s.name), name + '.name must be shortened')
|
||||
}
|
||||
|
||||
const findStation = (query) => stations(query, true, false)[0]
|
||||
const _validateLine = createValidateLine(cfg)
|
||||
const validateLine = (validate, l, name) => {
|
||||
_validateLine(validate, l, name)
|
||||
if (l.symbol !== null) {
|
||||
a.strictEqual(typeof l.symbol, 'string', name + '.symbol must be a string')
|
||||
a.ok(l.symbol, name + '.symbol must not be empty')
|
||||
}
|
||||
if (l.nr !== null) {
|
||||
a.strictEqual(typeof l.nr, 'number', name + '.nr must be a string')
|
||||
a.ok(l.nr, name + '.nr must not be empty')
|
||||
}
|
||||
if (l.metro !== null) {
|
||||
a.strictEqual(typeof l.metro, 'boolean', name + '.metro must be a boolean')
|
||||
}
|
||||
if (l.express !== null) {
|
||||
a.strictEqual(typeof l.express, 'boolean', name + '.express must be a boolean')
|
||||
}
|
||||
if (l.night !== null) {
|
||||
a.strictEqual(typeof l.night, 'boolean', name + '.night must be a boolean')
|
||||
}
|
||||
}
|
||||
|
||||
const _validateJourneyLeg = createValidateJourneyLeg(cfg)
|
||||
const validateJourneyLeg = (validate, l, name) => {
|
||||
_validateJourneyLeg(validate, l, name)
|
||||
if (l.mode !== 'walking') {
|
||||
validateDirection(l.direction, name + '.direction')
|
||||
}
|
||||
}
|
||||
|
||||
const _validateDeparture = createValidateDeparture(cfg)
|
||||
const validateDeparture = (validate, dep, name) => {
|
||||
_validateDeparture(validate, dep, name)
|
||||
validateDirection(dep.direction, name + '.direction')
|
||||
}
|
||||
|
||||
const validateMovement = (validate, m, name) => {
|
||||
_validateMovement(validate, m, name)
|
||||
validateDirection(m.direction, name + '.direction')
|
||||
}
|
||||
|
||||
const validate = createValidate(cfg, {
|
||||
station: validateStation,
|
||||
line: validateLine,
|
||||
journeyLeg: validateJourneyLeg,
|
||||
departure: validateDeparture,
|
||||
movement: validateMovement
|
||||
})
|
||||
|
||||
const test = tapePromise(tape)
|
||||
const client = createClient(vbbProfile)
|
||||
|
@ -57,58 +105,33 @@ const client = createClient(vbbProfile)
|
|||
const amrumerStr = '900000009101'
|
||||
const spichernstr = '900000042101'
|
||||
const bismarckstr = '900000024201'
|
||||
const westhafen = '900000001201'
|
||||
const wedding = '900000009104'
|
||||
const württembergallee = '900000026153'
|
||||
|
||||
test('journeys – station to station', co(function* (t) {
|
||||
const journeys = yield client.journeys(spichernstr, amrumerStr, {
|
||||
results: 3, departure: when, passedStations: true
|
||||
test('journeys – Spichernstr. to Bismarckstr.', co(function* (t) {
|
||||
const journeys = yield client.journeys(spichernstr, bismarckstr, {
|
||||
results: 3,
|
||||
departure: when,
|
||||
passedStations: true
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.strictEqual(journeys.length, 3)
|
||||
yield testJourneysStationToStation({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: spichernstr,
|
||||
toId: bismarckstr
|
||||
})
|
||||
// todo: find a journey where there ticket info is always available
|
||||
|
||||
for (let journey of journeys) {
|
||||
t.equal(journey.type, 'journey')
|
||||
|
||||
t.ok(Array.isArray(journey.legs))
|
||||
t.strictEqual(journey.legs.length, 1)
|
||||
const leg = journey.legs[0] // todo: all legs
|
||||
|
||||
t.equal(typeof leg.id, 'string')
|
||||
t.ok(leg.id)
|
||||
assertValidStation(t, leg.origin)
|
||||
assertValidStationProducts(t, leg.origin.products)
|
||||
t.ok(leg.origin.name.indexOf('(Berlin)') === -1)
|
||||
t.strictEqual(leg.origin.id, spichernstr)
|
||||
assertValidWhen(t, leg.departure, when)
|
||||
|
||||
assertValidStation(t, leg.destination)
|
||||
assertValidStationProducts(t, leg.destination.products)
|
||||
t.strictEqual(leg.destination.id, amrumerStr)
|
||||
assertValidWhen(t, leg.arrival, when)
|
||||
|
||||
assertValidLine(t, leg.line)
|
||||
if (!findStation(leg.direction)) {
|
||||
const err = new Error('unknown direction: ' + leg.direction)
|
||||
err.stack = err.stack.split('\n').slice(0, 2).join('\n')
|
||||
console.error(err)
|
||||
}
|
||||
t.ok(leg.direction.indexOf('(Berlin)') === -1)
|
||||
|
||||
t.ok(Array.isArray(leg.passed))
|
||||
for (let passed of leg.passed) assertValidStopover(t, passed)
|
||||
|
||||
// todo: find a journey where there ticket info is always available
|
||||
if (journey.tickets) {
|
||||
t.ok(Array.isArray(journey.tickets))
|
||||
for (let ticket of journey.tickets) assertValidTicket(t, ticket)
|
||||
}
|
||||
}
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('journeys – only subway', co(function* (t) {
|
||||
const journeys = yield client.journeys(spichernstr, bismarckstr, {
|
||||
results: 20, departure: when,
|
||||
results: 20,
|
||||
departure: when,
|
||||
products: {
|
||||
suburban: false,
|
||||
subway: true,
|
||||
|
@ -120,118 +143,46 @@ test('journeys – only subway', co(function* (t) {
|
|||
}
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
validate(t, journeys, 'journeys', 'journeys')
|
||||
t.ok(journeys.length > 1)
|
||||
for (let i = 0; i < journeys.length; i++) {
|
||||
const journey = journeys[i]
|
||||
for (let j = 0; j < journey.legs.length; j++) {
|
||||
const leg = journey.legs[j]
|
||||
|
||||
for (let journey of journeys) {
|
||||
for (let leg of journey.legs) {
|
||||
const name = `journeys[${i}].legs[${i}].line`
|
||||
if (leg.line) {
|
||||
assertValidLine(t, leg.line)
|
||||
t.equal(leg.line.mode, 'train')
|
||||
t.equal(leg.line.product, 'subway')
|
||||
t.equal(leg.line.mode, 'train', name + '.mode is invalid')
|
||||
t.equal(leg.line.product, 'subway', name + '.product is invalid')
|
||||
}
|
||||
t.ok(journey.legs.some(l => l.line), name + '.legs has no subway leg')
|
||||
}
|
||||
}
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('journeys – fails with no product', co(function* (t) {
|
||||
t.plan(1)
|
||||
try {
|
||||
client.journeys(spichernstr, bismarckstr, {
|
||||
departure: when,
|
||||
products: {
|
||||
suburban: false,
|
||||
subway: false,
|
||||
tram: false,
|
||||
bus: false,
|
||||
ferry: false,
|
||||
express: false,
|
||||
regional: false
|
||||
}
|
||||
})
|
||||
// silence rejections, we're only interested in exceptions
|
||||
.catch(() => {})
|
||||
} catch (err) {
|
||||
t.ok(err, 'error thrown')
|
||||
t.end()
|
||||
}
|
||||
}))
|
||||
|
||||
test('journeys before date/time', co(function* (t) {
|
||||
const journeys = yield client.journeys(spichernstr, bismarckstr, {
|
||||
results: 3, arrival: when
|
||||
test('journeys – fails with no product', (t) => {
|
||||
journeysFailsWithNoProduct({
|
||||
test: t,
|
||||
fetchJourneys: client.journeys,
|
||||
fromId: spichernstr,
|
||||
toId: bismarckstr,
|
||||
when,
|
||||
products
|
||||
})
|
||||
|
||||
for (let i = 0; i < journeys.length; i++) {
|
||||
const j = journeys[i]
|
||||
const name = `journeys[${i}]`
|
||||
|
||||
const lastLeg = j.legs[j.legs.length - 1]
|
||||
const arr = +new Date(lastLeg.arrival)
|
||||
t.ok(arr <= when, name + '.arrival is after `when`')
|
||||
}
|
||||
|
||||
t.end()
|
||||
}))
|
||||
})
|
||||
|
||||
test('earlier/later journeys', co(function* (t) {
|
||||
const model = yield client.journeys(spichernstr, bismarckstr, {
|
||||
results: 3, departure: when
|
||||
yield testEarlierLaterJourneys({
|
||||
test: t,
|
||||
fetchJourneys: client.journeys,
|
||||
validate,
|
||||
fromId: spichernstr,
|
||||
toId: bismarckstr
|
||||
})
|
||||
|
||||
t.equal(typeof model.earlierRef, 'string')
|
||||
t.ok(model.earlierRef)
|
||||
t.equal(typeof model.laterRef, 'string')
|
||||
t.ok(model.laterRef)
|
||||
|
||||
// departure/arrival and earlierThan/laterThan should be mutually exclusive
|
||||
t.throws(() => {
|
||||
client.journeys(spichernstr, bismarckstr, {
|
||||
departure: when, earlierThan: model.earlierRef
|
||||
})
|
||||
})
|
||||
t.throws(() => {
|
||||
client.journeys(spichernstr, bismarckstr, {
|
||||
departure: when, laterThan: model.laterRef
|
||||
})
|
||||
})
|
||||
t.throws(() => {
|
||||
client.journeys(spichernstr, bismarckstr, {
|
||||
arrival: when, earlierThan: model.earlierRef
|
||||
})
|
||||
})
|
||||
t.throws(() => {
|
||||
client.journeys(spichernstr, bismarckstr, {
|
||||
arrival: when, laterThan: model.laterRef
|
||||
})
|
||||
})
|
||||
|
||||
let earliestDep = Infinity, latestDep = -Infinity
|
||||
for (let j of model) {
|
||||
const dep = +new Date(j.legs[0].departure)
|
||||
if (dep < earliestDep) earliestDep = dep
|
||||
else if (dep > latestDep) latestDep = dep
|
||||
}
|
||||
|
||||
const earlier = yield client.journeys(spichernstr, bismarckstr, {
|
||||
results: 3,
|
||||
// todo: single journey ref?
|
||||
earlierThan: model.earlierRef
|
||||
})
|
||||
for (let j of earlier) {
|
||||
t.ok(new Date(j.legs[0].departure) < earliestDep)
|
||||
}
|
||||
|
||||
const later = yield client.journeys(spichernstr, bismarckstr, {
|
||||
results: 3,
|
||||
// todo: single journey ref?
|
||||
laterThan: model.laterRef
|
||||
})
|
||||
for (let j of later) {
|
||||
t.ok(new Date(j.legs[0].departure) > latestDep)
|
||||
}
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
|
@ -245,147 +196,92 @@ test('journey leg details', co(function* (t) {
|
|||
t.ok(p.line.name, 'precondition failed')
|
||||
const leg = yield client.journeyLeg(p.id, p.line.name, {when})
|
||||
|
||||
t.equal(typeof leg.id, 'string')
|
||||
t.ok(leg.id)
|
||||
|
||||
assertValidLine(t, leg.line)
|
||||
|
||||
t.equal(typeof leg.direction, 'string')
|
||||
t.ok(leg.direction)
|
||||
|
||||
t.ok(Array.isArray(leg.passed))
|
||||
for (let passed of leg.passed) assertValidStopover(t, passed)
|
||||
|
||||
validate(t, leg, 'journeyLeg', 'leg')
|
||||
t.end()
|
||||
}))
|
||||
|
||||
|
||||
|
||||
test('journeys – station to address', co(function* (t) {
|
||||
const journeys = yield client.journeys(spichernstr, {
|
||||
const torfstr = {
|
||||
type: 'location',
|
||||
address: 'Torfstr. 17, Berlin',
|
||||
latitude: 52.541797, longitude: 13.350042
|
||||
}, {results: 1, departure: when})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.strictEqual(journeys.length, 1)
|
||||
const journey = journeys[0]
|
||||
const leg = journey.legs[journey.legs.length - 1]
|
||||
|
||||
assertValidStation(t, leg.origin)
|
||||
assertValidStationProducts(t, leg.origin.products)
|
||||
assertValidWhen(t, leg.departure, when)
|
||||
|
||||
const dest = leg.destination
|
||||
assertValidAddress(t, dest)
|
||||
t.strictEqual(dest.address, '13353 Berlin-Wedding, Torfstr. 17')
|
||||
t.ok(isRoughlyEqual(.0001, dest.latitude, 52.541797))
|
||||
t.ok(isRoughlyEqual(.0001, dest.longitude, 13.350042))
|
||||
assertValidWhen(t, leg.arrival, when)
|
||||
address: '13353 Berlin-Wedding, Torfstr. 17',
|
||||
latitude: 52.541797,
|
||||
longitude: 13.350042
|
||||
}
|
||||
const journeys = yield client.journeys(spichernstr, torfstr, {
|
||||
results: 3,
|
||||
departure: when
|
||||
})
|
||||
|
||||
yield testJourneysStationToAddress({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: spichernstr,
|
||||
to: torfstr
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
|
||||
|
||||
test('journeys – station to POI', co(function* (t) {
|
||||
const journeys = yield client.journeys(spichernstr, {
|
||||
const atze = {
|
||||
type: 'location',
|
||||
id: '900980720',
|
||||
name: 'Berlin, Atze Musiktheater für Kinder',
|
||||
latitude: 52.543333, longitude: 13.351686
|
||||
}, {results: 1, departure: when})
|
||||
|
||||
t.ok(Array.isArray(journeys))
|
||||
t.strictEqual(journeys.length, 1)
|
||||
const journey = journeys[0]
|
||||
const leg = journey.legs[journey.legs.length - 1]
|
||||
|
||||
assertValidStation(t, leg.origin)
|
||||
assertValidStationProducts(t, leg.origin.products)
|
||||
assertValidWhen(t, leg.departure, when)
|
||||
|
||||
const dest = leg.destination
|
||||
assertValidPoi(t, dest)
|
||||
t.strictEqual(dest.id, '900980720')
|
||||
t.strictEqual(dest.name, 'Berlin, Atze Musiktheater für Kinder')
|
||||
t.ok(isRoughlyEqual(.0001, dest.latitude, 52.543333))
|
||||
t.ok(isRoughlyEqual(.0001, dest.longitude, 13.351686))
|
||||
assertValidWhen(t, leg.arrival, when)
|
||||
latitude: 52.543333,
|
||||
longitude: 13.351686
|
||||
}
|
||||
const journeys = yield client.journeys(spichernstr, atze, {
|
||||
results: 3,
|
||||
departure: when
|
||||
})
|
||||
|
||||
yield testJourneysStationToPoi({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
fromId: spichernstr,
|
||||
to: atze
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('journeys: via works – with detour', co(function* (t) {
|
||||
// Going from Westhafen to Wedding via Württembergalle without detour
|
||||
// is currently impossible. We check if the routing engine computes a detour.
|
||||
const westhafen = '900000001201'
|
||||
const wedding = '900000009104'
|
||||
const württembergallee = '900000026153'
|
||||
const [journey] = yield client.journeys(westhafen, wedding, {
|
||||
const journeys = yield client.journeys(westhafen, wedding, {
|
||||
via: württembergallee,
|
||||
results: 1,
|
||||
departure: when,
|
||||
passedStations: true
|
||||
})
|
||||
|
||||
t.ok(journey)
|
||||
|
||||
const l = journey.legs.some(l => l.passed && l.passed.some(p => p.station.id === württembergallee))
|
||||
t.ok(l, 'Württembergalle is not being passed')
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('journeys: via works – without detour', co(function* (t) {
|
||||
// When going from Ruhleben to Zoo via Kastanienallee, there is *no need*
|
||||
// to change trains / no need for a "detour".
|
||||
const ruhleben = '900000025202'
|
||||
const zoo = '900000023201'
|
||||
const kastanienallee = '900000020152'
|
||||
const [journey] = yield client.journeys(ruhleben, zoo, {
|
||||
via: kastanienallee,
|
||||
results: 1,
|
||||
departure: when,
|
||||
passedStations: true
|
||||
yield testJourneysWithDetour({
|
||||
test: t,
|
||||
journeys,
|
||||
validate,
|
||||
detourIds: [württembergallee]
|
||||
})
|
||||
|
||||
t.ok(journey)
|
||||
|
||||
const l = journey.legs.some(l => l.passed && l.passed.some(p => p.station.id === kastanienallee))
|
||||
t.ok(l, 'Kastanienallee is not being passed')
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
// todo: without detour test
|
||||
|
||||
test('departures', co(function* (t) {
|
||||
const deps = yield client.departures(spichernstr, {duration: 5, when})
|
||||
const departures = yield client.departures(spichernstr, {
|
||||
duration: 5, when
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(deps))
|
||||
t.deepEqual(deps, deps.sort((a, b) => t.when > b.when))
|
||||
for (let dep of deps) {
|
||||
t.equal(typeof dep.journeyId, 'string')
|
||||
t.ok(dep.journeyId)
|
||||
|
||||
t.equal(dep.station.name, 'U Spichernstr.')
|
||||
assertValidStation(t, dep.station)
|
||||
assertValidStationProducts(t, dep.station.products)
|
||||
t.strictEqual(dep.station.id, spichernstr)
|
||||
|
||||
assertValidWhen(t, dep.when, when)
|
||||
if (!findStation(dep.direction)) {
|
||||
const err = new Error('unknown direction: ' + dep.direction)
|
||||
err.stack = err.stack.split('\n').slice(0, 2).join('\n')
|
||||
console.error(err)
|
||||
}
|
||||
assertValidLine(t, dep.line)
|
||||
}
|
||||
yield testDepartures({
|
||||
test: t,
|
||||
departures,
|
||||
validate,
|
||||
id: spichernstr
|
||||
})
|
||||
t.end()
|
||||
}))
|
||||
|
||||
test('departures with station object', co(function* (t) {
|
||||
yield client.departures({
|
||||
const deps = yield client.departures({
|
||||
type: 'station',
|
||||
id: spichernstr,
|
||||
name: 'U Spichernstr',
|
||||
|
@ -396,7 +292,7 @@ test('departures with station object', co(function* (t) {
|
|||
}
|
||||
}, {when})
|
||||
|
||||
t.ok('did not fail')
|
||||
validate(t, deps, 'departures', 'departures')
|
||||
t.end()
|
||||
}))
|
||||
|
||||
|
@ -404,13 +300,13 @@ test('departures at 7-digit station', co(function* (t) {
|
|||
const eisenach = '8010097' // see derhuerst/vbb-hafas#22
|
||||
yield client.departures(eisenach, {when})
|
||||
t.pass('did not fail')
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
|
||||
|
||||
test('nearby', co(function* (t) {
|
||||
const berlinerStr = '900000044201'
|
||||
const landhausstr = '900000043252'
|
||||
|
||||
// Berliner Str./Bundesallee
|
||||
const nearby = yield client.nearby({
|
||||
type: 'location',
|
||||
|
@ -418,18 +314,14 @@ test('nearby', co(function* (t) {
|
|||
longitude: 13.3310411
|
||||
}, {distance: 200})
|
||||
|
||||
t.ok(Array.isArray(nearby))
|
||||
for (let n of nearby) {
|
||||
if (n.type === 'station') assertValidStation(t, n)
|
||||
else assertValidLocation(t, n, false)
|
||||
}
|
||||
validate(t, nearby, 'locations', 'nearby')
|
||||
|
||||
t.equal(nearby[0].id, '900000044201')
|
||||
t.equal(nearby[0].id, berlinerStr)
|
||||
t.equal(nearby[0].name, 'U Berliner Str.')
|
||||
t.ok(nearby[0].distance > 0)
|
||||
t.ok(nearby[0].distance < 100)
|
||||
|
||||
t.equal(nearby[1].id, '900000043252')
|
||||
t.equal(nearby[1].id, landhausstr)
|
||||
t.equal(nearby[1].name, 'Landhausstr.')
|
||||
t.ok(nearby[1].distance > 100)
|
||||
t.ok(nearby[1].distance < 200)
|
||||
|
@ -437,18 +329,12 @@ test('nearby', co(function* (t) {
|
|||
t.end()
|
||||
}))
|
||||
|
||||
|
||||
|
||||
test('locations', co(function* (t) {
|
||||
const locations = yield client.locations('Alexanderplatz', {results: 20})
|
||||
|
||||
t.ok(Array.isArray(locations))
|
||||
t.ok(locations.length > 0)
|
||||
validate(t, locations, 'locations', 'locations')
|
||||
t.ok(locations.length <= 20)
|
||||
for (let l of locations) {
|
||||
if (l.type === 'station') assertValidStation(t, l)
|
||||
else assertValidLocation(t, l)
|
||||
}
|
||||
|
||||
t.ok(locations.find(s => s.type === 'station'))
|
||||
t.ok(locations.find(s => s.id && s.name)) // POIs
|
||||
t.ok(locations.find(s => !s.name && s.address)) // addresses
|
||||
|
@ -457,21 +343,14 @@ test('locations', co(function* (t) {
|
|||
}))
|
||||
|
||||
test('station', co(function* (t) {
|
||||
const loc = yield client.station(spichernstr)
|
||||
const s = yield client.station(spichernstr)
|
||||
|
||||
assertValidStation(t, loc)
|
||||
t.equal(loc.id, spichernstr)
|
||||
|
||||
t.ok(Array.isArray(loc.lines))
|
||||
if (Array.isArray(loc.lines)) {
|
||||
for (let line of loc.lines) assertValidLine(t, line)
|
||||
}
|
||||
validate(t, s, 'station', 'station')
|
||||
t.equal(s.id, spichernstr)
|
||||
|
||||
t.end()
|
||||
}))
|
||||
|
||||
|
||||
|
||||
test('radar', co(function* (t) {
|
||||
const vehicles = yield client.radar({
|
||||
north: 52.52411,
|
||||
|
@ -482,53 +361,6 @@ test('radar', co(function* (t) {
|
|||
duration: 5 * 60, when
|
||||
})
|
||||
|
||||
t.ok(Array.isArray(vehicles))
|
||||
t.ok(vehicles.length > 0)
|
||||
for (let v of vehicles) {
|
||||
|
||||
if (!findStation(v.direction)) {
|
||||
const err = new Error('unknown direction: ' + v.direction)
|
||||
err.stack = err.stack.split('\n').slice(0, 2).join('\n')
|
||||
console.error(err)
|
||||
}
|
||||
assertValidLine(t, v.line)
|
||||
|
||||
t.equal(typeof v.location.latitude, 'number')
|
||||
t.ok(v.location.latitude <= 55, 'vehicle is too far away')
|
||||
t.ok(v.location.latitude >= 45, 'vehicle is too far away')
|
||||
t.equal(typeof v.location.longitude, 'number')
|
||||
t.ok(v.location.longitude >= 9, 'vehicle is too far away')
|
||||
t.ok(v.location.longitude <= 15, 'vehicle is too far away')
|
||||
|
||||
t.ok(Array.isArray(v.nextStops))
|
||||
for (let st of v.nextStops) {
|
||||
assertValidStopover(t, st, true)
|
||||
t.strictEqual(st.station.name.indexOf('(Berlin)'), -1)
|
||||
|
||||
if (st.arrival) {
|
||||
t.equal(typeof st.arrival, 'string')
|
||||
const arr = +new Date(st.arrival)
|
||||
// note that this can be an ICE train
|
||||
t.ok(isRoughlyEqual(14 * hour, +when, arr))
|
||||
}
|
||||
if (st.departure) {
|
||||
t.equal(typeof st.departure, 'string')
|
||||
const dep = +new Date(st.departure)
|
||||
// note that this can be an ICE train
|
||||
t.ok(isRoughlyEqual(14 * hour, +when, dep))
|
||||
}
|
||||
}
|
||||
|
||||
t.ok(Array.isArray(v.frames))
|
||||
for (let f of v.frames) {
|
||||
assertValidStation(t, f.origin, true)
|
||||
assertValidStationProducts(t, f.origin.products)
|
||||
t.strictEqual(f.origin.name.indexOf('(Berlin)'), -1)
|
||||
assertValidStation(t, f.destination, true)
|
||||
assertValidStationProducts(t, f.destination.products)
|
||||
t.strictEqual(f.destination.name.indexOf('(Berlin)'), -1)
|
||||
t.equal(typeof f.t, 'number')
|
||||
}
|
||||
}
|
||||
validate(t, vehicles, 'movements', 'vehicles')
|
||||
t.end()
|
||||
}))
|
||||
|
|
Loading…
Add table
Reference in a new issue