diff --git a/package.json b/package.json index a896a12a..f699a671 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,9 @@ "is-roughly-equal": "^0.1.0", "tap-spec": "^4.1.1", "tape": "^4.8.0", - "tape-promise": "^2.0.1" + "tape-promise": "^2.0.1", + "vbb-parse-line": "^0.2.5", + "vbb-stations-autocomplete": "^2.9.0" }, "scripts": { "test": "node test/index.js | tap-spec", diff --git a/test/db.js b/test/db.js index 3f238959..03ca7ef8 100644 --- a/test/db.js +++ b/test/db.js @@ -1,5 +1,6 @@ 'use strict' +const getStations = require('db-stations').full const tapePromise = require('tape-promise').default const tape = require('tape') const isRoughlyEqual = require('is-roughly-equal') @@ -8,7 +9,6 @@ const createClient = require('..') const dbProfile = require('../p/db') const modes = require('../p/db/modes') const { - findStation, assertValidStation, assertValidPoi, assertValidAddress, @@ -18,6 +18,22 @@ const { when, isValidWhen } = require('./util.js') +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 === '8011167') && diff --git a/test/index.js b/test/index.js index 30db69dc..85c39e86 100644 --- a/test/index.js +++ b/test/index.js @@ -1,3 +1,4 @@ 'use strict' require('./db') +require('./vbb') diff --git a/test/util.js b/test/util.js index 85a0871b..99864715 100644 --- a/test/util.js +++ b/test/util.js @@ -1,25 +1,8 @@ 'use strict' const isRoughlyEqual = require('is-roughly-equal') -const getStations = require('db-stations').full const floor = require('floordate') -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 assertValidStation = (t, s) => { t.equal(s.type, 'station') t.equal(typeof s.id, 'string') @@ -90,7 +73,6 @@ const isValidWhen = (w) => { } module.exports = { - findStation, assertValidStation, assertValidPoi, assertValidAddress, diff --git a/test/vbb.js b/test/vbb.js new file mode 100644 index 00000000..d686d2c9 --- /dev/null +++ b/test/vbb.js @@ -0,0 +1,329 @@ +'use strict' + +const test = require('tape') +const a = require('assert') +const isRoughlyEqual = require('is-roughly-equal') +const stations = require('vbb-stations-autocomplete') +const floor = require('floordate') + +const createClient = require('..') +const vbbProfile = require('../p/vbb') +const modes = require('../p/vbb/modes') +const { + assertValidStation, assertValidFrameStation, + assertValidPoi, + assertValidAddress, + assertValidLocation, + assertValidLine, + assertValidPassed, + hour, when, + assertValidWhen +} = require('./util') + +const findStation = (query) => stations(query, true, false) + +const client = createClient(vbbProfile) + +test('journeys – station to station', (t) => { + // U Spichernstr. to U Amrumer Str. + client.journeys('900000042101', '900000009101', { + results: 3, when, passedStations: true + }) + .then((journeys) => { + t.ok(Array.isArray(journeys)) + t.strictEqual(journeys.length, 3) + + for (let journey of journeys) { + assertValidStation(t, journey.origin) + t.ok(journey.origin.name.indexOf('(Berlin)') === -1) + t.strictEqual(journey.origin.id, '900000042101') + assertValidWhen(t, journey.departure) + + assertValidStation(t, journey.destination) + t.strictEqual(journey.destination.id, '900000009101') + assertValidWhen(t, journey.arrival) + + t.ok(Array.isArray(journey.parts)) + t.strictEqual(journey.parts.length, 1) + const part = journey.parts[0] + + t.equal(typeof part.id, 'string') + t.ok(part.id) + assertValidStation(t, part.origin) + t.ok(part.origin.name.indexOf('(Berlin)') === -1) + t.strictEqual(part.origin.id, '900000042101') + assertValidWhen(t, part.departure) + + assertValidStation(t, part.destination) + t.strictEqual(part.destination.id, '900000009101') + assertValidWhen(t, part.arrival) + + assertValidLine(t, part.line) + t.ok(findStation(part.direction)) + t.ok(part.direction.indexOf('(Berlin)') === -1) + + t.ok(Array.isArray(part.passed)) + for (let passed of part.passed) assertValidPassed(t, passed) + } + }) + .catch(t.ifError) + .then(() => t.end()) +}) + +test('journeys – only subway', (t) => { + // U Spichernstr. to U Bismarckstr. + client.journeys('900000042101', '900000024201', { + results: 20, when, + products: { + suburban: false, + subway: true, + tram: false, + bus: false, + ferry: false, + express: false, + regional: false + } + }) + .then((journeys) => { + t.ok(Array.isArray(journeys)) + t.ok(journeys.length > 1) + + for (let journey of journeys) { + for (let part of journey.parts) { + if (part.line) { + t.equal(part.line.mode, 'train') + t.equal(part.line.product, 'subway') + t.equal(part.line.public, true) + } + } + } + }) + .catch(t.ifError) + .then(() => t.end()) +}) + +test('journeys – fails with no product', (t) => { + // U Spichernstr. to U Bismarckstr. + client.journeys('900000042101', '900000024201', { + when, + products: { + suburban: false, + subway: false, + tram: false, + bus: false, + ferry: false, + express: false, + regional: false + } + }) + .catch((err) => { + t.ok(err, 'error thrown') + t.end() + }) +}) + +test('journey part details', (t) => { + // U Spichernstr. to U Amrumer Str. + client.journeys('900000042101', '900000009101', {results: 1, when}) + .then((journeys) => { + const part = journeys[0].parts[0] + t.ok(part.id, 'precondition failed') + t.ok(part.line.name, 'precondition failed') + return client.journeyPart(part.id, part.line.name, {when}) + }) + .then((part) => { + t.equal(typeof part.id, 'string') + t.ok(part.id) + + assertValidLine(t, part.line) + + t.equal(typeof part.direction, 'string') + t.ok(part.direction) + + t.ok(Array.isArray(part.passed)) + for (let passed of part.passed) assertValidPassed(t, passed) + }) + .catch(t.ifError) + .then(() => t.end()) +}) + + + +test('journeys – station to address', (t) => { + // U Spichernstr. to Torfstraße 17 + client.journeys('900000042101', { + type: 'address', name: 'Torfstraße 17', + latitude: 52.5416823, longitude: 13.3491223 + }, {results: 1, when}) + .then((journeys) => { + t.ok(Array.isArray(journeys)) + t.strictEqual(journeys.length, 1) + const journey = journeys[0] + const part = journey.parts[journey.parts.length - 1] + + assertValidStation(t, part.origin) + assertValidWhen(t, part.departure) + + const dest = part.destination + assertValidAddress(t, dest) + t.strictEqual(dest.name, 'Torfstr. 17') + t.ok(isRoughlyEqual(.0001, dest.coordinates.latitude, 52.5416823)) + t.ok(isRoughlyEqual(.0001, dest.coordinates.longitude, 13.3491223)) + assertValidWhen(t, part.arrival) + }) + .catch(t.ifError) + .then(() => t.end()) +}) + + + +test('journeys – station to POI', (t) => { + // U Spichernstr. to ATZE Musiktheater + client.journeys('900000042101', { + type: 'poi', name: 'ATZE Musiktheater', id: 9980720, + latitude: 52.543333, longitude: 13.351686 + }, {results: 1, when}) + .then((journeys) => { + t.ok(Array.isArray(journeys)) + t.strictEqual(journeys.length, 1) + const journey = journeys[0] + const part = journey.parts[journey.parts.length - 1] + + assertValidStation(t, part.origin) + assertValidWhen(t, part.departure) + + const dest = part.destination + assertValidPoi(t, dest) + t.strictEqual(dest.name, 'ATZE Musiktheater') + t.ok(isRoughlyEqual(.0001, dest.coordinates.latitude, 52.543333)) + t.ok(isRoughlyEqual(.0001, dest.coordinates.longitude, 13.351686)) + assertValidWhen(t, part.arrival) + }) + .catch(t.ifError) + .then(() => t.end()) +}) + + + +test('departures', (t) => { + client.departures('900000042101', {duration: 5, when}) // U Spichernstr. + .then((deps) => { + 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.ref, 'string') + t.ok(dep.ref) + + t.equal(dep.station.name, 'U Spichernstr.') + assertValidStation(t, dep.station) + t.strictEqual(dep.station.id, '900000042101') + + assertValidWhen(t, dep.when) + t.ok(findStation(dep.direction)) + assertValidLine(t, dep.line) + } + }) + .catch(t.ifError) + .then(() => t.end()) +}) + +test('departures at 7-digit station', (t) => { + const eisenach = '8010097' // see derhuerst/vbb-hafas#22 + client.departures(eisenach, {when}) + .then(() => { + t.pass('did not fail') + t.end() + }) + .catch(t.ifError) +}) + + + +test('nearby', (t) => { + client.nearby(52.4873452,13.3310411, {distance: 200}) // Berliner Str./Bundesallee + .then((nearby) => { + t.ok(Array.isArray(nearby)) + for (let n of nearby) assertValidLocation(t, n, false) + + t.equal(nearby[0].id, '900000044201') + 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].name, 'Landhausstr.') + t.ok(nearby[1].distance > 100) + t.ok(nearby[1].distance < 200) + }) + .catch(t.ifError) + .then(() => t.end()) +}) + + + +test('locations', (t) => { + client.locations('Alexanderplatz', {results: 10}) + .then((locations) => { + t.ok(Array.isArray(locations)) + t.ok(locations.length > 0) + t.ok(locations.length <= 10) + for (let l of locations) assertValidLocation(t, l) + t.ok(locations.find((s) => s.type === 'station')) + t.ok(locations.find((s) => s.type === 'poi')) + t.ok(locations.find((s) => s.type === 'address')) + }) + .catch(t.ifError) + .then(() => t.end()) +}) + + + +test('radar', (t) => { + client.radar(52.52411, 13.41002, 52.51942, 13.41709, {duration: 5 * 60, when}) + .then((vehicles) => { + t.ok(Array.isArray(vehicles)) + t.ok(vehicles.length > 0) + for (let v of vehicles) { + + t.ok(findStation(v.direction)) + assertValidLine(t, v.line) + + t.equal(typeof v.coordinates.latitude, 'number') + t.ok(v.coordinates.latitude <= 55, 'vehicle is too far away') + t.ok(v.coordinates.latitude >= 45, 'vehicle is too far away') + t.equal(typeof v.coordinates.longitude, 'number') + t.ok(v.coordinates.longitude >= 9, 'vehicle is too far away') + t.ok(v.coordinates.longitude <= 15, 'vehicle is too far away') + + t.ok(Array.isArray(v.nextStops)) + for (let s of v.nextStops) { + assertValidFrameStation(t, s.station) + if (!s.arrival && !s.departure) + t.ifError(new Error('neither arrival nor departure return')) + if (s.arrival) { + t.equal(typeof s.arrival, 'string') + const arr = +new Date(s.arrival) + t.ok(!Number.isNaN(arr)) + // note that this can be an ICE train + t.ok(isRoughlyEqual(14 * hour, +when, arr)) + } + if (s.departure) { + t.equal(typeof s.departure, 'string') + const dep = +new Date(s.departure) + t.ok(!Number.isNaN(dep)) + // 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) { + assertValidFrameStation(t, f.origin) + assertValidFrameStation(t, f.destination) + t.equal(typeof f.t, 'number') + } + } + }) + .catch(t.ifError) + .then(() => t.end()) +})