Add some more tests.

This commit is contained in:
Sam Rose 2024-09-09 17:51:32 +01:00
parent 5cd1b00dad
commit 1f405da3c3
No known key found for this signature in database
4 changed files with 126 additions and 35 deletions

View File

@ -53,7 +53,6 @@ export async function save(
builderSocket?.emitDatasourceUpdate(ctx, datasource) builderSocket?.emitDatasourceUpdate(ctx, datasource)
return table return table
} catch (err: any) { } catch (err: any) {
throw err
if (err instanceof Error) { if (err instanceof Error) {
ctx.throw(400, err.message) ctx.throw(400, err.message)
} else { } else {

View File

@ -378,6 +378,8 @@ export class GoogleSheetsIntegration implements DatasourcePlus {
return this.create({ sheet, row: json.body as Row }) return this.create({ sheet, row: json.body as Row })
case Operation.BULK_CREATE: case Operation.BULK_CREATE:
return this.createBulk({ sheet, rows: json.body as Row[] }) return this.createBulk({ sheet, rows: json.body as Row[] })
case Operation.BULK_UPSERT:
return this.createBulk({ sheet, rows: json.body as Row[] })
case Operation.READ: case Operation.READ:
return this.read({ ...json, sheet }) return this.read({ ...json, sheet })
case Operation.UPDATE: case Operation.UPDATE:
@ -557,32 +559,15 @@ export class GoogleSheetsIntegration implements DatasourcePlus {
} else { } else {
rows = await sheet.getRows() rows = await sheet.getRows()
} }
// this is a special case - need to handle the _id, it doesn't exist
// we cannot edit the returned structure from google, it does not have
// setter functions and is immutable, easier to update the filters
// to look for the _rowNumber property rather than rowNumber
if (query.filters?.equal) {
const idFilterKeys = Object.keys(query.filters.equal).filter(filter =>
filter.includes(GOOGLE_SHEETS_PRIMARY_KEY)
)
for (let idFilterKey of idFilterKeys) {
const id = query.filters.equal[idFilterKey]
delete query.filters.equal[idFilterKey]
query.filters.equal[`_${GOOGLE_SHEETS_PRIMARY_KEY}`] = id
}
}
if (hasFilters && query.paginate) { if (hasFilters && query.paginate) {
rows = rows.slice(offset, offset + limit) rows = rows.slice(offset, offset + limit)
} }
const headerValues = sheet.headerValues const headerValues = sheet.headerValues
let response = []
for (let row of rows) { let response = rows.map(row =>
response.push(
this.buildRowObject(headerValues, row.toObject(), row.rowNumber) this.buildRowObject(headerValues, row.toObject(), row.rowNumber)
) )
}
response = dataFilters.runQuery(response, query.filters || {}) response = dataFilters.runQuery(response, query.filters || {})
if (query.sort) { if (query.sort) {

View File

@ -104,11 +104,73 @@ describe("Google Sheets Integration", () => {
}) })
}) })
it.only("should be able to add a new row", async () => { it("should be able to add a new row", async () => {
await config.api.row.save(table._id!, { const row = await config.api.row.save(table._id!, {
name: "Test Contact", name: "Test Contact",
description: "original description", description: "original description",
}) })
expect(row.name).toEqual("Test Contact")
expect(row.description).toEqual("original description")
expect(mock.cell("A2")).toEqual("Test Contact")
expect(mock.cell("B2")).toEqual("original description")
const row2 = await config.api.row.save(table._id!, {
name: "Test Contact 2",
description: "original description 2",
})
expect(row2.name).toEqual("Test Contact 2")
expect(row2.description).toEqual("original description 2")
// Notable that adding a new row adds it at the top, not the bottom. Not
// entirely sure if this is the intended behaviour or an incorrect
// implementation of the GoogleSheetsMock.
expect(mock.cell("A2")).toEqual("Test Contact 2")
expect(mock.cell("B2")).toEqual("original description 2")
expect(mock.cell("A3")).toEqual("Test Contact")
expect(mock.cell("B3")).toEqual("original description")
})
it("should be able to add multiple rows", async () => {
await config.api.row.bulkImport(table._id!, {
rows: [
{
name: "Test Contact 1",
description: "original description 1",
},
{
name: "Test Contact 2",
description: "original description 2",
},
],
})
expect(mock.cell("A2")).toEqual("Test Contact 1")
expect(mock.cell("B2")).toEqual("original description 1")
expect(mock.cell("A3")).toEqual("Test Contact 2")
expect(mock.cell("B3")).toEqual("original description 2")
})
it("should be able to update a row", async () => {
const row = await config.api.row.save(table._id!, {
name: "Test Contact",
description: "original description",
})
expect(mock.cell("A2")).toEqual("Test Contact")
expect(mock.cell("B2")).toEqual("original description")
await config.api.row.save(table._id!, {
...row,
name: "Test Contact Updated",
description: "original description updated",
})
expect(mock.cell("A2")).toEqual("Test Contact Updated")
expect(mock.cell("B2")).toEqual("original description updated")
}) })
}) })
}) })

