|
1 | | -import { fireEvent, render, screen } from "@testing-library/svelte"; |
| 1 | +import { fireEvent, render, screen, waitFor } from "@testing-library/svelte"; |
2 | 2 | import { get } from "svelte/store"; |
3 | 3 | import { |
4 | 4 | afterEach, |
@@ -144,4 +144,89 @@ describe("PodcastView integration flow", () => { |
144 | 144 | expect.objectContaining({ path: expectedPath }), |
145 | 145 | ); |
146 | 146 | }); |
| 147 | + |
| 148 | + test("shows loading state while fetching and streams episodes per feed", async () => { |
| 149 | + const secondFeed: PodcastFeed = { |
| 150 | + title: "Second Podcast", |
| 151 | + url: "https://pod.example.com/feed-two.xml", |
| 152 | + artworkUrl: "https://pod.example.com/art-two.jpg", |
| 153 | + }; |
| 154 | + |
| 155 | + const firstEpisode: Episode = { |
| 156 | + title: "Episode A", |
| 157 | + streamUrl: "https://pod.example.com/a.mp3", |
| 158 | + url: "https://pod.example.com/a", |
| 159 | + description: "Episode A description", |
| 160 | + content: "<p>Episode A content</p>", |
| 161 | + podcastName: testFeed.title, |
| 162 | + artworkUrl: testFeed.artworkUrl, |
| 163 | + episodeDate: new Date("2024-02-01T00:00:00.000Z"), |
| 164 | + }; |
| 165 | + |
| 166 | + const secondEpisode: Episode = { |
| 167 | + title: "Episode B", |
| 168 | + streamUrl: "https://pod.example.com/b.mp3", |
| 169 | + url: "https://pod.example.com/b", |
| 170 | + description: "Episode B description", |
| 171 | + content: "<p>Episode B content</p>", |
| 172 | + podcastName: secondFeed.title, |
| 173 | + artworkUrl: secondFeed.artworkUrl, |
| 174 | + episodeDate: new Date("2024-01-15T00:00:00.000Z"), |
| 175 | + }; |
| 176 | + |
| 177 | + let resolveFirstFeed!: (value: Episode[]) => void; |
| 178 | + let resolveSecondFeed!: (value: Episode[]) => void; |
| 179 | + |
| 180 | + mockGetEpisodes |
| 181 | + .mockImplementationOnce( |
| 182 | + () => |
| 183 | + new Promise<Episode[]>((resolve) => { |
| 184 | + resolveFirstFeed = resolve; |
| 185 | + }), |
| 186 | + ) |
| 187 | + .mockImplementationOnce( |
| 188 | + () => |
| 189 | + new Promise<Episode[]>((resolve) => { |
| 190 | + resolveSecondFeed = resolve; |
| 191 | + }), |
| 192 | + ); |
| 193 | + |
| 194 | + plugin.set({ |
| 195 | + settings: { |
| 196 | + feedCache: { |
| 197 | + enabled: false, |
| 198 | + ttlHours: 6, |
| 199 | + }, |
| 200 | + }, |
| 201 | + } as never); |
| 202 | + |
| 203 | + savedFeeds.set({ |
| 204 | + [testFeed.title]: testFeed, |
| 205 | + [secondFeed.title]: secondFeed, |
| 206 | + }); |
| 207 | + viewState.set(ViewState.EpisodeList); |
| 208 | + |
| 209 | + render(PodcastView); |
| 210 | + |
| 211 | + await screen.findByText("Fetching episodes..."); |
| 212 | + |
| 213 | + resolveFirstFeed([firstEpisode]); |
| 214 | + |
| 215 | + expect( |
| 216 | + await screen.findByText(firstEpisode.title), |
| 217 | + ).toBeInTheDocument(); |
| 218 | + expect(screen.getByText("Fetching episodes...")).toBeInTheDocument(); |
| 219 | + expect(screen.queryByText(secondEpisode.title)).toBeNull(); |
| 220 | + |
| 221 | + resolveSecondFeed([secondEpisode]); |
| 222 | + |
| 223 | + expect( |
| 224 | + await screen.findByText(secondEpisode.title), |
| 225 | + ).toBeInTheDocument(); |
| 226 | + await waitFor(() => |
| 227 | + expect( |
| 228 | + screen.queryByText("Fetching episodes..."), |
| 229 | + ).not.toBeInTheDocument(), |
| 230 | + ); |
| 231 | + }); |
147 | 232 | }); |
0 commit comments