diff --git a/apps/librelingo-web/src/app/[sourceLanguageCode]/courses/[targetLanguageCode]/page.tsx b/apps/librelingo-web/src/app/[sourceLanguageCode]/courses/[targetLanguageCode]/page.tsx index fea9b2f476b..e0ea6d133dd 100644 --- a/apps/librelingo-web/src/app/[sourceLanguageCode]/courses/[targetLanguageCode]/page.tsx +++ b/apps/librelingo-web/src/app/[sourceLanguageCode]/courses/[targetLanguageCode]/page.tsx @@ -20,5 +20,14 @@ export default async function CourseHomePage({params}: Props) { const courseId = await getCourseId(params) const detail = await getCourseDetail(courseId) - return

{detail.targetLanguage.name}

+ return <>

{detail.targetLanguage.name}

+ + + } diff --git a/apps/librelingo-web/src/data/course.ts b/apps/librelingo-web/src/data/course.ts index 6f8a7273bc3..03041162c36 100644 --- a/apps/librelingo-web/src/data/course.ts +++ b/apps/librelingo-web/src/data/course.ts @@ -87,11 +87,13 @@ export async function getCourseId( } export async function getCourseDetail(courseId: string) { - const { languageName } = await getCourseMetadataByJsonPath(courseId) + const { languageName, modules } = + await getCourseMetadataByJsonPath(courseId) return { targetLanguage: { name: languageName, }, + modules, } } diff --git a/e2e-tests/course.spec.ts b/e2e-tests/course.spec.ts index bc7f324a8ba..09df4361bce 100644 --- a/e2e-tests/course.spec.ts +++ b/e2e-tests/course.spec.ts @@ -7,3 +7,26 @@ test('has the correct content', async ({ page }) => { page.getByRole('heading', { name: 'Test Language' }) ).toBeVisible() }) + +test('has cards leading to module pages', async ({ page }) => { + const courseHomePagePattern = new RegExp( + `[^/]*/courses/[^/]+/modules/[^/]+` + ) + await page.goto('/en/courses/test-1') + + const cards = await page.getByRole('listitem').all() + + expect(cards.length).toBeGreaterThanOrEqual(1) + const urls = new Set() + + for (const card of cards) { + const button = card.getByRole('link', { name: 'Learn' }) + const url = await button.getAttribute('href') + + expect(url).toMatch(courseHomePagePattern) + urls.add(url) + } + + // each course has to have a unique url + expect(urls.size).toBeGreaterThanOrEqual(cards.length) +}) diff --git a/e2e-tests/home.spec.ts b/e2e-tests/home.spec.ts index 551c219b1a1..2544c66f808 100644 --- a/e2e-tests/home.spec.ts +++ b/e2e-tests/home.spec.ts @@ -10,7 +10,9 @@ test('has the correct content', async ({ page }) => { await expect(firstCard.getByRole('link', { name: 'Learn' })).toBeVisible() }) -test('all card buttons lead to URLs matching the pattern', async ({ page }) => { +test('has cards for each course leading to the course page', async ({ + page, +}) => { const courseHomePagePattern = new RegExp(`[^/]*/courses/[^/]+`) await page.goto('/') diff --git a/src/librelingo_json_export/module.py b/src/librelingo_json_export/module.py index 20d21b29f6a..d51377f0d3a 100644 --- a/src/librelingo_json_export/module.py +++ b/src/librelingo_json_export/module.py @@ -29,6 +29,7 @@ def get_levels(words, phrases): return calculate_number_of_levels(len(words), len(phrases)) return { + "slug": slugify(module.title), "title": module.title, "skills": [ { diff --git a/src/librelingo_json_export/tests/test_course_get_course_data.py b/src/librelingo_json_export/tests/test_course_get_course_data.py index e2564f11783..b4394506f80 100644 --- a/src/librelingo_json_export/tests/test_course_get_course_data.py +++ b/src/librelingo_json_export/tests/test_course_get_course_data.py @@ -39,6 +39,7 @@ def test__get_course_data_return_value(): }, "modules": [ { + "slug": "basics", "title": "Basics", "skills": [ { @@ -67,7 +68,7 @@ def test__get_course_data_return_value(): }, ], }, - {"title": "Phrases", "skills": []}, + {"slug": "phrases", "title": "Phrases", "skills": []}, ], } @@ -89,6 +90,7 @@ def test__get_course_data_return_value_2(): }, "modules": [ { + "slug": "animals", "title": "Animals", "skills": [ { @@ -122,6 +124,7 @@ def test__get_course_data_return_value_with_introduction(): }, "modules": [ { + "slug": "animals", "title": "Animals", "skills": [ {