mirror of
https://github.com/public-transport/db-vendo-client.git
synced 2025-02-22 22:59:35 +02:00
tests
This commit is contained in:
parent
80e633dcb7
commit
0e328aa681
7 changed files with 113 additions and 343 deletions
3
.github/workflows/test.yml
vendored
3
.github/workflows/test.yml
vendored
|
@ -33,7 +33,7 @@ jobs:
|
|||
|
||||
- run: npm run lint
|
||||
- run: npm run test-unit
|
||||
|
||||
"""
|
||||
integration-tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
|
@ -84,3 +84,4 @@ jobs:
|
|||
- run: npm install
|
||||
|
||||
- run: npm run test-e2e
|
||||
"""
|
|
@ -155,7 +155,7 @@ const request = async (ctx, userAgent, reqData) => {
|
|||
}
|
||||
|
||||
const body = await res.text();
|
||||
//console.log(body);
|
||||
console.log(body);
|
||||
profile.logResponse(ctx, res, body, reqId);
|
||||
|
||||
const b = JSON.parse(body);
|
||||
|
|
|
@ -187,17 +187,9 @@ Pass in just opt.age, and the age group will calculated automatically.`);
|
|||
typ: ageGroupLabel[tvlrAgeGroup || ageGroup.ADULT],
|
||||
anzahl: 1,
|
||||
alter: 'age' in opt
|
||||
? [opt.age]
|
||||
? [opt.age+'']
|
||||
: [],
|
||||
/*ermaessigungen: opt.loyaltyCard TODO
|
||||
? formatLoyaltyCard(opt.loyaltyCard)
|
||||
: null,*/
|
||||
ermaessigungen: [
|
||||
{
|
||||
"art": "KEINE_ERMAESSIGUNG",
|
||||
"klasse": "KLASSENLOS"
|
||||
}
|
||||
]
|
||||
ermaessigungen: [formatLoyaltyCard(opt.loyaltyCard)]
|
||||
}]
|
||||
};
|
||||
return basicCtrfReq;
|
||||
|
|
|
@ -13,71 +13,44 @@ const c = {
|
|||
|
||||
// see https://gist.github.com/juliuste/202bb04f450a79f8fa12a2ec3abcd72d
|
||||
const formatLoyaltyCard = (data) => {
|
||||
if (data.type === c.BAHNCARD) {
|
||||
if (data.discount === 25) {
|
||||
return data.class === 1
|
||||
? 1
|
||||
: 2;
|
||||
if (!data) {
|
||||
return {
|
||||
"art": "KEINE_ERMAESSIGUNG",
|
||||
"klasse": "KLASSENLOS"
|
||||
}
|
||||
if (data.discount === 50) {
|
||||
return data.class === 1
|
||||
? 3
|
||||
: 4;
|
||||
}
|
||||
const cls = data.class === 1 ? 'KLASSE_1' : 'KLASSE_2';
|
||||
if (data.type === c.BAHNCARD) {
|
||||
return {
|
||||
art: 'BAHNCARD'+data.discount,
|
||||
klasse: cls
|
||||
}
|
||||
}
|
||||
if (data.type === c.VORTEILSCARD) {
|
||||
return 9;
|
||||
return {
|
||||
art: 'A-VORTEILSCARD',
|
||||
klasse: 'KLASSENLOS'
|
||||
}
|
||||
}
|
||||
if (data.type === c.HALBTAXABO) {
|
||||
return data.railplus
|
||||
? 10
|
||||
: 11;
|
||||
}
|
||||
if (data.type === c.VOORDEELURENABO) {
|
||||
return data.railplus
|
||||
? 12
|
||||
: 13;
|
||||
}
|
||||
if (data.type === c.SHCARD) {
|
||||
return 14;
|
||||
return {
|
||||
art: 'CH-HALBTAXABO_OHNE_RAILPLUS',
|
||||
klasse: 'KLASSENLOS'
|
||||
}
|
||||
}
|
||||
// TODO Rest
|
||||
if (data.type === c.GENERALABONNEMENT) {
|
||||
return 15;
|
||||
return {
|
||||
art: 'CH-GENERAL-ABONNEMENT',
|
||||
klasse: cls
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
const parseLoyaltyCard = (cardId) => {
|
||||
switch (cardId) {
|
||||
case 1:
|
||||
case 2: return {type: c.BAHNCARD, discount: 25, class: cardId === 1 ? 1 : 2};
|
||||
case 3:
|
||||
case 4: return {type: c.BAHNCARD, discount: 50, class: cardId === 3 ? 1 : 2};
|
||||
case 9: return {type: c.VORTEILSCARD};
|
||||
case 10:
|
||||
case 11: return {type: c.HALBTAXABO, railplus: cardId === 10};
|
||||
case 12:
|
||||
case 13: return {type: c.VOORDEELURENABO, railplus: cardId === 12};
|
||||
case 14: return {type: c.SHCARD};
|
||||
case 15: return {type: c.GENERALABONNEMENT};
|
||||
default: return {type: c.NONE};
|
||||
return {
|
||||
"art": "KEINE_ERMAESSIGUNG",
|
||||
"klasse": "KLASSENLOS"
|
||||
}
|
||||
};
|
||||
|
||||
const bcFirst50 = {
|
||||
type: c.BAHNCARD,
|
||||
class: 1,
|
||||
discount: 50,
|
||||
};
|
||||
eql(parseLoyaltyCard(formatLoyaltyCard(bcFirst50)), bcFirst50);
|
||||
const halbtaxRailplus = {
|
||||
type: c.HALBTAXABO,
|
||||
railplus: true,
|
||||
};
|
||||
eql(parseLoyaltyCard(formatLoyaltyCard(halbtaxRailplus)), halbtaxRailplus);
|
||||
|
||||
export {
|
||||
c as data,
|
||||
formatLoyaltyCard,
|
||||
parseLoyaltyCard,
|
||||
formatLoyaltyCard
|
||||
};
|
||||
|
|
|
@ -34,52 +34,85 @@ const opt = {
|
|||
},
|
||||
};
|
||||
|
||||
const berlinWienQuery0 = Object.freeze({
|
||||
getPasslist: false,
|
||||
maxChg: -1,
|
||||
minChgTime: 0,
|
||||
depLocL: [{
|
||||
type: 'S',
|
||||
lid: 'A=1@L=8098160@',
|
||||
}],
|
||||
viaLocL: [],
|
||||
arrLocL: [{
|
||||
type: 'S',
|
||||
lid: 'A=1@L=8000284@',
|
||||
}],
|
||||
jnyFltrL: [
|
||||
{type: 'PROD', mode: 'INC', value: '1023'},
|
||||
{type: 'META', mode: 'INC', meta: 'notBarrierfree'},
|
||||
],
|
||||
gisFltrL: [],
|
||||
getTariff: false,
|
||||
ushrp: true,
|
||||
getPT: true,
|
||||
getIV: false,
|
||||
getPolyline: false,
|
||||
outDate: '20230912',
|
||||
outTime: '080910',
|
||||
outFrwd: true,
|
||||
const berlinWienQuery0 = Object.freeze(
|
||||
{
|
||||
"abfahrtsHalt": "A=1@L=8098160@",
|
||||
"anfrageZeitpunkt": "2024-12-07T23:50:12",
|
||||
"ankunftsHalt": "A=1@L=8000284@",
|
||||
"ankunftSuche": "ABFAHRT",
|
||||
"klasse": "KLASSE_2",
|
||||
"produktgattungen": [
|
||||
"ICE",
|
||||
"EC_IC",
|
||||
"IR",
|
||||
"REGIONAL",
|
||||
"SBAHN",
|
||||
"BUS",
|
||||
"SCHIFF",
|
||||
"UBAHN",
|
||||
"TRAM",
|
||||
"ANRUFPFLICHTIG"
|
||||
],
|
||||
"schnelleVerbindungen": true,
|
||||
"sitzplatzOnly": false,
|
||||
"bikeCarriage": false,
|
||||
"reservierungsKontingenteVorhanden": false,
|
||||
"nurDeutschlandTicketVerbindungen": false,
|
||||
"deutschlandTicketVorhanden": false
|
||||
});
|
||||
|
||||
tap.test('formats a journeys() request correctly (DB)', (t) => {
|
||||
const _opt = {...opt};
|
||||
delete _opt.loyaltyCard;
|
||||
delete _opt.age;
|
||||
const ctx = {profile, opt: _opt};
|
||||
|
||||
// transformJourneysQuery() mutates its 2nd argument!
|
||||
const query = {...berlinWienQuery0};
|
||||
const req = profile.transformJourneysQuery(ctx, query);
|
||||
|
||||
t.same(req.body, {
|
||||
...berlinWienQuery0,
|
||||
reisende: [
|
||||
{
|
||||
"typ": "ERWACHSENER",
|
||||
"ermaessigungen": [
|
||||
{
|
||||
"art": "KEINE_ERMAESSIGUNG",
|
||||
"klasse": "KLASSENLOS"
|
||||
}
|
||||
],
|
||||
"alter": [],
|
||||
"anzahl": 1
|
||||
}
|
||||
]
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
|
||||
tap.test('formats a journeys() request with BC correctly (DB)', (t) => {
|
||||
const ctx = {profile, opt};
|
||||
|
||||
// transformJourneysQuery() mutates its 2nd argument!
|
||||
const query = {...berlinWienQuery0};
|
||||
const req = profile.transformJourneysQuery(ctx, query);
|
||||
|
||||
t.same(req, {
|
||||
t.same(req.body, {
|
||||
...berlinWienQuery0,
|
||||
trfReq: {
|
||||
jnyCl: 2,
|
||||
tvlrProf: [{
|
||||
type: 'Y', // "young"
|
||||
age: 24,
|
||||
redtnCard: 2, // BahnCard 25
|
||||
}],
|
||||
cType: 'PK',
|
||||
},
|
||||
reisende: [
|
||||
{
|
||||
"typ": "JUGENDLICHER",
|
||||
"ermaessigungen": [
|
||||
{
|
||||
"art": "BAHNCARD25",
|
||||
"klasse": "KLASSE_2"
|
||||
}
|
||||
],
|
||||
"alter": ["24"],
|
||||
"anzahl": 1
|
||||
}
|
||||
]
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
});
|
|
@ -5,16 +5,19 @@ const products = [
|
|||
{
|
||||
id: 'train',
|
||||
bitmasks: [1, 2],
|
||||
vendo: 'REGIONAL',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
id: 'bus',
|
||||
bitmasks: [4],
|
||||
vendo: 'BUS',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
id: 'tram',
|
||||
bitmasks: [8, 32],
|
||||
vendo: 'TRAM',
|
||||
default: false,
|
||||
},
|
||||
];
|
||||
|
@ -26,25 +29,8 @@ const ctx = {
|
|||
};
|
||||
|
||||
tap.test('formatProductsFilter works without customisations', (t) => {
|
||||
const expected = 1 | 2 | 4;
|
||||
const expected = ['REGIONAL', 'BUS'];
|
||||
const filter = {};
|
||||
t.same(format(ctx, filter), {
|
||||
type: 'PROD',
|
||||
mode: 'INC',
|
||||
value: String(expected),
|
||||
});
|
||||
t.same(format(ctx, filter), expected);
|
||||
t.end();
|
||||
});
|
||||
|
||||
tap.test('formatProductsFilter works with customisations', (t) => {
|
||||
t.equal(Number(format(ctx, {
|
||||
bus: true,
|
||||
}).value), 1 | 2 | 4);
|
||||
t.equal(Number(format(ctx, {
|
||||
bus: false,
|
||||
}).value), 1 | 2);
|
||||
t.equal(Number(format(ctx, {
|
||||
tram: true,
|
||||
}).value), 1 | 2 | 4 | 8 | 32);
|
||||
t.end();
|
||||
});
|
||||
});
|
|
@ -18,72 +18,13 @@ import {
|
|||
} from '../../lib/errors.js';
|
||||
import {formatTripReq} from '../../format/trip-req.js';
|
||||
|
||||
const resParameter = require('../fixtures/error-parameter.json');
|
||||
const resNoMatch = require('../fixtures/error-no-match.json');
|
||||
const resH9360 = require('../fixtures/error-h9360.json');
|
||||
const resLocation = require('../fixtures/error-location.json');
|
||||
const resNoMatch = {"verbindungen":[],"verbindungReference":{},"fehlerNachricht":{"code":"MDA-AK-MSG-1001","ueberschrift":"Datum liegt außerhalb der Fahrplanperiode.","text":"Das Datum liegt außerhalb der Fahrplanperiode."}};
|
||||
|
||||
const USER_AGENT = 'public-transport/hafas-client:test';
|
||||
|
||||
const secret = Symbol('secret');
|
||||
|
||||
tap.test('checkIfResponseIsOk properly throws HAFAS "H9360" errors', (t) => {
|
||||
try {
|
||||
checkIfResIsOk({
|
||||
body: resH9360,
|
||||
errProps: {secret},
|
||||
});
|
||||
} catch (err) {
|
||||
t.ok(err);
|
||||
|
||||
t.ok(err instanceof HafasError);
|
||||
t.equal(err.isHafasError, true);
|
||||
t.equal(err.message.slice(0, 7), 'H9360: ');
|
||||
t.ok(err.message.length > 7);
|
||||
|
||||
t.ok(err instanceof HafasInvalidRequestError);
|
||||
t.equal(err.isCausedByServer, false);
|
||||
t.equal(err.code, INVALID_REQUEST);
|
||||
t.equal(err.hafasCode, 'H9360');
|
||||
|
||||
t.equal(err.hafasResponseId, resH9360.id);
|
||||
t.equal(err.hafasMessage, 'HAFAS Kernel: Date outside of the timetable period.');
|
||||
t.equal(err.hafasDescription, 'Fehler bei der Datumseingabe oder Datum außerhalb der Fahrplanperiode (01.05.2022 - 10.12.2022)');
|
||||
t.equal(err.secret, secret);
|
||||
|
||||
t.end();
|
||||
}
|
||||
});
|
||||
|
||||
tap.test('checkIfResponseIsOk properly throws HAFAS "LOCATION" errors', (t) => {
|
||||
try {
|
||||
checkIfResIsOk({
|
||||
body: resLocation,
|
||||
errProps: {secret},
|
||||
});
|
||||
} catch (err) {
|
||||
t.ok(err);
|
||||
|
||||
t.ok(err instanceof HafasError);
|
||||
t.equal(err.isHafasError, true);
|
||||
t.equal(err.message.slice(0, 10), 'LOCATION: ');
|
||||
t.ok(err.message.length > 10);
|
||||
|
||||
t.ok(err instanceof HafasNotFoundError);
|
||||
t.equal(err.isCausedByServer, false);
|
||||
t.equal(err.code, NOT_FOUND);
|
||||
t.equal(err.hafasCode, 'LOCATION');
|
||||
|
||||
t.equal(err.hafasResponseId, resLocation.id);
|
||||
t.equal(err.hafasMessage, 'HCI Service: location missing or invalid');
|
||||
t.equal(err.hafasDescription, 'Während der Suche ist ein interner Fehler aufgetreten');
|
||||
t.equal(err.secret, secret);
|
||||
|
||||
t.end();
|
||||
}
|
||||
});
|
||||
|
||||
tap.test('checkIfResponseIsOk properly throws HAFAS "NO_MATCH" errors', (t) => {
|
||||
tap.test('checkIfResponseIsOk properly throws HAFAS errors', (t) => {
|
||||
try {
|
||||
checkIfResIsOk({
|
||||
body: resNoMatch,
|
||||
|
@ -94,169 +35,13 @@ tap.test('checkIfResponseIsOk properly throws HAFAS "NO_MATCH" errors', (t) => {
|
|||
|
||||
t.ok(err instanceof HafasError);
|
||||
t.equal(err.isHafasError, true);
|
||||
t.equal(err.message.slice(0, 10), 'NO_MATCH: ');
|
||||
t.ok(err.message.length > 10);
|
||||
|
||||
t.ok(err instanceof HafasNotFoundError);
|
||||
t.equal(err.isCausedByServer, false);
|
||||
t.equal(err.code, NOT_FOUND);
|
||||
t.equal(err.hafasCode, 'NO_MATCH');
|
||||
|
||||
t.equal(err.hafasResponseId, resNoMatch.id);
|
||||
t.equal(err.hafasMessage, 'Nothing found.');
|
||||
t.equal(err.hafasDescription, 'Während der Suche ist leider ein interner Fehler aufgetreten. Bitte wenden Sie sich an unsere Serviceauskunft unter Tel. 0421 596059.');
|
||||
t.equal(err.secret, secret);
|
||||
|
||||
t.end();
|
||||
}
|
||||
});
|
||||
|
||||
tap.test('checkIfResponseIsOk properly throws HAFAS "PARAMETER" errors', (t) => {
|
||||
try {
|
||||
checkIfResIsOk({
|
||||
body: resParameter,
|
||||
errProps: {secret},
|
||||
});
|
||||
} catch (err) {
|
||||
t.ok(err);
|
||||
|
||||
t.ok(err instanceof HafasError);
|
||||
t.equal(err.isHafasError, true);
|
||||
t.equal(err.message.slice(0, 11), 'PARAMETER: ');
|
||||
t.ok(err.message.length > 11);
|
||||
|
||||
t.ok(err instanceof HafasInvalidRequestError);
|
||||
t.equal(err.isCausedByServer, false);
|
||||
t.equal(err.code, INVALID_REQUEST);
|
||||
t.equal(err.hafasCode, 'PARAMETER');
|
||||
t.equal(err.code, 'MDA-AK-MSG-1001');
|
||||
|
||||
t.equal(err.hafasResponseId, resParameter.id);
|
||||
t.equal(err.hafasMessage, 'HCI Service: parameter invalid');
|
||||
t.equal(err.hafasDescription, 'Während der Suche ist ein interner Fehler aufgetreten');
|
||||
t.equal(err.secret, secret);
|
||||
t.equal(err.hafasMessage, 'Datum liegt außerhalb der Fahrplanperiode.');
|
||||
t.equal(err.hafasDescription, 'Das Datum liegt außerhalb der Fahrplanperiode.');
|
||||
|
||||
t.end();
|
||||
}
|
||||
});
|
||||
|
||||
tap.test('checkIfResponseIsOk properly parses an unknown HAFAS errors', (t) => {
|
||||
const body = {
|
||||
ver: '1.42',
|
||||
id: '1234567890',
|
||||
err: 'FOO',
|
||||
errTxt: 'random errTxt',
|
||||
errTxtOut: 'even more random errTxtOut',
|
||||
svcResL: [],
|
||||
};
|
||||
|
||||
try {
|
||||
checkIfResIsOk({
|
||||
body,
|
||||
errProps: {secret},
|
||||
});
|
||||
} catch (err) {
|
||||
t.ok(err);
|
||||
|
||||
t.ok(err instanceof HafasError);
|
||||
t.equal(err.isHafasError, true);
|
||||
t.equal(err.message, `${body.err}: ${body.errTxt}`);
|
||||
|
||||
t.equal(err.isCausedByServer, false);
|
||||
t.equal(err.code, null);
|
||||
t.equal(err.hafasCode, body.err);
|
||||
|
||||
t.equal(err.hafasResponseId, body.id);
|
||||
t.equal(err.hafasMessage, body.errTxt);
|
||||
t.equal(err.hafasDescription, body.errTxtOut);
|
||||
t.equal(err.secret, secret);
|
||||
|
||||
t.end();
|
||||
}
|
||||
});
|
||||
|
||||
const freeze = (val) => {
|
||||
if (
|
||||
'object' === typeof val
|
||||
&& val !== null
|
||||
&& !Array.isArray(val)
|
||||
) {
|
||||
Object.freeze(val);
|
||||
}
|
||||
};
|
||||
const ctx = {
|
||||
// random but unique
|
||||
opt: {
|
||||
language: 'ga',
|
||||
},
|
||||
profile: {
|
||||
endpoint: 'https://does.not.exist',
|
||||
client: {
|
||||
type: 'FOO',
|
||||
id: 'BAR',
|
||||
name: 'baZ',
|
||||
},
|
||||
auth: {
|
||||
type: 'AID',
|
||||
aid: 'some-auth-token',
|
||||
},
|
||||
ver: '1.23.4',
|
||||
|
||||
timezone: 'Europe/Amsterdam',
|
||||
locale: 'de-LU',
|
||||
defaultLanguage: 'fr',
|
||||
|
||||
transformReq: (_, req) => req,
|
||||
},
|
||||
};
|
||||
forEach(ctx, freeze);
|
||||
|
||||
tap.test('lib/request calls profile.transformReqBody & profile.transformReq properly', async (t) => {
|
||||
const customTransformReqBody = (ctx, reqBody) => {
|
||||
const p = 'transformReqBody call: ';
|
||||
t.same(ctx, customCtx, 'ctx should be the passed-in ctx');
|
||||
|
||||
t.ok(reqBody, 'reqBody');
|
||||
t.equal(reqBody.client, ctx.profile.client, p + 'reqBody.client');
|
||||
t.equal(reqBody.ext, ctx.profile.ext, p + 'reqBody.ext');
|
||||
t.equal(reqBody.var, ctx.profile.var, p + 'reqBody.var');
|
||||
t.equal(reqBody.auth, ctx.profile.auth, p + 'reqBody.auth');
|
||||
t.equal(reqBody.lang, ctx.opt.language, p + 'reqBody.lang');
|
||||
|
||||
// We test if lib/request.js handles returning a new object.
|
||||
return {
|
||||
...reqBody,
|
||||
};
|
||||
};
|
||||
|
||||
const customTransformReq = (ctx, req) => {
|
||||
const p = 'transformReq call: ';
|
||||
t.same(ctx, customCtx, p + 'ctx should be the passed-in ctx');
|
||||
|
||||
t.equal(typeof req.body, 'string', p + 'req.body');
|
||||
t.ok(req.body, p + 'req.body');
|
||||
|
||||
// We test if lib/request.js handles returning a new object.
|
||||
return {
|
||||
...req,
|
||||
// From node-fetch, used by isomorphic-fetch:
|
||||
// > req/res timeout in ms, it resets on redirect. 0 to disable (OS limit applies). Signal is recommended instead.
|
||||
timeout: 100,
|
||||
};
|
||||
};
|
||||
|
||||
const customCtx = {
|
||||
...ctx,
|
||||
profile: {
|
||||
...ctx.profile,
|
||||
transformReqBody: customTransformReqBody,
|
||||
transformReq: customTransformReq,
|
||||
},
|
||||
};
|
||||
const tripReq = formatTripReq(customCtx, 'unknown-trip-id');
|
||||
|
||||
// todo: set 1s timeout
|
||||
await t.rejects(async () => {
|
||||
await request(customCtx, USER_AGENT, tripReq);
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue