@@ -52,30 +52,30 @@ describe('PodcastService', () => {
5252 } ) ;
5353
5454 describe ( 'searchPodcasts' , ( ) => {
55- it ( 'should search podcasts using Castos API' , async ( ) => {
56- const mockCastosResponse = {
57- success : true ,
58- data : [
55+ it ( 'should search podcasts using the iTunes Search API' , async ( ) => {
56+ const mockItunesResponse = {
57+ resultCount : 2 ,
58+ results : [
5959 {
60- title : 'Test Podcast' ,
61- author : 'Test Author' ,
62- description : 'A test podcast description ' ,
63- image : 'https://example.com/image.jpg ' ,
64- url : 'https://example. com/feed.xml ' ,
60+ collectionName : 'Test Podcast' ,
61+ artistName : 'Test Author' ,
62+ artworkUrl600 : 'https://example.com/image.jpg ' ,
63+ feedUrl : 'https://example.com/feed.xml ' ,
64+ collectionViewUrl : 'https://podcasts.apple. com/test ' ,
6565 } ,
6666 {
67- title : 'Another Podcast' ,
68- author : 'Another Author' ,
69- description : 'Another description ' ,
70- image : 'https://example.com/image2.jpg ' ,
71- url : 'https://example. com/feed2.xml ' ,
67+ collectionName : 'Another Podcast' ,
68+ artistName : 'Another Author' ,
69+ artworkUrl600 : 'https://example.com/image2.jpg ' ,
70+ feedUrl : 'https://example.com/feed2.xml ' ,
71+ collectionViewUrl : 'https://podcasts.apple. com/another ' ,
7272 } ,
7373 ] ,
7474 } ;
7575
7676 mockFetch . mockResolvedValueOnce ( {
7777 ok : true ,
78- json : ( ) => Promise . resolve ( mockCastosResponse ) ,
78+ json : ( ) => Promise . resolve ( mockItunesResponse ) ,
7979 } ) ;
8080
8181 const results = await service . searchPodcasts ( 'test' ) ;
@@ -84,17 +84,16 @@ describe('PodcastService', () => {
8484 expect ( results [ 0 ] ) . toEqual ( {
8585 title : 'Test Podcast' ,
8686 author : 'Test Author' ,
87- description : 'A test podcast description' ,
87+ description : null ,
8888 imageUrl : 'https://example.com/image.jpg' ,
8989 feedUrl : 'https://example.com/feed.xml' ,
90- websiteUrl : null ,
90+ websiteUrl : 'https://podcasts.apple.com/test' ,
9191 } ) ;
92- expect ( mockFetch ) . toHaveBeenCalledWith (
93- 'https://castos.com/wp-admin/admin-ajax.php' ,
94- expect . objectContaining ( {
95- method : 'POST' ,
96- } )
97- ) ;
92+ const [ calledUrl , calledOptions ] = mockFetch . mock . calls [ 0 ] ;
93+ expect ( calledUrl ) . toContain ( 'https://itunes.apple.com/search' ) ;
94+ expect ( calledUrl ) . toContain ( 'media=podcast' ) ;
95+ expect ( calledUrl ) . toContain ( 'term=test' ) ;
96+ expect ( calledOptions ) . toMatchObject ( { method : 'GET' } ) ;
9897 } ) ;
9998
10099 it ( 'should return empty array when search fails' , async ( ) => {
@@ -111,7 +110,7 @@ describe('PodcastService', () => {
111110 it ( 'should handle empty search results' , async ( ) => {
112111 mockFetch . mockResolvedValueOnce ( {
113112 ok : true ,
114- json : ( ) => Promise . resolve ( { success : true , data : [ ] } ) ,
113+ json : ( ) => Promise . resolve ( { resultCount : 0 , results : [ ] } ) ,
115114 } ) ;
116115
117116 const results = await service . searchPodcasts ( 'nonexistent' ) ;
@@ -122,46 +121,46 @@ describe('PodcastService', () => {
122121 it ( 'should sanitize search query' , async ( ) => {
123122 mockFetch . mockResolvedValueOnce ( {
124123 ok : true ,
125- json : ( ) => Promise . resolve ( { success : true , data : [ ] } ) ,
124+ json : ( ) => Promise . resolve ( { resultCount : 0 , results : [ ] } ) ,
126125 } ) ;
127126
128127 await service . searchPodcasts ( 'test <script>alert("xss")</script>' ) ;
129128
130- // Verify the FormData was created with sanitized input
131- expect ( mockFetch ) . toHaveBeenCalled ( ) ;
129+ // The query is sanitized (script tags/special chars stripped) before being
130+ // placed in the request URL.
131+ const [ calledUrl ] = mockFetch . mock . calls [ 0 ] ;
132+ expect ( calledUrl ) . not . toContain ( 'script' ) ;
133+ expect ( calledUrl ) . not . toContain ( '%3C' ) ; // no encoded '<'
132134 } ) ;
133135
134- it ( 'should filter out results without url' , async ( ) => {
135- const mockCastosResponse = {
136- success : true ,
137- data : [
136+ it ( 'should filter out results without a feed url' , async ( ) => {
137+ const mockItunesResponse = {
138+ resultCount : 3 ,
139+ results : [
138140 {
139- title : 'Valid Podcast' ,
140- author : 'Author' ,
141- description : 'Description' ,
142- image : 'https://example.com/image.jpg' ,
143- url : 'https://example.com/feed.xml' ,
141+ collectionName : 'Valid Podcast' ,
142+ artistName : 'Author' ,
143+ artworkUrl600 : 'https://example.com/image.jpg' ,
144+ feedUrl : 'https://example.com/feed.xml' ,
144145 } ,
145146 {
146- title : 'Invalid Podcast - No URL' ,
147- author : 'Author' ,
148- description : 'Description' ,
149- image : 'https://example.com/image2.jpg' ,
150- // Missing url
147+ collectionName : 'Invalid Podcast - No feedUrl' ,
148+ artistName : 'Author' ,
149+ artworkUrl600 : 'https://example.com/image2.jpg' ,
150+ // Missing feedUrl
151151 } ,
152152 {
153- title : 'Invalid Podcast - Empty URL' ,
154- author : 'Author' ,
155- description : 'Description' ,
156- image : 'https://example.com/image3.jpg' ,
157- url : '' ,
153+ collectionName : 'Invalid Podcast - Empty feedUrl' ,
154+ artistName : 'Author' ,
155+ artworkUrl600 : 'https://example.com/image3.jpg' ,
156+ feedUrl : '' ,
158157 } ,
159158 ] ,
160159 } ;
161160
162161 mockFetch . mockResolvedValueOnce ( {
163162 ok : true ,
164- json : ( ) => Promise . resolve ( mockCastosResponse ) ,
163+ json : ( ) => Promise . resolve ( mockItunesResponse ) ,
165164 } ) ;
166165
167166 const results = await service . searchPodcasts ( 'test' ) ;
@@ -171,29 +170,34 @@ describe('PodcastService', () => {
171170 expect ( results [ 0 ] . feedUrl ) . toBe ( 'https://example.com/feed.xml' ) ;
172171 } ) ;
173172
174- it ( 'should handle url field from Castos API ' , async ( ) => {
175- const mockCastosResponse = {
176- success : true ,
177- data : [
173+ it ( 'should fall back to trackName and artworkUrl100 when collection fields are absent ' , async ( ) => {
174+ const mockItunesResponse = {
175+ resultCount : 1 ,
176+ results : [
178177 {
179- title : 'Podcast with url' ,
180- author : 'Author' ,
181- description : 'Description' ,
182- image : 'https://example.com/image.jpg' ,
183- url : 'https://example.com/feed.xml' ,
178+ trackName : 'Track-named Podcast' ,
179+ artworkUrl100 : 'https://example.com/image100.jpg' ,
180+ feedUrl : 'https://example.com/feed.xml' ,
184181 } ,
185182 ] ,
186183 } ;
187184
188185 mockFetch . mockResolvedValueOnce ( {
189186 ok : true ,
190- json : ( ) => Promise . resolve ( mockCastosResponse ) ,
187+ json : ( ) => Promise . resolve ( mockItunesResponse ) ,
191188 } ) ;
192189
193190 const results = await service . searchPodcasts ( 'test' ) ;
194191
195192 expect ( results ) . toHaveLength ( 1 ) ;
196- expect ( results [ 0 ] . feedUrl ) . toBe ( 'https://example.com/feed.xml' ) ;
193+ expect ( results [ 0 ] ) . toEqual ( {
194+ title : 'Track-named Podcast' ,
195+ author : null ,
196+ description : null ,
197+ imageUrl : 'https://example.com/image100.jpg' ,
198+ feedUrl : 'https://example.com/feed.xml' ,
199+ websiteUrl : null ,
200+ } ) ;
197201 } ) ;
198202 } ) ;
199203
0 commit comments