From 76c69a6e700429acb509cd6c442cd17962b3d7c9 Mon Sep 17 00:00:00 2001
From: Matiss Janis Aboltins <matiss@mja.lv>
Date: Sun, 23 Apr 2023 16:57:15 +0100
Subject: [PATCH] :arrow_up: (autocomplete) upgrade Downshift dependency (#945)

Upgrading `Downshift` dependency
---
 .../e2e/page-models/rules-page.js             |  2 +-
 .../e2e/page-models/schedules-page.js         |  6 ++--
 packages/desktop-client/package.json          |  4 +--
 packages/desktop-client/playwright.config.js  |  1 +
 .../components/autocomplete/Autocomplete.js   |  9 ++++--
 .../desktop-client/src/components/forms.js    |  6 ++--
 .../src/components/schedules/EditSchedule.js  | 10 ++++--
 patches/downshift+1.31.16.patch               | 21 ------------
 upcoming-release-notes/945.md                 |  6 ++++
 yarn.lock                                     | 32 +++++++++++++------
 10 files changed, 55 insertions(+), 42 deletions(-)
 delete mode 100644 patches/downshift+1.31.16.patch
 create mode 100644 upcoming-release-notes/945.md

diff --git a/packages/desktop-client/e2e/page-models/rules-page.js b/packages/desktop-client/e2e/page-models/rules-page.js
index 2f7783d5c..17d36257b 100644
--- a/packages/desktop-client/e2e/page-models/rules-page.js
+++ b/packages/desktop-client/e2e/page-models/rules-page.js
@@ -85,7 +85,7 @@ export class RulesPage {
       }
 
       if (value) {
-        await row.getByRole('combobox').fill(value);
+        await row.getByRole('textbox').fill(value);
         await this.page.keyboard.press('Enter');
       }
     }
