From 2055e86219132427b3f9ab14139b9a40b273628f Mon Sep 17 00:00:00 2001 From: Raju Udava <86527202+dstala@users.noreply.github.com> Date: Tue, 28 Mar 2023 13:32:14 +0530 Subject: [PATCH] test: bulk update webhook verification Signed-off-by: Raju Udava <86527202+dstala@users.noreply.github.com> --- tests/playwright/tests/01-webhook.spec.ts | 130 ++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/tests/playwright/tests/01-webhook.spec.ts b/tests/playwright/tests/01-webhook.spec.ts index e0a38d6c87..b311159bc8 100644 --- a/tests/playwright/tests/01-webhook.spec.ts +++ b/tests/playwright/tests/01-webhook.spec.ts @@ -4,8 +4,11 @@ import setup from '../setup'; import makeServer from '../setup/server'; import { WebhookFormPage } from '../pages/Dashboard/WebhookForm'; import { isSubset } from './utils/general'; +import { Api, UITypes } from 'nocodb-sdk'; +import { rowMixedValue } from '../setup/xcdb-records'; const hookPath = 'http://localhost:9090/hook'; +let api: Api; // clear server data async function clearServerData({ request }) { @@ -17,6 +20,23 @@ async function clearServerData({ request }) { await expect(await response.json()).toBe(0); } +async function getWebhookResponses({ request, count = 1 }) { + let response; + + // retry since there can be lag between the time the hook is triggered and the time the server receives the request + for (let i = 0; i < 20; i++) { + response = await request.get(hookPath + '/count'); + if ((await response.json()) === count) { + break; + } + await new Promise(resolve => setTimeout(resolve, 100)); + } + await expect(await response.json()).toBe(count); + + response = await request.get(hookPath + '/all'); + return await response.json(); +} + async function verifyHookTrigger(count: number, value: string, request, expectedData?: any) { // Retry since there can be lag between the time the hook is triggered and the time the server receives the request let response; @@ -92,6 +112,13 @@ test.describe.serial('Webhook', () => { context = await setup({ page }); dashboard = new DashboardPage(page, context.project); webhook = dashboard.webhookForm; + + api = new Api({ + baseURL: `http://localhost:8080/`, + headers: { + 'xc-auth': context.token, + }, + }); }); test('CRUD', async ({ request, page }) => { @@ -395,4 +422,107 @@ test.describe.serial('Webhook', () => { await dashboard.grid.deleteRow(0); await verifyHookTrigger(6, 'Delaware', request, buildExpectedResponseData('records.after.delete', 'Delaware')); }); + + test('Bulk operations', async ({ request, page }) => { + async function verifyBulkOperationTrigger(rsp, type, valueCounter, oldValueCounter?) { + for (let i = 0; i < rsp.length; i++) { + expect(rsp[i].type === type); + expect(rsp[i].data.table_name === 'numberBased'); + expect(rsp[i].data.view_name === 'numberBased'); + expect(rsp[i].data.rows.length === 25); + for (let j = 0; j < rsp[i].data.rows.length; j++) { + expect(rsp[i].data.rows[j].Number === (i * 25 + j + 1) * valueCounter); + } + + if (oldValueCounter) { + expect(rsp[i].data.previous_rows.length === 25); + for (let j = 0; j < rsp[i].data.previous_rows.length; j++) { + expect(rsp[i].data.previous_rows[j].Number === (i * 25 + j + 1) * oldValueCounter); + } + } + } + } + + // Waiting for the server to start + await page.waitForTimeout(1000); + + // close 'Team & Auth' tab + await dashboard.closeTab({ title: 'Team & Auth' }); + + const columns = [ + { + column_name: 'Id', + title: 'Id', + uidt: UITypes.ID, + }, + { + column_name: 'Number', + title: 'Number', + uidt: UITypes.Number, + }, + ]; + let project, table; + + try { + project = await api.project.read(context.project.id); + table = await api.base.tableCreate(context.project.id, project.bases?.[0].id, { + table_name: 'numberBased', + title: 'numberBased', + columns: columns, + }); + } catch (e) { + console.error(e); + } + + await page.reload(); + await dashboard.treeView.openTable({ title: 'numberBased' }); + + // create after insert webhook + await webhook.create({ + title: 'hook-1', + event: 'After Insert', + }); + await webhook.create({ + title: 'hook-1', + event: 'After Update', + }); + await webhook.create({ + title: 'hook-1', + event: 'After Delete', + }); + + await clearServerData({ request }); + const rowAttributesForInsert = Array.from({ length: 50 }, (_, i) => ({ + Id: i + 1, + Number: (i + 1) * 100, + })); + await api.dbTableRow.bulkCreate('noco', context.project.id, table.id, rowAttributesForInsert); + await page.reload(); + // 50 records inserted, we expect 2 webhook responses + let rsp = await getWebhookResponses({ request, count: 2 }); + await verifyBulkOperationTrigger(rsp, 'records.after.insert', 100); + + // bulk update all rows + await clearServerData({ request }); + // build rowAttributes for update to contain all the ids & their value set to 100 + const rowAttributesForUpdate = Array.from({ length: 50 }, (_, i) => ({ + Id: i + 1, + Number: (i + 1) * 111, + })); + + await api.dbTableRow.bulkUpdate('noco', context.project.id, table.id, rowAttributesForUpdate); + await page.reload(); + // 50 records updated, we expect 2 webhook responses + rsp = await getWebhookResponses({ request, count: 2 }); + await verifyBulkOperationTrigger(rsp, 'records.after.update', 111, 100); + + // bulk delete all rows + await clearServerData({ request }); + const rowAttributesForDelete = Array.from({ length: 50 }, (_, i) => ({ Id: i + 1 })); + + await api.dbTableRow.bulkDelete('noco', context.project.id, table.id, rowAttributesForDelete); + await page.reload(); + rsp = await getWebhookResponses({ request, count: 2 }); + await verifyBulkOperationTrigger(rsp, 'records.after.delete', 111); + }); });