Skip to content

Commit c5a3b7a

Browse files
committed
Merge remote-tracking branch 'upstream/26_1' into 26_1_3814_replace_Function_in_d.ts
2 parents e8042a5 + d05f924 commit c5a3b7a

File tree

66 files changed

+1042
-108
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1042
-108
lines changed

apps/react-storybook/stories/chat/Chat.stories.tsx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import HTMLReactParser from 'html-react-parser';
2323
import './styles.css';
2424
import { Guid } from 'devextreme-react/cjs/common';
2525
import { Message } from 'devextreme/artifacts/npm/devextreme/ui/chat';
26+
import type { ItemClickEvent as ButtonGroupItemClickEvent, Item as ButtonGroupItem } from 'devextreme/ui/button_group';
2627

2728
const meta: Meta<typeof Chat> = {
2829
title: 'Components/Chat',
@@ -1039,3 +1040,61 @@ export const SendButtonOptions: Story = {
10391040
);
10401041
},
10411042
};
1043+
1044+
const suggestionItems: ButtonGroupItem[] = [
1045+
{ text: '📦 Track my orders' },
1046+
{ text: '⭐ Check in-stock favorites' },
1047+
{ text: '🔄 Start a return' },
1048+
{ text: '🔍 Find my order' },
1049+
{ text: '💳 Payment & billing help with Soul' },
1050+
];
1051+
1052+
export const Suggestions: Story = {
1053+
args: {
1054+
sendImmediately: false,
1055+
},
1056+
argTypes: {
1057+
sendImmediately: {
1058+
name: 'Send immediately on suggestion click',
1059+
control: 'boolean',
1060+
},
1061+
},
1062+
render: ({ sendImmediately }) => {
1063+
const [messages, setMessages] = useState<ChatTypes.Message[]>([]);
1064+
const [inputFieldText, setInputFieldText] = useState('');
1065+
1066+
const onMessageEntered = useCallback(({ message }: ChatTypes.MessageEnteredEvent) => {
1067+
setMessages((prev) => [...prev, message]);
1068+
setInputFieldText('');
1069+
}, []);
1070+
1071+
const suggestions = useMemo<ChatTypes.Properties['suggestions']>(() => ({
1072+
items: suggestionItems,
1073+
onItemClick: (e: ButtonGroupItemClickEvent) => {
1074+
if (sendImmediately) {
1075+
setMessages((prev) => [...prev, {
1076+
timestamp: new Date(),
1077+
author: firstAuthor,
1078+
text: e.itemData?.text,
1079+
}]);
1080+
} else {
1081+
setInputFieldText(e.itemData?.text ?? '');
1082+
}
1083+
},
1084+
}), [sendImmediately]);
1085+
1086+
return (
1087+
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
1088+
<Chat
1089+
width={740}
1090+
height={500}
1091+
items={messages}
1092+
user={firstAuthor}
1093+
inputFieldText={inputFieldText}
1094+
onMessageEntered={onMessageEntered}
1095+
suggestions={suggestions}
1096+
/>
1097+
</div>
1098+
);
1099+
},
1100+
};
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/**
2+
* ESLint rule: no-is-ready-without-expect
3+
*
4+
* Disallows calling `.isReady()` outside of `t.expect()`.
5+
*
6+
* Correct:
7+
* await t.expect(dataGrid.isReady()).ok()
8+
* or
9+
* await t
10+
* .expect(dataGrid.isReady())
11+
* .ok()
12+
*
13+
* Incorrect:
14+
* await dataGrid.isReady()
15+
* dataGrid.isReady()
16+
* const ready = await dataGrid.isReady()
17+
*/
18+
19+
/* eslint-disable spellcheck/spell-checker */
20+
module.exports = {
21+
meta: {
22+
type: 'problem',
23+
docs: {
24+
description: 'Disallow calling .isReady() outside of t.expect()',
25+
},
26+
messages: {
27+
noIsReadyWithoutExpect:
28+
'isReady() must be used inside t.expect(), e.g.: await t.expect(widget.isReady()).ok()',
29+
},
30+
schema: [],
31+
},
32+
create(context) {
33+
return {
34+
CallExpression(node) {
35+
const { callee } = node;
36+
37+
if (
38+
callee.type !== 'MemberExpression'
39+
|| callee.property.type !== 'Identifier'
40+
|| callee.property.name !== 'isReady'
41+
) {
42+
return;
43+
}
44+
45+
// Walk up to find if this call is an argument of .expect()
46+
let current = node;
47+
let parent = current.parent;
48+
49+
while(parent) {
50+
if (
51+
parent.type === 'CallExpression'
52+
&& parent.callee.type === 'MemberExpression'
53+
&& parent.callee.property.type === 'Identifier'
54+
&& parent.callee.property.name === 'expect'
55+
) {
56+
// isReady() is inside .expect() — allowed
57+
return;
58+
}
59+
60+
current = parent;
61+
parent = current.parent;
62+
}
63+
64+
context.report({
65+
node,
66+
messageId: 'noIsReadyWithoutExpect',
67+
});
68+
},
69+
};
70+
},
71+
};

e2e/testcafe-devextreme/eslint.config.mjs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import spellCheckConfig from 'eslint-config-devextreme/spell-check';
1313
import typescriptConfig from 'eslint-config-devextreme/typescript';
1414
import testcafeConfig from 'eslint-config-devextreme/testcafe';
1515

