Browse Source

test: bulk update (draft)

Signed-off-by: Raju Udava <86527202+dstala@users.noreply.github.com>
test/pw-duplicate-check
Raju Udava 1 year ago
parent
commit
bb3910efc4
  1. 3
      packages/nc-gui/components/dlg/BulkUpdate.vue
  2. 143
      tests/playwright/pages/Dashboard/BulkUpdate/index.ts
  3. 13
      tests/playwright/pages/Dashboard/Grid/index.ts
  4. 3
      tests/playwright/pages/Dashboard/index.ts
  5. 76
      tests/playwright/tests/db/bulkUpdate.spec.ts

3
packages/nc-gui/components/dlg/BulkUpdate.vue

@ -187,7 +187,7 @@ onMounted(() => {
class="nc-drawer-bulk-update" class="nc-drawer-bulk-update"
:class="{ active: isExpanded }" :class="{ active: isExpanded }"
> >
<div class="flex p-2 items-center gap-2 p-4 nc-expanded-form-header"> <div class="flex p-2 items-center gap-2 p-4 nc-bulk-update-form-header">
<h5 class="text-lg font-weight-medium flex items-center gap-1 mb-0 min-w-0 overflow-x-hidden truncate"> <h5 class="text-lg font-weight-medium flex items-center gap-1 mb-0 min-w-0 overflow-x-hidden truncate">
<GeneralTableIcon :style="{ color: iconColor }" :meta="meta" class="mx-2" /> <GeneralTableIcon :style="{ color: iconColor }" :meta="meta" class="mx-2" />
@ -251,6 +251,7 @@ onMounted(() => {
<component <component
:is="iconMap.closeCircle" :is="iconMap.closeCircle"
class="group-hover:text-red-500 cursor-pointer text-4xl" class="group-hover:text-red-500 cursor-pointer text-4xl"
data-testid="nc-form-fields-close-icon"
@click="handleRemove(element)" @click="handleRemove(element)"
/> />
</div> </div>

143
tests/playwright/pages/Dashboard/BulkUpdate/index.ts

@ -0,0 +1,143 @@
import { expect, Locator } from '@playwright/test';
import BasePage from '../../Base';
import { DashboardPage } from '..';
import { DateTimeCellPageObject } from '../common/Cell/DateTimeCell';
import { getTextExcludeIconText } from '../../../tests/utils/general';
export class BulkUpdatePage extends BasePage {
readonly dashboard: DashboardPage;
readonly bulkUpdateButton: Locator;
readonly formHeader: Locator;
readonly columnsDrawer: Locator;
readonly form: Locator;
constructor(dashboard: DashboardPage) {
super(dashboard.rootPage);
this.dashboard = dashboard;
this.bulkUpdateButton = this.dashboard.get().locator('.nc-bulk-update-save-btn');
this.formHeader = this.dashboard.get().locator('.nc-bulk-update-form-header');
this.columnsDrawer = this.dashboard.get().locator('.nc-columns-drawer');
this.form = this.dashboard.get().locator('div.form');
}
get() {
return this.dashboard.get().locator(`.nc-drawer-bulk-update`);
}
async close() {
return this.dashboard.rootPage.keyboard.press('Escape');
}
async getInactiveColumn(index: number) {
const inactiveColumns = await this.columnsDrawer.locator('.ant-card');
return inactiveColumns.nth(index);
}
async getActiveColumn(index: number) {
const activeColumns = await this.form.locator('[data-testid="nc-form-fields"]');
return activeColumns.nth(index);
}
async getInactiveColumns() {
const inactiveColumns = await this.columnsDrawer.locator('.ant-card');
const inactiveColumnsCount = await inactiveColumns.count();
const inactiveColumnsTitles = [];
// get title for each inactive column
for (let i = 0; i < inactiveColumnsCount; i++) {
const title = await getTextExcludeIconText(inactiveColumns.nth(i).locator('.ant-card-body'));
inactiveColumnsTitles.push(title);
}
return inactiveColumnsTitles;
}
async getActiveColumns() {
const activeColumns = await this.form.locator('[data-testid="nc-form-fields"]');
const activeColumnsCount = await activeColumns.count();
const activeColumnsTitles = [];
// get title for each active column
for (let i = 0; i < activeColumnsCount; i++) {
const title = await getTextExcludeIconText(activeColumns.nth(i).locator('[data-testid="nc-form-input-label"]'));
activeColumnsTitles.push(title);
}
return activeColumnsTitles;
}
async removeField(index: number) {
const removeFieldButton = await this.form.locator('[data-testid="nc-form-fields"]');
const removeFieldButtonCount = await removeFieldButton.count();
await removeFieldButton.nth(index).locator('[data-testid="nc-form-fields-close-icon"]').click();
const newRemoveFieldButtonCount = await removeFieldButton.count();
expect(newRemoveFieldButtonCount).toBe(removeFieldButtonCount - 1);
}
async addField(index: number) {
const addFieldButton = await this.columnsDrawer.locator('.ant-card');
const addFieldButtonCount = await addFieldButton.count();
await addFieldButton.nth(index).click();
const newAddFieldButtonCount = await addFieldButton.count();
expect(newAddFieldButtonCount).toBe(addFieldButtonCount - 1);
}
//////////////////////////////////////////////////////////////////////////////
async fillField({ columnTitle, value, type = 'text' }: { columnTitle: string; value: string; type?: string }) {
const field = this.form.locator(`[data-testid="nc-form-input-${columnTitle}"]`);
await field.hover();
switch (type) {
case 'text':
await field.locator('input').fill(value);
break;
case 'geodata': {
const [lat, long] = value.split(',');
await this.rootPage.locator(`[data-testid="nc-geo-data-set-location-button"]`).click();
await this.rootPage.locator(`[data-testid="nc-geo-data-latitude"]`).fill(lat);
await this.rootPage.locator(`[data-testid="nc-geo-data-longitude"]`).fill(long);
await this.rootPage.locator(`[data-testid="nc-geo-data-save"]`).click();
break;
}
case 'belongsTo':
await field.locator('.nc-action-icon').click();
await this.dashboard.linkRecord.select(value);
break;
case 'hasMany':
case 'manyToMany':
await field.locator(`[data-testid="nc-child-list-button-link-to"]`).click();
await this.dashboard.linkRecord.select(value);
break;
case 'dateTime':
await field.locator('.nc-cell').click();
// eslint-disable-next-line no-case-declarations
const dateTimeObj = new DateTimeCellPageObject(this.dashboard.grid.cell);
await dateTimeObj.selectDate({ date: value.slice(0, 10) });
await dateTimeObj.selectTime({ hour: +value.slice(11, 13), minute: +value.slice(14, 16) });
await dateTimeObj.save();
break;
}
}
async save({
awaitResponse = true,
}: {
awaitResponse?: boolean;
} = {}) {
await this.bulkUpdateButton.click();
const confirmModal = await this.rootPage.locator('.ant-modal-confirm');
const saveRowAction = () => confirmModal.locator('.ant-btn-primary').click();
if (!awaitResponse) {
await saveRowAction();
} else {
await this.waitForResponse({
uiAction: saveRowAction,
requestUrlPathToMatch: 'api/v1/db/data/noco/',
httpMethodsToMatch: ['GET'],
responseJsonMatcher: json => json['pageInfo'],
});
}
await this.get().waitFor({ state: 'hidden' });
await this.rootPage.locator('[data-testid="grid-load-spinner"]').waitFor({ state: 'hidden' });
}
}

13
tests/playwright/pages/Dashboard/Grid/index.ts

@ -220,6 +220,19 @@ export class GridPage extends BasePage {
await this.deleteSelectedRows(); await this.deleteSelectedRows();
} }
async updateSelectedRows() {
await this.get().locator('[data-testid="nc-check-all"]').nth(0).click({
button: 'right',
});
await this.rootPage.locator('text=Bulk Update').click();
await this.dashboard.waitForLoaderToDisappear();
}
async updateAll() {
await this.selectAll();
await this.updateSelectedRows();
}
async verifyTotalRowCount({ count }: { count: number }) { async verifyTotalRowCount({ count }: { count: number }) {
// wait for 100 ms and try again : 5 times // wait for 100 ms and try again : 5 times
let i = 0; let i = 0;

3
tests/playwright/pages/Dashboard/index.ts

@ -3,6 +3,7 @@ import BasePage from '../Base';
import { GridPage } from './Grid'; import { GridPage } from './Grid';
import { FormPage } from './Form'; import { FormPage } from './Form';
import { ExpandedFormPage } from './ExpandedForm'; import { ExpandedFormPage } from './ExpandedForm';
import { BulkUpdatePage } from './BulkUpdate';
import { ChildList } from './Grid/Column/LTAR/ChildList'; import { ChildList } from './Grid/Column/LTAR/ChildList';
import { LinkRecord } from './Grid/Column/LTAR/LinkRecord'; import { LinkRecord } from './Grid/Column/LTAR/LinkRecord';
import { TreeViewPage } from './TreeView'; import { TreeViewPage } from './TreeView';
@ -29,6 +30,7 @@ export class DashboardPage extends BasePage {
readonly kanban: KanbanPage; readonly kanban: KanbanPage;
readonly map: MapPage; readonly map: MapPage;
readonly expandedForm: ExpandedFormPage; readonly expandedForm: ExpandedFormPage;
readonly bulkUpdateForm: BulkUpdatePage;
readonly webhookForm: WebhookFormPage; readonly webhookForm: WebhookFormPage;
readonly findRowByScanOverlay: FindRowByScanOverlay; readonly findRowByScanOverlay: FindRowByScanOverlay;
readonly childList: ChildList; readonly childList: ChildList;
@ -51,6 +53,7 @@ export class DashboardPage extends BasePage {
this.kanban = new KanbanPage(this); this.kanban = new KanbanPage(this);
this.map = new MapPage(this); this.map = new MapPage(this);
this.expandedForm = new ExpandedFormPage(this); this.expandedForm = new ExpandedFormPage(this);
this.bulkUpdateForm = new BulkUpdatePage(this);
this.webhookForm = new WebhookFormPage(this); this.webhookForm = new WebhookFormPage(this);
this.findRowByScanOverlay = new FindRowByScanOverlay(this); this.findRowByScanOverlay = new FindRowByScanOverlay(this);
this.childList = new ChildList(this); this.childList = new ChildList(this);

76
tests/playwright/tests/db/bulkUpdate.spec.ts

@ -0,0 +1,76 @@
import { expect, test } from '@playwright/test';
import setup from '../../setup';
import { DashboardPage } from '../../pages/Dashboard';
import { Api } from 'nocodb-sdk';
import { createDemoTable } from '../../setup/demoTable';
import { BulkUpdatePage } from '../../pages/Dashboard/BulkUpdate';
test.describe('Bulk update', () => {
let dashboard: DashboardPage;
let bulkUpdateForm: BulkUpdatePage;
let context: any;
let api: Api<any>;
let records: any[];
test.beforeEach(async ({ page }) => {
context = await setup({ page, isEmptyProject: true });
dashboard = new DashboardPage(page, context.project);
bulkUpdateForm = dashboard.bulkUpdateForm;
api = new Api({
baseURL: `http://localhost:8080/`,
headers: {
'xc-auth': context.token,
},
});
const table = await createDemoTable({ context, type: 'textBased', recordCnt: 50 });
records = await api.dbTableRow.list('noco', context.project.id, table.id, { limit: 50 });
await page.reload();
await dashboard.closeTab({ title: 'Team & Auth' });
await dashboard.treeView.openTable({ title: 'textBased' });
// Open bulk update form
await dashboard.grid.updateAll();
});
test('General- Click to add & remove', async () => {
let inactiveColumns = await bulkUpdateForm.getInactiveColumns();
expect(inactiveColumns).toEqual(['SingleLineText', 'MultiLineText', 'Email', 'PhoneNumber', 'URL']);
let activeColumns = await bulkUpdateForm.getActiveColumns();
expect(activeColumns).toEqual([]);
await bulkUpdateForm.addField(0);
await bulkUpdateForm.addField(0);
inactiveColumns = await bulkUpdateForm.getInactiveColumns();
expect(inactiveColumns).toEqual(['Email', 'PhoneNumber', 'URL']);
activeColumns = await bulkUpdateForm.getActiveColumns();
expect(activeColumns).toEqual(['SingleLineText', 'MultiLineText']);
});
test('General- Drag drop', async () => {
const src = await bulkUpdateForm.getInactiveColumn(0);
const dst = await bulkUpdateForm.form;
await src.dragTo(dst);
expect(await bulkUpdateForm.getActiveColumns()).toEqual(['SingleLineText']);
expect(await bulkUpdateForm.getInactiveColumns()).toEqual(['MultiLineText', 'Email', 'PhoneNumber', 'URL']);
const src2 = await bulkUpdateForm.getActiveColumn(0);
const dst2 = await bulkUpdateForm.columnsDrawer;
await src2.dragTo(dst2);
expect(await bulkUpdateForm.getActiveColumns()).toEqual([]);
expect(await bulkUpdateForm.getInactiveColumns()).toEqual([
'SingleLineText',
'MultiLineText',
'Email',
'PhoneNumber',
'URL',
]);
});
});
Loading…
Cancel
Save