Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[R20-1969] add skeletons to site search #1233

Merged
merged 10 commits into from
Jun 26, 2024
10 changes: 10 additions & 0 deletions examples/nuxt-app/test/features/maps/maps.feature
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ Feature: Custom collection map component
| method | status |
| GET | 200 |

@mockserver
Scenario: A loading screen is shown while the map loads
Given I load the page fixture with "/maps/basic-page"
And the page endpoint for path "/map" returns fixture "/maps/basic-page" with status 200
And the "/api/tide/elasticsearch/elasticsearch_index_develop_node/_search" network request is delayed by 500 milliseconds and stubbed with fixture "/site/search-response", status 200 and alias "searchReq"
Given I visit the page "/map"
Then the map loading screen should be displayed
When I wait 500 milliseconds
Then the map should be displayed

@mockserver
Scenario: Popup - 'popover' type
Given I load the page fixture with "/maps/basic-page"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Feature: Events collection
@mockserver
Example: Results formatting
Given the page endpoint for path "/events" returns fixture "/search-listing/events/page" with status 200
And the search network request is stubbed with fixture "/search-listing/events/response", status 200 and delayed by 400 milliseconds
And the search network request is stubbed with fixture "/search-listing/events/response" and status 200
When I visit the page "/events"
Then the search listing page should have 2 results
And the search listing layout should be "grid"
Expand Down
13 changes: 8 additions & 5 deletions examples/nuxt-app/test/features/search-listing/filters.feature
Original file line number Diff line number Diff line change
Expand Up @@ -389,8 +389,10 @@ Feature: Search listing - Filter
And the search network request is stubbed with fixture "/search-listing/filters/response" and status 200

When I visit the page "/"
And I type "The" into the search input
And I click the search button
And I toggle the search listing filters section
And I click the search listing dropdown field labelled "Terms filter example"
Then I click the option labelled "Purple" in the selected dropdown
And I submit the search filters
Then I should be scrolled to the search results

@mockserver
Expand All @@ -401,7 +403,8 @@ Feature: Search listing - Filter
Then the page endpoint for path "/" returns the loaded fixture

When I visit the page "/"
And I type "The" into the search input
And I click the search button

And I toggle the search listing filters section
And I click the search listing dropdown field labelled "Terms filter example"
Then I click the option labelled "Purple" in the selected dropdown
And I submit the search filters
Then I should not be scrolled to the search results
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Feature: Grants collection
@mockserver
Example: Results formatting
Given the page endpoint for path "/grants" returns fixture "/search-listing/grants/page" with status 200
And the search network request is stubbed with fixture "/search-listing/grants/response", status 200 and delayed by 400 milliseconds
And the search network request is stubbed with fixture "/search-listing/grants/response" and status 200
And the current date is "Fri, 02 Feb 2050 03:04:05 GMT"
When I visit the page "/grants"
Then the search listing page should have 3 results
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Feature: Result items
@mockserver
Example: Result item type can be set per result
Given the page endpoint for path "/search-results" returns fixture "/search-listing/result-items/page" with status 200
And the search network request is stubbed with fixture "/search-listing/result-items/response", status 200 and delayed by 400 milliseconds
And the search network request is stubbed with fixture "/search-listing/result-items/response" and status 200

When I visit the page "/search-results"
Then the search listing page should have 4 results
Expand Down
6 changes: 3 additions & 3 deletions examples/nuxt-app/test/features/search-listing/table.feature
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Feature: Table layout
@mockserver
Example: Table shows extra content using a custom component
Given the page endpoint for path "/search-listing-table-extra-components" returns fixture "/search-listing/table/page-extra-component" with status 200
And the search network request is stubbed with fixture "/search-listing/table/response", status 200 and delayed by 400 milliseconds
And the search network request is stubbed with fixture "/search-listing/table/response" and status 200
When I visit the page "/search-listing-table-extra-components"
And the search network request should be called with the "/search-listing/table/request" fixture
And the search listing layout should be "table"
Expand All @@ -48,7 +48,7 @@ Feature: Table layout
@mockserver
Example: Table shows extra structured content using object keys and components
Given the page endpoint for path "/search-listing-table-structured" returns fixture "/search-listing/table/page-extra-structured" with status 200
And the search network request is stubbed with fixture "/search-listing/table/response-elastic", status 200 and delayed by 400 milliseconds
And the search network request is stubbed with fixture "/search-listing/table/response-elastic" and status 200
When I visit the page "/search-listing-table-structured"
And the search network request should be called with the "/search-listing/table/request" fixture
And the search listing layout should be "table"
Expand All @@ -67,7 +67,7 @@ Feature: Table layout
@mockserver
Example: Table renders cells using core components
Given the page endpoint for path "/search-listing-table-structured" returns fixture "/search-listing/table/page-extra-structured" with status 200
And the search network request is stubbed with fixture "/search-listing/table/response-elastic", status 200 and delayed by 400 milliseconds
And the search network request is stubbed with fixture "/search-listing/table/response-elastic" and status 200
When I visit the page "/search-listing-table-structured"
And the search network request should be called with the "/search-listing/table/request" fixture