View File

@ -175,6 +175,20 @@ interface AppendParams {
responseDateTimeRenderOption?: DateTimeRenderOption responseDateTimeRenderOption?: DateTimeRenderOption
} }
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/batchGet#query-parameters
interface BatchGetParams {
ranges: string[]
majorDimension?: Dimension
valueRenderOption?: ValueRenderOption
dateTimeRenderOption?: DateTimeRenderOption
}
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/batchGet#response-body
interface BatchGetResponse {
spreadsheetId: string
valueRanges: ValueRange[]
}
interface AppendRequest { interface AppendRequest {
range: string range: string
params: AppendParams params: AppendParams
@ -268,39 +282,57 @@ export class GoogleSheetsMock {
} }
private mockAPI() { private mockAPI() {
this.get(`/v4/spreadsheets/${this.config.spreadsheetId}/`, () => const spreadsheetId = this.config.spreadsheetId
this.get(`/v4/spreadsheets/${spreadsheetId}/`, () =>
this.handleGetSpreadsheet() this.handleGetSpreadsheet()
) )
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/batchUpdate // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/batchUpdate
this.post( this.post(
`/v4/spreadsheets/${this.config.spreadsheetId}/:batchUpdate`, `/v4/spreadsheets/${spreadsheetId}/:batchUpdate`,
(_uri, request) => this.handleBatchUpdate(request as BatchUpdateRequest) (_uri, request) => this.handleBatchUpdate(request as BatchUpdateRequest)
) )
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/update // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/update
this.put( this.put(
new RegExp(`/v4/spreadsheets/${this.config.spreadsheetId}/values/.*`), new RegExp(`/v4/spreadsheets/${spreadsheetId}/values/.*`),
(_uri, request) => this.handleValueUpdate(request as ValueRange) (_uri, request) => this.handleValueUpdate(request as ValueRange)
) )
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/get // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/batchGet
this.get( this.get(
new RegExp(`/v4/spreadsheets/${this.config.spreadsheetId}/values/.*`), new RegExp(`/v4/spreadsheets/${spreadsheetId}/values:batchGet.*`),
uri => { uri => {
const url = new URL(uri, "https://sheets.googleapis.com/")
const params: BatchGetParams = {
ranges: url.searchParams.getAll("ranges"),
majorDimension:
(url.searchParams.get("majorDimension") as Dimension) || "ROWS",
valueRenderOption:
(url.searchParams.get("valueRenderOption") as ValueRenderOption) ||
undefined,
dateTimeRenderOption:
(url.searchParams.get(
"dateTimeRenderOption"
) as DateTimeRenderOption) || undefined,
}
return this.handleBatchGet(params as unknown as BatchGetParams)
}
)
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/get
this.get(new RegExp(`/v4/spreadsheets/${spreadsheetId}/values/.*`), uri => {
const range = uri.split("/").pop() const range = uri.split("/").pop()
if (!range) { if (!range) {
throw new Error("No range provided") throw new Error("No range provided")
} }
return this.getValueRange(decodeURIComponent(range)) return this.getValueRange(decodeURIComponent(range))
} })
)
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/append // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/append
this.post( this.post(
new RegExp( new RegExp(`/v4/spreadsheets/${spreadsheetId}/values/.*:append`),
`/v4/spreadsheets/${this.config.spreadsheetId}/values/.*:append`
),
(_uri, request) => { (_uri, request) => {
const url = new URL(_uri, "https://sheets.googleapis.com/") const url = new URL(_uri, "https://sheets.googleapis.com/")
const params: Record<string, any> = Object.fromEntries( const params: Record<string, any> = Object.fromEntries(
@ -373,6 +405,19 @@ export class GoogleSheetsMock {
} }
} }
private handleBatchGet(params: BatchGetParams): BatchGetResponse {
const { ranges, majorDimension } = params
if (majorDimension && majorDimension !== "ROWS") {
throw new Error("Only row-major updates are supported")
}
return {
spreadsheetId: this.spreadsheet.spreadsheetId,
valueRanges: ranges.map(range => this.getValueRange(range)),
}
}
private handleBatchUpdate( private handleBatchUpdate(
batchUpdateRequest: BatchUpdateRequest batchUpdateRequest: BatchUpdateRequest
): BatchUpdateResponse { ): BatchUpdateResponse {