11import fetchMock from 'fetch-mock-jest' ;
2+ import { cloneDeep } from 'lodash' ;
23import {
34 fireEvent ,
45 initializeMocks ,
@@ -8,41 +9,29 @@ import {
89 within ,
910} from '../../testUtils' ;
1011import mockResult from '../__mocks__/collection-search.json' ;
11- import mockEmptyResult from '../../search-modal/__mocks__/empty-search-result.json' ;
1212import {
13- mockCollection , mockContentLibrary , mockLibraryBlockTypes , mockXBlockFields ,
13+ mockContentLibrary , mockLibraryBlockTypes , mockXBlockFields ,
1414} from '../data/api.mocks' ;
1515import { mockContentSearchConfig } from '../../search-manager/data/api.mock' ;
1616import { mockBroadcastChannel } from '../../generic/data/api.mock' ;
1717import { LibraryLayout } from '..' ;
1818
1919mockContentSearchConfig . applyMock ( ) ;
2020mockContentLibrary . applyMock ( ) ;
21- mockCollection . applyMock ( ) ;
2221mockLibraryBlockTypes . applyMock ( ) ;
2322mockXBlockFields . applyMock ( ) ;
2423mockBroadcastChannel ( ) ;
2524
2625const searchEndpoint = 'http://mock.meilisearch.local/multi-search' ;
27-
28- /**
29- * Returns 0 components from the search query.
30- */
31- const returnEmptyResult = ( _url , req ) => {
32- const requestData = JSON . parse ( req . body ?. toString ( ) ?? '' ) ;
33- const query = requestData ?. queries [ 0 ] ?. q ?? '' ;
34- // We have to replace the query (search keywords) in the mock results with the actual query,
35- // because otherwise we may have an inconsistent state that causes more queries and unexpected results.
36- mockEmptyResult . results [ 0 ] . query = query ;
37- // And fake the required '_formatted' fields; it contains the highlighting <mark>...</mark> around matched words
38- // eslint-disable-next-line no-underscore-dangle, no-param-reassign
39- mockEmptyResult . results [ 0 ] ?. hits . forEach ( ( hit ) => { hit . _formatted = { ...hit } ; } ) ;
40- return mockEmptyResult ;
41- } ;
42-
4326const path = '/library/:libraryId/*' ;
4427const libraryTitle = mockContentLibrary . libraryData . title ;
45- const collectionTitle = mockCollection . collectionData . title ;
28+ const mockCollection = {
29+ collectionId : mockResult . results [ 2 ] . hits [ 0 ] . block_id ,
30+ collectionNeverLoads : 'collection-always-loading' ,
31+ collectionEmpty : 'collection-no-data' ,
32+ collectionNoComponents : 'collection-no-components' ,
33+ title : mockResult . results [ 2 ] . hits [ 0 ] . display_name ,
34+ } ;
4635
4736describe ( '<LibraryCollectionPage />' , ( ) => {
4837 beforeEach ( ( ) => {
@@ -52,14 +41,33 @@ describe('<LibraryCollectionPage />', () => {
5241 fetchMock . post ( searchEndpoint , ( _url , req ) => {
5342 const requestData = JSON . parse ( req . body ?. toString ( ) ?? '' ) ;
5443 const query = requestData ?. queries [ 0 ] ?. q ?? '' ;
44+ const mockResultCopy = cloneDeep ( mockResult ) ;
5545 // We have to replace the query (search keywords) in the mock results with the actual query,
5646 // because otherwise Instantsearch will update the UI and change the query,
5747 // leading to unexpected results in the test cases.
58- mockResult . results [ 0 ] . query = query ;
48+ mockResultCopy . results [ 0 ] . query = query ;
49+ mockResultCopy . results [ 2 ] . query = query ;
5950 // And fake the required '_formatted' fields; it contains the highlighting <mark>...</mark> around matched words
6051 // eslint-disable-next-line no-underscore-dangle, no-param-reassign
61- mockResult . results [ 0 ] ?. hits . forEach ( ( hit ) => { hit . _formatted = { ...hit } ; } ) ;
62- return mockResult ;
52+ mockResultCopy . results [ 0 ] ?. hits . forEach ( ( hit ) => { hit . _formatted = { ...hit } ; } ) ;
53+ const collectionQueryId = requestData ?. queries [ 2 ] ?. filter [ 2 ] ?. split ( 'block_id = "' ) [ 1 ] . split ( '"' ) [ 0 ] ;
54+ switch ( collectionQueryId ) {
55+ case mockCollection . collectionNeverLoads :
56+ return new Promise < any > ( ( ) => { } ) ;
57+ case mockCollection . collectionEmpty :
58+ mockResultCopy . results [ 2 ] . hits = [ ] ;
59+ mockResultCopy . results [ 2 ] . estimatedTotalHits = 0 ;
60+ break ;
61+ case mockCollection . collectionNoComponents :
62+ mockResultCopy . results [ 0 ] . hits = [ ] ;
63+ mockResultCopy . results [ 0 ] . estimatedTotalHits = 0 ;
64+ mockResultCopy . results [ 1 ] . facetDistribution . block_type = { } ;
65+ mockResultCopy . results [ 2 ] . hits [ 0 ] . num_children = 0 ;
66+ break ;
67+ default :
68+ break ;
69+ }
70+ return mockResultCopy ;
6371 } ) ;
6472 } ) ;
6573
@@ -69,34 +77,39 @@ describe('<LibraryCollectionPage />', () => {
6977 } ) ;
7078
7179 const renderLibraryCollectionPage = async ( collectionId ?: string , libraryId ?: string ) => {
72- const libId = libraryId || mockCollection . libraryId ;
80+ const libId = libraryId || mockContentLibrary . libraryId ;
7381 const colId = collectionId || mockCollection . collectionId ;
7482 render ( < LibraryLayout /> , {
7583 path,
7684 routerProps : {
7785 initialEntries : [ `/library/${ libId } /collection/${ colId } ` ] ,
7886 } ,
7987 } ) ;
88+
89+ if ( colId !== mockCollection . collectionNeverLoads ) {
90+ await waitFor ( ( ) => { expect ( fetchMock ) . toHaveFetchedTimes ( 1 , searchEndpoint , 'post' ) ; } ) ;
91+ }
8092 } ;
8193
8294 it ( 'shows the spinner before the query is complete' , async ( ) => {
8395 // This mock will never return data about the collection (it loads forever):
84- await renderLibraryCollectionPage ( mockCollection . collectionIdThatNeverLoads ) ;
96+ await renderLibraryCollectionPage ( mockCollection . collectionNeverLoads ) ;
8597 const spinner = screen . getByRole ( 'status' ) ;
8698 expect ( spinner . textContent ) . toEqual ( 'Loading...' ) ;
8799 } ) ;
88100
89101 it ( 'shows an error component if no collection returned' , async ( ) => {
90- // This mock will simulate a 404 error:
91- await renderLibraryCollectionPage ( mockCollection . collection404 ) ;
102+ // This mock will simulate incorrect collection id
103+ await renderLibraryCollectionPage ( mockCollection . collectionEmpty ) ;
104+ screen . debug ( ) ;
92105 expect ( await screen . findByTestId ( 'notFoundAlert' ) ) . toBeInTheDocument ( ) ;
93106 } ) ;
94107
95108 it ( 'shows collection data' , async ( ) => {
96109 await renderLibraryCollectionPage ( ) ;
97110 expect ( await screen . findByText ( 'All Collections' ) ) . toBeInTheDocument ( ) ;
98111 expect ( ( await screen . findAllByText ( libraryTitle ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
99- expect ( ( await screen . findAllByText ( collectionTitle ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
112+ expect ( ( await screen . findAllByText ( mockCollection . title ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
100113
101114 expect ( screen . queryByText ( 'This collection is currently empty.' ) ) . not . toBeInTheDocument ( ) ;
102115
@@ -108,12 +121,11 @@ describe('<LibraryCollectionPage />', () => {
108121 } ) ;
109122
110123 it ( 'shows a collection without associated components' , async ( ) => {
111- fetchMock . post ( searchEndpoint , returnEmptyResult , { overwriteRoutes : true } ) ;
112- await renderLibraryCollectionPage ( ) ;
124+ await renderLibraryCollectionPage ( mockCollection . collectionNoComponents ) ;
113125
114126 expect ( await screen . findByText ( 'All Collections' ) ) . toBeInTheDocument ( ) ;
115127 expect ( ( await screen . findAllByText ( libraryTitle ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
116- expect ( ( await screen . findAllByText ( collectionTitle ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
128+ expect ( ( await screen . findAllByText ( mockCollection . title ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
117129
118130 expect ( screen . getByText ( 'This collection is currently empty.' ) ) . toBeInTheDocument ( ) ;
119131
@@ -125,7 +137,7 @@ describe('<LibraryCollectionPage />', () => {
125137 it ( 'shows the new content button' , async ( ) => {
126138 await renderLibraryCollectionPage ( ) ;
127139
128- expect ( await screen . findByRole ( 'heading ') ) . toBeInTheDocument ( ) ;
140+ expect ( await screen . findByText ( 'All Collections ') ) . toBeInTheDocument ( ) ;
129141 expect ( await screen . findByText ( 'Content (5)' ) ) . toBeInTheDocument ( ) ;
130142 expect ( screen . getByRole ( 'button' , { name : / n e w / i } ) ) . toBeInTheDocument ( ) ;
131143 expect ( screen . queryByText ( 'Read Only' ) ) . not . toBeInTheDocument ( ) ;
@@ -135,9 +147,7 @@ describe('<LibraryCollectionPage />', () => {
135147 // Use a library mock that is read-only:
136148 const libraryId = mockContentLibrary . libraryIdReadOnly ;
137149 // Update search mock so it returns no results:
138- fetchMock . post ( searchEndpoint , returnEmptyResult , { overwriteRoutes : true } ) ;
139- await renderLibraryCollectionPage ( mockCollection . collectionId , libraryId ) ;
140- await waitFor ( ( ) => { expect ( fetchMock ) . toHaveFetchedTimes ( 1 , searchEndpoint , 'post' ) ; } ) ;
150+ await renderLibraryCollectionPage ( mockCollection . collectionNoComponents , libraryId ) ;
141151
142152 expect ( await screen . findByText ( 'All Collections' ) ) . toBeInTheDocument ( ) ;
143153 expect ( screen . getByText ( 'This collection is currently empty.' ) ) . toBeInTheDocument ( ) ;
@@ -147,27 +157,23 @@ describe('<LibraryCollectionPage />', () => {
147157
148158 it ( 'show a collection without search results' , async ( ) => {
149159 // Update search mock so it returns no results:
150- fetchMock . post ( searchEndpoint , returnEmptyResult , { overwriteRoutes : true } ) ;
151- await renderLibraryCollectionPage ( ) ;
160+ await renderLibraryCollectionPage ( mockCollection . collectionNoComponents ) ;
152161
153162 expect ( await screen . findByText ( 'All Collections' ) ) . toBeInTheDocument ( ) ;
154163 expect ( ( await screen . findAllByText ( libraryTitle ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
155- expect ( ( await screen . findAllByText ( collectionTitle ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
156-
157- await waitFor ( ( ) => { expect ( fetchMock ) . toHaveFetchedTimes ( 1 , searchEndpoint , 'post' ) ; } ) ;
164+ expect ( ( await screen . findAllByText ( mockCollection . title ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
158165
159166 fireEvent . change ( screen . getByRole ( 'searchbox' ) , { target : { value : 'noresults' } } ) ;
160167
161168 // Ensure the search endpoint is called again, only once more since the recently modified call
162169 // should not be impacted by the search
163170 await waitFor ( ( ) => { expect ( fetchMock ) . toHaveFetchedTimes ( 2 , searchEndpoint , 'post' ) ; } ) ;
164171
165- expect ( screen . getByText ( 'No matching components found in this collections.' ) ) . toBeInTheDocument ( ) ;
172+ expect ( screen . queryByText ( 'No matching components found in this collections.' ) ) . toBeInTheDocument ( ) ;
166173 } ) ;
167174
168175 it ( 'should open and close new content sidebar' , async ( ) => {
169176 await renderLibraryCollectionPage ( ) ;
170- await waitFor ( ( ) => { expect ( fetchMock ) . toHaveFetchedTimes ( 1 , searchEndpoint , 'post' ) ; } ) ;
171177
172178 expect ( await screen . findByText ( 'All Collections' ) ) . toBeInTheDocument ( ) ;
173179 expect ( screen . queryByText ( / a d d c o n t e n t / i) ) . not . toBeInTheDocument ( ) ;
@@ -188,8 +194,8 @@ describe('<LibraryCollectionPage />', () => {
188194
189195 expect ( await screen . findByText ( 'All Collections' ) ) . toBeInTheDocument ( ) ;
190196 expect ( ( await screen . findAllByText ( libraryTitle ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
191- expect ( ( await screen . findAllByText ( collectionTitle ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
192- expect ( ( await screen . findAllByText ( collectionTitle ) ) [ 1 ] ) . toBeInTheDocument ( ) ;
197+ expect ( ( await screen . findAllByText ( mockCollection . title ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
198+ expect ( ( await screen . findAllByText ( mockCollection . title ) ) [ 1 ] ) . toBeInTheDocument ( ) ;
193199
194200 expect ( screen . getByText ( 'Manage' ) ) . toBeInTheDocument ( ) ;
195201 expect ( screen . getByText ( 'Details' ) ) . toBeInTheDocument ( ) ;
@@ -200,8 +206,8 @@ describe('<LibraryCollectionPage />', () => {
200206
201207 expect ( await screen . findByText ( 'All Collections' ) ) . toBeInTheDocument ( ) ;
202208 expect ( ( await screen . findAllByText ( libraryTitle ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
203- expect ( ( await screen . findAllByText ( collectionTitle ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
204- expect ( ( await screen . findAllByText ( collectionTitle ) ) [ 1 ] ) . toBeInTheDocument ( ) ;
209+ expect ( ( await screen . findAllByText ( mockCollection . title ) ) [ 0 ] ) . toBeInTheDocument ( ) ;
210+ expect ( ( await screen . findAllByText ( mockCollection . title ) ) [ 1 ] ) . toBeInTheDocument ( ) ;
205211
206212 // Open by default; close the library info sidebar
207213 const closeButton = screen . getByRole ( 'button' , { name : / c l o s e / i } ) ;
@@ -218,7 +224,6 @@ describe('<LibraryCollectionPage />', () => {
218224
219225 it ( 'sorts collection components' , async ( ) => {
220226 await renderLibraryCollectionPage ( ) ;
221- await waitFor ( ( ) => { expect ( fetchMock ) . toHaveFetchedTimes ( 1 , searchEndpoint , 'post' ) ; } ) ;
222227
223228 expect ( await screen . findByTitle ( 'Sort search results' ) ) . toBeInTheDocument ( ) ;
224229
@@ -310,9 +315,7 @@ describe('<LibraryCollectionPage />', () => {
310315 } ) ;
311316
312317 it ( 'has an empty type filter when there are no results' , async ( ) => {
313- fetchMock . post ( searchEndpoint , returnEmptyResult , { overwriteRoutes : true } ) ;
314- await renderLibraryCollectionPage ( ) ;
315- await waitFor ( ( ) => { expect ( fetchMock ) . toHaveFetchedTimes ( 1 , searchEndpoint , 'post' ) ; } ) ;
318+ await renderLibraryCollectionPage ( mockCollection . collectionNoComponents ) ;
316319
317320 const filterButton = screen . getByRole ( 'button' , { name : / t y p e / i } ) ;
318321 fireEvent . click ( filterButton ) ;
0 commit comments