diff --git a/frontend/src/initKea.ts b/frontend/src/initKea.ts index 820052881db..74d8a46d279 100644 --- a/frontend/src/initKea.ts +++ b/frontend/src/initKea.ts @@ -4,6 +4,7 @@ import { routerPlugin } from 'kea-router' import { loadersPlugin } from 'kea-loaders' import { windowValuesPlugin } from 'kea-window-values' import { errorToast, identifierToHuman } from 'lib/utils' +import { waitForPlugin } from 'kea-waitfor' /* Actions for which we don't want to show error alerts, @@ -47,6 +48,7 @@ export function initKea(): void { ;(window as any).Sentry?.captureException(error) }, }), + waitForPlugin, ], }) } diff --git a/frontend/src/lib/api.mock.ts b/frontend/src/lib/api.mock.ts new file mode 100644 index 00000000000..dc6c5814c81 --- /dev/null +++ b/frontend/src/lib/api.mock.ts @@ -0,0 +1,26 @@ +import apiNoMock from 'lib/api' + +type APIMockReturnType = { + [K in keyof typeof apiNoMock]: jest.Mock, Parameters> +} + +type APIRoute = { + pathname: string + search: string + searchParams: Record + hash: string + hashParams: Record + url: string + data?: Record +} + +export const api = (apiNoMock as any) as APIMockReturnType + +export const mockAPIGet = (cb: (url: APIRoute) => any): void => { + beforeEach(async () => { + api.get.mockImplementation(async (url, data?: Record) => { + // kea-router is mocked out, must `await import()` to get access to the utility + return cb({ ...(await import('kea-router')).combineUrl(url), data }) + }) + }) +} diff --git a/frontend/src/lib/components/TaxonomicFilter/__snapshots__/infiniteListLogic.test.ts.snap b/frontend/src/lib/components/TaxonomicFilter/__snapshots__/infiniteListLogic.test.ts.snap new file mode 100644 index 00000000000..c6c695fea7d --- /dev/null +++ b/frontend/src/lib/components/TaxonomicFilter/__snapshots__/infiniteListLogic.test.ts.snap @@ -0,0 +1,1301 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`infiniteListLogic verbose version loaders remoteItems setting search query filters events 1`] = ` +Object { + "count": 3, + "queryChanged": true, + "results": Array [ + Object { + "description": "event1 is the best!", + "id": "uuid-0-foobar", + "name": "event1", + "query_usage_30_day": 1, + "volume_30_day": 2, + }, + Object { + "description": "test event is the best!", + "id": "uuid-1-foobar", + "name": "test event", + "query_usage_30_day": 4, + "volume_30_day": 15, + }, + Object { + "description": "other event is the best!", + "id": "uuid-5-foobar", + "name": "other event", + "query_usage_30_day": 16, + "volume_30_day": 67, + }, + ], + "searchQuery": "event", +} +`; + +exports[`infiniteListLogic verbose version values has proper defaults 1`] = ` +Object { + "fuse": Fuse { + "_docs": Array [], + "_keyStore": "[{\\"path\\":[\\"name\\"],\\"id\\":\\"name\\",\\"weight\\":0.5,\\"src\\":\\"name\\"}]", + "_myIndex": Object { + "keys": Array [ + Object { + "id": "name", + "path": Array [ + "name", + ], + "src": "name", + "weight": 1, + }, + ], + "records": Array [], + }, + "options": Object { + "distance": 100, + "findAllMatches": false, + "getFn": [Function], + "ignoreFieldNorm": false, + "ignoreLocation": false, + "includeMatches": false, + "includeScore": false, + "isCaseSensitive": false, + "keys": Array [ + "name", + ], + "location": 0, + "minMatchCharLength": 1, + "shouldSort": true, + "sortFn": [Function], + "threshold": 0.3, + "useExtendedSearch": false, + }, + }, + "group": Object { + "endpoint": "api/projects/@current/event_definitions", + "getName": [Function], + "getValue": [Function], + "name": "Events", + "type": "events", + }, + "groupType": undefined, + "index": 0, + "isLoading": false, + "isRemoteDataSource": true, + "items": Object { + "count": 56, + "queryChanged": false, + "results": Array [ + Object { + "description": "event1 is the best!", + "id": "uuid-0-foobar", + "name": "event1", + "query_usage_30_day": 1, + "volume_30_day": 2, + }, + Object { + "description": "test event is the best!", + "id": "uuid-1-foobar", + "name": "test event", + "query_usage_30_day": 4, + "volume_30_day": 15, + }, + Object { + "description": "$click is the best!", + "id": "uuid-2-foobar", + "name": "$click", + "query_usage_30_day": 7, + "volume_30_day": 28, + }, + Object { + "description": "$autocapture is the best!", + "id": "uuid-3-foobar", + "name": "$autocapture", + "query_usage_30_day": 10, + "volume_30_day": 41, + }, + Object { + "description": "search is the best!", + "id": "uuid-4-foobar", + "name": "search", + "query_usage_30_day": 13, + "volume_30_day": 54, + }, + Object { + "description": "other event is the best!", + "id": "uuid-5-foobar", + "name": "other event", + "query_usage_30_day": 16, + "volume_30_day": 67, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-6-foobar", + "name": "misc-6-generated", + "query_usage_30_day": 19, + "volume_30_day": 80, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-7-foobar", + "name": "misc-7-generated", + "query_usage_30_day": 22, + "volume_30_day": 93, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-8-foobar", + "name": "misc-8-generated", + "query_usage_30_day": 25, + "volume_30_day": 106, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-9-foobar", + "name": "misc-9-generated", + "query_usage_30_day": 28, + "volume_30_day": 119, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-10-foobar", + "name": "misc-10-generated", + "query_usage_30_day": 31, + "volume_30_day": 132, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-11-foobar", + "name": "misc-11-generated", + "query_usage_30_day": 34, + "volume_30_day": 145, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-12-foobar", + "name": "misc-12-generated", + "query_usage_30_day": 37, + "volume_30_day": 158, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-13-foobar", + "name": "misc-13-generated", + "query_usage_30_day": 40, + "volume_30_day": 171, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-14-foobar", + "name": "misc-14-generated", + "query_usage_30_day": 43, + "volume_30_day": 184, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-15-foobar", + "name": "misc-15-generated", + "query_usage_30_day": 46, + "volume_30_day": 197, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-16-foobar", + "name": "misc-16-generated", + "query_usage_30_day": 49, + "volume_30_day": 210, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-17-foobar", + "name": "misc-17-generated", + "query_usage_30_day": 52, + "volume_30_day": 223, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-18-foobar", + "name": "misc-18-generated", + "query_usage_30_day": 55, + "volume_30_day": 236, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-19-foobar", + "name": "misc-19-generated", + "query_usage_30_day": 58, + "volume_30_day": 249, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-20-foobar", + "name": "misc-20-generated", + "query_usage_30_day": 61, + "volume_30_day": 262, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-21-foobar", + "name": "misc-21-generated", + "query_usage_30_day": 64, + "volume_30_day": 275, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-22-foobar", + "name": "misc-22-generated", + "query_usage_30_day": 67, + "volume_30_day": 288, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-23-foobar", + "name": "misc-23-generated", + "query_usage_30_day": 70, + "volume_30_day": 301, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-24-foobar", + "name": "misc-24-generated", + "query_usage_30_day": 73, + "volume_30_day": 314, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-25-foobar", + "name": "misc-25-generated", + "query_usage_30_day": 76, + "volume_30_day": 327, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-26-foobar", + "name": "misc-26-generated", + "query_usage_30_day": 79, + "volume_30_day": 340, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-27-foobar", + "name": "misc-27-generated", + "query_usage_30_day": 82, + "volume_30_day": 353, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-28-foobar", + "name": "misc-28-generated", + "query_usage_30_day": 85, + "volume_30_day": 366, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-29-foobar", + "name": "misc-29-generated", + "query_usage_30_day": 88, + "volume_30_day": 379, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-30-foobar", + "name": "misc-30-generated", + "query_usage_30_day": 91, + "volume_30_day": 392, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-31-foobar", + "name": "misc-31-generated", + "query_usage_30_day": 94, + "volume_30_day": 405, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-32-foobar", + "name": "misc-32-generated", + "query_usage_30_day": 97, + "volume_30_day": 418, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-33-foobar", + "name": "misc-33-generated", + "query_usage_30_day": 100, + "volume_30_day": 431, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-34-foobar", + "name": "misc-34-generated", + "query_usage_30_day": 103, + "volume_30_day": 444, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-35-foobar", + "name": "misc-35-generated", + "query_usage_30_day": 106, + "volume_30_day": 457, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-36-foobar", + "name": "misc-36-generated", + "query_usage_30_day": 109, + "volume_30_day": 470, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-37-foobar", + "name": "misc-37-generated", + "query_usage_30_day": 112, + "volume_30_day": 483, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-38-foobar", + "name": "misc-38-generated", + "query_usage_30_day": 115, + "volume_30_day": 496, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-39-foobar", + "name": "misc-39-generated", + "query_usage_30_day": 118, + "volume_30_day": 509, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-40-foobar", + "name": "misc-40-generated", + "query_usage_30_day": 121, + "volume_30_day": 522, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-41-foobar", + "name": "misc-41-generated", + "query_usage_30_day": 124, + "volume_30_day": 535, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-42-foobar", + "name": "misc-42-generated", + "query_usage_30_day": 127, + "volume_30_day": 548, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-43-foobar", + "name": "misc-43-generated", + "query_usage_30_day": 130, + "volume_30_day": 561, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-44-foobar", + "name": "misc-44-generated", + "query_usage_30_day": 133, + "volume_30_day": 574, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-45-foobar", + "name": "misc-45-generated", + "query_usage_30_day": 136, + "volume_30_day": 587, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-46-foobar", + "name": "misc-46-generated", + "query_usage_30_day": 139, + "volume_30_day": 600, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-47-foobar", + "name": "misc-47-generated", + "query_usage_30_day": 142, + "volume_30_day": 613, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-48-foobar", + "name": "misc-48-generated", + "query_usage_30_day": 145, + "volume_30_day": 626, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-49-foobar", + "name": "misc-49-generated", + "query_usage_30_day": 148, + "volume_30_day": 639, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-50-foobar", + "name": "misc-50-generated", + "query_usage_30_day": 151, + "volume_30_day": 652, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-51-foobar", + "name": "misc-51-generated", + "query_usage_30_day": 154, + "volume_30_day": 665, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-52-foobar", + "name": "misc-52-generated", + "query_usage_30_day": 157, + "volume_30_day": 678, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-53-foobar", + "name": "misc-53-generated", + "query_usage_30_day": 160, + "volume_30_day": 691, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-54-foobar", + "name": "misc-54-generated", + "query_usage_30_day": 163, + "volume_30_day": 704, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-55-foobar", + "name": "misc-55-generated", + "query_usage_30_day": 166, + "volume_30_day": 717, + }, + ], + "searchQuery": "", + }, + "limit": 100, + "listGroupType": "events", + "localItems": Object { + "count": 0, + "first": false, + "results": Array [], + "searchQuery": "", + }, + "rawLocalItems": null, + "remoteEndpoint": "api/projects/@current/event_definitions", + "remoteItems": Object { + "count": 56, + "queryChanged": false, + "results": Array [ + Object { + "description": "event1 is the best!", + "id": "uuid-0-foobar", + "name": "event1", + "query_usage_30_day": 1, + "volume_30_day": 2, + }, + Object { + "description": "test event is the best!", + "id": "uuid-1-foobar", + "name": "test event", + "query_usage_30_day": 4, + "volume_30_day": 15, + }, + Object { + "description": "$click is the best!", + "id": "uuid-2-foobar", + "name": "$click", + "query_usage_30_day": 7, + "volume_30_day": 28, + }, + Object { + "description": "$autocapture is the best!", + "id": "uuid-3-foobar", + "name": "$autocapture", + "query_usage_30_day": 10, + "volume_30_day": 41, + }, + Object { + "description": "search is the best!", + "id": "uuid-4-foobar", + "name": "search", + "query_usage_30_day": 13, + "volume_30_day": 54, + }, + Object { + "description": "other event is the best!", + "id": "uuid-5-foobar", + "name": "other event", + "query_usage_30_day": 16, + "volume_30_day": 67, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-6-foobar", + "name": "misc-6-generated", + "query_usage_30_day": 19, + "volume_30_day": 80, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-7-foobar", + "name": "misc-7-generated", + "query_usage_30_day": 22, + "volume_30_day": 93, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-8-foobar", + "name": "misc-8-generated", + "query_usage_30_day": 25, + "volume_30_day": 106, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-9-foobar", + "name": "misc-9-generated", + "query_usage_30_day": 28, + "volume_30_day": 119, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-10-foobar", + "name": "misc-10-generated", + "query_usage_30_day": 31, + "volume_30_day": 132, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-11-foobar", + "name": "misc-11-generated", + "query_usage_30_day": 34, + "volume_30_day": 145, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-12-foobar", + "name": "misc-12-generated", + "query_usage_30_day": 37, + "volume_30_day": 158, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-13-foobar", + "name": "misc-13-generated", + "query_usage_30_day": 40, + "volume_30_day": 171, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-14-foobar", + "name": "misc-14-generated", + "query_usage_30_day": 43, + "volume_30_day": 184, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-15-foobar", + "name": "misc-15-generated", + "query_usage_30_day": 46, + "volume_30_day": 197, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-16-foobar", + "name": "misc-16-generated", + "query_usage_30_day": 49, + "volume_30_day": 210, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-17-foobar", + "name": "misc-17-generated", + "query_usage_30_day": 52, + "volume_30_day": 223, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-18-foobar", + "name": "misc-18-generated", + "query_usage_30_day": 55, + "volume_30_day": 236, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-19-foobar", + "name": "misc-19-generated", + "query_usage_30_day": 58, + "volume_30_day": 249, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-20-foobar", + "name": "misc-20-generated", + "query_usage_30_day": 61, + "volume_30_day": 262, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-21-foobar", + "name": "misc-21-generated", + "query_usage_30_day": 64, + "volume_30_day": 275, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-22-foobar", + "name": "misc-22-generated", + "query_usage_30_day": 67, + "volume_30_day": 288, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-23-foobar", + "name": "misc-23-generated", + "query_usage_30_day": 70, + "volume_30_day": 301, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-24-foobar", + "name": "misc-24-generated", + "query_usage_30_day": 73, + "volume_30_day": 314, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-25-foobar", + "name": "misc-25-generated", + "query_usage_30_day": 76, + "volume_30_day": 327, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-26-foobar", + "name": "misc-26-generated", + "query_usage_30_day": 79, + "volume_30_day": 340, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-27-foobar", + "name": "misc-27-generated", + "query_usage_30_day": 82, + "volume_30_day": 353, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-28-foobar", + "name": "misc-28-generated", + "query_usage_30_day": 85, + "volume_30_day": 366, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-29-foobar", + "name": "misc-29-generated", + "query_usage_30_day": 88, + "volume_30_day": 379, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-30-foobar", + "name": "misc-30-generated", + "query_usage_30_day": 91, + "volume_30_day": 392, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-31-foobar", + "name": "misc-31-generated", + "query_usage_30_day": 94, + "volume_30_day": 405, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-32-foobar", + "name": "misc-32-generated", + "query_usage_30_day": 97, + "volume_30_day": 418, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-33-foobar", + "name": "misc-33-generated", + "query_usage_30_day": 100, + "volume_30_day": 431, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-34-foobar", + "name": "misc-34-generated", + "query_usage_30_day": 103, + "volume_30_day": 444, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-35-foobar", + "name": "misc-35-generated", + "query_usage_30_day": 106, + "volume_30_day": 457, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-36-foobar", + "name": "misc-36-generated", + "query_usage_30_day": 109, + "volume_30_day": 470, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-37-foobar", + "name": "misc-37-generated", + "query_usage_30_day": 112, + "volume_30_day": 483, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-38-foobar", + "name": "misc-38-generated", + "query_usage_30_day": 115, + "volume_30_day": 496, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-39-foobar", + "name": "misc-39-generated", + "query_usage_30_day": 118, + "volume_30_day": 509, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-40-foobar", + "name": "misc-40-generated", + "query_usage_30_day": 121, + "volume_30_day": 522, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-41-foobar", + "name": "misc-41-generated", + "query_usage_30_day": 124, + "volume_30_day": 535, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-42-foobar", + "name": "misc-42-generated", + "query_usage_30_day": 127, + "volume_30_day": 548, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-43-foobar", + "name": "misc-43-generated", + "query_usage_30_day": 130, + "volume_30_day": 561, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-44-foobar", + "name": "misc-44-generated", + "query_usage_30_day": 133, + "volume_30_day": 574, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-45-foobar", + "name": "misc-45-generated", + "query_usage_30_day": 136, + "volume_30_day": 587, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-46-foobar", + "name": "misc-46-generated", + "query_usage_30_day": 139, + "volume_30_day": 600, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-47-foobar", + "name": "misc-47-generated", + "query_usage_30_day": 142, + "volume_30_day": 613, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-48-foobar", + "name": "misc-48-generated", + "query_usage_30_day": 145, + "volume_30_day": 626, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-49-foobar", + "name": "misc-49-generated", + "query_usage_30_day": 148, + "volume_30_day": 639, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-50-foobar", + "name": "misc-50-generated", + "query_usage_30_day": 151, + "volume_30_day": 652, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-51-foobar", + "name": "misc-51-generated", + "query_usage_30_day": 154, + "volume_30_day": 665, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-52-foobar", + "name": "misc-52-generated", + "query_usage_30_day": 157, + "volume_30_day": 678, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-53-foobar", + "name": "misc-53-generated", + "query_usage_30_day": 160, + "volume_30_day": 691, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-54-foobar", + "name": "misc-54-generated", + "query_usage_30_day": 163, + "volume_30_day": 704, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-55-foobar", + "name": "misc-55-generated", + "query_usage_30_day": 166, + "volume_30_day": 717, + }, + ], + "searchQuery": "", + }, + "remoteItemsLoading": false, + "results": Array [ + Object { + "description": "event1 is the best!", + "id": "uuid-0-foobar", + "name": "event1", + "query_usage_30_day": 1, + "volume_30_day": 2, + }, + Object { + "description": "test event is the best!", + "id": "uuid-1-foobar", + "name": "test event", + "query_usage_30_day": 4, + "volume_30_day": 15, + }, + Object { + "description": "$click is the best!", + "id": "uuid-2-foobar", + "name": "$click", + "query_usage_30_day": 7, + "volume_30_day": 28, + }, + Object { + "description": "$autocapture is the best!", + "id": "uuid-3-foobar", + "name": "$autocapture", + "query_usage_30_day": 10, + "volume_30_day": 41, + }, + Object { + "description": "search is the best!", + "id": "uuid-4-foobar", + "name": "search", + "query_usage_30_day": 13, + "volume_30_day": 54, + }, + Object { + "description": "other event is the best!", + "id": "uuid-5-foobar", + "name": "other event", + "query_usage_30_day": 16, + "volume_30_day": 67, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-6-foobar", + "name": "misc-6-generated", + "query_usage_30_day": 19, + "volume_30_day": 80, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-7-foobar", + "name": "misc-7-generated", + "query_usage_30_day": 22, + "volume_30_day": 93, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-8-foobar", + "name": "misc-8-generated", + "query_usage_30_day": 25, + "volume_30_day": 106, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-9-foobar", + "name": "misc-9-generated", + "query_usage_30_day": 28, + "volume_30_day": 119, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-10-foobar", + "name": "misc-10-generated", + "query_usage_30_day": 31, + "volume_30_day": 132, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-11-foobar", + "name": "misc-11-generated", + "query_usage_30_day": 34, + "volume_30_day": 145, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-12-foobar", + "name": "misc-12-generated", + "query_usage_30_day": 37, + "volume_30_day": 158, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-13-foobar", + "name": "misc-13-generated", + "query_usage_30_day": 40, + "volume_30_day": 171, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-14-foobar", + "name": "misc-14-generated", + "query_usage_30_day": 43, + "volume_30_day": 184, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-15-foobar", + "name": "misc-15-generated", + "query_usage_30_day": 46, + "volume_30_day": 197, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-16-foobar", + "name": "misc-16-generated", + "query_usage_30_day": 49, + "volume_30_day": 210, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-17-foobar", + "name": "misc-17-generated", + "query_usage_30_day": 52, + "volume_30_day": 223, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-18-foobar", + "name": "misc-18-generated", + "query_usage_30_day": 55, + "volume_30_day": 236, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-19-foobar", + "name": "misc-19-generated", + "query_usage_30_day": 58, + "volume_30_day": 249, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-20-foobar", + "name": "misc-20-generated", + "query_usage_30_day": 61, + "volume_30_day": 262, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-21-foobar", + "name": "misc-21-generated", + "query_usage_30_day": 64, + "volume_30_day": 275, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-22-foobar", + "name": "misc-22-generated", + "query_usage_30_day": 67, + "volume_30_day": 288, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-23-foobar", + "name": "misc-23-generated", + "query_usage_30_day": 70, + "volume_30_day": 301, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-24-foobar", + "name": "misc-24-generated", + "query_usage_30_day": 73, + "volume_30_day": 314, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-25-foobar", + "name": "misc-25-generated", + "query_usage_30_day": 76, + "volume_30_day": 327, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-26-foobar", + "name": "misc-26-generated", + "query_usage_30_day": 79, + "volume_30_day": 340, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-27-foobar", + "name": "misc-27-generated", + "query_usage_30_day": 82, + "volume_30_day": 353, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-28-foobar", + "name": "misc-28-generated", + "query_usage_30_day": 85, + "volume_30_day": 366, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-29-foobar", + "name": "misc-29-generated", + "query_usage_30_day": 88, + "volume_30_day": 379, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-30-foobar", + "name": "misc-30-generated", + "query_usage_30_day": 91, + "volume_30_day": 392, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-31-foobar", + "name": "misc-31-generated", + "query_usage_30_day": 94, + "volume_30_day": 405, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-32-foobar", + "name": "misc-32-generated", + "query_usage_30_day": 97, + "volume_30_day": 418, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-33-foobar", + "name": "misc-33-generated", + "query_usage_30_day": 100, + "volume_30_day": 431, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-34-foobar", + "name": "misc-34-generated", + "query_usage_30_day": 103, + "volume_30_day": 444, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-35-foobar", + "name": "misc-35-generated", + "query_usage_30_day": 106, + "volume_30_day": 457, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-36-foobar", + "name": "misc-36-generated", + "query_usage_30_day": 109, + "volume_30_day": 470, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-37-foobar", + "name": "misc-37-generated", + "query_usage_30_day": 112, + "volume_30_day": 483, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-38-foobar", + "name": "misc-38-generated", + "query_usage_30_day": 115, + "volume_30_day": 496, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-39-foobar", + "name": "misc-39-generated", + "query_usage_30_day": 118, + "volume_30_day": 509, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-40-foobar", + "name": "misc-40-generated", + "query_usage_30_day": 121, + "volume_30_day": 522, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-41-foobar", + "name": "misc-41-generated", + "query_usage_30_day": 124, + "volume_30_day": 535, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-42-foobar", + "name": "misc-42-generated", + "query_usage_30_day": 127, + "volume_30_day": 548, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-43-foobar", + "name": "misc-43-generated", + "query_usage_30_day": 130, + "volume_30_day": 561, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-44-foobar", + "name": "misc-44-generated", + "query_usage_30_day": 133, + "volume_30_day": 574, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-45-foobar", + "name": "misc-45-generated", + "query_usage_30_day": 136, + "volume_30_day": 587, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-46-foobar", + "name": "misc-46-generated", + "query_usage_30_day": 139, + "volume_30_day": 600, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-47-foobar", + "name": "misc-47-generated", + "query_usage_30_day": 142, + "volume_30_day": 613, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-48-foobar", + "name": "misc-48-generated", + "query_usage_30_day": 145, + "volume_30_day": 626, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-49-foobar", + "name": "misc-49-generated", + "query_usage_30_day": 148, + "volume_30_day": 639, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-50-foobar", + "name": "misc-50-generated", + "query_usage_30_day": 151, + "volume_30_day": 652, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-51-foobar", + "name": "misc-51-generated", + "query_usage_30_day": 154, + "volume_30_day": 665, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-52-foobar", + "name": "misc-52-generated", + "query_usage_30_day": 157, + "volume_30_day": 678, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-53-foobar", + "name": "misc-53-generated", + "query_usage_30_day": 160, + "volume_30_day": 691, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-54-foobar", + "name": "misc-54-generated", + "query_usage_30_day": 163, + "volume_30_day": 704, + }, + Object { + "description": "name generation is the best!", + "id": "uuid-55-foobar", + "name": "misc-55-generated", + "query_usage_30_day": 166, + "volume_30_day": 717, + }, + ], + "searchQuery": "", + "selectedItem": Object { + "description": "event1 is the best!", + "id": "uuid-0-foobar", + "name": "event1", + "query_usage_30_day": 1, + "volume_30_day": 2, + }, + "selectedItemInView": true, + "selectedItemValue": "event1", + "startIndex": 0, + "stopIndex": 0, + "totalCount": 56, + "value": undefined, +} +`; diff --git a/frontend/src/lib/components/TaxonomicFilter/infiniteListLogic.test.ts b/frontend/src/lib/components/TaxonomicFilter/infiniteListLogic.test.ts new file mode 100644 index 00000000000..01b7c8d9d18 --- /dev/null +++ b/frontend/src/lib/components/TaxonomicFilter/infiniteListLogic.test.ts @@ -0,0 +1,105 @@ +import { infiniteListLogic } from './infiniteListLogic' +import { BuiltLogic } from 'kea' +import { waitForAction } from 'kea-waitfor' +import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types' +import { infiniteListLogicType } from 'lib/components/TaxonomicFilter/infiniteListLogicType' +import { mockAPIGet } from 'lib/api.mock' +import { initKeaTestLogic } from '~/test/utils' +import { mockEventDefinitions } from '~/test/mocks' + +jest.mock('lib/api') + +describe('infiniteListLogic verbose version', () => { + let logic: BuiltLogic + + mockAPIGet(async ({ pathname, searchParams }) => { + if (pathname === 'api/projects/@current/event_definitions') { + const results = searchParams.search + ? mockEventDefinitions.filter((e) => e.name.includes(searchParams.search)) + : mockEventDefinitions + return { + results, + count: results.length, + } + } + }) + + initKeaTestLogic({ + logic: infiniteListLogic, + props: { + taxonomicFilterLogicKey: 'testList', + listGroupType: TaxonomicFilterGroupType.Events, + }, + waitFor: 'loadRemoteItemsSuccess', + onLogic: (l) => (logic = l), + }) + + describe('values', () => { + it('has proper defaults', () => { + expect(logic.values).toMatchSnapshot() + }) + }) + + describe('loaders', () => { + describe('remoteItems', () => { + it('loads initial items on mount', async () => { + expect(logic.values.remoteItems.results.length).toEqual(56) + }) + + it('setting search query filters events', async () => { + logic.actions.setSearchQuery('event') + expect(logic.values.searchQuery).toEqual('event') + + await waitForAction(logic.actions.loadRemoteItemsSuccess) + expect(logic.values.remoteItems.results.length).toEqual(3) + expect(logic.values.remoteItems).toMatchSnapshot() + }) + }) + }) + + describe('reducers', () => { + describe('index', () => { + it('is set via setIndex', async () => { + expect(logic.values.index).toEqual(0) + logic.actions.setIndex(1) + expect(logic.values.index).toEqual(1) + }) + + it('can go up and down', async () => { + expect(logic.values.remoteItems.results.length).toEqual(56) + + logic.actions.moveUp() + expect(logic.values.index).toEqual(55) + + logic.actions.moveUp() + expect(logic.values.index).toEqual(54) + + logic.actions.moveDown() + expect(logic.values.index).toEqual(55) + + logic.actions.moveDown() + expect(logic.values.index).toEqual(0) + + logic.actions.moveDown() + expect(logic.values.index).toEqual(1) + }) + }) + }) + + describe('actions', () => { + describe('selectSelected', () => { + it('actually selects the selected', async () => { + expect(logic.values.selectedItem).toEqual(expect.objectContaining({ name: 'event1' })) + + logic.actions.selectItem = jest.fn() + logic.actions.selectSelected() + + expect(logic.actions.selectItem).toHaveBeenCalledWith( + 'events', + 'event1', + expect.objectContaining({ name: 'event1' }) + ) + }) + }) + }) +}) diff --git a/frontend/src/lib/components/TaxonomicFilter/infiniteListLogic.ts b/frontend/src/lib/components/TaxonomicFilter/infiniteListLogic.ts index b62c4a61acd..bcd3f91531b 100644 --- a/frontend/src/lib/components/TaxonomicFilter/infiniteListLogic.ts +++ b/frontend/src/lib/components/TaxonomicFilter/infiniteListLogic.ts @@ -6,28 +6,10 @@ import { EventDefinitionStorage } from '~/models/eventDefinitionsModel' import { infiniteListLogicType } from './infiniteListLogicType' import { CohortType, EventDefinition } from '~/types' import Fuse from 'fuse.js' -import { InfiniteListLogicProps } from 'lib/components/TaxonomicFilter/types' +import { InfiniteListLogicProps, ListFuse, ListStorage, LoaderOptions } from 'lib/components/TaxonomicFilter/types' import { taxonomicFilterLogic } from 'lib/components/TaxonomicFilter/taxonomicFilterLogic' import { groups } from 'lib/components/TaxonomicFilter/groups' -interface ListStorage { - results: (EventDefinition | CohortType)[] - searchQuery?: string // Query used for the results currently in state - count: number - queryChanged?: boolean - first?: boolean -} - -interface LoaderOptions { - offset: number - limit: number -} - -type ListFuse = Fuse<{ - name: string - item: EventDefinition | CohortType -}> // local alias for typegen - function appendAtIndex(array: T[], items: any[], startIndex?: number): T[] { if (startIndex === undefined) { return [...array, ...items] @@ -51,7 +33,7 @@ const API_CACHE_TIMEOUT = 60000 const apiCache: Record = {} const apiCacheTimers: Record = {} -export const infiniteListLogic = kea>({ +export const infiniteListLogic = kea({ props: {} as InfiniteListLogicProps, key: (props) => `${props.taxonomicFilterLogicKey}-${props.listGroupType}`, @@ -235,7 +217,7 @@ export const infiniteListLogic = kea [s.index, s.items], (index, items) => (index >= 0 ? items.results[index] : undefined)], selectedItemValue: [ (s) => [s.selectedItem, s.group], - (selectedItem, group) => group?.getValue?.(selectedItem) || null, + (selectedItem, group) => (selectedItem ? group?.getValue?.(selectedItem) || null : null), ], selectedItemInView: [ (s) => [s.index, s.startIndex, s.stopIndex], diff --git a/frontend/src/lib/components/TaxonomicFilter/taxonomicFilterLogic.ts b/frontend/src/lib/components/TaxonomicFilter/taxonomicFilterLogic.ts index c46fd2d2e25..118794ce3e1 100644 --- a/frontend/src/lib/components/TaxonomicFilter/taxonomicFilterLogic.ts +++ b/frontend/src/lib/components/TaxonomicFilter/taxonomicFilterLogic.ts @@ -6,6 +6,7 @@ import { TaxonomicFilterValue, } from 'lib/components/TaxonomicFilter/types' import { infiniteListLogic } from 'lib/components/TaxonomicFilter/infiniteListLogic' +import { groups } from 'lib/components/TaxonomicFilter/groups' export const taxonomicFilterLogic = kea({ props: {} as TaxonomicFilterLogicProps, @@ -63,7 +64,7 @@ export const taxonomicFilterLogic = kea({ ], groupTypes: [ () => [(_, props) => props.groupTypes], - (groupTypes): TaxonomicFilterGroupType[] => groupTypes || [], + (groupTypes): TaxonomicFilterGroupType[] => groupTypes || groups.map((g) => g.type), ], value: [() => [(_, props) => props.value], (value) => value], groupType: [() => [(_, props) => props.groupType], (groupType) => groupType], diff --git a/frontend/src/lib/components/TaxonomicFilter/types.ts b/frontend/src/lib/components/TaxonomicFilter/types.ts index 6ade3a48450..32e62ab7118 100644 --- a/frontend/src/lib/components/TaxonomicFilter/types.ts +++ b/frontend/src/lib/components/TaxonomicFilter/types.ts @@ -1,4 +1,6 @@ import { LogicWrapper } from 'kea' +import { CohortType, EventDefinition } from '~/types' +import Fuse from 'fuse.js' export interface TaxonomicFilterProps { groupType?: TaxonomicFilterGroupType @@ -36,7 +38,24 @@ export enum TaxonomicFilterGroupType { PersonProperties = 'person_properties', } -export interface InfiniteListLogicProps { - taxonomicFilterLogicKey: string +export interface InfiniteListLogicProps extends TaxonomicFilterLogicProps { listGroupType: TaxonomicFilterGroupType } + +export interface ListStorage { + results: (EventDefinition | CohortType)[] + searchQuery?: string // Query used for the results currently in state + count: number + queryChanged?: boolean + first?: boolean +} + +export interface LoaderOptions { + offset: number + limit: number +} + +export type ListFuse = Fuse<{ + name: string + item: EventDefinition | CohortType +}> // local alias for typegen diff --git a/frontend/src/test/mocks.ts b/frontend/src/test/mocks.ts new file mode 100644 index 00000000000..dd57c494d65 --- /dev/null +++ b/frontend/src/test/mocks.ts @@ -0,0 +1,17 @@ +import { EventDefinition } from '~/types' + +export const mockEventDefinitions: EventDefinition[] = [ + 'event1', + 'test event', + '$click', + '$autocapture', + 'search', + 'other event', + ...Array(50), +].map((name, index) => ({ + id: `uuid-${index}-foobar`, + name: name || `misc-${index}-generated`, + description: `${name || 'name generation'} is the best!`, + query_usage_30_day: index * 3 + 1, + volume_30_day: index * 13 + 2, +})) diff --git a/frontend/src/test/utils.ts b/frontend/src/test/utils.ts new file mode 100644 index 00000000000..2a0b74a85c9 --- /dev/null +++ b/frontend/src/test/utils.ts @@ -0,0 +1,33 @@ +// Utilities for frontend logic tests +import { BuiltLogic, Logic, LogicWrapper } from 'kea' +import { initKea } from '~/initKea' +import { waitForAction } from 'kea-waitfor' + +export function initKeaTestLogic({ + logic, + props, + waitFor, + onLogic, +}: { + logic: LogicWrapper + props?: LogicWrapper['props'] + waitFor?: string + onLogic?: (l: BuiltLogic) => any +}): void { + let builtLogic: BuiltLogic + let unmount: () => void + + beforeEach(async () => { + initKea() + builtLogic = logic.build(props) + await onLogic?.(builtLogic) + unmount = builtLogic.mount() + if (waitFor) { + await waitForAction(builtLogic.actionTypes[waitFor]) + } + }) + + afterEach(() => { + unmount() + }) +} diff --git a/jest.config.ts b/jest.config.ts index 11005aa507a..0b9f0599437 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -130,7 +130,7 @@ export default { // runner: "jest-runner", // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], + setupFiles: ['../../jest.setup.ts'], // A list of paths to modules that run some code to configure or set up the testing framework before each test setupFilesAfterEnv: ['givens/setup'], diff --git a/jest.setup.ts b/jest.setup.ts new file mode 100644 index 00000000000..a9a4348b207 --- /dev/null +++ b/jest.setup.ts @@ -0,0 +1 @@ +import 'whatwg-fetch' diff --git a/package.json b/package.json index 191207e1882..80d168ca9cd 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "kea-loaders": "^0.4.0", "kea-localstorage": "^1.1.1", "kea-router": "^1.0.2", + "kea-waitfor": "^0.2.0", "kea-window-values": "^0.0.1", "md5": "^2.3.0", "posthog-js": "1.12.1", @@ -148,7 +149,8 @@ "typescript": "^4.3.2", "webpack": "^4.46.0", "webpack-cli": "^4.5.0", - "webpack-dev-server": "^3.11.2" + "webpack-dev-server": "^3.11.2", + "whatwg-fetch": "^3.6.2" }, "optionalDependencies": { "fsevents": "^2.1.2" diff --git a/yarn.lock b/yarn.lock index 968d54ae2af..eb294911d90 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7212,6 +7212,11 @@ kea-typegen@^1.1.5: prettier "^2.3.1" yargs "^16.2.0" +kea-waitfor@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/kea-waitfor/-/kea-waitfor-0.2.0.tgz#8de370a8160f9cfddf9897598deb1aaf3aa20f9e" + integrity sha512-lR+q/sw+OtURQuXsiHDHJXLMUv+hJLjTNoZeAZucO+JC1ul2VbbhqFQSD8VXea3bpAaK5BL4t/QucoY00IpXMQ== + kea-window-values@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/kea-window-values/-/kea-window-values-0.0.1.tgz#918eee6647507e2d3d5d19466b9561261e7bc8d7" @@ -11785,6 +11790,11 @@ whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" +whatwg-fetch@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" + integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== + whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"