diff --git a/src/course-home/data/redux.test.js b/src/course-home/data/redux.test.js index ad226a6e..700535d6 100644 --- a/src/course-home/data/redux.test.js +++ b/src/course-home/data/redux.test.js @@ -8,8 +8,6 @@ import * as thunks from './thunks'; import executeThunk from '../../utils'; -import './__factories__'; -import '../../courseware/data/__factories__/courseMetadata.factory'; import initializeMockApp from '../../setupTest'; import initializeStore from '../../store'; diff --git a/src/courseware/CoursewareContainer.test.jsx b/src/courseware/CoursewareContainer.test.jsx index 1aa1c183..81c480f9 100644 --- a/src/courseware/CoursewareContainer.test.jsx +++ b/src/courseware/CoursewareContainer.test.jsx @@ -14,7 +14,6 @@ import tabMessages from '../tab-page/messages'; import initializeMockApp from '../setupTest'; import CoursewareContainer from './CoursewareContainer'; -import './data/__factories__'; import buildSimpleCourseBlocks from './data/__factories__/courseBlocks.factory'; import initializeStore from '../store'; diff --git a/src/courseware/course/sequence/Sequence.test.jsx b/src/courseware/course/sequence/Sequence.test.jsx index a452f91c..5c6108d3 100644 --- a/src/courseware/course/sequence/Sequence.test.jsx +++ b/src/courseware/course/sequence/Sequence.test.jsx @@ -1,32 +1,67 @@ import React from 'react'; -import { cloneDeep } from 'lodash'; +import { Factory } from 'rosie'; import { sendTrackEvent } from '@edx/frontend-platform/analytics'; import { - initialState, loadUnit, render, screen, testUnits, fireEvent, waitFor, + loadUnit, render, screen, fireEvent, waitFor, initializeTestStore, } from '../../../setupTest'; import Sequence from './Sequence'; +import { fetchSequenceFailure } from '../../data/slice'; jest.mock('@edx/frontend-platform/analytics'); describe('Sequence', () => { - const mockData = { - unitId: '3', - sequenceId: '1', - courseId: '1', - unitNavigationHandler: () => {}, - nextSequenceHandler: () => {}, - previousSequenceHandler: () => {}, - intl: {}, - }; + let mockData; + const courseMetadata = Factory.build('courseMetadata'); + const unitBlocks = Array.from({ length: 3 }).map(() => Factory.build( + 'block', + { type: 'vertical' }, + { courseId: courseMetadata.id }, + )); + + beforeAll(async () => { + const store = await initializeTestStore({ courseMetadata, unitBlocks }); + const { courseware } = store.getState(); + mockData = { + unitId: unitBlocks[0].id, + sequenceId: courseware.sequenceId, + courseId: courseware.courseId, + unitNavigationHandler: () => {}, + nextSequenceHandler: () => {}, + previousSequenceHandler: () => {}, + }; + }); + + it('renders correctly without data', async () => { + const testStore = await initializeTestStore({ excludeFetchCourse: true, excludeFetchSequence: true }, false); + render(, { store: testStore }); - it('renders correctly without data', () => { - render(, { initialState: {} }); expect(screen.getByText('There is no content here.')).toBeInTheDocument(); expect(screen.queryByRole('button')).not.toBeInTheDocument(); }); it('renders correctly for gated content', async () => { - const { container } = render(); + const sequenceBlock = [Factory.build( + 'block', + { type: 'sequential', children: [unitBlocks.map(block => block.id)] }, + { courseId: courseMetadata.id }, + )]; + const gatedContent = { + gated: true, + prereq_id: `${sequenceBlock[0].id}-prereq`, + prereq_section_name: `${sequenceBlock[0].display_name}-prereq`, + gated_section_name: sequenceBlock[0].display_name, + }; + const sequenceMetadata = [Factory.build( + 'sequenceMetadata', + { courseId: courseMetadata.id, gated_content: gatedContent }, + { unitBlocks, sequenceBlock: sequenceBlock[0] }, + )]; + const testStore = await initializeTestStore({ unitBlocks, sequenceBlock, sequenceMetadata }, false); + const { container } = render( + , + { store: testStore }, + ); + expect(screen.getByText('Loading locked content messaging...')).toBeInTheDocument(); // Only `Previous`, `Next` and `Bookmark` buttons. expect(screen.getAllByRole('button').length).toEqual(3); @@ -39,10 +74,10 @@ describe('Sequence', () => { expect(screen.queryByText('Loading locked content messaging...')).not.toBeInTheDocument(); }); - it('displays error message on sequence load failure', () => { - const testState = cloneDeep(initialState); - testState.courseware.sequenceStatus = 'failed'; - render(, { initialState: testState }); + it('displays error message on sequence load failure', async () => { + const testStore = await initializeTestStore({ excludeFetchCourse: true, excludeFetchSequence: true }, false); + testStore.dispatch(fetchSequenceFailure({ sequenceId: mockData.sequenceId })); + render(, { store: testStore }); expect(screen.getByText('There was an error loading this course.')).toBeInTheDocument(); }); @@ -51,7 +86,7 @@ describe('Sequence', () => { render(); expect(screen.getByText('Loading learning sequence...')).toBeInTheDocument(); // Renders navigation buttons plus one button for each unit. - expect(screen.getAllByRole('button').length).toEqual(3 + testUnits.length); + expect(screen.getAllByRole('button')).toHaveLength(3 + unitBlocks.length); loadUnit(); await waitFor(() => expect(screen.queryByText('Loading learning sequence...')).not.toBeInTheDocument()); @@ -60,21 +95,41 @@ describe('Sequence', () => { }); describe('sequence and unit navigation buttons', () => { - it('navigates to the previous sequence if the unit is the first in the sequence', async () => { + let testStore; + const sequenceBlock = [Factory.build( + 'block', + { type: 'sequential', children: [unitBlocks.map(block => block.id)] }, + { courseId: courseMetadata.id }, + ), Factory.build( + 'block', + { type: 'sequential', children: [unitBlocks.map(block => block.id)] }, + { courseId: courseMetadata.id }, + )]; + + beforeAll(async () => { + testStore = await initializeTestStore({ courseMetadata, unitBlocks, sequenceBlock }, false); + }); + + beforeEach(() => { sendTrackEvent.mockClear(); - const unitId = '1'; - const sequenceId = '2'; - const previousSequenceHandler = jest.fn(); - render(); + }); + + it('navigates to the previous sequence if the unit is the first in the sequence', async () => { + const testData = { + ...mockData, + sequenceId: sequenceBlock[1].id, + previousSequenceHandler: jest.fn(), + }; + render(, { store: testStore }); const sequencePreviousButton = screen.getByRole('button', { name: /previous/i }); fireEvent.click(sequencePreviousButton); - expect(previousSequenceHandler).toHaveBeenCalledTimes(1); + expect(testData.previousSequenceHandler).toHaveBeenCalledTimes(1); expect(sendTrackEvent).toHaveBeenCalledTimes(1); expect(sendTrackEvent).toHaveBeenCalledWith('edx.ui.lms.sequence.previous_selected', { - current_tab: Number(unitId), - id: unitId, - tab_count: testUnits.length, + current_tab: 1, + id: testData.unitId, + tab_count: unitBlocks.length, widget_placement: 'top', }); @@ -83,30 +138,32 @@ describe('Sequence', () => { const unitPreviousButton = screen.getAllByRole('button', { name: /previous/i }) .filter(button => button !== sequencePreviousButton)[0]; fireEvent.click(unitPreviousButton); - expect(previousSequenceHandler).toHaveBeenCalledTimes(2); + expect(testData.previousSequenceHandler).toHaveBeenCalledTimes(2); expect(sendTrackEvent).toHaveBeenCalledTimes(2); expect(sendTrackEvent).toHaveBeenNthCalledWith(2, 'edx.ui.lms.sequence.previous_selected', { - current_tab: Number(unitId), - id: unitId, - tab_count: testUnits.length, + current_tab: 1, + id: testData.unitId, + tab_count: unitBlocks.length, widget_placement: 'bottom', }); }); it('navigates to the next sequence if the unit is the last in the sequence', async () => { - sendTrackEvent.mockClear(); - const unitId = String(testUnits.length); - const sequenceId = '1'; - const nextSequenceHandler = jest.fn(); - render(); + const testData = { + ...mockData, + unitId: unitBlocks[unitBlocks.length - 1].id, + sequenceId: sequenceBlock[0].id, + nextSequenceHandler: jest.fn(), + }; + render(, { store: testStore }); const sequenceNextButton = screen.getByRole('button', { name: /next/i }); fireEvent.click(sequenceNextButton); - expect(nextSequenceHandler).toHaveBeenCalledTimes(1); + expect(testData.nextSequenceHandler).toHaveBeenCalledTimes(1); expect(sendTrackEvent).toHaveBeenCalledWith('edx.ui.lms.sequence.next_selected', { - current_tab: Number(unitId), - id: unitId, - tab_count: testUnits.length, + current_tab: unitBlocks.length, + id: testData.unitId, + tab_count: unitBlocks.length, widget_placement: 'top', }); @@ -115,141 +172,167 @@ describe('Sequence', () => { const unitNextButton = screen.getAllByRole('button', { name: /next/i }) .filter(button => button !== sequenceNextButton)[0]; fireEvent.click(unitNextButton); - expect(nextSequenceHandler).toHaveBeenCalledTimes(2); + expect(testData.nextSequenceHandler).toHaveBeenCalledTimes(2); expect(sendTrackEvent).toHaveBeenCalledTimes(2); expect(sendTrackEvent).toHaveBeenNthCalledWith(2, 'edx.ui.lms.sequence.next_selected', { - current_tab: Number(unitId), - id: unitId, - tab_count: testUnits.length, + current_tab: unitBlocks.length, + id: testData.unitId, + tab_count: unitBlocks.length, widget_placement: 'bottom', }); }); it('navigates to the previous/next unit if the unit is not in the corner of the sequence', () => { - sendTrackEvent.mockClear(); - const unitNavigationHandler = jest.fn(); - const previousSequenceHandler = jest.fn(); - const nextSequenceHandler = jest.fn(); - render(); + const unitNumber = 1; + const testData = { + ...mockData, + unitId: unitBlocks[unitNumber].id, + sequenceId: sequenceBlock[0].id, + unitNavigationHandler: jest.fn(), + previousSequenceHandler: jest.fn(), + nextSequenceHandler: jest.fn(), + }; + render(, { store: testStore }); fireEvent.click(screen.getByRole('button', { name: /previous/i })); - expect(previousSequenceHandler).not.toHaveBeenCalled(); - expect(unitNavigationHandler).toHaveBeenCalledWith(String(Number(mockData.unitId) - 1)); + expect(testData.previousSequenceHandler).not.toHaveBeenCalled(); + expect(testData.unitNavigationHandler).toHaveBeenCalledWith(unitBlocks[unitNumber - 1].id); fireEvent.click(screen.getByRole('button', { name: /next/i })); - expect(nextSequenceHandler).not.toHaveBeenCalled(); + expect(testData.nextSequenceHandler).not.toHaveBeenCalled(); // As `previousSequenceHandler` and `nextSequenceHandler` are mocked, we aren't really changing the position here. // Therefore the next unit will still be `the initial one + 1`. - expect(unitNavigationHandler).toHaveBeenNthCalledWith(2, String(Number(mockData.unitId) + 1)); + expect(testData.unitNavigationHandler).toHaveBeenNthCalledWith(2, unitBlocks[unitNumber + 1].id); expect(sendTrackEvent).toHaveBeenCalledTimes(2); }); it('handles the `Previous` buttons for the first unit in the first sequence', async () => { - sendTrackEvent.mockClear(); - const unitNavigationHandler = jest.fn(); - const previousSequenceHandler = jest.fn(); - const unitId = '1'; - render(); + const testData = { + ...mockData, + unitId: unitBlocks[0].id, + sequenceId: sequenceBlock[0].id, + unitNavigationHandler: jest.fn(), + previousSequenceHandler: jest.fn(), + }; + render(, { store: testStore }); loadUnit(); await waitFor(() => expect(screen.queryByText('Loading learning sequence...')).not.toBeInTheDocument()); screen.getAllByRole('button', { name: /previous/i }).forEach(button => fireEvent.click(button)); - expect(previousSequenceHandler).not.toHaveBeenCalled(); - expect(unitNavigationHandler).not.toHaveBeenCalled(); + expect(testData.previousSequenceHandler).not.toHaveBeenCalled(); + expect(testData.unitNavigationHandler).not.toHaveBeenCalled(); expect(sendTrackEvent).not.toHaveBeenCalled(); }); it('handles the `Next` buttons for the last unit in the last sequence', async () => { - sendTrackEvent.mockClear(); - const unitNavigationHandler = jest.fn(); - const nextSequenceHandler = jest.fn(); - const unitId = String(testUnits.length); - const sequenceId = String(Object.keys(initialState.models.sequences).length); - render(); + const testData = { + ...mockData, + unitId: unitBlocks[unitBlocks.length - 1].id, + sequenceId: sequenceBlock[sequenceBlock.length - 1].id, + unitNavigationHandler: jest.fn(), + nextSequenceHandler: jest.fn(), + }; + render(, { store: testStore }); loadUnit(); await waitFor(() => expect(screen.queryByText('Loading learning sequence...')).not.toBeInTheDocument()); screen.getAllByRole('button', { name: /next/i }).forEach(button => fireEvent.click(button)); - expect(nextSequenceHandler).toHaveBeenCalledTimes(1); - expect(unitNavigationHandler).not.toHaveBeenCalled(); - expect(sendTrackEvent).toHaveBeenCalledWith('edx.ui.lms.sequence.next_selected', { - current_tab: Number(unitId), - id: unitId, - tab_count: testUnits.length, - widget_placement: 'top', - }); + expect(testData.nextSequenceHandler).not.toHaveBeenCalled(); + expect(testData.unitNavigationHandler).not.toHaveBeenCalled(); + expect(sendTrackEvent).not.toHaveBeenCalled(); }); it('handles the navigation buttons for empty sequence', async () => { - sendTrackEvent.mockClear(); - const testState = cloneDeep(initialState); - testState.models.sequences['1'].unitIds = []; + const testSequenceBlock = [Factory.build( + 'block', + { type: 'sequential', children: [unitBlocks.map(block => block.id)] }, + { courseId: courseMetadata.id }, + ), Factory.build( + 'block', + { type: 'sequential', children: [] }, + { courseId: courseMetadata.id }, + ), Factory.build( + 'block', + { type: 'sequential', children: [unitBlocks.map(block => block.id)] }, + { courseId: courseMetadata.id }, + )]; + const testSequenceMetadata = testSequenceBlock.map(block => Factory.build( + 'sequenceMetadata', + { courseId: courseMetadata.id }, + { unitBlocks: block.children.length ? unitBlocks : [], sequenceBlock: block }, + )); + const innerTestStore = await initializeTestStore({ + courseMetadata, unitBlocks, sequenceBlock: testSequenceBlock, sequenceMetadata: testSequenceMetadata, + }, false); + const testData = { + ...mockData, + unitId: unitBlocks[0].id, + sequenceId: testSequenceBlock[1].id, + unitNavigationHandler: jest.fn(), + previousSequenceHandler: jest.fn(), + nextSequenceHandler: jest.fn(), + }; - const unitNavigationHandler = jest.fn(); - const previousSequenceHandler = jest.fn(); - const nextSequenceHandler = jest.fn(); - render(, { initialState: testState }); + render(, { store: innerTestStore }); loadUnit(); await waitFor(() => expect(screen.queryByText('Loading learning sequence...')).not.toBeInTheDocument()); screen.getAllByRole('button', { name: /previous/i }).forEach(button => fireEvent.click(button)); - expect(previousSequenceHandler).toHaveBeenCalledTimes(2); - expect(unitNavigationHandler).not.toHaveBeenCalled(); + expect(testData.previousSequenceHandler).toHaveBeenCalledTimes(2); + expect(testData.unitNavigationHandler).not.toHaveBeenCalled(); screen.getAllByRole('button', { name: /next/i }).forEach(button => fireEvent.click(button)); - expect(nextSequenceHandler).toHaveBeenCalledTimes(2); - expect(unitNavigationHandler).not.toHaveBeenCalled(); + expect(testData.nextSequenceHandler).toHaveBeenCalledTimes(2); + expect(testData.unitNavigationHandler).not.toHaveBeenCalled(); expect(sendTrackEvent).toHaveBeenNthCalledWith(1, 'edx.ui.lms.sequence.previous_selected', { current_tab: 1, - id: mockData.unitId, + id: testData.unitId, tab_count: 0, widget_placement: 'top', }); expect(sendTrackEvent).toHaveBeenNthCalledWith(2, 'edx.ui.lms.sequence.previous_selected', { current_tab: 1, - id: mockData.unitId, + id: testData.unitId, tab_count: 0, widget_placement: 'bottom', }); expect(sendTrackEvent).toHaveBeenNthCalledWith(3, 'edx.ui.lms.sequence.next_selected', { current_tab: 1, - id: mockData.unitId, + id: testData.unitId, tab_count: 0, widget_placement: 'top', }); expect(sendTrackEvent).toHaveBeenNthCalledWith(4, 'edx.ui.lms.sequence.next_selected', { current_tab: 1, - id: mockData.unitId, + id: testData.unitId, tab_count: 0, widget_placement: 'bottom', }); }); it('handles unit navigation button', () => { - sendTrackEvent.mockClear(); - const unitNavigationHandler = jest.fn(); - const targetUnit = '4'; - render(); + const currentTabNumber = 1; + const targetUnitNumber = 2; + const targetUnit = unitBlocks[targetUnitNumber - 1]; + const testData = { + ...mockData, + unitId: unitBlocks[currentTabNumber - 1].id, + sequenceId: sequenceBlock[0].id, + unitNavigationHandler: jest.fn(), + }; + render(, { store: testStore }); - fireEvent.click(screen.getByRole('button', { name: targetUnit })); - expect(unitNavigationHandler).toHaveBeenCalledWith(targetUnit); + fireEvent.click(screen.getByRole('button', { name: targetUnit.display_name })); + expect(testData.unitNavigationHandler).toHaveBeenCalledWith(targetUnit.id); expect(sendTrackEvent).toHaveBeenCalledWith('edx.ui.lms.sequence.tab_selected', { - current_tab: Number(mockData.unitId), - id: mockData.unitId, - target_tab: Number(targetUnit), - tab_count: testUnits.length, + current_tab: currentTabNumber, + id: testData.unitId, + target_tab: targetUnitNumber, + tab_count: unitBlocks.length, widget_placement: 'top', }); }); diff --git a/src/courseware/course/sequence/SequenceContent.test.jsx b/src/courseware/course/sequence/SequenceContent.test.jsx index a26521b1..23c60a27 100644 --- a/src/courseware/course/sequence/SequenceContent.test.jsx +++ b/src/courseware/course/sequence/SequenceContent.test.jsx @@ -1,36 +1,44 @@ import React from 'react'; -import { initialState, render, screen } from '../../../setupTest'; +import { initializeTestStore, render, screen } from '../../../setupTest'; import SequenceContent from './SequenceContent'; describe('Sequence Content', () => { - const mockData = { - gated: false, - courseId: '1', - sequenceId: '1', - unitId: '1', - unitLoadedHandler: () => {}, - intl: {}, - }; + let mockData; + let store; + + beforeAll(async () => { + store = await initializeTestStore(); + const { models, courseware } = store.getState(); + mockData = { + gated: false, + courseId: courseware.courseId, + sequenceId: courseware.sequenceId, + unitId: models.sequences[courseware.sequenceId].unitIds[0], + unitLoadedHandler: () => {}, + }; + }); it('displays loading message', () => { - render(, { initialState }); + render(); expect(screen.getByText('Loading learning sequence...')).toBeInTheDocument(); }); it('displays messages for the locked content', async () => { - const { container } = render(, { initialState }); - expect(screen.getByText('Loading locked content messaging...')).toBeInTheDocument(); + const { gatedContent } = store.getState().models.sequences[mockData.sequenceId]; + const { container } = render(); + expect(screen.getByText('Loading locked content messaging...')).toBeInTheDocument(); expect(await screen.findByText('Content Locked')).toBeInTheDocument(); - expect(screen.getByText('test-sequence')).toBeInTheDocument(); expect(screen.queryByText('Loading locked content messaging...')).not.toBeInTheDocument(); expect(container.querySelector('svg')).toHaveClass('fa-lock'); - expect(screen.getByText(/You must complete the prerequisite/)).toBeInTheDocument(); + expect(screen.getByText( + `You must complete the prerequisite: '${gatedContent.gatedSectionName}' to access this content.`, + )).toBeInTheDocument(); expect(screen.getByRole('button', { name: 'Go To Prerequisite Section' })).toBeInTheDocument(); }); it('displays message for no content', () => { - render(, { initialState }); + render(); expect(screen.getByText('There is no content here.')).toBeInTheDocument(); }); }); diff --git a/src/courseware/course/sequence/Unit.test.jsx b/src/courseware/course/sequence/Unit.test.jsx index 16c23c11..6f65251a 100644 --- a/src/courseware/course/sequence/Unit.test.jsx +++ b/src/courseware/course/sequence/Unit.test.jsx @@ -1,50 +1,66 @@ import React from 'react'; -import { cloneDeep } from 'lodash'; +import { Factory } from 'rosie'; import { - initialState, loadUnit, messageEvent, render, screen, waitFor, + initializeTestStore, loadUnit, messageEvent, render, screen, waitFor, } from '../../../setupTest'; import Unit from './Unit'; describe('Unit', () => { - const mockData = { - id: '3', - courseId: '1', - intl: {}, - }; + let mockData; + const courseMetadata = Factory.build( + 'courseMetadata', + { content_type_gating_enabled: true }, + ); + const unitBlocks = [Factory.build( + 'block', + { type: 'problem' }, + { courseId: courseMetadata.id }, + ), Factory.build( + 'block', + { type: 'vertical', graded: true, bookmarked: true }, + { courseId: courseMetadata.id }, + )]; + const [unit, gradedUnit] = unitBlocks; + + beforeAll(async () => { + await initializeTestStore({ courseMetadata, unitBlocks }); + mockData = { + id: unit.id, + courseId: courseMetadata.id, + }; + }); it('renders correctly', () => { - render(, { initialState }); + render(); expect(screen.getByText('Loading learning sequence...')).toBeInTheDocument(); - expect(screen.getByTitle(mockData.id)).toHaveAttribute('height', String(0)); - expect(screen.getByTitle(mockData.id)).toHaveAttribute( + const renderedUnit = screen.getByTitle(unit.display_name); + expect(renderedUnit).toHaveAttribute('height', String(0)); + expect(renderedUnit).toHaveAttribute( 'src', `http://localhost:18000/xblock/${mockData.id}?show_title=0&show_bookmark_button=0`, ); }); it('renders proper message for gated content', () => { - // Clone initialState. - const testState = cloneDeep(initialState); - testState.models.units[mockData.id].graded = true; - render(, { initialState: testState }); + render(); - expect(screen.getByText('Loading locked content messaging...')).toBeInTheDocument(); expect(screen.getByText('Loading learning sequence...')).toBeInTheDocument(); + expect(screen.getByText('Loading locked content messaging...')).toBeInTheDocument(); }); it('handles receiving MessageEvent', async () => { - render(, { initialState }); + render(); loadUnit(); // Loading message is gone now. await waitFor(() => expect(screen.queryByText('Loading learning sequence...')).not.toBeInTheDocument()); // Iframe's height is set via message. - expect(screen.getByTitle(mockData.id)).toHaveAttribute('height', String(messageEvent.payload.height)); + expect(screen.getByTitle(unit.display_name)).toHaveAttribute('height', String(messageEvent.payload.height)); }); it('calls onLoaded after receiving MessageEvent', async () => { const onLoaded = jest.fn(); - render(, { initialState }); + render(); loadUnit(); await waitFor(() => expect(onLoaded).toHaveBeenCalledTimes(1)); @@ -54,24 +70,24 @@ describe('Unit', () => { const onLoaded = jest.fn(); // Clone message and set different height. const testMessageWithOtherHeight = { ...messageEvent, payload: { height: 200 } }; - render(, { initialState }); + render(); loadUnit(); - await waitFor(() => expect(screen.getByTitle(mockData.id)).toHaveAttribute('height', String(messageEvent.payload.height))); + await waitFor(() => expect(screen.getByTitle(unit.display_name)).toHaveAttribute('height', String(messageEvent.payload.height))); window.postMessage(testMessageWithOtherHeight, '*'); - await waitFor(() => expect(screen.getByTitle(mockData.id)).toHaveAttribute('height', String(testMessageWithOtherHeight.payload.height))); + await waitFor(() => expect(screen.getByTitle(unit.display_name)).toHaveAttribute('height', String(testMessageWithOtherHeight.payload.height))); expect(onLoaded).toHaveBeenCalledTimes(1); }); it('ignores MessageEvent with unhandled type', async () => { // Clone message and set different type. const testMessageWithUnhandledType = { ...messageEvent, type: 'wrong type' }; - render(, { initialState }); + render(); window.postMessage(testMessageWithUnhandledType, '*'); // HACK: We don't have a function we could reliably await here, so this test relies on the timeout of `waitFor`. await expect(waitFor( - () => expect(screen.getByTitle(mockData.id)).toHaveAttribute('height', String(testMessageWithUnhandledType.payload.height)), + () => expect(screen.getByTitle(unit.display_name)).toHaveAttribute('height', String(testMessageWithUnhandledType.payload.height)), { timeout: 100 }, )).rejects.toThrowError(/Expected the element to have attribute/); }); diff --git a/src/courseware/course/sequence/sequence-navigation/SequenceNavigation.jsx b/src/courseware/course/sequence/sequence-navigation/SequenceNavigation.jsx index 44ab4f70..c5d38cb8 100644 --- a/src/courseware/course/sequence/sequence-navigation/SequenceNavigation.jsx +++ b/src/courseware/course/sequence/sequence-navigation/SequenceNavigation.jsx @@ -11,6 +11,7 @@ import UnitButton from './UnitButton'; import SequenceNavigationTabs from './SequenceNavigationTabs'; import { useSequenceNavigationMetadata } from './hooks'; import { useModel } from '../../../../generic/model-store'; +import { LOADED } from '../../../data/slice'; export default function SequenceNavigation({ unitId, @@ -22,8 +23,10 @@ export default function SequenceNavigation({ }) { const sequence = useModel('sequences', sequenceId); const { isFirstUnit, isLastUnit } = useSequenceNavigationMetadata(sequenceId, unitId); - const isLocked = sequence.gatedContent !== undefined && sequence.gatedContent.gated; const sequenceStatus = useSelector(state => state.courseware.sequenceStatus); + const isLocked = sequenceStatus === LOADED ? ( + sequence.gatedContent !== undefined && sequence.gatedContent.gated + ) : undefined; const renderUnitButtons = () => { if (isLocked) { @@ -46,7 +49,7 @@ export default function SequenceNavigation({ ); }; - return sequenceStatus === 'loaded' && ( + return sequenceStatus === LOADED && (