diff --git a/src/course-home/live-tab/LiveTab.jsx b/src/course-home/live-tab/LiveTab.jsx index 05a470e038..eccbf60db9 100644 --- a/src/course-home/live-tab/LiveTab.jsx +++ b/src/course-home/live-tab/LiveTab.jsx @@ -13,6 +13,7 @@ const LiveTab = () => { return (
diff --git a/src/course-home/live-tab/LiveTab.test.jsx b/src/course-home/live-tab/LiveTab.test.jsx new file mode 100644 index 0000000000..71ffb4f4ba --- /dev/null +++ b/src/course-home/live-tab/LiveTab.test.jsx @@ -0,0 +1,77 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { useSelector } from 'react-redux'; +import LiveTab from './LiveTab'; + +jest.mock('react-redux', () => ({ + useSelector: jest.fn(), +})); + +describe('LiveTab', () => { + afterEach(() => { + jest.clearAllMocks(); + document.body.innerHTML = ''; + }); + + it('renders iframe from liveModel using dangerouslySetInnerHTML', () => { + useSelector.mockImplementation((selector) => selector({ + courseHome: { courseId: 'course-v1:test+id+2024' }, + models: { + live: { + 'course-v1:test+id+2024': { + iframe: '', + }, + }, + }, + })); + + render(); + + const iframe = document.getElementById('lti-tab-embed'); + expect(iframe).toBeInTheDocument(); + expect(iframe.src).toBe('about:blank'); + }); + + it('adds classes to iframe after mount', () => { + document.body.innerHTML = ` +
+ +
+ `; + + useSelector.mockImplementation((selector) => selector({ + courseHome: { courseId: 'course-v1:test+id+2024' }, + models: { + live: { + 'course-v1:test+id+2024': { + iframe: '', + }, + }, + }, + })); + + render(); + + const iframe = document.getElementById('lti-tab-embed'); + expect(iframe.className).toContain('vh-100'); + expect(iframe.className).toContain('w-100'); + expect(iframe.className).toContain('border-0'); + }); + + it('does not throw if iframe is not found in DOM', () => { + useSelector.mockImplementation((selector) => selector({ + courseHome: { courseId: 'course-v1:test+id+2024' }, + models: { + live: { + 'course-v1:test+id+2024': { + iframe: '
No iframe here
', + }, + }, + }, + })); + + expect(() => render()).not.toThrow(); + const iframe = document.getElementById('lti-tab-embed'); + expect(iframe).toBeNull(); + }); +}); diff --git a/src/course-home/outline-tab/OutlineTab.test.jsx b/src/course-home/outline-tab/OutlineTab.test.jsx index 8a95e66ae7..c843d4ffd2 100644 --- a/src/course-home/outline-tab/OutlineTab.test.jsx +++ b/src/course-home/outline-tab/OutlineTab.test.jsx @@ -132,6 +132,24 @@ describe('Outline Tab', () => { expect(expandedSectionNode).toHaveAttribute('aria-expanded', 'true'); }); + it('displays correct heading for expanded section', async () => { + const { courseBlocks } = await buildMinimalCourseBlocks(courseId, 'Title', { resumeBlock: true }); + setTabData({ course_blocks: { blocks: courseBlocks.blocks } }); + await fetchAndRender(); + const headingContent = screen.getByText('Title of Section'); + const { parentElement } = headingContent; + expect(parentElement.tagName).toBe('H2'); + }); + + it('checks that the expanded section is within the correct list', async () => { + const { courseBlocks } = await buildMinimalCourseBlocks(courseId, 'Title', { resumeBlock: true }); + setTabData({ course_blocks: { blocks: courseBlocks.blocks } }); + await fetchAndRender(); + const listElement = screen.getByRole('presentation', { id: 'courseHome-outline' }); + expect(listElement).toBeInTheDocument(); + expect(listElement.tagName).toBe('OL'); + }); + it('includes outline_tab_notifications_slot', async () => { const { courseBlocks } = await buildMinimalCourseBlocks(courseId, 'Title', { resumeBlock: true }); setTabData({ diff --git a/src/course-home/outline-tab/Section.scss b/src/course-home/outline-tab/Section.scss new file mode 100644 index 0000000000..8cf4e666af --- /dev/null +++ b/src/course-home/outline-tab/Section.scss @@ -0,0 +1,4 @@ +.course-outline-tab-section-title { + font-size: $font-size-base; + line-height: $line-height-base; +} diff --git a/src/course-home/outline-tab/section-outline/SectionTitle.tsx b/src/course-home/outline-tab/section-outline/SectionTitle.tsx index 69c4ddfd98..057e9ade3c 100644 --- a/src/course-home/outline-tab/section-outline/SectionTitle.tsx +++ b/src/course-home/outline-tab/section-outline/SectionTitle.tsx @@ -35,7 +35,9 @@ const SectionTitle: React.FC = ({ complete, hideFromTOC, title }) => { )}
- {title} +

+ {title} +

, {intl.formatMessage(complete ? messages.completedSection : messages.incompleteSection)} diff --git a/src/index.scss b/src/index.scss index f4ae867e15..9f314c97c2 100755 --- a/src/index.scss +++ b/src/index.scss @@ -446,12 +446,12 @@ .course-outline-tab .pgn__card { .pgn__card-header { display: block; - + .pgn__card-header-content { margin-top: 0; } } - + .pgn__card-header-actions { margin-left: 0; } @@ -466,6 +466,8 @@ @import "courseware/course/content-tools/calculator/calculator.scss"; @import "courseware/course/content-tools/contentTools.scss"; @import "course-home/dates-tab/timeline/Day.scss"; +@import "course-home/outline-tab/Section.scss"; +@import "generic/upsell-bullets/UpsellBullets.scss"; @import "course-home/outline-tab/widgets/ProctoringInfoPanel.scss"; @import "course-home/outline-tab/widgets/FlagButton.scss"; @import "course-home/progress-tab/course-completion/CompletionDonutChart.scss"; diff --git a/src/plugin-slots/CourseHomeSectionOutlineSlot/index.tsx b/src/plugin-slots/CourseHomeSectionOutlineSlot/index.tsx index 5d7ae6e0ee..0e3d65e9ac 100644 --- a/src/plugin-slots/CourseHomeSectionOutlineSlot/index.tsx +++ b/src/plugin-slots/CourseHomeSectionOutlineSlot/index.tsx @@ -15,7 +15,7 @@ const CourseHomeSectionOutlineSlot: React.FC = ({ id="course_home_section_outline_slot" pluginProps={{ expandAll, sectionIds, sections }} > -
    +