// todo: use import assertions once they're supported by Node.js & ESLint // https://github.com/tc39/proposal-import-assertions import {createRequire} from 'module' const require = createRequire(import.meta.url) import tap from 'tap' import forEach from 'lodash/forEach.js' import { checkIfResponseIsOk as checkIfResIsOk, request, } from '../../lib/request.js' import { INVALID_REQUEST, NOT_FOUND, HafasError, HafasInvalidRequestError, HafasNotFoundError, } 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 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) => { try { checkIfResIsOk({ body: resNoMatch, errProps: {secret}, }) } catch (err) { t.ok(err) 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.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.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() })