Expand Down
10 changes: 9 additions & 1 deletion examples/nuxt-app/test/features/site/search.feature
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@ Feature: Site search

@mockserver
Example: Display and manage site search results
Given the "/api/tide/search/**" network request is stubbed with fixture "/site/search-response" and status 200 as alias "siteSearchReq"
Given the "/api/tide/search/**" network request is delayed by 500 milliseconds and stubbed with fixture "/site/search-response", status 200 and alias "siteSearchReq"
When I visit the page "/search?q=demo"
Then the search listing skeleton should display 10 items with the class "tide-search-result-skeleton"

When I wait 500 milliseconds
Then the search listing page should have 5 results
And the filters toggle should show 0 applied filters
And the search input should have the value "demo"
And the search listing results count should read "Displaying 1-5 of 5 results"
And the search listing results should have following items:
| title | content | url | component |
| TAFE and training providers in Melbourne’s south-east | Explore local TAFE and training providers across Melbourne’s south-eastern region | /tafes-training-providers-melbourne-south-eastern-region | rpl-search-result |
| Time for a career change? | With TAFE, it's now easier than ever to learn new skills for your chosen career or retrain to get the job of your dreams | /career-change | rpl-search-result |

When I toggle the search listing filters section
And I click the search listing dropdown field labelled "Select a topic"
Expand Down
2 changes: 1 addition & 1 deletion examples/nuxt-app/test/fixtures/site/search-response.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"page": {
"current": 1,
"total_pages": 1,
"total_results": 4,
"total_results": 5,
"size": 10
},
"request_id": "3940dd8bb5a8a54484a2487ffb5fa272"
Expand Down
29 changes: 27 additions & 2 deletions packages/ripple-test-utils/step_definitions/common/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ Given(
(req) => {
if (req.body.size === 0) {
req.reply({
statusCode: status,
fixture: fixture
statusCode,
fixture
})
} else {
req.alias = 'searchReq'
Expand Down Expand Up @@ -209,6 +209,31 @@ Given(
})
}
)

Given(
'the {string} network request is delayed by {int} milliseconds and stubbed with fixture {string}, status {int} and alias {string}',
(
url: string,
delay: number,
fixture: string,
statusCode: number,
alias: string
) => {
cy.intercept('POST', url, (req) => {
if (req.body.size === 0) {
req.reply({})
} else {
req.alias = alias
req.reply({
statusCode,
fixture,
delay
})
}
})
}
)

Given(
'the {string} aggregation request is stubbed with fixture {string} and status {int} as alias {string}',
(url: string, fixture: string, status: number, alias: string) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ Then(`the map matches the image snapshot {string}`, (title) => {
})
})

Then(`the map loading screen should be displayed`, () => {
cy.get('.tide-search-listing-results-map-skeleton').should('be.visible')
})

Then(`the map should be displayed`, () => {
cy.get('.rpl-map').should('be.visible')
})

