Skip to content
Open
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
8 changes: 5 additions & 3 deletions frontends/api/src/test-utils/factories/learningResources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,9 +363,11 @@ const learningResource: PartialFactory<LearningResource> = (overrides = {}) => {

const learningResources = makePaginatedFactory(learningResource)

const learningResourceSummary: LearningResourceFactory<
LearningResourceSummary
> = (overrides = {}) => {
// Not a LearningResourceFactory: summaries carry every resource type, so
// resource_type has to be overridable.
const learningResourceSummary: Factory<LearningResourceSummary> = (
overrides = {},
) => {
return {
id: uniqueEnforcerId.enforce(() => faker.number.int()),
last_modified: faker.date.recent().toISOString(),
Expand Down
31 changes: 17 additions & 14 deletions frontends/main/src/app/sitemaps/podcast/sitemap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,24 @@ describe("Podcast Sitemaps", () => {

it("generates expected URLs for podcast resources", async () => {
const page = faker.number.int({ min: 5, max: 10 })
const podcastList = factories.learningResources.podcasts({
count: 3,
pageSize: 3,
})
const results = Array.from({ length: 3 }, () =>
factories.learningResources.resourceSummary({
resource_type: ResourceTypeEnum.Podcast,
}),
)

setMockResponse.get(
urls.learningResources.list({
urls.learningResources.summaryList({
limit: 1_000,
offset: page * 1_000,
resource_type: RESOURCE_TYPES,
}),
podcastList,
{ count: results.length, next: null, previous: null, results },
)

const sitemapPage = await sitemap({ id: Promise.resolve(String(page)) })
expect(sitemapPage).toEqual(
podcastList.results.map((resource) => ({
results.map((resource) => ({
url: `http://test.learn.odl.local:8062${podcastPageView(
String(resource.id),
resource.title,
Expand All @@ -70,14 +71,16 @@ describe("Podcast Sitemaps", () => {
const podcastId1 = faker.number.int()
const podcastId2 = faker.number.int()
const episodeWithMultipleParents =
factories.learningResources.podcastEpisode({
podcast_episode: { podcasts: [podcastId1, podcastId2] },
factories.learningResources.resourceSummary({
resource_type: ResourceTypeEnum.PodcastEpisode,
canonical_parent_ids: [podcastId1, podcastId2],
})
const episodeWithOneParent = factories.learningResources.podcastEpisode({
podcast_episode: { podcasts: [podcastId1] },
const episodeWithOneParent = factories.learningResources.resourceSummary({
resource_type: ResourceTypeEnum.PodcastEpisode,
canonical_parent_ids: [podcastId1],
})
const episodeWithoutParent = factories.learningResources.podcastEpisode({
podcast_episode: { podcasts: [] },
const episodeWithoutParent = factories.learningResources.resourceSummary({
resource_type: ResourceTypeEnum.PodcastEpisode,
})
const results = [
episodeWithMultipleParents,
Expand All @@ -86,7 +89,7 @@ describe("Podcast Sitemaps", () => {
]

setMockResponse.get(
urls.learningResources.list({
urls.learningResources.summaryList({
limit: 1_000,
offset: page * 1_000,
resource_type: RESOURCE_TYPES,
Expand Down
5 changes: 2 additions & 3 deletions frontends/main/src/app/sitemaps/podcast/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { getQueryClient } from "@/app/getQueryClient"
import { learningResourceQueries } from "api/hooks/learningResources"
import { ResourceTypeEnum } from "api"
import { podcastPageView, podcastEpisodePageView } from "@/common/urls"
import { parentPodcastIds } from "@/common/slugs"
import type { GenerateSitemapResult } from "../types"
import {
dangerouslyDetectProductionBuildPhase,
Expand Down Expand Up @@ -52,7 +51,7 @@ export default constructSitemap(async (page) => {
const BASE_URL = requiredEnv("NEXT_PUBLIC_ORIGIN")
const queryClient = getQueryClient()
const data = await queryClient.fetchQuery(
learningResourceQueries.list({
learningResourceQueries.summaryList({
limit: PAGE_SIZE,
offset: page * PAGE_SIZE,
resource_type: RESOURCE_TYPES,
Expand All @@ -69,7 +68,7 @@ export default constructSitemap(async (page) => {
]
}
if (resource.resource_type === ResourceTypeEnum.PodcastEpisode) {
return parentPodcastIds(resource).map((parentPodcastId) => ({
return resource.canonical_parent_ids.map((parentPodcastId) => ({
url: `${BASE_URL}${podcastEpisodePageView(
String(resource.id),
String(parentPodcastId),
Expand Down
72 changes: 40 additions & 32 deletions frontends/main/src/app/sitemaps/video/sitemap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { generateSitemaps, default as sitemap } from "./sitemap"
import { setMockResponse, urls, factories } from "api/test-utils"
import { ResourceTypeEnum } from "api"
import { videoDetailPageView, videoPlaylistPageView } from "@/common/urls"
import { videoPlaylistIds } from "@/common/slugs"

const RESOURCE_TYPES = [ResourceTypeEnum.Video, ResourceTypeEnum.VideoPlaylist]

Expand Down Expand Up @@ -35,18 +34,24 @@ describe("Video Sitemaps", () => {

it("generates expected URLs for video and video playlist resources", async () => {
const page = faker.number.int({ min: 5, max: 10 })
const videoList = factories.learningResources.videos({
count: 3,
pageSize: 3,
const playlistId = faker.number.int()
const otherPlaylistId = faker.number.int()
// A video in several playlists is addressed by its first, matching the
// canonical tag and the bare-URL redirect on the video page.
const videoWithPlaylists = factories.learningResources.resourceSummary({
resource_type: ResourceTypeEnum.Video,
canonical_parent_ids: [playlistId, otherPlaylistId],
})
const playlistList = factories.learningResources.videoPlaylists({
count: 2,
pageSize: 2,
const videoWithoutPlaylist = factories.learningResources.resourceSummary({
resource_type: ResourceTypeEnum.Video,
})
const results = [...videoList.results, ...playlistList.results]
const playlist = factories.learningResources.resourceSummary({
resource_type: ResourceTypeEnum.VideoPlaylist,
})
const results = [videoWithPlaylists, videoWithoutPlaylist, playlist]

setMockResponse.get(
urls.learningResources.list({
urls.learningResources.summaryList({
limit: 1_000,
offset: page * 1_000,
resource_type: RESOURCE_TYPES,
Expand All @@ -55,28 +60,31 @@ describe("Video Sitemaps", () => {
)

const sitemapPage = await sitemap({ id: Promise.resolve(String(page)) })
expect(sitemapPage).toEqual(
results.map((resource) => {
const base = "http://test.learn.odl.local:8062"
if (resource.resource_type === ResourceTypeEnum.VideoPlaylist) {
return {
url: `${base}${videoPlaylistPageView(
String(resource.id),
resource.title,
)}`,
lastModified: resource.last_modified ?? undefined,
}
}
const [firstPlaylist] = videoPlaylistIds(resource)
return {
url: `${base}${videoDetailPageView(
resource.id,
firstPlaylist,
resource.title,
)}`,
lastModified: resource.last_modified ?? undefined,
}
}),
)
const base = "http://test.learn.odl.local:8062"
expect(sitemapPage).toEqual([
{
url: `${base}${videoDetailPageView(
videoWithPlaylists.id,
playlistId,
videoWithPlaylists.title,
)}`,
lastModified: videoWithPlaylists.last_modified ?? undefined,
},
{
url: `${base}${videoDetailPageView(
videoWithoutPlaylist.id,
undefined,
videoWithoutPlaylist.title,
)}`,
lastModified: videoWithoutPlaylist.last_modified ?? undefined,
},
{
url: `${base}${videoPlaylistPageView(
String(playlist.id),
playlist.title,
)}`,
lastModified: playlist.last_modified ?? undefined,
},
])
})
})
5 changes: 2 additions & 3 deletions frontends/main/src/app/sitemaps/video/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { getQueryClient } from "@/app/getQueryClient"
import { learningResourceQueries } from "api/hooks/learningResources"
import { ResourceTypeEnum } from "api"
import { videoDetailPageView, videoPlaylistPageView } from "@/common/urls"
import { videoPlaylistIds } from "@/common/slugs"
import type { GenerateSitemapResult } from "../types"
import {
dangerouslyDetectProductionBuildPhase,
Expand Down Expand Up @@ -49,7 +48,7 @@ export default constructSitemap(async (page) => {
const BASE_URL = requiredEnv("NEXT_PUBLIC_ORIGIN")
const queryClient = getQueryClient()
const data = await queryClient.fetchQuery(
learningResourceQueries.list({
learningResourceQueries.summaryList({
limit: PAGE_SIZE,
offset: page * PAGE_SIZE,
resource_type: RESOURCE_TYPES,
Expand All @@ -61,7 +60,7 @@ export default constructSitemap(async (page) => {
// Emit the true canonical: a video with playlists redirects bare →
// playlists[0], so include it (couples to playlists[0] ordering, same as
// the canonical tag + page redirect — no new coupling).
const [firstPlaylist] = videoPlaylistIds(resource)
const [firstPlaylist] = resource.canonical_parent_ids
return [
{
url: `${BASE_URL}${videoDetailPageView(
Expand Down
Loading