From 8b1239ae39dea98689c71d3a468717cb02af6e6f Mon Sep 17 00:00:00 2001 From: DarkPhoenix2704 Date: Tue, 20 Feb 2024 07:16:20 +0000 Subject: [PATCH] test: unit test for calendar view --- packages/nocodb/tests/unit/factory/view.ts | 11 +- .../tests/unit/rest/tests/viewRow.test.ts | 274 ++++++++++++++++-- 2 files changed, 266 insertions(+), 19 deletions(-) diff --git a/packages/nocodb/tests/unit/factory/view.ts b/packages/nocodb/tests/unit/factory/view.ts index a0945b0666..99deecdb08 100644 --- a/packages/nocodb/tests/unit/factory/view.ts +++ b/packages/nocodb/tests/unit/factory/view.ts @@ -9,10 +9,15 @@ const createView = async ( title, table, type, + range, }: { title: string; table: Model; type: ViewTypes; + range?: { + fk_from_column_id?: string; + fk_to_column_id?: string; + }; }, ) => { const viewTypeStr = (type) => { @@ -25,6 +30,8 @@ const createView = async ( return 'grids'; case ViewTypes.KANBAN: return 'kanbans'; + case ViewTypes.CALENDAR: + return 'calendars'; default: throw new Error('Invalid view type'); } @@ -36,16 +43,16 @@ const createView = async ( .send({ title, type, + ...(range?.fk_from_column_id ? { calendar_range: [range] } : {}), }); if (response.status !== 200) { throw new Error('createView', response.body.message); } - const view = (await View.getByTitleOrId({ + return (await View.getByTitleOrId({ fk_model_id: table.id, titleOrId: title, })) as View; - return view; }; const getView = async ( diff --git a/packages/nocodb/tests/unit/rest/tests/viewRow.test.ts b/packages/nocodb/tests/unit/rest/tests/viewRow.test.ts index 293fece88a..43ec3f405a 100644 --- a/packages/nocodb/tests/unit/rest/tests/viewRow.test.ts +++ b/packages/nocodb/tests/unit/rest/tests/viewRow.test.ts @@ -43,9 +43,12 @@ let sakilaProject: Base; // models let customerTable: Model; let filmTable: Model; +let rentalTable: Model; + // columns let customerColumns; let filmColumns; +let rentalColumns; // views let customerGridView: View; let customerGalleryView: View; @@ -53,6 +56,9 @@ let customerFormView: View; // use film table because it has single select field let filmKanbanView: View; +// Use rental table because it has a date field +let rentalCalendarView: View; + const testGetViewRowList = async (view: View) => { const response = await request(context.app) .get( @@ -95,6 +101,21 @@ const testGetViewRowListKanban = async (view: View) => { .and.to.be.a('number'); }; +const testGetViewListCalendar = async (view: View) => { + const response = await request(context.app) + .get( + `/api/v1/db/data/noco/${sakilaProject.id}/${rentalTable.id}/views/${view.id}`, + ) + .set('xc-auth', context.token) + .expect(200); + + const pageInfo = response.body.pageInfo; + + if (pageInfo.totalRows !== 16044 && response.body.list.length !== 16044) { + throw new Error('Calendar View row list is not correct'); + } +}; + function viewRowStaticTests() { before(async function () { console.time('#### viewRowTests'); @@ -132,6 +153,24 @@ function viewRowStaticTests() { table: filmTable, type: ViewTypes.KANBAN, }); + + rentalTable = await getTable({ + base: sakilaProject, + name: 'rental', + }); + + rentalColumns = await rentalTable.getColumns(); + + rentalCalendarView = await createView(context, { + title: 'Rental Calendar', + table: rentalTable, + type: ViewTypes.CALENDAR, + range: { + fk_from_column_id: rentalColumns.find((c) => c.title === 'RentalDate') + .id, + }, + }); + console.timeEnd('#### viewRowTests'); }); @@ -148,14 +187,28 @@ function viewRowStaticTests() { await testGetViewRowList(customerGridView); }); + it('Get view row list Calendar', async () => { + await testGetViewListCalendar(rentalCalendarView); + }); + const testGetViewDataListWithRequiredColumns = async (view: View) => { - const requiredColumns = customerColumns + const columns = + view.type === ViewTypes.CALENDAR ? rentalColumns : customerColumns; + const requiredColumns = columns .filter((_, index) => index < 3) .filter((c: ColumnType) => c.uidt !== UITypes.ForeignKey); + let table; + + if (view.type === ViewTypes.CALENDAR) { + table = rentalTable; + } else { + table = customerTable; + } + const response = await request(context.app) .get( - `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/views/${view.id}`, + `/api/v1/db/data/noco/${sakilaProject.id}/${table.id}/views/${view.id}`, ) .set('xc-auth', context.token) .query({ @@ -188,6 +241,9 @@ function viewRowStaticTests() { it('Get view data list with required columns grid', async () => { await testGetViewDataListWithRequiredColumns(customerGridView); }); + it('Get view data list with required columns grid', async () => { + await testGetViewDataListWithRequiredColumns(rentalCalendarView); + }); const testGetGroupedViewDataListWithRequiredColumns = async (view: View) => { const requiredColumns = filmColumns @@ -457,6 +513,23 @@ function viewRowTests() { table: filmTable, type: ViewTypes.KANBAN, }); + + rentalTable = await getTable({ + base: sakilaProject, + name: 'rental', + }); + + rentalColumns = await rentalTable.getColumns(); + + rentalCalendarView = await createView(context, { + title: 'Rental Calendar', + table: rentalTable, + type: ViewTypes.CALENDAR, + range: { + fk_from_column_id: rentalColumns.find((c) => c.title === 'RentalDate') + .id, + }, + }); console.timeEnd('#### viewRowTests'); }); @@ -554,6 +627,10 @@ function viewRowTests() { await testGetViewDataListWithRequiredColumnsAndFilter(ViewTypes.GRID); }); + it('Get nested sorted filtered table data list with a lookup column Calendar', async function () { + await testGetViewDataListWithRequiredColumnsAndFilter(ViewTypes.CALENDAR); + }); + const testGetNestedSortedFilteredTableDataListWithLookupColumn = async ( viewType: ViewTypes, ) => { @@ -657,6 +734,7 @@ function viewRowTests() { const testCreateRowView = async (viewType: ViewTypes) => { const table = await createTable(context, base); + const view = await createView(context, { title: 'View', table: table, @@ -691,8 +769,13 @@ function viewRowTests() { await testCreateRowView(ViewTypes.KANBAN); }); + it('Create table row Calendar', async function () { + await testCreateRowView(ViewTypes.CALENDAR); + }); + const testCreateRowViewWithWrongView = async (viewType: ViewTypes) => { const table = await createTable(context, base); + const nonRelatedView = await createView(context, { title: 'View', table: customerTable, @@ -726,16 +809,22 @@ function viewRowTests() { await testCreateRowViewWithWrongView(ViewTypes.KANBAN); }); + it('Create table row wrong calendar id', async function () { + await testCreateRowViewWithWrongView(ViewTypes.CALENDAR); + }); + // todo: Test that all the columns needed to be shown in the view are returned const testFindOneSortedDataWithRequiredColumns = async ( viewType: ViewTypes, ) => { + const table = viewType === ViewTypes.CALENDAR ? rentalTable : customerTable; const view = await createView(context, { title: 'View', - table: customerTable, + table: table, type: viewType, }); + const firstNameColumn = customerColumns.find( (col) => col.title === 'FirstName', ); @@ -954,6 +1043,9 @@ function viewRowTests() { it('Groupby desc sorted and with rollup view data list with required columns GALLERY', async function () { await testGroupDescSorted(ViewTypes.GALLERY); }); + it('Groupby desc sorted and with rollup view data list with required columns CALENDAR', async function () { + await testGroupDescSorted(ViewTypes.CALENDAR); + }); const testGroupWithOffset = async (viewType: ViewTypes) => { const view = await createView(context, { @@ -1006,41 +1098,81 @@ function viewRowTests() { it('Groupby desc sorted and with rollup view data list with required columns GRID', async function () { await testGroupWithOffset(ViewTypes.GRID); }); + it('Groupby desc sorted and with rollup view data list with required columns CALENDAR', async function () { + await testGroupWithOffset(ViewTypes.CALENDAR); + }); const testCount = async (viewType: ViewTypes) => { + let calendar_range = {}; + let table; + + if (viewType === ViewTypes.CALENDAR) { + table = rentalTable; + calendar_range = { + fk_from_column_id: rentalColumns.find((c) => c.title === 'RentalDate') + .id, + }; + } else { + table = customerTable; + } + const view = await createView(context, { title: 'View', - table: customerTable, + table: table, type: viewType, + range: calendar_range, }); const response = await request(context.app) .get( - `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/views/${view.id}/count`, + `/api/v1/db/data/noco/${sakilaProject.id}/${table.id}/views/${view.id}/count`, ) .set('xc-auth', context.token) .expect(200); - if (parseInt(response.body.count) !== 599) { - throw new Error('Wrong count'); + if (viewType === ViewTypes.CALENDAR) { + if (parseInt(response.body.count) !== 16044) { + throw new Error('Wrong count'); + } + } else { + if (parseInt(response.body.count) !== 599) { + throw new Error('Wrong count'); + } } }; it('Count view data list with required columns', async function () { await testCount(ViewTypes.GRID); await testCount(ViewTypes.FORM); await testCount(ViewTypes.GALLERY); + await testCount(ViewTypes.CALENDAR); }); const testReadViewRow = async (viewType: ViewTypes) => { + let table; + let calendar_range = {}; + + let Id = 'CustomerId'; + if (viewType === ViewTypes.CALENDAR) { + table = rentalTable; + calendar_range = { + fk_from_column_id: rentalColumns.find((c) => c.title === 'RentalDate') + .id, + }; + Id = 'RentalId'; + } else { + table = customerTable; + } + const view = await createView(context, { title: 'View', - table: customerTable, + table: table, type: viewType, + range: calendar_range, }); const listResponse = await request(context.app) .get( - `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/views/${view.id}`, + `/api/v1/db/data/noco/${sakilaProject.id}/${table.id}/views/${view.id}`, ) .set('xc-auth', context.token) .expect(200); @@ -1049,13 +1181,13 @@ function viewRowTests() { const readResponse = await request(context.app) .get( - `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/views/${view.id}/${row['CustomerId']}`, + `/api/v1/db/data/noco/${sakilaProject.id}/${table.id}/views/${view.id}/${row[Id]}`, ) .set('xc-auth', context.token) .expect(200); if ( - row['CustomerId'] !== readResponse.body['CustomerId'] || + row[Id] !== readResponse.body[Id] || row['FirstName'] !== readResponse.body['FirstName'] ) { throw new Error('Wrong read'); @@ -1065,15 +1197,31 @@ function viewRowTests() { await testReadViewRow(ViewTypes.GALLERY); await testReadViewRow(ViewTypes.FORM); await testReadViewRow(ViewTypes.GRID); + await testReadViewRow(ViewTypes.CALENDAR); }); const testUpdateViewRow = async (viewType: ViewTypes) => { const table = await createTable(context, base); const row = await createRow(context, { base, table }); + + let calendar_range = {}; + + if (viewType === ViewTypes.CALENDAR) { + const column = await createColumn(context, table, { + title: 'RentalDate', + column_name: 'rental_date', + uidt: UITypes.Date, + }); + calendar_range = { + fk_from_column_id: column.id, + }; + } + const view = await createView(context, { title: 'View', table: table, type: viewType, + range: calendar_range, }); const updateResponse = await request(context.app) @@ -1099,6 +1247,9 @@ function viewRowTests() { it('Update view row FORM', async function () { await testUpdateViewRow(ViewTypes.FORM); }); + it('Update view row CALENDAR', async function () { + await testUpdateViewRow(ViewTypes.CALENDAR); + }); const testUpdateViewRowWithValidationAndInvalidData = async ( viewType: ViewTypes, @@ -1112,10 +1263,25 @@ function viewRowTests() { validate: true, }, }); + + let calendar_range = {}; + + if (viewType === ViewTypes.CALENDAR) { + const column = await createColumn(context, table, { + title: 'RentalDate', + column_name: 'rental_date', + uidt: UITypes.Date, + }); + calendar_range = { + fk_from_column_id: column.id, + }; + } + const view = await createView(context, { title: 'View', table: table, type: viewType, + range: calendar_range, }); const row = await createRow(context, { base, table }); @@ -1139,7 +1305,9 @@ function viewRowTests() { it('Update view row with validation and invalid data FORM', async function () { await testUpdateViewRowWithValidationAndInvalidData(ViewTypes.FORM); }); - + it('Update view row with validation and invalid data CALENDAR', async function () { + await testUpdateViewRowWithValidationAndInvalidData(ViewTypes.CALENDAR); + }); // todo: Test webhooks of before and after update // todo: Test with form view @@ -1155,10 +1323,25 @@ function viewRowTests() { validate: true, }, }); + + let calendar_range = {}; + + if (viewType === ViewTypes.CALENDAR) { + const column = await createColumn(context, table, { + title: 'RentalDate', + column_name: 'rental_date', + uidt: UITypes.Date, + }); + calendar_range = { + fk_from_column_id: column.id, + }; + } + const view = await createView(context, { title: 'View', table: table, type: viewType, + range: calendar_range, }); const row = await createRow(context, { base, table }); @@ -1190,14 +1373,31 @@ function viewRowTests() { it('Update view row with validation and valid data FORM', async function () { await testUpdateViewRowWithValidationAndValidData(ViewTypes.FORM); }); + it('Update view row with validation and valid data CALENDAR', async function () { + await testUpdateViewRowWithValidationAndValidData(ViewTypes.CALENDAR); + }); const testDeleteViewRow = async (viewType: ViewTypes) => { const table = await createTable(context, base); + + let calendar_range = {}; + if (viewType === ViewTypes.CALENDAR) { + const range = await createColumn(context, table, { + title: 'RentalDate', + column_name: 'rental_date', + uidt: UITypes.Date, + }); + calendar_range = { + fk_from_column_id: range.id, + }; + } + const row = await createRow(context, { base, table }); const view = await createView(context, { title: 'View', table: table, type: viewType, + range: calendar_range, }); await request(context.app) @@ -1222,6 +1422,9 @@ function viewRowTests() { it('Delete view row FORM', async function () { await testDeleteViewRow(ViewTypes.FORM); }); + it('Delete view row CALENDAR', async function () { + await testDeleteViewRow(ViewTypes.CALENDAR); + }); const testDeleteViewRowWithForeignKeyConstraint = async ( viewType: ViewTypes, @@ -1275,21 +1478,40 @@ function viewRowTests() { it('Delete view row with ltar foreign key constraint FORM', async function () { await testDeleteViewRowWithForeignKeyConstraint(ViewTypes.FORM); }); + it('Delete view row with ltar foreign key constraint Calendar', async function () { + await testDeleteViewRowWithForeignKeyConstraint(ViewTypes.CALENDAR); + }); const testViewRowExists = async (viewType: ViewTypes) => { + let table; + let calendar_range = {}; + let colTitle; + + if (viewType === ViewTypes.CALENDAR) { + colTitle = 'RentalId'; + table = rentalTable; + calendar_range = { + fk_from_column_id: rentalColumns.find((c) => c.title === 'RentalId').id, + }; + } else { + table = customerTable; + colTitle = 'CustomerId'; + } const row = await getOneRow(context, { base: sakilaProject, - table: customerTable, + table: table, }); + const view = await createView(context, { title: 'View', - table: customerTable, + table: table, type: viewType, + range: calendar_range, }); const response = await request(context.app) .get( - `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/views/${view.id}/${row['CustomerId']}/exist`, + `/api/v1/db/data/noco/${sakilaProject.id}/${table.id}/views/${view.id}/${row[colTitle]}/exist`, ) .set('xc-auth', context.token) .expect(200); @@ -1302,17 +1524,34 @@ function viewRowTests() { await testViewRowExists(ViewTypes.GALLERY); await testViewRowExists(ViewTypes.GRID); await testViewRowExists(ViewTypes.FORM); + await testViewRowExists(ViewTypes.CALENDAR); }); const testViewRowNotExists = async (viewType: ViewTypes) => { + let calendar_range = {}; + if (viewType === ViewTypes.CALENDAR) { + calendar_range = { + fk_from_column_id: rentalColumns.find((c) => c.title === 'RentalDate') + .id, + }; + } + let table; + + if (viewType === ViewTypes.CALENDAR) { + table = rentalTable; + } else { + table = customerTable; + } + const view = await createView(context, { title: 'View', - table: customerTable, + table: table, type: viewType, + range: calendar_range, }); const response = await request(context.app) .get( - `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/views/${view.id}/999999/exist`, + `/api/v1/db/data/noco/${sakilaProject.id}/${table.id}/views/${view.id}/999999/exist`, ) .set('xc-auth', context.token) .expect(200); @@ -1325,6 +1564,7 @@ function viewRowTests() { await testViewRowNotExists(ViewTypes.GALLERY); await testViewRowNotExists(ViewTypes.GRID); await testViewRowNotExists(ViewTypes.FORM); + await testViewRowNotExists(ViewTypes.CALENDAR); }); it('Export csv GRID', async function () {