Skip to content

Commit 4b6cbb3

Browse files
authored
fix(compat/ui5-table): fire loadMore with arrow-down on last row (#11401)
On some screen sizes and table row's heights, the user can't reach the bottom of the table by using the arrow-down key. Although the last row is being reached and gets focused, the very bottom of the table can't be reached, and the load-more event isn't fired. For this use-case, but not only, we now fire the "load-more" event whenever the user presses ARROW DOWN on the last table row. Fixes: #9235
1 parent ec4f08c commit 4b6cbb3

13 files changed

+1067
-2
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"ci:test:main:cy:suite-1": "yarn workspace @ui5/webcomponents test:cypress:suite-1",
5656
"ci:test:main:cy:suite-2": "yarn workspace @ui5/webcomponents test:cypress:suite-2",
5757
"ci:test:fiori": "yarn workspace @ui5/webcomponents-fiori test:ssr && yarn workspace @ui5/webcomponents-fiori test:cypress && yarn workspace @ui5/webcomponents-fiori test",
58-
"ci:test:compat": "yarn workspace @ui5/webcomponents-compat test:ssr && yarn workspace @ui5/webcomponents-compat test",
58+
"ci:test:compat": "yarn workspace @ui5/webcomponents-compat test:ssr && yarn workspace @ui5/webcomponents-compat test:cypress && yarn workspace @ui5/webcomponents-compat test",
5959
"ci:test:ai": "yarn workspace @ui5/webcomponents-ai test:ssr && yarn workspace @ui5/webcomponents-ai test",
6060

6161
"lint": "wsrun --exclude-missing lint",

packages/compat/.eslintignore

+2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
target
33
dist
44
src/generated
5+
cypress/*
56
lib
67
test
78
bundle.*.js
89
rollup.config*.js
910
wdio.conf.cjs
1011
postcss.config.cjs
12+
cypress.config.js
1113
package-scripts.cjs
1214
.eslintrc.cjs

packages/compat/cypress.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import cypressConfig from "@ui5/cypress-internal/cypress.config.js";
2+
3+
export default cypressConfig;
+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import Label from "@ui5/webcomponents/dist/Label.js";
2+
import Table from "../../src/Table.js";
3+
import TableCell from "../../src/TableCell.js";
4+
import TableRow from "../../src/TableRow.js";
5+
import TableColumn from "../../src/TableColumn.js";
6+
7+
describe("Table", () => {
8+
it("tests doesn't fire loadMore with ArrowDown on last row", () => {
9+
cy.mount(
10+
<Table>
11+
<TableColumn slot="columns" minWidth={350}>
12+
<Label>Product</Label>
13+
</TableColumn>
14+
15+
<TableColumn slot="columns" minWidth={800} popinText="Supplier">
16+
<Label>Supplier</Label>
17+
</TableColumn>
18+
19+
<TableColumn slot="columns" minWidth={600} popinText="Dimensions" demandPopin>
20+
<Label>Dimensions</Label>
21+
</TableColumn>
22+
23+
<TableRow>
24+
<TableCell>
25+
<Label>Product 1</Label>
26+
</TableCell>
27+
<TableCell>
28+
<Label>Supplier 1</Label>
29+
</TableCell>
30+
<TableCell>
31+
<Label>10x20x30</Label>
32+
</TableCell>
33+
</TableRow>
34+
35+
<TableRow>
36+
<TableCell>
37+
<Label>Product 2</Label>
38+
</TableCell>
39+
<TableCell>
40+
<Label>Supplier 2</Label>
41+
</TableCell>
42+
<TableCell>
43+
<Label>15x25x35</Label>
44+
</TableCell>
45+
</TableRow>
46+
47+
<TableRow id="row-3">
48+
<TableCell>
49+
<Label>Product 3</Label>
50+
</TableCell>
51+
<TableCell>
52+
<Label>Supplier 3</Label>
53+
</TableCell>
54+
<TableCell>
55+
<Label>20x30x40</Label>
56+
</TableCell>
57+
</TableRow>
58+
</Table>
59+
);
60+
61+
cy.get("[ui5-table]")
62+
.then(table => table.get(0).addEventListener("load-more", cy.stub().as("loadMore")));
63+
64+
cy.get("#row-3")
65+
.shadow()
66+
.find(".ui5-table-row-root")
67+
.as("lastRow")
68+
69+
cy.get("@lastRow")
70+
.realClick();
71+
72+
cy.get("@lastRow")
73+
.should("be.focused");
74+
75+
cy.get("@lastRow")
76+
.realPress("ArrowDown");
77+
78+
cy.get("@loadMore")
79+
.should("not.have.been.calledOnce");
80+
});
81+
82+
it("tests fire loadMore with ArrowDown on last row", () => {
83+
cy.mount(
84+
<Table growing="Scroll">
85+
<TableColumn slot="columns" minWidth={350}>
86+
<Label>Product</Label>
87+
</TableColumn>
88+
89+
<TableColumn slot="columns" minWidth={800} popinText="Supplier">
90+
<Label>Supplier</Label>
91+
</TableColumn>
92+
93+
<TableColumn slot="columns" minWidth={600} popinText="Dimensions" demandPopin>
94+
<Label>Dimensions</Label>
95+
</TableColumn>
96+
97+
<TableRow>
98+
<TableCell>
99+
<Label>Product 1</Label>
100+
</TableCell>
101+
<TableCell>
102+
<Label>Supplier 1</Label>
103+
</TableCell>
104+
<TableCell>
105+
<Label>10x20x30</Label>
106+
</TableCell>
107+
</TableRow>
108+
109+
<TableRow>
110+
<TableCell>
111+
<Label>Product 2</Label>
112+
</TableCell>
113+
<TableCell>
114+
<Label>Supplier 2</Label>
115+
</TableCell>
116+
<TableCell>
117+
<Label>15x25x35</Label>
118+
</TableCell>
119+
</TableRow>
120+
121+
<TableRow id="row-3">
122+
<TableCell>
123+
<Label>Product 3</Label>
124+
</TableCell>
125+
<TableCell>
126+
<Label>Supplier 3</Label>
127+
</TableCell>
128+
<TableCell>
129+
<Label>20x30x40</Label>
130+
</TableCell>
131+
</TableRow>
132+
</Table>
133+
);
134+
135+
cy.get("[ui5-table]")
136+
.then(tableGrowing => tableGrowing.get(0).addEventListener("load-more", cy.stub().as("loadMore")));
137+
138+
cy.get("#row-3")
139+
.shadow()
140+
.find(".ui5-table-row-root")
141+
.as("lastRow")
142+
143+
cy.get("@lastRow")
144+
.realClick();
145+
146+
cy.get("@lastRow")
147+
.should("be.focused");
148+
149+
cy.get("@lastRow")
150+
.realPress("ArrowDown");
151+
152+
cy.get("@loadMore")
153+
.should("have.been.calledOnce");
154+
});
155+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/// <reference types="cypress" />
2+
// ***********************************************
3+
// This example commands.ts shows you how to
4+
// create various custom commands and overwrite
5+
// existing commands.
6+
//
7+
// For more comprehensive examples of custom
8+
// commands please read more here:
9+
// https://on.cypress.io/custom-commands
10+
// ***********************************************
11+
//
12+
//
13+
// -- This is a parent command --
14+
// Cypress.Commands.add('login', (email, password) => { ... })
15+
//
16+
//
17+
// -- This is a child command --
18+
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
19+
//
20+
//
21+
// -- This is a dual command --
22+
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
23+
//
24+
//
25+
// -- This will overwrite an existing command --
26+
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
27+
//
28+
// declare global {
29+
// namespace Cypress {
30+
// interface Chainable {
31+
// login(email: string, password: string): Chainable<void>
32+
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
33+
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
34+
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
35+
// }
36+
// }
37+
// }
38+
39+
import "@ui5/cypress-internal/commands.js";
40+
import "../../../main/cypress/support/commands.js";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
7+
<title>Components App</title>
8+
</head>
9+
<body>
10+
<div data-cy-root></div>
11+
</body>
12+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// ***********************************************************
2+
// This example support/component.ts is processed and
3+
// loaded automatically before your test files.
4+
//
5+
// This is a great place to put global configuration and
6+
// behavior that modifies Cypress.
7+
//
8+
// You can change the location of this file or turn off
9+
// automatically serving support files with the
10+
// 'supportFile' configuration option.
11+
//
12+
// You can read more here:
13+
// https://on.cypress.io/configuration
14+
// ***********************************************************
15+
16+
// Import commands.js using ES2015 syntax:
17+
import './commands'

packages/compat/cypress/tsconfig.json

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"include": [
3+
"./**/*"
4+
],
5+
"compilerOptions": {
6+
"jsx": "react-jsx",
7+
"jsxImportSource": "@ui5/webcomponents-base",
8+
"module": "NodeNext",
9+
"moduleResolution": "nodenext",
10+
"types": [
11+
"cypress",
12+
"cypress-real-events",
13+
"cypress-axe",
14+
],
15+
"paths": {
16+
"@ui5/webcomponents-base/dist/*": [
17+
"../../base/src/*"
18+
],
19+
"@ui5/webcomponents/dist/*": [
20+
"../../main/src/*"
21+
],
22+
"@ui5/webcomponents-localization/dist/*": [
23+
"../../localization/src/*"
24+
],
25+
"@ui5/webcomponents-theming/dist/*": [
26+
"../../theming/src/*"
27+
],
28+
"@ui5/webcomponents-icons/dist/*": [
29+
"../../icons/src/*"
30+
],
31+
"@ui5/webcomponents-icons-business-suite/dist/*": [
32+
"../../icons-business-suite/src/*"
33+
],
34+
"@ui5/webcomponents-icons-tnt/dist/*": [
35+
"../../icons-tnt/src/*"
36+
]
37+
},
38+
},
39+
"references": [
40+
{
41+
"path": "../"
42+
},
43+
{
44+
"path": "../../main/cypress"
45+
}
46+
]
47+
}

