From eaced7e51bfe5a0034772b72a655695897c002fb Mon Sep 17 00:00:00 2001 From: Siim Raud Date: Tue, 16 Sep 2025 13:26:23 +0300 Subject: [PATCH 1/5] Basic test --- .../services/ticket/set-external-data.spec.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 packages/javascript-api/src/lib/services/ticket/set-external-data.spec.ts diff --git a/packages/javascript-api/src/lib/services/ticket/set-external-data.spec.ts b/packages/javascript-api/src/lib/services/ticket/set-external-data.spec.ts new file mode 100644 index 00000000..27360f1e --- /dev/null +++ b/packages/javascript-api/src/lib/services/ticket/set-external-data.spec.ts @@ -0,0 +1,40 @@ +import * as sinon from 'sinon'; +import { Qminder } from '../../qminder'; +import { TicketService } from './ticket.service'; + +describe('Ticket.setExternalData', () => { + let requestStub: sinon.SinonStub; + + beforeEach(() => { + Qminder.setKey('EXAMPLE_API_KEY'); + Qminder.setServer('api.qminder.com'); + requestStub = sinon.stub(Qminder.ApiBase, 'request'); + }); + + afterEach(() => { + sinon.restore(); + }); + + it('sends POST to v1/tickets//external with stringified data and returns success', async () => { + const ticketId = '123'; + const provider = 'crm'; + const title = 'Case #42'; + const data = { foo: 'bar', num: 5 }; + + requestStub.resolves({ result: 'success' }); + + const result = await TicketService.setExternalData(ticketId as any, provider, title, data); + + expect(result).toBe('success'); + + expect(requestStub.calledOnce).toBeTruthy(); + const [url, options] = requestStub.getCall(0).args as [string, any]; + expect(url).toBe(`v1/tickets/${ticketId}/external`); + expect(options.method).toBe('POST'); + expect(options.body).toEqual({ + provider, + title, + data: JSON.stringify(data), + }); + }); +}); From 908e7fc50b0c22d1879401601b84e2c33d910848 Mon Sep 17 00:00:00 2001 From: Siim Raud Date: Tue, 16 Sep 2025 13:30:14 +0300 Subject: [PATCH 2/5] Typescript type --- .../services/ticket/set-external-data.spec.ts | 2 +- .../src/lib/services/ticket/ticket.ts | 37 ++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/javascript-api/src/lib/services/ticket/set-external-data.spec.ts b/packages/javascript-api/src/lib/services/ticket/set-external-data.spec.ts index 27360f1e..ff43d750 100644 --- a/packages/javascript-api/src/lib/services/ticket/set-external-data.spec.ts +++ b/packages/javascript-api/src/lib/services/ticket/set-external-data.spec.ts @@ -19,7 +19,7 @@ describe('Ticket.setExternalData', () => { const ticketId = '123'; const provider = 'crm'; const title = 'Case #42'; - const data = { foo: 'bar', num: 5 }; + const data = { fields: [ { type: 'message', content: 'Hello', importance: 'info' }, { type: 'text', title: 'Order', value: '42' }, { type: 'list', title: 'Links', items: [ { title: 'Home', url: 'https://example.com' } ] } ] } as any; requestStub.resolves({ result: 'success' }); diff --git a/packages/javascript-api/src/lib/services/ticket/ticket.ts b/packages/javascript-api/src/lib/services/ticket/ticket.ts index 0f4ff6a3..e135bc5b 100644 --- a/packages/javascript-api/src/lib/services/ticket/ticket.ts +++ b/packages/javascript-api/src/lib/services/ticket/ticket.ts @@ -751,11 +751,46 @@ export function forward( return ApiBase.request(`v1/tickets/${ticketId}/forward`, { body: body }); } +export type ExternalData = { + fields?: ExternalDataField[]; +}; + +export type ExternalDataField = + | ExternalMessageField + | ExternalTextualField + | ExternalListField; + +export interface ExternalMessageField { + type: 'message'; + content: string; + importance: 'info' | 'warning' | 'error'; +} + +export interface ExternalTextualField { + type: 'text' | 'email' | 'phoneNumber'; + title: string; + value: string; +} + +export interface ExternalListItem { + title: string; + text?: string; + url?: string; + footer?: string; + timestamp?: string; +} + +export interface ExternalListField { + type: 'list'; + title: string; + items: ExternalListItem[]; +} + export function setExternalData( ticket: IdOrObject, provider: string, title: string, - data: any, + data: ExternalData, ): Promise<'success'> { const ticketId = extractId(ticket); From ae7ad4af128fa313d77d5eb775bf473970ed0f52 Mon Sep 17 00:00:00 2001 From: Siim Raud Date: Tue, 16 Sep 2025 13:34:26 +0300 Subject: [PATCH 3/5] Separate model file --- .../src/lib/model/ticket/external-data.ts | 34 ++++++++++++++++++ .../src/lib/services/ticket/ticket.ts | 35 +------------------ 2 files changed, 35 insertions(+), 34 deletions(-) create mode 100644 packages/javascript-api/src/lib/model/ticket/external-data.ts diff --git a/packages/javascript-api/src/lib/model/ticket/external-data.ts b/packages/javascript-api/src/lib/model/ticket/external-data.ts new file mode 100644 index 00000000..e5c9977d --- /dev/null +++ b/packages/javascript-api/src/lib/model/ticket/external-data.ts @@ -0,0 +1,34 @@ +export type ExternalData = { + fields?: ExternalDataField[]; +}; + +export type ExternalDataField = + | ExternalMessageField + | ExternalTextualField + | ExternalListField; + +export interface ExternalMessageField { + type: 'message'; + content: string; + importance: 'info' | 'warning' | 'error'; +} + +export interface ExternalTextualField { + type: 'text' | 'email' | 'phoneNumber'; + title: string; + value: string; +} + +export interface ExternalListItem { + title: string; + text?: string; + url?: string; + footer?: string; + timestamp?: string; +} + +export interface ExternalListField { + type: 'list'; + title: string; + items: ExternalListItem[]; +} diff --git a/packages/javascript-api/src/lib/services/ticket/ticket.ts b/packages/javascript-api/src/lib/services/ticket/ticket.ts index e135bc5b..dbe9d436 100644 --- a/packages/javascript-api/src/lib/services/ticket/ticket.ts +++ b/packages/javascript-api/src/lib/services/ticket/ticket.ts @@ -11,6 +11,7 @@ import { } from '../../util/id-or-object.js'; import { ApiBase } from '../api-base/api-base.js'; import { ResponseValidationError } from '../../model/errors/response-validation-error.js'; +import { ExternalData } from '../../model/ticket/external-data.js'; /** * Represents a collection of search criteria for TicketService.count(). @@ -751,40 +752,6 @@ export function forward( return ApiBase.request(`v1/tickets/${ticketId}/forward`, { body: body }); } -export type ExternalData = { - fields?: ExternalDataField[]; -}; - -export type ExternalDataField = - | ExternalMessageField - | ExternalTextualField - | ExternalListField; - -export interface ExternalMessageField { - type: 'message'; - content: string; - importance: 'info' | 'warning' | 'error'; -} - -export interface ExternalTextualField { - type: 'text' | 'email' | 'phoneNumber'; - title: string; - value: string; -} - -export interface ExternalListItem { - title: string; - text?: string; - url?: string; - footer?: string; - timestamp?: string; -} - -export interface ExternalListField { - type: 'list'; - title: string; - items: ExternalListItem[]; -} export function setExternalData( ticket: IdOrObject, From 2ff3a9199448f7ee1b439294183e74775cee9495 Mon Sep 17 00:00:00 2001 From: Siim Raud Date: Tue, 16 Sep 2025 13:36:59 +0300 Subject: [PATCH 4/5] Not using "any" --- .../services/ticket/set-external-data.spec.ts | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/javascript-api/src/lib/services/ticket/set-external-data.spec.ts b/packages/javascript-api/src/lib/services/ticket/set-external-data.spec.ts index ff43d750..d5bc3ee1 100644 --- a/packages/javascript-api/src/lib/services/ticket/set-external-data.spec.ts +++ b/packages/javascript-api/src/lib/services/ticket/set-external-data.spec.ts @@ -1,6 +1,7 @@ import * as sinon from 'sinon'; import { Qminder } from '../../qminder'; import { TicketService } from './ticket.service'; +import { ExternalData } from '../../model/ticket/external-data.js'; describe('Ticket.setExternalData', () => { let requestStub: sinon.SinonStub; @@ -19,11 +20,26 @@ describe('Ticket.setExternalData', () => { const ticketId = '123'; const provider = 'crm'; const title = 'Case #42'; - const data = { fields: [ { type: 'message', content: 'Hello', importance: 'info' }, { type: 'text', title: 'Order', value: '42' }, { type: 'list', title: 'Links', items: [ { title: 'Home', url: 'https://example.com' } ] } ] } as any; + const data: ExternalData = { + fields: [ + { type: 'message', content: 'Hello', importance: 'info' }, + { type: 'text', title: 'Order', value: '42' }, + { + type: 'list', + title: 'Links', + items: [{ title: 'Home', url: 'https://example.com' }], + }, + ], + }; requestStub.resolves({ result: 'success' }); - const result = await TicketService.setExternalData(ticketId as any, provider, title, data); + const result = await TicketService.setExternalData( + ticketId, + provider, + title, + data, + ); expect(result).toBe('success'); From c60297ddfa67a93adaf4660d6de1e86e82ebc139 Mon Sep 17 00:00:00 2001 From: Siim Raud Date: Tue, 16 Sep 2025 13:38:14 +0300 Subject: [PATCH 5/5] Prettier --- packages/javascript-api/src/lib/services/ticket/ticket.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/javascript-api/src/lib/services/ticket/ticket.ts b/packages/javascript-api/src/lib/services/ticket/ticket.ts index dbe9d436..ef4dbe75 100644 --- a/packages/javascript-api/src/lib/services/ticket/ticket.ts +++ b/packages/javascript-api/src/lib/services/ticket/ticket.ts @@ -752,7 +752,6 @@ export function forward( return ApiBase.request(`v1/tickets/${ticketId}/forward`, { body: body }); } - export function setExternalData( ticket: IdOrObject, provider: string,