- Changes in the Unit sidebar context to enable selected components - Implements the component info sidebar. - Implements the container/component selection when opening the align sidebar
260 lines
7.8 KiB
TypeScript
260 lines
7.8 KiB
TypeScript
import { getXBlockApiUrl } from '@src/course-outline/data/api';
|
|
import { render, screen, initializeMocks } from '@src/testUtils';
|
|
import { userEvent } from '@testing-library/user-event';
|
|
import { LibraryReferenceCard } from './LibraryReferenceCard';
|
|
|
|
let axiosMock;
|
|
const upstreamData = {
|
|
id: 'lct:UNIX:CIT1:subsection:99d7e14e2d6f4ab7989dc0d948f917df',
|
|
name: 'upstream subsection',
|
|
};
|
|
const sectionData = {
|
|
id: 'block-v1:UNIX+UX1+2025_T3+type@chapter+block@asafd',
|
|
displayName: 'downstream section',
|
|
upstreamInfo: {
|
|
upstreamRef: 'lct:UNIX:CIT1:section:d12323',
|
|
upstreamName: 'upstream section',
|
|
downstreamKey: 'block-v1:UNIX+UX1+2025_T3+type@chapter+block@asafd',
|
|
versionAvailable: 2,
|
|
versionDeclined: null,
|
|
readyToSync: false,
|
|
topLevelParentKey: null,
|
|
downstreamCustomized: [],
|
|
},
|
|
};
|
|
const itemData = {
|
|
id: 'block-v1:UNIX+UX1+2025_T3+type@sequential+block@sequential45d4d95a',
|
|
displayName: 'downstream subsection',
|
|
upstreamInfo: {
|
|
upstreamRef: upstreamData.id,
|
|
upstreamName: upstreamData.name,
|
|
downstreamKey: 'block-v1:UNIX+UX1+2025_T3+type@sequential+block@sequential45d4d95a',
|
|
versionAvailable: 2,
|
|
versionDeclined: null,
|
|
readyToSync: false,
|
|
topLevelParentKey: null,
|
|
downstreamCustomized: [],
|
|
},
|
|
};
|
|
|
|
const mockUseCourseAuthoringContext = jest.fn().mockReturnValue({
|
|
openUnlinkModal: jest.fn(),
|
|
courseId: 'course1',
|
|
});
|
|
|
|
jest.mock('@src/CourseAuthoringContext', () => ({
|
|
useCourseAuthoringContext: () => mockUseCourseAuthoringContext(),
|
|
}));
|
|
const mockPostChange = jest.fn();
|
|
const mockOpenContainerInfoSidebar = jest.fn();
|
|
const mockOpenSyncModal = jest.fn();
|
|
jest.mock('@src/hooks', () => ({
|
|
useToggleWithValue: () => [false, {}, mockOpenSyncModal, jest.fn()],
|
|
}));
|
|
|
|
describe('LibraryReferenceCard', () => {
|
|
beforeEach(() => {
|
|
const mocks = initializeMocks();
|
|
axiosMock = mocks.axiosMock;
|
|
axiosMock
|
|
.onGet(getXBlockApiUrl(sectionData.id))
|
|
.reply(200, sectionData);
|
|
axiosMock
|
|
.onGet(getXBlockApiUrl(itemData.id))
|
|
.reply(200, itemData);
|
|
});
|
|
|
|
it('renders the LibraryReferenceCard normally', async () => {
|
|
render(
|
|
<LibraryReferenceCard
|
|
itemId={itemData.id}
|
|
sectionId={sectionData.id}
|
|
postChange={mockPostChange}
|
|
goToParent={mockOpenContainerInfoSidebar}
|
|
/>,
|
|
);
|
|
expect(await screen.findByText(/Library Reference/)).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders the LibraryReferenceCard error message', async () => {
|
|
const user = userEvent.setup();
|
|
const data = {
|
|
...itemData,
|
|
upstreamInfo: {
|
|
...itemData.upstreamInfo,
|
|
errorMessage: 'some error',
|
|
},
|
|
};
|
|
axiosMock
|
|
.onGet(getXBlockApiUrl(itemData.id))
|
|
.reply(200, data);
|
|
render(
|
|
<LibraryReferenceCard
|
|
itemId={itemData.id}
|
|
sectionId={sectionData.id}
|
|
postChange={mockPostChange}
|
|
goToParent={mockOpenContainerInfoSidebar}
|
|
/>,
|
|
);
|
|
expect(await screen.findByText(
|
|
`The link between ${itemData.displayName} and the library version has been broken. To edit or make changes, unlink component.`,
|
|
)).toBeInTheDocument();
|
|
|
|
await user.click(await screen.findByRole('button', { name: 'Unlink from library' }));
|
|
expect(mockUseCourseAuthoringContext().openUnlinkModal).toHaveBeenCalledWith({
|
|
value: data,
|
|
sectionId: sectionData.id,
|
|
});
|
|
});
|
|
|
|
it('renders the LibraryReferenceCard ready to sync', async () => {
|
|
const user = userEvent.setup();
|
|
axiosMock
|
|
.onGet(getXBlockApiUrl(itemData.id))
|
|
.reply(200, {
|
|
...itemData,
|
|
upstreamInfo: {
|
|
...itemData.upstreamInfo,
|
|
readyToSync: true,
|
|
},
|
|
});
|
|
render(
|
|
<LibraryReferenceCard
|
|
itemId={itemData.id}
|
|
sectionId={sectionData.id}
|
|
postChange={mockPostChange}
|
|
goToParent={mockOpenContainerInfoSidebar}
|
|
/>,
|
|
);
|
|
expect(await screen.findByText(
|
|
`${itemData.displayName} has available updates`,
|
|
)).toBeInTheDocument();
|
|
|
|
await user.click(await screen.findByRole('button', { name: 'Review Updates' }));
|
|
expect(mockOpenSyncModal).toHaveBeenCalled();
|
|
});
|
|
|
|
it('renders the LibraryReferenceCard customized text', async () => {
|
|
axiosMock
|
|
.onGet(getXBlockApiUrl(itemData.id))
|
|
.reply(200, {
|
|
...itemData,
|
|
upstreamInfo: {
|
|
...itemData.upstreamInfo,
|
|
downstreamCustomized: ['displayName'],
|
|
},
|
|
});
|
|
render(
|
|
<LibraryReferenceCard
|
|
itemId={itemData.id}
|
|
sectionId={sectionData.id}
|
|
postChange={mockPostChange}
|
|
goToParent={mockOpenContainerInfoSidebar}
|
|
/>,
|
|
);
|
|
expect(await screen.findByText(
|
|
`${itemData.displayName} has been modified in this course.`,
|
|
)).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders the LibraryReferenceCard with top level error message', async () => {
|
|
const user = userEvent.setup();
|
|
axiosMock
|
|
.onGet(getXBlockApiUrl(itemData.id))
|
|
.reply(200, {
|
|
...itemData,
|
|
upstreamInfo: {
|
|
...itemData.upstreamInfo,
|
|
topLevelParentKey: sectionData.upstreamInfo.downstreamKey,
|
|
errorMessage: 'some error',
|
|
},
|
|
});
|
|
render(
|
|
<LibraryReferenceCard
|
|
itemId={itemData.id}
|
|
sectionId={sectionData.id}
|
|
postChange={mockPostChange}
|
|
goToParent={mockOpenContainerInfoSidebar}
|
|
/>,
|
|
);
|
|
expect(await screen.findByText(
|
|
`${itemData.displayName} was reused as part of a section which has a broken link. To recieve library updates to this component, unlink the broken link.`,
|
|
)).toBeInTheDocument();
|
|
|
|
await user.click(await screen.findByRole('button', { name: 'Unlink section' }));
|
|
// should call unlink with parent section data
|
|
expect(mockUseCourseAuthoringContext().openUnlinkModal).toHaveBeenCalledWith({
|
|
value: sectionData,
|
|
sectionId: sectionData.id,
|
|
});
|
|
});
|
|
|
|
it('renders the LibraryReferenceCard with top level ready to sync', async () => {
|
|
const user = userEvent.setup();
|
|
axiosMock
|
|
.onGet(getXBlockApiUrl(itemData.id))
|
|
.reply(200, {
|
|
...itemData,
|
|
upstreamInfo: {
|
|
...itemData.upstreamInfo,
|
|
topLevelParentKey: sectionData.upstreamInfo.downstreamKey,
|
|
},
|
|
});
|
|
const parentData = {
|
|
...sectionData,
|
|
upstreamInfo: {
|
|
...sectionData.upstreamInfo,
|
|
readyToSync: true,
|
|
},
|
|
};
|
|
axiosMock
|
|
.onGet(getXBlockApiUrl(sectionData.id))
|
|
.reply(200, parentData);
|
|
render(
|
|
<LibraryReferenceCard
|
|
itemId={itemData.id}
|
|
sectionId={sectionData.id}
|
|
postChange={mockPostChange}
|
|
goToParent={mockOpenContainerInfoSidebar}
|
|
/>,
|
|
);
|
|
expect(await screen.findByText(
|
|
`${itemData.displayName} was reused as part of a section which has updates available.`,
|
|
)).toBeInTheDocument();
|
|
|
|
await user.click(await screen.findByRole('button', { name: 'Review Updates' }));
|
|
expect(mockOpenSyncModal).toHaveBeenCalledWith(parentData);
|
|
});
|
|
|
|
it('renders the LibraryReferenceCard with top level go to parent option', async () => {
|
|
const user = userEvent.setup();
|
|
axiosMock
|
|
.onGet(getXBlockApiUrl(itemData.id))
|
|
.reply(200, {
|
|
...itemData,
|
|
upstreamInfo: {
|
|
...itemData.upstreamInfo,
|
|
topLevelParentKey: sectionData.upstreamInfo.downstreamKey,
|
|
},
|
|
});
|
|
render(
|
|
<LibraryReferenceCard
|
|
itemId={itemData.id}
|
|
sectionId={sectionData.id}
|
|
postChange={mockPostChange}
|
|
goToParent={mockOpenContainerInfoSidebar}
|
|
/>,
|
|
);
|
|
expect(await screen.findByText(
|
|
`${itemData.displayName} was reused as part of a section.`,
|
|
)).toBeInTheDocument();
|
|
|
|
await user.click(await screen.findByRole('button', { name: 'View section' }));
|
|
expect(mockOpenContainerInfoSidebar).toHaveBeenCalledWith(
|
|
sectionData.id,
|
|
undefined,
|
|
sectionData.id,
|
|
);
|
|
});
|
|
});
|