diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (fluent-blue-light).png index 9113860dbd0f..51d337f2ba1a 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (generic-light).png index f7f10e1f89a3..008248bc24e9 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (material-blue-light).png index 603c3dbb305c..c50e7d2e1eaf 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (fluent-blue-light).png index 50e6c9799d2f..0a2b6aacfa50 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (generic-light).png index 15e2bc9bb657..a168bac10913 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (material-blue-light).png index fb5e85843073..14da190025b7 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (fluent-blue-light).png index ab720dd8a7fa..666b38cd0066 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (generic-light).png index bfed395bc43c..7d2ae7d59074 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (material-blue-light).png index 79076f1ebed0..e129e5fbdd67 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (fluent-blue-light).png index 2c0db88a1203..dc6b6d171606 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (generic-light).png index 143a095a79f6..8779673709bf 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (material-blue-light).png index 42933fd04ce3..de1168d5f1d3 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (fluent-blue-light).png index 50bcc841b5c4..7eb8751ec7f9 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (generic-light).png index 29bbeae5f8ed..3c36839b0983 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (material-blue-light).png index 518530c20907..3ab1ca8343c0 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (fluent-blue-light).png index 124e9dd832a7..c1f199132898 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (generic-light).png index b013c66e7ebb..924eb92c0681 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (material-blue-light).png index a820c739272a..653b1263c5ee 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist appearance in RTL mode (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist appearance in RTL mode (fluent-blue-light).png index b528bcfe0e7d..d470457d6dd1 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist appearance in RTL mode (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist appearance in RTL mode (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist appearance in RTL mode (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist appearance in RTL mode (generic-light).png index abcf805c54fe..217ffc2fbc5a 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist appearance in RTL mode (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist appearance in RTL mode (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist appearance in RTL mode (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist appearance in RTL mode (material-blue-light).png index cf5432e3531d..78f12b4e4be1 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist appearance in RTL mode (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist appearance in RTL mode (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (fluent-blue-dark).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (fluent-blue-dark).png index d9327c3d7469..8140a01656e3 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (fluent-blue-dark).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (fluent-blue-dark).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (fluent-blue-light).png index 240a9d916dd2..df6caafefb09 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (fluent-blue-light-compact).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (fluent-blue-light-compact).png index 415520c1eecd..818cc761d650 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (fluent-blue-light-compact).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (fluent-blue-light-compact).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (generic-dark).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (generic-dark).png index 7635c747a9a4..6eb9d783890c 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (generic-dark).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (generic-dark).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (generic-light).png index a5e2c155957f..1a081f4748da 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (generic-light-compact).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (generic-light-compact).png index 9355f94ccee6..cf169786b383 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (generic-light-compact).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (generic-light-compact).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (material-blue-dark).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (material-blue-dark).png index 5d1d6fe2b3da..71f9558ceda9 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (material-blue-dark).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (material-blue-dark).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (material-blue-light).png index c69689c3bd94..ba0a52823504 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (material-blue-light-compact).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (material-blue-light-compact).png index f6e1855d3a77..96ad4bf64856 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (material-blue-light-compact).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with long text in error (material-blue-light-compact).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with one error (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with one error (fluent-blue-light).png index 8afa18fe9ef0..dcc49f3ef53e 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with one error (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with one error (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with one error (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with one error (generic-light).png index 4a67d04580a8..7e08bd657282 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with one error (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with one error (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with one error (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with one error (material-blue-light).png index 0374bfa8ff0e..bc2de203a6ad 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with one error (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Errorlist with one error (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (fluent-blue-light).png index 7fa272de690c..86c1a7b55717 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (generic-light).png index 1a2b6656e642..c44c1df506ba 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (material-blue-light).png index 848505e7b11c..101273f2b366 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (fluent-blue-light).png index 35810cb82719..5ff050e2dd9d 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (generic-light).png index 0ace0185d84d..842b10dc2058 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (material-blue-light).png index a50e0e636243..781c02fff227 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (fluent-blue-light).png index d194ad2dcda1..e515963366f9 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (generic-light).png index 5ef4d8f32be4..52ef0bf57c49 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (material-blue-light).png index 76a033ad091d..0e7ed02ae013 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (fluent-blue-light).png index 4375859afe37..bf6f55e4ec91 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (generic-light).png index cde1a2d08f59..39f814274e5d 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (material-blue-light).png index 767b36b41372..450260aa5083 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (fluent-blue-light).png index a63e03af7570..ae979acf5fd0 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (generic-light).png index c3450cb82793..d4c7cc3bccba 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (material-blue-light).png index 78f62ffc75f0..51324961d5ba 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (fluent-blue-light).png index e7121a899632..c49d94d026c5 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (generic-light).png index 9f90ef26c755..0388d03d6d79 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (material-blue-light).png index 8c2a31bcbcea..fa11f3b18c66 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (fluent-blue-light).png index 4b7d6547ead8..575b3c052315 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (generic-light).png index 979c6d320109..bdf02946671b 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (material-blue-light).png index 5dbe93970033..8b1da8770302 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (fluent-blue-light).png index 27149b15c5f8..10395c2e22e0 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (generic-light).png index f90c15523702..8af835a85ff4 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (material-blue-light).png index ec87071b72df..86e1423b1261 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after call renderMessage() (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after call renderMessage() (fluent-blue-light).png index f8978cccfa7f..2f70dd3fcce8 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after call renderMessage() (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after call renderMessage() (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after call renderMessage() (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after call renderMessage() (generic-light).png index f5d024005347..f0fbb543e17e 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after call renderMessage() (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after call renderMessage() (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after call renderMessage() (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after call renderMessage() (material-blue-light).png index 06bbf73f8d15..3902dbd0dee0 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after call renderMessage() (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after call renderMessage() (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after typing in textarea (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after typing in textarea (fluent-blue-light).png index a6590b3bf184..da5ebfb1da2f 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after typing in textarea (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after typing in textarea (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after typing in textarea (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after typing in textarea (generic-light).png index eb8821f55c26..399d28c524c4 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after typing in textarea (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after typing in textarea (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after typing in textarea (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after typing in textarea (material-blue-light).png index 20bbdbd6fe35..a661dde69cb2 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after typing in textarea (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scrollbar position after typing in textarea (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with a lot of messages (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with a lot of messages (fluent-blue-light).png index 29c94dff4744..8958a7d64a0e 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with a lot of messages (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with a lot of messages (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with a lot of messages (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with a lot of messages (generic-light).png index 1edab78e520a..0c2b69cfdea6 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with a lot of messages (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with a lot of messages (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with a lot of messages (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with a lot of messages (material-blue-light).png index c239f46b6290..475fbd10d0d7 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with a lot of messages (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with a lot of messages (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (fluent-blue-light).png index 2338fe0e7789..aa6d5b9dcea3 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (generic-light).png index 97ed47eab40c..349cbab2548f 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (material-blue-light).png index bd2a374b47b5..8742892592c0 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (material-blue-light).png differ diff --git a/packages/devextreme/js/__internal/ui/chat/chat.ts b/packages/devextreme/js/__internal/ui/chat/chat.ts index 1dedf1bf99e5..3a64adfd0819 100644 --- a/packages/devextreme/js/__internal/ui/chat/chat.ts +++ b/packages/devextreme/js/__internal/ui/chat/chat.ts @@ -5,6 +5,7 @@ import $ from '@js/core/renderer'; import { isDefined } from '@js/core/utils/type'; import type { Options as DataSourceOptions } from '@js/data/data_source'; import DataHelperMixin from '@js/data_helper'; +import type { Format } from '@js/localization'; import messageLocalization from '@js/localization/message'; import type { Message, @@ -31,6 +32,8 @@ const TEXTEDITOR_INPUT_CLASS = 'dx-texteditor-input'; type Properties = ChatProperties & { title: string; + dayHeaderFormat?: Format; + messageTimestampFormat?: Format; }; class Chat extends Widget { @@ -59,6 +62,8 @@ class Chat extends Widget { items: [], dataSource: null, user: { id: new Guid().toString() }, + dayHeaderFormat: 'shortdate', + messageTimestampFormat: 'shorttime', errors: [], onMessageSend: undefined, onTypingStart: undefined, @@ -124,7 +129,13 @@ class Chat extends Widget { } _renderMessageList(): void { - const { items = [], user, showDayHeaders = true } = this.option(); + const { + items = [], + user, + showDayHeaders = true, + dayHeaderFormat, + messageTimestampFormat, + } = this.option(); const currentUserId = user?.id; const $messageList = $('
'); @@ -137,6 +148,8 @@ class Chat extends Widget { showDayHeaders, // @ts-expect-error isLoading: this._dataController.isLoading(), + dayHeaderFormat, + messageTimestampFormat, }); } @@ -298,6 +311,8 @@ class Chat extends Widget { this._createTypingEndAction(); break; case 'showDayHeaders': + case 'dayHeaderFormat': + case 'messageTimestampFormat': this._messageList.option(name, value); break; default: diff --git a/packages/devextreme/js/__internal/ui/chat/messagegroup.ts b/packages/devextreme/js/__internal/ui/chat/messagegroup.ts index 8d15fc978bd8..0f034b393706 100644 --- a/packages/devextreme/js/__internal/ui/chat/messagegroup.ts +++ b/packages/devextreme/js/__internal/ui/chat/messagegroup.ts @@ -1,7 +1,9 @@ import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import dateSerialization from '@js/core/utils/date_serialization'; -import { isDefined } from '@js/core/utils/type'; +import { isDate } from '@js/core/utils/type'; +import type { Format } from '@js/localization'; +import dateLocalization from '@js/localization/date'; import messageLocalization from '@js/localization/message'; import type { Message } from '@js/ui/chat'; import type { WidgetOptions } from '@js/ui/widget/ui.widget'; @@ -24,6 +26,7 @@ export type MessageGroupAlignment = 'start' | 'end'; export interface Properties extends WidgetOptions { items: Message[]; alignment: MessageGroupAlignment; + messageTimestampFormat?: Format; } class MessageGroup extends Widget { @@ -36,6 +39,7 @@ class MessageGroup extends Widget { ...super._getDefaultOptions(), items: [], alignment: 'start', + messageTimestampFormat: 'shorttime', }; } @@ -131,19 +135,29 @@ class MessageGroup extends Widget { .addClass(CHAT_MESSAGEGROUP_TIME_CLASS) .appendTo($information); - if (isDefined(timestamp)) { - $time.text(this._getTimeValue(timestamp)); + const shouldAddTimeValue = this._shouldAddTimeValue(timestamp); + + if (shouldAddTimeValue) { + const timeValue = this._getTimeValue(timestamp); + $time.text(timeValue); } $information.appendTo(this.element()); } - _getTimeValue(timestamp: Date | string | number): string { - const options: Intl.DateTimeFormatOptions = { hour: '2-digit', minute: '2-digit', hour12: false }; - const date = dateSerialization.deserializeDate(timestamp); + _shouldAddTimeValue(timestamp: Date | string | number | undefined): boolean { + const deserializedDate = dateSerialization.deserializeDate(timestamp); + + return isDate(deserializedDate) && !isNaN(deserializedDate.getTime()); + } + + _getTimeValue(timestamp: Date | string | number | undefined): string { + const deserializedDate = dateSerialization.deserializeDate(timestamp); + + const { messageTimestampFormat } = this.option(); + const formattedTime = dateLocalization.format(deserializedDate, messageTimestampFormat); - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return date.toLocaleTimeString(undefined, options); + return formattedTime as string; } _optionChanged(args: OptionChanged): void { @@ -152,6 +166,7 @@ class MessageGroup extends Widget { switch (name) { case 'items': case 'alignment': + case 'messageTimestampFormat': this._invalidate(); break; default: diff --git a/packages/devextreme/js/__internal/ui/chat/messagelist.ts b/packages/devextreme/js/__internal/ui/chat/messagelist.ts index ab4c72f33e92..0675db8937e6 100644 --- a/packages/devextreme/js/__internal/ui/chat/messagelist.ts +++ b/packages/devextreme/js/__internal/ui/chat/messagelist.ts @@ -7,6 +7,8 @@ import dateUtils from '@js/core/utils/date'; import dateSerialization from '@js/core/utils/date_serialization'; import { isElementInDom } from '@js/core/utils/dom'; import { isDate, isDefined } from '@js/core/utils/type'; +import type { Format } from '@js/localization'; +import dateLocalization from '@js/localization/date'; import messageLocalization from '@js/localization/message'; import { getScrollTopMax } from '@js/renovation/ui/scroll_view/utils/get_scroll_top_max'; import type { Message } from '@js/ui/chat'; @@ -35,6 +37,8 @@ export interface Properties extends WidgetOptions { items: Message[]; currentUserId: number | string | undefined; showDayHeaders: boolean; + dayHeaderFormat?: Format; + messageTimestampFormat?: Format; isLoading?: boolean; } @@ -53,6 +57,8 @@ class MessageList extends Widget { items: [], currentUserId: '', showDayHeaders: true, + dayHeaderFormat: 'shortdate', + messageTimestampFormat: 'shorttime', isLoading: false, }; } @@ -162,10 +168,12 @@ class MessageList extends Widget { _createMessageGroupComponent(items: Message[], userId: string | number | undefined): void { const $messageGroup = $('
').appendTo(this._$content()); + const { messageTimestampFormat } = this.option(); const messageGroup = this._createComponent($messageGroup, MessageGroup, { items, alignment: this._messageGroupAlignment(userId), + messageTimestampFormat, }); this._messageGroups?.push(messageGroup); @@ -204,13 +212,10 @@ class MessageList extends Widget { const deserializedDate = dateSerialization.deserializeDate(timestamp); const today = new Date(); const yesterday = new Date(new Date().setDate(today.getDate() - 1)); + const { dayHeaderFormat } = this.option(); this._lastMessageDate = deserializedDate; - let headerDate = deserializedDate.toLocaleDateString(undefined, { - day: '2-digit', - month: '2-digit', - year: 'numeric', - }).replace(/[/-]/g, '.'); + let headerDate = dateLocalization.format(deserializedDate, dayHeaderFormat); if (dateUtils.sameDate(deserializedDate, today)) { headerDate = `${messageLocalization.format('Today')} ${headerDate}`; @@ -222,7 +227,7 @@ class MessageList extends Widget { $('
') .addClass(CHAT_MESSAGELIST_DAY_HEADER_CLASS) - .text(headerDate) + .text(headerDate as string) .appendTo(this._$content()); } @@ -415,6 +420,8 @@ class MessageList extends Widget { this._processItemsUpdating(value ?? [], previousValue ?? []); break; case 'showDayHeaders': + case 'dayHeaderFormat': + case 'messageTimestampFormat': this._invalidate(); break; case 'isLoading': diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/chat.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/chat.tests.js index a163f2147eff..79e6bd72c746 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/chat.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/chat.tests.js @@ -30,7 +30,7 @@ const MOCK_CHAT_HEADER_TEXT = 'Chat title'; export const MOCK_COMPANION_USER_ID = 'COMPANION_USER_ID'; export const MOCK_CURRENT_USER_ID = 'CURRENT_USER_ID'; -export const NOW = '1721747399083'; +export const NOW = 1721747399083; export const userFirst = { id: MOCK_COMPANION_USER_ID, @@ -209,6 +209,58 @@ QUnit.module('Chat', () => { assert.strictEqual(messageList.option('showDayHeaders'), false, 'showDayHeaders is passed on runtime'); }); + + QUnit.test('dayHeaderFormat option value should be passed to messageList on init', function(assert) { + const dayHeaderFormat = 'dd of MMMM, yyyy'; + + this.reinit({ + dayHeaderFormat, + }); + + const messageList = this.getMessageList(); + + assert.strictEqual(messageList.option('dayHeaderFormat'), dayHeaderFormat, 'dayHeaderFormat is passed on init'); + }); + + QUnit.test('messageTimestampFormat option value should be passed to messageList on init', function(assert) { + const messageTimestampFormat = 'hh hours and mm minutes'; + + this.reinit({ + messageTimestampFormat, + }); + + const messageList = this.getMessageList(); + + assert.strictEqual(messageList.option('messageTimestampFormat'), messageTimestampFormat, 'messageTimestampFormat is passed on init'); + }); + + QUnit.test('dayHeaderFormat option value should be passed to messageList at runtime', function(assert) { + const dayHeaderFormat = 'dd of MMMM, yyyy'; + + this.reinit({ + dayHeaderFormat: 'yyyy', + }); + + this.instance.option('dayHeaderFormat', dayHeaderFormat); + + const messageList = this.getMessageList(); + + assert.strictEqual(messageList.option('dayHeaderFormat'), dayHeaderFormat, 'dayHeaderFormat is updated at runtime'); + }); + + QUnit.test('messageTimestampFormat option value should be passed to messageList at runtime', function(assert) { + const messageTimestampFormat = 'hh hours and mm minutes'; + + this.reinit({ + messageTimestampFormat: 'hh', + }); + + this.instance.option('messageTimestampFormat', messageTimestampFormat); + + const messageList = this.getMessageList(); + + assert.strictEqual(messageList.option('messageTimestampFormat'), messageTimestampFormat, 'messageTimestampFormat is updated at runtime'); + }); }); QUnit.module('ErrorList integration', { diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageGroup.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageGroup.tests.js index c6285053d0f1..39ba2c992672 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageGroup.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageGroup.tests.js @@ -2,12 +2,17 @@ import $ from 'jquery'; import MessageGroup from '__internal/ui/chat/messagegroup'; import ChatAvatar from '__internal/ui/chat/avatar'; +import dateLocalization from 'localization/date'; const AVATAR_CLASS = 'dx-avatar'; const CHAT_MESSAGEGROUP_TIME_CLASS = 'dx-chat-messagegroup-time'; const CHAT_MESSAGEBUBBLE_CLASS = 'dx-chat-messagebubble'; const CHAT_MESSAGEGROUP_AUTHOR_NAME_CLASS = 'dx-chat-messagegroup-author-name'; +const getStringTime = (time) => { + return dateLocalization.format(time, 'shorttime'); +}; + const moduleConfig = { beforeEach: function() { const init = (options = {}) => { @@ -46,7 +51,7 @@ QUnit.module('MessageGroup', moduleConfig, () => { const $time = this.$element.find(`.${CHAT_MESSAGEGROUP_TIME_CLASS}`); assert.strictEqual($time.length, 1); - assert.strictEqual($time.text(), '21:34', 'time text is correct'); + assert.strictEqual($time.text(), getStringTime(new Date(timestamp)), 'time text is correct'); }); }); @@ -63,7 +68,38 @@ QUnit.module('MessageGroup', moduleConfig, () => { const $time = this.$element.find(`.${CHAT_MESSAGEGROUP_TIME_CLASS}`); - assert.strictEqual($time.text(), '21:34'); + assert.strictEqual($time.text(), getStringTime(messageTimeFirst)); + }); + + QUnit.test('time should have formatted value if messageTimestampFormat is specified on init', function(assert) { + const messageTime = new Date(2021, 9, 17, 4, 20); + + this.reinit({ + items: [ + { timestamp: messageTime }, + ], + messageTimestampFormat: 'hh_mm', + }); + + const $time = this.$element.find(`.${CHAT_MESSAGEGROUP_TIME_CLASS}`); + + assert.strictEqual($time.text(), '04_20'); + }); + + QUnit.test('time should have formatted value if messageTimestampFormat is specified at runtime', function(assert) { + const messageTime = new Date(2021, 9, 17, 4, 20); + + this.reinit({ + items: [ + { timestamp: messageTime }, + ], + }); + + this.instance.option('messageTimestampFormat', 'hh...mm'); + + const $time = this.$element.find(`.${CHAT_MESSAGEGROUP_TIME_CLASS}`); + + assert.strictEqual($time.text(), '04...20'); }); }); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageList.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageList.tests.js index 25bf501d3fe3..1156a6046fe4 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageList.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageList.tests.js @@ -11,6 +11,7 @@ import { } from './chat.tests.js'; import MessageGroup from '__internal/ui/chat/messagegroup'; import localization from 'localization'; +import dateLocalization from 'localization/date'; const CHAT_MESSAGEGROUP_CLASS = 'dx-chat-messagegroup'; const CHAT_MESSAGEBUBBLE_CLASS = 'dx-chat-messagebubble'; @@ -24,11 +25,7 @@ const SCROLLVIEW_REACHBOTTOM_INDICATOR = 'dx-scrollview-scrollbottom'; const MS_IN_DAY = 86400000; const getStringDate = (date) => { - return date.toLocaleDateString(undefined, { - day: '2-digit', - month: '2-digit', - year: 'numeric', - }).replace(/[/-]/g, '.'); + return dateLocalization.format(date, 'shortdate'); }; const SCROLLVIEW_CLASS = 'dx-scrollview'; @@ -54,8 +51,8 @@ const moduleConfig = { } }; -QUnit.module('MessageList', moduleConfig, () => { - QUnit.module('Render', () => { +QUnit.module('MessageList', () => { + QUnit.module('Render', moduleConfig, () => { QUnit.test('should be initialized with correct type', function(assert) { assert.ok(this.instance instanceof MessageList); }); @@ -357,7 +354,7 @@ QUnit.module('MessageList', moduleConfig, () => { let $dayHeaders = this.getDayHeaders(); - assert.strictEqual($dayHeaders.length, 1, 'day header was aaded'); + assert.strictEqual($dayHeaders.length, 1, 'day header was added'); this.instance.option({ items }); @@ -411,7 +408,69 @@ QUnit.module('MessageList', moduleConfig, () => { }); }); - QUnit.module('MessageGroup integration', () => { + QUnit.module('Options', () => { + QUnit.module('dayHeaderFormat', { + beforeEach: function() { + this.clock = sinon.useFakeTimers(new Date('2021/10/17')); + moduleConfig.beforeEach.apply(this, arguments); + }, + afterEach: function() { + this.clock.restore(); + } + }, () => { + [{ + getTimestamp: () => new Date(), + scenario: 'today', + expectedDayHeaderText: 'Today 17 of October, 2021', + }, + { + getTimestamp: () => new Date(Date.now() - MS_IN_DAY), + dayHeaderPrefix: 'Yesterday ', + scenario: 'yesterday', + expectedDayHeaderText: 'Yesterday 16 of October, 2021', + }, { + getTimestamp: () => new Date('10.10.2024'), + dayHeaderPrefix: '', + scenario: '10.10.2024', + expectedDayHeaderText: '10 of October, 2024', + }].forEach(({ getTimestamp, scenario, expectedDayHeaderText }) => { + QUnit.test(`Day header should be formatted when dayHeaderFormat is specified on init (timestamp=${scenario})`, function(assert) { + const items = [{ + timestamp: getTimestamp(), + text: 'A', + }]; + + this.reinit({ + items, + dayHeaderFormat: 'dd of MMMM, yyyy', + }); + + const $dayHeaders = this.getDayHeaders(); + + assert.strictEqual($dayHeaders.text(), expectedDayHeaderText, 'day header has formatted text'); + }); + + QUnit.test(`Day header should be formatted when dayHeaderFormat is specified at runtime (timestamp=${scenario})`, function(assert) { + const items = [{ + timestamp: getTimestamp(), + text: 'A', + }]; + + this.reinit({ + items, + }); + + this.instance.option('dayHeaderFormat', 'dd of MMMM, yyyy'); + + const $dayHeaders = this.getDayHeaders(); + + assert.strictEqual($dayHeaders.text(), expectedDayHeaderText, 'day header has formatted text'); + }); + }); + }); + }); + + QUnit.module('MessageGroup integration', moduleConfig, () => { QUnit.test('message group component should not be rendered if items is empty', function(assert) { const $messageGroups = this.$element.find(`.${CHAT_MESSAGEGROUP_CLASS}`); @@ -636,9 +695,32 @@ QUnit.module('MessageList', moduleConfig, () => { assert.strictEqual($firstMessageGroupBubbles.length, 2, 'correct bubble count'); assert.strictEqual($secondMessageGroupBubbles.length, 1, 'correct bubble count'); }); + + QUnit.test('messageTimestampFormat should be passed to message group on init', function(assert) { + this.reinit({ + items: [{ timestamp: '2024-09-26T14:00:00', text: 'text' }], + messageTimestampFormat: 'hh.mm', + }); + + const messageGroup = MessageGroup.getInstance(this.$element.find(`.${CHAT_MESSAGEGROUP_CLASS}`)); + + assert.strictEqual(messageGroup.option('messageTimestampFormat'), 'hh.mm'); + }); + + QUnit.test('messageTimestampFormat should be passed to message group at runtime', function(assert) { + this.reinit({ + items: [{ timestamp: '2024-09-26T14:00:00', text: 'text' }], + }); + + this.instance.option('messageTimestampFormat', 'hh.mm'); + + const messageGroup = MessageGroup.getInstance(this.$element.find(`.${CHAT_MESSAGEGROUP_CLASS}`)); + + assert.strictEqual(messageGroup.option('messageTimestampFormat'), 'hh.mm'); + }); }); - QUnit.module('Items option change', () => { + QUnit.module('Items option change', moduleConfig, () => { QUnit.test('should not be any errors if the new message in items is undefined', function(assert) { const newMessage = undefined; const items = [{}]; @@ -659,6 +741,8 @@ QUnit.module('MessageList', moduleConfig, () => { QUnit.module('Items option change performance', { beforeEach: function() { + moduleConfig.beforeEach.apply(this, arguments); + const createInvalidateStub = () => { this.invalidateStub = sinon.stub(this.instance, '_invalidate'); }; @@ -760,6 +844,8 @@ QUnit.module('MessageList', moduleConfig, () => { QUnit.module('ScrollView', { beforeEach: function() { + moduleConfig.beforeEach.apply(this, arguments); + this.getScrollOffsetMax = () => { const scrollView = this.getScrollView(); return $(scrollView.content()).height() - $(scrollView.container()).height(); @@ -1076,7 +1162,7 @@ QUnit.module('MessageList', moduleConfig, () => { }); }); - QUnit.module('localization', () => { + QUnit.module('localization', moduleConfig, () => { QUnit.test('message, prompt texts should be equal custom localized values from the dictionary', function(assert) { const defaultLocale = localization.locale(); diff --git a/packages/devextreme/testing/tests/DevExpress.ui/defaultOptions.tests.js b/packages/devextreme/testing/tests/DevExpress.ui/defaultOptions.tests.js index 265c576b618d..52a07db64a72 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui/defaultOptions.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui/defaultOptions.tests.js @@ -1352,6 +1352,8 @@ testComponentDefaults(Chat, onMessageSend: undefined, dataSource: undefined, showDayHeaders: true, + dayHeaderFormat: 'shortdate', + messageTimestampFormat: 'shorttime', } ); @@ -1392,6 +1394,7 @@ testComponentDefaults(ChatMessageGroup, {}, { alignment: 'start', + messageTimestampFormat: 'shorttime', } ); @@ -1402,6 +1405,8 @@ testComponentDefaults(ChatMessageList, currentUserId: '', showDayHeaders: true, isLoading: false, + dayHeaderFormat: 'shortdate', + messageTimestampFormat: 'shorttime', } );