diff --git a/packages/rest-api-client/src/client/__tests__/AppClient.test.ts b/packages/rest-api-client/src/client/__tests__/AppClient.test.ts index 6fac1539bd..6cfebf2510 100644 --- a/packages/rest-api-client/src/client/__tests__/AppClient.test.ts +++ b/packages/rest-api-client/src/client/__tests__/AppClient.test.ts @@ -1,1471 +1,14 @@ -import type { MockClient } from "../../http/MockClient"; -import { buildMockClient } from "../../http/MockClient"; -import { AppClient } from "../AppClient"; -import { KintoneRequestConfigBuilder } from "../../KintoneRequestConfigBuilder"; - -const APP_ID = 1; -const REVISION = 5; -const RECORD_ID = 3; -const properties = { - fieldCode: { - type: "SINGLE_LINE_TEXT" as const, - code: "fieldCode", - label: "Text Field", - }, -}; - -const layout = [ - { - type: "ROW" as const, - fields: [ - { - type: "SINGLE_LINE_TEXT", - code: "fieldCode1", - size: { width: "100" }, - }, - { - type: "LABEL", - label: "label1", - size: { width: "100" }, - }, - { - type: "SPACER", - elementId: "space", - size: { width: "100", height: "50" }, - }, - ], - }, - { - type: "SUBTABLE" as const, - code: "tableFieldCode", - fields: [ - { - type: "MULTI_LINE_TEXT", - code: "fieldCode2", - size: { width: "150", innerHeight: "200" }, - }, - ], - }, - { - type: "GROUP" as const, - code: "fieldCode3", - layout: [ - { - type: "ROW" as const, - fields: [ - { - type: "NUMBER", - code: "fieldCode3_1", - size: { - width: 200, - }, - }, - ], - }, - ], - }, -]; - -const views = { - view1: { - type: "LIST" as const, - index: 0, - name: "view1", - fields: ["field"], - filterCond: 'field = "foo"', - sort: "sortField desc", - }, - view2: { - type: "CALENDAR" as const, - index: 1, - name: "view2", - date: "dateField", - title: "titleField", - filterCond: 'field = "bar"', - sort: "sortField asc", - }, - view3: { - type: "CUSTOM" as const, - index: 2, - name: "view3", - html: "
Hello!
", - pager: true, - device: "DESKTOP" as const, - }, -}; - -const states = { - status1: { - name: "status1", - index: 0, - assignee: { - type: "ONE" as const, - entities: [ - { entity: { type: "FIELD_ENTITY" as const, code: "creator" } }, - ], - }, - }, - status2: { - name: "status2", - index: 1, - assignee: { - type: "ANY" as const, - entities: [{ entity: { type: "CREATOR" as const } }], - }, - }, - status3: { - name: "status3", - index: 2, - assignee: { - type: "ALL" as const, - entities: [ - { entity: { type: "USER" as const, code: "user1" } }, - { entity: { type: "USER" as const, code: "user2" } }, - ], - }, - }, -}; -const actions = [ - { name: "action1to2", from: "status1", to: "status2" }, - { - name: "action2to3", - from: "status2", - to: "status3", - filterCond: 'field = "foo"', - }, -]; - -describe("AppClient", () => { - let mockClient: MockClient; - let appClient: AppClient; - - beforeEach(() => { - const requestConfigBuilder = new KintoneRequestConfigBuilder({ - baseUrl: "https://example.cybozu.com", - auth: { type: "apiToken", apiToken: "foo" }, - }); - mockClient = buildMockClient(requestConfigBuilder); - appClient = new AppClient(mockClient); - }); - describe("getFormFields", () => { - const lang = "default"; - const params = { app: APP_ID, lang } as const; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getFormFields(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/form/fields.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getFormFields({ ...params, preview: true }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/form/fields.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - - describe("addFormFields", () => { - const params = { app: APP_ID, properties, revision: REVISION }; - beforeEach(async () => { - await appClient.addFormFields(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/form/fields.json", - ); - }); - it("should send a post request", () => { - expect(mockClient.getLogs()[0].method).toBe("post"); - }); - it("should pass app, properties and revision as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("updateFormFields", () => { - const params = { app: APP_ID, properties, revision: REVISION }; - beforeEach(async () => { - await appClient.updateFormFields(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/form/fields.json", - ); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app, properties and revision to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("deleteFormFields", () => { - const fields = ["fieldCode1", "fieldCode2"]; - const params = { app: APP_ID, fields, revision: REVISION }; - beforeEach(async () => { - await appClient.deleteFormFields(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/form/fields.json", - ); - }); - it("should send a delete request", () => { - expect(mockClient.getLogs()[0].method).toBe("delete"); - }); - it("should pass app, fields, and revision to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getFormLayout", () => { - const params = { app: APP_ID }; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getFormLayout(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/form/layout.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getFormLayout({ ...params, preview: true }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/form/layout.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - - describe("updateFormLayout", () => { - const params = { app: APP_ID, layout, revision: REVISION }; - - beforeEach(async () => { - await appClient.updateFormLayout(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/form/layout.json", - ); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app, layout and revision to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getViews", () => { - const lang = "default"; - const params = { app: APP_ID, lang } as const; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getViews(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/views.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getViews({ ...params, preview: true }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/views.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - - describe("updateViews", () => { - const params = { app: APP_ID, views, revision: REVISION }; - beforeEach(async () => { - await appClient.updateViews(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/preview/app/views.json"); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app, views and revision to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getApp", () => { - const params = { - id: APP_ID, - }; - beforeEach(async () => { - await appClient.getApp(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/app.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass id as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getApps", () => { - const params = { - ids: [APP_ID], - codes: ["APP"], - name: "app", - spaceIds: [1, 2], - limit: 100, - offset: 30, - }; - beforeEach(async () => { - await appClient.getApps(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/apps.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass ids, codes, name, spaceIds, limit, and offset as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("addApp", () => { - describe("without space", () => { - const params = { - name: "app", - }; - beforeEach(async () => { - await appClient.addApp(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/preview/app.json"); - }); - it("should send a post request", () => { - expect(mockClient.getLogs()[0].method).toBe("post"); - }); - it("should pass name, space, and thread as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("with space", () => { - const params = { - name: "app", - space: 10, - }; - const defaultThread = 20; - beforeEach(async () => { - mockClient.mockResponse({ defaultThread }); - await appClient.addApp(params); - }); - it("should fetch the default thread of the space", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/space.json"); - expect(mockClient.getLogs()[0].method).toBe("get"); - expect(mockClient.getLogs()[0].params).toEqual({ id: params.space }); - }); - it("should add new app into the default thread", () => { - expect(mockClient.getLogs()[1].path).toBe("/k/v1/preview/app.json"); - expect(mockClient.getLogs()[1].method).toBe("post"); - expect(mockClient.getLogs()[1].params).toEqual({ - ...params, - thread: defaultThread, - }); - }); - }); - }); - - describe("getProcessManagement", () => { - const lang = "default"; - const params = { app: APP_ID, lang } as const; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getProcessManagement(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/status.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getProcessManagement({ ...params, preview: true }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/status.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - - describe("updateProcessManagement", () => { - const params = { - app: APP_ID, - revision: REVISION, - enable: true, - states, - actions, - }; - beforeEach(async () => { - await appClient.updateProcessManagement(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/status.json", - ); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app, states, actions and revision to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getAppSettings", () => { - const lang = "default"; - const params = { app: APP_ID, lang } as const; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getAppSettings(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/settings.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getAppSettings({ ...params, preview: true }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/settings.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - - describe("updateAppSettings", () => { - const params = { - app: APP_ID, - revision: REVISION, - name: "test app", - description: "
Description
", - icon: { - type: "FILE" as const, - file: { - fileKey: "file key", - }, - }, - theme: "WHITE" as const, - }; - beforeEach(async () => { - await appClient.updateAppSettings(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/settings.json", - ); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app, name, description, icon, theme and revision to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getDeployStatus", () => { - const params = { - apps: [APP_ID], - }; - beforeEach(async () => { - await appClient.getDeployStatus(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/deploy.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass apps as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("deployApp", () => { - const params = { - apps: [{ app: APP_ID, revision: REVISION }], - revert: true, - }; - beforeEach(async () => { - await appClient.deployApp(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/deploy.json", - ); - }); - it("should send a post request", () => { - expect(mockClient.getLogs()[0].method).toBe("post"); - }); - it("should pass apps and revert as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getFieldAcl", () => { - const params = { - app: APP_ID, - }; - beforeEach(async () => { - await appClient.getFieldAcl(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/field/acl.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("updateFieldAcl", () => { - const params = { - app: APP_ID, - rights: [ - { - code: "foo", - entities: [ - { - accessibility: "READ" as const, - entity: { - code: "bar", - type: "USER" as const, - }, - }, - ], - }, - ], - }; - - beforeEach(async () => { - await appClient.updateFieldAcl(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/preview/field/acl.json"); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app and rights as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getRecordAcl", () => { - const lang = "default"; - const params = { - app: APP_ID, - lang, - } as const; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getRecordAcl(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/record/acl.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getRecordAcl({ ...params, preview: true }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/record/acl.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - - describe("updateRecordAcl", () => { - const params = { - app: APP_ID, - rights: [ - { - filterCond: 'field = "foo"', - entities: [ - { - entity: { - code: "bar", - type: "USER" as const, - }, - viewable: false, - editable: false, - deletable: false, - includeSubs: true, - }, - ], - }, - ], - revision: REVISION, - }; - beforeEach(async () => { - await appClient.updateRecordAcl(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/record/acl.json", - ); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app, right and revision as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getPerRecordNotifications", () => { - const params = { - app: APP_ID, - }; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getPerRecordNotifications(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/app/notifications/perRecord.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getPerRecordNotifications({ ...params, preview: true }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/notifications/perRecord.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and preview as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - - describe("getAppAcl", () => { - const params = { - app: APP_ID, - }; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getAppAcl(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/acl.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getAppAcl({ ...params, preview: true }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/preview/app/acl.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and preview as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - - describe("updateAppAcl", () => { - const params = { - app: APP_ID, - rights: [ - { - entity: { - type: "USER" as const, - code: "foo", - }, - appEditable: true, - recordViewable: true, - recordAddable: true, - recordEditable: true, - recordDeletable: true, - recordImportable: true, - recordExportable: true, - }, - ], - }; - beforeEach(async () => { - await appClient.updateAppAcl(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/preview/app/acl.json"); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app and rights as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("evaluateRecordsAcl", () => { - const params = { - app: APP_ID, - ids: [RECORD_ID], - }; - beforeEach(async () => { - await appClient.evaluateRecordsAcl(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/records/acl/evaluate.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and ids as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getAppCustomize", () => { - const params = { app: APP_ID }; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getAppCustomize(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/customize.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getAppCustomize({ ...params, preview: true }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/customize.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and preview as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - - describe("updateAppCustomize", () => { - const resource = { - js: [ - { - type: "URL" as const, - url: "https://www.example.com/example-mobile.js", - }, - ], - css: [ - { - type: "FILE" as const, - file: { - fileKey: "ddfc8e89-7aa3-4350-b9ab-3a75c9cf46b3", - }, - }, - ], - }; - const params = { - app: APP_ID, - scope: "ALL" as const, - desktop: resource, - mobile: resource, - revision: REVISION, - }; - describe("customize resources are specified", () => { - beforeEach(async () => { - await appClient.updateAppCustomize(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/customize.json", - ); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app, scope, desktop, mobile and revision as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - - describe("getGeneralNotifications", () => { - const params = { - app: APP_ID, - }; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getGeneralNotifications(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/app/notifications/general.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getGeneralNotifications({ ...params, preview: true }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/notifications/general.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and preview as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - - describe("updateReminderNotifications", () => { - const params = { - app: 1, - notifications: [ - { - timing: { - code: "CREATED_TIME", - daysLater: "1", - hoursLater: "2", - }, - filterCond: 'CREATED_TIME in ("user1)', - title: "test title1", - targets: [ - { - entity: { - type: "USER", - code: "user1", - } as const, - includeSubs: false, - }, - ], - }, - { - timing: { - code: "CREATED_TIME", - daysLater: "-3", - time: "08:30", - }, - filterCond: 'CREATED_TIME in ("user1")', - title: "test title2", - targets: [ - { - entity: { - type: "USER", - code: "user1", - } as const, - includeSubs: false, - }, - ], - }, - ], - timezone: "Asia/Tokyo", - revision: "2", - }; - beforeEach(async () => { - await appClient.updateReminderNotifications(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/notifications/reminder.json", - ); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app and rights as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("updatePerRecordNotifications", () => { - const params = { - app: APP_ID, - notifications: [ - { - filterCond: 'Customer = "foo"', - title: "Send a notification", - targets: [ - { - entity: { - type: "USER" as const, - code: "foo", - }, - includeSubs: false, - }, - ], - }, - ], - revision: 1, - }; - - beforeEach(async () => { - await appClient.updatePerRecordNotifications(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/notifications/perRecord.json", - ); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app and rights as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getAppNotificationsReminder", () => { - const lang = "default"; - const params = { app: APP_ID, lang } as const; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getReminderNotifications(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/app/notifications/reminder.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getReminderNotifications({ - ...params, - preview: true, - }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/notifications/reminder.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - describe("updateAppUpdateGeneralNotifications", () => { - const params = { - app: APP_ID, - notifications: [ - { - entity: { - type: "USER" as const, - code: "foo", - }, - includeSubs: true, - recordAdded: true, - recordEdited: true, - commentAdded: true, - statusChanged: true, - fileImported: true, - }, - ], - notifyToCommenter: true, - revision: 1, - }; - beforeEach(async () => { - await appClient.updateGeneralNotifications(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/notifications/general.json", - ); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app and rights as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getReports", () => { - const lang = "default"; - const params = { app: APP_ID, lang } as const; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getReports(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/reports.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getReports({ - ...params, - preview: true, - }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/reports.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - - describe("updateReports", () => { - const params = { - app: 1, - reports: { - "Graph 1": { - chartType: "BAR" as const, - chartMode: "NORMAL" as const, - name: "Graph 1", - index: 0, - groups: [ - { - code: "Radio_button", - }, - ], - aggregations: [ - { - type: "COUNT" as const, - }, - ], - filterCond: "", - sorts: [ - { - by: "TOTAL" as const, - order: "DESC" as const, - }, - ], - periodicReport: { - active: true, - period: { - every: "QUARTER" as const, - pattern: "JAN_APR_JUL_OCT" as const, - dayOfMonth: "END_OF_MONTH" as const, - time: "23:30", - }, - }, - }, - }, - }; - beforeEach(async () => { - await appClient.updateReports(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/reports.json", - ); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app and rights as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getAppActions", () => { - const lang = "default"; - const params = { app: APP_ID, lang } as const; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getAppActions(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/actions.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getAppActions({ - ...params, - preview: true, - }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/actions.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - - describe("updateAppActions", () => { - const params = { - app: APP_ID, - actions: { - Action_A: { - name: "Action_A", - index: "0", - destApp: { - code: "INVOICE", - }, - mappings: [ - { - srcType: "FIELD" as const, - srcField: "CompanyName", - destField: "CompanyName", - }, - { - srcType: "FIELD" as const, - srcField: "DivisionName", - destField: "DivisionName", - }, - { - srcType: "RECORD_URL" as const, - destField: "URL", - }, - ], - entities: [ - { - type: "USER" as const, - code: "Administrator", - }, - ], - }, - }, - }; - beforeEach(async () => { - await appClient.updateAppActions(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/actions.json", - ); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app and actions as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); -}); - -describe("AppClient: AdminNotes", () => { - let mockClient: MockClient; - let appClient: AppClient; - - beforeEach(() => { - const requestConfigBuilder = new KintoneRequestConfigBuilder({ - baseUrl: "https://example.cybozu.com", - auth: { type: "apiToken", apiToken: "foo" }, - }); - mockClient = buildMockClient(requestConfigBuilder); - appClient = new AppClient(mockClient); - }); - describe("getAdminNotes", () => { - const params = { app: APP_ID } as const; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getAdminNotes(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/adminNotes.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getAdminNotes({ - ...params, - preview: true, - }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/adminNotes.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); - describe("updateAdminNotes", () => { - const params = { app: APP_ID } as const; - beforeEach(async () => { - await appClient.updateAdminNotes(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/adminNotes.json", - ); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app, content, includeInTemplateAndDuplicates, and revision as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); -}); - -describe("AppClient: move", () => { - let mockClient: MockClient; - let appClient: AppClient; - - beforeEach(() => { - const requestConfigBuilder = new KintoneRequestConfigBuilder({ - baseUrl: "https://example.cybozu.com", - auth: { type: "apiToken", apiToken: "foo" }, - }); - mockClient = buildMockClient(requestConfigBuilder); - appClient = new AppClient(mockClient); - }); - describe("move", () => { - const params = { app: APP_ID, space: 1 } as const; - beforeEach(async () => { - await appClient.move(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/move.json"); - }); - it("should send a post request", () => { - expect(mockClient.getLogs()[0].method).toBe("post"); - }); - it("should pass app and space as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); -}); - -describe("AppClient: plugins", () => { - let mockClient: MockClient; - let appClient: AppClient; - - beforeEach(() => { - const requestConfigBuilder = new KintoneRequestConfigBuilder({ - baseUrl: "https://example.cybozu.com", - auth: { type: "apiToken", apiToken: "foo" }, - }); - mockClient = buildMockClient(requestConfigBuilder); - appClient = new AppClient(mockClient); - }); - describe("getPlugins", () => { - const params = { app: APP_ID, lang: "en" } as const; - describe("without preview", () => { - beforeEach(async () => { - await appClient.getPlugins(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/plugins.json"); - }); - it("should pass app and lang as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("preview: true", () => { - beforeEach(async () => { - await appClient.getPlugins({ - ...params, - preview: true, - }); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe( - "/k/v1/preview/app/plugins.json", - ); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and lang as a param to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - }); -}); +import { APP_ID, makeClients } from "./fixtures/AppClientFixture"; describe("AppClient with guestSpaceId", () => { it("should pass the path to the http client", async () => { const GUEST_SPACE_ID = 2; + const clients = makeClients(GUEST_SPACE_ID); + const appClient = clients.appClient; + const mockClient = clients.mockClient; const lang = "default"; const params = { app: APP_ID, lang } as const; - const requestConfigBuilder = new KintoneRequestConfigBuilder({ - baseUrl: "https://example.cybozu.com", - auth: { type: "session" }, - }); - const mockClient = buildMockClient(requestConfigBuilder); - const appClient = new AppClient(mockClient, GUEST_SPACE_ID); + await appClient.getFormFields(params); expect(mockClient.getLogs()[0].path).toBe( `/k/guest/${GUEST_SPACE_ID}/v1/app/form/fields.json`, diff --git a/packages/rest-api-client/src/client/__tests__/RecordClient.test.ts b/packages/rest-api-client/src/client/__tests__/RecordClient.test.ts index 0827c521b2..120b267f47 100644 --- a/packages/rest-api-client/src/client/__tests__/RecordClient.test.ts +++ b/packages/rest-api-client/src/client/__tests__/RecordClient.test.ts @@ -1,1365 +1,13 @@ -import { RecordClient } from "../RecordClient"; -import { BulkRequestClient } from "../BulkRequestClient"; -import type { MockClient } from "../../http/MockClient"; -import { buildMockClient } from "../../http/MockClient"; -import { KintoneAllRecordsError } from "../../error/KintoneAllRecordsError"; -import { KintoneRestAPIError } from "../../error/KintoneRestAPIError"; -import type { Record } from "../types"; -import { KintoneRequestConfigBuilder } from "../../KintoneRequestConfigBuilder"; - -describe("RecordClient", () => { - let mockClient: MockClient; - let recordClient: RecordClient; - const APP_ID = 1; - const RECORD_ID = 2; - const fieldCode = "Customer"; - const record = { - [fieldCode]: { - value: "ABC Corporation", - }, - }; - - beforeEach(() => { - const requestConfigBuilder = new KintoneRequestConfigBuilder({ - baseUrl: "https://example.cybozu.com", - auth: { type: "apiToken", apiToken: "foo" }, - }); - mockClient = buildMockClient(requestConfigBuilder); - const bulkRequestClient = new BulkRequestClient(mockClient); - recordClient = new RecordClient(mockClient, bulkRequestClient); - }); - describe("getRecord", () => { - const params = { app: APP_ID, id: RECORD_ID }; - beforeEach(async () => { - await recordClient.getRecord(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/record.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app and id to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("addRecord", () => { - const params = { app: APP_ID, record }; - beforeEach(async () => { - await recordClient.addRecord(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/record.json"); - }); - it("should send a post request", () => { - expect(mockClient.getLogs()[0].method).toBe("post"); - }); - it("should pass app and record object to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("updateRecord", () => { - const params = { - app: APP_ID, - id: RECORD_ID, - record, - revision: 5, - }; - beforeEach(async () => { - await recordClient.updateRecord(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/record.json"); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app, id, record, and revision to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("upsertRecord", () => { - describe("update", () => { - const params = { - app: APP_ID, - updateKey: { - field: "Code", - value: "foo", - }, - record, - revision: 5, - }; - let getRecordsMockFn: jest.Mock; - let updateRecordMockFn: jest.Mock; - let addRecordMockFn: jest.Mock; - beforeEach(async () => { - getRecordsMockFn = jest.fn().mockResolvedValue({ - records: [ - { - $id: { - type: "__ID__", - value: "10", - }, - }, - ], - }); - updateRecordMockFn = jest.fn().mockResolvedValue({ - revision: "2", - }); - addRecordMockFn = jest.fn(); - const bulkRequestClient = new BulkRequestClient(mockClient); - recordClient = new RecordClient(mockClient, bulkRequestClient); - recordClient.getRecords = getRecordsMockFn; - recordClient.updateRecord = updateRecordMockFn; - recordClient.addRecord = addRecordMockFn; - }); - - it("should call getRecords with a query built with udpateKey", async () => { - await recordClient.upsertRecord(params); - expect(getRecordsMockFn.mock.calls.length).toBe(1); - expect(getRecordsMockFn.mock.calls[0][0]).toEqual({ - app: params.app, - query: `${params.updateKey.field} = "${params.updateKey.value}"`, - }); - }); - it("should call updateRecord with the params", async () => { - await recordClient.upsertRecord(params); - expect(updateRecordMockFn.mock.calls.length).toBe(1); - expect(updateRecordMockFn.mock.calls[0][0]).toEqual(params); - }); - it("should not call addRecord", async () => { - await recordClient.upsertRecord(params); - expect(addRecordMockFn.mock.calls.length).toBe(0); - }); - it("should return id and revision properties", async () => { - const result = await recordClient.upsertRecord(params); - expect(result).toEqual({ - id: "10", - revision: "2", - }); - }); - }); - describe("insert", () => { - const params = { - app: APP_ID, - updateKey: { - field: "Customer", - value: "foo", - }, - record, - revision: 5, - }; - let getRecordsMockFn: jest.Mock; - let updateRecordMockFn: jest.Mock; - let addRecordMockFn: jest.Mock; - beforeEach(() => { - getRecordsMockFn = jest.fn().mockResolvedValue({ - records: [], - }); - updateRecordMockFn = jest.fn(); - addRecordMockFn = jest.fn().mockResolvedValue({ - id: "10", - revision: "1", - }); - const bulkRequestClient = new BulkRequestClient(mockClient); - recordClient = new RecordClient(mockClient, bulkRequestClient); - recordClient.getRecords = getRecordsMockFn; - recordClient.updateRecord = updateRecordMockFn; - recordClient.addRecord = addRecordMockFn; - }); - - it("should call getRecords with a query built with udpateKey", async () => { - await recordClient.upsertRecord(params); - expect(getRecordsMockFn.mock.calls.length).toBe(1); - expect(getRecordsMockFn.mock.calls[0][0]).toEqual({ - app: params.app, - query: `${params.updateKey.field} = "${params.updateKey.value}"`, - }); - }); - it("should call addRecord with the params", async () => { - await recordClient.upsertRecord(params); - expect(addRecordMockFn.mock.calls.length).toBe(1); - expect(addRecordMockFn.mock.calls[0][0]).toEqual({ - app: params.app, - record: { - ...params.record, - [params.updateKey.field]: { value: params.updateKey.value }, - }, - }); - }); - it("should not call updateRecord", async () => { - await recordClient.upsertRecord(params); - expect(updateRecordMockFn.mock.calls.length).toBe(0); - }); - it("should return id and revision properties", async () => { - const result = await recordClient.upsertRecord(params); - expect(result).toEqual({ - id: "10", - revision: "1", - }); - }); - }); - }); - - describe("getRecords", () => { - describe("without offset", () => { - const params = { - app: APP_ID, - fields: [fieldCode], - query: `${fieldCode} = "foo"`, - totalCount: true, - }; - beforeEach(async () => { - await recordClient.getRecords(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/records.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app, fields, query and totalCount to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - describe("with offset", () => { - let consoleWarnMock: jest.SpyInstance; - beforeEach(() => { - consoleWarnMock = jest.spyOn(console, "warn"); - consoleWarnMock.mockImplementation((x) => x); - }); - describe("offset <= 10000", () => { - const params = { - app: APP_ID, - fields: [fieldCode], - query: `${fieldCode} = "foo" offset 10000`, - totalCount: true, - }; - it("doesn't output any message to the console", async () => { - await recordClient.getRecords(params); - expect(consoleWarnMock.mock.calls.length).toBe(0); - }); - }); - describe("offset > 10000", () => { - const params = { - app: APP_ID, - fields: [fieldCode], - query: `${fieldCode} = "foo" offset 10001`, - totalCount: true, - }; - it("outputs a message to the console only once when the request succeeds", async () => { - await recordClient.getRecords(params); - await recordClient.getRecords(params); - expect(consoleWarnMock.mock.calls.length).toBe(1); - }); - it("doesn't output any message to the console when the request fails", async () => { - expect.assertions(1); - mockClient.mockResponse(new Error("failed")); - try { - await recordClient.getRecords(params); - } catch { - expect(consoleWarnMock.mock.calls.length).toBe(0); - } - }); - }); - afterEach(() => { - consoleWarnMock.mockReset(); - consoleWarnMock.mockRestore(); - }); - }); - }); - - describe("addRecords", () => { - const params = { app: APP_ID, records: [record] }; - const mockResponse = { - ids: ["10", "20", "30"], - revisions: ["1", "2", "3"], - }; - let response: any; - beforeEach(async () => { - mockClient.mockResponse(mockResponse); - response = await recordClient.addRecords(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/records.json"); - }); - it("should send a post request", () => { - expect(mockClient.getLogs()[0].method).toBe("post"); - }); - it("should pass app and records to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - it("should return a response having ids, revisions, and records", () => { - expect(response).toEqual({ - ...mockResponse, - records: [ - { id: "10", revision: "1" }, - { id: "20", revision: "2" }, - { id: "30", revision: "3" }, - ], - }); - }); - }); - - describe("updateRecords", () => { - const params = { - app: APP_ID, - records: [{ id: RECORD_ID, record, revision: 5 }], - }; - beforeEach(async () => { - await recordClient.updateRecords(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/records.json"); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app, id, record, and revision to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("deleteRecords", () => { - const ids = [10, 20, 30]; - const revisions = [1, 2, 3]; - const params = { - app: APP_ID, - ids, - revisions, - }; - beforeEach(async () => { - await recordClient.deleteRecords(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/records.json"); - }); - it("should send a delete request", () => { - expect(mockClient.getLogs()[0].method).toBe("delete"); - }); - it("should pass app, ids, and revisions to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("createCursor", () => { - const params = { - app: APP_ID, - fields: [fieldCode], - query: `${fieldCode} = "foo"`, - size: 10, - }; - beforeEach(async () => { - await recordClient.createCursor(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/records/cursor.json"); - }); - it("should send a post request", () => { - expect(mockClient.getLogs()[0].method).toBe("post"); - }); - it("should pass app, fields, query, and size to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getRecordsByCursor", () => { - const params = { - id: "cursor id", - }; - beforeEach(async () => { - await recordClient.getRecordsByCursor(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/records/cursor.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass id to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("deleteCursor", () => { - const params = { - id: "cursor id", - }; - beforeEach(async () => { - await recordClient.deleteCursor(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/records/cursor.json"); - }); - it("should send a delete request", () => { - expect(mockClient.getLogs()[0].method).toBe("delete"); - }); - it("should pass id to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getAllRecordsWithId", () => { - describe("success with condition", () => { - it("should do nothing if `fields` is not specified", async () => { - const params = { - app: APP_ID, - condition: `${fieldCode} = "foo"`, - }; - mockClient.mockResponse({ records: [] }); - await recordClient.getAllRecordsWithId(params); - expect(mockClient.getLogs()[0].params.fields).toBe(undefined); - }); - - it("should do nothing if `fields` is empty", async () => { - const params = { - app: APP_ID, - fields: [], - condition: `${fieldCode} = "foo"`, - }; - mockClient.mockResponse({ records: [] }); - await recordClient.getAllRecordsWithId(params); - expect(mockClient.getLogs()[0].params.fields).toEqual([]); - }); - - it("should append `$id` if `fields` is specified and doesn't contain `$id`", async () => { - const params = { - app: APP_ID, - fields: [fieldCode], - condition: `${fieldCode} = "foo"`, - }; - mockClient.mockResponse({ records: [] }); - await recordClient.getAllRecordsWithId(params); - expect(mockClient.getLogs()[0].params.fields.sort()).toEqual( - [...params.fields, "$id"].sort(), - ); - }); - - it("should do nothing if `fields` is specified and contains `$id`", async () => { - const params = { - app: APP_ID, - fields: ["$id", fieldCode], - condition: `${fieldCode} = "foo"`, - }; - mockClient.mockResponse({ records: [] }); - await recordClient.getAllRecordsWithId(params); - expect(mockClient.getLogs()[0].params.fields).toEqual(params.fields); - }); - }); - - describe("success with condition", () => { - const params = { - app: APP_ID, - fields: ["$id"], - condition: `${fieldCode} = "foo"`, - }; - let result: Record[]; - - beforeEach(async () => { - const records = []; - for (let i = 1; i <= 500; i++) { - records.push({ - $id: { - type: "__ID__", - value: i.toString(), - }, - }); - } - mockClient.mockResponse({ records }); - mockClient.mockResponse({ - records: [{ $id: { type: "__ID__", value: "501" } }], - }); - result = await recordClient.getAllRecordsWithId(params); - }); - - it("should return all records", () => { - expect(mockClient.getLogs()[0]).toEqual({ - path: "/k/v1/records.json", - method: "get", - params: { - app: params.app, - fields: params.fields, - query: `(${params.condition}) and $id > 0 order by $id asc limit 500`, - }, - }); - expect(mockClient.getLogs()[1]).toEqual({ - path: "/k/v1/records.json", - method: "get", - params: { - app: params.app, - fields: params.fields, - query: `(${params.condition}) and $id > 500 order by $id asc limit 500`, - }, - }); - - expect(result.length).toBe(501); - expect(result[500]).toStrictEqual({ - $id: { type: "__ID__", value: "501" }, - }); - }); - }); - - describe("success without condition", () => { - const params = { - app: APP_ID, - fields: ["$id"], - }; - let result: Record[]; - - beforeEach(async () => { - const records = []; - for (let i = 1; i <= 500; i++) { - records.push({ - $id: { - type: "__ID__", - value: i.toString(), - }, - }); - } - mockClient.mockResponse({ records }); - mockClient.mockResponse({ - records: [{ $id: { type: "__ID__", value: "501" } }], - }); - result = await recordClient.getAllRecordsWithId(params); - }); - - it("should return all records", () => { - expect(mockClient.getLogs()[0]).toEqual({ - path: "/k/v1/records.json", - method: "get", - params: { - app: params.app, - fields: params.fields, - query: "$id > 0 order by $id asc limit 500", - }, - }); - expect(mockClient.getLogs()[1]).toEqual({ - path: "/k/v1/records.json", - method: "get", - params: { - app: params.app, - fields: params.fields, - query: "$id > 500 order by $id asc limit 500", - }, - }); - - expect(result.length).toBe(501); - expect(result[500]).toStrictEqual({ - $id: { type: "__ID__", value: "501" }, - }); - }); - }); - - describe("error in missing $id", () => { - it("should throw error when missing $id in `getRecords` response.", async () => { - const records: Record[] = []; - for (let i = 1; i < 500; i++) { - records.push({ - $id: { - type: "__ID__", - value: i.toString(), - }, - }); - } - records.push({ - $id: { - type: "RECORD_NUMBER", - value: "2", - }, - }); - mockClient.mockResponse({ records }); - const params = { - app: APP_ID, - }; - - await expect(recordClient.getAllRecordsWithId(params)).rejects.toThrow( - "Missing `$id` in `getRecords` response. This error is likely caused by a bug in Kintone REST API Client. Please file an issue.", - ); - }); - }); - }); - - describe("getAllRecordsWithOffset", () => { - describe("condition and orderBy parameters", () => { - it("with condition and orderBy", async () => { - const params = { - app: APP_ID, - condition: `${fieldCode} = "foo"`, - orderBy: `${fieldCode} asc`, - }; - mockClient.mockResponse({ records: [] }); - await recordClient.getAllRecordsWithOffset(params); - expect(mockClient.getLogs()[0].params.query).toBe( - `${fieldCode} = "foo" order by ${fieldCode} asc limit 500 offset 0`, - ); - }); - - it("with condition, without orderBy", async () => { - const params = { - app: APP_ID, - condition: `${fieldCode} = "foo"`, - }; - mockClient.mockResponse({ records: [] }); - await recordClient.getAllRecordsWithOffset(params); - expect(mockClient.getLogs()[0].params.query).toBe( - `${fieldCode} = "foo" limit 500 offset 0`, - ); - }); - - it("without condition, with orderBy", async () => { - const params = { - app: APP_ID, - orderBy: `${fieldCode} asc`, - }; - mockClient.mockResponse({ records: [] }); - await recordClient.getAllRecordsWithOffset(params); - expect(mockClient.getLogs()[0].params.query).toBe( - `order by ${fieldCode} asc limit 500 offset 0`, - ); - }); - - it("neither condition nor orderBy", async () => { - const params = { - app: APP_ID, - }; - mockClient.mockResponse({ records: [] }); - await recordClient.getAllRecordsWithOffset(params); - expect(mockClient.getLogs()[0].params.query).toBe("limit 500 offset 0"); - }); - }); - - describe("success", () => { - const params = { - app: APP_ID, - fields: ["$id"], - condition: `${fieldCode} = "foo"`, - }; - let result: Record[]; - - beforeEach(async () => { - const records = []; - for (let i = 1; i <= 500; i++) { - records.push({ - $id: { - type: "__ID__", - value: i.toString(), - }, - }); - } - mockClient.mockResponse({ records }); - mockClient.mockResponse({ - records: [{ $id: { type: "__ID__", value: "501" } }], - }); - result = await recordClient.getAllRecordsWithOffset(params); - }); - - it("should return all records", () => { - expect(mockClient.getLogs()[0]).toEqual({ - path: "/k/v1/records.json", - method: "get", - params: { - app: params.app, - fields: params.fields, - query: `${params.condition} limit 500 offset 0`, - }, - }); - expect(mockClient.getLogs()[1]).toEqual({ - path: "/k/v1/records.json", - method: "get", - params: { - app: params.app, - fields: params.fields, - query: `${params.condition} limit 500 offset 500`, - }, - }); - - expect(result.length).toBe(501); - expect(result[500]).toStrictEqual({ - $id: { type: "__ID__", value: "501" }, - }); - }); - }); - }); - - describe("getAllRecords", () => { - describe("`orderBy` is specified", () => { - const params = { - app: APP_ID, - condition: `${fieldCode} = "foo"`, - orderBy: `${fieldCode} asc`, - }; - let withCursorMockFn: jest.Mock; - let withOffsetMockFn: jest.Mock; - beforeEach(() => { - withCursorMockFn = jest.fn(); - withOffsetMockFn = jest.fn(); - recordClient.getAllRecordsWithCursor = withCursorMockFn; - recordClient.getAllRecordsWithOffset = withOffsetMockFn; - }); - it("should call `getAllRecordsWithCursor` if `withCursor` is not specified", async () => { - await recordClient.getAllRecords({ ...params }); - expect(withCursorMockFn.mock.calls.length).toBe(1); - expect(withCursorMockFn.mock.calls[0][0]).toStrictEqual({ - app: params.app, - query: `${params.condition} order by ${params.orderBy}`, - }); - }); - it("should call `getAllRecordsWithCursor` if `withCursor` is true", async () => { - await recordClient.getAllRecords({ ...params, withCursor: true }); - expect(withCursorMockFn.mock.calls.length).toBe(1); - expect(withCursorMockFn.mock.calls[0][0]).toStrictEqual({ - app: params.app, - query: `${params.condition} order by ${params.orderBy}`, - }); - }); - it("should call `getAllRecordsWithOffset` if `withCursor` is false", async () => { - await recordClient.getAllRecords({ ...params, withCursor: false }); - expect(withOffsetMockFn.mock.calls.length).toBe(1); - expect(withOffsetMockFn.mock.calls[0][0]).toStrictEqual(params); - }); - }); - - describe("`orderBy` is an empty string", () => { - const params = { - app: APP_ID, - condition: `${fieldCode} = "foo"`, - orderBy: "", - }; - const { orderBy, ...expected } = params; - let mockFn: jest.Mock; - beforeEach(() => { - mockFn = jest.fn(); - recordClient.getAllRecordsWithId = mockFn; - }); - it("should call `getAllRecordsWithId` if `withCursor` is not specified", async () => { - await recordClient.getAllRecords(params); - expect(mockFn.mock.calls.length).toBe(1); - expect(mockFn.mock.calls[0][0]).toStrictEqual(expected); - }); - it("should call `getAllRecordsWithId` if `withCursor` is true", async () => { - await recordClient.getAllRecords({ ...params, withCursor: true }); - expect(mockFn.mock.calls.length).toBe(1); - expect(mockFn.mock.calls[0][0]).toStrictEqual(expected); - }); - it("should call `getAllRecordsWithId` if `withCursor` is false", async () => { - await recordClient.getAllRecords({ ...params, withCursor: false }); - expect(mockFn.mock.calls.length).toBe(1); - expect(mockFn.mock.calls[0][0]).toStrictEqual(expected); - }); - }); - describe("`orderBy` is not specified", () => { - const params = { - app: APP_ID, - condition: `${fieldCode} = "foo"`, - }; - let mockFn: jest.Mock; - beforeEach(() => { - mockFn = jest.fn(); - recordClient.getAllRecordsWithId = mockFn; - }); - it("should call `getAllRecordsWithId` if `withCursor` is not specified", async () => { - await recordClient.getAllRecords(params); - expect(mockFn.mock.calls.length).toBe(1); - expect(mockFn.mock.calls[0][0]).toStrictEqual(params); - }); - it("should call `getAllRecordsWithId` if `withCursor` is true", async () => { - await recordClient.getAllRecords({ ...params, withCursor: true }); - expect(mockFn.mock.calls.length).toBe(1); - expect(mockFn.mock.calls[0][0]).toStrictEqual(params); - }); - it("should call `getAllRecordsWithId` if `withCursor` is false", async () => { - await recordClient.getAllRecords({ ...params, withCursor: false }); - expect(mockFn.mock.calls.length).toBe(1); - expect(mockFn.mock.calls[0][0]).toStrictEqual(params); - }); - }); - }); - - describe("getAllRecordsWithCursor", () => { - const params = { - app: APP_ID, - fields: [fieldCode], - query: `${fieldCode} = "foo"`, - }; - const CURSOR_ID = "1"; - let result: Record[]; - - describe("success", () => { - beforeEach(async () => { - // response from createCursor - mockClient.mockResponse({ id: CURSOR_ID, totalCount: "4" }); - // response from getRecordsByCursor - mockClient.mockResponse({ - records: [ - { $id: { type: "__ID__", value: "1" } }, - { $id: { type: "__ID__", value: "2" } }, - ], - next: true, - }); - mockClient.mockResponse({ - records: [ - { $id: { type: "__ID__", value: "3" } }, - { $id: { type: "__ID__", value: "4" } }, - ], - next: false, - }); - result = await recordClient.getAllRecordsWithCursor(params); - }); - - it("should create a cursor", () => { - expect(mockClient.getLogs()[0]).toEqual({ - path: "/k/v1/records/cursor.json", - method: "post", - params, - }); - }); - - it("should return all records", () => { - expect(mockClient.getLogs()[1]).toEqual({ - path: "/k/v1/records/cursor.json", - method: "get", - params: { id: CURSOR_ID }, - }); - expect(mockClient.getLogs()[2]).toEqual({ - path: "/k/v1/records/cursor.json", - method: "get", - params: { id: CURSOR_ID }, - }); - expect(result).toStrictEqual([ - { $id: { type: "__ID__", value: "1" } }, - { $id: { type: "__ID__", value: "2" } }, - { $id: { type: "__ID__", value: "3" } }, - { $id: { type: "__ID__", value: "4" } }, - ]); - }); - - it("should not call deleteCursor", () => { - expect(mockClient.getLogs().length).toEqual(3); - }); - }); - - describe("failure", () => { - beforeEach(() => { - // response from createCursor - mockClient.mockResponse({ id: CURSOR_ID, totalCount: "4" }); - // response from getRecordsByCursor - mockClient.mockResponse({ - records: [{ id: 1 }, { id: 2 }], - next: true, - }); - mockClient.mockResponse(new Error("failed")); - }); - - it("should raise error", async () => { - await expect( - recordClient.getAllRecordsWithCursor(params), - ).rejects.toThrow("failed"); - expect(mockClient.getLogs()[3]).toStrictEqual({ - path: "/k/v1/records/cursor.json", - method: "delete", - params: { id: CURSOR_ID }, - }); - }); - }); - }); - - describe("addAllRecords", () => { - const params = { - app: APP_ID, - records: Array.from({ length: 3000 }, (_, index) => index + 1).map( - (value) => ({ - [fieldCode]: { - value, - }, - }), - ), - }; - let response: any; - describe("success", () => { - const mockResponse = { - results: Array.from({ length: 20 }, (_, index) => index + 1).map( - (value) => ({ - ids: Array.from({ length: 100 }, (_, index) => index + 1), - revisions: Array.from({ length: 100 }, () => 1), - }), - ), - }; - const mockResponse2 = { - results: Array.from({ length: 10 }, (_, index) => index + 1).map( - (value) => ({ - ids: Array.from({ length: 100 }, (_, index) => index + 1), - revisions: Array.from({ length: 100 }, () => 1), - }), - ), - }; - beforeEach(async () => { - // response from first call of bulkRequest.send - mockClient.mockResponse(mockResponse); - // response from second call of bulkRequest.send - mockClient.mockResponse(mockResponse2); - response = await recordClient.addAllRecords(params); - }); - it("should call bulkRequest multiple times", () => { - expect(mockClient.getLogs().length).toBe(2); - }); - - it("should return merged result of each bulkRequest's result", () => { - const accumulateResponse = ( - acc: Array<{ id: number; revision: number }>, - { ids, revisions }: { ids: number[]; revisions: number[] }, - ) => - acc.concat( - ids.map((id, index) => ({ - id, - revision: revisions[index], - })), - ); - - const expected = [ - ...mockResponse.results.reduce(accumulateResponse, []), - ...mockResponse2.results.reduce(accumulateResponse, []), - ]; - expect(response.records).toStrictEqual(expected); - }); - }); - - describe("parameter error", () => { - it("should raise an Error if `records` parameter is not an array", async () => { - const invalidParams: any = { - app: APP_ID, - records: Array.from({ length: 3000 }, (_, index) => index + 1).map( - (value) => { - if (value === 1000) { - return value; - } - return { - [fieldCode]: { - value, - }, - }; - }, - ), - }; - await expect(recordClient.addAllRecords(invalidParams)).rejects.toThrow( - "the `records` parameter must be an array of object.", - ); - }); - }); - describe("response error", () => { - // success - const mockResponse = { - results: Array.from({ length: 20 }, (_, index) => index + 1).map( - (value) => ({ - ids: Array.from({ length: 100 }, (_, index) => index + 1), - revisions: Array.from({ length: 100 }, () => 1), - }), - ), - }; - // failed - const errorResponse = { - data: { - results: [ - {}, - {}, - { - id: "some id", - code: "some code", - message: "some error message", - errors: { - [`records[5].Customer`]: { - messages: ["key is missing"], - }, - }, - }, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - ], - }, - status: 500, - statusText: "Internal Server Error", - headers: { - "X-Some-Header": "error", - }, - }; - beforeEach(async () => { - mockClient.mockResponse(mockResponse); - mockClient.mockResponse(new KintoneRestAPIError(errorResponse)); - }); - it("should raise an KintoneAllRecordsError if an error occurs during bulkRequest", async () => { - await expect(recordClient.addAllRecords(params)).rejects.toBeInstanceOf( - KintoneAllRecordsError, - ); - }); - }); - }); - - describe("updateAllRecords", () => { - const params = { - app: APP_ID, - records: Array.from({ length: 3000 }, (_, index) => index + 1).map( - (value) => ({ - id: value, - record: { - [fieldCode]: { - value: `${fieldCode}-${value}`, - }, - }, - revision: 1, - }), - ), - }; - let response: any; - describe("success", () => { - const mockResponse = { - results: Array.from({ length: 20 }, (_, index) => index).map( - (value) => ({ - records: Array.from({ length: 100 }, (_, index) => - String(value * 100 + index + 1), - ).map((id) => ({ - id, - revision: "2", - })), - }), - ), - }; - const mockResponse2 = { - results: Array.from({ length: 10 }, (_, index) => index).map( - (value) => ({ - records: Array.from({ length: 100 }, (_, index) => - String(2000 + value * 100 + index + 1), - ).map((id) => ({ - id, - revision: "2", - })), - }), - ), - }; - beforeEach(async () => { - // response from first call of bulkRequest.send - mockClient.mockResponse(mockResponse); - // response from second call of bulkRequest.send - mockClient.mockResponse(mockResponse2); - response = await recordClient.updateAllRecords(params); - }); - it("should call bulkRequest multiple times", () => { - expect(mockClient.getLogs().length).toBe(2); - }); - - it("should return merged result of each bulkRequest's result", () => { - const accumulateResponse = ( - acc: Array<{ id: string; revision: string }>, - result: { records: Array<{ id: string; revision: string }> }, - ) => { - return acc.concat(result.records); - }; - - const expected = [ - ...mockResponse.results, - ...mockResponse2.results, - ].reduce(accumulateResponse, []); - expect(response.records).toStrictEqual(expected); - }); - }); - - describe("response error", () => { - // success - const mockResponse = { - results: Array.from({ length: 20 }, (_, index) => index).map( - (value) => ({ - records: Array.from({ length: 100 }, (_, index) => - String(value * 100 + index + 1), - ).map((id) => ({ - id, - revision: "2", - })), - }), - ), - }; - // failed - const errorResponse = { - data: { - results: [ - {}, - {}, - { - id: "some id", - code: "some code", - message: "some error message", - errors: { - [`records[5].Customer`]: { - messages: ["key is missing"], - }, - }, - }, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - ], - }, - status: 500, - statusText: "Internal Server Error", - headers: { - "X-Some-Header": "error", - }, - }; - beforeEach(async () => { - mockClient.mockResponse(mockResponse); - mockClient.mockResponse(new KintoneRestAPIError(errorResponse)); - }); - it("should raise an KintoneAllRecordsError if an error occurs during bulkRequest", async () => { - await expect( - recordClient.updateAllRecords(params), - ).rejects.toBeInstanceOf(KintoneAllRecordsError); - }); - }); - }); - - describe("deleteAllRecords", () => { - const params = { - app: APP_ID, - records: Array.from({ length: 3000 }, (_, index) => index + 1).map( - (value) => ({ - id: value, - revision: 1, - }), - ), - }; - let response: any; - describe("success", () => { - const mockResponse = { - results: Array.from({ length: 20 }, () => ({})), - }; - const mockResponse2 = { - results: Array.from({ length: 10 }, () => ({})), - }; - beforeEach(async () => { - // response from first call of bulkRequest.send - mockClient.mockResponse(mockResponse); - // response from second call of bulkRequest.send - mockClient.mockResponse(mockResponse2); - response = await recordClient.deleteAllRecords(params); - }); - it("should call bulkRequest multiple times", () => { - expect(mockClient.getLogs().length).toBe(2); - }); - - it("should return an empty object", () => { - expect(response).toStrictEqual({}); - }); - }); - - describe("response error", () => { - // success - const mockResponse = { - results: Array.from({ length: 20 }, () => ({})), - }; - // failed - const errorResponse = { - data: { - results: [ - {}, - {}, - { - id: "some id", - code: "some code", - message: "some error message", - }, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - ], - }, - status: 500, - statusText: "Internal Server Error", - headers: { - "X-Some-Header": "error", - }, - }; - beforeEach(async () => { - mockClient.mockResponse(mockResponse); - mockClient.mockResponse(new KintoneRestAPIError(errorResponse)); - }); - it("should raise an KintoneAllRecordsError if an error occurs during bulkRequest", async () => { - await expect( - recordClient.deleteAllRecords(params), - ).rejects.toBeInstanceOf(KintoneAllRecordsError); - }); - }); - }); - - describe("addRecordComment", () => { - const params = { - app: APP_ID, - record: RECORD_ID, - comment: { - text: "hello", - mentions: [ - { - code: "Administrator", - type: "USER" as const, - }, - ], - }, - }; - beforeEach(async () => { - await recordClient.addRecordComment(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/record/comment.json"); - }); - it("should send a post request", () => { - expect(mockClient.getLogs()[0].method).toBe("post"); - }); - it("should pass app, record and comment to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("deleteRecordComment", () => { - const params = { - app: APP_ID, - record: RECORD_ID, - comment: "1", - }; - beforeEach(async () => { - await recordClient.deleteRecordComment(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/record/comment.json"); - }); - it("should send a delete request", () => { - expect(mockClient.getLogs()[0].method).toBe("delete"); - }); - it("should pass app, record and comment to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("getRecordComments", () => { - const params = { - app: APP_ID, - record: RECORD_ID, - order: "desc" as const, - offset: 5, - limit: 5, - }; - beforeEach(async () => { - await recordClient.getRecordComments(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/record/comments.json"); - }); - it("should send a get request", () => { - expect(mockClient.getLogs()[0].method).toBe("get"); - }); - it("should pass app, record, order, offset and limit to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("updateRecordAssignees", () => { - const params = { - app: APP_ID, - id: RECORD_ID, - assignees: ["user1"], - revision: 10, - }; - beforeEach(async () => { - await recordClient.updateRecordAssignees(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/record/assignees.json"); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app, id, assignees, and revision to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("updateRecordStatus", () => { - const params = { - action: "Action1", - app: APP_ID, - assignee: "user1", - id: RECORD_ID, - revision: 10, - }; - beforeEach(async () => { - await recordClient.updateRecordStatus(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/record/status.json"); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass action, app, assignee, id, and revision to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); - - describe("updateRecordsStatus", () => { - const params = { - app: APP_ID, - records: [ - { - action: "Action1", - assignee: "user1", - id: RECORD_ID, - revision: 10, - }, - ], - }; - beforeEach(async () => { - await recordClient.updateRecordsStatus(params); - }); - it("should pass the path to the http client", () => { - expect(mockClient.getLogs()[0].path).toBe("/k/v1/records/status.json"); - }); - it("should send a put request", () => { - expect(mockClient.getLogs()[0].method).toBe("put"); - }); - it("should pass app and records to the http client", () => { - expect(mockClient.getLogs()[0].params).toEqual(params); - }); - }); -}); +import { APP_ID, makeClients, RECORD_ID } from "./fixtures/RecordClientFixture"; describe("RecordClient with guestSpaceId", () => { it("should pass the path to the http client", async () => { - const APP_ID = 1; - const RECORD_ID = 2; const GUEST_SPACE_ID = 3; - const requestConfigBuilder = new KintoneRequestConfigBuilder({ - baseUrl: "https://example.cybozu.com", - auth: { type: "session" }, - }); - const mockClient = buildMockClient(requestConfigBuilder); - const bulkRequestClient = new BulkRequestClient(mockClient); - const recordClient = new RecordClient( - mockClient, - bulkRequestClient, - GUEST_SPACE_ID, - ); + const clients = makeClients(GUEST_SPACE_ID); + const recordClient = clients.recordClient; + const mockClient = clients.mockClient; + const params = { app: APP_ID, id: RECORD_ID }; await recordClient.getRecord(params); expect(mockClient.getLogs()[0].path).toBe( diff --git a/packages/rest-api-client/src/client/__tests__/app/Acl.test.ts b/packages/rest-api-client/src/client/__tests__/app/Acl.test.ts new file mode 100644 index 0000000000..e7fff41e82 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/app/Acl.test.ts @@ -0,0 +1,231 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { AppClient } from "../../AppClient"; +import { APP_ID, makeClients, REVISION } from "../fixtures/AppClientFixture"; + +const RECORD_ID = 3; + +describe("Acl", () => { + let mockClient: MockClient; + let appClient: AppClient; + + beforeEach(() => { + const clients = makeClients(); + appClient = clients.appClient; + mockClient = clients.mockClient; + }); + + describe("getFieldAcl", () => { + const params = { + app: APP_ID, + }; + beforeEach(async () => { + await appClient.getFieldAcl(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/field/acl.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("updateFieldAcl", () => { + const params = { + app: APP_ID, + rights: [ + { + code: "foo", + entities: [ + { + accessibility: "READ" as const, + entity: { + code: "bar", + type: "USER" as const, + }, + }, + ], + }, + ], + }; + + beforeEach(async () => { + await appClient.updateFieldAcl(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/preview/field/acl.json"); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app and rights as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("getRecordAcl", () => { + const lang = "default"; + const params = { + app: APP_ID, + lang, + } as const; + describe("without preview", () => { + beforeEach(async () => { + await appClient.getRecordAcl(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/record/acl.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("preview: true", () => { + beforeEach(async () => { + await appClient.getRecordAcl({ ...params, preview: true }); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/record/acl.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); + + describe("updateRecordAcl", () => { + const params = { + app: APP_ID, + rights: [ + { + filterCond: 'field = "foo"', + entities: [ + { + entity: { + code: "bar", + type: "USER" as const, + }, + viewable: false, + editable: false, + deletable: false, + includeSubs: true, + }, + ], + }, + ], + revision: REVISION, + }; + beforeEach(async () => { + await appClient.updateRecordAcl(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/record/acl.json", + ); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app, right and revision as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("getAppAcl", () => { + const params = { + app: APP_ID, + }; + describe("without preview", () => { + beforeEach(async () => { + await appClient.getAppAcl(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/acl.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("preview: true", () => { + beforeEach(async () => { + await appClient.getAppAcl({ ...params, preview: true }); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/preview/app/acl.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and preview as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); + + describe("updateAppAcl", () => { + const params = { + app: APP_ID, + rights: [ + { + entity: { + type: "USER" as const, + code: "foo", + }, + appEditable: true, + recordViewable: true, + recordAddable: true, + recordEditable: true, + recordDeletable: true, + recordImportable: true, + recordExportable: true, + }, + ], + }; + beforeEach(async () => { + await appClient.updateAppAcl(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/preview/app/acl.json"); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app and rights as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("evaluateRecordsAcl", () => { + const params = { + app: APP_ID, + ids: [RECORD_ID], + }; + beforeEach(async () => { + await appClient.evaluateRecordsAcl(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/records/acl/evaluate.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and ids as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/app/Actions.test.ts b/packages/rest-api-client/src/client/__tests__/app/Actions.test.ts new file mode 100644 index 0000000000..5e166f1b43 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/app/Actions.test.ts @@ -0,0 +1,103 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { AppClient } from "../../AppClient"; +import { APP_ID, makeClients } from "../fixtures/AppClientFixture"; + +describe("Actions", () => { + let mockClient: MockClient; + let appClient: AppClient; + + beforeEach(() => { + const clients = makeClients(); + appClient = clients.appClient; + mockClient = clients.mockClient; + }); + + describe("getAppActions", () => { + const lang = "default"; + const params = { app: APP_ID, lang } as const; + describe("without preview", () => { + beforeEach(async () => { + await appClient.getAppActions(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/actions.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("preview: true", () => { + beforeEach(async () => { + await appClient.getAppActions({ + ...params, + preview: true, + }); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/actions.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); + + describe("updateAppActions", () => { + const params = { + app: APP_ID, + actions: { + Action_A: { + name: "Action_A", + index: "0", + destApp: { + code: "INVOICE", + }, + mappings: [ + { + srcType: "FIELD" as const, + srcField: "CompanyName", + destField: "CompanyName", + }, + { + srcType: "FIELD" as const, + srcField: "DivisionName", + destField: "DivisionName", + }, + { + srcType: "RECORD_URL" as const, + destField: "URL", + }, + ], + entities: [ + { + type: "USER" as const, + code: "Administrator", + }, + ], + }, + }, + }; + beforeEach(async () => { + await appClient.updateAppActions(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/actions.json", + ); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app and actions as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/app/App.test.ts b/packages/rest-api-client/src/client/__tests__/app/App.test.ts new file mode 100644 index 0000000000..7b51a0af07 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/app/App.test.ts @@ -0,0 +1,115 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { AppClient } from "../../AppClient"; +import { APP_ID, makeClients } from "../fixtures/AppClientFixture"; + +describe("App Test", () => { + let mockClient: MockClient; + let appClient: AppClient; + + beforeEach(() => { + const clients = makeClients(); + appClient = clients.appClient; + mockClient = clients.mockClient; + }); + + describe("getApp", () => { + const params = { + id: APP_ID, + }; + beforeEach(async () => { + await appClient.getApp(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/app.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass id as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("getApps", () => { + const params = { + ids: [APP_ID], + codes: ["APP"], + name: "app", + spaceIds: [1, 2], + limit: 100, + offset: 30, + }; + beforeEach(async () => { + await appClient.getApps(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/apps.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass ids, codes, name, spaceIds, limit, and offset as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("addApp", () => { + describe("without space", () => { + const params = { + name: "app", + }; + beforeEach(async () => { + await appClient.addApp(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/preview/app.json"); + }); + it("should send a post request", () => { + expect(mockClient.getLogs()[0].method).toBe("post"); + }); + it("should pass name, space, and thread as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("with space", () => { + const params = { + name: "app", + space: 10, + }; + const defaultThread = 20; + beforeEach(async () => { + mockClient.mockResponse({ defaultThread }); + await appClient.addApp(params); + }); + it("should fetch the default thread of the space", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/space.json"); + expect(mockClient.getLogs()[0].method).toBe("get"); + expect(mockClient.getLogs()[0].params).toEqual({ id: params.space }); + }); + it("should add new app into the default thread", () => { + expect(mockClient.getLogs()[1].path).toBe("/k/v1/preview/app.json"); + expect(mockClient.getLogs()[1].method).toBe("post"); + expect(mockClient.getLogs()[1].params).toEqual({ + ...params, + thread: defaultThread, + }); + }); + }); + }); + + describe("move", () => { + const params = { app: APP_ID, space: 1 } as const; + beforeEach(async () => { + await appClient.move(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/move.json"); + }); + it("should send a post request", () => { + expect(mockClient.getLogs()[0].method).toBe("post"); + }); + it("should pass app and space as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/app/AppCustomize.test.ts b/packages/rest-api-client/src/client/__tests__/app/AppCustomize.test.ts new file mode 100644 index 0000000000..591cd00d07 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/app/AppCustomize.test.ts @@ -0,0 +1,90 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { AppClient } from "../../AppClient"; +import { APP_ID, makeClients, REVISION } from "../fixtures/AppClientFixture"; + +describe("AppCustomize", () => { + let mockClient: MockClient; + let appClient: AppClient; + + beforeEach(() => { + const clients = makeClients(); + appClient = clients.appClient; + mockClient = clients.mockClient; + }); + + describe("getAppCustomize", () => { + const params = { app: APP_ID }; + describe("without preview", () => { + beforeEach(async () => { + await appClient.getAppCustomize(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/customize.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("preview: true", () => { + beforeEach(async () => { + await appClient.getAppCustomize({ ...params, preview: true }); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/customize.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and preview as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); + + describe("updateAppCustomize", () => { + const resource = { + js: [ + { + type: "URL" as const, + url: "https://www.example.com/example-mobile.js", + }, + ], + css: [ + { + type: "FILE" as const, + file: { + fileKey: "ddfc8e89-7aa3-4350-b9ab-3a75c9cf46b3", + }, + }, + ], + }; + const params = { + app: APP_ID, + scope: "ALL" as const, + desktop: resource, + mobile: resource, + revision: REVISION, + }; + describe("customize resources are specified", () => { + beforeEach(async () => { + await appClient.updateAppCustomize(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/customize.json", + ); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app, scope, desktop, mobile and revision as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/app/AppSettings.test.ts b/packages/rest-api-client/src/client/__tests__/app/AppSettings.test.ts new file mode 100644 index 0000000000..28d68da55e --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/app/AppSettings.test.ts @@ -0,0 +1,79 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { AppClient } from "../../AppClient"; +import { APP_ID, makeClients, REVISION } from "../fixtures/AppClientFixture"; + +describe("AppSettings", () => { + let mockClient: MockClient; + let appClient: AppClient; + + beforeEach(() => { + const clients = makeClients(); + appClient = clients.appClient; + mockClient = clients.mockClient; + }); + + describe("getAppSettings", () => { + const lang = "default"; + const params = { app: APP_ID, lang } as const; + describe("without preview", () => { + beforeEach(async () => { + await appClient.getAppSettings(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/settings.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("preview: true", () => { + beforeEach(async () => { + await appClient.getAppSettings({ ...params, preview: true }); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/settings.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); + + describe("updateAppSettings", () => { + const params = { + app: APP_ID, + revision: REVISION, + name: "test app", + description: "
Description
", + icon: { + type: "FILE" as const, + file: { + fileKey: "file key", + }, + }, + theme: "WHITE" as const, + }; + beforeEach(async () => { + await appClient.updateAppSettings(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/settings.json", + ); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app, name, description, icon, theme and revision to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/app/Deploy.test.ts b/packages/rest-api-client/src/client/__tests__/app/Deploy.test.ts new file mode 100644 index 0000000000..073e436f22 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/app/Deploy.test.ts @@ -0,0 +1,55 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { AppClient } from "../../AppClient"; +import { APP_ID, makeClients, REVISION } from "../fixtures/AppClientFixture"; + +describe("Deploy", () => { + let mockClient: MockClient; + let appClient: AppClient; + + beforeEach(() => { + const clients = makeClients(); + appClient = clients.appClient; + mockClient = clients.mockClient; + }); + + describe("getDeployStatus", () => { + const params = { + apps: [APP_ID], + }; + beforeEach(async () => { + await appClient.getDeployStatus(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/deploy.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass apps as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("deployApp", () => { + const params = { + apps: [{ app: APP_ID, revision: REVISION }], + revert: true, + }; + beforeEach(async () => { + await appClient.deployApp(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/deploy.json", + ); + }); + it("should send a post request", () => { + expect(mockClient.getLogs()[0].method).toBe("post"); + }); + it("should pass apps and revert as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/app/FormField.test.ts b/packages/rest-api-client/src/client/__tests__/app/FormField.test.ts new file mode 100644 index 0000000000..fe8d9de53e --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/app/FormField.test.ts @@ -0,0 +1,112 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { AppClient } from "../../AppClient"; +import { APP_ID, makeClients, REVISION } from "../fixtures/AppClientFixture"; + +const properties = { + fieldCode: { + type: "SINGLE_LINE_TEXT" as const, + code: "fieldCode", + label: "Text Field", + }, +}; + +describe("FormField Test", () => { + let appClient: AppClient; + let mockClient: MockClient; + + beforeEach(() => { + const clients = makeClients(); + appClient = clients.appClient; + mockClient = clients.mockClient; + }); + + describe("getFormFields", () => { + const lang = "default"; + const params = { app: APP_ID, lang } as const; + describe("without preview", () => { + beforeEach(async () => { + await appClient.getFormFields(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/form/fields.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("preview: true", () => { + beforeEach(async () => { + await appClient.getFormFields({ ...params, preview: true }); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/form/fields.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); + + describe("addFormFields", () => { + const params = { app: APP_ID, properties, revision: REVISION }; + beforeEach(async () => { + await appClient.addFormFields(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/form/fields.json", + ); + }); + it("should send a post request", () => { + expect(mockClient.getLogs()[0].method).toBe("post"); + }); + it("should pass app, properties and revision as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("updateFormFields", () => { + const params = { app: APP_ID, properties, revision: REVISION }; + beforeEach(async () => { + await appClient.updateFormFields(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/form/fields.json", + ); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app, properties and revision to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("deleteFormFields", () => { + const fields = ["fieldCode1", "fieldCode2"]; + const params = { app: APP_ID, fields, revision: REVISION }; + beforeEach(async () => { + await appClient.deleteFormFields(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/form/fields.json", + ); + }); + it("should send a delete request", () => { + expect(mockClient.getLogs()[0].method).toBe("delete"); + }); + it("should pass app, fields, and revision to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/app/FormLayout.test.ts b/packages/rest-api-client/src/client/__tests__/app/FormLayout.test.ts new file mode 100644 index 0000000000..5d8df6c666 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/app/FormLayout.test.ts @@ -0,0 +1,119 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { AppClient } from "../../AppClient"; +import { APP_ID, makeClients, REVISION } from "../fixtures/AppClientFixture"; + +const layout = [ + { + type: "ROW" as const, + fields: [ + { + type: "SINGLE_LINE_TEXT", + code: "fieldCode1", + size: { width: "100" }, + }, + { + type: "LABEL", + label: "label1", + size: { width: "100" }, + }, + { + type: "SPACER", + elementId: "space", + size: { width: "100", height: "50" }, + }, + ], + }, + { + type: "SUBTABLE" as const, + code: "tableFieldCode", + fields: [ + { + type: "MULTI_LINE_TEXT", + code: "fieldCode2", + size: { width: "150", innerHeight: "200" }, + }, + ], + }, + { + type: "GROUP" as const, + code: "fieldCode3", + layout: [ + { + type: "ROW" as const, + fields: [ + { + type: "NUMBER", + code: "fieldCode3_1", + size: { + width: 200, + }, + }, + ], + }, + ], + }, +]; + +describe("FormLayout Test", () => { + let mockClient: MockClient; + let appClient: AppClient; + + beforeEach(() => { + const clients = makeClients(); + appClient = clients.appClient; + mockClient = clients.mockClient; + }); + + describe("getFormLayout", () => { + const params = { app: APP_ID }; + describe("without preview", () => { + beforeEach(async () => { + await appClient.getFormLayout(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/form/layout.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("preview: true", () => { + beforeEach(async () => { + await appClient.getFormLayout({ ...params, preview: true }); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/form/layout.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); + + describe("updateFormLayout", () => { + const params = { app: APP_ID, layout, revision: REVISION }; + + beforeEach(async () => { + await appClient.updateFormLayout(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/form/layout.json", + ); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app, layout and revision to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/app/Notifications.test.ts b/packages/rest-api-client/src/client/__tests__/app/Notifications.test.ts new file mode 100644 index 0000000000..6e4a23aca6 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/app/Notifications.test.ts @@ -0,0 +1,262 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { AppClient } from "../../AppClient"; +import { APP_ID, makeClients } from "../fixtures/AppClientFixture"; + +describe("RecordNotification", () => { + let mockClient: MockClient; + let appClient: AppClient; + + beforeEach(() => { + const clients = makeClients(); + appClient = clients.appClient; + mockClient = clients.mockClient; + }); + + describe("getPerRecordNotifications", () => { + const params = { + app: APP_ID, + }; + describe("without preview", () => { + beforeEach(async () => { + await appClient.getPerRecordNotifications(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/app/notifications/perRecord.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("preview: true", () => { + beforeEach(async () => { + await appClient.getPerRecordNotifications({ ...params, preview: true }); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/notifications/perRecord.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and preview as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); + + describe("getGeneralNotifications", () => { + const params = { + app: APP_ID, + }; + describe("without preview", () => { + beforeEach(async () => { + await appClient.getGeneralNotifications(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/app/notifications/general.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("preview: true", () => { + beforeEach(async () => { + await appClient.getGeneralNotifications({ ...params, preview: true }); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/notifications/general.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and preview as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); + + describe("updateReminderNotifications", () => { + const params = { + app: 1, + notifications: [ + { + timing: { + code: "CREATED_TIME", + daysLater: "1", + hoursLater: "2", + }, + filterCond: 'CREATED_TIME in ("user1)', + title: "test title1", + targets: [ + { + entity: { + type: "USER", + code: "user1", + } as const, + includeSubs: false, + }, + ], + }, + { + timing: { + code: "CREATED_TIME", + daysLater: "-3", + time: "08:30", + }, + filterCond: 'CREATED_TIME in ("user1")', + title: "test title2", + targets: [ + { + entity: { + type: "USER", + code: "user1", + } as const, + includeSubs: false, + }, + ], + }, + ], + timezone: "Asia/Tokyo", + revision: "2", + }; + beforeEach(async () => { + await appClient.updateReminderNotifications(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/notifications/reminder.json", + ); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app and rights as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("updatePerRecordNotifications", () => { + const params = { + app: APP_ID, + notifications: [ + { + filterCond: 'Customer = "foo"', + title: "Send a notification", + targets: [ + { + entity: { + type: "USER" as const, + code: "foo", + }, + includeSubs: false, + }, + ], + }, + ], + revision: 1, + }; + + beforeEach(async () => { + await appClient.updatePerRecordNotifications(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/notifications/perRecord.json", + ); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app and rights as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("getAppNotificationsReminder", () => { + const lang = "default"; + const params = { app: APP_ID, lang } as const; + describe("without preview", () => { + beforeEach(async () => { + await appClient.getReminderNotifications(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/app/notifications/reminder.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("preview: true", () => { + beforeEach(async () => { + await appClient.getReminderNotifications({ + ...params, + preview: true, + }); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/notifications/reminder.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); + describe("updateAppUpdateGeneralNotifications", () => { + const params = { + app: APP_ID, + notifications: [ + { + entity: { + type: "USER" as const, + code: "foo", + }, + includeSubs: true, + recordAdded: true, + recordEdited: true, + commentAdded: true, + statusChanged: true, + fileImported: true, + }, + ], + notifyToCommenter: true, + revision: 1, + }; + beforeEach(async () => { + await appClient.updateGeneralNotifications(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/notifications/general.json", + ); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app and rights as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/app/Plugins.test.ts b/packages/rest-api-client/src/client/__tests__/app/Plugins.test.ts new file mode 100644 index 0000000000..a3d3fc9fdc --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/app/Plugins.test.ts @@ -0,0 +1,52 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { AppClient } from "../../AppClient"; +import { APP_ID, makeClients } from "../fixtures/AppClientFixture"; + +describe("AppClient: plugins", () => { + let mockClient: MockClient; + let appClient: AppClient; + + beforeEach(() => { + const clients = makeClients(); + appClient = clients.appClient; + mockClient = clients.mockClient; + }); + + describe("getPlugins", () => { + const params = { app: APP_ID, lang: "en" } as const; + describe("without preview", () => { + beforeEach(async () => { + await appClient.getPlugins(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/plugins.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("preview: true", () => { + beforeEach(async () => { + await appClient.getPlugins({ + ...params, + preview: true, + }); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/plugins.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/app/ProcessManagement.test.ts b/packages/rest-api-client/src/client/__tests__/app/ProcessManagement.test.ts new file mode 100644 index 0000000000..d8d21145dc --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/app/ProcessManagement.test.ts @@ -0,0 +1,115 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { AppClient } from "../../AppClient"; +import { APP_ID, makeClients, REVISION } from "../fixtures/AppClientFixture"; + +const states = { + status1: { + name: "status1", + index: 0, + assignee: { + type: "ONE" as const, + entities: [ + { entity: { type: "FIELD_ENTITY" as const, code: "creator" } }, + ], + }, + }, + status2: { + name: "status2", + index: 1, + assignee: { + type: "ANY" as const, + entities: [{ entity: { type: "CREATOR" as const } }], + }, + }, + status3: { + name: "status3", + index: 2, + assignee: { + type: "ALL" as const, + entities: [ + { entity: { type: "USER" as const, code: "user1" } }, + { entity: { type: "USER" as const, code: "user2" } }, + ], + }, + }, +}; + +const actions = [ + { name: "action1to2", from: "status1", to: "status2" }, + { + name: "action2to3", + from: "status2", + to: "status3", + filterCond: 'field = "foo"', + }, +]; + +describe("ProcessManagement", () => { + let mockClient: MockClient; + let appClient: AppClient; + + beforeEach(() => { + const clients = makeClients(); + appClient = clients.appClient; + mockClient = clients.mockClient; + }); + + describe("getProcessManagement", () => { + const lang = "default"; + const params = { app: APP_ID, lang } as const; + describe("without preview", () => { + beforeEach(async () => { + await appClient.getProcessManagement(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/status.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("preview: true", () => { + beforeEach(async () => { + await appClient.getProcessManagement({ ...params, preview: true }); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/status.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); + + describe("updateProcessManagement", () => { + const params = { + app: APP_ID, + revision: REVISION, + enable: true, + states, + actions, + }; + beforeEach(async () => { + await appClient.updateProcessManagement(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/status.json", + ); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app, states, actions and revision to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/app/Reports.test.ts b/packages/rest-api-client/src/client/__tests__/app/Reports.test.ts new file mode 100644 index 0000000000..d8756d4359 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/app/Reports.test.ts @@ -0,0 +1,106 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { AppClient } from "../../AppClient"; +import { APP_ID, makeClients } from "../fixtures/AppClientFixture"; + +describe("Reports", () => { + let mockClient: MockClient; + let appClient: AppClient; + + beforeEach(() => { + const clients = makeClients(); + appClient = clients.appClient; + mockClient = clients.mockClient; + }); + + describe("getReports", () => { + const lang = "default"; + const params = { app: APP_ID, lang } as const; + describe("without preview", () => { + beforeEach(async () => { + await appClient.getReports(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/reports.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("preview: true", () => { + beforeEach(async () => { + await appClient.getReports({ + ...params, + preview: true, + }); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/reports.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); + + describe("updateReports", () => { + const params = { + app: 1, + reports: { + "Graph 1": { + chartType: "BAR" as const, + chartMode: "NORMAL" as const, + name: "Graph 1", + index: 0, + groups: [ + { + code: "Radio_button", + }, + ], + aggregations: [ + { + type: "COUNT" as const, + }, + ], + filterCond: "", + sorts: [ + { + by: "TOTAL" as const, + order: "DESC" as const, + }, + ], + periodicReport: { + active: true, + period: { + every: "QUARTER" as const, + pattern: "JAN_APR_JUL_OCT" as const, + dayOfMonth: "END_OF_MONTH" as const, + time: "23:30", + }, + }, + }, + }, + }; + beforeEach(async () => { + await appClient.updateReports(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/reports.json", + ); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app and rights as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/app/Views.test.ts b/packages/rest-api-client/src/client/__tests__/app/Views.test.ts new file mode 100644 index 0000000000..281c396638 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/app/Views.test.ts @@ -0,0 +1,92 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { AppClient } from "../../AppClient"; +import { APP_ID, makeClients, REVISION } from "../fixtures/AppClientFixture"; + +const views = { + view1: { + type: "LIST" as const, + index: 0, + name: "view1", + fields: ["field"], + filterCond: 'field = "foo"', + sort: "sortField desc", + }, + view2: { + type: "CALENDAR" as const, + index: 1, + name: "view2", + date: "dateField", + title: "titleField", + filterCond: 'field = "bar"', + sort: "sortField asc", + }, + view3: { + type: "CUSTOM" as const, + index: 2, + name: "view3", + html: "
Hello!
", + pager: true, + device: "DESKTOP" as const, + }, +}; + +describe("Views Test", () => { + let mockClient: MockClient; + let appClient: AppClient; + + beforeEach(() => { + const clients = makeClients(); + appClient = clients.appClient; + mockClient = clients.mockClient; + }); + describe("getViews", () => { + const lang = "default"; + const params = { app: APP_ID, lang } as const; + describe("without preview", () => { + beforeEach(async () => { + await appClient.getViews(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/app/views.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("preview: true", () => { + beforeEach(async () => { + await appClient.getViews({ ...params, preview: true }); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe( + "/k/v1/preview/app/views.json", + ); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and lang as a param to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + }); + + describe("updateViews", () => { + const params = { app: APP_ID, views, revision: REVISION }; + beforeEach(async () => { + await appClient.updateViews(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/preview/app/views.json"); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app, views and revision to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/fixtures/AppClientFixture.ts b/packages/rest-api-client/src/client/__tests__/fixtures/AppClientFixture.ts new file mode 100644 index 0000000000..77151130a4 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/fixtures/AppClientFixture.ts @@ -0,0 +1,20 @@ +import { buildMockClient } from "../../../http/MockClient"; +import { KintoneRequestConfigBuilder } from "../../../KintoneRequestConfigBuilder"; +import { AppClient } from "../../AppClient"; +import type { SpaceID } from "../../types"; + +export const makeClients = (guestSpaceId?: SpaceID) => { + const requestConfigBuilder = new KintoneRequestConfigBuilder({ + baseUrl: "https://example.cybozu.com", + auth: { type: "apiToken", apiToken: "foo" }, + }); + const mockClient = buildMockClient(requestConfigBuilder); + const appClient = new AppClient(mockClient, guestSpaceId); + return { + appClient: appClient, + mockClient: mockClient, + }; +}; + +export const APP_ID = 1; +export const REVISION = 5; diff --git a/packages/rest-api-client/src/client/__tests__/fixtures/RecordClientFixture.ts b/packages/rest-api-client/src/client/__tests__/fixtures/RecordClientFixture.ts new file mode 100644 index 0000000000..49ef362185 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/fixtures/RecordClientFixture.ts @@ -0,0 +1,34 @@ +import { buildMockClient } from "../../../http/MockClient"; +import { KintoneRequestConfigBuilder } from "../../../KintoneRequestConfigBuilder"; +import { BulkRequestClient } from "../../BulkRequestClient"; +import { RecordClient } from "../../RecordClient"; +import type { SpaceID } from "../../types"; + +export const makeClients = (guestSpaceId?: SpaceID) => { + const requestConfigBuilder = new KintoneRequestConfigBuilder({ + baseUrl: "https://example.cybozu.com", + auth: { type: "apiToken", apiToken: "foo" }, + }); + const mockClient = buildMockClient(requestConfigBuilder); + const bulkRequestClient = new BulkRequestClient(mockClient); + const recordClient = new RecordClient( + mockClient, + bulkRequestClient, + guestSpaceId, + ); + + return { + recordClient: recordClient, + mockClient: mockClient, + }; +}; + +export const APP_ID = 1; +export const RECORD_ID = 2; + +export const fieldCode = "Customer"; +export const record = { + [fieldCode]: { + value: "ABC Corporation", + }, +}; diff --git a/packages/rest-api-client/src/client/__tests__/record/AllRecords.test.ts b/packages/rest-api-client/src/client/__tests__/record/AllRecords.test.ts new file mode 100644 index 0000000000..70d207f0b7 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/record/AllRecords.test.ts @@ -0,0 +1,821 @@ +import { KintoneAllRecordsError, KintoneRestAPIError } from "../../../error"; +import type { MockClient } from "../../../http/MockClient"; +import type { RecordClient } from "../../RecordClient"; +import type { Record } from "../../types"; +import { + APP_ID, + fieldCode, + makeClients, +} from "../fixtures/RecordClientFixture"; + +describe("AllRecordsTest", () => { + let mockClient: MockClient; + let recordClient: RecordClient; + + beforeEach(() => { + const clients = makeClients(); + recordClient = clients.recordClient; + mockClient = clients.mockClient; + }); + + describe("getAllRecordsWithId", () => { + describe("success with condition", () => { + it("should do nothing if `fields` is not specified", async () => { + const params = { + app: APP_ID, + condition: `${fieldCode} = "foo"`, + }; + mockClient.mockResponse({ records: [] }); + await recordClient.getAllRecordsWithId(params); + expect(mockClient.getLogs()[0].params.fields).toBe(undefined); + }); + + it("should do nothing if `fields` is empty", async () => { + const params = { + app: APP_ID, + fields: [], + condition: `${fieldCode} = "foo"`, + }; + mockClient.mockResponse({ records: [] }); + await recordClient.getAllRecordsWithId(params); + expect(mockClient.getLogs()[0].params.fields).toEqual([]); + }); + + it("should append `$id` if `fields` is specified and doesn't contain `$id`", async () => { + const params = { + app: APP_ID, + fields: [fieldCode], + condition: `${fieldCode} = "foo"`, + }; + mockClient.mockResponse({ records: [] }); + await recordClient.getAllRecordsWithId(params); + expect(mockClient.getLogs()[0].params.fields.sort()).toEqual( + [...params.fields, "$id"].sort(), + ); + }); + + it("should do nothing if `fields` is specified and contains `$id`", async () => { + const params = { + app: APP_ID, + fields: ["$id", fieldCode], + condition: `${fieldCode} = "foo"`, + }; + mockClient.mockResponse({ records: [] }); + await recordClient.getAllRecordsWithId(params); + expect(mockClient.getLogs()[0].params.fields).toEqual(params.fields); + }); + }); + + describe("success with condition", () => { + const params = { + app: APP_ID, + fields: ["$id"], + condition: `${fieldCode} = "foo"`, + }; + let result: Record[]; + + beforeEach(async () => { + const records = []; + for (let i = 1; i <= 500; i++) { + records.push({ + $id: { + type: "__ID__", + value: i.toString(), + }, + }); + } + mockClient.mockResponse({ records }); + mockClient.mockResponse({ + records: [{ $id: { type: "__ID__", value: "501" } }], + }); + result = await recordClient.getAllRecordsWithId(params); + }); + + it("should return all records", () => { + expect(mockClient.getLogs()[0]).toEqual({ + path: "/k/v1/records.json", + method: "get", + params: { + app: params.app, + fields: params.fields, + query: `(${params.condition}) and $id > 0 order by $id asc limit 500`, + }, + }); + expect(mockClient.getLogs()[1]).toEqual({ + path: "/k/v1/records.json", + method: "get", + params: { + app: params.app, + fields: params.fields, + query: `(${params.condition}) and $id > 500 order by $id asc limit 500`, + }, + }); + + expect(result.length).toBe(501); + expect(result[500]).toStrictEqual({ + $id: { type: "__ID__", value: "501" }, + }); + }); + }); + + describe("success without condition", () => { + const params = { + app: APP_ID, + fields: ["$id"], + }; + let result: Record[]; + + beforeEach(async () => { + const records = []; + for (let i = 1; i <= 500; i++) { + records.push({ + $id: { + type: "__ID__", + value: i.toString(), + }, + }); + } + mockClient.mockResponse({ records }); + mockClient.mockResponse({ + records: [{ $id: { type: "__ID__", value: "501" } }], + }); + result = await recordClient.getAllRecordsWithId(params); + }); + + it("should return all records", () => { + expect(mockClient.getLogs()[0]).toEqual({ + path: "/k/v1/records.json", + method: "get", + params: { + app: params.app, + fields: params.fields, + query: "$id > 0 order by $id asc limit 500", + }, + }); + expect(mockClient.getLogs()[1]).toEqual({ + path: "/k/v1/records.json", + method: "get", + params: { + app: params.app, + fields: params.fields, + query: "$id > 500 order by $id asc limit 500", + }, + }); + + expect(result.length).toBe(501); + expect(result[500]).toStrictEqual({ + $id: { type: "__ID__", value: "501" }, + }); + }); + }); + + describe("error in missing $id", () => { + it("should throw error when missing $id in `getRecords` response.", async () => { + const records: Record[] = []; + for (let i = 1; i < 500; i++) { + records.push({ + $id: { + type: "__ID__", + value: i.toString(), + }, + }); + } + records.push({ + $id: { + type: "RECORD_NUMBER", + value: "2", + }, + }); + mockClient.mockResponse({ records }); + const params = { + app: APP_ID, + }; + + await expect(recordClient.getAllRecordsWithId(params)).rejects.toThrow( + "Missing `$id` in `getRecords` response. This error is likely caused by a bug in Kintone REST API Client. Please file an issue.", + ); + }); + }); + }); + + describe("getAllRecordsWithOffset", () => { + describe("condition and orderBy parameters", () => { + it("with condition and orderBy", async () => { + const params = { + app: APP_ID, + condition: `${fieldCode} = "foo"`, + orderBy: `${fieldCode} asc`, + }; + mockClient.mockResponse({ records: [] }); + await recordClient.getAllRecordsWithOffset(params); + expect(mockClient.getLogs()[0].params.query).toBe( + `${fieldCode} = "foo" order by ${fieldCode} asc limit 500 offset 0`, + ); + }); + + it("with condition, without orderBy", async () => { + const params = { + app: APP_ID, + condition: `${fieldCode} = "foo"`, + }; + mockClient.mockResponse({ records: [] }); + await recordClient.getAllRecordsWithOffset(params); + expect(mockClient.getLogs()[0].params.query).toBe( + `${fieldCode} = "foo" limit 500 offset 0`, + ); + }); + + it("without condition, with orderBy", async () => { + const params = { + app: APP_ID, + orderBy: `${fieldCode} asc`, + }; + mockClient.mockResponse({ records: [] }); + await recordClient.getAllRecordsWithOffset(params); + expect(mockClient.getLogs()[0].params.query).toBe( + `order by ${fieldCode} asc limit 500 offset 0`, + ); + }); + + it("neither condition nor orderBy", async () => { + const params = { + app: APP_ID, + }; + mockClient.mockResponse({ records: [] }); + await recordClient.getAllRecordsWithOffset(params); + expect(mockClient.getLogs()[0].params.query).toBe("limit 500 offset 0"); + }); + }); + + describe("success", () => { + const params = { + app: APP_ID, + fields: ["$id"], + condition: `${fieldCode} = "foo"`, + }; + let result: Record[]; + + beforeEach(async () => { + const records = []; + for (let i = 1; i <= 500; i++) { + records.push({ + $id: { + type: "__ID__", + value: i.toString(), + }, + }); + } + mockClient.mockResponse({ records }); + mockClient.mockResponse({ + records: [{ $id: { type: "__ID__", value: "501" } }], + }); + result = await recordClient.getAllRecordsWithOffset(params); + }); + + it("should return all records", () => { + expect(mockClient.getLogs()[0]).toEqual({ + path: "/k/v1/records.json", + method: "get", + params: { + app: params.app, + fields: params.fields, + query: `${params.condition} limit 500 offset 0`, + }, + }); + expect(mockClient.getLogs()[1]).toEqual({ + path: "/k/v1/records.json", + method: "get", + params: { + app: params.app, + fields: params.fields, + query: `${params.condition} limit 500 offset 500`, + }, + }); + + expect(result.length).toBe(501); + expect(result[500]).toStrictEqual({ + $id: { type: "__ID__", value: "501" }, + }); + }); + }); + }); + + describe("getAllRecords", () => { + describe("`orderBy` is specified", () => { + const params = { + app: APP_ID, + condition: `${fieldCode} = "foo"`, + orderBy: `${fieldCode} asc`, + }; + let withCursorMockFn: jest.Mock; + let withOffsetMockFn: jest.Mock; + beforeEach(() => { + withCursorMockFn = jest.fn(); + withOffsetMockFn = jest.fn(); + recordClient.getAllRecordsWithCursor = withCursorMockFn; + recordClient.getAllRecordsWithOffset = withOffsetMockFn; + }); + it("should call `getAllRecordsWithCursor` if `withCursor` is not specified", async () => { + await recordClient.getAllRecords({ ...params }); + expect(withCursorMockFn.mock.calls.length).toBe(1); + expect(withCursorMockFn.mock.calls[0][0]).toStrictEqual({ + app: params.app, + query: `${params.condition} order by ${params.orderBy}`, + }); + }); + it("should call `getAllRecordsWithCursor` if `withCursor` is true", async () => { + await recordClient.getAllRecords({ ...params, withCursor: true }); + expect(withCursorMockFn.mock.calls.length).toBe(1); + expect(withCursorMockFn.mock.calls[0][0]).toStrictEqual({ + app: params.app, + query: `${params.condition} order by ${params.orderBy}`, + }); + }); + it("should call `getAllRecordsWithOffset` if `withCursor` is false", async () => { + await recordClient.getAllRecords({ ...params, withCursor: false }); + expect(withOffsetMockFn.mock.calls.length).toBe(1); + expect(withOffsetMockFn.mock.calls[0][0]).toStrictEqual(params); + }); + }); + + describe("`orderBy` is an empty string", () => { + const params = { + app: APP_ID, + condition: `${fieldCode} = "foo"`, + orderBy: "", + }; + const { orderBy, ...expected } = params; + let mockFn: jest.Mock; + beforeEach(() => { + mockFn = jest.fn(); + recordClient.getAllRecordsWithId = mockFn; + }); + it("should call `getAllRecordsWithId` if `withCursor` is not specified", async () => { + await recordClient.getAllRecords(params); + expect(mockFn.mock.calls.length).toBe(1); + expect(mockFn.mock.calls[0][0]).toStrictEqual(expected); + }); + it("should call `getAllRecordsWithId` if `withCursor` is true", async () => { + await recordClient.getAllRecords({ ...params, withCursor: true }); + expect(mockFn.mock.calls.length).toBe(1); + expect(mockFn.mock.calls[0][0]).toStrictEqual(expected); + }); + it("should call `getAllRecordsWithId` if `withCursor` is false", async () => { + await recordClient.getAllRecords({ ...params, withCursor: false }); + expect(mockFn.mock.calls.length).toBe(1); + expect(mockFn.mock.calls[0][0]).toStrictEqual(expected); + }); + }); + describe("`orderBy` is not specified", () => { + const params = { + app: APP_ID, + condition: `${fieldCode} = "foo"`, + }; + let mockFn: jest.Mock; + beforeEach(() => { + mockFn = jest.fn(); + recordClient.getAllRecordsWithId = mockFn; + }); + it("should call `getAllRecordsWithId` if `withCursor` is not specified", async () => { + await recordClient.getAllRecords(params); + expect(mockFn.mock.calls.length).toBe(1); + expect(mockFn.mock.calls[0][0]).toStrictEqual(params); + }); + it("should call `getAllRecordsWithId` if `withCursor` is true", async () => { + await recordClient.getAllRecords({ ...params, withCursor: true }); + expect(mockFn.mock.calls.length).toBe(1); + expect(mockFn.mock.calls[0][0]).toStrictEqual(params); + }); + it("should call `getAllRecordsWithId` if `withCursor` is false", async () => { + await recordClient.getAllRecords({ ...params, withCursor: false }); + expect(mockFn.mock.calls.length).toBe(1); + expect(mockFn.mock.calls[0][0]).toStrictEqual(params); + }); + }); + }); + + describe("getAllRecordsWithCursor", () => { + const params = { + app: APP_ID, + fields: [fieldCode], + query: `${fieldCode} = "foo"`, + }; + const CURSOR_ID = "1"; + let result: Record[]; + + describe("success", () => { + beforeEach(async () => { + // response from createCursor + mockClient.mockResponse({ id: CURSOR_ID, totalCount: "4" }); + // response from getRecordsByCursor + mockClient.mockResponse({ + records: [ + { $id: { type: "__ID__", value: "1" } }, + { $id: { type: "__ID__", value: "2" } }, + ], + next: true, + }); + mockClient.mockResponse({ + records: [ + { $id: { type: "__ID__", value: "3" } }, + { $id: { type: "__ID__", value: "4" } }, + ], + next: false, + }); + result = await recordClient.getAllRecordsWithCursor(params); + }); + + it("should create a cursor", () => { + expect(mockClient.getLogs()[0]).toEqual({ + path: "/k/v1/records/cursor.json", + method: "post", + params, + }); + }); + + it("should return all records", () => { + expect(mockClient.getLogs()[1]).toEqual({ + path: "/k/v1/records/cursor.json", + method: "get", + params: { id: CURSOR_ID }, + }); + expect(mockClient.getLogs()[2]).toEqual({ + path: "/k/v1/records/cursor.json", + method: "get", + params: { id: CURSOR_ID }, + }); + expect(result).toStrictEqual([ + { $id: { type: "__ID__", value: "1" } }, + { $id: { type: "__ID__", value: "2" } }, + { $id: { type: "__ID__", value: "3" } }, + { $id: { type: "__ID__", value: "4" } }, + ]); + }); + + it("should not call deleteCursor", () => { + expect(mockClient.getLogs().length).toEqual(3); + }); + }); + + describe("failure", () => { + beforeEach(() => { + // response from createCursor + mockClient.mockResponse({ id: CURSOR_ID, totalCount: "4" }); + // response from getRecordsByCursor + mockClient.mockResponse({ + records: [{ id: 1 }, { id: 2 }], + next: true, + }); + mockClient.mockResponse(new Error("failed")); + }); + + it("should raise error", async () => { + await expect( + recordClient.getAllRecordsWithCursor(params), + ).rejects.toThrow("failed"); + expect(mockClient.getLogs()[3]).toStrictEqual({ + path: "/k/v1/records/cursor.json", + method: "delete", + params: { id: CURSOR_ID }, + }); + }); + }); + }); + + describe("addAllRecords", () => { + const params = { + app: APP_ID, + records: Array.from({ length: 3000 }, (_, index) => index + 1).map( + (value) => ({ + [fieldCode]: { + value, + }, + }), + ), + }; + let response: any; + describe("success", () => { + const mockResponse = { + results: Array.from({ length: 20 }, (_, index) => index + 1).map( + () => ({ + ids: Array.from({ length: 100 }, (_, index) => index + 1), + revisions: Array.from({ length: 100 }, () => 1), + }), + ), + }; + const mockResponse2 = { + results: Array.from({ length: 10 }, (_, index) => index + 1).map( + () => ({ + ids: Array.from({ length: 100 }, (_, index) => index + 1), + revisions: Array.from({ length: 100 }, () => 1), + }), + ), + }; + beforeEach(async () => { + // response from first call of bulkRequest.send + mockClient.mockResponse(mockResponse); + // response from second call of bulkRequest.send + mockClient.mockResponse(mockResponse2); + response = await recordClient.addAllRecords(params); + }); + it("should call bulkRequest multiple times", () => { + expect(mockClient.getLogs().length).toBe(2); + }); + + it("should return merged result of each bulkRequest's result", () => { + const accumulateResponse = ( + acc: Array<{ id: number; revision: number }>, + { ids, revisions }: { ids: number[]; revisions: number[] }, + ) => + acc.concat( + ids.map((id, index) => ({ + id, + revision: revisions[index], + })), + ); + + const expected = [ + ...mockResponse.results.reduce(accumulateResponse, []), + ...mockResponse2.results.reduce(accumulateResponse, []), + ]; + expect(response.records).toStrictEqual(expected); + }); + }); + + describe("parameter error", () => { + it("should raise an Error if `records` parameter is not an array", async () => { + const invalidParams: any = { + app: APP_ID, + records: Array.from({ length: 3000 }, (_, index) => index + 1).map( + (value) => { + if (value === 1000) { + return value; + } + return { + [fieldCode]: { + value, + }, + }; + }, + ), + }; + await expect(recordClient.addAllRecords(invalidParams)).rejects.toThrow( + "the `records` parameter must be an array of object.", + ); + }); + }); + describe("response error", () => { + // success + const mockResponse = { + results: Array.from({ length: 20 }, (_, index) => index + 1).map( + () => ({ + ids: Array.from({ length: 100 }, (_, index) => index + 1), + revisions: Array.from({ length: 100 }, () => 1), + }), + ), + }; + // failed + const errorResponse = { + data: { + results: [ + {}, + {}, + { + id: "some id", + code: "some code", + message: "some error message", + errors: { + [`records[5].Customer`]: { + messages: ["key is missing"], + }, + }, + }, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + ], + }, + status: 500, + statusText: "Internal Server Error", + headers: { + "X-Some-Header": "error", + }, + }; + beforeEach(async () => { + mockClient.mockResponse(mockResponse); + mockClient.mockResponse(new KintoneRestAPIError(errorResponse)); + }); + it("should raise an KintoneAllRecordsError if an error occurs during bulkRequest", async () => { + await expect(recordClient.addAllRecords(params)).rejects.toBeInstanceOf( + KintoneAllRecordsError, + ); + }); + }); + }); + + describe("updateAllRecords", () => { + const params = { + app: APP_ID, + records: Array.from({ length: 3000 }, (_, index) => index + 1).map( + (value) => ({ + id: value, + record: { + [fieldCode]: { + value: `${fieldCode}-${value}`, + }, + }, + revision: 1, + }), + ), + }; + let response: any; + describe("success", () => { + const mockResponse = { + results: Array.from({ length: 20 }, (_, index) => index).map( + (value) => ({ + records: Array.from({ length: 100 }, (_, index) => + String(value * 100 + index + 1), + ).map((id) => ({ + id, + revision: "2", + })), + }), + ), + }; + const mockResponse2 = { + results: Array.from({ length: 10 }, (_, index) => index).map( + (value) => ({ + records: Array.from({ length: 100 }, (_, index) => + String(2000 + value * 100 + index + 1), + ).map((id) => ({ + id, + revision: "2", + })), + }), + ), + }; + beforeEach(async () => { + // response from first call of bulkRequest.send + mockClient.mockResponse(mockResponse); + // response from second call of bulkRequest.send + mockClient.mockResponse(mockResponse2); + response = await recordClient.updateAllRecords(params); + }); + it("should call bulkRequest multiple times", () => { + expect(mockClient.getLogs().length).toBe(2); + }); + + it("should return merged result of each bulkRequest's result", () => { + const accumulateResponse = ( + acc: Array<{ id: string; revision: string }>, + result: { records: Array<{ id: string; revision: string }> }, + ) => { + return acc.concat(result.records); + }; + + const expected = [ + ...mockResponse.results, + ...mockResponse2.results, + ].reduce(accumulateResponse, []); + expect(response.records).toStrictEqual(expected); + }); + }); + + describe("response error", () => { + // success + const mockResponse = { + results: Array.from({ length: 20 }, (_, index) => index).map( + (value) => ({ + records: Array.from({ length: 100 }, (_, index) => + String(value * 100 + index + 1), + ).map((id) => ({ + id, + revision: "2", + })), + }), + ), + }; + // failed + const errorResponse = { + data: { + results: [ + {}, + {}, + { + id: "some id", + code: "some code", + message: "some error message", + errors: { + [`records[5].Customer`]: { + messages: ["key is missing"], + }, + }, + }, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + ], + }, + status: 500, + statusText: "Internal Server Error", + headers: { + "X-Some-Header": "error", + }, + }; + beforeEach(async () => { + mockClient.mockResponse(mockResponse); + mockClient.mockResponse(new KintoneRestAPIError(errorResponse)); + }); + it("should raise an KintoneAllRecordsError if an error occurs during bulkRequest", async () => { + await expect( + recordClient.updateAllRecords(params), + ).rejects.toBeInstanceOf(KintoneAllRecordsError); + }); + }); + }); + + describe("deleteAllRecords", () => { + const params = { + app: APP_ID, + records: Array.from({ length: 3000 }, (_, index) => index + 1).map( + (value) => ({ + id: value, + revision: 1, + }), + ), + }; + let response: any; + describe("success", () => { + const mockResponse = { + results: Array.from({ length: 20 }, () => ({})), + }; + const mockResponse2 = { + results: Array.from({ length: 10 }, () => ({})), + }; + beforeEach(async () => { + // response from first call of bulkRequest.send + mockClient.mockResponse(mockResponse); + // response from second call of bulkRequest.send + mockClient.mockResponse(mockResponse2); + response = await recordClient.deleteAllRecords(params); + }); + it("should call bulkRequest multiple times", () => { + expect(mockClient.getLogs().length).toBe(2); + }); + + it("should return an empty object", () => { + expect(response).toStrictEqual({}); + }); + }); + + describe("response error", () => { + // success + const mockResponse = { + results: Array.from({ length: 20 }, () => ({})), + }; + // failed + const errorResponse = { + data: { + results: [ + {}, + {}, + { + id: "some id", + code: "some code", + message: "some error message", + }, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + ], + }, + status: 500, + statusText: "Internal Server Error", + headers: { + "X-Some-Header": "error", + }, + }; + beforeEach(async () => { + mockClient.mockResponse(mockResponse); + mockClient.mockResponse(new KintoneRestAPIError(errorResponse)); + }); + it("should raise an KintoneAllRecordsError if an error occurs during bulkRequest", async () => { + await expect( + recordClient.deleteAllRecords(params), + ).rejects.toBeInstanceOf(KintoneAllRecordsError); + }); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/record/Cursor.test.ts b/packages/rest-api-client/src/client/__tests__/record/Cursor.test.ts new file mode 100644 index 0000000000..32eb9f8727 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/record/Cursor.test.ts @@ -0,0 +1,75 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { RecordClient } from "../../RecordClient"; +import { + APP_ID, + fieldCode, + makeClients, +} from "../fixtures/RecordClientFixture"; + +describe("CursorTest", () => { + let mockClient: MockClient; + let recordClient: RecordClient; + + beforeEach(() => { + const clients = makeClients(); + recordClient = clients.recordClient; + mockClient = clients.mockClient; + }); + + describe("createCursor", () => { + const params = { + app: APP_ID, + fields: [fieldCode], + query: `${fieldCode} = "foo"`, + size: 10, + }; + beforeEach(async () => { + await recordClient.createCursor(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/records/cursor.json"); + }); + it("should send a post request", () => { + expect(mockClient.getLogs()[0].method).toBe("post"); + }); + it("should pass app, fields, query, and size to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("getRecordsByCursor", () => { + const params = { + id: "cursor id", + }; + beforeEach(async () => { + await recordClient.getRecordsByCursor(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/records/cursor.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass id to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("deleteCursor", () => { + const params = { + id: "cursor id", + }; + beforeEach(async () => { + await recordClient.deleteCursor(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/records/cursor.json"); + }); + it("should send a delete request", () => { + expect(mockClient.getLogs()[0].method).toBe("delete"); + }); + it("should pass id to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/record/Record.test.ts b/packages/rest-api-client/src/client/__tests__/record/Record.test.ts new file mode 100644 index 0000000000..4b18f7b725 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/record/Record.test.ts @@ -0,0 +1,338 @@ +import type { MockClient } from "../../../http/MockClient"; +import { BulkRequestClient } from "../../BulkRequestClient"; +import { RecordClient } from "../../RecordClient"; +import { + APP_ID, + fieldCode, + makeClients, + record, + RECORD_ID, +} from "../fixtures/RecordClientFixture"; + +describe("RecordTest", () => { + let mockClient: MockClient; + let recordClient: RecordClient; + + beforeEach(() => { + const clients = makeClients(); + recordClient = clients.recordClient; + mockClient = clients.mockClient; + }); + + describe("getRecord", () => { + const params = { app: APP_ID, id: RECORD_ID }; + beforeEach(async () => { + await recordClient.getRecord(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/record.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app and id to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("addRecord", () => { + const params = { app: APP_ID, record }; + beforeEach(async () => { + await recordClient.addRecord(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/record.json"); + }); + it("should send a post request", () => { + expect(mockClient.getLogs()[0].method).toBe("post"); + }); + it("should pass app and record object to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("updateRecord", () => { + const params = { + app: APP_ID, + id: RECORD_ID, + record, + revision: 5, + }; + beforeEach(async () => { + await recordClient.updateRecord(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/record.json"); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app, id, record, and revision to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("upsertRecord", () => { + describe("update", () => { + const params = { + app: APP_ID, + updateKey: { + field: "Code", + value: "foo", + }, + record, + revision: 5, + }; + let getRecordsMockFn: jest.Mock; + let updateRecordMockFn: jest.Mock; + let addRecordMockFn: jest.Mock; + beforeEach(async () => { + getRecordsMockFn = jest.fn().mockResolvedValue({ + records: [ + { + $id: { + type: "__ID__", + value: "10", + }, + }, + ], + }); + updateRecordMockFn = jest.fn().mockResolvedValue({ + revision: "2", + }); + addRecordMockFn = jest.fn(); + const bulkRequestClient = new BulkRequestClient(mockClient); + recordClient = new RecordClient(mockClient, bulkRequestClient); + recordClient.getRecords = getRecordsMockFn; + recordClient.updateRecord = updateRecordMockFn; + recordClient.addRecord = addRecordMockFn; + }); + + it("should call getRecords with a query built with udpateKey", async () => { + await recordClient.upsertRecord(params); + expect(getRecordsMockFn.mock.calls.length).toBe(1); + expect(getRecordsMockFn.mock.calls[0][0]).toEqual({ + app: params.app, + query: `${params.updateKey.field} = "${params.updateKey.value}"`, + }); + }); + it("should call updateRecord with the params", async () => { + await recordClient.upsertRecord(params); + expect(updateRecordMockFn.mock.calls.length).toBe(1); + expect(updateRecordMockFn.mock.calls[0][0]).toEqual(params); + }); + it("should not call addRecord", async () => { + await recordClient.upsertRecord(params); + expect(addRecordMockFn.mock.calls.length).toBe(0); + }); + it("should return id and revision properties", async () => { + const result = await recordClient.upsertRecord(params); + expect(result).toEqual({ + id: "10", + revision: "2", + }); + }); + }); + describe("insert", () => { + const params = { + app: APP_ID, + updateKey: { + field: "Customer", + value: "foo", + }, + record, + revision: 5, + }; + let getRecordsMockFn: jest.Mock; + let updateRecordMockFn: jest.Mock; + let addRecordMockFn: jest.Mock; + beforeEach(() => { + getRecordsMockFn = jest.fn().mockResolvedValue({ + records: [], + }); + updateRecordMockFn = jest.fn(); + addRecordMockFn = jest.fn().mockResolvedValue({ + id: "10", + revision: "1", + }); + const bulkRequestClient = new BulkRequestClient(mockClient); + recordClient = new RecordClient(mockClient, bulkRequestClient); + recordClient.getRecords = getRecordsMockFn; + recordClient.updateRecord = updateRecordMockFn; + recordClient.addRecord = addRecordMockFn; + }); + + it("should call getRecords with a query built with udpateKey", async () => { + await recordClient.upsertRecord(params); + expect(getRecordsMockFn.mock.calls.length).toBe(1); + expect(getRecordsMockFn.mock.calls[0][0]).toEqual({ + app: params.app, + query: `${params.updateKey.field} = "${params.updateKey.value}"`, + }); + }); + it("should call addRecord with the params", async () => { + await recordClient.upsertRecord(params); + expect(addRecordMockFn.mock.calls.length).toBe(1); + expect(addRecordMockFn.mock.calls[0][0]).toEqual({ + app: params.app, + record: { + ...params.record, + [params.updateKey.field]: { value: params.updateKey.value }, + }, + }); + }); + it("should not call updateRecord", async () => { + await recordClient.upsertRecord(params); + expect(updateRecordMockFn.mock.calls.length).toBe(0); + }); + it("should return id and revision properties", async () => { + const result = await recordClient.upsertRecord(params); + expect(result).toEqual({ + id: "10", + revision: "1", + }); + }); + }); + }); + + describe("getRecords", () => { + describe("without offset", () => { + const params = { + app: APP_ID, + fields: [fieldCode], + query: `${fieldCode} = "foo"`, + totalCount: true, + }; + beforeEach(async () => { + await recordClient.getRecords(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/records.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app, fields, query and totalCount to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + describe("with offset", () => { + let consoleWarnMock: jest.SpyInstance; + beforeEach(() => { + consoleWarnMock = jest.spyOn(console, "warn"); + consoleWarnMock.mockImplementation((x) => x); + }); + describe("offset <= 10000", () => { + const params = { + app: APP_ID, + fields: [fieldCode], + query: `${fieldCode} = "foo" offset 10000`, + totalCount: true, + }; + it("doesn't output any message to the console", async () => { + await recordClient.getRecords(params); + expect(consoleWarnMock.mock.calls.length).toBe(0); + }); + }); + describe("offset > 10000", () => { + const params = { + app: APP_ID, + fields: [fieldCode], + query: `${fieldCode} = "foo" offset 10001`, + totalCount: true, + }; + it("outputs a message to the console only once when the request succeeds", async () => { + await recordClient.getRecords(params); + await recordClient.getRecords(params); + expect(consoleWarnMock.mock.calls.length).toBe(1); + }); + it("doesn't output any message to the console when the request fails", async () => { + expect.assertions(1); + mockClient.mockResponse(new Error("failed")); + try { + await recordClient.getRecords(params); + } catch { + expect(consoleWarnMock.mock.calls.length).toBe(0); + } + }); + }); + afterEach(() => { + consoleWarnMock.mockReset(); + consoleWarnMock.mockRestore(); + }); + }); + }); + + describe("addRecords", () => { + const params = { app: APP_ID, records: [record] }; + const mockResponse = { + ids: ["10", "20", "30"], + revisions: ["1", "2", "3"], + }; + let response: any; + beforeEach(async () => { + mockClient.mockResponse(mockResponse); + response = await recordClient.addRecords(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/records.json"); + }); + it("should send a post request", () => { + expect(mockClient.getLogs()[0].method).toBe("post"); + }); + it("should pass app and records to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + it("should return a response having ids, revisions, and records", () => { + expect(response).toEqual({ + ...mockResponse, + records: [ + { id: "10", revision: "1" }, + { id: "20", revision: "2" }, + { id: "30", revision: "3" }, + ], + }); + }); + }); + + describe("updateRecords", () => { + const params = { + app: APP_ID, + records: [{ id: RECORD_ID, record, revision: 5 }], + }; + beforeEach(async () => { + await recordClient.updateRecords(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/records.json"); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app, id, record, and revision to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("deleteRecords", () => { + const ids = [10, 20, 30]; + const revisions = [1, 2, 3]; + const params = { + app: APP_ID, + ids, + revisions, + }; + beforeEach(async () => { + await recordClient.deleteRecords(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/records.json"); + }); + it("should send a delete request", () => { + expect(mockClient.getLogs()[0].method).toBe("delete"); + }); + it("should pass app, ids, and revisions to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/record/RecordAssignees.test.ts b/packages/rest-api-client/src/client/__tests__/record/RecordAssignees.test.ts new file mode 100644 index 0000000000..333fc68981 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/record/RecordAssignees.test.ts @@ -0,0 +1,39 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { RecordClient } from "../../RecordClient"; +import { + APP_ID, + makeClients, + RECORD_ID, +} from "../fixtures/RecordClientFixture"; + +describe("RecordAssigneesTest", () => { + let mockClient: MockClient; + let recordClient: RecordClient; + + beforeEach(() => { + const clients = makeClients(); + recordClient = clients.recordClient; + mockClient = clients.mockClient; + }); + + describe("updateRecordAssignees", () => { + const params = { + app: APP_ID, + id: RECORD_ID, + assignees: ["user1"], + revision: 10, + }; + beforeEach(async () => { + await recordClient.updateRecordAssignees(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/record/assignees.json"); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app, id, assignees, and revision to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/record/RecordComment.test.ts b/packages/rest-api-client/src/client/__tests__/record/RecordComment.test.ts new file mode 100644 index 0000000000..ca7bc29f38 --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/record/RecordComment.test.ts @@ -0,0 +1,88 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { RecordClient } from "../../RecordClient"; +import { + APP_ID, + makeClients, + RECORD_ID, +} from "../fixtures/RecordClientFixture"; + +describe("RecordComment", () => { + let mockClient: MockClient; + let recordClient: RecordClient; + + beforeEach(() => { + const clients = makeClients(); + recordClient = clients.recordClient; + mockClient = clients.mockClient; + }); + + describe("addRecordComment", () => { + const params = { + app: APP_ID, + record: RECORD_ID, + comment: { + text: "hello", + mentions: [ + { + code: "Administrator", + type: "USER" as const, + }, + ], + }, + }; + beforeEach(async () => { + await recordClient.addRecordComment(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/record/comment.json"); + }); + it("should send a post request", () => { + expect(mockClient.getLogs()[0].method).toBe("post"); + }); + it("should pass app, record and comment to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("deleteRecordComment", () => { + const params = { + app: APP_ID, + record: RECORD_ID, + comment: "1", + }; + beforeEach(async () => { + await recordClient.deleteRecordComment(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/record/comment.json"); + }); + it("should send a delete request", () => { + expect(mockClient.getLogs()[0].method).toBe("delete"); + }); + it("should pass app, record and comment to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("getRecordComments", () => { + const params = { + app: APP_ID, + record: RECORD_ID, + order: "desc" as const, + offset: 5, + limit: 5, + }; + beforeEach(async () => { + await recordClient.getRecordComments(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/record/comments.json"); + }); + it("should send a get request", () => { + expect(mockClient.getLogs()[0].method).toBe("get"); + }); + it("should pass app, record, order, offset and limit to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +}); diff --git a/packages/rest-api-client/src/client/__tests__/record/RecordStatus.test.ts b/packages/rest-api-client/src/client/__tests__/record/RecordStatus.test.ts new file mode 100644 index 0000000000..4be75cc07f --- /dev/null +++ b/packages/rest-api-client/src/client/__tests__/record/RecordStatus.test.ts @@ -0,0 +1,66 @@ +import type { MockClient } from "../../../http/MockClient"; +import type { RecordClient } from "../../RecordClient"; +import { + APP_ID, + makeClients, + RECORD_ID, +} from "../fixtures/RecordClientFixture"; + +describe("RecordStatusTest", () => { + let mockClient: MockClient; + let recordClient: RecordClient; + + beforeEach(() => { + const clients = makeClients(); + recordClient = clients.recordClient; + mockClient = clients.mockClient; + }); + + describe("updateRecordStatus", () => { + const params = { + action: "Action1", + app: APP_ID, + assignee: "user1", + id: RECORD_ID, + revision: 10, + }; + beforeEach(async () => { + await recordClient.updateRecordStatus(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/record/status.json"); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass action, app, assignee, id, and revision to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); + + describe("updateRecordsStatus", () => { + const params = { + app: APP_ID, + records: [ + { + action: "Action1", + assignee: "user1", + id: RECORD_ID, + revision: 10, + }, + ], + }; + beforeEach(async () => { + await recordClient.updateRecordsStatus(params); + }); + it("should pass the path to the http client", () => { + expect(mockClient.getLogs()[0].path).toBe("/k/v1/records/status.json"); + }); + it("should send a put request", () => { + expect(mockClient.getLogs()[0].method).toBe("put"); + }); + it("should pass app and records to the http client", () => { + expect(mockClient.getLogs()[0].params).toEqual(params); + }); + }); +});