@ -1,6 +1,6 @@
import 'mocha' ;
import 'mocha' ;
import { createProject , createSakilaProject } from './factory/project' ;
import init from '../init' ;
import init from '../init' ;
import { createProject , createSakilaProject } from './factory/project' ;
import request from 'supertest' ;
import request from 'supertest' ;
import Project from '../../../../src/lib/models/Project' ;
import Project from '../../../../src/lib/models/Project' ;
import Model from '../../../../src/lib/models/Model' ;
import Model from '../../../../src/lib/models/Model' ;
@ -8,8 +8,11 @@ import { createTable, getTable } from './factory/table';
import View from '../../../../src/lib/models/View' ;
import View from '../../../../src/lib/models/View' ;
import { ColumnType , UITypes , ViewType , ViewTypes } from 'nocodb-sdk' ;
import { ColumnType , UITypes , ViewType , ViewTypes } from 'nocodb-sdk' ;
import { createView } from './factory/view' ;
import { createView } from './factory/view' ;
import { createLookupColumn , createRollupColumn } from './factory/column' ;
import { createColumn , create LookupColumn , createLtarColumn , create RollupColumn , updateView Column } from './factory/column' ;
import Audit from '../../../../src/lib/models/Audit' ;
import Audit from '../../../../src/lib/models/Audit' ;
import Column from '../../../../src/lib/models/Column' ;
import GalleryView from '../../../../src/lib/models/GalleryView' ;
import { createRelation , createRow , getOneRow , getRow } from './factory/row' ;
const isColumnsCorrectInResponse = ( row , columns : ColumnType [ ] ) = > {
const isColumnsCorrectInResponse = ( row , columns : ColumnType [ ] ) = > {
const responseColumnsListStr = Object . keys ( row ) . sort ( ) . join ( ',' ) ;
const responseColumnsListStr = Object . keys ( row ) . sort ( ) . join ( ',' ) ;
@ -33,7 +36,6 @@ function viewRowTests() {
beforeEach ( async function ( ) {
beforeEach ( async function ( ) {
context = await init ( ) ;
context = await init ( ) ;
sakilaProject = await createSakilaProject ( context ) ;
sakilaProject = await createSakilaProject ( context ) ;
project = await createProject ( context ) ;
project = await createProject ( context ) ;
customerTable = await getTable ( { project : sakilaProject , name : 'customer' } )
customerTable = await getTable ( { project : sakilaProject , name : 'customer' } )
@ -609,13 +611,8 @@ function viewRowTests() {
it ( 'Find one sorted data list with required columns grid' , async function ( ) {
it ( 'Find one sorted data list with required columns grid' , async function ( ) {
await testFindOneSortedDataWithRequiredColumns ( ViewTypes . GRID ) ;
await testFindOneSortedDataWithRequiredColumns ( ViewTypes . GRID ) ;
} ) ;
} ) ;
const testFindOneSortedFilteredNestedFieldsDataWithRollup = async ( viewType : ViewTypes ) = > {
const testFindOneSortedFilteredNestedFieldsDataWithRollup = async ( viewType : ViewTypes ) = > {
const view = await createView ( context , {
title : 'View' ,
table : customerTable ,
type : viewType
} ) ;
const rollupColumn = await createRollupColumn ( context , {
const rollupColumn = await createRollupColumn ( context , {
project : sakilaProject ,
project : sakilaProject ,
title : 'Number of rentals' ,
title : 'Number of rentals' ,
@ -624,7 +621,18 @@ function viewRowTests() {
relatedTableName : 'rental' ,
relatedTableName : 'rental' ,
relatedTableColumnTitle : 'RentalDate' ,
relatedTableColumnTitle : 'RentalDate' ,
} ) ;
} ) ;
const view = await createView ( context , {
title : 'View' ,
table : customerTable ,
type : viewType
} ) ;
await updateViewColumn ( context , {
column : rollupColumn ,
view : view ,
attr : { show : true } ,
} )
const paymentListColumn = ( await customerTable . getColumns ( ) ) . find (
const paymentListColumn = ( await customerTable . getColumns ( ) ) . find (
( c ) = > c . title === 'Payment List'
( c ) = > c . title === 'Payment List'
) ;
) ;
@ -693,7 +701,7 @@ function viewRowTests() {
. expect ( 200 ) ;
. expect ( 200 ) ;
if ( ascResponse . body [ rollupColumn . title ] !== 12 ) {
if ( ascResponse . body [ rollupColumn . title ] !== 12 ) {
console . log ( ascResponse . body ) ;
console . log ( 'response.body' , ascResponse . body ) ;
throw new Error ( 'Wrong filter' ) ;
throw new Error ( 'Wrong filter' ) ;
}
}
@ -708,13 +716,518 @@ function viewRowTests() {
}
}
// todo: gallery view doesnt seem to support rollup
// todo: gallery view doesnt seem to support rollup
// it.only('Find one sorted filtered view with nested fields data list with a rollup column in customer table FORM', async function () {
// it.only('Find one sorted filtered view with nested fields data list with a rollup column in customer table GALLERY', async function () {
// await testFindOneSortedFilteredNestedFieldsDataWithRollup(ViewTypes.GALLERY);
// });
// it('Find one sorted filtered view with nested fields data list with a rollup column in customer table FORM', async function () {
// await testFindOneSortedFilteredNestedFieldsDataWithRollup(ViewTypes.FORM);
// await testFindOneSortedFilteredNestedFieldsDataWithRollup(ViewTypes.FORM);
// });
// });
it ( 'Find one sorted filtered view with nested fields data list with a rollup column in customer table GRID' , async function ( ) {
it ( 'Find one view sorted filtered view with nested fields data list with a rollup column in customer table GRID' , async function ( ) {
await testFindOneSortedFilteredNestedFieldsDataWithRollup ( ViewTypes . GRID ) ;
await testFindOneSortedFilteredNestedFieldsDataWithRollup ( ViewTypes . GRID ) ;
} ) ;
} ) ;
const testGroupDescSorted = async ( viewType : ViewTypes ) = > {
const view = await createView ( context , {
title : 'View' ,
table : customerTable ,
type : viewType
} ) ;
const firstNameColumn = customerColumns . find (
( col ) = > col . title === 'FirstName'
) ;
const rollupColumn = await createRollupColumn ( context , {
project : sakilaProject ,
title : 'Rollup' ,
rollupFunction : 'count' ,
table : customerTable ,
relatedTableName : 'rental' ,
relatedTableColumnTitle : 'RentalDate' ,
} ) ;
const visibleColumns = [ firstNameColumn ] ;
const sortInfo = ` -FirstName, + ${ rollupColumn . title } ` ;
const response = await request ( context . app )
. get (
` /api/v1/db/data/noco/ ${ sakilaProject . id } / ${ customerTable . id } /views/ ${ view . id } /groupby `
)
. set ( 'xc-auth' , context . token )
. query ( {
fields : visibleColumns.map ( ( c ) = > c . title ) ,
sort : sortInfo ,
column_name : firstNameColumn.column_name ,
} )
. expect ( 200 ) ;
if (
response . body . list [ 4 ] [ 'first_name' ] !== 'WILLIE' ||
response . body . list [ 4 ] [ 'count' ] !== 2
)
throw new Error ( 'Wrong groupby' ) ;
}
it ( 'Groupby desc sorted and with rollup view data list with required columns GRID' , async function ( ) {
await testGroupDescSorted ( ViewTypes . GRID ) ;
} ) ;
it ( 'Groupby desc sorted and with rollup view data list with required columns FORM' , async function ( ) {
await testGroupDescSorted ( ViewTypes . FORM ) ;
} ) ;
it ( 'Groupby desc sorted and with rollup view data list with required columns GALLERY' , async function ( ) {
await testGroupDescSorted ( ViewTypes . GALLERY ) ;
} ) ;
const testGroupWithOffset = async ( viewType : ViewTypes ) = > {
const view = await createView ( context , {
title : 'View' ,
table : customerTable ,
type : viewType
} ) ;
const firstNameColumn = customerColumns . find (
( col ) = > col . title === 'FirstName'
) ;
const rollupColumn = await createRollupColumn ( context , {
project : sakilaProject ,
title : 'Rollup' ,
rollupFunction : 'count' ,
table : customerTable ,
relatedTableName : 'rental' ,
relatedTableColumnTitle : 'RentalDate' ,
} ) ;
const visibleColumns = [ firstNameColumn ] ;
const sortInfo = ` -FirstName, + ${ rollupColumn . title } ` ;
const response = await request ( context . app )
. get (
` /api/v1/db/data/noco/ ${ sakilaProject . id } / ${ customerTable . id } /views/ ${ view . id } /groupby `
)
. set ( 'xc-auth' , context . token )
. query ( {
fields : visibleColumns.map ( ( c ) = > c . title ) ,
sort : sortInfo ,
column_name : firstNameColumn.column_name ,
offset : 4 ,
} )
. expect ( 200 ) ;
if (
response . body . list [ 0 ] [ 'first_name' ] !== 'WILLIE' ||
response . body . list [ 0 ] [ 'count' ] !== 2
)
throw new Error ( 'Wrong groupby' ) ;
}
it ( 'Groupby desc sorted and with rollup view data list with required columns GALLERY' , async function ( ) {
await testGroupWithOffset ( ViewTypes . GALLERY ) ;
} ) ;
it ( 'Groupby desc sorted and with rollup view data list with required columns FORM' , async function ( ) {
await testGroupWithOffset ( ViewTypes . FORM ) ;
} ) ;
it ( 'Groupby desc sorted and with rollup view data list with required columns GRID' , async function ( ) {
await testGroupWithOffset ( ViewTypes . GRID ) ;
} ) ;
const testCount = async ( viewType : ViewTypes ) = > {
const view = await createView ( context , {
title : 'View' ,
table : customerTable ,
type : viewType
} ) ;
const response = await request ( context . app )
. get ( ` /api/v1/db/data/noco/ ${ sakilaProject . id } / ${ customerTable . id } /views/ ${ view . id } /count ` )
. set ( 'xc-auth' , context . token )
. expect ( 200 ) ;
if ( response . body . count !== 599 ) {
throw new Error ( 'Wrong count' ) ;
}
}
it ( 'Count view data list with required columns GRID' , async function ( ) {
await testCount ( ViewTypes . GRID ) ;
} ) ;
it ( 'Count view data list with required columns FORM' , async function ( ) {
await testCount ( ViewTypes . FORM ) ;
} ) ;
it ( 'Count view data list with required columns GALLERY' , async function ( ) {
await testCount ( ViewTypes . GALLERY ) ;
} ) ;
const testReadViewRow = async ( viewType : ViewTypes ) = > {
const view = await createView ( context , {
title : 'View' ,
table : customerTable ,
type : viewType
} ) ;
const listResponse = await request ( context . app )
. get ( ` /api/v1/db/data/noco/ ${ sakilaProject . id } / ${ customerTable . id } /views/ ${ view . id } ` )
. set ( 'xc-auth' , context . token )
. expect ( 200 ) ;
const row = listResponse . body . list [ 0 ] ;
const readResponse = await request ( context . app )
. get (
` /api/v1/db/data/noco/ ${ sakilaProject . id } / ${ customerTable . id } /views/ ${ view . id } / ${ row [ 'CustomerId' ] } `
)
. set ( 'xc-auth' , context . token )
. expect ( 200 ) ;
if (
row [ 'CustomerId' ] !== readResponse . body [ 'CustomerId' ] ||
row [ 'FirstName' ] !== readResponse . body [ 'FirstName' ]
) {
throw new Error ( 'Wrong read' ) ;
}
}
it ( 'Read view row GALLERY' , async function ( ) {
await testReadViewRow ( ViewTypes . GALLERY ) ;
} )
it ( 'Read view row FORM' , async function ( ) {
await testReadViewRow ( ViewTypes . FORM ) ;
} )
it ( 'Read view row GRID' , async function ( ) {
await testReadViewRow ( ViewTypes . GRID ) ;
} )
const testUpdateViewRow = async ( viewType : ViewTypes ) = > {
const table = await createTable ( context , project ) ;
const row = await createRow ( context , { project , table } ) ;
const view = await createView ( context , {
title : 'View' ,
table : table ,
type : viewType
} ) ;
const updateResponse = await request ( context . app )
. patch ( ` /api/v1/db/data/noco/ ${ project . id } / ${ table . id } /views/ ${ view . id } / ${ row [ 'Id' ] } ` )
. set ( 'xc-auth' , context . token )
. send ( {
title : 'Updated' ,
} )
. expect ( 200 ) ;
if ( updateResponse . body [ 'Title' ] !== 'Updated' ) {
throw new Error ( 'Wrong update' ) ;
}
}
it ( 'Update view row GALLERY' , async function ( ) {
await testUpdateViewRow ( ViewTypes . GALLERY ) ;
} )
it ( 'Update view row GRID' , async function ( ) {
await testUpdateViewRow ( ViewTypes . GRID ) ;
} )
it ( 'Update view row FORM' , async function ( ) {
await testUpdateViewRow ( ViewTypes . FORM ) ;
} )
const testUpdateViewRowWithValidationAndInvalidData = async ( viewType : ViewTypes ) = > {
const table = await createTable ( context , project ) ;
const emailColumn = await createColumn ( context , table , {
title : 'Email' ,
column_name : 'email' ,
uidt : UITypes.Email ,
meta : {
validate : true ,
} ,
} ) ;
const view = await createView ( context , {
title : 'View' ,
table : table ,
type : viewType
} ) ;
const row = await createRow ( context , { project , table } ) ;
await request ( context . app )
. patch ( ` /api/v1/db/data/noco/ ${ project . id } / ${ table . id } /views/ ${ view . id } / ${ row [ 'Id' ] } ` )
. set ( 'xc-auth' , context . token )
. send ( {
[ emailColumn . column_name ] : 'invalidemail' ,
} )
. expect ( 400 ) ;
}
it ( 'Update view row with validation and invalid data GALLERY' , async function ( ) {
await testUpdateViewRowWithValidationAndInvalidData ( ViewTypes . GALLERY ) ;
} )
it ( 'Update view row with validation and invalid data GRID' , async function ( ) {
await testUpdateViewRowWithValidationAndInvalidData ( ViewTypes . GRID ) ;
} )
it ( 'Update view row with validation and invalid data FORM' , async function ( ) {
await testUpdateViewRowWithValidationAndInvalidData ( ViewTypes . FORM ) ;
} )
// todo: Test webhooks of before and after update
// todo: Test with form view
const testUpdateViewRowWithValidationAndValidData = async ( viewType : ViewTypes ) = > {
const table = await createTable ( context , project ) ;
const emailColumn = await createColumn ( context , table , {
title : 'Email' ,
column_name : 'email' ,
uidt : UITypes.Email ,
meta : {
validate : true ,
} ,
} ) ;
const view = await createView ( context , {
title : 'View' ,
table : table ,
type : viewType
} ) ;
const row = await createRow ( context , { project , table } ) ;
const response = await request ( context . app )
. patch ( ` /api/v1/db/data/noco/ ${ project . id } / ${ table . id } /views/ ${ view . id } / ${ row [ 'Id' ] } ` )
. set ( 'xc-auth' , context . token )
. send ( {
[ emailColumn . column_name ] : 'valid@example.com' ,
} )
. expect ( 200 ) ;
const updatedRow = await getRow (
context ,
{ project ,
table ,
id : response.body [ 'Id' ] }
) ;
if ( updatedRow [ emailColumn . title ] !== 'valid@example.com' ) {
throw new Error ( 'Wrong update' ) ;
}
}
it ( 'Update view row with validation and valid data GALLERY' , async function ( ) {
await testUpdateViewRowWithValidationAndValidData ( ViewTypes . GALLERY ) ;
} )
it ( 'Update view row with validation and valid data GRID' , async function ( ) {
await testUpdateViewRowWithValidationAndValidData ( ViewTypes . GRID ) ;
} )
it ( 'Update view row with validation and valid data FORM' , async function ( ) {
await testUpdateViewRowWithValidationAndValidData ( ViewTypes . FORM ) ;
} )
const testDeleteViewRow = async ( viewType : ViewTypes ) = > {
const table = await createTable ( context , project ) ;
const row = await createRow ( context , { project , table } ) ;
const view = await createView ( context , {
title : 'View' ,
table : table ,
type : viewType
} ) ;
await request ( context . app )
. delete ( ` /api/v1/db/data/noco/ ${ project . id } / ${ table . id } /views/ ${ view . id } / ${ row [ 'Id' ] } ` )
. set ( 'xc-auth' , context . token )
. expect ( 200 ) ;
const deleteRow = await getRow ( context , { project , table , id : row [ 'Id' ] } ) ;
if ( deleteRow && Object . keys ( deleteRow ) . length > 0 ) {
console . log ( deleteRow ) ;
throw new Error ( 'Wrong delete' ) ;
}
}
it ( 'Delete view row GALLERY' , async function ( ) {
await testDeleteViewRow ( ViewTypes . GALLERY ) ;
} )
it ( 'Delete view row GRID' , async function ( ) {
await testDeleteViewRow ( ViewTypes . GRID ) ;
} )
it ( 'Delete view row FORM' , async function ( ) {
await testDeleteViewRow ( ViewTypes . FORM ) ;
} )
const testDeleteViewRowWithForiegnKeyConstraint = async ( viewType : ViewTypes ) = > {
const table = await createTable ( context , project ) ;
const relatedTable = await createTable ( context , project , {
table_name : 'Table2' ,
title : 'Table2_Title' ,
} ) ;
const ltarColumn = await createLtarColumn ( context , {
title : 'Ltar' ,
parentTable : table ,
childTable : relatedTable ,
type : 'hm' ,
} ) ;
const view = await createView ( context , {
title : 'View' ,
table : table ,
type : viewType
} ) ;
const row = await createRow ( context , { project , table } ) ;
await createRelation ( context , {
project ,
table ,
childTable : relatedTable ,
column : ltarColumn ,
type : 'hm' ,
rowId : row [ 'Id' ] ,
} ) ;
const response = await request ( context . app )
. delete ( ` /api/v1/db/data/noco/ ${ project . id } / ${ table . id } /views/ ${ view . id } / ${ row [ 'Id' ] } ` )
. set ( 'xc-auth' , context . token )
. expect ( 200 ) ;
const deleteRow = await getRow ( context , { project , table , id : row [ 'Id' ] } ) ;
if ( ! deleteRow ) {
throw new Error ( 'Should not delete' ) ;
}
if (
! ( response . body . message [ 0 ] as string ) . includes (
'is a LinkToAnotherRecord of'
)
) {
throw new Error ( 'Should give ltar foreign key error' ) ;
}
}
it ( 'Delete view row with ltar foreign key constraint GALLERY' , async function ( ) {
await testDeleteViewRowWithForiegnKeyConstraint ( ViewTypes . GALLERY ) ;
} )
it ( 'Delete view row with ltar foreign key constraint GRID' , async function ( ) {
await testDeleteViewRowWithForiegnKeyConstraint ( ViewTypes . GRID ) ;
} )
it ( 'Delete view row with ltar foreign key constraint FORM' , async function ( ) {
await testDeleteViewRowWithForiegnKeyConstraint ( ViewTypes . FORM ) ;
} )
const testViewRowExists = async ( viewType : ViewTypes ) = > {
const row = await getOneRow ( context , {
project : sakilaProject ,
table : customerTable ,
} ) ;
const view = await createView ( context , {
title : 'View' ,
table : customerTable ,
type : viewType
} ) ;
const response = await request ( context . app )
. get (
` /api/v1/db/data/noco/ ${ sakilaProject . id } / ${ customerTable . id } /views/ ${ view . id } / ${ row [ 'CustomerId' ] } /exist `
)
. set ( 'xc-auth' , context . token )
. expect ( 200 ) ;
if ( ! response . body ) {
throw new Error ( 'Should exist' ) ;
}
}
it ( 'Exist should be true view row when it exists GALLERY' , async function ( ) {
await testViewRowExists ( ViewTypes . GALLERY ) ;
} ) ;
it ( 'Exist should be true view row when it exists GRID' , async function ( ) {
await testViewRowExists ( ViewTypes . GRID ) ;
} )
it ( 'Exist should be true view row when it exists FORM' , async function ( ) {
await testViewRowExists ( ViewTypes . FORM ) ;
} )
const testViewRowNotExists = async ( viewType : ViewTypes ) = > {
const view = await createView ( context , {
title : 'View' ,
table : customerTable ,
type : viewType
} ) ;
const response = await request ( context . app )
. get (
` /api/v1/db/data/noco/ ${ sakilaProject . id } / ${ customerTable . id } /views/ ${ view . id } /invalid-id/exist `
)
. set ( 'xc-auth' , context . token )
. expect ( 200 ) ;
if ( response . body ) {
throw new Error ( 'Should not exist' ) ;
}
}
it ( 'Exist should be false view row when it does not exist GALLERY' , async function ( ) {
await testViewRowNotExists ( ViewTypes . GALLERY ) ;
} )
it ( 'Exist should be false view row when it does not exist GRID' , async function ( ) {
await testViewRowNotExists ( ViewTypes . GRID ) ;
} )
it ( 'Exist should be false view row when it does not exist FORM' , async function ( ) {
await testViewRowNotExists ( ViewTypes . FORM ) ;
} )
it ( 'Export csv GRID' , async function ( ) {
const view = await createView ( context , {
title : 'View' ,
table : customerTable ,
type : ViewTypes . GRID
} ) ;
const response = await request ( context . app )
. get ( ` /api/v1/db/data/noco/ ${ sakilaProject . id } / ${ customerTable . title } /views/ ${ view . id } /export/csv ` )
. set ( 'xc-auth' , context . token )
. expect ( 200 ) ;
if ( ! response [ 'header' ] [ 'content-disposition' ] . includes ( "View-export.csv" ) ) {
console . log ( response [ 'header' ] [ 'content-disposition' ] ) ;
throw new Error ( 'Wrong file name' ) ;
}
if ( ! response . text ) {
throw new Error ( 'Wrong export' ) ;
}
} )
it ( 'Export excel GRID' , async function ( ) {
const view = await createView ( context , {
title : 'View' ,
table : customerTable ,
type : ViewTypes . GRID
} ) ;
const response = await request ( context . app )
. get ( ` /api/v1/db/data/noco/ ${ sakilaProject . id } / ${ customerTable . title } /views/ ${ view . id } /export/excel ` )
. set ( 'xc-auth' , context . token )
. expect ( 200 ) ;
if ( ! response [ 'header' ] [ 'content-disposition' ] . includes ( "View-export.xlsx" ) ) {
console . log ( response [ 'header' ] [ 'content-disposition' ] ) ;
throw new Error ( 'Wrong file name' ) ;
}
if ( ! response . text ) {
throw new Error ( 'Wrong export' ) ;
}
} )
}
}
export default function ( ) {
export default function ( ) {