16+
import noIsReadyWithoutExpect from './eslint-rules/no-is-ready-without-expect.js';
17+
1618
const __filename = fileURLToPath(import.meta.url);
1719
const __dirname = path.dirname(__filename);
1820
const compatibility = new FlatCompatibility({
@@ -258,4 +260,22 @@ export default [
258260
'@typescript-eslint/no-empty-object-type': 'off',
259261
}
260262
},
263+
{
264+
files: [
265+
'tests/dataGrid/**/*.ts',
266+
'tests/cardView/**/*.ts',
267+
'tests/common/treeList/**/*.ts',
268+
'tests/common/filterBuilder/**/*.ts',
269+
],
270+
plugins: {
271+
'local': {
272+
rules: {
273+
'no-is-ready-without-expect': noIsReadyWithoutExpect,
274+
},
275+
},
276+
},
277+
rules: {
278+
'local/no-is-ready-without-expect': 'error',
279+
},
280+
},
261281
];

e2e/testcafe-devextreme/tests/cardView/editing/editing.functional.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,14 @@ const config = {
3030

3131
test('should show default values in popup fields after onInitNewCard', async (t) => {
3232
const cardView = new CardView(CARD_VIEW_SELECTOR);
33-
await cardView.isReady();
33+
await t
34+
.expect(cardView.isReady())
35+
.ok();
3436

3537
await t.click(cardView.getToolbar().getAddButton().element);
36-
await cardView.isReady();
38+
await t
39+
.expect(cardView.isReady())
40+
.ok();
3741

3842
const popup = cardView.getEditingPopup();
3943

e2e/testcafe-devextreme/tests/common/filterBuilder/filterBuilderScrolling.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ fixture.disablePageReloads`Filter Builder Scrolling Test`
1111
test('FilterBuilder - The field drop-down closes with the page scroll', async (t) => {
1212
const filterBuilder = new FilterBuilder('#container');
1313

14-
await filterBuilder.isReady();
14+
await t
15+
.expect(filterBuilder.isReady())
16+
.ok();
1517

1618
await t
1719
.click(filterBuilder.getItem('operation'))

e2e/testcafe-devextreme/tests/common/treeList/adaptiveRow.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ fixture.disablePageReloads`Adaptive Row`
77

88
test.meta({ browserSize: [400, 400] })('Should be shown and hidden when the window is resized', async (t) => {
99
const treeList = new TreeList('#container');
10-
await treeList.isReady();
10+
await t
11+
.expect(treeList.isReady())
12+
.ok();
1113

1214
const adaptiveButton = treeList.getAdaptiveButton();
1315
await t.expect(adaptiveButton.exists).ok();

e2e/testcafe-devextreme/tests/common/treeList/rowDragging.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ test('TreeList - Expand/collapse mechanism breaks after dragging action in the s
6767
test(`TreeList - The W1025 warning occurs when dragging a row (height: ${height ?? 'not set'}). (T1280519)`, async (t) => {
6868
const treeList = new TreeList('#container');
6969

70-
await treeList.isReady();
70+
await t
71+
.expect(treeList.isReady())
72+
.ok();
7173

7274
await treeList.moveRow(0, 10, 10, true);
7375

e2e/testcafe-devextreme/tests/common/treeList/toast.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ fixture.disablePageReloads`Toasts in TreeList`
1010
test('Toast should be visible after calling and should be not visible after default display time', async (t) => {
1111
const treeList = new TreeList('#container');
1212
const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
13-
await treeList.isReady();
13+
await t
14+
.expect(treeList.isReady())
15+
.ok();
16+
1417
await treeList.apiShowErrorToast();
1518
await t.expect(treeList.getToast().exists).ok();
1619

@@ -21,5 +24,5 @@ test('Toast should be visible after calling and should be not visible after defa
2124
.ok(compareResults.errorMessages());
2225
await t.expect(treeList.getToast().exists).notOk();
2326
}).before(async () => {
24-
createWidget('dxTreeList', {});
27+
await createWidget('dxTreeList', {});
2528
});

e2e/testcafe-devextreme/tests/dataGrid/common/adaptivity/functional.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ fixture.disablePageReloads`Adaptivity.Functional`
77

88
test.meta({ browserSize: [400, 400] })('Should be shown and hidden when the window is resized', async (t) => {
99
const dataGrid = new DataGrid('#container');
10-
await dataGrid.isReady();
10+
await t
11+
.expect(dataGrid.isReady())
12+
.ok();
1113

1214
const adaptiveButton = dataGrid.getAdaptiveButton();
1315
await t.expect(adaptiveButton.exists).ok();

e2e/testcafe-devextreme/tests/dataGrid/common/columnChooser.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,10 @@ test(
277277

278278
test('ColumnChooser should receive and render custom texts', async (t) => {
279279
const dataGrid = new DataGrid('#container');
280-
await dataGrid.isReady();
280+
await t
281+
.expect(dataGrid.isReady())
282+
.ok();
283+
281284
const columnChooserBtn = dataGrid.getColumnChooserButton();
282285
await t.click(columnChooserBtn);
283286
const columnChooser = dataGrid.getColumnChooser();

0 commit comments

Comments
 (0)