diff --git a/lib/__tests__/fileMapper.ts b/lib/__tests__/fileMapper.ts index 2d1301f9..a617fa62 100644 --- a/lib/__tests__/fileMapper.ts +++ b/lib/__tests__/fileMapper.ts @@ -13,7 +13,7 @@ import { download as __download, fetchFileStream as __fetchFileStream, } from '../../api/fileMapper'; -import folderWithoutSources from './fixtures/folderWithoutSources.json'; +import folderWithoutSources from './fixtures/fileMapper/folderWithoutSources.json'; jest.mock('../../api/fileMapper'); const utimesSpy = jest.spyOn(fs, 'utimes'); diff --git a/lib/__tests__/fixtures/folderWithoutSources.json b/lib/__tests__/fixtures/fileMapper/folderWithoutSources.json similarity index 100% rename from lib/__tests__/fixtures/folderWithoutSources.json rename to lib/__tests__/fixtures/fileMapper/folderWithoutSources.json diff --git a/lib/__tests__/fixtures/hubdb/createRowsResponse.json b/lib/__tests__/fixtures/hubdb/createRowsResponse.json new file mode 100644 index 00000000..127af5b2 --- /dev/null +++ b/lib/__tests__/fixtures/hubdb/createRowsResponse.json @@ -0,0 +1,32 @@ +{ + "status": "COMPLETE", + "results": [ + { + "name": "My Event", + "id": "string", + "createdAt": "string", + "updatedAt": "string", + "publishedAt": null, + "values": { "text_column": "a" }, + "path": null + }, + { + "name": "My Better Event", + "id": "string", + "createdAt": "string", + "updatedAt": "string", + "publishedAt": null, + "values": { "text_column": "b" }, + "path": null + }, + { + "name": "My Best Event", + "id": "string", + "createdAt": "string", + "updatedAt": "string", + "publishedAt": null, + "values": { "text_column": "c" }, + "path": null + } + ] +} diff --git a/lib/__tests__/fixtures/hubdb/fetchRowsResponse.json b/lib/__tests__/fixtures/hubdb/fetchRowsResponse.json new file mode 100644 index 00000000..89b5cc73 --- /dev/null +++ b/lib/__tests__/fixtures/hubdb/fetchRowsResponse.json @@ -0,0 +1,33 @@ +{ + "total": 3, + "results": [ + { + "name": "My Event", + "id": "string", + "createdAt": "string", + "updatedAt": "string", + "publishedAt": null, + "values": { "text_column": "a" }, + "path": null + }, + { + "name": "My Better Event", + "id": "string", + "createdAt": "string", + "updatedAt": "string", + "publishedAt": null, + "values": { "text_column": "b" }, + "path": null + }, + { + "name": "My Best Event", + "id": "string", + "createdAt": "string", + "updatedAt": "string", + "publishedAt": null, + "values": { "text_column": "c" }, + "path": null + } + ], + "paging": null +} diff --git a/lib/__tests__/fixtures/hubdb/fetchRowsResponseWithPaging.json b/lib/__tests__/fixtures/hubdb/fetchRowsResponseWithPaging.json new file mode 100644 index 00000000..ed6d2511 --- /dev/null +++ b/lib/__tests__/fixtures/hubdb/fetchRowsResponseWithPaging.json @@ -0,0 +1,37 @@ +{ + "total": 3, + "results": [ + { + "name": "Paging 1", + "id": "string", + "createdAt": "string", + "updatedAt": "string", + "publishedAt": null, + "values": { "text_column": "a" }, + "path": null + }, + { + "name": "Paging 2", + "id": "string", + "createdAt": "string", + "updatedAt": "string", + "publishedAt": null, + "values": { "text_column": "b" }, + "path": null + }, + { + "name": "Paging 3", + "id": "string", + "createdAt": "string", + "updatedAt": "string", + "publishedAt": null, + "values": { "text_column": "c" }, + "path": null + } + ], + "paging": { + "next": { + "after": "testing" + } + } +} diff --git a/lib/__tests__/fixtures/hubdb/tableResponse.json b/lib/__tests__/fixtures/hubdb/tableResponse.json new file mode 100644 index 00000000..96b2ec00 --- /dev/null +++ b/lib/__tests__/fixtures/hubdb/tableResponse.json @@ -0,0 +1,28 @@ +{ + "id": "cool-table-id", + "name": "cool-table-name", + "createdAt": "string", + "publishedAt": "string", + "updatedAt": "string", + "label": "string", + "allowChildTables": false, + "allowPublicApiAccess": false, + "columns": [ + { + "name": "first_col", + "label": "first_col", + "id": "col_1", + "type": "TEXT" + }, + { + "name": "second_col", + "label": "first_col", + "id": "col_2", + "type": "TEXT" + } + ], + "rowCount": 3, + "useForPages": false, + "enableChildTablePages": false, + "archived": false +} diff --git a/lib/__tests__/hubdb.ts b/lib/__tests__/hubdb.ts new file mode 100644 index 00000000..409c07dd --- /dev/null +++ b/lib/__tests__/hubdb.ts @@ -0,0 +1,121 @@ +import fs from 'fs-extra'; +import { + downloadHubDbTable, + createHubDbTable, + clearHubDbTableRows, +} from '../hubdb'; +import { + createRows as __createRows, + createTable as __createTable, + fetchRows as __fetchRows, + fetchTable as __fetchTable, + publishTable as __publishTable, +} from '../../api/hubdb'; +import { getCwd as __getCwd } from '../path'; +import hubdbFetchRowResponse from './fixtures/hubdb/fetchRowsResponse.json'; +import hubdbFetchRowsResponseWithPaging from './fixtures/hubdb/fetchRowsResponseWithPaging.json'; +import hubdbTableResponse from './fixtures/hubdb/tableResponse.json'; +import hubdbCreateRowsResponse from './fixtures/hubdb/createRowsResponse.json'; +import { Table } from '../../types/Hubdb'; + +jest.mock('fs-extra'); +jest.mock('../path'); +jest.mock('../../api/hubdb'); + +const mockedFS = fs as jest.Mocked; +const getCwd = __getCwd as jest.MockedFunction; +const createRows = __createRows as jest.MockedFunction; +const createTable = __createTable as jest.MockedFunction; +const fetchRows = __fetchRows as jest.MockedFunction; +const fetchTable = __fetchTable as jest.MockedFunction; +const publishTable = __publishTable as jest.MockedFunction< + typeof __publishTable +>; + +describe('hubdb', () => { + describe('downloadHubDbTable', () => { + const accountId = 123; + const tableId = '456'; + const destPath = 'tmp.json'; + const projectCwd = '/home/tom/projects'; + + beforeEach(() => { + mockedFS.outputFile.mockClear(); + getCwd.mockReturnValue(projectCwd); + fetchRows.mockReturnValue(Promise.resolve(hubdbFetchRowResponse)); + fetchTable.mockReturnValue(Promise.resolve(hubdbTableResponse)); + }); + + it('fetches all results', async () => { + const { filePath } = await downloadHubDbTable( + accountId, + tableId, + destPath + ); + const outputFile = JSON.parse( + mockedFS.outputFile.mock.calls[0][1] as string + ) as unknown as Table; + + if (!outputFile.rows) { + throw new Error('No rows found on the table object'); + } + + expect(outputFile.rows.length).toBe(3); + expect(outputFile.rows[1].name).toBe('My Better Event'); + expect(outputFile.rows[0].values['text_column']).toBe('a'); + expect(outputFile.name).toBe('cool-table-name'); + expect(filePath).toEqual(`${projectCwd}/${destPath}`); + }); + + it('fetches all results with paging', async () => { + fetchRows.mockReturnValueOnce( + Promise.resolve(hubdbFetchRowsResponseWithPaging) + ); + await downloadHubDbTable(accountId, tableId, destPath); + const outputFile = JSON.parse( + mockedFS.outputFile.mock.calls[0][1] as string + ) as unknown as Table; + + if (!outputFile.rows) { + throw new Error('No rows found on the table object'); + } + + expect(outputFile.rows.length).toEqual(6); + expect(outputFile.rows[0].name).toMatchInlineSnapshot(`"Paging 1"`); + expect(outputFile.rows[5].name).toMatchInlineSnapshot(`"My Best Event"`); + }); + }); + + describe('createHubDbTable', () => { + it('creates a table', async () => { + const accountId = 123; + const srcPath = 'tmp.json'; + const projectCwd = '/home/tom/projects'; + + mockedFS.statSync.mockReturnValue({ isFile: () => true } as fs.Stats); + mockedFS.readJsonSync.mockReturnValue(hubdbTableResponse); + + createTable.mockReturnValue(Promise.resolve(hubdbTableResponse)); + createRows.mockReturnValue(Promise.resolve(hubdbCreateRowsResponse)); + publishTable.mockReturnValue(Promise.resolve(hubdbTableResponse)); + + const table = await createHubDbTable( + accountId, + `${projectCwd}/${srcPath}` + ); + + expect(table.rowCount).toEqual(3); + expect(table.tableId).toEqual('cool-table-id'); + expect(publishTable).toBeCalled(); + }); + }); + + describe('clearHubDbTableRows', () => { + it('clears all of the hubdb table rows', async () => { + fetchRows.mockReturnValue(Promise.resolve(hubdbFetchRowResponse)); + const result = await clearHubDbTableRows(123, '456'); + + expect(result.deletedRowCount).toBe(3); + }); + }); +}); diff --git a/lib/hubdb.ts b/lib/hubdb.ts index 205cb796..f99ab263 100644 --- a/lib/hubdb.ts +++ b/lib/hubdb.ts @@ -22,7 +22,7 @@ function validateJsonPath(src: string): void { } function validateJsonFile(src: string): void { - let stats; + let stats: fs.Stats; try { stats = fs.statSync(src); @@ -40,7 +40,7 @@ function validateJsonFile(src: string): void { export async function addRowsToHubDbTable( accountId: number, tableId: string, - rows: Array + rows: Array = [] ): Promise<{ tableId: string; rowCount: number }> { const rowsToUpdate = rows.map(row => { const values = row.values; diff --git a/package.json b/package.json index ae055eba..827fe856 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "release:major": "yarn check-main && yarn version --major && yarn build && yarn pub && yarn push", "release:minor": "yarn check-main && yarn version --minor && yarn build && yarn pub && yarn push", "release:patch": "yarn check-main && yarn version --patch && yarn build && yarn pub && yarn push", - "test": "jest --silent" + "test": "node --experimental-vm-modules ./node_modules/.bin/jest" }, "license": "Apache-2.0", "devDependencies": { diff --git a/types/Hubdb.ts b/types/Hubdb.ts index abb4ec36..afd59675 100644 --- a/types/Hubdb.ts +++ b/types/Hubdb.ts @@ -11,22 +11,27 @@ export type Schema = { export type Table = { id: string; name: string; - portalId: number; + portalId?: number; createdAt: string; publishedAt: string; updatedAt: string; label: string; columns: Array; - rows: Array; - partitioningSettings?: null; //TODO - published: boolean; - cosObjectType: string; - updated: number; + rows?: Array; + partitioningSettings?: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + teamIds: Array; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + userIds: Array; + }; + published?: boolean; + cosObjectType?: string; + updated?: number; archived: boolean; - columnCount: number; - cdnPurgeEmbargoTime: number | null; + columnCount?: number; + cdnPurgeEmbargoTime?: number | null; rowCount: number; - createdBy: { + createdBy?: { id: string; email: string; firstName: string; @@ -35,16 +40,16 @@ export type Table = { useForPages: boolean; allowChildTables: boolean; enableChildTablePages: boolean; - crmObjectTypeId: number; - dynamicMetaTags?: null; //TODO + crmObjectTypeId?: number; + dynamicMetaTags?: { [key: string]: number }; allowPublicApiAccess: boolean; }; export type Column = { name: string; label: string; - id: string; - archived: boolean; + id?: string; + archived?: boolean; type: string; deleted?: boolean; foreignIdsByName?: { @@ -60,7 +65,12 @@ export type Row = { createdAt: string; updatedAt: string; publishedAt: string | null; - values: { text_column: string }; + values: { + text_column?: string; + number_column?: number; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + multiselect?: Array; + }; path: string | null; name: string | null; childTableId?: string; @@ -70,12 +80,14 @@ export type Row = { export type CreateRowsResponse = { status: string; results: Array; - startedAt: string; - completedAt: string; + startedAt?: string; + completedAt?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + links?: { [key: string]: any }; }; export type FetchRowsResponse = { total: number; results: Array; - paging?: { next: { after: string | null } }; + paging?: { next: { after: string | null } } | null; };