Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pw formula tests, check formula not supported error #7273

Merged
merged 1 commit into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 10 additions & 2 deletions tests/playwright/pages/Base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Locator, Page } from '@playwright/test';
import { expect, Locator, Page } from '@playwright/test';
import { readFileSync } from 'fs';

type ResponseSelector = (json: any) => boolean;
Expand All @@ -16,6 +16,12 @@ export default abstract class BasePage {
await this.rootPage.locator('.ant-message .ant-message-notice-content', { hasText: message }).last().isVisible();
}

async verifyLastToast({ message }: { message: string }) {
await expect(
this.rootPage.locator('.ant-message .ant-message-notice-content', { hasText: message }).last()
).toHaveText(message);
}

async waitForResponse({
// Playwright action that triggers the request i.e locatorSomething.click()
uiAction,
Expand All @@ -24,18 +30,20 @@ export default abstract class BasePage {
// A function that takes the response body and returns true if the response is the one we are looking for
responseJsonMatcher,
timeout,
responseStatusCodeToMatch = 200,
}: {
uiAction: () => Promise<any>;
requestUrlPathToMatch: string;
httpMethodsToMatch?: string[];
responseJsonMatcher?: ResponseSelector;
timeout?: number;
responseStatusCodeToMatch?: number;
}) {
const [res] = await Promise.all([
this.rootPage.waitForResponse(
res =>
res.url().includes(requestUrlPathToMatch) &&
res.status() === 200 &&
res.status() === responseStatusCodeToMatch &&
httpMethodsToMatch.includes(res.request().method()),
timeout ? { timeout } : undefined
),
Expand Down
14 changes: 14 additions & 0 deletions tests/playwright/pages/Dashboard/Grid/Column/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,20 @@ export class ColumnPageObject extends BasePage {
await this.rootPage.waitForTimeout(200);
}

async saveFail({ errorMessage }: { errorMessage?: string } = {}) {
await this.waitForResponse({
uiAction: async () => await this.get().locator('button:has-text("Save")').click(),
requestUrlPathToMatch: 'api/v1/db/meta',
httpMethodsToMatch: ['GET', 'PATCH'],
responseStatusCodeToMatch: 400,
});
await this.verifyLastToast({
message: errorMessage,
});
await this.get().waitFor({ state: 'visible' });
await this.rootPage.waitForTimeout(200);
}

async verify({ title, isVisible = true }: { title: string; isVisible?: boolean }) {
if (!isVisible) {
return await expect(this.getColumnHeader(title)).not.toBeVisible();
Expand Down
63 changes: 40 additions & 23 deletions tests/playwright/tests/db/columns/columnFormula.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { test } from '@playwright/test';
import { DashboardPage } from '../../../pages/Dashboard';
import setup, { NcContext, unsetup } from '../../../setup';
import { enableQuickRun, isPg, isSqlite } from '../../../setup/db';
import { enableQuickRun, isMysql, isPg, isSqlite } from '../../../setup/db';

// Add formula to be verified here & store expected results for 5 rows
// Column data from City table (Sakila DB)
Expand All @@ -19,6 +19,7 @@ const formulaDataByDbType = (context: NcContext, index: number) => {
{
formula: '1 + 1',
result: ['2', '2', '2', '2', '2'],
unSupDbType: [],
},
{
formula: 'ADD({CityId}, {CountryId}) + AVG({CityId}, {CountryId}) + LEN({City})',
Expand Down Expand Up @@ -92,6 +93,7 @@ const formulaDataByDbType = (context: NcContext, index: number) => {
{
formula: 'VALUE("12ab-c345")',
result: ['-12345', '-12345', '-12345', '-12345', '-12345'],
unSupDbType: ['sqlite3'],
},
{
formula: 'TRUE()',
Expand All @@ -101,19 +103,6 @@ const formulaDataByDbType = (context: NcContext, index: number) => {
formula: 'FALSE()',
result: ['0', '0', '0', '0', '0'],
},
{
formula: 'REGEX_MATCH({City}, "a[a-z]a")',
result: ['0', '0', '0', '0', '1'],
},
{
formula: 'REGEX_EXTRACT({City}, "a[a-z]a")',
result: ['', '', '', '', 'ana'],
},
{
formula: 'REGEX_REPLACE({City}, "a[a-z]a","...")',
result: ['A Corua (La Corua)', 'Abha', 'Abu Dhabi', 'Acua', 'Ad...'],
},

{
formula: '"City Name: " & {City}',
result: [
Expand All @@ -137,12 +126,30 @@ const formulaDataByDbType = (context: NcContext, index: number) => {
formula: 'RECORD_ID()',
result: ['1', '2', '3', '4', '5'],
},
{
formula: 'REGEX_MATCH({City}, "a[a-z]a")',
result: ['0', '0', '0', '0', '1'],
unSupDbType: ['sqlite3'],
},
{
// TODO: this is bug in mysql, its being case in-sensitive.
formula: 'REGEX_EXTRACT({City}, "a[a-z]a")',
result: ['', '', '', '', 'ana'],
unSupDbType: ['sqlite3'],
},
{
// TODO: this is bug in mysql, its being case in-sensitive.
formula: 'REGEX_REPLACE({City}, "a[a-z]a","...")',
result: ['A Corua (La Corua)', 'Abha', 'Abu Dhabi', 'Acua', 'Ad...'],
unSupDbType: ['sqlite3'],
},
];
else
return [
{
formula: `DATETIME_DIFF("2023/10/14", "2023/01/12", "y")`,
result: ['0', '0', '0', '0', '0'],
unSupDbType: [],
},
{
formula: `DATETIME_DIFF("2023-01-12", "2021-08-29", "y")`,
Expand Down Expand Up @@ -180,9 +187,16 @@ const formulaDataByDbType = (context: NcContext, index: number) => {
},
{
formula: `LOG({CityId}) + EXP({CityId}) + POWER({CityId}, 3) + SQRT({CountryId})`,
result: isPg(context)
? ['13.04566088154786', '24.74547123273205', '57.61253379902822', '126.94617671688704', '283.9609869087087']
: ['13.04566088154786', '25.137588417628013', '58.23402483297667', '127.73041108667896', '284.8714548168068'],
result:
isPg(context) || isSqlite(context)
? ['13.04566088154786', '24.74547123273205', '57.61253379902822', '126.94617671688704', '283.9609869087087']
: [
'13.04566088154786',
'25.137588417628013',
'58.23402483297667',
'127.73041108667896',
'284.8714548168068',
],
},
{
formula: `NOW()`,
Expand Down Expand Up @@ -245,26 +259,29 @@ test.describe('Virtual Columns', () => {
async function formulaTestSpec(index: number) {
// close 'Team & Auth' tab
const formulaData = formulaDataByDbType(context, index);
const dbType = context.base.sources[0].type;
await dashboard.closeTab({ title: 'Team & Auth' });

await dashboard.treeView.openTable({ title: 'City' });
// Create formula column
// Create dummy formula column which will then be updated for every testcase
await dashboard.grid.column.create({
title: 'NC_MATH_0',
type: 'Formula',
formula: formulaData[1].formula,
formula: '1 + 1',
});

// verify different formula's
for (let i = 1; i < formulaData.length; i++) {
// Sqlite does not support log function
if (isSqlite(context) && formulaData[i].formula.includes('LOG(')) continue;

for (let i = 0; i < formulaData.length; i++) {
await dashboard.grid.column.openEdit({
title: 'NC_MATH_0',
type: 'Formula',
formula: formulaData[i].formula,
});
if (formulaData[i].unSupDbType?.includes(dbType)) {
// assert for message not supported or greyed out save button.
await dashboard.grid.column.saveFail({ errorMessage: 'Invalid Formula' });
continue;
}
await dashboard.grid.column.save({ isUpdated: true });
if (formulaData[i].formula !== `NOW()`) {
await formulaResultVerify({
Expand Down