Repository: segmentio/evergreen (JavaScript)

Issue:
Autocomplete: `allowOtherValues` not working?
Hi, this doesn't seem to be correct behavior: I'm using Autocomplete with property `allowOtherValues` enabled. When I select an item from the Autocomplete menu, the input value does not get updated.

Reproduction steps:
Navigate to https://evergreen.segment.com/components/autocomplete#default_example
Click on "Open in CodeSandbox".
Check that the Autocomplete component is working correctly.
Edit sample code to add property `allowOtherValues` to the Autocomplete element.
Refresh the "Browser" frame in CodeSandbox.
Select an item in Autocomplete and verify that it is not updating the value of the input element.


Discussion:
Hmm, yeah, it looks like you're right. It looks like it _does_ select the value (typing in 'a', selecting Apple, backspacing, and then typing 'a' again shows the Apple option selected) but it doesn't seem to be properly updating the input field. Not sure when/if this ever worked, but going as far back as 6.4.0 it is still showing this behavior.
This should be resolved in https://github.com/segmentio/evergreen/releases/tag/v6.10.4



Patch:
diff --git a/package.json b/package.json
index ce14813ca..940aac3e9 100644
--- a/package.json
+++ b/package.json
@@ -107,7 +107,7 @@
     "@storybook/react": "^6.0.21",
     "@storybook/theming": "^6.0.21",
     "@testing-library/jest-dom": "^5.11.6",
-    "@testing-library/react": "^11.2.2",
+    "@testing-library/react": "13.3.0",
     "@testing-library/user-event": "^13.1.9",
     "babel-core": "7.0.0-bridge.0",
     "babel-eslint": "^10.0.1",
diff --git a/src/autocomplete/src/Autocomplete.js b/src/autocomplete/src/Autocomplete.js
index 69fe0b659..e9fb47dd4 100644
--- a/src/autocomplete/src/Autocomplete.js
+++ b/src/autocomplete/src/Autocomplete.js
@@ -131,7 +131,7 @@ const Autocomplete = memo(
           return {
             ...changes,
             selectedItem: changes.selectedItem || state.inputValue,
-            inputValue: state.inputValue
+            inputValue: changes.selectedItem || state.inputValue
           }
         }
 
diff --git a/src/autocomplete/stories/index.stories.js b/src/autocomplete/stories/index.stories.js
index 4421d6e22..3668e5e5f 100644
--- a/src/autocomplete/stories/index.stories.js
+++ b/src/autocomplete/stories/index.stories.js
@@ -5,6 +5,7 @@ import Box from 'ui-box'
 import { Autocomplete } from '..'
 import { Button } from '../../buttons'
 import { TextInput } from '../../text-input'
+import { Label, Code } from '../../typography'
 
 // Generate a big list of items
 const items = [
@@ -130,6 +131,23 @@ storiesOf('autocomplete', module).add('Autocomplete', () => {
           )}
         </Autocomplete>
       </Box>
+      <Box padding={40}>
+        <Box marginBottom={16}>
+          <Label>
+            Uncontrolled Example w/ <Code size="small">allowOtherValues</Code>
+          </Label>
+        </Box>
+        <Autocomplete
+          allowOtherValues={true}
+          items={['Apple', 'Apricot', 'Banana', 'Cherry', 'Cucumber']}
+          title="Fruits"
+        >
+          {props => {
+            const { getInputProps, getRef, inputValue } = props
+            return <TextInput placeholder="Fruits" value={inputValue} ref={getRef} {...getInputProps()} />
+          }}
+        </Autocomplete>
+      </Box>
     </Box>
   )
 })
diff --git a/yarn.lock b/yarn.lock
index 9cada57e6..42e08c639 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2697,19 +2697,19 @@
   dependencies:
     defer-to-connect "^2.0.0"
 
