diff --git a/__tests__/Events.spec.js b/__tests__/Events.spec.js index 85fb61f..465cc49 100644 --- a/__tests__/Events.spec.js +++ b/__tests__/Events.spec.js @@ -1,3 +1,4 @@ +const { buildParams } = require('./helpers') const Events = require('../lib/Events') const Logger = require('../lib/Logger') @@ -34,8 +35,11 @@ describe('Events class', function () { }, ], ])('valid options value', function (options) { + const urlParams = buildParams(options) API.listEvents(options) + expect(Request.get).toHaveBeenCalledTimes(1) + expect(Request.get).toHaveBeenCalledWith(`/events?${urlParams}`) }) test.each([ @@ -44,50 +48,58 @@ describe('Events class', function () { [{ query: {} }], [{ subcalendarId: 'id' }], [{ format: 'text' }], + [{ startDate: '' }], + [{ endDate: undefined }], + [{ subcalendarId: undefined }], ])('invalid options value', function (options) { expect(() => API.listEvents(options)).toThrow() }) - test.each([ - [{}], - [{ startDate: '' }], - [{ endDate: undefined }], - [{ query: false }], - [{ subcalendarId: null }], - [{ format: 0 }], - ])('ignored options value', function (options) { - API.listEvents(options) - expect(Request.get).toHaveBeenCalledTimes(1) - }) + test.each([[{}], [{ subcalendarId: null }]])( + 'ignored options value', + function (options) { + API.listEvents(options) + expect(Request.get).toHaveBeenCalledTimes(1) + expect(Request.get).toHaveBeenCalledWith(`/events`) + } + ) test('invalid option parameter', function () { expect(() => API.listEvents({ someKey: true })).toThrow() }) - test.each([[], 'string', true, false, 123])( + test.each([[], 'string', true, false, 123, null])( 'invalid options', function (option) { expect(() => API.listEvents(option)).toThrow() } ) + + test('ignored option: undefined', function () { + API.listEvents(undefined) + expect(Request.get).toHaveBeenCalledTimes(1) + expect(Request.get).toHaveBeenCalledWith(`/events`) + }) }) describe('method: listEvent', function () { test('with event id (number)', function () { API.listEvent(1234) expect(Request.get).toHaveBeenCalledTimes(1) + expect(Request.get).toHaveBeenCalledWith(`/events/1234`) }) test('with event id (string)', function () { API.listEvent('1234') expect(Request.get).toHaveBeenCalledTimes(1) + expect(Request.get).toHaveBeenCalledWith(`/events/1234`) }) test('without event id', function () { expect(() => API.listEvent()).toThrow() }) - test.each([[], 'string', true, false, {}])( + test.each([[], 'string', true, false, {}, null, undefined])( 'invalid event id', function (id) { expect(() => API.listEvent(id)).toThrow() diff --git a/__tests__/SubCalendar.spec.js b/__tests__/SubCalendar.spec.js index 45663e4..88f52d6 100644 --- a/__tests__/SubCalendar.spec.js +++ b/__tests__/SubCalendar.spec.js @@ -1,3 +1,4 @@ +const { buildParams } = require('./helpers') const SubCalendar = require('../lib/SubCalendar') const Logger = require('../lib/Logger') @@ -19,9 +20,11 @@ describe('SubCalendar class', function () { test.each([[{ includeInactive: true }], [{ includeInactive: false }]])( 'valid options value', function (options) { + const urlParams = buildParams(options) API.listSubCalendars(options) expect(Request.get).toHaveBeenCalledTimes(1) + expect(Request.get).toHaveBeenCalledWith(`/subcalendars?${urlParams}`) } ) @@ -29,32 +32,39 @@ describe('SubCalendar class', function () { [{ includeInactive: 'text' }], [{ includeInactive: [] }], [{ includeInactive: {} }], + [{ includeInactive: undefined }], + [{ includeInactive: 1234 }], ])('invalid options value', function (options) { expect(() => API.listSubCalendars(options)).toThrow() }) - test.each([ - [{}], - [{ includeInactive: '' }], - [{ includeInactive: null }], - [{ includeInactive: undefined }], - [{ includeInactive: 0 }], - ])('ignored options value', function (options) { - API.listSubCalendars(options) + test.each([[{}], [{ includeInactive: null }]])( + 'ignored options value', + function (options) { + API.listSubCalendars(options) - expect(Request.get).toHaveBeenCalledTimes(1) - }) + expect(Request.get).toHaveBeenCalledTimes(1) + expect(Request.get).toHaveBeenCalledWith('/subcalendars') + } + ) test('invalid option parameter', function () { expect(() => API.listSubCalendars({ someKey: true })).toThrow() }) - test.each([([], 'string', true, false, 123)])( + test.each([([], 'string', true, false, 123, null)])( 'invalid options', function (option) { expect(() => API.listSubCalendars(option)).toThrow() } ) + + test('ignored option: undefined', function () { + API.listSubCalendars(undefined) + + expect(Request.get).toHaveBeenCalledTimes(1) + expect(Request.get).toHaveBeenCalledWith('/subcalendars') + }) }) describe('method: listSubCalendar', function () { @@ -62,20 +72,25 @@ describe('SubCalendar class', function () { API.listSubCalendar(1234) expect(Request.get).toHaveBeenCalledTimes(1) + expect(Request.get).toHaveBeenCalledWith('/subcalendars/1234') }) test('with id (string)', function () { API.listSubCalendar('1234') expect(Request.get).toHaveBeenCalledTimes(1) + expect(Request.get).toHaveBeenCalledWith('/subcalendars/1234') }) test('without id', function () { expect(() => API.listSubCalendar()).toThrow() }) - test.each([[], {}, true, false, 'text'])('invalid id', function (id) { - expect(() => API.listSubCalendar(id)).toThrow() - }) + test.each([[], {}, true, false, 'text', null, undefined])( + 'invalid id', + function (id) { + expect(() => API.listSubCalendar(id)).toThrow() + } + ) }) }) diff --git a/__tests__/helpers.js b/__tests__/helpers.js new file mode 100644 index 0000000..2fd8d23 --- /dev/null +++ b/__tests__/helpers.js @@ -0,0 +1,13 @@ +exports.buildParams = function (params) { + let urlParams = '' + Object.keys(params).forEach(function (key) { + if (key === 'subcalendarId') { + params[key].forEach((id) => { + urlParams += `${key}[]=${id}&` + }) + } else { + urlParams += `${key}=${params[key]}&` + } + }) + return urlParams.substring(0, urlParams.length - 1) +} diff --git a/examples/example.js b/examples/example.js index 7e7a218..ba50ff5 100644 --- a/examples/example.js +++ b/examples/example.js @@ -9,26 +9,25 @@ const { Events, SubCalendar } = new Client({ ;(async function getLeaves() { // fetch id for leave calendar let leaveCalId - await SubCalendar.listSubCalendars({ includeInactive: true }).then( - ({ data: { subcalendars } }) => { + await SubCalendar.listSubCalendars() + .then(({ data: { subcalendars } }) => { for (const subCal of subcalendars) { if (subCal.name === 'leave') { leaveCalId = subCal.id break } } - } - ) + }) + .catch((err) => console.log(err.response.data)) - // get all events identified by leaveCalId - const { - data: { events }, - } = await Events.listEvents({ - startDate: '2022-06-06', - endDate: '2022-06-10', - subcalendarId: leaveCalId, - }) - - // leave events - console.log(events) + if (leaveCalId) { + // get all events identified by leaveCalId + await Events.listEvents({ + startDate: '2022-06-06', + endDate: '2022-06-10', + subcalendarId: [leaveCalId], + }) + .then(({ data: { events } }) => console.log(events)) + .catch((err) => console.log(err.response.data)) + } })() diff --git a/jest.config.js b/jest.config.js index 9a1888a..c02f013 100644 --- a/jest.config.js +++ b/jest.config.js @@ -3,5 +3,5 @@ module.exports = { clearMocks: true, // The glob patterns Jest uses to detect test files - testMatch: ['**/__tests__/**/*.[jt]s'], + testMatch: ['**/__tests__/**/*.(spec|test).[jt]s'], } diff --git a/lib/API.js b/lib/API.js index e86d8bb..03d7a7f 100644 --- a/lib/API.js +++ b/lib/API.js @@ -29,4 +29,22 @@ module.exports = class API { this._Logger.error(msg) } } + + _buildUrlParams(params) { + let urlParams = '' + + Object.keys(params).forEach((key) => { + if (params[key] !== null && params[key] !== undefined) { + if (params[key] instanceof Array) { + params[key].forEach((value) => { + urlParams += `${key}[]=${value}&` + }) + } else { + urlParams += `${key}=${params[key]}&` + } + } + }) + + return urlParams.substring(0, urlParams.length - 1) + } } diff --git a/lib/Client.js b/lib/Client.js index a7a098a..4c2e512 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -17,7 +17,10 @@ module.exports = class Client { } getBaseUrl() { - return join(this.#url, this.#calToken) + return join(this.#url, this.#calToken).replace( + /(?<=http(s)?):\/(?!\/)/, + '://' + ) } getAuthHeader() { diff --git a/lib/Events.js b/lib/Events.js index cc90c4e..86005f5 100644 --- a/lib/Events.js +++ b/lib/Events.js @@ -26,10 +26,8 @@ module.exports = class Events extends API { ) { this._validateOptionType(params) - const urlParams = this.#buildParams(params) - const path = urlParams - ? join(this.#ENDPOINT, `?${urlParams}`) - : this.#ENDPOINT + const urlParams = this.#getUrlParams(params) + const path = urlParams ? `${this.#ENDPOINT}?${urlParams}` : this.#ENDPOINT return this._Request.get(path) } @@ -40,23 +38,10 @@ module.exports = class Events extends API { return this._Request.get(join(this.#ENDPOINT, eventId.toString())) } - #buildParams(params) { + #getUrlParams(params) { this.#validateParams(params) - let urlParams = '' - Object.keys(params).forEach((key) => { - if (params[key]) { - if (key === 'subcalendarId') { - params[key].forEach((id) => { - urlParams += `${key}[]=${id}&` - }) - } else { - urlParams += `${key}=${params[key]}&` - } - } - }) - - return urlParams.substring(0, urlParams.length - 1) + return this._buildUrlParams(params) } #validateParams(params) { @@ -65,29 +50,35 @@ module.exports = class Events extends API { this._Logger.error(`Invalid url param: '${key}'`) } - if (params[key]) { - if ( - key === 'format' && - !this.#URL_PARAMS.format.split('|').includes(params[key]) - ) { - this._Logger.error(`Format can either be 'html' or 'markdown'`) + if (params[key] !== null) { + if (key === 'format') { + if (!this.#URL_PARAMS.format.split('|').includes(params[key])) { + this._Logger.error(`Format can either be 'html' or 'markdown'`) + } + return } - - if (key !== 'format') { - if (key === 'subcalendarId' && !params[key] instanceof Array) { - this._Logger.error( - `Parameter '${key}' must be of type '${this.#URL_PARAMS[key]}'` - ) - } else if ( - key !== 'subcalendarId' && - typeof params[key] !== this.#URL_PARAMS[key] + if (key === 'subcalendarId') { + if ( + !(params[key] instanceof Array) || + typeof params[key] == 'string' ) { this._Logger.error( - `Parameter '${key}' must be of type '${ - this.#URL_PARAMS[key] - }'. Given '${typeof params[key]}'` + `Parameter '${key}' must be of type '${this.#URL_PARAMS[key]}'` ) } + return + } + if (typeof params[key] !== this.#URL_PARAMS[key]) { + this._Logger.error( + `Parameter '${key}' must be of type '${ + this.#URL_PARAMS[key] + }'. Given '${typeof params[key]}'` + ) + } + if (key === 'startDate' || key === 'endDate') { + if (params[key] === '') { + this._Logger.error(`Invalid date for '${key}': ${params[key]}`) + } } } }) diff --git a/lib/SubCalendar.js b/lib/SubCalendar.js index 1e7c3c4..8b21e21 100644 --- a/lib/SubCalendar.js +++ b/lib/SubCalendar.js @@ -18,10 +18,8 @@ module.exports = class SubCalendar extends API { ) { this._validateOptionType(params) - const urlParams = this.#buildParams(params) - const path = urlParams - ? join(this.#ENDPOINT, `?${urlParams}`) - : this.#ENDPOINT + const urlParams = this.#getUrlParams(params) + const path = urlParams ? `${this.#ENDPOINT}?${urlParams}` : this.#ENDPOINT return this._Request.get(path) } @@ -32,14 +30,10 @@ module.exports = class SubCalendar extends API { return this._Request.get(join(this.#ENDPOINT, calendarId.toString())) } - #buildParams(params) { + #getUrlParams(params) { this.#validateParams(params) - let urlParams = params.includeInactive - ? `includeInactive:${params.includeInactive}` - : '' - - return urlParams + return this._buildUrlParams(params) } #validateParams(params) { @@ -48,7 +42,7 @@ module.exports = class SubCalendar extends API { this._Logger.error(`Invalid url param: '${key}'`) } - if (params[key]) { + if (params[key] !== null) { if (typeof params[key] !== this.#URL_PARAMS[key]) { this._Logger.error( `Parameter '${key}' must be of type '${ diff --git a/package.json b/package.json index 3dbfee6..7741188 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@sawjan/teamup-client", "description": "Simple client for Teamup calendar API", - "version": "1.0.0", + "version": "1.1.0", "main": "./lib/index.js", "author": "Sawjan G. (https://sajang.com.np)", "license": "MIT",