When(
`I click the map component at coordinates {int} {int}`,
(x: number, y: number) => {
Expand Down
12 changes: 10 additions & 2 deletions packages/ripple-tide-search/components/TideSearchListingPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -234,15 +234,23 @@ const handleSearchSubmit = (event: any) => {
} else {
// If there's no filters in the form, we need to just do the search without submitting the filter form
submitSearch()
scrollToResults(resultsContainer)
if (event?.type === 'button') {
scrollToResults(resultsContainer)
}
emitSearchEvent({ ...event, ...baseEvent() })
}
}

const handleFilterSubmit = (event: any) => {
filterForm.value = event.value
submitSearch()
scrollToResults(resultsContainer)

if (
!cachedSubmitEvent.value?.type ||
cachedSubmitEvent.value?.type === 'button'
) {
scrollToResults(resultsContainer)
}

emitSearchEvent({ ...event, ...cachedSubmitEvent.value, ...baseEvent() })

Expand Down
55 changes: 45 additions & 10 deletions packages/ripple-tide-search/components/TideSearchPage.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
import { getActiveFilterURL, useRuntimeConfig, useTideSite } from '#imports'
import {
getActiveFilterURL,
scrollToElementTopWithOffset,
useRuntimeConfig,
useTideSite
} from '#imports'
import useSearchUI from './../composables/useSearchUI'
import {
AppSearchFilterConfigItem,
Expand All @@ -17,12 +22,14 @@ interface Props {
filtersConfig: AppSearchFilterConfigItem[]
searchDriverOptions: Omit<SearchDriverOptions, 'apiConnector'>
searchResultsMappingFn: (item: any) => MappedSearchResult<any>
scrollToResults: boolean
}

const props = withDefaults(defineProps<Props>(), {
id: 'tide-search-page',
pageTitle: 'Search',
filtersConfig: () => [],
scrollToResults: true,
searchDriverOptions: () => ({
initialState: { resultsPerPage: 10 },
alwaysSearchOnInitialLoad: true,
Expand Down Expand Up @@ -100,6 +107,7 @@ const {
props.searchResultsMappingFn
)

const initialLoad = ref(true)
const filtersExpanded = ref(false)
const submitFiltersLabel = 'Apply search filters'

Expand Down Expand Up @@ -133,15 +141,29 @@ const emitSearchEvent = (event) => {
)
}

const scrollToResults = () => {
if (props.scrollToResults) {
const scrollToElement = document.querySelector('.rpl-layout__body-wrap')

if (scrollToElement) {
scrollToElementTopWithOffset(scrollToElement)
}
}
}

const handleSubmit = (event) => {
doSearch()

emitSearchEvent(event)

if (event?.type === 'button') {
scrollToResults()
}
}

const handleFilterSubmit = (event) => {
filterFormValues.value = event.data
doSearch()
scrollToResults()

emitSearchEvent({ ...event, text: submitFiltersLabel, type: 'button' })
}
Expand Down Expand Up @@ -201,6 +223,19 @@ const handlePagination = (event) => {
)
}

const displayResults = computed(() => {
if (loading.value) {
return Array(props.searchDriverOptions?.initialState?.resultsPerPage).fill({
id: 'skeleton',
component: 'TideSearchResultSkeleton'
})
}

return results.value?.length ? results.value : []
})

const loading = computed(() => initialLoad.value || searchState.value.isLoading)

watch(
() => searchState.value.isLoading,
(loading, prevLoading) => {
Expand All @@ -213,6 +248,8 @@ watch(
},
{ global: true }
)

initialLoad.value = false
}
}
)
Expand Down Expand Up @@ -291,12 +328,13 @@ watch(
</RplHeroHeader>
</template>
<template #body>
<RplPageComponent v-if="!searchState.error && searchState.totalResults">
<RplPageComponent v-if="!searchState.error">
<TideSearchResultsCount
v-if="!searchState.error && searchState.totalResults"
:pagingStart="searchState.pagingStart"
:pagingEnd="searchState.pagingEnd"
:totalResults="searchState.totalResults"
:results="results"
:loading="loading"
/>
</RplPageComponent>
<RplPageComponent>
Expand All @@ -305,22 +343,19 @@ watch(
<div
:class="{
'tide-search-results': true,
'tide-search-results--loading':
searchState.isLoading && !searchState.error
'tide-search-results--loading': loading && !searchState.error
}"
>
<TideSearchError v-if="searchState.error" />
<TideSearchNoResults
v-else-if="
searchComplete &&
!searchState.isLoading &&
!searchState.totalResults
searchComplete && !loading && !searchState.totalResults
"
:query="searchState.searchTerm"
/>
<RplResultListing v-else>
<RplResultListingItem
v-for="(result, idx) in results"
v-for="(result, idx) in displayResults"
:key="`result-${idx}-${result.id}`"
data-component-type="search-result"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ interface Props {
pagingStart: number
pagingEnd: number
totalResults: number
loading: boolean
loading?: boolean
results?: any[]
}

withDefaults(defineProps<Props>(), {
results: () => []
results: () => [],
loading: false
})
</script>
Loading
Loading