-"@testing-library/dom@^7.28.1":
-  version "7.31.2"
-  resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.31.2.tgz#df361db38f5212b88555068ab8119f5d841a8c4a"
-  integrity sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==
+"@testing-library/dom@^8.5.0":
+  version "8.16.0"
+  resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.16.0.tgz#d6fc50250aed17b1035ca1bd64655e342db3936a"
+  integrity sha512-uxF4zmnLHHDlmW4l+0WDjcgLVwCvH+OVLpD8Dfp+Bjfz85prwxWGbwXgJdLtkgjD0qfOzkJF9SmA6YZPsMYX4w==
   dependencies:
     "@babel/code-frame" "^7.10.4"
     "@babel/runtime" "^7.12.5"
     "@types/aria-query" "^4.2.0"
-    aria-query "^4.2.2"
+    aria-query "^5.0.0"
     chalk "^4.1.0"
-    dom-accessibility-api "^0.5.6"
+    dom-accessibility-api "^0.5.9"
     lz-string "^1.4.4"
-    pretty-format "^26.6.2"
+    pretty-format "^27.0.2"
 
 "@testing-library/jest-dom@^5.11.6":
   version "5.14.1"
@@ -2726,13 +2726,14 @@
     lodash "^4.17.15"
     redent "^3.0.0"
 
-"@testing-library/react@^11.2.2":
-  version "11.2.7"
-  resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-11.2.7.tgz#b29e2e95c6765c815786c0bc1d5aed9cb2bf7818"
-  integrity sha512-tzRNp7pzd5QmbtXNG/mhdcl7Awfu/Iz1RaVHY75zTdOkmHCuzMhRL83gWHSgOAcjS3CCbyfwUHMZgRJb4kAfpA==
+"@testing-library/react@13.3.0":
+  version "13.3.0"
+  resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-13.3.0.tgz#bf298bfbc5589326bbcc8052b211f3bb097a97c5"
+  integrity sha512-DB79aA426+deFgGSjnf5grczDPiL4taK3hFaa+M5q7q20Kcve9eQottOG5kZ74KEr55v0tU2CQormSSDK87zYQ==
   dependencies:
     "@babel/runtime" "^7.12.5"
-    "@testing-library/dom" "^7.28.1"
+    "@testing-library/dom" "^8.5.0"
+    "@types/react-dom" "^18.0.0"
 
 "@testing-library/user-event@^13.1.9":
   version "13.2.0"
@@ -3026,6 +3027,13 @@
   dependencies:
     "@types/react" "*"
 
+"@types/react-dom@^18.0.0":
+  version "18.0.6"
+  resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.6.tgz#36652900024842b74607a17786b6662dd1e103a1"
+  integrity sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==
+  dependencies:
+    "@types/react" "*"
+
 "@types/react-syntax-highlighter@11.0.5":
   version "11.0.5"
   resolved "https://registry.yarnpkg.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.5.tgz#0d546261b4021e1f9d85b50401c0a42acb106087"
@@ -3464,7 +3472,7 @@ ansi-html@0.0.7, ansi-html@^0.0.7:
   resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e"
   integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4=
 
-ansi-regex@5.0.1, ansi-regex@^2.0.0, ansi-regex@^3.0.0, ansi-regex@^4.1.0, ansi-regex@^5.0.0:
+ansi-regex@5.0.1, ansi-regex@^2.0.0, ansi-regex@^3.0.0, ansi-regex@^4.1.0, ansi-regex@^5.0.0, ansi-regex@^5.0.1:
   version "5.0.1"
   resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
   integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
@@ -3488,6 +3496,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
   dependencies:
     color-convert "^2.0.1"
 
+ansi-styles@^5.0.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
+  integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
+
 ansi-to-html@^0.6.11:
   version "0.6.15"
   resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.6.15.tgz#ac6ad4798a00f6aa045535d7f6a9cb9294eebea7"
@@ -3554,6 +3567,11 @@ aria-query@^4.2.2:
     "@babel/runtime" "^7.10.2"
     "@babel/runtime-corejs3" "^7.10.2"
 
