mirror of https://github.com/nocodb/nocodb
Raju Udava
2 years ago
6 changed files with 651 additions and 20 deletions
@ -0,0 +1,131 @@
|
||||
import { ColumnType, UITypes } from 'nocodb-sdk'; |
||||
|
||||
const rowMixedValue = (column: ColumnType, index: number) => { |
||||
// Array of country names
|
||||
const countries = [ |
||||
'Afghanistan', |
||||
'Albania', |
||||
'', |
||||
'Andorra', |
||||
'Angola', |
||||
'Antigua and Barbuda', |
||||
'Argentina', |
||||
null, |
||||
'Armenia', |
||||
'Australia', |
||||
'Austria', |
||||
'', |
||||
null, |
||||
]; |
||||
|
||||
// Array of sample random paragraphs (comma separated list of cities and countries). Not more than 200 characters
|
||||
const longText = [ |
||||
'Aberdeen, United Kingdom', |
||||
'Abidjan, Côte d’Ivoire', |
||||
'Abuja, Nigeria', |
||||
'', |
||||
'Addis Ababa, Ethiopia', |
||||
'Adelaide, Australia', |
||||
'Ahmedabad, India', |
||||
'Albuquerque, United States', |
||||
null, |
||||
'Alexandria, Egypt', |
||||
'Algiers, Algeria', |
||||
'Allahabad, India', |
||||
'', |
||||
null, |
||||
]; |
||||
|
||||
// Array of random integers, not more than 10000
|
||||
const numbers = [33, null, 456, 333, 267, 34, 8754, 3234, 44, 33, null]; |
||||
const decimals = [33.3, 456.34, 333.3, null, 267.5674, 34.0, 8754.0, 3234.547, 44.2647, 33.98, null]; |
||||
const duration = [10, 20, 30, 40, 50, 60, null, 70, 80, 90, null]; |
||||
const rating = [0, 1, 2, 3, null, 0, 4, 5, 0, 1, null]; |
||||
|
||||
// Array of random sample email strings (not more than 100 characters)
|
||||
const emails = [ |
||||
'jbutt@gmail.com', |
||||
'josephine_darakjy@darakjy.org', |
||||
'art@venere.org', |
||||
'', |
||||
null, |
||||
'donette.foller@cox.net', |
||||
'simona@morasca.com', |
||||
'mitsue_tollner@yahoo.com', |
||||
'leota@hotmail.com', |
||||
'sage_wieser@cox.net', |
||||
'', |
||||
null, |
||||
]; |
||||
|
||||
// Array of random sample phone numbers
|
||||
const phoneNumbers = [ |
||||
'1-541-754-3010', |
||||
'504-621-8927', |
||||
'810-292-9388', |
||||
'856-636-8749', |
||||
'907-385-4412', |
||||
'513-570-1893', |
||||
'419-503-2484', |
||||
'773-573-6914', |
||||
'', |
||||
null, |
||||
]; |
||||
|
||||
// Array of random sample URLs
|
||||
const urls = [ |
||||
'https://www.google.com', |
||||
'https://www.facebook.com', |
||||
'https://www.youtube.com', |
||||
'https://www.amazon.com', |
||||
'https://www.wikipedia.org', |
||||
'https://www.twitter.com', |
||||
'https://www.instagram.com', |
||||
'https://www.linkedin.com', |
||||
'https://www.reddit.com', |
||||
'https://www.tiktok.com', |
||||
'https://www.pinterest.com', |
||||
'https://www.netflix.com', |
||||
'https://www.microsoft.com', |
||||
'https://www.apple.com', |
||||
'', |
||||
null, |
||||
]; |
||||
|
||||
const singleSelect = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec', null]; |
||||
|
||||
const multiSelect = ['jan,feb,mar', 'apr,may,jun', 'jul,aug,sep', 'oct,nov,dec', 'jan,feb,mar', null]; |
||||
|
||||
switch (column.uidt) { |
||||
case UITypes.Number: |
||||
case UITypes.Percent: |
||||
return numbers[index % numbers.length]; |
||||
case UITypes.Decimal: |
||||
case UITypes.Currency: |
||||
return decimals[index % decimals.length]; |
||||
case UITypes.Duration: |
||||
return duration[index % duration.length]; |
||||
case UITypes.Rating: |
||||
return rating[index % rating.length]; |
||||
case UITypes.SingleLineText: |
||||
return countries[index % countries.length]; |
||||
case UITypes.Email: |
||||
return emails[index % emails.length]; |
||||
case UITypes.PhoneNumber: |
||||
return phoneNumbers[index % phoneNumbers.length]; |
||||
case UITypes.LongText: |
||||
return longText[index % longText.length]; |
||||
case UITypes.Date: |
||||
return '2020-01-01'; |
||||
case UITypes.URL: |
||||
return urls[index % urls.length]; |
||||
case UITypes.SingleSelect: |
||||
return singleSelect[index % singleSelect.length]; |
||||
case UITypes.MultiSelect: |
||||
return multiSelect[index % multiSelect.length]; |
||||
default: |
||||
return `test-${index}`; |
||||
} |
||||
}; |
||||
|
||||
export { rowMixedValue }; |
@ -0,0 +1,417 @@
|
||||
import { test } from '@playwright/test'; |
||||
import { DashboardPage } from '../pages/Dashboard'; |
||||
import setup from '../setup'; |
||||
import { ToolbarPage } from '../pages/Dashboard/common/Toolbar'; |
||||
import { UITypes } from 'nocodb-sdk'; |
||||
import { Api } from 'nocodb-sdk'; |
||||
import { rowMixedValue } from '../setup/xcdb-records'; |
||||
|
||||
let dashboard: DashboardPage, toolbar: ToolbarPage; |
||||
let context: any; |
||||
let api: Api<any>; |
||||
let records = []; |
||||
const skipList = { |
||||
Number: ['is null', 'is not null', 'is blank', 'is not blank'], |
||||
Decimal: ['is null', 'is not null', 'is blank', 'is not blank'], |
||||
Percent: ['is null', 'is not null', 'is blank', 'is not blank'], |
||||
Currency: ['is null', 'is not null', 'is blank', 'is not blank'], |
||||
Rating: ['is null', 'is not null', 'is blank', 'is not blank'], |
||||
}; |
||||
|
||||
// define validateRowArray function
|
||||
async function validateRowArray(param) { |
||||
const { rowCount } = param; |
||||
await dashboard.grid.verifyTotalRowCount({ count: rowCount }); |
||||
|
||||
// const { sequence, length, totalRowCount, column } = param;
|
||||
//
|
||||
// await dashboard.grid.verifyTotalRowCount({ count: totalRowCount });
|
||||
//
|
||||
// for (let j = 0; j < length; j++) {
|
||||
// await dashboard.grid.cell.verify({
|
||||
// index: j,
|
||||
// columnHeader: column,
|
||||
// value: sequence,
|
||||
// });
|
||||
// }
|
||||
} |
||||
|
||||
async function verifyFilter(param: { column: string; opType: string; value?: string; result: { rowCount: number } }) { |
||||
// if opType was included in skip list, skip it
|
||||
if (skipList[param.column]?.includes(param.opType)) { |
||||
return; |
||||
} |
||||
|
||||
await toolbar.clickFilter(); |
||||
await toolbar.filter.add({ |
||||
columnTitle: param.column, |
||||
opType: param.opType, |
||||
value: param.value, |
||||
isLocallySaved: false, |
||||
}); |
||||
await toolbar.clickFilter(); |
||||
|
||||
// verify filtered rows
|
||||
await validateRowArray({ |
||||
rowCount: param.result.rowCount, |
||||
}); |
||||
|
||||
// Reset filter
|
||||
await toolbar.filter.reset(); |
||||
} |
||||
|
||||
test.describe('Filter Tests: Numerical', () => { |
||||
test.beforeEach(async ({ page }) => { |
||||
context = await setup({ page }); |
||||
dashboard = new DashboardPage(page, context.project); |
||||
toolbar = dashboard.grid.toolbar; |
||||
|
||||
api = new Api({ |
||||
baseURL: `http://localhost:8080/`, |
||||
headers: { |
||||
'xc-auth': context.token, |
||||
}, |
||||
}); |
||||
|
||||
const columns = [ |
||||
{ |
||||
column_name: 'Id', |
||||
title: 'Id', |
||||
uidt: UITypes.ID, |
||||
}, |
||||
{ |
||||
column_name: 'Number', |
||||
title: 'Number', |
||||
uidt: UITypes.Number, |
||||
}, |
||||
{ |
||||
column_name: 'Decimal', |
||||
title: 'Decimal', |
||||
uidt: UITypes.Decimal, |
||||
}, |
||||
{ |
||||
column_name: 'Currency', |
||||
title: 'Currency', |
||||
uidt: UITypes.Currency, |
||||
}, |
||||
{ |
||||
column_name: 'Percent', |
||||
title: 'Percent', |
||||
uidt: UITypes.Percent, |
||||
}, |
||||
{ |
||||
column_name: 'Duration', |
||||
title: 'Duration', |
||||
uidt: UITypes.Duration, |
||||
}, |
||||
{ |
||||
column_name: 'Rating', |
||||
title: 'Rating', |
||||
uidt: UITypes.Rating, |
||||
}, |
||||
]; |
||||
|
||||
try { |
||||
const project = await api.project.read(context.project.id); |
||||
const table = await api.base.tableCreate(context.project.id, project.bases?.[0].id, { |
||||
table_name: 'numberBased', |
||||
title: 'numberBased', |
||||
columns: columns, |
||||
}); |
||||
|
||||
const rowAttributes = []; |
||||
for (let i = 0; i < 400; i++) { |
||||
const row = { |
||||
Number: rowMixedValue(columns[1], i), |
||||
Decimal: rowMixedValue(columns[2], i), |
||||
Currency: rowMixedValue(columns[3], i), |
||||
Percent: rowMixedValue(columns[4], i), |
||||
Duration: rowMixedValue(columns[5], i), |
||||
Rating: rowMixedValue(columns[6], i), |
||||
}; |
||||
rowAttributes.push(row); |
||||
} |
||||
|
||||
await api.dbTableRow.bulkCreate('noco', context.project.id, table.id, rowAttributes); |
||||
records = await api.dbTableRow.list('noco', context.project.id, table.id, { limit: 400 }); |
||||
} catch (e) { |
||||
console.error(e); |
||||
} |
||||
}); |
||||
|
||||
test('Filter: Number', async () => { |
||||
// close 'Team & Auth' tab
|
||||
await dashboard.closeTab({ title: 'Team & Auth' }); |
||||
await dashboard.treeView.openTable({ title: 'numberBased' }); |
||||
const dataType = 'Number'; |
||||
|
||||
const filterList = [ |
||||
{ |
||||
op: '=', |
||||
value: '33', |
||||
rowCount: records.list.filter(r => r[dataType] === 33).length, |
||||
}, |
||||
{ |
||||
op: '!=', |
||||
value: '33', |
||||
rowCount: records.list.filter(r => r[dataType] !== 33).length, |
||||
}, |
||||
{ |
||||
op: 'is null', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] === null).length, |
||||
}, |
||||
{ |
||||
op: 'is not null', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] !== null).length, |
||||
}, |
||||
{ |
||||
op: 'is blank', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] === null).length, |
||||
}, |
||||
{ |
||||
op: 'is not blank', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] !== null).length, |
||||
}, |
||||
{ |
||||
op: '>', |
||||
value: '44', |
||||
rowCount: records.list.filter(r => r[dataType] > 44 && r[dataType] != null).length, |
||||
}, |
||||
{ |
||||
op: '>=', |
||||
value: '44', |
||||
rowCount: records.list.filter(r => r[dataType] >= 44 && r[dataType] != null).length, |
||||
}, |
||||
{ |
||||
op: '<', |
||||
value: '44', |
||||
rowCount: records.list.filter(r => r[dataType] < 44 && r[dataType] != null).length, |
||||
}, |
||||
{ |
||||
op: '<=', |
||||
value: '44', |
||||
rowCount: records.list.filter(r => r[dataType] <= 44 && r[dataType] != null).length, |
||||
}, |
||||
]; |
||||
|
||||
for (let i = 0; i < filterList.length; i++) { |
||||
await verifyFilter({ |
||||
column: dataType, |
||||
opType: filterList[i].op, |
||||
value: filterList[i].value, |
||||
result: { rowCount: filterList[i].rowCount }, |
||||
}); |
||||
} |
||||
}); |
||||
|
||||
test('Filter: Decimal', async () => { |
||||
// close 'Team & Auth' tab
|
||||
await dashboard.closeTab({ title: 'Team & Auth' }); |
||||
await dashboard.treeView.openTable({ title: 'numberBased' }); |
||||
const dataType = 'Decimal'; |
||||
|
||||
const filterList = [ |
||||
{ |
||||
op: '=', |
||||
value: '33.3', |
||||
rowCount: records.list.filter(r => r[dataType] === 33.3).length, |
||||
}, |
||||
{ |
||||
op: '!=', |
||||
value: '33.3', |
||||
rowCount: records.list.filter(r => r[dataType] !== 33.3).length, |
||||
}, |
||||
{ |
||||
op: 'is null', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] === null).length, |
||||
}, |
||||
{ |
||||
op: 'is not null', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] !== null).length, |
||||
}, |
||||
{ |
||||
op: 'is blank', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] === null).length, |
||||
}, |
||||
{ |
||||
op: 'is not blank', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] !== null).length, |
||||
}, |
||||
{ |
||||
op: '>', |
||||
value: '44.26', |
||||
rowCount: records.list.filter(r => r[dataType] > 44.26 && r[dataType] != null).length, |
||||
}, |
||||
{ |
||||
op: '>=', |
||||
value: '44.26', |
||||
rowCount: records.list.filter(r => r[dataType] >= 44.26 && r[dataType] != null).length, |
||||
}, |
||||
{ |
||||
op: '<', |
||||
value: '44.26', |
||||
rowCount: records.list.filter(r => r[dataType] < 44.26 && r[dataType] != null).length, |
||||
}, |
||||
{ |
||||
op: '<=', |
||||
value: '44.26', |
||||
rowCount: records.list.filter(r => r[dataType] <= 44.26 && r[dataType] != null).length, |
||||
}, |
||||
]; |
||||
|
||||
for (let i = 0; i < filterList.length; i++) { |
||||
await verifyFilter({ |
||||
column: dataType, |
||||
opType: filterList[i].op, |
||||
value: filterList[i].value, |
||||
result: { rowCount: filterList[i].rowCount }, |
||||
}); |
||||
} |
||||
}); |
||||
|
||||
test('Filter: Percent', async () => { |
||||
// close 'Team & Auth' tab
|
||||
await dashboard.closeTab({ title: 'Team & Auth' }); |
||||
await dashboard.treeView.openTable({ title: 'numberBased' }); |
||||
const dataType = 'Percent'; |
||||
|
||||
const filterList = [ |
||||
{ |
||||
op: '=', |
||||
value: '33', |
||||
rowCount: records.list.filter(r => r[dataType] === 33).length, |
||||
}, |
||||
{ |
||||
op: '!=', |
||||
value: '33', |
||||
rowCount: records.list.filter(r => r[dataType] !== 33).length, |
||||
}, |
||||
{ |
||||
op: 'is null', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] === null).length, |
||||
}, |
||||
{ |
||||
op: 'is not null', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] !== null).length, |
||||
}, |
||||
{ |
||||
op: 'is blank', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] === null).length, |
||||
}, |
||||
{ |
||||
op: 'is not blank', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] !== null).length, |
||||
}, |
||||
{ |
||||
op: '>', |
||||
value: '44', |
||||
rowCount: records.list.filter(r => r[dataType] > 44 && r[dataType] != null).length, |
||||
}, |
||||
{ |
||||
op: '>=', |
||||
value: '44', |
||||
rowCount: records.list.filter(r => r[dataType] >= 44 && r[dataType] != null).length, |
||||
}, |
||||
{ |
||||
op: '<', |
||||
value: '44', |
||||
rowCount: records.list.filter(r => r[dataType] < 44 && r[dataType] != null).length, |
||||
}, |
||||
{ |
||||
op: '<=', |
||||
value: '44', |
||||
rowCount: records.list.filter(r => r[dataType] <= 44 && r[dataType] != null).length, |
||||
}, |
||||
]; |
||||
|
||||
for (let i = 0; i < filterList.length; i++) { |
||||
await verifyFilter({ |
||||
column: dataType, |
||||
opType: filterList[i].op, |
||||
value: filterList[i].value, |
||||
result: { rowCount: filterList[i].rowCount }, |
||||
}); |
||||
} |
||||
}); |
||||
|
||||
test('Filter: Currency', async () => { |
||||
// close 'Team & Auth' tab
|
||||
await dashboard.closeTab({ title: 'Team & Auth' }); |
||||
await dashboard.treeView.openTable({ title: 'numberBased' }); |
||||
const dataType = 'Currency'; |
||||
|
||||
const filterList = [ |
||||
{ |
||||
op: '=', |
||||
value: '33.3', |
||||
rowCount: records.list.filter(r => r[dataType] === 33.3).length, |
||||
}, |
||||
{ |
||||
op: '!=', |
||||
value: '33.3', |
||||
rowCount: records.list.filter(r => r[dataType] !== 33.3).length, |
||||
}, |
||||
{ |
||||
op: 'is null', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] === null).length, |
||||
}, |
||||
{ |
||||
op: 'is not null', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] !== null).length, |
||||
}, |
||||
{ |
||||
op: 'is blank', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] === null).length, |
||||
}, |
||||
{ |
||||
op: 'is not blank', |
||||
value: '', |
||||
rowCount: records.list.filter(r => r[dataType] !== null).length, |
||||
}, |
||||
{ |
||||
op: '>', |
||||
value: '44.26', |
||||
rowCount: records.list.filter(r => r[dataType] > 44.26 && r[dataType] != null).length, |
||||
}, |
||||
{ |
||||
op: '>=', |
||||
value: '44.26', |
||||
rowCount: records.list.filter(r => r[dataType] >= 44.26 && r[dataType] != null).length, |
||||
}, |
||||
{ |
||||
op: '<', |
||||
value: '44.26', |
||||
rowCount: records.list.filter(r => r[dataType] < 44.26 && r[dataType] != null).length, |
||||
}, |
||||
{ |
||||
op: '<=', |
||||
value: '44.26', |
||||
rowCount: records.list.filter(r => r[dataType] <= 44.26 && r[dataType] != null).length, |
||||
}, |
||||
]; |
||||
|
||||
for (let i = 0; i < filterList.length; i++) { |
||||
await verifyFilter({ |
||||
column: dataType, |
||||
opType: filterList[i].op, |
||||
value: filterList[i].value, |
||||
result: { rowCount: filterList[i].rowCount }, |
||||
}); |
||||
} |
||||
}); |
||||
}); |
Loading…
Reference in new issue