2022-06-09 04:59:31 +00:00
|
|
|
import { ObjectsRegistry } from "../Objects/Registry";
|
2023-06-01 17:26:05 +00:00
|
|
|
import sampleTableData from "../../fixtures/Table/sampleTableData.json";
|
|
|
|
|
|
2022-04-12 10:01:22 +00:00
|
|
|
const path = require("path");
|
|
|
|
|
|
2022-06-09 04:59:31 +00:00
|
|
|
type filterTypes =
|
|
|
|
|
| "contains"
|
|
|
|
|
| "does not contain"
|
|
|
|
|
| "starts with"
|
|
|
|
|
| "ends with"
|
|
|
|
|
| "is exactly"
|
|
|
|
|
| "empty"
|
|
|
|
|
| "not empty"
|
|
|
|
|
| "is equal to"
|
|
|
|
|
| "not equal to"
|
|
|
|
|
| "greater than"
|
|
|
|
|
| "greater than or equal to"
|
|
|
|
|
| "less than"
|
|
|
|
|
| "less than or equal to";
|
|
|
|
|
type columnTypeValues =
|
2023-05-19 18:37:06 +00:00
|
|
|
| "Plain text"
|
2022-06-09 04:59:31 +00:00
|
|
|
| "URL"
|
|
|
|
|
| "Number"
|
|
|
|
|
| "Image"
|
|
|
|
|
| "Video"
|
|
|
|
|
| "Date"
|
|
|
|
|
| "Button"
|
2023-05-19 18:37:06 +00:00
|
|
|
| "Menu button"
|
2023-06-29 07:07:41 +00:00
|
|
|
| "Icon button"
|
|
|
|
|
| "Select";
|
2022-03-31 11:51:08 +00:00
|
|
|
|
|
|
|
|
export class Table {
|
2023-06-15 13:21:11 +00:00
|
|
|
private agHelper = ObjectsRegistry.AggregateHelper;
|
|
|
|
|
private deployMode = ObjectsRegistry.DeployMode;
|
|
|
|
|
private locator = ObjectsRegistry.CommonLocators;
|
|
|
|
|
private propPane = ObjectsRegistry.PropertyPane;
|
|
|
|
|
private assertHelper = ObjectsRegistry.AssertHelper;
|
2022-06-09 04:59:31 +00:00
|
|
|
|
2023-05-02 17:49:42 +00:00
|
|
|
private _tableWrap = "//div[contains(@class,'tableWrap')]";
|
2022-06-09 04:59:31 +00:00
|
|
|
private _tableHeader =
|
2023-05-02 17:49:42 +00:00
|
|
|
this._tableWrap +
|
|
|
|
|
"//div[contains(@class,'thead')]//div[contains(@class,'tr')][1]";
|
2022-06-09 04:59:31 +00:00
|
|
|
private _columnHeader = (columnName: string) =>
|
|
|
|
|
this._tableWrap +
|
2023-05-02 17:49:42 +00:00
|
|
|
"//div[contains(@class,'thead')]//div[contains(@class,'tr')][1]//div[@role='columnheader']//div[contains(text(),'" +
|
2022-06-09 04:59:31 +00:00
|
|
|
columnName +
|
2023-05-02 17:49:42 +00:00
|
|
|
"')]/parent::div/parent::div";
|
2023-06-15 13:21:11 +00:00
|
|
|
private _columnHeaderDiv = (columnName: string) =>
|
|
|
|
|
`[data-header=${columnName}]`;
|
2023-03-07 21:59:34 +00:00
|
|
|
private _tableWidgetVersion = (version: "v1" | "v2") =>
|
|
|
|
|
`.t--widget-tablewidget${version == "v1" ? "" : version}`;
|
|
|
|
|
private _nextPage = (version: "v1" | "v2") =>
|
|
|
|
|
this._tableWidgetVersion(version) + " .t--table-widget-next-page";
|
|
|
|
|
private _previousPage = (version: "v1" | "v2") =>
|
|
|
|
|
this._tableWidgetVersion(version) + " .t--table-widget-prev-page";
|
|
|
|
|
private _pageNumber = ".t--widget-tablewidgetv2 .page-item";
|
|
|
|
|
private _pageNumberServerSideOff =
|
|
|
|
|
".t--widget-tablewidgetv2 .t--table-widget-page-input input";
|
2022-06-23 15:13:15 +00:00
|
|
|
private _pageNumberServerSidePagination = ".t--widget-tablewidget .page-item";
|
|
|
|
|
private _pageNumberClientSidePagination =
|
2022-06-09 04:59:31 +00:00
|
|
|
".t--widget-tablewidget .t--table-widget-page-input input";
|
2023-03-07 21:59:34 +00:00
|
|
|
_tableRow = (rowNum: number, colNum: number, version: "v1" | "v2") =>
|
|
|
|
|
this._tableWidgetVersion(version) +
|
|
|
|
|
` .tbody .td[data-rowindex=${rowNum}][data-colindex=${colNum}]`;
|
2023-06-15 13:21:11 +00:00
|
|
|
_editCellIconDiv = ".t--editable-cell-icon";
|
2023-06-16 18:40:10 +00:00
|
|
|
_editCellEditor = ".t--inlined-cell-editor";
|
|
|
|
|
_editCellEditorInput = this._editCellEditor + " input";
|
2023-03-07 21:59:34 +00:00
|
|
|
_tableRowColumnDataVersion = (version: "v1" | "v2") =>
|
|
|
|
|
`${version == "v1" ? " div div" : " .cell-wrapper"}`;
|
|
|
|
|
_tableRowColumnData = (
|
|
|
|
|
rowNum: number,
|
|
|
|
|
colNum: number,
|
|
|
|
|
version: "v1" | "v2",
|
|
|
|
|
) =>
|
|
|
|
|
this._tableRow(rowNum, colNum, version) +
|
|
|
|
|
this._tableRowColumnDataVersion(version);
|
|
|
|
|
_tableLoadStateDelete = (version: "v1" | "v2") =>
|
|
|
|
|
this._tableRow(0, 0, version) + ` div div button span:contains('Delete')`;
|
|
|
|
|
_tableRowImageColumnData = (
|
|
|
|
|
rowNum: number,
|
|
|
|
|
colNum: number,
|
|
|
|
|
version: "v1" | "v2",
|
|
|
|
|
) => this._tableRow(rowNum, colNum, version) + ` div div.image-cell`;
|
|
|
|
|
_tableEmptyColumnData = (version: "v1" | "v2") =>
|
|
|
|
|
this._tableWidgetVersion(version) + " .tbody .td"; //selected-row
|
2022-06-09 04:59:31 +00:00
|
|
|
_tableSelectedRow =
|
|
|
|
|
this._tableWrap +
|
|
|
|
|
"//div[contains(@class, 'tbody')]//div[contains(@class, 'selected-row')]/div";
|
|
|
|
|
_liNextPage = "li[title='Next Page']";
|
|
|
|
|
_liPreviousPage = "li[title='Previous Page']";
|
|
|
|
|
_liCurrentSelectedPage =
|
|
|
|
|
"//div[@type='LIST_WIDGET']//ul[contains(@class, 'rc-pagination')]/li[contains(@class, 'rc-pagination-item-active')]/a";
|
|
|
|
|
private _searchText = "input[type='search']";
|
|
|
|
|
_searchBoxCross =
|
|
|
|
|
"//div[contains(@class, 't--search-input')]/following-sibling::div";
|
2023-05-11 05:26:03 +00:00
|
|
|
_addIcon = "button .bp3-icon-add";
|
2022-06-09 04:59:31 +00:00
|
|
|
_trashIcon = "button span[icon='trash']";
|
|
|
|
|
_visibleTextSpan = (spanText: string) => "//span[text()='" + spanText + "']";
|
|
|
|
|
_filterBtn = ".t--table-filter-toggle-btn";
|
|
|
|
|
_filterColumnsDropdown = ".t--table-filter-columns-dropdown";
|
|
|
|
|
_dropdownText = ".t--dropdown-option";
|
|
|
|
|
_filterConditionDropdown = ".t--table-filter-conditions-dropdown";
|
2023-06-15 13:21:11 +00:00
|
|
|
_filterInputValue = ".t--table-filter-value-input input";
|
2023-03-07 21:59:34 +00:00
|
|
|
_addColumn = ".t--add-column-btn";
|
|
|
|
|
_deleteColumn = ".t--delete-column-btn";
|
|
|
|
|
_defaultColName =
|
|
|
|
|
"[data-rbd-draggable-id='customColumn1'] input[type='text']";
|
2022-06-09 04:59:31 +00:00
|
|
|
private _filterApplyBtn = ".t--apply-filter-btn";
|
|
|
|
|
private _filterCloseBtn = ".t--close-filter-btn";
|
|
|
|
|
private _removeFilter = ".t--table-filter-remove-btn";
|
|
|
|
|
private _clearAllFilter = ".t--clear-all-filter-btn";
|
|
|
|
|
private _addFilter = ".t--add-filter-btn";
|
|
|
|
|
_filterOperatorDropdown = ".t--table-filter-operators-dropdown";
|
|
|
|
|
private _downloadBtn = ".t--table-download-btn";
|
|
|
|
|
private _downloadOption = ".t--table-download-data-option";
|
2023-06-16 18:40:10 +00:00
|
|
|
_columnSettings = (
|
|
|
|
|
columnName: string,
|
|
|
|
|
type: "Edit" | "Visibility" | "Editable",
|
|
|
|
|
) => {
|
|
|
|
|
const classMap = {
|
|
|
|
|
Edit: "t--edit-column-btn",
|
|
|
|
|
Visibility: "t--show-column-btn",
|
|
|
|
|
Editable: "t--card-checkbox",
|
|
|
|
|
};
|
|
|
|
|
const classToCheck = classMap[type];
|
|
|
|
|
return `//input[@placeholder='Column title'][@value='${columnName}']/parent::div/parent::div/parent::div/parent::div/following-sibling::div/*[contains(@class, '${classToCheck}')]`;
|
|
|
|
|
};
|
|
|
|
|
_columnSettingsV2 = (
|
|
|
|
|
columnName: string,
|
|
|
|
|
type: "Edit" | "Visibility" | "Editable",
|
|
|
|
|
) => {
|
|
|
|
|
const classMap = {
|
|
|
|
|
Edit: ".t--edit-column-btn",
|
|
|
|
|
Visibility: ".t--show-column-btn",
|
|
|
|
|
Editable: ".t--card-checkbox",
|
|
|
|
|
};
|
|
|
|
|
const classToCheck = classMap[type];
|
|
|
|
|
return `.t--property-pane-view .tablewidgetv2-primarycolumn-list div[data-rbd-draggable-id=${columnName}] ${classToCheck}`;
|
|
|
|
|
};
|
2022-06-09 04:59:31 +00:00
|
|
|
_showPageItemsCount = "div.show-page-items";
|
|
|
|
|
_filtersCount = this._filterBtn + " span.action-title";
|
2023-06-01 17:26:05 +00:00
|
|
|
_headerCell = (column: string) =>
|
|
|
|
|
`.t--widget-tablewidgetv2 .thead .th:contains(${column})`;
|
|
|
|
|
_addNewRow = ".t--add-new-row";
|
|
|
|
|
_saveNewRow = ".t--save-new-row";
|
2023-06-29 07:07:41 +00:00
|
|
|
_discardRow = ".t--discard-new-row";
|
2023-06-01 17:26:05 +00:00
|
|
|
_searchInput = ".t--search-input input";
|
|
|
|
|
_bodyCell = (cellValue: string) =>
|
|
|
|
|
`.t--table-text-cell:contains(${cellValue})`;
|
|
|
|
|
_newRow = ".new-row";
|
|
|
|
|
_connectDataHeader = ".t--cypress-table-overlay-header";
|
|
|
|
|
_connectDataButton = ".t--cypress-table-overlay-connectdata";
|
2023-06-16 18:40:10 +00:00
|
|
|
_updateMode = (mode: "Single" | "Multi") =>
|
|
|
|
|
"//span[text()='" + mode + " Row']/ancestor::div";
|
2023-06-22 05:52:13 +00:00
|
|
|
_hideMenu = ".hide-menu";
|
2023-06-21 12:01:06 +00:00
|
|
|
_tableColumnHeaderMenuTrigger = (columnName: string) =>
|
|
|
|
|
`${this._columnHeaderDiv(columnName)} .header-menu .bp3-popover2-target`;
|
|
|
|
|
_columnHeaderMenu = ".bp3-menu";
|
2023-06-29 07:07:41 +00:00
|
|
|
_selectMenuItem = ".menu-item-text";
|
2022-03-31 11:51:08 +00:00
|
|
|
|
2023-03-07 21:59:34 +00:00
|
|
|
public WaitUntilTableLoad(
|
|
|
|
|
rowIndex = 0,
|
|
|
|
|
colIndex = 0,
|
|
|
|
|
tableVersion: "v1" | "v2" = "v1",
|
|
|
|
|
) {
|
|
|
|
|
// this.agHelper
|
|
|
|
|
// .GetElement(this._tableRowColumnData(rowIndex, colIndex, tableVersion), 30000)
|
|
|
|
|
// .waitUntil(($ele) =>
|
|
|
|
|
// cy
|
|
|
|
|
// .wrap($ele)
|
|
|
|
|
// .children("button")
|
|
|
|
|
// .should("have.length", 0),
|
|
|
|
|
// );
|
|
|
|
|
//or above will also work:
|
|
|
|
|
this.agHelper.AssertElementAbsence(
|
|
|
|
|
this._tableLoadStateDelete(tableVersion),
|
|
|
|
|
30000,
|
|
|
|
|
); //For CURD generated pages Delete button appears first when table is loading & not fully loaded, hence validating that here!
|
|
|
|
|
cy.waitUntil(
|
|
|
|
|
() => this.ReadTableRowColumnData(rowIndex, colIndex, tableVersion),
|
|
|
|
|
{
|
|
|
|
|
errorMsg: "Table is not populated",
|
|
|
|
|
timeout: 10000,
|
|
|
|
|
interval: 2000,
|
|
|
|
|
},
|
|
|
|
|
).then((cellData) => {
|
|
|
|
|
expect(cellData).not.empty;
|
|
|
|
|
});
|
|
|
|
|
this.agHelper.Sleep(500); //for table to settle loading!
|
2022-03-31 11:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-07 21:59:34 +00:00
|
|
|
public AssertTableLoaded(
|
|
|
|
|
rowIndex = 0,
|
|
|
|
|
colIndex = 0,
|
|
|
|
|
tableVersion: "v1" | "v2" = "v1",
|
|
|
|
|
) {
|
2023-02-24 17:11:25 +00:00
|
|
|
this.agHelper
|
2023-03-07 21:59:34 +00:00
|
|
|
.GetElement(
|
|
|
|
|
this._tableRowColumnData(rowIndex, colIndex, tableVersion),
|
|
|
|
|
30000,
|
|
|
|
|
)
|
2023-02-24 17:11:25 +00:00
|
|
|
.waitUntil(($ele) =>
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
cy.wrap($ele).children("span").should("not.be.empty"),
|
2023-02-24 17:11:25 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-07 21:59:34 +00:00
|
|
|
public WaitForTableEmpty(tableVersion: "v1" | "v2" = "v1") {
|
|
|
|
|
cy.waitUntil(() => cy.get(this._tableEmptyColumnData(tableVersion)), {
|
2022-06-09 04:59:31 +00:00
|
|
|
errorMsg: "Table is populated when not expected",
|
|
|
|
|
timeout: 10000,
|
|
|
|
|
interval: 2000,
|
|
|
|
|
}).then(($children) => {
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
cy.wrap($children).children().should("have.length", 0); //or below
|
2022-06-09 04:59:31 +00:00
|
|
|
//expect($children).to.have.lengthOf(0)
|
|
|
|
|
this.agHelper.Sleep(500);
|
|
|
|
|
});
|
2022-03-31 11:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public AssertTableHeaderOrder(expectedOrder: string) {
|
2022-06-09 04:59:31 +00:00
|
|
|
cy.xpath(this._tableHeader)
|
|
|
|
|
.invoke("text")
|
|
|
|
|
.then((x) => {
|
|
|
|
|
expect(x).to.eq(expectedOrder);
|
|
|
|
|
});
|
2022-03-31 11:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
2023-06-15 13:21:11 +00:00
|
|
|
public AssertColumnFreezeStatus(columnName: string, freezed = true) {
|
|
|
|
|
if (freezed) {
|
|
|
|
|
this.agHelper
|
|
|
|
|
.GetElement(this._columnHeaderDiv(columnName))
|
|
|
|
|
.then(($elem) => {
|
|
|
|
|
expect($elem.attr("data-sticky-td")).to.equal("true");
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
this.agHelper
|
|
|
|
|
.GetElement(this._columnHeaderDiv(columnName))
|
|
|
|
|
.should("not.have.attr", "data-sticky-td");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-09 04:59:31 +00:00
|
|
|
public ReadTableRowColumnData(
|
|
|
|
|
rowNum: number,
|
|
|
|
|
colNum: number,
|
2023-03-07 21:59:34 +00:00
|
|
|
tableVersion: "v1" | "v2" = "v1",
|
2022-06-09 04:59:31 +00:00
|
|
|
timeout = 1000,
|
|
|
|
|
) {
|
|
|
|
|
//timeout can be sent higher values incase of larger tables
|
|
|
|
|
this.agHelper.Sleep(timeout); //Settling time for table!
|
2022-09-02 01:05:45 +00:00
|
|
|
return this.agHelper
|
2023-03-07 21:59:34 +00:00
|
|
|
.GetElement(this._tableRowColumnData(rowNum, colNum, tableVersion), 30000)
|
2022-09-02 01:05:45 +00:00
|
|
|
.invoke("text");
|
2022-03-31 11:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
2022-07-16 10:41:17 +00:00
|
|
|
public AssertTableRowImageColumnIsLoaded(
|
|
|
|
|
rowNum: number,
|
|
|
|
|
colNum: number,
|
|
|
|
|
timeout = 200,
|
2023-03-07 21:59:34 +00:00
|
|
|
tableVersion: "v1" | "v2" = "v1",
|
2022-07-16 10:41:17 +00:00
|
|
|
) {
|
|
|
|
|
//timeout can be sent higher values incase of larger tables
|
|
|
|
|
this.agHelper.Sleep(timeout); //Settling time for table!
|
|
|
|
|
return cy
|
2023-03-07 21:59:34 +00:00
|
|
|
.get(this._tableRowImageColumnData(rowNum, colNum, tableVersion))
|
2022-07-16 10:41:17 +00:00
|
|
|
.invoke("attr", "style")
|
|
|
|
|
.should("not.be.empty");
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-31 11:51:08 +00:00
|
|
|
public AssertHiddenColumns(columnNames: string[]) {
|
2022-06-09 04:59:31 +00:00
|
|
|
columnNames.forEach(($header) => {
|
2022-03-31 11:51:08 +00:00
|
|
|
cy.xpath(this._columnHeader($header))
|
|
|
|
|
.invoke("attr", "class")
|
|
|
|
|
.then((classes) => {
|
|
|
|
|
expect(classes).includes("hidden-header");
|
|
|
|
|
});
|
2022-06-09 04:59:31 +00:00
|
|
|
});
|
2022-03-31 11:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-07 21:59:34 +00:00
|
|
|
public NavigateToNextPage(
|
|
|
|
|
isServerPagination = true,
|
|
|
|
|
tableVersion: "v1" | "v2" = "v1",
|
|
|
|
|
) {
|
2022-03-31 11:51:08 +00:00
|
|
|
let curPageNo: number;
|
2023-03-07 21:59:34 +00:00
|
|
|
if (tableVersion == "v1") {
|
|
|
|
|
this.agHelper
|
|
|
|
|
.GetText(
|
|
|
|
|
isServerPagination
|
|
|
|
|
? this._pageNumberServerSidePagination
|
|
|
|
|
: this._pageNumberClientSidePagination,
|
|
|
|
|
isServerPagination ? "text" : "val",
|
|
|
|
|
)
|
|
|
|
|
.then(($currentPageNo) => (curPageNo = Number($currentPageNo)));
|
|
|
|
|
cy.get(this._nextPage(tableVersion)).click();
|
|
|
|
|
this.agHelper
|
|
|
|
|
.GetText(
|
|
|
|
|
isServerPagination
|
|
|
|
|
? this._pageNumberServerSidePagination
|
|
|
|
|
: this._pageNumberClientSidePagination,
|
|
|
|
|
isServerPagination ? "text" : "val",
|
|
|
|
|
)
|
|
|
|
|
.then(($newPageNo) => expect(Number($newPageNo)).to.eq(curPageNo + 1));
|
|
|
|
|
} else if (tableVersion == "v2") {
|
|
|
|
|
cy.get(this._pageNumber)
|
|
|
|
|
.invoke("text")
|
|
|
|
|
.then(($currentPageNo) => (curPageNo = Number($currentPageNo)));
|
|
|
|
|
cy.get(this._nextPage(tableVersion)).click();
|
|
|
|
|
cy.get(this._pageNumber)
|
|
|
|
|
.invoke("text")
|
|
|
|
|
.then(($newPageNo) => expect(Number($newPageNo)).to.eq(curPageNo + 1));
|
|
|
|
|
}
|
2022-03-31 11:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-07 21:59:34 +00:00
|
|
|
public NavigateToPreviousPage(
|
|
|
|
|
isServerPagination = true,
|
|
|
|
|
tableVersion: "v1" | "v2" = "v1",
|
|
|
|
|
) {
|
2022-03-31 11:51:08 +00:00
|
|
|
let curPageNo: number;
|
2023-03-07 21:59:34 +00:00
|
|
|
if (tableVersion == "v1") {
|
|
|
|
|
this.agHelper
|
|
|
|
|
.GetText(
|
|
|
|
|
isServerPagination
|
|
|
|
|
? this._pageNumberServerSidePagination
|
|
|
|
|
: this._pageNumberClientSidePagination,
|
|
|
|
|
isServerPagination ? "text" : "val",
|
|
|
|
|
)
|
|
|
|
|
.then(($currentPageNo) => (curPageNo = Number($currentPageNo)));
|
|
|
|
|
cy.get(this._previousPage(tableVersion)).click();
|
|
|
|
|
this.agHelper
|
|
|
|
|
.GetText(
|
|
|
|
|
isServerPagination
|
|
|
|
|
? this._pageNumberServerSidePagination
|
|
|
|
|
: this._pageNumberClientSidePagination,
|
|
|
|
|
isServerPagination ? "text" : "val",
|
|
|
|
|
)
|
|
|
|
|
.then(($newPageNo) => expect(Number($newPageNo)).to.eq(curPageNo - 1));
|
|
|
|
|
} else if (tableVersion == "v2") {
|
|
|
|
|
cy.get(this._pageNumber)
|
|
|
|
|
.invoke("text")
|
|
|
|
|
.then(($currentPageNo) => (curPageNo = Number($currentPageNo)));
|
|
|
|
|
cy.get(this._previousPage(tableVersion)).click();
|
|
|
|
|
cy.get(this._pageNumber)
|
|
|
|
|
.invoke("text")
|
|
|
|
|
.then(($newPageNo) => expect(Number($newPageNo)).to.eq(curPageNo - 1));
|
|
|
|
|
}
|
2022-03-31 11:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-07 21:59:34 +00:00
|
|
|
public AssertPageNumber(
|
|
|
|
|
pageNo: number,
|
|
|
|
|
serverSide: "Off" | "On" | "" = "On",
|
|
|
|
|
tableVersion: "v1" | "v2" = "v1",
|
|
|
|
|
) {
|
|
|
|
|
const serverSideOn =
|
|
|
|
|
tableVersion == "v1"
|
|
|
|
|
? this._pageNumberServerSidePagination
|
|
|
|
|
: this._pageNumber;
|
|
|
|
|
const serverSideOff =
|
|
|
|
|
tableVersion == "v1"
|
|
|
|
|
? this._pageNumberClientSidePagination
|
|
|
|
|
: this._pageNumberServerSideOff;
|
|
|
|
|
|
2022-06-09 04:59:31 +00:00
|
|
|
if (serverSide == "On")
|
2023-03-07 21:59:34 +00:00
|
|
|
cy.get(serverSideOn).should("have.text", Number(pageNo));
|
2022-03-31 11:51:08 +00:00
|
|
|
else {
|
2023-03-07 21:59:34 +00:00
|
|
|
cy.get(serverSideOff).should("have.value", Number(pageNo));
|
|
|
|
|
cy.get(this._previousPage(tableVersion)).should("have.attr", "disabled");
|
|
|
|
|
cy.get(this._nextPage(tableVersion)).should("have.attr", "disabled");
|
2022-03-31 11:51:08 +00:00
|
|
|
}
|
2023-03-07 21:59:34 +00:00
|
|
|
if (pageNo == 1)
|
|
|
|
|
cy.get(this._previousPage(tableVersion)).should("have.attr", "disabled");
|
2022-03-31 11:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-23 11:32:18 +00:00
|
|
|
public AssertSelectedRow(rowNum = 0) {
|
2022-03-31 11:51:08 +00:00
|
|
|
cy.xpath(this._tableSelectedRow)
|
|
|
|
|
.invoke("attr", "data-rowindex")
|
2022-06-09 04:59:31 +00:00
|
|
|
.then(($rowIndex) => {
|
2022-03-31 11:51:08 +00:00
|
|
|
expect(Number($rowIndex)).to.eq(rowNum);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-07 21:59:34 +00:00
|
|
|
public SelectTableRow(
|
|
|
|
|
rowIndex: number,
|
|
|
|
|
columnIndex = 0,
|
|
|
|
|
select = true,
|
|
|
|
|
tableVersion: "v1" | "v2" = "v1",
|
|
|
|
|
) {
|
2022-08-28 23:06:17 +00:00
|
|
|
//rowIndex - 0 for 1st row
|
2022-09-02 01:05:45 +00:00
|
|
|
this.agHelper
|
2023-03-07 21:59:34 +00:00
|
|
|
.GetElement(this._tableRow(rowIndex, columnIndex, tableVersion))
|
2022-09-02 01:05:45 +00:00
|
|
|
.parent("div")
|
|
|
|
|
.invoke("attr", "class")
|
|
|
|
|
.then(($classes: any) => {
|
|
|
|
|
if (
|
|
|
|
|
(select && !$classes?.includes("selected-row")) ||
|
|
|
|
|
(!select && $classes?.includes("selected-row"))
|
|
|
|
|
)
|
|
|
|
|
this.agHelper.GetNClick(
|
2023-03-07 21:59:34 +00:00
|
|
|
this._tableRow(rowIndex, columnIndex, tableVersion),
|
2022-09-02 01:05:45 +00:00
|
|
|
0,
|
|
|
|
|
true,
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
2022-06-09 04:59:31 +00:00
|
|
|
this.agHelper.Sleep(); //for select to reflect
|
2022-04-03 16:43:20 +00:00
|
|
|
}
|
|
|
|
|
|
2022-04-12 10:01:22 +00:00
|
|
|
public AssertSearchText(searchTxt: string) {
|
2022-06-09 04:59:31 +00:00
|
|
|
cy.get(this._searchText).should("have.value", searchTxt);
|
2022-04-12 10:01:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public SearchTable(searchTxt: string, index = 0) {
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
cy.get(this._searchText).eq(index).type(searchTxt);
|
2022-04-12 10:01:22 +00:00
|
|
|
}
|
|
|
|
|
|
2023-06-20 08:58:06 +00:00
|
|
|
public ResetSearch() {
|
2023-04-13 10:08:46 +00:00
|
|
|
this.agHelper.GetNClick(this._searchBoxCross);
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-07 21:59:34 +00:00
|
|
|
public RemoveSearchTextNVerify(
|
|
|
|
|
cellDataAfterSearchRemoved: string,
|
|
|
|
|
tableVersion: "v1" | "v2" = "v1",
|
|
|
|
|
) {
|
2023-06-20 08:58:06 +00:00
|
|
|
this.ResetSearch();
|
2023-03-07 21:59:34 +00:00
|
|
|
this.ReadTableRowColumnData(0, 0, tableVersion).then(
|
|
|
|
|
(aftSearchRemoved: any) => {
|
|
|
|
|
expect(aftSearchRemoved).to.eq(cellDataAfterSearchRemoved);
|
|
|
|
|
},
|
|
|
|
|
);
|
2022-04-12 10:01:22 +00:00
|
|
|
}
|
|
|
|
|
|
2022-05-10 05:10:46 +00:00
|
|
|
public OpenFilter() {
|
2022-06-09 04:59:31 +00:00
|
|
|
this.agHelper.GetNClick(this._filterBtn);
|
2022-05-10 05:10:46 +00:00
|
|
|
}
|
|
|
|
|
|
2022-06-09 04:59:31 +00:00
|
|
|
public OpenNFilterTable(
|
|
|
|
|
colName: string,
|
|
|
|
|
colCondition: filterTypes,
|
|
|
|
|
inputText = "",
|
|
|
|
|
operator: "AND" | "OR" | "" = "",
|
|
|
|
|
index = 0,
|
|
|
|
|
) {
|
2022-04-12 10:01:22 +00:00
|
|
|
if (operator) {
|
2022-06-09 04:59:31 +00:00
|
|
|
this.agHelper.GetNClick(this._addFilter);
|
|
|
|
|
this.agHelper.GetNClick(this._filterOperatorDropdown);
|
2022-08-04 04:48:15 +00:00
|
|
|
this.agHelper.GetNClickByContains(this.locator._dropdownText, operator);
|
2022-06-09 04:59:31 +00:00
|
|
|
} else this.OpenFilter();
|
|
|
|
|
|
|
|
|
|
this.agHelper.GetNClick(this._filterColumnsDropdown, index);
|
2022-08-04 04:48:15 +00:00
|
|
|
this.agHelper.GetNClickByContains(this.locator._dropdownText, colName);
|
2022-06-09 04:59:31 +00:00
|
|
|
this.agHelper.GetNClick(this._filterConditionDropdown, index);
|
2022-08-04 04:48:15 +00:00
|
|
|
this.agHelper.GetNClickByContains(this.locator._dropdownText, colCondition);
|
2022-04-12 10:01:22 +00:00
|
|
|
|
|
|
|
|
if (inputText)
|
2022-06-09 04:59:31 +00:00
|
|
|
this.agHelper
|
|
|
|
|
.GetNClick(this._filterInputValue, index)
|
|
|
|
|
.type(inputText)
|
|
|
|
|
.wait(500);
|
2022-04-12 10:01:22 +00:00
|
|
|
|
2022-06-09 04:59:31 +00:00
|
|
|
this.agHelper.GetNClick(this._filterApplyBtn);
|
2022-04-12 10:01:22 +00:00
|
|
|
//this.agHelper.ClickButton("APPLY")
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-13 10:08:46 +00:00
|
|
|
public RemoveFilter(toClose = true, removeOne = false, index = 0) {
|
|
|
|
|
if (removeOne) this.agHelper.GetNClick(this._removeFilter, index);
|
|
|
|
|
else this.agHelper.GetNClick(this._clearAllFilter);
|
|
|
|
|
if (toClose) this.CloseFilter();
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-09 04:59:31 +00:00
|
|
|
public RemoveFilterNVerify(
|
|
|
|
|
cellDataAfterFilterRemoved: string,
|
|
|
|
|
toClose = true,
|
|
|
|
|
removeOne = true,
|
|
|
|
|
index = 0,
|
2023-03-07 21:59:34 +00:00
|
|
|
tableVersion: "v1" | "v2" = "v1",
|
2022-06-09 04:59:31 +00:00
|
|
|
) {
|
2023-04-13 10:08:46 +00:00
|
|
|
this.RemoveFilter(toClose, removeOne, index);
|
2023-03-07 21:59:34 +00:00
|
|
|
this.ReadTableRowColumnData(0, 0, tableVersion).then(
|
|
|
|
|
(aftFilterRemoved: any) => {
|
|
|
|
|
expect(aftFilterRemoved).to.eq(cellDataAfterFilterRemoved);
|
|
|
|
|
},
|
|
|
|
|
);
|
2022-04-12 10:01:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public CloseFilter() {
|
2022-06-09 04:59:31 +00:00
|
|
|
this.agHelper.GetNClick(this._filterCloseBtn);
|
2022-04-12 10:01:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public DownloadFromTable(filetype: "Download as CSV" | "Download as Excel") {
|
|
|
|
|
cy.get(this._downloadBtn).click({ force: true });
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
cy.get(this._downloadOption).contains(filetype).click({ force: true });
|
2022-04-12 10:01:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ValidateDownloadNVerify(fileName: string, textToBePresent: string) {
|
|
|
|
|
let downloadsFolder = Cypress.config("downloadsFolder");
|
|
|
|
|
cy.log("downloadsFolder is:" + downloadsFolder);
|
|
|
|
|
cy.readFile(path.join(downloadsFolder, fileName)).should("exist");
|
2022-06-09 04:59:31 +00:00
|
|
|
this.VerifyDownloadedFile(fileName, textToBePresent);
|
2022-04-12 10:01:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public VerifyDownloadedFile(fileName: string, textToBePresent: string) {
|
|
|
|
|
const downloadedFilename = Cypress.config("downloadsFolder")
|
|
|
|
|
.concat("/")
|
|
|
|
|
.concat(fileName);
|
|
|
|
|
cy.readFile(downloadedFilename, "binary", {
|
|
|
|
|
timeout: 15000,
|
|
|
|
|
}).should((buffer) => expect(buffer).to.contain(textToBePresent));
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-07 21:59:34 +00:00
|
|
|
public ChangeColumnType(
|
|
|
|
|
columnName: string,
|
|
|
|
|
newDataType: columnTypeValues,
|
|
|
|
|
tableVersion: "v1" | "v2" = "v1",
|
|
|
|
|
) {
|
2023-06-15 13:21:11 +00:00
|
|
|
this.EditColumn(columnName, tableVersion);
|
2023-05-19 18:37:06 +00:00
|
|
|
this.agHelper.SelectDropdownList("Column type", newDataType);
|
2023-06-18 04:55:16 +00:00
|
|
|
this.assertHelper.AssertNetworkStatus("@updateLayout");
|
2023-03-07 21:59:34 +00:00
|
|
|
if (tableVersion == "v2") this.propPane.NavigateBackToPropertyPane();
|
2022-05-04 09:29:42 +00:00
|
|
|
}
|
|
|
|
|
|
2022-06-09 04:59:31 +00:00
|
|
|
public AssertURLColumnNavigation(
|
|
|
|
|
row: number,
|
|
|
|
|
col: number,
|
|
|
|
|
expectedURL: string,
|
2023-03-07 21:59:34 +00:00
|
|
|
tableVersion: "v1" | "v2" = "v1",
|
2023-06-15 13:21:11 +00:00
|
|
|
networkCall = "viewPage",
|
2022-06-09 04:59:31 +00:00
|
|
|
) {
|
2023-06-15 13:21:11 +00:00
|
|
|
cy.url().then(($currentUrl) => {
|
2023-06-30 18:46:57 +00:00
|
|
|
this.deployMode.StubWindowNAssert(
|
2023-06-15 13:21:11 +00:00
|
|
|
this._tableRowColumnData(row, col, tableVersion),
|
2023-06-30 18:46:57 +00:00
|
|
|
expectedURL,
|
|
|
|
|
$currentUrl,
|
|
|
|
|
networkCall,
|
|
|
|
|
);
|
2023-06-15 13:21:11 +00:00
|
|
|
this.WaitUntilTableLoad(0, 0, tableVersion);
|
|
|
|
|
});
|
2022-05-04 09:29:42 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-07 21:59:34 +00:00
|
|
|
public AddColumn(colId: string) {
|
|
|
|
|
cy.get(this._addColumn).scrollIntoView();
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
cy.get(this._addColumn).should("be.visible").click({ force: true });
|
2023-03-07 21:59:34 +00:00
|
|
|
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
|
|
|
|
cy.wait(3000);
|
|
|
|
|
cy.get(this._defaultColName).clear({
|
|
|
|
|
force: true,
|
|
|
|
|
});
|
|
|
|
|
cy.get(this._defaultColName).type(colId, { force: true });
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-15 13:21:11 +00:00
|
|
|
public EditColumn(columnName: string, tableVersion: "v1" | "v2") {
|
|
|
|
|
const colSettings =
|
|
|
|
|
tableVersion == "v1"
|
2023-06-16 18:40:10 +00:00
|
|
|
? this._columnSettings(columnName, "Edit")
|
|
|
|
|
: this._columnSettingsV2(columnName, "Edit");
|
|
|
|
|
this.agHelper.GetNClick(colSettings);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public EnableVisibilityOfColumn(
|
|
|
|
|
columnName: string,
|
|
|
|
|
tableVersion: "v1" | "v2",
|
|
|
|
|
) {
|
|
|
|
|
const colSettings =
|
|
|
|
|
tableVersion == "v1"
|
|
|
|
|
? this._columnSettings(columnName, "Visibility")
|
|
|
|
|
: this._columnSettingsV2(columnName, "Visibility");
|
2023-06-15 13:21:11 +00:00
|
|
|
this.agHelper.GetNClick(colSettings);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-20 08:58:06 +00:00
|
|
|
public EnableEditableOfColumn(
|
|
|
|
|
columnName: string,
|
|
|
|
|
tableVersion: "v1" | "v2" = "v2",
|
|
|
|
|
) {
|
2023-06-16 18:40:10 +00:00
|
|
|
const colSettings =
|
|
|
|
|
tableVersion == "v1"
|
|
|
|
|
? this._columnSettings(columnName, "Editable")
|
|
|
|
|
: this._columnSettingsV2(columnName, "Editable");
|
|
|
|
|
this.agHelper.GetNClick(colSettings);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-30 18:46:57 +00:00
|
|
|
public ClickOnEditIcon(rowIndex: number, colIndex: number) {
|
2023-06-15 13:21:11 +00:00
|
|
|
this.agHelper.HoverElement(this._tableRow(rowIndex, colIndex, "v2"));
|
|
|
|
|
this.agHelper.GetNClick(
|
|
|
|
|
this._tableRow(rowIndex, colIndex, "v2") + " " + this._editCellIconDiv,
|
2023-06-20 08:58:06 +00:00
|
|
|
0,
|
|
|
|
|
true,
|
|
|
|
|
);
|
2023-06-15 13:21:11 +00:00
|
|
|
this.agHelper.AssertElementVisible(
|
|
|
|
|
this._tableRow(rowIndex, colIndex, "v2") +
|
|
|
|
|
" " +
|
|
|
|
|
this._editCellEditorInput,
|
2023-03-07 21:59:34 +00:00
|
|
|
);
|
2023-06-30 18:46:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public EditTableCell(
|
|
|
|
|
rowIndex: number,
|
|
|
|
|
colIndex: number,
|
|
|
|
|
newValue: "" | number | string,
|
|
|
|
|
toSaveNewValue = true,
|
|
|
|
|
) {
|
|
|
|
|
this.ClickOnEditIcon(rowIndex, colIndex);
|
2023-06-20 08:58:06 +00:00
|
|
|
this.UpdateTableCell(
|
|
|
|
|
rowIndex,
|
|
|
|
|
colIndex,
|
|
|
|
|
newValue.toString(),
|
|
|
|
|
toSaveNewValue,
|
|
|
|
|
);
|
|
|
|
|
this.agHelper.Sleep();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public UpdateTableCell(
|
|
|
|
|
rowIndex: number,
|
|
|
|
|
colIndex: number,
|
|
|
|
|
newValue: "" | number | string,
|
|
|
|
|
toSaveNewValue = false,
|
|
|
|
|
) {
|
|
|
|
|
this.agHelper.UpdateInputValue(
|
|
|
|
|
this._tableRow(rowIndex, colIndex, "v2") +
|
|
|
|
|
" " +
|
|
|
|
|
this._editCellEditorInput,
|
|
|
|
|
newValue.toString(),
|
|
|
|
|
);
|
2023-06-16 18:40:10 +00:00
|
|
|
toSaveNewValue &&
|
|
|
|
|
this.agHelper.TypeText(this._editCellEditorInput, "{enter}", 0, true);
|
2023-03-07 21:59:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public DeleteColumn(colId: string) {
|
|
|
|
|
this.propPane.NavigateBackToPropertyPane();
|
|
|
|
|
cy.get(
|
|
|
|
|
"[data-rbd-draggable-id='" + colId + "'] .t--delete-column-btn",
|
|
|
|
|
).click({
|
|
|
|
|
force: true,
|
|
|
|
|
});
|
|
|
|
|
cy.wait(1000);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-03 16:43:20 +00:00
|
|
|
//List methods - keeping it for now!
|
|
|
|
|
public NavigateToNextPage_List() {
|
|
|
|
|
let curPageNo: number;
|
2022-06-09 04:59:31 +00:00
|
|
|
cy.xpath(this._liCurrentSelectedPage)
|
|
|
|
|
.invoke("text")
|
|
|
|
|
.then(($currentPageNo) => (curPageNo = Number($currentPageNo)));
|
|
|
|
|
cy.get(this._liNextPage).click();
|
2022-05-04 09:45:57 +00:00
|
|
|
//cy.scrollTo('top', { easing: 'linear' })
|
2022-06-09 04:59:31 +00:00
|
|
|
cy.xpath(this._liCurrentSelectedPage)
|
|
|
|
|
.invoke("text")
|
|
|
|
|
.then(($newPageNo) => expect(Number($newPageNo)).to.eq(curPageNo + 1));
|
2022-04-03 16:43:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public NavigateToPreviousPage_List() {
|
|
|
|
|
let curPageNo: number;
|
2022-06-09 04:59:31 +00:00
|
|
|
cy.xpath(this._liCurrentSelectedPage)
|
|
|
|
|
.invoke("text")
|
|
|
|
|
.then(($currentPageNo) => (curPageNo = Number($currentPageNo)));
|
|
|
|
|
cy.get(this._liPreviousPage).click();
|
2022-05-04 09:45:57 +00:00
|
|
|
//cy.scrollTo('top', { easing: 'linear' })
|
2022-06-09 04:59:31 +00:00
|
|
|
cy.xpath(this._liCurrentSelectedPage)
|
|
|
|
|
.invoke("text")
|
|
|
|
|
.then(($newPageNo) => expect(Number($newPageNo)).to.eq(curPageNo - 1));
|
2022-04-03 16:43:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public AssertPageNumber_List(pageNo: number, checkNoNextPage = false) {
|
2022-06-09 04:59:31 +00:00
|
|
|
cy.xpath(this._liCurrentSelectedPage)
|
|
|
|
|
.invoke("text")
|
|
|
|
|
.then(($currentPageNo) => expect(Number($currentPageNo)).to.eq(pageNo));
|
2022-04-03 16:43:20 +00:00
|
|
|
|
|
|
|
|
if (pageNo == 1)
|
2022-06-09 04:59:31 +00:00
|
|
|
cy.get(this._liPreviousPage).should("have.attr", "aria-disabled", "true");
|
2022-04-03 16:43:20 +00:00
|
|
|
|
|
|
|
|
if (checkNoNextPage)
|
2022-06-09 04:59:31 +00:00
|
|
|
cy.get(this._liNextPage).should("have.attr", "aria-disabled", "true");
|
|
|
|
|
else cy.get(this._liNextPage).should("have.attr", "aria-disabled", "false");
|
2022-04-03 16:43:20 +00:00
|
|
|
}
|
2023-06-01 17:26:05 +00:00
|
|
|
|
|
|
|
|
public AddSampleTableData() {
|
2023-06-15 13:21:11 +00:00
|
|
|
this.propPane.EnterJSContext("Table data", JSON.stringify(sampleTableData));
|
2023-06-01 17:26:05 +00:00
|
|
|
this.ChangeColumnType("action", "Button", "v2");
|
|
|
|
|
}
|
2023-06-21 12:01:06 +00:00
|
|
|
|
|
|
|
|
public SortColumn(columnName: string, direction: string) {
|
|
|
|
|
this.agHelper.GetNClick(
|
|
|
|
|
this._tableColumnHeaderMenuTrigger(columnName),
|
|
|
|
|
0,
|
|
|
|
|
true,
|
|
|
|
|
);
|
|
|
|
|
this.agHelper.GetNClickByContains(
|
|
|
|
|
this._columnHeaderMenu,
|
|
|
|
|
`Sort column ${direction}`,
|
|
|
|
|
);
|
|
|
|
|
this.agHelper.Sleep(500);
|
|
|
|
|
}
|
2022-05-31 05:33:59 +00:00
|
|
|
}
|