diff --git a/JSDemos/Demos/Form/Validation/Angular/app/app.component.html b/JSDemos/Demos/Form/Validation/Angular/app/app.component.html
index daddee27aef..bc18b670026 100644
--- a/JSDemos/Demos/Form/Validation/Angular/app/app.component.html
+++ b/JSDemos/Demos/Form/Validation/Angular/app/app.component.html
@@ -108,7 +108,7 @@
diff --git a/JSDemos/menuMeta.json b/JSDemos/menuMeta.json
index d47204c988f..74cb630c1a4 100644
--- a/JSDemos/menuMeta.json
+++ b/JSDemos/menuMeta.json
@@ -4543,6 +4543,7 @@
"Equivalents": "Submit",
"Name": "Validation",
"Widget": "Form",
+ "Badge": "Updated",
"MvcAdditionalFiles": [
"/Views/Form/SuccessValidation.cshtml",
"/ViewModels/EditorsViewModel.cs",
diff --git a/MVCDemos/Views/Form/Validation.cshtml b/MVCDemos/Views/Form/Validation.cshtml
index 42571b0ab60..a83ea2986de 100644
--- a/MVCDemos/Views/Form/Validation.cshtml
+++ b/MVCDemos/Views/Form/Validation.cshtml
@@ -132,12 +132,12 @@
formInstance = e.component;
}
- function onOptionChanged(e) {
- if(e.name === 'isDirty') {
- const resetButton = formInstance.getButton('Reset');
- resetButton.option('disabled', !e.value);
- }
- }
+ function onOptionChanged(e) {
+ if(e.name === 'isDirty') {
+ const resetButton = formInstance.getButton('Reset');
+ resetButton.option('disabled', !e.value);
+ }
+ }
function onResetButtonClick(e) {
formInstance.reset();
diff --git a/NetCoreDemos/Views/Form/Validation.cshtml b/NetCoreDemos/Views/Form/Validation.cshtml
index 96c4d2dbccb..06843fb7d43 100644
--- a/NetCoreDemos/Views/Form/Validation.cshtml
+++ b/NetCoreDemos/Views/Form/Validation.cshtml
@@ -133,12 +133,12 @@
formInstance = e.component;
}
- function onOptionChanged(e) {
- if(e.name === 'isDirty') {
- const resetButton = formInstance.getButton('Reset');
- resetButton.option('disabled', !e.value);
- }
- }
+ function onOptionChanged(e) {
+ if(e.name === 'isDirty') {
+ const resetButton = formInstance.getButton('Reset');
+ resetButton.option('disabled', !e.value);
+ }
+ }
function onResetButtonClick(e) {
formInstance.reset();
diff --git a/testing/widgets/common/etalons/common_dialogs_and_notifications_overview_popup.png b/testing/widgets/common/etalons/common_dialogs_and_notifications_overview_popup.png
index b0671352903..9e6017b4ece 100644
Binary files a/testing/widgets/common/etalons/common_dialogs_and_notifications_overview_popup.png and b/testing/widgets/common/etalons/common_dialogs_and_notifications_overview_popup.png differ
diff --git a/testing/widgets/datagrid/etalons/datagrid_column_customization_2.png b/testing/widgets/datagrid/etalons/datagrid_column_customization_2.png
index 3880070b262..4b6dc3528f6 100644
Binary files a/testing/widgets/datagrid/etalons/datagrid_column_customization_2.png and b/testing/widgets/datagrid/etalons/datagrid_column_customization_2.png differ
diff --git a/testing/widgets/form/Validation.test.js b/testing/widgets/form/Validation.test.js
new file mode 100644
index 00000000000..7e5a5cee486
--- /dev/null
+++ b/testing/widgets/form/Validation.test.js
@@ -0,0 +1,32 @@
+import { Selector as $ } from 'testcafe';
+import { createScreenshotsComparer } from 'devextreme-screenshot-comparer';
+import { runManualTest } from '../../../utils/visual-tests/matrix-test-helper';
+
+const FIELD_BUTTON_ITEM_CLASS = '.dx-field-button-item';
+const CHECKBOX_CLASS = '.dx-checkbox';
+
+fixture('Form.Validation')
+ .page('http://localhost:8080/')
+ .beforeEach(async (t) => {
+ await t
+ .resizeWindow(900, 1200);
+ });
+
+runManualTest('Form', 'Validation', ['jQuery', 'Vue', 'Angular'], (test) => {
+ test('Validation', async (t) => {
+ const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
+
+ await takeScreenshot('form_validation_summary.png');
+
+ await t.click($(FIELD_BUTTON_ITEM_CLASS).nth(1));
+ await takeScreenshot('form_validation_before_reset.png');
+
+ await t.click(CHECKBOX_CLASS);
+ await t.click($(FIELD_BUTTON_ITEM_CLASS).nth(0));
+ await takeScreenshot('form_validation_after_reset.png');
+
+ await t
+ .expect(compareResults.isValid())
+ .ok(compareResults.errorMessages());
+ });
+});
diff --git a/testing/widgets/form/etalons/form_validation_after_reset.png b/testing/widgets/form/etalons/form_validation_after_reset.png
new file mode 100644
index 00000000000..b38b8043cd9
Binary files /dev/null and b/testing/widgets/form/etalons/form_validation_after_reset.png differ
diff --git a/testing/widgets/form/etalons/form_validation_before_reset.png b/testing/widgets/form/etalons/form_validation_before_reset.png
new file mode 100644
index 00000000000..e797bde9807
Binary files /dev/null and b/testing/widgets/form/etalons/form_validation_before_reset.png differ
diff --git a/testing/widgets/form/etalons/form_validation_summary.png b/testing/widgets/form/etalons/form_validation_summary.png
new file mode 100644
index 00000000000..b38b8043cd9
Binary files /dev/null and b/testing/widgets/form/etalons/form_validation_summary.png differ
diff --git a/testing/widgets/pivotgrid/etalons/Integrated field chooser.png b/testing/widgets/pivotgrid/etalons/Integrated field chooser.png
index 3cf24d827d6..525b930db15 100644
Binary files a/testing/widgets/pivotgrid/etalons/Integrated field chooser.png and b/testing/widgets/pivotgrid/etalons/Integrated field chooser.png differ
diff --git a/testing/widgets/popup/etalons/popup with scrollable container.png b/testing/widgets/popup/etalons/popup with scrollable container.png
index c5bc1afcc6d..0179349f157 100644
Binary files a/testing/widgets/popup/etalons/popup with scrollable container.png and b/testing/widgets/popup/etalons/popup with scrollable container.png differ
diff --git a/testing/widgets/popup/etalons/popup with scrollview.png b/testing/widgets/popup/etalons/popup with scrollview.png
index 5cff0a537d8..d22dd86a67d 100644
Binary files a/testing/widgets/popup/etalons/popup with scrollview.png and b/testing/widgets/popup/etalons/popup with scrollview.png differ
diff --git a/testing/widgets/scheduler/customDragAndDrop.test.js b/testing/widgets/scheduler/customDragAndDrop.test.js
new file mode 100644
index 00000000000..eaf07637465
--- /dev/null
+++ b/testing/widgets/scheduler/customDragAndDrop.test.js
@@ -0,0 +1,46 @@
+import { createScreenshotsComparer } from 'devextreme-screenshot-comparer';
+import { runManualTest } from '../../../utils/visual-tests/matrix-test-helper';
+
+const LIST_SELECTOR = '#list.dx-draggable';
+const LIST_ITEM_SELECTOR = '.dx-card.dx-draggable';
+const DATE_TABLE_CELL_SELECTOR = '.dx-scheduler-date-table .dx-scheduler-date-table-cell';
+const ALL_DAY_PANEL_CELL_SELECTOR = '.dx-scheduler-all-day-table .dx-scheduler-all-day-table-cell';
+const DATE_TABLE_APPOINTMENT_SELECTOR = '.dx-scheduler-date-table-container .dx-scheduler-appointment';
+const ALL_DAY_PANEL_APPOINTMENT_SELECTOR = '.dx-scheduler-all-day-panel .dx-scheduler-appointment';
+
+const DRAG_MOUSE_OPTIONS = { speed: 0.5 };
+
+fixture('Scheduler.CustomDragAndDrop')
+ .page('http://localhost:8080/')
+ .beforeEach(async (t) => {
+ await t
+ .resizeWindow(900, 600);
+ });
+
+[
+ [LIST_ITEM_SELECTOR, DATE_TABLE_CELL_SELECTOR, 'list', 'date-table'],
+ [DATE_TABLE_APPOINTMENT_SELECTOR, LIST_SELECTOR, 'date-table', 'list'],
+ [LIST_ITEM_SELECTOR, ALL_DAY_PANEL_CELL_SELECTOR, 'list', 'all-day-panel'],
+ [ALL_DAY_PANEL_APPOINTMENT_SELECTOR, LIST_SELECTOR, 'all-day-panel', 'list'],
+].forEach(([
+ fromSelector,
+ toSelector,
+ fromName,
+ toName,
+]) => {
+ runManualTest('Scheduler', 'CustomDragAndDrop', ['jQuery', 'React', 'Vue', 'Angular'], (test) => {
+ test(`Should drag-and-drop from ${fromName} to ${toName}`, async (t) => {
+ const {
+ takeScreenshot,
+ compareResults,
+ } = createScreenshotsComparer(t);
+
+ await t.dragToElement(fromSelector, toSelector, DRAG_MOUSE_OPTIONS);
+ await takeScreenshot(`scheduler_custom-dnd_${fromName}_${toName}.png`);
+
+ await t
+ .expect(compareResults.isValid())
+ .ok(compareResults.errorMessages());
+ });
+ });
+});
diff --git a/testing/widgets/scheduler/etalons/scheduler_custom-dnd_all-day-panel_list.png b/testing/widgets/scheduler/etalons/scheduler_custom-dnd_all-day-panel_list.png
new file mode 100644
index 00000000000..ccf5adf08cb
Binary files /dev/null and b/testing/widgets/scheduler/etalons/scheduler_custom-dnd_all-day-panel_list.png differ
diff --git a/testing/widgets/scheduler/etalons/scheduler_custom-dnd_date-table_list.png b/testing/widgets/scheduler/etalons/scheduler_custom-dnd_date-table_list.png
new file mode 100644
index 00000000000..cabb80edfe3
Binary files /dev/null and b/testing/widgets/scheduler/etalons/scheduler_custom-dnd_date-table_list.png differ
diff --git a/testing/widgets/scheduler/etalons/scheduler_custom-dnd_list_all-day-panel.png b/testing/widgets/scheduler/etalons/scheduler_custom-dnd_list_all-day-panel.png
new file mode 100644
index 00000000000..4f63491dfb5
Binary files /dev/null and b/testing/widgets/scheduler/etalons/scheduler_custom-dnd_list_all-day-panel.png differ
diff --git a/testing/widgets/scheduler/etalons/scheduler_custom-dnd_list_date-table.png b/testing/widgets/scheduler/etalons/scheduler_custom-dnd_list_date-table.png
new file mode 100644
index 00000000000..4c294cbaaff
Binary files /dev/null and b/testing/widgets/scheduler/etalons/scheduler_custom-dnd_list_date-table.png differ
diff --git a/testing/widgets/toolbar/etalons/toolbar_singleline_mode_menu_open.png b/testing/widgets/toolbar/etalons/toolbar_singleline_mode_menu_open.png
index c8492410d76..e100709ee6f 100644
Binary files a/testing/widgets/toolbar/etalons/toolbar_singleline_mode_menu_open.png and b/testing/widgets/toolbar/etalons/toolbar_singleline_mode_menu_open.png differ