diff --git a/assets/src/api.ts b/assets/src/api.ts index 4a3fcd062..fb07efa5d 100644 --- a/assets/src/api.ts +++ b/assets/src/api.ts @@ -26,6 +26,11 @@ import { routePatternsFromData, } from "./models/routePatternData" import * as Sentry from "@sentry/react" +import { LocationSearchResult } from "./models/locationSearchResult" +import { + LocationSearchResultData, + locationSearchResultsFromData, +} from "./models/locationSearchResultData" export interface RouteData { id: string @@ -212,6 +217,16 @@ export const fetchSwings = (routeIds: RouteId[]): Promise => defaultResult: [], }) +export const fetchLocationSearchResults = ( + searchText: string +): Promise => + checkedApiCall({ + url: `api/location_search/search?query=${searchText}`, + dataStruct: array(LocationSearchResultData), + parser: nullableParser(locationSearchResultsFromData), + defaultResult: [], + }) + export const putNotificationReadState = ( newReadState: NotificationState, notificationIds: NotificationId[] diff --git a/assets/src/components/mapPage.tsx b/assets/src/components/mapPage.tsx index e3a904343..4f8b3abb7 100644 --- a/assets/src/components/mapPage.tsx +++ b/assets/src/components/mapPage.tsx @@ -39,6 +39,7 @@ import OldSearchForm from "./oldSearchForm" import inTestGroup, { TestGroups } from "../userInTestGroup" import { Socket } from "phoenix" import SearchResultsByProperty from "./mapPage/searchResultsByProperty" +import { LocationSearchResult } from "../models/locationSearchResult" const thereIsAnActiveSearch = ( vehicles: (Vehicle | Ghost)[] | null, @@ -69,18 +70,16 @@ const OldSearchResultList = ({ } const SearchMode = ({ - selectSearchResult, + onSelectVehicleResult, + onSelectLocationResult, }: { - selectSearchResult: (result: Vehicle | Ghost | null) => void + onSelectVehicleResult: (result: Vehicle | Ghost | null) => void + onSelectLocationResult: (result: LocationSearchResult | null) => void }): React.ReactElement => { const CurrentSearchForm = inTestGroup(TestGroups.LocationSearch) ? SearchFormFromStateDispatchContext : OldSearchForm - const CurrentSearchResults = inTestGroup(TestGroups.LocationSearch) - ? SearchResultsByProperty - : OldSearchResultList - const [{ searchPageState }] = useContext(StateDispatchContext) return ( <> @@ -98,7 +97,14 @@ const SearchMode = ({
{searchPageState.isActive ? ( - + inTestGroup(TestGroups.LocationSearch) ? ( + + ) : ( + + ) ) : ( )} @@ -221,12 +227,12 @@ const Selection = ({ vehicleId={selectedEntity.vehicleId} setSelection={setSelection} /> - ) : ( + ) : selectedEntity.type === SelectedEntityType.RoutePattern ? ( - )} + ) : null}
) } @@ -251,7 +257,7 @@ const MapPage = (): ReactElement => { ) // #endregion - const setSelection = useCallback( + const setVehicleSelection = useCallback( (selectedEntity: SelectedEntity | null) => { switch (selectedEntity?.type) { case SelectedEntityType.Vehicle: @@ -269,20 +275,35 @@ const MapPage = (): ReactElement => { [dispatch] ) - const selectSearchResult = useCallback( + const selectVehicleResult = useCallback( (vehicleOrGhost: Vehicle | Ghost | null) => { if (vehicleOrGhost) { - setSelection({ + setVehicleSelection({ type: SelectedEntityType.Vehicle, vehicleId: vehicleOrGhost.id, }) } else { - setSelection(null) + setVehicleSelection(null) } }, - [setSelection] + [setVehicleSelection] ) + const selectLocationResult = ( + location: LocationSearchResult | null + ): void => { + if (location) { + dispatch( + setSelectedEntity({ + type: SelectedEntityType.Location, + location, + }) + ) + } else { + dispatch(setSelectedEntity(null)) + } + } + return (
=> { {selectedEntity ? ( ) : ( - + )}
diff --git a/assets/src/components/mapPage/searchResultsByProperty.tsx b/assets/src/components/mapPage/searchResultsByProperty.tsx index 2f2269bf3..81cdf7109 100644 --- a/assets/src/components/mapPage/searchResultsByProperty.tsx +++ b/assets/src/components/mapPage/searchResultsByProperty.tsx @@ -11,18 +11,36 @@ import { setPropertyMatchLimit } from "../../state/searchPageState" import Loading from "../loading" import SearchResults from "../searchResults" import React from "react" +import { useLocationSearchResults } from "../../hooks/useLocationSearchResults" +import { Card, CardBody } from "../card" +import { LocationSearchResult } from "../../models/locationSearchResult" -const SearchResultSection = ({ +const SearchResultSection = (props: { + property: SearchProperty + text: string + limit: number + onSelectVehicle: (vehicle: Vehicle | Ghost) => void + onSelectLocation: (location: LocationSearchResult) => void + showMore: () => void +}) => { + if (props.property === "location") { + return + } else { + return + } +} + +const VehicleSearchResultSection = ({ property, text, limit, - selectVehicle, + onSelectVehicle, showMore, }: { property: SearchProperty text: string limit: number - selectVehicle: (vehicle: Vehicle | Ghost) => void + onSelectVehicle: (vehicle: Vehicle | Ghost) => void showMore: () => void }) => { const { socket } = useContext(SocketContext) @@ -54,7 +72,7 @@ const SearchResultSection = ({ {limitedSearchResults.hasMoreMatches && (
@@ -74,17 +92,85 @@ const SearchResultSection = ({ ) } +const LocationSearchResultSection = ({ + text, + limit, + onSelectLocation, + showMore, +}: { + text: string + limit: number + onSelectLocation: (location: LocationSearchResult) => void + showMore: () => void +}) => { + const locationSearchResults = useLocationSearchResults(text) + + return ( +
+

+ {searchPropertyDisplayConfig.location.name} +

+ {locationSearchResults === null ? ( + + ) : locationSearchResults.length > 0 ? ( + <> +
    + {locationSearchResults + .slice(0, limit) + .map((locationSearchResult) => ( +
  • + onSelectLocation(locationSearchResult)} + > + {locationSearchResult.name && + locationSearchResult.address && ( + {locationSearchResult.address} + )} + +
  • + ))} +
+ {locationSearchResults.length > limit && ( +
+ +
+ )} + + ) : ( + "No results found" + )} +
+ ) +} + const SearchResultsByProperty = ({ - selectSearchResult, + onSelectVehicleResult, + onSelectLocationResult, }: { - selectSearchResult: (result: Vehicle | Ghost | null) => void + onSelectVehicleResult: (result: Vehicle | Ghost | null) => void + onSelectLocationResult: (result: LocationSearchResult | null) => void }) => { const [{ searchPageState }, dispatch] = useContext(StateDispatchContext) return (
{Object.entries(searchPageState.query.properties) - .filter(([property, limit]) => limit != null && property != "location") + .filter(([, limit]) => limit != null) .map(([property, limit]) => ({ property: property as SearchProperty, limit: limit as number, @@ -100,7 +186,8 @@ const SearchResultsByProperty = ({ property={property} text={searchPageState.query.text} limit={limit} - selectVehicle={selectSearchResult} + onSelectVehicle={onSelectVehicleResult} + onSelectLocation={onSelectLocationResult} showMore={() => dispatch(setPropertyMatchLimit(property, limit + 25)) } diff --git a/assets/src/hooks/useLocationSearchResults.ts b/assets/src/hooks/useLocationSearchResults.ts new file mode 100644 index 000000000..db5396ca2 --- /dev/null +++ b/assets/src/hooks/useLocationSearchResults.ts @@ -0,0 +1,31 @@ +import { useEffect, useState } from "react" +import { fetchLocationSearchResults } from "../api" +import { LocationSearchResult } from "../models/locationSearchResult" + +export const useLocationSearchResults = ( + text: string | null +): LocationSearchResult[] | null => { + const [searchResults, setSearchResults] = useState< + LocationSearchResult[] | null + >(null) + + useEffect(() => { + let shouldUpdate = true + + if (text) { + fetchLocationSearchResults(text).then((results) => { + if (shouldUpdate) { + setSearchResults(results) + } + }) + } else { + setSearchResults(null) + } + + return () => { + shouldUpdate = false + } + }, [text]) + + return searchResults +} diff --git a/assets/src/models/locationSearchResult.ts b/assets/src/models/locationSearchResult.ts new file mode 100644 index 000000000..1e7b997ef --- /dev/null +++ b/assets/src/models/locationSearchResult.ts @@ -0,0 +1,7 @@ +export interface LocationSearchResult { + id: string + name: string | null + address: string + latitude: number + longitude: number +} diff --git a/assets/src/models/locationSearchResultData.ts b/assets/src/models/locationSearchResultData.ts new file mode 100644 index 000000000..912e467fc --- /dev/null +++ b/assets/src/models/locationSearchResultData.ts @@ -0,0 +1,30 @@ +import { Infer, nullable, number, string, type } from "superstruct" +import { LocationSearchResult } from "./locationSearchResult" + +export const LocationSearchResultData = type({ + id: string(), + name: nullable(string()), + address: string(), + latitude: number(), + longitude: number(), +}) +export type LocationSearchResultData = Infer + +export const locationSearchResultFromData = ({ + id, + name, + address, + latitude, + longitude, +}: LocationSearchResultData): LocationSearchResult => ({ + id, + name, + address, + latitude, + longitude, +}) + +export const locationSearchResultsFromData = ( + locationSearchResultsData: LocationSearchResultData[] +): LocationSearchResult[] => + locationSearchResultsData.map(locationSearchResultFromData) diff --git a/assets/src/state/searchPageState.ts b/assets/src/state/searchPageState.ts index ba3310ad1..f0008f054 100644 --- a/assets/src/state/searchPageState.ts +++ b/assets/src/state/searchPageState.ts @@ -1,4 +1,5 @@ import { Dispatch as ReactDispatch } from "react" +import { LocationSearchResult } from "../models/locationSearchResult" import { emptySearchQuery, isValidSearchQuery, @@ -14,6 +15,7 @@ import { RouteId, RoutePatternId } from "../schedule" export enum SelectedEntityType { Vehicle = 1, RoutePattern, + Location, } interface SelectedVehicleId { @@ -30,7 +32,15 @@ export interface SelectedRoutePattern extends RoutePatternIdentifier { type: SelectedEntityType.RoutePattern } -export type SelectedEntity = SelectedVehicleId | SelectedRoutePattern +export interface SelectedLocation { + type: SelectedEntityType.Location + location: LocationSearchResult +} + +export type SelectedEntity = + | SelectedVehicleId + | SelectedRoutePattern + | SelectedLocation export interface SearchPageState { query: SearchQuery diff --git a/assets/tests/api.test.ts b/assets/tests/api.test.ts index 67a7bbf4d..1720f9487 100644 --- a/assets/tests/api.test.ts +++ b/assets/tests/api.test.ts @@ -14,6 +14,7 @@ import { putRouteTabs, fetchStations, fetchRoutePatterns, + fetchLocationSearchResults, } from "../src/api" import routeFactory from "./factories/route" import routeTabFactory from "./factories/routeTab" @@ -22,6 +23,8 @@ import * as browser from "../src/models/browser" import { string, unknown } from "superstruct" import { LocationType } from "../src/models/stopData" import * as Sentry from "@sentry/react" +import locationSearchResultDataFactory from "./factories/locationSearchResultData" +import locationSearchResultFactory from "./factories/locationSearchResult" jest.mock("@sentry/react", () => ({ __esModule: true, @@ -734,6 +737,33 @@ describe("fetchSwings", () => { }) }) +describe("fetchLocationSearchResults", () => { + test("parses location search results", (done) => { + const result = locationSearchResultDataFactory.build({ + name: "Some Landmark", + address: "123 Test St", + latitude: 1, + longitude: 2, + }) + + mockFetch(200, { + data: [result], + }) + + fetchLocationSearchResults("query").then((results) => { + expect(results).toEqual([ + locationSearchResultFactory.build({ + name: "Some Landmark", + address: "123 Test St", + latitude: 1, + longitude: 2, + }), + ]) + done() + }) + }) +}) + describe("putUserSetting", () => { test("uses PUT and CSRF token", () => { mockFetch(200, "") diff --git a/assets/tests/components/mapPage/searchResultsByProperty.test.tsx b/assets/tests/components/mapPage/searchResultsByProperty.test.tsx index 295b5176c..2502dea33 100644 --- a/assets/tests/components/mapPage/searchResultsByProperty.test.tsx +++ b/assets/tests/components/mapPage/searchResultsByProperty.test.tsx @@ -3,17 +3,25 @@ import { render, screen, within } from "@testing-library/react" import "@testing-library/jest-dom" import SearchResultsByProperty from "../../../src/components/mapPage/searchResultsByProperty" import { useLimitedSearchResults } from "../../../src/hooks/useSearchResults" +import { useLocationSearchResults } from "../../../src/hooks/useLocationSearchResults" import vehicleFactory from "../../factories/vehicle" import { SearchProperty } from "../../../src/models/searchQuery" import { StateDispatchProvider } from "../../../src/contexts/stateDispatchContext" import stateFactory from "../../factories/applicationState" import { searchPageStateFactory } from "../../factories/searchPageState" +import locationSearchResultFactory from "../../factories/locationSearchResult" +import { LocationSearchResult } from "../../../src/models/locationSearchResult" jest.mock("../../../src/hooks/useSearchResults", () => ({ __esModule: true, useLimitedSearchResults: jest.fn(() => null), })) +jest.mock("../../../src/hooks/useLocationSearchResults", () => ({ + __esModule: true, + useLocationSearchResults: jest.fn(() => null), +})) + afterEach(() => { jest.resetAllMocks() }) @@ -50,6 +58,7 @@ describe("searchResultsByProperty", () => { } } ) + ;(useLocationSearchResults as jest.Mock).mockImplementation(() => []) render( { })} dispatch={jest.fn()} > - + ) expect( @@ -76,6 +88,7 @@ describe("searchResultsByProperty", () => { matchingVehicles: [vehicleMatch], hasMoreMatches: false, }) + ;(useLocationSearchResults as jest.Mock).mockImplementation(() => []) render( { })} dispatch={jest.fn()} > - + ) expect( @@ -131,6 +147,7 @@ describe("searchResultsByProperty", () => { } } ) + ;(useLocationSearchResults as jest.Mock).mockImplementation(() => []) render( { })} dispatch={jest.fn()} > - + ) - const [vehicles, operators, runs] = screen.getAllByRole("heading") + const [vehicles, operators, runs, locations] = + screen.getAllByRole("heading") expect(vehicles).toHaveTextContent("Vehicles") expect(operators).toHaveTextContent("Operators") expect(runs).toHaveTextContent("Runs") + expect(locations).toHaveTextContent("Locations") }) test("Lists the matching vehicles under the appropriate header", () => { @@ -178,6 +200,7 @@ describe("searchResultsByProperty", () => { } } ) + ;(useLocationSearchResults as jest.Mock).mockImplementation(() => []) render( { })} dispatch={jest.fn()} > - + ) const vehicles = screen.getByLabelText("Vehicles") @@ -208,11 +234,63 @@ describe("searchResultsByProperty", () => { ).toBeInTheDocument() }) + test("Lists the matching locations under the locations header", () => { + const locationMatch = locationSearchResultFactory.build() + ;(useLocationSearchResults as jest.Mock).mockImplementation(() => [ + locationMatch, + ]) + + render( + + + + ) + const locations = screen.getByLabelText("Locations") + expect( + within(locations).getByLabelText(locationMatch.name!) + ).toBeInTheDocument() + }) + + test("Shows loading indication for locations", () => { + ;(useLocationSearchResults as jest.Mock).mockImplementation(() => null) + + render( + + + + ) + const locations = screen.getByLabelText("Locations") + expect(locations).toHaveTextContent(/loading/i) + }) + test("For sections that have more matches, includes a 'Show more' button", () => { ;(useLimitedSearchResults as jest.Mock).mockReturnValue({ matchingVehicles: [vehicleMatch], hasMoreMatches: true, }) + ;(useLocationSearchResults as jest.Mock).mockImplementation(() => []) render( { })} dispatch={jest.fn()} > - + ) expect( @@ -237,4 +318,72 @@ describe("searchResultsByProperty", () => { }) ).toBeInTheDocument() }) + + test("When locations section has more matches, includes a 'Show more' button", () => { + const locations: LocationSearchResult[] = [] + + for (let i = 0; i <= 5; i++) { + locations.push(locationSearchResultFactory.build()) + } + + ;(useLocationSearchResults as jest.Mock).mockImplementation(() => locations) + + render( + + + + ) + expect( + within(screen.getByLabelText("Locations")).getByRole("button", { + name: "Show more", + }) + ).toBeInTheDocument() + }) + + test("When locations section does not have more matches, doesn't include a 'Show more' button", () => { + ;(useLocationSearchResults as jest.Mock).mockImplementation(() => [ + locationSearchResultFactory.build(), + ]) + + render( + + + + ) + expect( + within(screen.getByLabelText("Locations")).queryByRole("button", { + name: "Show more", + }) + ).not.toBeInTheDocument() + }) }) diff --git a/assets/tests/factories/locationSearchResult.ts b/assets/tests/factories/locationSearchResult.ts new file mode 100644 index 000000000..6cb835d1e --- /dev/null +++ b/assets/tests/factories/locationSearchResult.ts @@ -0,0 +1,14 @@ +import { Factory } from "fishery" +import { LocationSearchResult } from "../../src/models/locationSearchResult" + +const locationSearchResultFactory = Factory.define( + ({ sequence }) => ({ + id: `${sequence}`, + address: `${sequence} Test St`, + name: "Some Landmark", + latitude: 1, + longitude: 2, + }) +) + +export default locationSearchResultFactory diff --git a/assets/tests/factories/locationSearchResultData.ts b/assets/tests/factories/locationSearchResultData.ts new file mode 100644 index 000000000..7bcb253e2 --- /dev/null +++ b/assets/tests/factories/locationSearchResultData.ts @@ -0,0 +1,13 @@ +import { Factory } from "fishery" +import { LocationSearchResultData } from "../../src/models/locationSearchResultData" + +const locationSearchResultDataFactory = + Factory.define(({ sequence }) => ({ + id: `${sequence}`, + address: `${sequence} Test St`, + name: "Some Landmark", + latitude: 1, + longitude: 2, + })) + +export default locationSearchResultDataFactory diff --git a/assets/tests/hooks/useLocationSearchResults.test.ts b/assets/tests/hooks/useLocationSearchResults.test.ts new file mode 100644 index 000000000..698988e88 --- /dev/null +++ b/assets/tests/hooks/useLocationSearchResults.test.ts @@ -0,0 +1,51 @@ +import { useLocationSearchResults } from "../../src/hooks/useLocationSearchResults" +import { renderHook } from "@testing-library/react" +import * as Api from "../../src/api" +import { instantPromise } from "../testHelpers/mockHelpers" +import locationSearchResultFactory from "../factories/locationSearchResult" + +jest.mock("../../src/api", () => ({ + __esModule: true, + + fetchLocationSearchResults: jest.fn(() => new Promise(() => {})), +})) + +describe("useLocationSearchResults", () => { + test("returns null if no search query is given", () => { + const mockFetchLocationSearchResults: jest.Mock = + Api.fetchLocationSearchResults as jest.Mock + + const { result } = renderHook(() => useLocationSearchResults(null)) + + expect(result.current).toBeNull() + expect(mockFetchLocationSearchResults).not.toHaveBeenCalled() + }) + + test("returns null while loading", () => { + const mockFetchLocationSearchResults: jest.Mock = + Api.fetchLocationSearchResults as jest.Mock + + const { result } = renderHook(() => + useLocationSearchResults("search string") + ) + + expect(result.current).toBeNull() + expect(mockFetchLocationSearchResults).toHaveBeenCalled() + }) + + test("returns results", () => { + const results = [locationSearchResultFactory.build()] + const mockFetchLocationSearchResults: jest.Mock = + Api.fetchLocationSearchResults as jest.Mock + mockFetchLocationSearchResults.mockImplementationOnce(() => + instantPromise(results) + ) + + const { result } = renderHook(() => + useLocationSearchResults("search string") + ) + + expect(result.current).toEqual(results) + expect(mockFetchLocationSearchResults).toHaveBeenCalled() + }) +}) diff --git a/assets/tests/models/locationSearchResultData.test.ts b/assets/tests/models/locationSearchResultData.test.ts new file mode 100644 index 000000000..3d0e0ef57 --- /dev/null +++ b/assets/tests/models/locationSearchResultData.test.ts @@ -0,0 +1,48 @@ +import { + locationSearchResultFromData, + locationSearchResultsFromData, +} from "../../src/models/locationSearchResultData" +import locationSearchResultFactory from "../factories/locationSearchResult" +import locationSearchResultDataFactory from "../factories/locationSearchResultData" + +describe("locationSearchResultFromData", () => { + test("passes supplied data through", () => { + const data = locationSearchResultDataFactory.build({ + name: "Some Landmark", + address: "123 Test St", + latitude: 1, + longitude: 2, + }) + + expect(locationSearchResultFromData(data)).toEqual( + locationSearchResultFactory.build({ + name: "Some Landmark", + address: "123 Test St", + latitude: 1, + longitude: 2, + }) + ) + }) +}) + +describe("locationSearchResultsFromData", () => { + test("passes supplied data through", () => { + const data = [ + locationSearchResultDataFactory.build({ + name: "Some Landmark", + address: "123 Test St", + latitude: 1, + longitude: 2, + }), + ] + + expect(locationSearchResultsFromData(data)).toEqual([ + locationSearchResultFactory.build({ + name: "Some Landmark", + address: "123 Test St", + latitude: 1, + longitude: 2, + }), + ]) + }) +}) diff --git a/assets/tests/state/searchPageState.test.ts b/assets/tests/state/searchPageState.test.ts index 48a8a7e50..9cbaa3f34 100644 --- a/assets/tests/state/searchPageState.test.ts +++ b/assets/tests/state/searchPageState.test.ts @@ -18,6 +18,7 @@ import { setPropertyMatchLimit, setSearchProperties, } from "../../src/state/searchPageState" +import locationSearchResultFactory from "../factories/locationSearchResult" import { searchPageStateFactory } from "../factories/searchPageState" import { emptySearchQueryFactory, @@ -263,6 +264,26 @@ describe("reducer", () => { }) }) + test("can set to location", () => { + const initialState: SearchPageState = { + ...initialSearchPageState, + } + + const location = locationSearchResultFactory.build() + + const updatedState = reducer( + initialState, + setSelectedEntity({ + type: SelectedEntityType.Location, + location, + }) + ) + expect(updatedState.selectedEntity).toEqual({ + type: SelectedEntityType.Location, + location, + }) + }) + test("when there isn't already a selectedEntity, setting a new one doesn't change the history", () => { const initialState = searchPageStateFactory.build() diff --git a/lib/skate/location_search/aws_location_request.ex b/lib/skate/location_search/aws_location_request.ex index 7a40c6ea5..d1f87ea97 100644 --- a/lib/skate/location_search/aws_location_request.ex +++ b/lib/skate/location_search/aws_location_request.ex @@ -15,7 +15,7 @@ defmodule Skate.LocationSearch.AwsLocationRequest do service: :places } |> request_fn.() do - {:ok, response} -> parse_search_response(response) + {:ok, response} -> {:ok, parse_search_response(response)} {:error, error} -> {:error, error} end end @@ -35,7 +35,7 @@ defmodule Skate.LocationSearch.AwsLocationRequest do service: :places } |> request_fn.() do - {:ok, response} -> parse_suggest_response(response) + {:ok, response} -> {:ok, parse_suggest_response(response)} {:error, error} -> {:error, error} end end diff --git a/test/skate/location_search/aws_location_request_test.exs b/test/skate/location_search/aws_location_request_test.exs index 456f77303..303aff2fe 100644 --- a/test/skate/location_search/aws_location_request_test.exs +++ b/test/skate/location_search/aws_location_request_test.exs @@ -41,7 +41,7 @@ defmodule Skate.LocationSearch.AwsLocationRequestTest do expected_address = "#{address_number} #{street}, #{address_suffix}" - assert [%SearchResult{name: ^name, address: ^expected_address}] = + assert {:ok, [%SearchResult{name: ^name, address: ^expected_address}]} = AwsLocationRequest.search("search text") end @@ -73,7 +73,7 @@ defmodule Skate.LocationSearch.AwsLocationRequestTest do expected_address = "#{address_number} #{street}, #{address_suffix}" - assert [%SearchResult{name: nil, address: ^expected_address}] = + assert {:ok, [%SearchResult{name: nil, address: ^expected_address}]} = AwsLocationRequest.search("search text") end @@ -101,7 +101,7 @@ defmodule Skate.LocationSearch.AwsLocationRequestTest do {:ok, response} end) - assert [%SearchResult{name: nil, address: ^address_suffix}] = + assert {:ok, [%SearchResult{name: nil, address: ^address_suffix}]} = AwsLocationRequest.search("search text") end @@ -133,7 +133,7 @@ defmodule Skate.LocationSearch.AwsLocationRequestTest do {:ok, response} end) - assert ["some place"] = AwsLocationRequest.suggest("text") + assert {:ok, ["some place"]} = AwsLocationRequest.suggest("text") end test "returns errors" do