├── .eslintrc.js ├── .flowconfig ├── .gitignore ├── .watchmanconfig ├── LICENSE ├── README.md ├── babel.config.js ├── examples └── result_images │ └── react-native-autocomplete-search-complex.png ├── flow-typed └── npm │ └── jest_v23.x.x.js ├── index.js ├── package-lock.json ├── package.json ├── src ├── InputAutoSuggest.js ├── SuggestionListItem.js └── services │ ├── suggest.js │ └── suggest.test.js ├── yarn-error.log └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": "airbnb", 3 | "parser": "babel-eslint", 4 | "rules": { 5 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx", ".ts"] }], 6 | }, 7 | "globals": { "fetch": false }, 8 | "env": { 9 | "jest": true 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [untyped] 2 | .*/node_modules/react-native 3 | 4 | [ignore] 5 | ; We fork some components by platform 6 | .*/*[.]android.js 7 | 8 | ; Ignore "BUCK" generated dirs 9 | /\.buckd/ 10 | 11 | ; Ignore unexpected extra "@providesModule" 12 | .*/node_modules/.*/node_modules/fbjs/.* 13 | 14 | ; Ignore duplicate module providers 15 | ; For RN Apps installed via npm, "Libraries" folder is inside 16 | ; "node_modules/react-native" but in the source repo it is in the root 17 | .*/Libraries/react-native/React.js 18 | 19 | ; Ignore polyfills 20 | .*/Libraries/polyfills/.* 21 | 22 | ; Ignore metro 23 | .*/node_modules/metro/.* 24 | 25 | [include] 26 | 27 | [libs] 28 | node_modules/react-native/Libraries/react-native/react-native-interface.js 29 | node_modules/react-native/flow/ 30 | node_modules/react-native/flow-github/ 31 | 32 | [options] 33 | emoji=true 34 | 35 | esproposal.optional_chaining=enable 36 | esproposal.nullish_coalescing=enable 37 | 38 | module.system=haste 39 | module.system.haste.use_name_reducers=true 40 | # get basename 41 | module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' 42 | # strip .js or .js.flow suffix 43 | module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' 44 | # strip .ios suffix 45 | module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' 46 | module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' 47 | module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' 48 | module.system.haste.paths.blacklist=.*/__tests__/.* 49 | module.system.haste.paths.blacklist=.*/__mocks__/.* 50 | module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/Animated/src/polyfills/.* 51 | module.system.haste.paths.whitelist=/node_modules/react-native/Libraries/.* 52 | 53 | munge_underscores=true 54 | 55 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 56 | 57 | module.file_ext=.js 58 | module.file_ext=.jsx 59 | module.file_ext=.json 60 | module.file_ext=.native.js 61 | 62 | suppress_type=$FlowIssue 63 | suppress_type=$FlowFixMe 64 | suppress_type=$FlowFixMeProps 65 | suppress_type=$FlowFixMeState 66 | 67 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 68 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 69 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 70 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 71 | 72 | [version] 73 | ^0.86.0 74 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ENV 2 | .env 3 | .env.dev 4 | .env.dev.local 5 | .env.production 6 | .env.staging 7 | 8 | # OSX 9 | # 10 | .DS_Store 11 | 12 | # Xcode 13 | # 14 | build/ 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | xcuserdata 24 | *.xccheckout 25 | *.moved-aside 26 | DerivedData 27 | *.hmap 28 | *.ipa 29 | *.xcuserstate 30 | project.xcworkspace 31 | 32 | # Android/IntelliJ 33 | # 34 | build/ 35 | .idea 36 | .gradle 37 | local.properties 38 | *.iml 39 | 40 | # node.js 41 | # 42 | node_modules/ 43 | npm-debug.log 44 | yarn-error.log 45 | 46 | # BUCK 47 | buck-out/ 48 | \.buckd/ 49 | *.keystore 50 | 51 | # fastlane 52 | # 53 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 54 | # screenshots whenever they are needed. 55 | # For more information about the recommended setup visit: 56 | # https://docs.fastlane.tools/best-practices/source-control/ 57 | 58 | */fastlane/report.xml 59 | */fastlane/Preview.html 60 | */fastlane/screenshots 61 | 62 | # Bundle artifact 63 | *.jsbundle 64 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": [ 3 | ".git", 4 | "node_modules" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 nathanh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Intro / Preview 2 | 3 | Component to search suggestion during you write a word. Based on a static data list or remote data. You can search suggestion in static data or fetching data suggestion from an api doing the work when you send the word you write. If suggestion is selected, an object ({ id: XX, name: XX }) is sent back to the parent component. The same occurs by simply write data corresponding to one suggestion. The component is usable with static data or data stored remotly like an elastic index using suggest feature (ex: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html). 4 | 5 | 6 | 7 | ### Installation 8 | 9 | 10 | 11 | **Install package via npm:** 12 | ``` 13 | npm install react-native-autocomplete-search 14 | ``` 15 | 16 | or 17 | 18 | **Install package via npm:** 19 | ``` 20 | yarn add react-native-autocomplete-search 21 | ``` 22 | 23 | ### Props details of InputAutosuggest 24 | 25 | **inputStyle:** style object to change the style of the InputText used *// Optional* 26 | 27 | **flatListStyle:** style object to change the style of the FlatList used *// Optional* 28 | 29 | **itemTextStyle:** style object to change the style of the text suggestion, *// Optional* 30 | 31 | **itemTagStyle:** style object to change the style of the tag suggestion, *// Optional* 32 | 33 | **apiEndpointSuggestData:** function to access suggest feature to remote data (elatic index for example), *// omit if using staticData* 34 | 35 | **staticData:** Array containing static data used to search suggestion instead of using apiEndpointSuggestData *// omit if using apiEndpointSuggestData* 36 | 37 | **onDataSelectedChange:** function to handle selected data in parent component 38 | 39 | **keyPathRequestResult:** path as string. It is used in the case of fetching data like elastic for example, array suggestion can be in a specific path of the object. *// can be omit if your data object is an array* 40 | 41 | **itemFormat:** object to containing path string for 'id' and 'name' in the data array. 'tags' is an array of string and is optional. *// Optional if you data array contains id and name property in each object* 42 | 43 | 44 | ### Usage 45 | **Include the library in your code** 46 | ``` 47 | import { InputAutoSuggest } from 'react-native-autocomplete-search'; 48 | ``` 49 | 50 | **Simple usage with static data** 51 | 52 | ``` 53 | 63 | ``` 64 | 65 | **Complex usage with static data** 66 | ``` 67 | 79 | ``` 80 | 81 | itemFormat is used to give the path to the id, name and tags giving: 82 | 83 | 84 | 85 | 86 | **Simple usage with remote data fetching** 87 | 88 | You can use the component to send the text you write and ask an api to make the suggestions. Just give your method calling the api to apiEndpointSuggestData prop instead of staticData. 89 | ``` 90 | YOUR-METHOD-CALLING-API(text)} 93 | itemFormat={{id: 'details.id', name: 'details.name', tags:['details.continent', 'details.country']}} 94 | /> 95 | ``` 96 | 97 | **Get back the data selected to the parent component** 98 | 99 | You can get back data information about the research by using the prop function 'onDataSelectedChange': 100 | on object is passed as { id: XX, name: XX } or as null if there is not corresponding research information about the test. 101 | 102 | ``` 103 | YOUR-METHOD-CALLING-API(text)} 106 | itemFormat={{id: 'details.id', name: 'details.name', tags:['details.continent', 'details.country']}} 107 | onDataSelectedChange={data => console.log(data)} 108 | /> 109 | ``` 110 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.cache(true); 3 | 4 | return { 5 | presets: ['@babel/preset-env', '@babel/preset-flow'], 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /examples/result_images/react-native-autocomplete-search-complex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najeal/react-native-autocomplete-search/757e914c076505b948953664fcc377c21a923f4c/examples/result_images/react-native-autocomplete-search-complex.png -------------------------------------------------------------------------------- /flow-typed/npm/jest_v23.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 78c200acffbcc16bba9478f5396c3a00 2 | // flow-typed version: b2980740dd/jest_v23.x.x/flow_>=v0.39.x 3 | 4 | type JestMockFn, TReturn> = { 5 | (...args: TArguments): TReturn, 6 | /** 7 | * An object for introspecting mock calls 8 | */ 9 | mock: { 10 | /** 11 | * An array that represents all calls that have been made into this mock 12 | * function. Each call is represented by an array of arguments that were 13 | * passed during the call. 14 | */ 15 | calls: Array, 16 | /** 17 | * An array that contains all the object instances that have been 18 | * instantiated from this mock function. 19 | */ 20 | instances: Array, 21 | /** 22 | * An array that contains all the object results that have been 23 | * returned by this mock function call 24 | */ 25 | results: Array<{ isThrow: boolean, value: TReturn }> 26 | }, 27 | /** 28 | * Resets all information stored in the mockFn.mock.calls and 29 | * mockFn.mock.instances arrays. Often this is useful when you want to clean 30 | * up a mock's usage data between two assertions. 31 | */ 32 | mockClear(): void, 33 | /** 34 | * Resets all information stored in the mock. This is useful when you want to 35 | * completely restore a mock back to its initial state. 36 | */ 37 | mockReset(): void, 38 | /** 39 | * Removes the mock and restores the initial implementation. This is useful 40 | * when you want to mock functions in certain test cases and restore the 41 | * original implementation in others. Beware that mockFn.mockRestore only 42 | * works when mock was created with jest.spyOn. Thus you have to take care of 43 | * restoration yourself when manually assigning jest.fn(). 44 | */ 45 | mockRestore(): void, 46 | /** 47 | * Accepts a function that should be used as the implementation of the mock. 48 | * The mock itself will still record all calls that go into and instances 49 | * that come from itself -- the only difference is that the implementation 50 | * will also be executed when the mock is called. 51 | */ 52 | mockImplementation( 53 | fn: (...args: TArguments) => TReturn 54 | ): JestMockFn, 55 | /** 56 | * Accepts a function that will be used as an implementation of the mock for 57 | * one call to the mocked function. Can be chained so that multiple function 58 | * calls produce different results. 59 | */ 60 | mockImplementationOnce( 61 | fn: (...args: TArguments) => TReturn 62 | ): JestMockFn, 63 | /** 64 | * Accepts a string to use in test result output in place of "jest.fn()" to 65 | * indicate which mock function is being referenced. 66 | */ 67 | mockName(name: string): JestMockFn, 68 | /** 69 | * Just a simple sugar function for returning `this` 70 | */ 71 | mockReturnThis(): void, 72 | /** 73 | * Accepts a value that will be returned whenever the mock function is called. 74 | */ 75 | mockReturnValue(value: TReturn): JestMockFn, 76 | /** 77 | * Sugar for only returning a value once inside your mock 78 | */ 79 | mockReturnValueOnce(value: TReturn): JestMockFn, 80 | /** 81 | * Sugar for jest.fn().mockImplementation(() => Promise.resolve(value)) 82 | */ 83 | mockResolvedValue(value: TReturn): JestMockFn>, 84 | /** 85 | * Sugar for jest.fn().mockImplementationOnce(() => Promise.resolve(value)) 86 | */ 87 | mockResolvedValueOnce(value: TReturn): JestMockFn>, 88 | /** 89 | * Sugar for jest.fn().mockImplementation(() => Promise.reject(value)) 90 | */ 91 | mockRejectedValue(value: TReturn): JestMockFn>, 92 | /** 93 | * Sugar for jest.fn().mockImplementationOnce(() => Promise.reject(value)) 94 | */ 95 | mockRejectedValueOnce(value: TReturn): JestMockFn> 96 | }; 97 | 98 | type JestAsymmetricEqualityType = { 99 | /** 100 | * A custom Jasmine equality tester 101 | */ 102 | asymmetricMatch(value: mixed): boolean 103 | }; 104 | 105 | type JestCallsType = { 106 | allArgs(): mixed, 107 | all(): mixed, 108 | any(): boolean, 109 | count(): number, 110 | first(): mixed, 111 | mostRecent(): mixed, 112 | reset(): void 113 | }; 114 | 115 | type JestClockType = { 116 | install(): void, 117 | mockDate(date: Date): void, 118 | tick(milliseconds?: number): void, 119 | uninstall(): void 120 | }; 121 | 122 | type JestMatcherResult = { 123 | message?: string | (() => string), 124 | pass: boolean 125 | }; 126 | 127 | type JestMatcher = (actual: any, expected: any) => 128 | | JestMatcherResult 129 | | Promise; 130 | 131 | type JestPromiseType = { 132 | /** 133 | * Use rejects to unwrap the reason of a rejected promise so any other 134 | * matcher can be chained. If the promise is fulfilled the assertion fails. 135 | */ 136 | rejects: JestExpectType, 137 | /** 138 | * Use resolves to unwrap the value of a fulfilled promise so any other 139 | * matcher can be chained. If the promise is rejected the assertion fails. 140 | */ 141 | resolves: JestExpectType 142 | }; 143 | 144 | /** 145 | * Jest allows functions and classes to be used as test names in test() and 146 | * describe() 147 | */ 148 | type JestTestName = string | Function; 149 | 150 | /** 151 | * Plugin: jest-styled-components 152 | */ 153 | 154 | type JestStyledComponentsMatcherValue = 155 | | string 156 | | JestAsymmetricEqualityType 157 | | RegExp 158 | | typeof undefined; 159 | 160 | type JestStyledComponentsMatcherOptions = { 161 | media?: string; 162 | modifier?: string; 163 | supports?: string; 164 | } 165 | 166 | type JestStyledComponentsMatchersType = { 167 | toHaveStyleRule( 168 | property: string, 169 | value: JestStyledComponentsMatcherValue, 170 | options?: JestStyledComponentsMatcherOptions 171 | ): void, 172 | }; 173 | 174 | /** 175 | * Plugin: jest-enzyme 176 | */ 177 | type EnzymeMatchersType = { 178 | // 5.x 179 | toBeEmpty(): void, 180 | toBePresent(): void, 181 | // 6.x 182 | toBeChecked(): void, 183 | toBeDisabled(): void, 184 | toBeEmptyRender(): void, 185 | toContainMatchingElement(selector: string): void; 186 | toContainMatchingElements(n: number, selector: string): void; 187 | toContainExactlyOneMatchingElement(selector: string): void; 188 | toContainReact(element: React$Element): void, 189 | toExist(): void, 190 | toHaveClassName(className: string): void, 191 | toHaveHTML(html: string): void, 192 | toHaveProp: ((propKey: string, propValue?: any) => void) & ((props: Object) => void), 193 | toHaveRef(refName: string): void, 194 | toHaveState: ((stateKey: string, stateValue?: any) => void) & ((state: Object) => void), 195 | toHaveStyle: ((styleKey: string, styleValue?: any) => void) & ((style: Object) => void), 196 | toHaveTagName(tagName: string): void, 197 | toHaveText(text: string): void, 198 | toHaveValue(value: any): void, 199 | toIncludeText(text: string): void, 200 | toMatchElement( 201 | element: React$Element, 202 | options?: {| ignoreProps?: boolean, verbose?: boolean |}, 203 | ): void, 204 | toMatchSelector(selector: string): void, 205 | // 7.x 206 | toHaveDisplayName(name: string): void, 207 | }; 208 | 209 | // DOM testing library extensions https://github.com/kentcdodds/dom-testing-library#custom-jest-matchers 210 | type DomTestingLibraryType = { 211 | toBeDisabled(): void, 212 | toBeEmpty(): void, 213 | toBeInTheDocument(): void, 214 | toBeVisible(): void, 215 | toContainElement(element: HTMLElement | null): void, 216 | toContainHTML(htmlText: string): void, 217 | toHaveAttribute(name: string, expectedValue?: string): void, 218 | toHaveClass(...classNames: string[]): void, 219 | toHaveFocus(): void, 220 | toHaveFormValues(expectedValues: { [name: string]: any }): void, 221 | toHaveStyle(css: string): void, 222 | toHaveTextContent(content: string | RegExp, options?: { normalizeWhitespace: boolean }): void, 223 | toBeInTheDOM(): void, 224 | }; 225 | 226 | // Jest JQuery Matchers: https://github.com/unindented/custom-jquery-matchers 227 | type JestJQueryMatchersType = { 228 | toExist(): void, 229 | toHaveLength(len: number): void, 230 | toHaveId(id: string): void, 231 | toHaveClass(className: string): void, 232 | toHaveTag(tag: string): void, 233 | toHaveAttr(key: string, val?: any): void, 234 | toHaveProp(key: string, val?: any): void, 235 | toHaveText(text: string | RegExp): void, 236 | toHaveData(key: string, val?: any): void, 237 | toHaveValue(val: any): void, 238 | toHaveCss(css: {[key: string]: any}): void, 239 | toBeChecked(): void, 240 | toBeDisabled(): void, 241 | toBeEmpty(): void, 242 | toBeHidden(): void, 243 | toBeSelected(): void, 244 | toBeVisible(): void, 245 | toBeFocused(): void, 246 | toBeInDom(): void, 247 | toBeMatchedBy(sel: string): void, 248 | toHaveDescendant(sel: string): void, 249 | toHaveDescendantWithText(sel: string, text: string | RegExp): void 250 | }; 251 | 252 | 253 | // Jest Extended Matchers: https://github.com/jest-community/jest-extended 254 | type JestExtendedMatchersType = { 255 | /** 256 | * Note: Currently unimplemented 257 | * Passing assertion 258 | * 259 | * @param {String} message 260 | */ 261 | // pass(message: string): void; 262 | 263 | /** 264 | * Note: Currently unimplemented 265 | * Failing assertion 266 | * 267 | * @param {String} message 268 | */ 269 | // fail(message: string): void; 270 | 271 | /** 272 | * Use .toBeEmpty when checking if a String '', Array [] or Object {} is empty. 273 | */ 274 | toBeEmpty(): void; 275 | 276 | /** 277 | * Use .toBeOneOf when checking if a value is a member of a given Array. 278 | * @param {Array.<*>} members 279 | */ 280 | toBeOneOf(members: any[]): void; 281 | 282 | /** 283 | * Use `.toBeNil` when checking a value is `null` or `undefined`. 284 | */ 285 | toBeNil(): void; 286 | 287 | /** 288 | * Use `.toSatisfy` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean`. 289 | * @param {Function} predicate 290 | */ 291 | toSatisfy(predicate: (n: any) => boolean): void; 292 | 293 | /** 294 | * Use `.toBeArray` when checking if a value is an `Array`. 295 | */ 296 | toBeArray(): void; 297 | 298 | /** 299 | * Use `.toBeArrayOfSize` when checking if a value is an `Array` of size x. 300 | * @param {Number} x 301 | */ 302 | toBeArrayOfSize(x: number): void; 303 | 304 | /** 305 | * Use `.toIncludeAllMembers` when checking if an `Array` contains all of the same members of a given set. 306 | * @param {Array.<*>} members 307 | */ 308 | toIncludeAllMembers(members: any[]): void; 309 | 310 | /** 311 | * Use `.toIncludeAnyMembers` when checking if an `Array` contains any of the members of a given set. 312 | * @param {Array.<*>} members 313 | */ 314 | toIncludeAnyMembers(members: any[]): void; 315 | 316 | /** 317 | * Use `.toSatisfyAll` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean` for all values in an array. 318 | * @param {Function} predicate 319 | */ 320 | toSatisfyAll(predicate: (n: any) => boolean): void; 321 | 322 | /** 323 | * Use `.toBeBoolean` when checking if a value is a `Boolean`. 324 | */ 325 | toBeBoolean(): void; 326 | 327 | /** 328 | * Use `.toBeTrue` when checking a value is equal (===) to `true`. 329 | */ 330 | toBeTrue(): void; 331 | 332 | /** 333 | * Use `.toBeFalse` when checking a value is equal (===) to `false`. 334 | */ 335 | toBeFalse(): void; 336 | 337 | /** 338 | * Use .toBeDate when checking if a value is a Date. 339 | */ 340 | toBeDate(): void; 341 | 342 | /** 343 | * Use `.toBeFunction` when checking if a value is a `Function`. 344 | */ 345 | toBeFunction(): void; 346 | 347 | /** 348 | * Use `.toHaveBeenCalledBefore` when checking if a `Mock` was called before another `Mock`. 349 | * 350 | * Note: Required Jest version >22 351 | * Note: Your mock functions will have to be asynchronous to cause the timestamps inside of Jest to occur in a differentJS event loop, otherwise the mock timestamps will all be the same 352 | * 353 | * @param {Mock} mock 354 | */ 355 | toHaveBeenCalledBefore(mock: JestMockFn): void; 356 | 357 | /** 358 | * Use `.toBeNumber` when checking if a value is a `Number`. 359 | */ 360 | toBeNumber(): void; 361 | 362 | /** 363 | * Use `.toBeNaN` when checking a value is `NaN`. 364 | */ 365 | toBeNaN(): void; 366 | 367 | /** 368 | * Use `.toBeFinite` when checking if a value is a `Number`, not `NaN` or `Infinity`. 369 | */ 370 | toBeFinite(): void; 371 | 372 | /** 373 | * Use `.toBePositive` when checking if a value is a positive `Number`. 374 | */ 375 | toBePositive(): void; 376 | 377 | /** 378 | * Use `.toBeNegative` when checking if a value is a negative `Number`. 379 | */ 380 | toBeNegative(): void; 381 | 382 | /** 383 | * Use `.toBeEven` when checking if a value is an even `Number`. 384 | */ 385 | toBeEven(): void; 386 | 387 | /** 388 | * Use `.toBeOdd` when checking if a value is an odd `Number`. 389 | */ 390 | toBeOdd(): void; 391 | 392 | /** 393 | * Use `.toBeWithin` when checking if a number is in between the given bounds of: start (inclusive) and end (exclusive). 394 | * 395 | * @param {Number} start 396 | * @param {Number} end 397 | */ 398 | toBeWithin(start: number, end: number): void; 399 | 400 | /** 401 | * Use `.toBeObject` when checking if a value is an `Object`. 402 | */ 403 | toBeObject(): void; 404 | 405 | /** 406 | * Use `.toContainKey` when checking if an object contains the provided key. 407 | * 408 | * @param {String} key 409 | */ 410 | toContainKey(key: string): void; 411 | 412 | /** 413 | * Use `.toContainKeys` when checking if an object has all of the provided keys. 414 | * 415 | * @param {Array.} keys 416 | */ 417 | toContainKeys(keys: string[]): void; 418 | 419 | /** 420 | * Use `.toContainAllKeys` when checking if an object only contains all of the provided keys. 421 | * 422 | * @param {Array.} keys 423 | */ 424 | toContainAllKeys(keys: string[]): void; 425 | 426 | /** 427 | * Use `.toContainAnyKeys` when checking if an object contains at least one of the provided keys. 428 | * 429 | * @param {Array.} keys 430 | */ 431 | toContainAnyKeys(keys: string[]): void; 432 | 433 | /** 434 | * Use `.toContainValue` when checking if an object contains the provided value. 435 | * 436 | * @param {*} value 437 | */ 438 | toContainValue(value: any): void; 439 | 440 | /** 441 | * Use `.toContainValues` when checking if an object contains all of the provided values. 442 | * 443 | * @param {Array.<*>} values 444 | */ 445 | toContainValues(values: any[]): void; 446 | 447 | /** 448 | * Use `.toContainAllValues` when checking if an object only contains all of the provided values. 449 | * 450 | * @param {Array.<*>} values 451 | */ 452 | toContainAllValues(values: any[]): void; 453 | 454 | /** 455 | * Use `.toContainAnyValues` when checking if an object contains at least one of the provided values. 456 | * 457 | * @param {Array.<*>} values 458 | */ 459 | toContainAnyValues(values: any[]): void; 460 | 461 | /** 462 | * Use `.toContainEntry` when checking if an object contains the provided entry. 463 | * 464 | * @param {Array.} entry 465 | */ 466 | toContainEntry(entry: [string, string]): void; 467 | 468 | /** 469 | * Use `.toContainEntries` when checking if an object contains all of the provided entries. 470 | * 471 | * @param {Array.>} entries 472 | */ 473 | toContainEntries(entries: [string, string][]): void; 474 | 475 | /** 476 | * Use `.toContainAllEntries` when checking if an object only contains all of the provided entries. 477 | * 478 | * @param {Array.>} entries 479 | */ 480 | toContainAllEntries(entries: [string, string][]): void; 481 | 482 | /** 483 | * Use `.toContainAnyEntries` when checking if an object contains at least one of the provided entries. 484 | * 485 | * @param {Array.>} entries 486 | */ 487 | toContainAnyEntries(entries: [string, string][]): void; 488 | 489 | /** 490 | * Use `.toBeExtensible` when checking if an object is extensible. 491 | */ 492 | toBeExtensible(): void; 493 | 494 | /** 495 | * Use `.toBeFrozen` when checking if an object is frozen. 496 | */ 497 | toBeFrozen(): void; 498 | 499 | /** 500 | * Use `.toBeSealed` when checking if an object is sealed. 501 | */ 502 | toBeSealed(): void; 503 | 504 | /** 505 | * Use `.toBeString` when checking if a value is a `String`. 506 | */ 507 | toBeString(): void; 508 | 509 | /** 510 | * Use `.toEqualCaseInsensitive` when checking if a string is equal (===) to another ignoring the casing of both strings. 511 | * 512 | * @param {String} string 513 | */ 514 | toEqualCaseInsensitive(string: string): void; 515 | 516 | /** 517 | * Use `.toStartWith` when checking if a `String` starts with a given `String` prefix. 518 | * 519 | * @param {String} prefix 520 | */ 521 | toStartWith(prefix: string): void; 522 | 523 | /** 524 | * Use `.toEndWith` when checking if a `String` ends with a given `String` suffix. 525 | * 526 | * @param {String} suffix 527 | */ 528 | toEndWith(suffix: string): void; 529 | 530 | /** 531 | * Use `.toInclude` when checking if a `String` includes the given `String` substring. 532 | * 533 | * @param {String} substring 534 | */ 535 | toInclude(substring: string): void; 536 | 537 | /** 538 | * Use `.toIncludeRepeated` when checking if a `String` includes the given `String` substring the correct number of times. 539 | * 540 | * @param {String} substring 541 | * @param {Number} times 542 | */ 543 | toIncludeRepeated(substring: string, times: number): void; 544 | 545 | /** 546 | * Use `.toIncludeMultiple` when checking if a `String` includes all of the given substrings. 547 | * 548 | * @param {Array.} substring 549 | */ 550 | toIncludeMultiple(substring: string[]): void; 551 | }; 552 | 553 | interface JestExpectType { 554 | not: 555 | & JestExpectType 556 | & EnzymeMatchersType 557 | & DomTestingLibraryType 558 | & JestJQueryMatchersType 559 | & JestStyledComponentsMatchersType 560 | & JestExtendedMatchersType, 561 | /** 562 | * If you have a mock function, you can use .lastCalledWith to test what 563 | * arguments it was last called with. 564 | */ 565 | lastCalledWith(...args: Array): void, 566 | /** 567 | * toBe just checks that a value is what you expect. It uses === to check 568 | * strict equality. 569 | */ 570 | toBe(value: any): void, 571 | /** 572 | * Use .toBeCalledWith to ensure that a mock function was called with 573 | * specific arguments. 574 | */ 575 | toBeCalledWith(...args: Array): void, 576 | /** 577 | * Using exact equality with floating point numbers is a bad idea. Rounding 578 | * means that intuitive things fail. 579 | */ 580 | toBeCloseTo(num: number, delta: any): void, 581 | /** 582 | * Use .toBeDefined to check that a variable is not undefined. 583 | */ 584 | toBeDefined(): void, 585 | /** 586 | * Use .toBeFalsy when you don't care what a value is, you just want to 587 | * ensure a value is false in a boolean context. 588 | */ 589 | toBeFalsy(): void, 590 | /** 591 | * To compare floating point numbers, you can use toBeGreaterThan. 592 | */ 593 | toBeGreaterThan(number: number): void, 594 | /** 595 | * To compare floating point numbers, you can use toBeGreaterThanOrEqual. 596 | */ 597 | toBeGreaterThanOrEqual(number: number): void, 598 | /** 599 | * To compare floating point numbers, you can use toBeLessThan. 600 | */ 601 | toBeLessThan(number: number): void, 602 | /** 603 | * To compare floating point numbers, you can use toBeLessThanOrEqual. 604 | */ 605 | toBeLessThanOrEqual(number: number): void, 606 | /** 607 | * Use .toBeInstanceOf(Class) to check that an object is an instance of a 608 | * class. 609 | */ 610 | toBeInstanceOf(cls: Class<*>): void, 611 | /** 612 | * .toBeNull() is the same as .toBe(null) but the error messages are a bit 613 | * nicer. 614 | */ 615 | toBeNull(): void, 616 | /** 617 | * Use .toBeTruthy when you don't care what a value is, you just want to 618 | * ensure a value is true in a boolean context. 619 | */ 620 | toBeTruthy(): void, 621 | /** 622 | * Use .toBeUndefined to check that a variable is undefined. 623 | */ 624 | toBeUndefined(): void, 625 | /** 626 | * Use .toContain when you want to check that an item is in a list. For 627 | * testing the items in the list, this uses ===, a strict equality check. 628 | */ 629 | toContain(item: any): void, 630 | /** 631 | * Use .toContainEqual when you want to check that an item is in a list. For 632 | * testing the items in the list, this matcher recursively checks the 633 | * equality of all fields, rather than checking for object identity. 634 | */ 635 | toContainEqual(item: any): void, 636 | /** 637 | * Use .toEqual when you want to check that two objects have the same value. 638 | * This matcher recursively checks the equality of all fields, rather than 639 | * checking for object identity. 640 | */ 641 | toEqual(value: any): void, 642 | /** 643 | * Use .toHaveBeenCalled to ensure that a mock function got called. 644 | */ 645 | toHaveBeenCalled(): void, 646 | toBeCalled(): void; 647 | /** 648 | * Use .toHaveBeenCalledTimes to ensure that a mock function got called exact 649 | * number of times. 650 | */ 651 | toHaveBeenCalledTimes(number: number): void, 652 | toBeCalledTimes(number: number): void; 653 | /** 654 | * 655 | */ 656 | toHaveBeenNthCalledWith(nthCall: number, ...args: Array): void; 657 | nthCalledWith(nthCall: number, ...args: Array): void; 658 | /** 659 | * 660 | */ 661 | toHaveReturned(): void; 662 | toReturn(): void; 663 | /** 664 | * 665 | */ 666 | toHaveReturnedTimes(number: number): void; 667 | toReturnTimes(number: number): void; 668 | /** 669 | * 670 | */ 671 | toHaveReturnedWith(value: any): void; 672 | toReturnWith(value: any): void; 673 | /** 674 | * 675 | */ 676 | toHaveLastReturnedWith(value: any): void; 677 | lastReturnedWith(value: any): void; 678 | /** 679 | * 680 | */ 681 | toHaveNthReturnedWith(nthCall: number, value: any): void; 682 | nthReturnedWith(nthCall: number, value: any): void; 683 | /** 684 | * Use .toHaveBeenCalledWith to ensure that a mock function was called with 685 | * specific arguments. 686 | */ 687 | toHaveBeenCalledWith(...args: Array): void, 688 | toBeCalledWith(...args: Array): void, 689 | /** 690 | * Use .toHaveBeenLastCalledWith to ensure that a mock function was last called 691 | * with specific arguments. 692 | */ 693 | toHaveBeenLastCalledWith(...args: Array): void, 694 | lastCalledWith(...args: Array): void, 695 | /** 696 | * Check that an object has a .length property and it is set to a certain 697 | * numeric value. 698 | */ 699 | toHaveLength(number: number): void, 700 | /** 701 | * 702 | */ 703 | toHaveProperty(propPath: string, value?: any): void, 704 | /** 705 | * Use .toMatch to check that a string matches a regular expression or string. 706 | */ 707 | toMatch(regexpOrString: RegExp | string): void, 708 | /** 709 | * Use .toMatchObject to check that a javascript object matches a subset of the properties of an object. 710 | */ 711 | toMatchObject(object: Object | Array): void, 712 | /** 713 | * Use .toStrictEqual to check that a javascript object matches a subset of the properties of an object. 714 | */ 715 | toStrictEqual(value: any): void, 716 | /** 717 | * This ensures that an Object matches the most recent snapshot. 718 | */ 719 | toMatchSnapshot(propertyMatchers?: any, name?: string): void, 720 | /** 721 | * This ensures that an Object matches the most recent snapshot. 722 | */ 723 | toMatchSnapshot(name: string): void, 724 | 725 | toMatchInlineSnapshot(snapshot?: string): void, 726 | toMatchInlineSnapshot(propertyMatchers?: any, snapshot?: string): void, 727 | /** 728 | * Use .toThrow to test that a function throws when it is called. 729 | * If you want to test that a specific error gets thrown, you can provide an 730 | * argument to toThrow. The argument can be a string for the error message, 731 | * a class for the error, or a regex that should match the error. 732 | * 733 | * Alias: .toThrowError 734 | */ 735 | toThrow(message?: string | Error | Class | RegExp): void, 736 | toThrowError(message?: string | Error | Class | RegExp): void, 737 | /** 738 | * Use .toThrowErrorMatchingSnapshot to test that a function throws a error 739 | * matching the most recent snapshot when it is called. 740 | */ 741 | toThrowErrorMatchingSnapshot(): void, 742 | toThrowErrorMatchingInlineSnapshot(snapshot?: string): void, 743 | } 744 | 745 | type JestObjectType = { 746 | /** 747 | * Disables automatic mocking in the module loader. 748 | * 749 | * After this method is called, all `require()`s will return the real 750 | * versions of each module (rather than a mocked version). 751 | */ 752 | disableAutomock(): JestObjectType, 753 | /** 754 | * An un-hoisted version of disableAutomock 755 | */ 756 | autoMockOff(): JestObjectType, 757 | /** 758 | * Enables automatic mocking in the module loader. 759 | */ 760 | enableAutomock(): JestObjectType, 761 | /** 762 | * An un-hoisted version of enableAutomock 763 | */ 764 | autoMockOn(): JestObjectType, 765 | /** 766 | * Clears the mock.calls and mock.instances properties of all mocks. 767 | * Equivalent to calling .mockClear() on every mocked function. 768 | */ 769 | clearAllMocks(): JestObjectType, 770 | /** 771 | * Resets the state of all mocks. Equivalent to calling .mockReset() on every 772 | * mocked function. 773 | */ 774 | resetAllMocks(): JestObjectType, 775 | /** 776 | * Restores all mocks back to their original value. 777 | */ 778 | restoreAllMocks(): JestObjectType, 779 | /** 780 | * Removes any pending timers from the timer system. 781 | */ 782 | clearAllTimers(): void, 783 | /** 784 | * The same as `mock` but not moved to the top of the expectation by 785 | * babel-jest. 786 | */ 787 | doMock(moduleName: string, moduleFactory?: any): JestObjectType, 788 | /** 789 | * The same as `unmock` but not moved to the top of the expectation by 790 | * babel-jest. 791 | */ 792 | dontMock(moduleName: string): JestObjectType, 793 | /** 794 | * Returns a new, unused mock function. Optionally takes a mock 795 | * implementation. 796 | */ 797 | fn, TReturn>( 798 | implementation?: (...args: TArguments) => TReturn 799 | ): JestMockFn, 800 | /** 801 | * Determines if the given function is a mocked function. 802 | */ 803 | isMockFunction(fn: Function): boolean, 804 | /** 805 | * Given the name of a module, use the automatic mocking system to generate a 806 | * mocked version of the module for you. 807 | */ 808 | genMockFromModule(moduleName: string): any, 809 | /** 810 | * Mocks a module with an auto-mocked version when it is being required. 811 | * 812 | * The second argument can be used to specify an explicit module factory that 813 | * is being run instead of using Jest's automocking feature. 814 | * 815 | * The third argument can be used to create virtual mocks -- mocks of modules 816 | * that don't exist anywhere in the system. 817 | */ 818 | mock( 819 | moduleName: string, 820 | moduleFactory?: any, 821 | options?: Object 822 | ): JestObjectType, 823 | /** 824 | * Returns the actual module instead of a mock, bypassing all checks on 825 | * whether the module should receive a mock implementation or not. 826 | */ 827 | requireActual(moduleName: string): any, 828 | /** 829 | * Returns a mock module instead of the actual module, bypassing all checks 830 | * on whether the module should be required normally or not. 831 | */ 832 | requireMock(moduleName: string): any, 833 | /** 834 | * Resets the module registry - the cache of all required modules. This is 835 | * useful to isolate modules where local state might conflict between tests. 836 | */ 837 | resetModules(): JestObjectType, 838 | /** 839 | * Exhausts the micro-task queue (usually interfaced in node via 840 | * process.nextTick). 841 | */ 842 | runAllTicks(): void, 843 | /** 844 | * Exhausts the macro-task queue (i.e., all tasks queued by setTimeout(), 845 | * setInterval(), and setImmediate()). 846 | */ 847 | runAllTimers(): void, 848 | /** 849 | * Exhausts all tasks queued by setImmediate(). 850 | */ 851 | runAllImmediates(): void, 852 | /** 853 | * Executes only the macro task queue (i.e. all tasks queued by setTimeout() 854 | * or setInterval() and setImmediate()). 855 | */ 856 | advanceTimersByTime(msToRun: number): void, 857 | /** 858 | * Executes only the macro task queue (i.e. all tasks queued by setTimeout() 859 | * or setInterval() and setImmediate()). 860 | * 861 | * Renamed to `advanceTimersByTime`. 862 | */ 863 | runTimersToTime(msToRun: number): void, 864 | /** 865 | * Executes only the macro-tasks that are currently pending (i.e., only the 866 | * tasks that have been queued by setTimeout() or setInterval() up to this 867 | * point) 868 | */ 869 | runOnlyPendingTimers(): void, 870 | /** 871 | * Explicitly supplies the mock object that the module system should return 872 | * for the specified module. Note: It is recommended to use jest.mock() 873 | * instead. 874 | */ 875 | setMock(moduleName: string, moduleExports: any): JestObjectType, 876 | /** 877 | * Indicates that the module system should never return a mocked version of 878 | * the specified module from require() (e.g. that it should always return the 879 | * real module). 880 | */ 881 | unmock(moduleName: string): JestObjectType, 882 | /** 883 | * Instructs Jest to use fake versions of the standard timer functions 884 | * (setTimeout, setInterval, clearTimeout, clearInterval, nextTick, 885 | * setImmediate and clearImmediate). 886 | */ 887 | useFakeTimers(): JestObjectType, 888 | /** 889 | * Instructs Jest to use the real versions of the standard timer functions. 890 | */ 891 | useRealTimers(): JestObjectType, 892 | /** 893 | * Creates a mock function similar to jest.fn but also tracks calls to 894 | * object[methodName]. 895 | */ 896 | spyOn(object: Object, methodName: string, accessType?: "get" | "set"): JestMockFn, 897 | /** 898 | * Set the default timeout interval for tests and before/after hooks in milliseconds. 899 | * Note: The default timeout interval is 5 seconds if this method is not called. 900 | */ 901 | setTimeout(timeout: number): JestObjectType 902 | }; 903 | 904 | type JestSpyType = { 905 | calls: JestCallsType 906 | }; 907 | 908 | /** Runs this function after every test inside this context */ 909 | declare function afterEach( 910 | fn: (done: () => void) => ?Promise, 911 | timeout?: number 912 | ): void; 913 | /** Runs this function before every test inside this context */ 914 | declare function beforeEach( 915 | fn: (done: () => void) => ?Promise, 916 | timeout?: number 917 | ): void; 918 | /** Runs this function after all tests have finished inside this context */ 919 | declare function afterAll( 920 | fn: (done: () => void) => ?Promise, 921 | timeout?: number 922 | ): void; 923 | /** Runs this function before any tests have started inside this context */ 924 | declare function beforeAll( 925 | fn: (done: () => void) => ?Promise, 926 | timeout?: number 927 | ): void; 928 | 929 | /** A context for grouping tests together */ 930 | declare var describe: { 931 | /** 932 | * Creates a block that groups together several related tests in one "test suite" 933 | */ 934 | (name: JestTestName, fn: () => void): void, 935 | 936 | /** 937 | * Only run this describe block 938 | */ 939 | only(name: JestTestName, fn: () => void): void, 940 | 941 | /** 942 | * Skip running this describe block 943 | */ 944 | skip(name: JestTestName, fn: () => void): void, 945 | 946 | /** 947 | * each runs this test against array of argument arrays per each run 948 | * 949 | * @param {table} table of Test 950 | */ 951 | each( 952 | ...table: Array | mixed> | [Array, string] 953 | ): ( 954 | name: JestTestName, 955 | fn?: (...args: Array) => ?Promise, 956 | timeout?: number 957 | ) => void, 958 | }; 959 | 960 | /** An individual test unit */ 961 | declare var it: { 962 | /** 963 | * An individual test unit 964 | * 965 | * @param {JestTestName} Name of Test 966 | * @param {Function} Test 967 | * @param {number} Timeout for the test, in milliseconds. 968 | */ 969 | ( 970 | name: JestTestName, 971 | fn?: (done: () => void) => ?Promise, 972 | timeout?: number 973 | ): void, 974 | 975 | /** 976 | * Only run this test 977 | * 978 | * @param {JestTestName} Name of Test 979 | * @param {Function} Test 980 | * @param {number} Timeout for the test, in milliseconds. 981 | */ 982 | only( 983 | name: JestTestName, 984 | fn?: (done: () => void) => ?Promise, 985 | timeout?: number 986 | ): { 987 | each( 988 | ...table: Array | mixed> | [Array, string] 989 | ): ( 990 | name: JestTestName, 991 | fn?: (...args: Array) => ?Promise, 992 | timeout?: number 993 | ) => void, 994 | }, 995 | 996 | /** 997 | * Skip running this test 998 | * 999 | * @param {JestTestName} Name of Test 1000 | * @param {Function} Test 1001 | * @param {number} Timeout for the test, in milliseconds. 1002 | */ 1003 | skip( 1004 | name: JestTestName, 1005 | fn?: (done: () => void) => ?Promise, 1006 | timeout?: number 1007 | ): void, 1008 | 1009 | /** 1010 | * Run the test concurrently 1011 | * 1012 | * @param {JestTestName} Name of Test 1013 | * @param {Function} Test 1014 | * @param {number} Timeout for the test, in milliseconds. 1015 | */ 1016 | concurrent( 1017 | name: JestTestName, 1018 | fn?: (done: () => void) => ?Promise, 1019 | timeout?: number 1020 | ): void, 1021 | 1022 | /** 1023 | * each runs this test against array of argument arrays per each run 1024 | * 1025 | * @param {table} table of Test 1026 | */ 1027 | each( 1028 | ...table: Array | mixed> | [Array, string] 1029 | ): ( 1030 | name: JestTestName, 1031 | fn?: (...args: Array) => ?Promise, 1032 | timeout?: number 1033 | ) => void, 1034 | }; 1035 | 1036 | declare function fit( 1037 | name: JestTestName, 1038 | fn: (done: () => void) => ?Promise, 1039 | timeout?: number 1040 | ): void; 1041 | /** An individual test unit */ 1042 | declare var test: typeof it; 1043 | /** A disabled group of tests */ 1044 | declare var xdescribe: typeof describe; 1045 | /** A focused group of tests */ 1046 | declare var fdescribe: typeof describe; 1047 | /** A disabled individual test */ 1048 | declare var xit: typeof it; 1049 | /** A disabled individual test */ 1050 | declare var xtest: typeof it; 1051 | 1052 | type JestPrettyFormatColors = { 1053 | comment: { close: string, open: string }, 1054 | content: { close: string, open: string }, 1055 | prop: { close: string, open: string }, 1056 | tag: { close: string, open: string }, 1057 | value: { close: string, open: string }, 1058 | }; 1059 | 1060 | type JestPrettyFormatIndent = string => string; 1061 | type JestPrettyFormatRefs = Array; 1062 | type JestPrettyFormatPrint = any => string; 1063 | type JestPrettyFormatStringOrNull = string | null; 1064 | 1065 | type JestPrettyFormatOptions = {| 1066 | callToJSON: boolean, 1067 | edgeSpacing: string, 1068 | escapeRegex: boolean, 1069 | highlight: boolean, 1070 | indent: number, 1071 | maxDepth: number, 1072 | min: boolean, 1073 | plugins: JestPrettyFormatPlugins, 1074 | printFunctionName: boolean, 1075 | spacing: string, 1076 | theme: {| 1077 | comment: string, 1078 | content: string, 1079 | prop: string, 1080 | tag: string, 1081 | value: string, 1082 | |}, 1083 | |}; 1084 | 1085 | type JestPrettyFormatPlugin = { 1086 | print: ( 1087 | val: any, 1088 | serialize: JestPrettyFormatPrint, 1089 | indent: JestPrettyFormatIndent, 1090 | opts: JestPrettyFormatOptions, 1091 | colors: JestPrettyFormatColors, 1092 | ) => string, 1093 | test: any => boolean, 1094 | }; 1095 | 1096 | type JestPrettyFormatPlugins = Array; 1097 | 1098 | /** The expect function is used every time you want to test a value */ 1099 | declare var expect: { 1100 | /** The object that you want to make assertions against */ 1101 | (value: any): 1102 | & JestExpectType 1103 | & JestPromiseType 1104 | & EnzymeMatchersType 1105 | & DomTestingLibraryType 1106 | & JestJQueryMatchersType 1107 | & JestStyledComponentsMatchersType 1108 | & JestExtendedMatchersType, 1109 | 1110 | /** Add additional Jasmine matchers to Jest's roster */ 1111 | extend(matchers: { [name: string]: JestMatcher }): void, 1112 | /** Add a module that formats application-specific data structures. */ 1113 | addSnapshotSerializer(pluginModule: JestPrettyFormatPlugin): void, 1114 | assertions(expectedAssertions: number): void, 1115 | hasAssertions(): void, 1116 | any(value: mixed): JestAsymmetricEqualityType, 1117 | anything(): any, 1118 | arrayContaining(value: Array): Array, 1119 | objectContaining(value: Object): Object, 1120 | /** Matches any received string that contains the exact expected string. */ 1121 | stringContaining(value: string): string, 1122 | stringMatching(value: string | RegExp): string, 1123 | not: { 1124 | arrayContaining: (value: $ReadOnlyArray) => Array, 1125 | objectContaining: (value: {}) => Object, 1126 | stringContaining: (value: string) => string, 1127 | stringMatching: (value: string | RegExp) => string, 1128 | }, 1129 | }; 1130 | 1131 | // TODO handle return type 1132 | // http://jasmine.github.io/2.4/introduction.html#section-Spies 1133 | declare function spyOn(value: mixed, method: string): Object; 1134 | 1135 | /** Holds all functions related to manipulating test runner */ 1136 | declare var jest: JestObjectType; 1137 | 1138 | /** 1139 | * The global Jasmine object, this is generally not exposed as the public API, 1140 | * using features inside here could break in later versions of Jest. 1141 | */ 1142 | declare var jasmine: { 1143 | DEFAULT_TIMEOUT_INTERVAL: number, 1144 | any(value: mixed): JestAsymmetricEqualityType, 1145 | anything(): any, 1146 | arrayContaining(value: Array): Array, 1147 | clock(): JestClockType, 1148 | createSpy(name: string): JestSpyType, 1149 | createSpyObj( 1150 | baseName: string, 1151 | methodNames: Array 1152 | ): { [methodName: string]: JestSpyType }, 1153 | objectContaining(value: Object): Object, 1154 | stringMatching(value: string): string 1155 | }; 1156 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import SuggestionListItem from './src/SuggestionListItem'; 2 | import InputAutoSuggest from './src/InputAutoSuggest'; 3 | 4 | module.exports = { 5 | InputAutoSuggest: InputAutoSuggest, 6 | SuggestionListItem: SuggestionListItem, 7 | }; 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-autocomplete-search", 3 | "version": "1.0.1", 4 | "description": "react-native component used for autocompletion when searching data from local or remote source", 5 | "main": "index.js", 6 | "repository": "https://github.com/najeal/react-native-autocomplete-search.git", 7 | "author": "nathanh", 8 | "license": "MIT", 9 | "keywords": [ 10 | "react-native", 11 | "react-component", 12 | "search", 13 | "local", 14 | "remote", 15 | "source", 16 | "autocomplete", 17 | "autocompletion", 18 | "autosuggestion", 19 | "autosuggest", 20 | "suggestion", 21 | "suggest" 22 | ], 23 | "scripts": { 24 | "test": "jest" 25 | }, 26 | "peerDependencies": { 27 | "prop-types": "*", 28 | "react": "*", 29 | "react-native": "*" 30 | }, 31 | "devDependencies": { 32 | "@babel/core": "^7.1.6", 33 | "@babel/preset-env": "^7.1.6", 34 | "babel-core": "^7.0.0-bridge.0", 35 | "babel-eslint": "^10.0.1", 36 | "babel-jest": "^23.6.0", 37 | "eslint": "^5.9.0", 38 | "eslint-config-airbnb": "^17.1.0", 39 | "eslint-plugin-import": "^2.14.0", 40 | "eslint-plugin-jsx-a11y": "^6.1.2", 41 | "eslint-plugin-react": "^7.11.1", 42 | "flow-bin": "^0.86.0", 43 | "jest": "^23.6.0", 44 | "react": "^16.6.3", 45 | "regenerator-runtime": "^0.13.1" 46 | }, 47 | "dependencies": { 48 | "@babel/preset-flow": "^7.0.0", 49 | "lodash": "^4.17.11" 50 | }, 51 | "jest": { 52 | "verbose": true, 53 | "moduleDirectories": [ 54 | "node_modules", 55 | "src" 56 | ], 57 | "transform": { 58 | "^.+\\.js?$": "babel-jest" 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/InputAutoSuggest.js: -------------------------------------------------------------------------------- 1 | 2 | import { 3 | FlatList, View, TextInput, StyleSheet, 4 | } from 'react-native'; 5 | import PropTypes from 'prop-types'; 6 | import React, { Component } from 'react'; 7 | import * as _ from 'lodash'; 8 | // import { TextInput } from 'react-native-ui-lib'; 9 | import SuggestionListItem from './SuggestionListItem'; 10 | import suggest from './services/suggest'; 11 | 12 | 13 | let style; 14 | 15 | class InputAutoSuggest extends Component { 16 | constructor(props) { 17 | super(props); 18 | const { staticData, itemFormat } = this.props; 19 | 20 | const data = suggest.searchForRelevant('', staticData || [], itemFormat); 21 | this.state = { data: data.suggest, value: '' }; 22 | 23 | this.searchList = this.searchList.bind(this); 24 | this.renderItem = this.renderItem.bind(this); 25 | } 26 | 27 | onPressItem = (id: string, name: string) => { 28 | // updater functions are preferred for transactional updates 29 | const { onDataSelectedChange } = this.props; 30 | const existingItem = { id, name }; 31 | this.setState({ 32 | value: name, 33 | }); 34 | onDataSelectedChange(existingItem); 35 | }; 36 | 37 | keyExtractor = item => item.id; 38 | 39 | async searchList(text) { 40 | const { 41 | keyPathRequestResult, 42 | itemFormat, 43 | apiEndpointSuggestData, 44 | onDataSelectedChange, 45 | staticData, 46 | } = this.props; 47 | this.setState({ value: text }); 48 | let suggestData = null; 49 | if (staticData != null) { 50 | try { 51 | suggestData = !text ? staticData : suggest.searchForRelevant(text, staticData, itemFormat); 52 | } catch (e) { 53 | suggestData = { suggest: [], existingItem: null }; 54 | } 55 | } else { 56 | try { 57 | suggestData = await suggest.searchForSuggest( 58 | text, 59 | apiEndpointSuggestData, 60 | keyPathRequestResult, 61 | itemFormat, 62 | ); 63 | } catch (e) { 64 | suggestData = { suggest: [], existingItem: null }; 65 | } 66 | } 67 | onDataSelectedChange(suggestData.existingItem); 68 | this.setState({ 69 | data: suggestData.suggest, 70 | }); 71 | } 72 | 73 | renderItem = ({ item }) => { 74 | const { itemTextStyle, itemTagStyle } = this.props; 75 | return ( 76 | 84 | ); 85 | }; 86 | 87 | render() { 88 | const { value, data } = this.state; 89 | const { inputStyle, flatListStyle } = this.props; 90 | return ( 91 | 92 | 98 | 105 | 106 | ); 107 | } 108 | } 109 | InputAutoSuggest.propTypes = { 110 | inputStyle: PropTypes.shape({}), 111 | flatListStyle: PropTypes.shape({}), 112 | itemTextStyle: PropTypes.shape({}), 113 | itemTagStyle: PropTypes.shape({}), 114 | apiEndpointSuggestData: PropTypes.func, 115 | staticData: PropTypes.arrayOf(PropTypes.shape({})), 116 | onDataSelectedChange: PropTypes.func, 117 | keyPathRequestResult: PropTypes.string, 118 | itemFormat: PropTypes.shape({ 119 | id: PropTypes.string.isRequired, 120 | name: PropTypes.string.isRequired, 121 | tags: PropTypes.arrayOf(PropTypes.string), 122 | }), 123 | }; 124 | InputAutoSuggest.defaultProps = { 125 | inputStyle: {}, 126 | flatListStyle: {}, 127 | itemTextStyle: { fontSize: 25 }, 128 | itemTagStyle: { fontSize: 22 }, 129 | staticData: null, 130 | apiEndpointSuggestData: () => _.noop, 131 | onDataSelectedChange: () => _.noop, 132 | keyPathRequestResult: 'suggest.city[0].options', 133 | itemFormat: { 134 | id: 'id', 135 | name: 'name', 136 | tags: [], 137 | }, 138 | }; 139 | 140 | style = StyleSheet.create({ 141 | container: { 142 | flexDirection: 'column', 143 | justifyContent: 'flex-start', 144 | }, 145 | input: { 146 | fontSize: 22, 147 | borderBottomWidth: 1, 148 | }, 149 | flatList: {}, 150 | itemTextStyle: { fontSize: 30 }, 151 | }); 152 | 153 | export default InputAutoSuggest; 154 | -------------------------------------------------------------------------------- /src/SuggestionListItem.js: -------------------------------------------------------------------------------- 1 | import { 2 | View, Text, TouchableOpacity, 3 | } from 'react-native'; 4 | import PropTypes from 'prop-types'; 5 | import React, { PureComponent } from 'react'; 6 | 7 | class SuggestionListItem extends PureComponent { 8 | onPress = () => { 9 | const { name, id, onPressItem } = this.props; 10 | onPressItem(id, name); 11 | }; 12 | 13 | render() { 14 | const { 15 | name, tags, textStyle, tagStyle, 16 | } = this.props; 17 | return ( 18 | 19 | 20 | 21 | { name } 22 | 23 | { 24 | tags && tags.map(tag => ( 25 | 26 | { tag.item } 27 | 28 | )) 29 | } 30 | 31 | 32 | ); 33 | } 34 | } 35 | SuggestionListItem.propTypes = { 36 | textStyle: PropTypes.shape({}), 37 | tagStyle: PropTypes.shape({}), 38 | name: PropTypes.string.isRequired, 39 | id: PropTypes.string.isRequired, 40 | tags: PropTypes.arrayOf(PropTypes.string), 41 | onPressItem: PropTypes.func.isRequired, 42 | }; 43 | SuggestionListItem.defaultProps = { 44 | tags: [], 45 | textStyle: {}, 46 | tagStyle: {}, 47 | }; 48 | 49 | export default SuggestionListItem; 50 | -------------------------------------------------------------------------------- /src/services/suggest.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import _ from 'lodash'; 4 | 5 | export type FormatDescribe = { 6 | id: string, 7 | name: string, 8 | tags?: ?Array 9 | }; 10 | 11 | export type SuggestionDescribe = { 12 | id: string, 13 | name: string, 14 | tags: ?Array<{item: string, id: string}> 15 | } 16 | 17 | export type SuggestData = { 18 | suggest: Array, 19 | existingItem: ?{id:string, name:string} 20 | } 21 | 22 | function suggestFormat( 23 | datas: Array<{}>, 24 | itemFormat: FormatDescribe, 25 | text: string):SuggestData { 26 | let searching = true; 27 | let existingItem = null; 28 | let tags: ?Array<{item: string, id: string}> = null; 29 | const suggest: Array = datas.map( 30 | (data:{}) => { 31 | const id = _.get(data, itemFormat.id); 32 | const name = _.get(data, itemFormat.name); 33 | tags = (itemFormat.tags != null) ? itemFormat.tags.map((tag, index) => ({ 34 | item: _.get(data, tag), 35 | id: String(index), 36 | })) : null; 37 | // search text presence 38 | if (searching && (name === text)) { 39 | existingItem = { id, name }; 40 | searching = false; 41 | } 42 | return { id, name, tags }; 43 | }, 44 | ); 45 | return { suggest, existingItem }; 46 | } 47 | 48 | async function searchForSuggest(text:string, 49 | apiEndpointSuggestData:(text: string)=>any, 50 | keyPathRequestResult:string, 51 | itemFormat:FormatDescribe) { 52 | const response = await apiEndpointSuggestData(text); 53 | const responseData = await response.json(); 54 | return suggestFormat(_.get(responseData, keyPathRequestResult), itemFormat, text); 55 | } 56 | 57 | function searchForRelevant( 58 | text:string, 59 | items:Array<{}>, 60 | itemFormat:FormatDescribe):SuggestData { 61 | const suggest:Array = []; 62 | let counter = 0; 63 | let existingItem = null; 64 | const reg = text ? new RegExp(`^${text}`, 'iu') : null; 65 | let tags: ?Array<{item: string, id: string}> = null; 66 | items.some((element) => { 67 | const name = _.get(element, itemFormat.name); 68 | if (!reg || reg.test(name)) { 69 | const id = _.get(element, itemFormat.id); 70 | if (!existingItem && text === name) { 71 | existingItem = { id, name }; 72 | } 73 | tags = (itemFormat.tags != null) 74 | ? itemFormat.tags.map( 75 | (tag, index) => ({ 76 | item: _.get(element, tag), 77 | id: String(index), 78 | })) 79 | : null; 80 | suggest.push({ id, name, tags }); 81 | counter += 1; 82 | } 83 | return false; 84 | }); 85 | return { suggest, existingItem }; 86 | } 87 | 88 | export default { searchForSuggest, searchForRelevant }; 89 | -------------------------------------------------------------------------------- /src/services/suggest.test.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import suggest from './suggest'; 4 | import type {FormatDescribe, SuggestData,SuggestionDescribe} from './suggest'; 5 | 6 | describe('suggest searchForRelevant tests', () => { 7 | it('test path', () => { 8 | const res = suggest.searchForRelevant('', [{ 9 | val: 'val1', 10 | details: {id: '1', name: 'val'} 11 | }], 12 | {id:'details.id', name:'details.name'}); 13 | expect(res.suggest).toEqual( 14 | [{id: '1', name:'val', tags: null}] 15 | ); 16 | }); 17 | 18 | it('test path multiple data', () => { 19 | const input:Array<{}> = [{ 20 | val: 'val1', 21 | details: {id: '1', name: 'val'} 22 | },{ 23 | val: 'val2', 24 | details: {id: '2', name: 'val2'} 25 | }]; 26 | const inputFormat:FormatDescribe = { 27 | id:'details.id', 28 | name:'details.name' 29 | }; 30 | const res = suggest.searchForRelevant('', input, inputFormat); 31 | expect(res.suggest).toEqual( 32 | [{id: '1', name:'val', tags: null}, {id: '2', name:'val2', tags: null}] 33 | ); 34 | }); 35 | 36 | it('test path multiple data and tags', () => { 37 | const input:Array<{}> = [{ 38 | val: 'val1', 39 | details: {id: '1', name: 'val', country:'FR'} 40 | },{ 41 | val: 'val2', 42 | details: {id: '2', name: 'val2', country:'BE'} 43 | }]; 44 | const inputFormat:FormatDescribe = { 45 | id:'details.id', 46 | name:'details.name', 47 | tags: ['details.country'] 48 | }; 49 | const res = suggest.searchForRelevant('', input, inputFormat); 50 | expect(res.suggest).toEqual( 51 | [{id: '1', name:'val', tags: [{id: "0", item: 'FR'}]}, {id: '2', name:'val2', tags: [{id:"0", item:'BE'}]}] 52 | ); 53 | }); 54 | 55 | it('test path multiple data and multiple tags', () => { 56 | const input:Array<{}> = [{ 57 | val: 'val1', 58 | details: {id: '1', name: 'val', country:'FR', code:'S'} 59 | },{ 60 | val: 'val2', 61 | details: {id: '2', name: 'val2', country:'BE', code:'R'} 62 | }]; 63 | const inputFormat:FormatDescribe = { 64 | id:'details.id', 65 | name:'details.name', 66 | tags: ['details.country', 'details.code'] 67 | }; 68 | const res = suggest.searchForRelevant('', input, inputFormat); 69 | expect(res.suggest).toEqual( 70 | [{ 71 | id: '1', 72 | name:'val', 73 | tags: [{id: "0", item: 'FR'}, {id: "1", item: 'S'}] 74 | },{ 75 | id: '2', 76 | name:'val2', 77 | tags: [{id:"0", item:'BE'},{id: "1", item: 'R'}]}] 78 | ); 79 | }); 80 | }); 81 | --------------------------------------------------------------------------------