Browse Source

test: added multifield editor fieldPage class

pull/7408/head
Ramesh Mane 12 months ago
parent
commit
698482dbdd
  1. 56
      packages/nc-gui/components/smartsheet/details/Fields.vue
  2. 94
      tests/playwright/pages/Dashboard/Details/FieldsPage.ts

56
packages/nc-gui/components/smartsheet/details/Fields.vue

@ -916,7 +916,7 @@ watch(
toggleVisibility(event.target.checked, viewFieldsMap[field.id]) toggleVisibility(event.target.checked, viewFieldsMap[field.id])
} }
" "
data-testid="nc-field-checkbox" data-testid="nc-field-visibility-checkbox"
/> />
<NcCheckbox v-else :disabled="true" class="opacity-0" :checked="true" /> <NcCheckbox v-else :disabled="true" class="opacity-0" :checked="true" />
<SmartsheetHeaderVirtualCellIcon <SmartsheetHeaderVirtualCellIcon
@ -948,7 +948,13 @@ watch(
</div> </div>
<div class="flex items-center justify-end gap-1"> <div class="flex items-center justify-end gap-1">
<div class="nc-field-status-wrapper flex items-center"> <div class="nc-field-status-wrapper flex items-center">
<NcBadge v-if="fieldStatus(field) === 'delete'" color="red" :border="false" class="bg-red-50 text-red-700"> <NcBadge
v-if="fieldStatus(field) === 'delete'"
color="red"
:border="false"
class="bg-red-50 text-red-700"
data-testid="nc-field-status-deleted-field"
>
Deleted field Deleted field
</NcBadge> </NcBadge>
<NcBadge <NcBadge
@ -956,6 +962,7 @@ watch(
color="orange" color="orange"
:border="false" :border="false"
class="bg-green-50 text-green-700" class="bg-green-50 text-green-700"
data-testid="nc-field-status-new-field"
> >
New field New field
</NcBadge> </NcBadge>
@ -965,6 +972,7 @@ watch(
color="orange" color="orange"
:border="false" :border="false"
class="bg-orange-50 text-orange-700" class="bg-orange-50 text-orange-700"
data-testid="nc-field-status-updated-field"
> >
Updated field Updated field
</NcBadge> </NcBadge>
@ -973,6 +981,7 @@ watch(
color="yellow" color="yellow"
:border="false" :border="false"
class="ml-1 bg-yellow-50 text-yellow-700" class="ml-1 bg-yellow-50 text-yellow-700"
data-testid="nc-field-status-incomplete-configuration"
> >
Incomplete configuration Incomplete configuration
</NcBadge> </NcBadge>
@ -984,6 +993,7 @@ watch(
class="no-action mr-2" class="no-action mr-2"
:disabled="loading" :disabled="loading"
@click="recoverField(field)" @click="recoverField(field)"
data-testid="nc-field-restore-changes"
> >
<div class="flex items-center text-xs gap-1"> <div class="flex items-center text-xs gap-1">
<GeneralIcon icon="reload" /> <GeneralIcon icon="reload" />
@ -993,7 +1003,7 @@ watch(
<NcDropdown <NcDropdown
v-else v-else
:trigger="['click']" :trigger="['click']"
overlay-class-name="nc-dropdown-table-explorer" overlay-class-name="nc-field-item-action-dropdown nc-dropdown-table-explorer"
@update:visible="onFieldOptionUpdate" @update:visible="onFieldOptionUpdate"
@click.stop @click.stop
> >
@ -1005,7 +1015,7 @@ watch(
'!hover:(text-brand-700 bg-brand-100) !group-hover:(text-brand-500)': compareCols(field, activeField), '!hover:(text-brand-700 bg-brand-100) !group-hover:(text-brand-500)': compareCols(field, activeField),
'!hover:(text-gray-700 bg-gray-200) !group-hover:(text-gray-500)': !compareCols(field, activeField), '!hover:(text-gray-700 bg-gray-200) !group-hover:(text-gray-500)': !compareCols(field, activeField),
}" }"
data-testid="nc-table-explorer-dropdown-button" data-testid="nc-field-item-action-button"
> >
<GeneralIcon icon="threeDotVertical" class="no-action text-inherit" /> <GeneralIcon icon="threeDotVertical" class="no-action text-inherit" />
</NcButton> </NcButton>
@ -1019,6 +1029,7 @@ watch(
<div <div
class="flex flex-row px-3 py-2 w-46 justify-between items-center group hover:bg-gray-100 cursor-pointer" class="flex flex-row px-3 py-2 w-46 justify-between items-center group hover:bg-gray-100 cursor-pointer"
@click="onClickCopyFieldUrl(field)" @click="onClickCopyFieldUrl(field)"
data-testid="nc-field-item-action-copy-id"
> >
<div class="flex flex-row items-baseline gap-x-1 font-bold text-xs"> <div class="flex flex-row items-baseline gap-x-1 font-bold text-xs">
<div class="text-gray-600">{{ $t('labels.idColon') }}</div> <div class="text-gray-600">{{ $t('labels.idColon') }}</div>
@ -1036,19 +1047,37 @@ watch(
</template> </template>
<template v-if="!isLocked"> <template v-if="!isLocked">
<NcMenuItem key="table-explorer-duplicate" @click="duplicateField(field)"> <NcMenuItem
key="table-explorer-duplicate"
@click="duplicateField(field)"
data-testid="nc-field-item-action-duplicate"
>
<Icon class="iconify text-gray-800" icon="lucide:copy" /><span>Duplicate</span> <Icon class="iconify text-gray-800" icon="lucide:copy" /><span>Duplicate</span>
</NcMenuItem> </NcMenuItem>
<NcMenuItem v-if="!field.pv" key="table-explorer-insert-above" @click="addField(field, true)"> <NcMenuItem
v-if="!field.pv"
key="table-explorer-insert-above"
@click="addField(field, true)"
data-testid="nc-field-item-action-insert-above"
>
<Icon class="iconify text-gray-800" icon="lucide:arrow-up" /><span>Insert above</span> <Icon class="iconify text-gray-800" icon="lucide:arrow-up" /><span>Insert above</span>
</NcMenuItem> </NcMenuItem>
<NcMenuItem key="table-explorer-insert-below" @click="addField(field)"> <NcMenuItem
key="table-explorer-insert-below"
@click="addField(field)"
data-testid="nc-field-item-action-insert-below"
>
<Icon class="iconify text-gray-800" icon="lucide:arrow-down" /><span>Insert below</span> <Icon class="iconify text-gray-800" icon="lucide:arrow-down" /><span>Insert below</span>
</NcMenuItem> </NcMenuItem>
<a-menu-divider class="my-1.5" /> <a-menu-divider class="my-1.5" />
<NcMenuItem key="table-explorer-delete" class="!hover:bg-red-50" @click="onFieldDelete(field)"> <NcMenuItem
key="table-explorer-delete"
class="!hover:bg-red-50"
@click="onFieldDelete(field)"
data-testid="nc-field-item-action-delete"
>
<div class="text-red-500"> <div class="text-red-500">
<GeneralIcon icon="delete" class="group-hover:text-accent -ml-0.25 -mt-0.75 mr-0.5" /> <GeneralIcon icon="delete" class="group-hover:text-accent -ml-0.25 -mt-0.75 mr-0.5" />
Delete Delete
@ -1086,7 +1115,7 @@ watch(
'opacity-0 !cursor-default': isLocked, 'opacity-0 !cursor-default': isLocked,
}" }"
/> />
<NcCheckbox :disabled="true" :checked="true" /> <NcCheckbox :disabled="true" :checked="true" data-testid="nc-field-visibility-checkbox" />
<SmartsheetHeaderCellIcon <SmartsheetHeaderCellIcon
v-if="displayColumn" v-if="displayColumn"
:column-meta="fieldState(displayColumn) || displayColumn" :column-meta="fieldState(displayColumn) || displayColumn"
@ -1102,7 +1131,7 @@ watch(
show-on-truncate-only show-on-truncate-only
> >
<template #title> {{ fieldState(displayColumn)?.title || displayColumn.title }} </template> <template #title> {{ fieldState(displayColumn)?.title || displayColumn.title }} </template>
<span> <span data-testid="nc-field-title">
{{ fieldState(displayColumn)?.title || displayColumn.title }} {{ fieldState(displayColumn)?.title || displayColumn.title }}
</span> </span>
</NcTooltip> </NcTooltip>
@ -1114,6 +1143,7 @@ watch(
color="red" color="red"
:border="false" :border="false"
class="bg-red-50 text-red-700" class="bg-red-50 text-red-700"
data-testid="nc-field-status-deleted-field"
> >
Deleted field Deleted field
</NcBadge> </NcBadge>
@ -1123,6 +1153,7 @@ watch(
color="orange" color="orange"
:border="false" :border="false"
class="bg-orange-50 text-orange-700" class="bg-orange-50 text-orange-700"
data-testid="nc-field-status-updated-field"
> >
Updated field Updated field
</NcBadge> </NcBadge>
@ -1134,6 +1165,7 @@ watch(
class="no-action mr-2" class="no-action mr-2"
:disabled="loading" :disabled="loading"
@click="recoverField(displayColumn)" @click="recoverField(displayColumn)"
data-testid="nc-field-restore-changes"
> >
<div class="flex items-center text-xs gap-1"> <div class="flex items-center text-xs gap-1">
<GeneralIcon icon="reload" /> <GeneralIcon icon="reload" />
@ -1143,7 +1175,7 @@ watch(
<NcDropdown <NcDropdown
v-else v-else
:trigger="['click']" :trigger="['click']"
overlay-class-name="nc-dropdown-table-explorer-display-column" overlay-class-name="nc-field-item-action-dropdown-display-column nc-dropdown-table-explorer-display-column"
@update:visible="onFieldOptionUpdate" @update:visible="onFieldOptionUpdate"
@click.stop @click.stop
> >
@ -1161,6 +1193,7 @@ watch(
activeField, activeField,
), ),
}" }"
data-testid="nc-field-item-action-button"
> >
<GeneralIcon icon="threeDotVertical" class="no-action text-inherit" /> <GeneralIcon icon="threeDotVertical" class="no-action text-inherit" />
</NcButton> </NcButton>
@ -1173,6 +1206,7 @@ watch(
<div <div
class="flex flex-row px-3 py-2 w-46 justify-between items-center group hover:bg-gray-100 cursor-pointer" class="flex flex-row px-3 py-2 w-46 justify-between items-center group hover:bg-gray-100 cursor-pointer"
@click="onClickCopyFieldUrl(displayColumn)" @click="onClickCopyFieldUrl(displayColumn)"
data-testid="nc-field-item-action-copy-id"
> >
<div class="flex flex-row items-baseline gap-x-1 font-bold text-xs"> <div class="flex flex-row items-baseline gap-x-1 font-bold text-xs">
<div class="text-gray-600">{{ $t('labels.idColon') }}</div> <div class="text-gray-600">{{ $t('labels.idColon') }}</div>

94
tests/playwright/pages/Dashboard/Details/FieldsPage.ts

@ -31,7 +31,6 @@ export class FieldsPage extends BasePage {
async clickNewField() { async clickNewField() {
await this.addNewFieldButton.click(); await this.addNewFieldButton.click();
await this.addOrEditColumn.waitFor({ state: 'visible' });
} }
async create({ async create({
@ -68,17 +67,9 @@ export class FieldsPage extends BasePage {
insertBelowColumnTitle?: string; insertBelowColumnTitle?: string;
}) { }) {
if (insertAboveColumnTitle) { if (insertAboveColumnTitle) {
await this.grid.get().locator(`th[data-title="${insertBeforeColumnTitle}"] .nc-ui-dt-dropdown`).click(); await this.selectFieldAction({ title: insertAboveColumnTitle, action: 'insert-above' });
if (isDisplayValue) {
await expect(this.rootPage.locator('li[role="menuitem"]:has-text("Insert Before")')).toHaveCount(0);
return;
}
await this.rootPage.locator('li[role="menuitem"]:has-text("Insert Before"):visible').click();
} else if (insertBelowColumnTitle) { } else if (insertBelowColumnTitle) {
await this.grid.get().locator(`th[data-title="${insertAfterColumnTitle}"] .nc-ui-dt-dropdown`).click(); await this.selectFieldAction({ title: insertBelowColumnTitle, action: 'insert-below' });
await this.rootPage.locator('li[role="menuitem"]:has-text("Insert After"):visible').click();
} else { } else {
await this.clickNewField(); await this.clickNewField();
} }
@ -96,7 +87,7 @@ export class FieldsPage extends BasePage {
break; break;
case 'Duration': case 'Duration':
if (format) { if (format) {
await this.get().locator('.ant-select-single').nth(1).click(); await this.addOrEditColumn.locator('.ant-select-single').nth(1).click();
await this.rootPage await this.rootPage
.locator(`.ant-select-item`, { .locator(`.ant-select-item`, {
hasText: format, hasText: format,
@ -105,30 +96,30 @@ export class FieldsPage extends BasePage {
} }
break; break;
case 'Date': case 'Date':
await this.get().locator('.nc-date-select').click(); await this.addOrEditColumn.locator('.nc-date-select').click();
await this.rootPage.locator('.nc-date-select').pressSequentially(dateFormat); await this.rootPage.locator('.nc-date-select').pressSequentially(dateFormat);
await this.rootPage.locator('.ant-select-item').locator(`text="${dateFormat}"`).click(); await this.rootPage.locator('.ant-select-item').locator(`text="${dateFormat}"`).click();
break; break;
case 'DateTime': case 'DateTime':
// Date Format // Date Format
await this.get().locator('.nc-date-select').click(); await this.addOrEditColumn.locator('.nc-date-select').click();
await this.rootPage.locator('.ant-select-item').locator(`text="${dateFormat}"`).click(); await this.rootPage.locator('.ant-select-item').locator(`text="${dateFormat}"`).click();
// Time Format // Time Format
await this.get().locator('.nc-time-select').click(); await this.addOrEditColumn.locator('.nc-time-select').click();
await this.rootPage.locator('.ant-select-item').locator(`text="${timeFormat}"`).click(); await this.rootPage.locator('.ant-select-item').locator(`text="${timeFormat}"`).click();
break; break;
case 'Formula': case 'Formula':
await this.get().locator('.nc-formula-input').fill(formula); await this.addOrEditColumn.locator('.nc-formula-input').fill(formula);
break; break;
case 'QrCode': case 'QrCode':
await this.get().locator('.ant-select-single').nth(1).click(); await this.addOrEditColumn.locator('.ant-select-single').nth(1).click();
await this.rootPage await this.rootPage
.locator(`.ant-select-item`) .locator(`.ant-select-item`)
.locator(`[data-testid="nc-qr-${qrCodeValueColumnTitle}"]`) .locator(`[data-testid="nc-qr-${qrCodeValueColumnTitle}"]`)
.click(); .click();
break; break;
case 'Barcode': case 'Barcode':
await this.get().locator('.ant-select-single').nth(1).click(); await this.addOrEditColumn.locator('.ant-select-single').nth(1).click();
await this.rootPage await this.rootPage
.locator(`.ant-select-item`, { .locator(`.ant-select-item`, {
hasText: new RegExp(`^${barcodeValueColumnTitle}$`), hasText: new RegExp(`^${barcodeValueColumnTitle}$`),
@ -136,13 +127,13 @@ export class FieldsPage extends BasePage {
.click(); .click();
break; break;
case 'Lookup': case 'Lookup':
await this.get().locator('.ant-select-single').nth(1).click(); await this.addOrEditColumn.locator('.ant-select-single').nth(1).click();
await this.rootPage await this.rootPage
.locator(`.ant-select-item`, { .locator(`.ant-select-item`, {
hasText: childTable, hasText: childTable,
}) })
.click(); .click();
await this.get().locator('.ant-select-single').nth(2).click(); await this.addOrEditColumn.locator('.ant-select-single').nth(2).click();
await this.rootPage await this.rootPage
.locator(`.ant-select-item`, { .locator(`.ant-select-item`, {
hasText: childColumn, hasText: childColumn,
@ -151,19 +142,19 @@ export class FieldsPage extends BasePage {
.click(); .click();
break; break;
case 'Rollup': case 'Rollup':
await this.get().locator('.ant-select-single').nth(1).click(); await this.addOrEditColumn.locator('.ant-select-single').nth(1).click();
await this.rootPage await this.rootPage
.locator(`.ant-select-item`, { .locator(`.ant-select-item`, {
hasText: childTable, hasText: childTable,
}) })
.click(); .click();
await this.get().locator('.ant-select-single').nth(2).click(); await this.addOrEditColumn.locator('.ant-select-single').nth(2).click();
await this.rootPage await this.rootPage
.locator(`.nc-dropdown-relation-column >> .ant-select-item`, { .locator(`.nc-dropdown-relation-column >> .ant-select-item`, {
hasText: childColumn, hasText: childColumn,
}) })
.click(); .click();
await this.get().locator('.ant-select-single').nth(3).click(); await this.addOrEditColumn.locator('.ant-select-single').nth(3).click();
await this.rootPage await this.rootPage
.locator(`.nc-dropdown-rollup-function >> .ant-select-item`, { .locator(`.nc-dropdown-rollup-function >> .ant-select-item`, {
hasText: rollupType, hasText: rollupType,
@ -172,11 +163,11 @@ export class FieldsPage extends BasePage {
.click(); .click();
break; break;
case 'Links': case 'Links':
await this.get() await this.addOrEditColumn
.locator('.nc-ltar-relation-type >> .ant-radio') .locator('.nc-ltar-relation-type >> .ant-radio')
.nth(relationType === 'Has Many' ? 0 : 1) .nth(relationType === 'Has Many' ? 0 : 1)
.click(); .click();
await this.get().locator('.ant-select-single').nth(1).click(); await this.addOrEditColumn.locator('.ant-select-single').nth(1).click();
await this.rootPage.locator(`.nc-ltar-child-table >> input[type="search"]`).fill(childTable); await this.rootPage.locator(`.nc-ltar-child-table >> input[type="search"]`).fill(childTable);
await this.rootPage await this.rootPage
.locator(`.nc-dropdown-ltar-child-table >> .ant-select-item`, { .locator(`.nc-dropdown-ltar-child-table >> .ant-select-item`, {
@ -193,37 +184,36 @@ export class FieldsPage extends BasePage {
await this.saveChanges(); await this.saveChanges();
const headersText = []; const fieldsText = [];
const locator = this.grid.get().locator(`th`); const locator = this.fieldListWrapper.locator('>div');
const count = await locator.count(); const count = await locator.count();
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
const header = locator.nth(i); const text = await locator.nth(i).getByTestId('nc-field-title').textContent();
const text = await getTextExcludeIconText(header); fieldsText.push(text);
headersText.push(text);
} }
// verify column inserted after the target column // verify field inserted above the target field
if (insertAboveColumnTitle) { if (insertAboveColumnTitle) {
expect(headersText[headersText.findIndex(title => title.startsWith(insertAboveColumnTitle)) + 1]).toBe(title); expect(fieldsText[fieldsText.findIndex(title => title.startsWith(insertAboveColumnTitle)) - 1]).toBe(title);
} }
// verify column inserted before the target column // verify field inserted below the target field
if (insertBelowColumnTitle) { if (insertBelowColumnTitle) {
expect(headersText[headersText.findIndex(title => title.startsWith(insertAboveColumnTitle)) - 1]).toBe(title); expect(fieldsText[fieldsText.findIndex(title => title.startsWith(insertAboveColumnTitle)) + 1]).toBe(title);
} }
} }
async fillTitle({ title }: { title: string }) { async fillTitle({ title }: { title: string }) {
const fieldTitleInput = this.get().locator('.nc-fields-input'); const fieldTitleInput = this.addOrEditColumn.locator('.nc-fields-input');
await fieldTitleInput.click(); await fieldTitleInput.click();
await fieldTitleInput.fill(title); await fieldTitleInput.fill(title);
} }
async selectType({ type }: { type: string }) { async selectType({ type }: { type: string }) {
await this.get().locator('.ant-select-selector > .ant-select-selection-item').click(); await this.addOrEditColumn.locator('.ant-select-selector > .ant-select-selection-item').click();
await this.get().locator('.ant-select-selection-search-input[aria-expanded="true"]').waitFor(); await this.addOrEditColumn.locator('.ant-select-selection-search-input[aria-expanded="true"]').waitFor();
await this.get().locator('.ant-select-selection-search-input[aria-expanded="true"]').fill(type); await this.addOrEditColumn.locator('.ant-select-selection-search-input[aria-expanded="true"]').fill(type);
// Select column type // Select column type
await this.rootPage.locator('.rc-virtual-list-holder-inner > div').locator(`text="${type}"`).click(); await this.rootPage.locator('.rc-virtual-list-holder-inner > div').locator(`text="${type}"`).click();
@ -241,4 +231,32 @@ export class FieldsPage extends BasePage {
async getField({ title }: { title: string }) { async getField({ title }: { title: string }) {
return this.fieldListWrapper.getByTestId('nc-field-title').locator(`text=${title}`); return this.fieldListWrapper.getByTestId('nc-field-title').locator(`text=${title}`);
} }
async getFieldVisibilityCheckbox({ title }: { title: string }) {
return (await this.getField({ title })).getByTestId('nc-field-visibility-checkbox');
}
async selectFieldAction({
title,
action,
isDisplayValueField = false,
}: {
title: string;
action: 'copy-id' | 'duplicate' | 'insert-above' | 'insert-below' | 'delete';
isDisplayValueField?: boolean;
}) {
const field = await this.getField({ title });
await field.hover();
await field.getByTestId('nc-field-item-action-button').waitFor({ state: 'visible' });
await field.getByTestId('nc-field-item-action-button').click();
const fieldActionDropdown = isDisplayValueField
? this.rootPage.locator('.nc-field-item-action-dropdown-display-column')
: this.rootPage.locator('.nc-field-item-action-dropdown');
await fieldActionDropdown.waitFor({ state: 'visible' });
await fieldActionDropdown.getByTestId(`nc-field-item-action-${action}`).click();
await fieldActionDropdown.waitFor({ state: 'hidden' });
}
} }

Loading…
Cancel
Save