diff --git a/packages/desktop-client/e2e/page-models/schedules-page.js b/packages/desktop-client/e2e/page-models/schedules-page.js
index 401fea1cb..052cd31cb 100644
--- a/packages/desktop-client/e2e/page-models/schedules-page.js
+++ b/packages/desktop-client/e2e/page-models/schedules-page.js
@@ -71,12 +71,14 @@ export class SchedulesPage {
 
   async _fillScheduleFields(data) {
     if (data.payee) {
-      await this.page.getByLabel('Payee').fill(data.payee);
+      await this.page.getByRole('textbox', { name: 'Payee' }).fill(data.payee);
       await this.page.keyboard.press('Enter');
     }
 
     if (data.account) {
-      await this.page.getByLabel('Account').fill(data.account);
+      await this.page
+        .getByRole('textbox', { name: 'Account' })
+        .fill(data.account);
       await this.page.keyboard.press('Enter');
     }
 
diff --git a/packages/desktop-client/package.json b/packages/desktop-client/package.json
index 6919cde28..e78af4a33 100644
--- a/packages/desktop-client/package.json
+++ b/packages/desktop-client/package.json
@@ -24,7 +24,7 @@
     "customize-cra": "^1.0.0",
     "date-fns": "^2.29.3",
     "debounce": "^1.2.0",
-    "downshift": "1.31.16",
+    "downshift": "7.6.0",
     "focus-visible": "^4.1.1",
     "formik": "^0.11.10",
     "glamor": "^2.20.40",
@@ -64,7 +64,7 @@
     "build": "cross-env INLINE_RUNTIME_CHUNK=false react-app-rewired build",
     "build:browser": "cross-env ./bin/build-browser",
     "test": "react-app-rewired test",
-    "e2e": "npx playwright test e2e --browser=chromium",
+    "e2e": "npx playwright test --browser=chromium",
     "lint": "eslint ."
   },
   "jest": {
diff --git a/packages/desktop-client/playwright.config.js b/packages/desktop-client/playwright.config.js
index fd4d84f00..1969400a2 100644
--- a/packages/desktop-client/playwright.config.js
+++ b/packages/desktop-client/playwright.config.js
@@ -1,6 +1,7 @@
 module.exports = {
   timeout: 20000, // 20 seconds
   retries: 1,
+  testDir: 'e2e/',
   use: {
     screenshot: 'on',
     browserName: 'chromium',
diff --git a/packages/desktop-client/src/components/autocomplete/Autocomplete.js b/packages/desktop-client/src/components/autocomplete/Autocomplete.js
index d6b3a4ea7..1e205ab90 100644
--- a/packages/desktop-client/src/components/autocomplete/Autocomplete.js
+++ b/packages/desktop-client/src/components/autocomplete/Autocomplete.js
@@ -108,6 +108,7 @@ function SingleAutocomplete({
   focused,
   embedded = false,
   containerProps,
+  labelProps = {},
   inputProps = {},
   suggestions,
   tooltipStyle,
@@ -260,7 +261,10 @@ function SingleAutocomplete({
           return;
         }
 
-        if ('highlightedIndex' in changes) {
+        if (
+          'highlightedIndex' in changes &&
+          changes.type !== Downshift.stateChangeTypes.changeInput
+        ) {
           setHighlightedIndex(changes.highlightedIndex);
         }
         if ('isOpen' in changes) {
@@ -292,6 +296,7 @@ function SingleAutocomplete({
 
         inst.lastChangeType = changes.type;
       }}
+      labelId={labelProps?.id}
     >
       {({
         getInputProps,
@@ -379,7 +384,7 @@ function SingleAutocomplete({
 
                 // Handle escape ourselves
                 if (e.key === 'Escape') {
-                  e.preventDefault();
+                  e.nativeEvent.preventDownshiftDefault = true;
 
                   if (!embedded) {
                     e.stopPropagation();
diff --git a/packages/desktop-client/src/components/forms.js b/packages/desktop-client/src/components/forms.js
index 9518fe317..5ce7b0cf6 100644
--- a/packages/desktop-client/src/components/forms.js
+++ b/packages/desktop-client/src/components/forms.js
@@ -25,10 +25,12 @@ export function SectionLabel({ title, style }) {
   );
 }
 
-export function FormLabel({ style, title, htmlFor }) {
+export function FormLabel({ style, title, id, htmlFor }) {
   return (
     <Text style={[{ fontSize: 13, marginBottom: 3, color: colors.n3 }, style]}>
-      <label htmlFor={htmlFor}>{title}</label>
+      <label htmlFor={htmlFor} id={id}>
+        {title}
+      </label>
     </Text>
   );
 }
diff --git a/packages/desktop-client/src/components/schedules/EditSchedule.js b/packages/desktop-client/src/components/schedules/EditSchedule.js
index c795d2994..e07835e97 100644
--- a/packages/desktop-client/src/components/schedules/EditSchedule.js
+++ b/packages/desktop-client/src/components/schedules/EditSchedule.js
@@ -451,9 +451,10 @@ export default function ScheduleDetails() {
       </Stack>
       <Stack direction="row" style={{ marginTop: 20 }}>
         <FormField style={{ flex: 1 }}>
-          <FormLabel title="Payee" htmlFor="payee-field" />
+          <FormLabel title="Payee" id="payee-label" htmlFor="payee-field" />
           <PayeeAutocomplete
             value={state.fields.payee}
+            labelProps={{ id: 'payee-label' }}
             inputProps={{ id: 'payee-field', placeholder: '(none)' }}
             onSelect={id =>
               dispatch({ type: 'set-field', field: 'payee', value: id })
@@ -463,10 +464,15 @@ export default function ScheduleDetails() {
         </FormField>
 
         <FormField style={{ flex: 1 }}>
-          <FormLabel title="Account" htmlFor="account-field" />
+          <FormLabel
+            title="Account"
+            id="account-label"
+            htmlFor="account-field"
+          />
           <AccountAutocomplete
             includeClosedAccounts={false}
             value={state.fields.account}
+            labelProps={{ id: 'account-label' }}
             inputProps={{ id: 'account-field', placeholder: '(none)' }}
             onSelect={id =>
               dispatch({ type: 'set-field', field: 'account', value: id })
diff --git a/patches/downshift+1.31.16.patch b/patches/downshift+1.31.16.patch
deleted file mode 100644
index 812df6f8c..000000000
--- a/patches/downshift+1.31.16.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-diff --git a/node_modules/downshift/dist/downshift.esm.js b/node_modules/downshift/dist/downshift.esm.js
-index f39a298..da7b6f5 100644
---- a/node_modules/downshift/dist/downshift.esm.js
-+++ b/node_modules/downshift/dist/downshift.esm.js
-@@ -1200,10 +1200,15 @@ var _initialiseProps = function () {
-       // onMouseMove is used over onMouseEnter here. onMouseMove
-       // is only triggered on actual mouse movement while onMouseEnter
-       // can fire on DOM changes, interrupting keyboard navigation
--      onMouseMove: composeEventHandlers(onMouseMove, function () {
-+      onMouseMove: composeEventHandlers(onMouseMove, function (e) {
-         if (index === _this4.getState().highlightedIndex) {
-           return;
-         }
-+
-+        if(e.movementX === 0 && e.movementY === 0) {
-+          return;
-+        }
-+
-         _this4.setHighlightedIndex(index, {
-           type: Downshift.stateChangeTypes.itemMouseEnter
-         });
diff --git a/upcoming-release-notes/945.md b/upcoming-release-notes/945.md
new file mode 100644
index 000000000..0a584c2c4
--- /dev/null
+++ b/upcoming-release-notes/945.md
@@ -0,0 +1,6 @@
+---
+category: Maintenance
+authors: [MatissJanis]
+---
+
+Autocomplete: upgrade `Downshift` dependency
diff --git a/yarn.lock b/yarn.lock
index f352d13e2..4181322ba 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -73,7 +73,7 @@ __metadata:
     customize-cra: ^1.0.0
     date-fns: ^2.29.3
     debounce: ^1.2.0
-    downshift: 1.31.16
+    downshift: 7.6.0
     focus-visible: ^4.1.1
     formik: ^0.11.10
     glamor: ^2.20.40
@@ -1593,7 +1593,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2":
+"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.8, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2":
   version: 7.21.0
   resolution: "@babel/runtime@npm:7.21.0"
   dependencies:
@@ -6863,6 +6863,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"compute-scroll-into-view@npm:^2.0.4":
+  version: 2.0.4
+  resolution: "compute-scroll-into-view@npm:2.0.4"
+  checksum: f3d1db9276c16af42155b572750514939cd0ab0a0f46498906f6811c5b654c5ff2b3f9bfd65958e57439e000a5e1ae092eb96b9e153d194a73e52ffd2380550c
+  languageName: node
+  linkType: hard
+
 "concat-map@npm:0.0.1":
   version: 0.0.1
   resolution: "concat-map@npm:0.0.1"
@@ -8306,13 +8313,18 @@ __metadata:
   languageName: node
   linkType: hard
 
-"downshift@npm:1.31.16":
-  version: 1.31.16
-  resolution: "downshift@npm:1.31.16"
+"downshift@npm:7.6.0":
+  version: 7.6.0
+  resolution: "downshift@npm:7.6.0"
+  dependencies:
+    "@babel/runtime": ^7.14.8
+    compute-scroll-into-view: ^2.0.4
+    prop-types: ^15.7.2
+    react-is: ^17.0.2
+    tslib: ^2.3.0
   peerDependencies:
-    prop-types: ">=15"
-    react: ">=0.14.x"
-  checksum: 558fb4658290477c74fb961b435ad8e416089a06f2beb8d570be29e33867de70ec79d4b6b07278773137d4d8f7dfc10b540c74898c53906607a7948b63e5dace
+    react: ">=16.12.0"
+  checksum: f738e0b50bcacedbf14c8de3baceb8e7be88ec4a2ab6becdc58ae253883d47de1085240db189cc485eb5995d0f35ac017836266116a95e0ac8c19b4600d38598
   languageName: node
   linkType: hard
 
@@ -16897,7 +16909,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"react-is@npm:^17.0.1":
+"react-is@npm:^17.0.1, react-is@npm:^17.0.2":
   version: 17.0.2
   resolution: "react-is@npm:17.0.2"
   checksum: 9d6d111d8990dc98bc5402c1266a808b0459b5d54830bbea24c12d908b536df7883f268a7868cfaedde3dd9d4e0d574db456f84d2e6df9c4526f99bb4b5344d8
@@ -19625,7 +19637,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"tslib@npm:^2.0.0, tslib@npm:^2.0.3":
+"tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.3.0":
   version: 2.5.0
   resolution: "tslib@npm:2.5.0"
   checksum: ae3ed5f9ce29932d049908ebfdf21b3a003a85653a9a140d614da6b767a93ef94f460e52c3d787f0e4f383546981713f165037dc2274df212ea9f8a4541004e1
-- 
GitLab