From 0e328aa6811c53bf2950fa2cff4780907bf8a2ff Mon Sep 17 00:00:00 2001 From: Traines Date: Sat, 7 Dec 2024 23:48:08 +0000 Subject: [PATCH] tests --- .github/workflows/test.yml | 3 +- lib/request.js | 2 +- p/db/index.js | 12 +- p/db/loyalty-cards.js | 81 ++++------- test/format/db-journeys-query.js | 107 ++++++++++----- test/format/products-filter.js | 26 +--- test/lib/request.js | 225 +------------------------------ 7 files changed, 113 insertions(+), 343 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 022144a8..31e82f44 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -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 +""" \ No newline at end of file diff --git a/lib/request.js b/lib/request.js index f39e40fd..3a320a9f 100644 --- a/lib/request.js +++ b/lib/request.js @@ -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); diff --git a/p/db/index.js b/p/db/index.js index 953c1cb4..881a8c1e 100644 --- a/p/db/index.js +++ b/p/db/index.js @@ -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; diff --git a/p/db/loyalty-cards.js b/p/db/loyalty-cards.js index 753d425d..37b7565e 100644 --- a/p/db/loyalty-cards.js +++ b/p/db/loyalty-cards.js @@ -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 }; diff --git a/test/format/db-journeys-query.js b/test/format/db-journeys-query.js index df353bd2..a26171fe 100644 --- a/test/format/db-journeys-query.js +++ b/test/format/db-journeys-query.js @@ -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(); -}); +}); \ No newline at end of file diff --git a/test/format/products-filter.js b/test/format/products-filter.js index 6de98da4..520bd303 100644 --- a/test/format/products-filter.js +++ b/test/format/products-filter.js @@ -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(); -}); +}); \ No newline at end of file diff --git a/test/lib/request.js b/test/lib/request.js index 6e463570..ef0e0b0b 100644 --- a/test/lib/request.js +++ b/test/lib/request.js @@ -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(); -});