packages/compat/package-scripts.cjs

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ const options = {
66
compatPackage: true,
77
noWatchTS: true,
88
dev: true,
9+
internal: {
10+
cypress_code_coverage: false,
11+
cypress_acc_tests: false,
12+
},
913
};
1014

1115
const scripts = getScripts(options);

packages/compat/package.json

+4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
"generateAPI": "nps generateAPI",
2727
"bundle": "nps build.bundle",
2828
"test": "wc-dev test",
29+
"test:cypress": "nps test-cy-ci",
30+
"test:cypress:single": "npx cypress run --component --browser chrome --spec",
31+
"test:cypress:open": "nps test-cy-open",
2932
"test:ssr": "node -e \"import('./test/ssr/component-imports.js')\"",
3033
"create-ui5-element": "wc-create-ui5-element",
3134
"prepublishOnly": "tsc -b"
@@ -51,6 +54,7 @@
5154
"@ui5/webcomponents-theming": "2.10.0-rc.3"
5255
},
5356
"devDependencies": {
57+
"@ui5/cypress-internal": "0.0.0",
5458
"@ui5/webcomponents-tools": "2.10.0-rc.3",
5559
"chromedriver": "^135.0.0"
5660
}

packages/compat/src/Table.ts

+7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
isTabPrevious,
1818
isSpace,
1919
isEnter,
20+
isDown,
2021
isCtrlA,
2122
isUpAlt,
2223
isDownAlt,
@@ -856,6 +857,12 @@ class Table extends UI5Element {
856857
this._itemNavigation.setCurrentItem(e.target as ITableRow);
857858
}
858859

860+
onRowKeyDown(e: KeyboardEvent) {
861+
if (this.growing === "Scroll" && isDown(e) && this.currentItemIdx === this.rows.length - 1) {
862+
debounce(this.loadMore.bind(this), GROWING_WITH_SCROLL_DEBOUNCE_RATE);
863+
}
864+
}
865+
859866
_onColumnHeaderFocused() {
860867
this._itemNavigation.setCurrentItem(this._columnHeader);
861868
}

packages/compat/src/TableTemplate.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export default function TableTemplate(this: Table) {
6262
<tbody>
6363
{
6464
this.rows.map(row =>
65-
<slot name={row._individualSlot}></slot>
65+
<slot name={row._individualSlot} onKeyDown={this.onRowKeyDown}></slot>
6666
)}
6767

6868
{!this.rows.length && !this.hideNoData &&

0 commit comments

Comments
 (0)