+aria-query@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.0.0.tgz#210c21aaf469613ee8c9a62c7f86525e058db52c"
+  integrity sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==
+
 arr-diff@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
@@ -5694,6 +5712,11 @@ dom-accessibility-api@^0.5.6:
   resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz#3f5d43b52c7a3bd68b5fb63fa47b4e4c1fdf65a9"
   integrity sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw==
 
+dom-accessibility-api@^0.5.9:
+  version "0.5.14"
+  resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz#56082f71b1dc7aac69d83c4285eef39c15d93f56"
+  integrity sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==
+
 dom-converter@^0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768"
@@ -11539,6 +11562,15 @@ pretty-format@^26.0.0, pretty-format@^26.6.2:
     ansi-styles "^4.0.0"
     react-is "^17.0.1"
 
+pretty-format@^27.0.2:
+  version "27.5.1"
+  resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e"
+  integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==
+  dependencies:
+    ansi-regex "^5.0.1"
+    ansi-styles "^5.0.0"
+    react-is "^17.0.1"
+
 pretty-hrtime@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"


Test patch:
diff --git a/src/autocomplete/__tests__/Autocomplete.test.js b/src/autocomplete/__tests__/Autocomplete.test.js
new file mode 100644
index 000000000..e4673994e
--- /dev/null
+++ b/src/autocomplete/__tests__/Autocomplete.test.js
@@ -0,0 +1,88 @@
+import React from 'react'
+import { render, screen } from '@testing-library/react'
+import userEvent from '@testing-library/user-event'
+import { TextInput } from '../../text-input'
+import Autocomplete from '../src/Autocomplete'
+
+const makeAutocompleteFixture = (props = {}) => (
+  <Autocomplete {...props}>
+    {renderProps => {
+      const { getInputProps, getRef, inputValue } = renderProps
+      return <TextInput value={inputValue} ref={getRef} {...getInputProps()} data-testid="TextInput" />
+    }}
+  </Autocomplete>
+)
+
+describe('Autocomplete', () => {
+  describe('when allowOtherValues is false', () => {
+    describe('when input field loses focus', () => {
+      it('should clear input value', async () => {
+        const items = ['Apple', 'Orange']
+
+        render(
+          makeAutocompleteFixture({
+            allowOtherValues: false,
+            items
+          })
+        )
+
+        const textInput = await screen.findByTestId('TextInput')
+        userEvent.click(textInput)
+        userEvent.type(textInput, 'A')
+
+        // Change focus by clicking off of the component
+        userEvent.click(document.body)
+
+        expect(textInput).not.toHaveValue()
+      })
+    })
+  })
+
+  describe('when allowOtherValues is true', () => {
+    describe('when item from list is selected', () => {
+      it('should set input value to selected item', async () => {
+        const items = ['Apple', 'Orange']
+
+        render(
+          makeAutocompleteFixture({
+            allowOtherValues: true,
+            items
+          })
+        )
+
+        // Type 'A' into the input to filter items down containing the string
+        const textInput = await screen.findByTestId('TextInput')
+        userEvent.click(textInput)
+        userEvent.type(textInput, 'A')
+
+        // Click the 'Apple' option, which should also update the input element
+        const item = await screen.findByText('Apple')
+        userEvent.click(item)
+
+        expect(textInput).toHaveValue('Apple')
+      })
+    })
+
+    describe('when input field loses focus', () => {
+      it('should maintain input value', async () => {
+        const items = ['Apple', 'Orange']
+
+        render(
+          makeAutocompleteFixture({
+            allowOtherValues: true,
+            items
+          })
+        )
+
+        const textInput = await screen.findByTestId('TextInput')
+        userEvent.click(textInput)
+        userEvent.type(textInput, 'A')
+
+        // Change focus by clicking off of the component
+        userEvent.click(document.body)
+
+        expect(textInput).toHaveValue('A')
+      })
+    })
+  })
+})