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

Add loader to podcast page #2804

Merged
merged 4 commits into from
Apr 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions static/js/components/Loading.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,53 @@ export const PostLoading = () => (
</div>
)

export const PodcastEpisodeLoading = () =>
R.times(
i => (
<Card key={i}>
<ContentLoader
speed={contentLoaderSpeed}
style={{ width: "100%", height: "74px" }}
width={1000}
height={74}
preserveAspectRatio="none"
>
<rect x="0" y="0" rx="5" ry="5" width="60%" height="12" />
<rect x="0" y="25" rx="5" ry="5" width="30%" height="14" />
<rect x="0" y="55" rx="15" ry="15" width="140" height="18" />
<rect x="66%" y="0" rx="5" ry="5" width="34%" height={69} />
</ContentLoader>
</Card>
),
6
)

export const PodcastLoading = () => (
<Grid>
{R.times(
i => (
<Cell width={4} key={i}>
<Card className="borderless">
<ContentLoader
speed={contentLoaderSpeed}
style={{ width: "100%", height: "280px" }}
width={1000}
height={280}
preserveAspectRatio="none"
>
<rect x="0" y="0" rx="5" ry="5" width="100%" height={180} />
<rect x="30" y="190" rx="5" ry="5" width="20%" height="12" />
<rect x="30" y="210" rx="5" ry="5" width="80%" height="18" />
<rect x="30" y="260" rx="15" ry="15" width="30%" height="12" />
</ContentLoader>
</Card>
</Cell>
),
9
)}
</Grid>
)

type CSLProps = {
layout: string
}
Expand Down
22 changes: 20 additions & 2 deletions static/js/components/Loading_test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
// @flow
import React from "react"
import { assert } from "chai"
import { mount } from "enzyme"
import { shallow, mount } from "enzyme"

import { withLoading, withSpinnerLoading, withPostLoading } from "./Loading"
import {
withLoading,
withSpinnerLoading,
withPostLoading,
PodcastLoading,
PodcastEpisodeLoading
} from "./Loading"
import { NotFound, NotAuthorized } from "../components/ErrorPages"

const GenericLoader = () => <div className="loading">loading...</div>
Expand Down Expand Up @@ -81,4 +87,16 @@ describe("Loading component", () => {
assert.lengthOf(wrapper.find(".post-content-loader"), 5)
})
})

describe("podcasts", () => {
it("should show nine empty items for podcasts", () => {
const wrapper = shallow(<PodcastLoading />)
assert.equal(wrapper.find("Card.borderless").length, 9)
})

it("should show six empty items for podcast episodes", () => {
const wrapper = shallow(<PodcastEpisodeLoading />)
assert.equal(wrapper.find("Card").length, 6)
})
})
})
15 changes: 9 additions & 6 deletions static/js/pages/PodcastFrontpage.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useSelector } from "react-redux"
import PodcastEpisodeCard from "../components/PodcastEpisodeCard"
import PodcastCard from "../components/PodcastCard"
import { Cell, Grid } from "../components/Grid"
import { PodcastLoading, PodcastEpisodeLoading } from "../components/Loading"

import {
podcastsRequest,
Expand All @@ -20,8 +21,6 @@ export default function PodcastFrontpage() {
recentPodcastEpisodesRequest()
)

const loaded = isFinishedPodcasts && isFinishedRecent

const podcasts = useSelector(podcastsSelector)
const recentEpisodes = useSelector(recentEpisodesSelector)

Expand All @@ -31,7 +30,7 @@ export default function PodcastFrontpage() {
<div className="recent-header">
<div className="title">RECENT EPISODES</div>
</div>
{loaded ? (
{isFinishedRecent && isFinishedPodcasts ? (
<>
{recentEpisodes
.slice(0, 6)
Expand All @@ -43,19 +42,23 @@ export default function PodcastFrontpage() {
/>
))}
</>
) : null}
) : (
<PodcastEpisodeLoading />
)}
</div>
<div className="all-podcasts">
<h1>Podcasts Series</h1>
{loaded ? (
{isFinishedPodcasts ? (
<Grid>
{Object.values(podcasts).map((podcast: any) => (
<Cell width={4} key={podcast.id}>
<PodcastCard podcast={podcast} />
</Cell>
))}
</Grid>
) : null}
) : (
<PodcastLoading />
)}
</div>
</div>
)
Expand Down
50 changes: 49 additions & 1 deletion static/js/pages/PodcastFrontpage_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import PodcastFrontpage from "./PodcastFrontpage"

import IntegrationTestHelper from "../util/integration_test_helper"

import { genericQueryResponse, queryListResponse } from "../lib/test_utils"
import {
genericQueryResponse,
isIf,
queryListResponse,
shouldIf
} from "../lib/test_utils"
import { podcastApiURL, recentPodcastApiURL } from "../lib/url"
import { makePodcast, makePodcastEpisode } from "../factories/podcasts"

Expand Down Expand Up @@ -48,4 +53,47 @@ describe("PodcastFrontpage tests", () => {
wrapper.find("PodcastCard").map(card => card.prop("podcast"))
).map(podcasts => assert.deepEqual(...podcasts))
})

describe("loader", () => {
[
[true, true, true, true],
[true, false, true, true],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this line should be true, false, true, false, but when I change it to that locally the test stops passing

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The episode rendering looks up information in both the episode and podcasts API data, so if only the podcast data is loading, the episode list still needs to show a spinner

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahhh that makes sense

[false, true, false, true],
[false, false, false, false]
].forEach(
([
podcastLoading,
episodesLoading,
expectedPodcastSpinner,
expectedRecentEpisodesSpinner
]) => {
it(`${shouldIf(
expectedPodcastSpinner
)} show a spinner for podcasts and ${shouldIf(
expectedRecentEpisodesSpinner
)} show a spinner for recent episodes, if podcasts ${isIf(
podcastLoading
)} loading and recent episodes ${isIf(
episodesLoading
)} loading`, async () => {
helper.isLoadingStub
.withArgs(podcastApiURL.toString())
.returns(podcastLoading)
helper.isLoadingStub
.withArgs(recentPodcastApiURL.toString())
.returns(episodesLoading)

const { wrapper } = await render()
assert.equal(
expectedRecentEpisodesSpinner,
wrapper.find("PodcastEpisodeLoading").exists()
)
assert.equal(
expectedPodcastSpinner,
wrapper.find("PodcastLoading").exists()
)
})
}
)
})
})
5 changes: 4 additions & 1 deletion static/js/util/integration_test_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export default class IntegrationTestHelper {
status: 200
}
this.handleRequestStub = this.sandbox.stub().returns(defaultResponse)
this.isLoadingStub = this.sandbox.stub().returns(false)
this.sandbox
.stub(networkInterfaceFuncs, "makeRequest")
.callsFake((url, method, options) => ({
Expand All @@ -107,7 +108,9 @@ export default class IntegrationTestHelper {
const resText = (response && response.text) || undefined
const resHeaders = (response && response.header) || undefined

callback(err, resStatus, resBody, resText, resHeaders)
if (!this.isLoadingStub(url, method, options)) {
callback(err, resStatus, resBody, resText, resHeaders)
}
},
abort: () => {}
}))
Expand Down