diff --git a/src/Options.ts b/src/Options.ts index 271b0faf..42156409 100644 --- a/src/Options.ts +++ b/src/Options.ts @@ -31,4 +31,30 @@ type Options = Xor< apiEndpoint?: string; } & Pick; +const falsyDescriptions = new Map([ + [undefined, 'undefined'], + [null, 'null'], + ['', 'an empty string'], +]); + +/** + * Returns an error message (string) similar to `"Parameter "×" is null."` if a property with the passed key exists in + * the passed options object, or `null` if said property does not exist. + */ +function describeFalsyOption(options: Options, key: keyof Options) { + if (key in options == false) { + return null; + } + return `Parameter "${key}" is ${falsyDescriptions.get(options[key]) ?? options[key]}.`; +}; + +/** + * Throws a `TypeError` if the passed options object does not contain an `apiKey` or an `accessToken`. + */ +export function checkCredentials(options: Options) { + if (!options.apiKey && !options.accessToken) { + throw new TypeError(describeFalsyOption(options, 'apiKey') ?? describeFalsyOption(options, 'accessToken') ?? 'Missing parameter "apiKey" or "accessToken".'); + } +} + export default Options; diff --git a/src/createMollieClient.ts b/src/createMollieClient.ts index 9e83a2ce..60c70485 100644 --- a/src/createMollieClient.ts +++ b/src/createMollieClient.ts @@ -3,6 +3,7 @@ import { version as libraryVersion } from '../package.json'; import caCertificates from './cacert.pem'; import NetworkClient from './communication/NetworkClient'; import TransformingNetworkClient, { Transformers } from './communication/TransformingNetworkClient'; +import { checkCredentials } from './Options'; import type Options from './Options'; // Transformers @@ -70,9 +71,7 @@ export default function createMollieClient(options: Options) { ); } - if (!options.apiKey && !options.accessToken) { - throw new TypeError('Missing parameter "apiKey" or "accessToken".'); - } + checkCredentials(options); const networkClient = new NetworkClient({ ...options, libraryVersion, nodeVersion: process.version, caCertificates }); diff --git a/tests/unit/createMollieClient.test.ts b/tests/unit/createMollieClient.test.ts index ee145d1f..6a40a37f 100644 --- a/tests/unit/createMollieClient.test.ts +++ b/tests/unit/createMollieClient.test.ts @@ -1,9 +1,19 @@ import createMollieClient from '../..'; -describe('mollie', () => { - it('should fail when no api key is provided', () => { +describe('createMollieClient', () => { + it('should fail when no credentials are provided', () => { // eslint-disable-next-line @typescript-eslint/ban-ts-ignore // @ts-ignore - expect(() => createMollieClient(undefined)).toThrowError(TypeError); + expect(() => createMollieClient({})).toThrow('Missing parameter "apiKey" or "accessToken".'); + }); + + it('should throw a descriptive error when a apiKey is set to null', () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // @ts-ignore + expect(() => createMollieClient({ apiKey: null })).toThrow('Parameter "apiKey" is null.'); + }); + + it('should throw a descriptive error when a apiKey is set to an empty string', () => { + expect(() => createMollieClient({ apiKey: '' })).toThrow('Parameter "apiKey" is an empty string.'); }); });