diff --git a/src/course-unit/CourseUnit.test.jsx b/src/course-unit/CourseUnit.test.jsx index 8dd56ea40..ca28391ef 100644 --- a/src/course-unit/CourseUnit.test.jsx +++ b/src/course-unit/CourseUnit.test.jsx @@ -305,38 +305,36 @@ describe('', () => { const user = userEvent.setup(); render(); - await waitFor(async () => { - const iframe = screen.getByTitle(xblockContainerIframeMessages.xblockIframeTitle.defaultMessage); - expect(iframe).toHaveAttribute( - 'aria-label', - xblockContainerIframeMessages.xblockIframeLabel.defaultMessage - .replace('{xblockCount}', courseVerticalChildrenMock.children.length), - ); + const iframe = await screen.findByTitle(xblockContainerIframeMessages.xblockIframeTitle.defaultMessage); + expect(iframe).toHaveAttribute( + 'aria-label', + xblockContainerIframeMessages.xblockIframeLabel.defaultMessage + .replace('{xblockCount}', courseVerticalChildrenMock.children.length), + ); - simulatePostMessageEvent(messageTypes.deleteXBlock, { - usageId: courseVerticalChildrenMock.children[0].block_id, - }); - - expect(screen.getByText(/Delete this component?/i)).toBeInTheDocument(); - expect(screen.getByText(/Deleting this component is permanent and cannot be undone./i)).toBeInTheDocument(); - - const dialog = screen.getByRole('dialog'); - expect(dialog).toBeInTheDocument(); - - // Find the Cancel and Delete buttons within the iframe by their specific classes - const cancelButton = await within(dialog).findByRole('button', { name: /Cancel/i }); - const deleteButton = await within(dialog).findByRole('button', { name: /Delete/i }); - - expect(cancelButton).toBeInTheDocument(); - - simulatePostMessageEvent(messageTypes.deleteXBlock, { - usageId: courseVerticalChildrenMock.children[0].block_id, - }); - - expect(screen.getByRole('dialog')).toBeInTheDocument(); - await user.click(deleteButton); + simulatePostMessageEvent(messageTypes.deleteXBlock, { + usageId: courseVerticalChildrenMock.children[0].block_id, }); + expect(await screen.findByText(/Delete this component?/i)).toBeInTheDocument(); + expect(await screen.findByText(/Deleting this component is permanent and cannot be undone./i)).toBeInTheDocument(); + + const dialog = await screen.findByRole('dialog'); + expect(dialog).toBeInTheDocument(); + + // Find the Cancel and Delete buttons within the iframe by their specific classes + const cancelButton = await within(dialog).findByRole('button', { name: /Cancel/i }); + const deleteButton = await within(dialog).findByRole('button', { name: /Delete/i }); + + expect(cancelButton).toBeInTheDocument(); + + simulatePostMessageEvent(messageTypes.deleteXBlock, { + usageId: courseVerticalChildrenMock.children[0].block_id, + }); + + expect(await screen.findByRole('dialog')).toBeInTheDocument(); + await user.click(deleteButton); + axiosMock .onPost(getXBlockBaseApiUrl(blockId), { publish: PUBLISH_TYPES.makePublic, @@ -355,17 +353,17 @@ describe('', () => { }); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); - await waitFor(() => { - // check if the sidebar status is Published and Live - expect(screen.getByText(legacySidebarMessages.sidebarTitlePublishedAndLive.defaultMessage)).toBeInTheDocument(); - expect(screen.getByText( - unitInfoMessages.publishLastPublished.defaultMessage - .replace('{publishedOn}', courseSectionVerticalMock.xblock_info.published_on) - .replace('{publishedBy}', userName), - )).toBeInTheDocument(); - expect(screen.queryByRole('button', { name: legacySidebarMessages.actionButtonPublishTitle.defaultMessage })).not.toBeInTheDocument(); - expect(screen.getByText(unitDisplayName)).toBeInTheDocument(); - }); + // check if the sidebar status is Published and Live + expect(await screen.findByText( + legacySidebarMessages.sidebarTitlePublishedAndLive.defaultMessage, + )).toBeInTheDocument(); + expect(await screen.findByText( + unitInfoMessages.publishLastPublished.defaultMessage + .replace('{publishedOn}', courseSectionVerticalMock.xblock_info.published_on) + .replace('{publishedBy}', userName), + )).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: legacySidebarMessages.actionButtonPublishTitle.defaultMessage })).not.toBeInTheDocument(); + expect(await screen.findByText(unitDisplayName)).toBeInTheDocument(); axiosMock .onDelete(getXBlockBaseApiUrl(courseVerticalChildrenMock.children[0].block_id)) @@ -397,35 +395,34 @@ describe('', () => { .reply(200, courseSectionVerticalMock); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); - await waitFor(() => { - const iframe = screen.getByTitle(xblockContainerIframeMessages.xblockIframeTitle.defaultMessage); - expect(iframe).toHaveAttribute( - 'aria-label', - xblockContainerIframeMessages.xblockIframeLabel.defaultMessage - .replace('{xblockCount}', updatedCourseVerticalChildren.length), - ); - // after removing the xblock, the sidebar status changes to Draft (unpublished changes) - expect(screen.getByText( - legacySidebarMessages.sidebarTitleDraftUnpublishedChanges.defaultMessage, - )).toBeInTheDocument(); - expect(screen.getByText(legacySidebarMessages.releaseStatusTitle.defaultMessage)).toBeInTheDocument(); - expect(screen.getByText(unitInfoMessages.visibilityVisibleToTitle.defaultMessage)).toBeInTheDocument(); - expect(screen.getByText(unitInfoMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument(); - expect(screen.getByText(legacySidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument(); - expect(screen.getByText( - legacySidebarMessages.actionButtonDiscardChangesTitle.defaultMessage, - )).toBeInTheDocument(); - expect(screen.getByText(courseSectionVerticalMock.xblock_info.release_date)).toBeInTheDocument(); - expect(screen.getByText( - unitInfoMessages.publishInfoDraftSaved.defaultMessage - .replace('{editedOn}', courseSectionVerticalMock.xblock_info.edited_on) - .replace('{editedBy}', courseSectionVerticalMock.xblock_info.edited_by), - )).toBeInTheDocument(); - expect(screen.getByText( - legacySidebarMessages.releaseInfoWithSection.defaultMessage - .replace('{sectionName}', courseSectionVerticalMock.xblock_info.release_date_from), - )).toBeInTheDocument(); - }); + expect(await screen.findByTitle( + xblockContainerIframeMessages.xblockIframeTitle.defaultMessage, + )).toHaveAttribute( + 'aria-label', + xblockContainerIframeMessages.xblockIframeLabel.defaultMessage + .replace('{xblockCount}', updatedCourseVerticalChildren.length), + ); + // after removing the xblock, the sidebar status changes to Draft (unpublished changes) + expect(await screen.findByText( + legacySidebarMessages.sidebarTitleDraftUnpublishedChanges.defaultMessage, + )).toBeInTheDocument(); + expect(await screen.findByText(legacySidebarMessages.releaseStatusTitle.defaultMessage)).toBeInTheDocument(); + expect(await screen.findByText(unitInfoMessages.visibilityVisibleToTitle.defaultMessage)).toBeInTheDocument(); + expect(await screen.findByText(unitInfoMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument(); + expect(await screen.findByText(legacySidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument(); + expect(await screen.findByText( + legacySidebarMessages.actionButtonDiscardChangesTitle.defaultMessage, + )).toBeInTheDocument(); + expect(await screen.findByText(courseSectionVerticalMock.xblock_info.release_date)).toBeInTheDocument(); + expect(await screen.findByText( + unitInfoMessages.publishInfoDraftSaved.defaultMessage + .replace('{editedOn}', courseSectionVerticalMock.xblock_info.edited_on) + .replace('{editedBy}', courseSectionVerticalMock.xblock_info.edited_by), + )).toBeInTheDocument(); + expect(await screen.findByText( + legacySidebarMessages.releaseInfoWithSection.defaultMessage + .replace('{sectionName}', courseSectionVerticalMock.xblock_info.release_date_from), + )).toBeInTheDocument(); }); it('checks if the xblock unlink is called when the corresponding unlink button is clicked', async () => { diff --git a/src/generic/upstream-info-icon/UpstreamInfoIcon.scss b/src/generic/upstream-info-icon/UpstreamInfoIcon.scss index f15194984..0f498fc77 100644 --- a/src/generic/upstream-info-icon/UpstreamInfoIcon.scss +++ b/src/generic/upstream-info-icon/UpstreamInfoIcon.scss @@ -45,3 +45,9 @@ height: 18px; } } + +.upstream-info-tooltip { + .tooltip-inner { + background-color: var(--pgn-color-primary-700); + } +} diff --git a/src/generic/upstream-info-icon/UpstreamInfoIcon.test.tsx b/src/generic/upstream-info-icon/UpstreamInfoIcon.test.tsx index ba5efad0a..06b4fa61d 100644 --- a/src/generic/upstream-info-icon/UpstreamInfoIcon.test.tsx +++ b/src/generic/upstream-info-icon/UpstreamInfoIcon.test.tsx @@ -25,8 +25,8 @@ describe('', () => { downstreamCustomized: [], upstreamName: 'Upstream', }); - expect(screen.getByTitle('This item is linked to a library item.')).toBeInTheDocument(); - expect(screen.queryByTitle('The linked library object has updates available.')).not.toBeInTheDocument(); + expect(screen.getByTitle('This item is linked to a library item')).toBeInTheDocument(); + expect(screen.queryByTitle('The linked library object has updates available')).not.toBeInTheDocument(); }); it('should render with broken link', () => { @@ -37,8 +37,8 @@ describe('', () => { downstreamCustomized: [], upstreamName: 'Upstream', }); - expect(screen.getByTitle('This item is linked to a library item.')).toBeInTheDocument(); - expect(screen.getByTitle('The referenced library or library object is not available.')).toBeInTheDocument(); + expect(screen.getByTitle('This item is linked to a library item')).toBeInTheDocument(); + expect(screen.getByTitle('The referenced library or library object is not available')).toBeInTheDocument(); }); it('should render with ready to sync link and opens the sync modal', async () => { @@ -50,9 +50,9 @@ describe('', () => { upstreamName: 'Upstream', }); - const icon = screen.getByTitle('This item is linked to a library item.'); + const icon = screen.getByTitle('This item is linked to a library item'); expect(icon).toBeInTheDocument(); - expect(screen.getByTitle('The linked library object has updates available.')).toBeInTheDocument(); + expect(screen.getByTitle('The linked library object has updates available')).toBeInTheDocument(); fireEvent.click(icon); await waitFor(() => expect(mockOpenSyncModal).toHaveBeenCalled()); @@ -67,8 +67,8 @@ describe('', () => { upstreamName: 'Upstream', }); - expect(screen.getByTitle('This item is linked to a library item.')).toBeInTheDocument(); - expect(screen.getByTitle('This library reference has course overrides applied.')).toBeInTheDocument(); + expect(screen.getByTitle('This item is linked to a library item')).toBeInTheDocument(); + expect(screen.getByTitle('This library reference has course overrides applied')).toBeInTheDocument(); }); it('should render with ready to sync and course overrides', () => { @@ -80,9 +80,9 @@ describe('', () => { upstreamName: 'Upstream', }); - expect(screen.getByTitle('This item is linked to a library item.')).toBeInTheDocument(); - expect(screen.queryByTitle('This library reference has course overrides applied.')).not.toBeInTheDocument(); - expect(screen.getByTitle('The linked library object has updates available.')).toBeInTheDocument(); + expect(screen.getByTitle('This item is linked to a library item')).toBeInTheDocument(); + expect(screen.queryByTitle('This library reference has course overrides applied')).not.toBeInTheDocument(); + expect(screen.getByTitle('The linked library object has updates available')).toBeInTheDocument(); }); it('should render null without upstream', () => { diff --git a/src/generic/upstream-info-icon/index.tsx b/src/generic/upstream-info-icon/index.tsx index ec93a5bd6..80173e5bd 100644 --- a/src/generic/upstream-info-icon/index.tsx +++ b/src/generic/upstream-info-icon/index.tsx @@ -84,7 +84,7 @@ const UpstreamInfoIconContent = ({ key={`upstream-icon-${upstreamInfo.upstreamRef}`} placement="top" overlay={( - + {tooltipMessage} )} diff --git a/src/generic/upstream-info-icon/messages.ts b/src/generic/upstream-info-icon/messages.ts index ac844a64e..63710e4b7 100644 --- a/src/generic/upstream-info-icon/messages.ts +++ b/src/generic/upstream-info-icon/messages.ts @@ -2,27 +2,27 @@ import { defineMessages } from '@edx/frontend-platform/i18n'; const messages = defineMessages({ upstreamLinkOk: { - defaultMessage: 'This item is linked to a library item.', + defaultMessage: 'This item is linked to a library item', id: 'upstream-icon.ok', description: 'Hint and aria-label for the upstream icon when the link is valid.', }, upstreamLinkError: { - defaultMessage: 'The referenced library or library object is not available.', + defaultMessage: 'The referenced library or library object is not available', id: 'upstream-icon.error', description: 'Hint and aria-label for the upstream icon when the link is broken.', }, upstreamLinkReadyToSyncAriaLabel: { - defaultMessage: 'The linked library object has updates available.', + defaultMessage: 'The linked library object has updates available', id: 'upstream-icon.ready-to-sync.aria-label', description: 'Hint and aria-label for the upstream icon when the link is ready to sync.', }, upstreamLinkReadyToSyncTooltip: { - defaultMessage: 'The linked {upstreamName} has updates available.', + defaultMessage: 'The linked {upstreamName} has updates available', id: 'upstream-icon.ready-to-sync.tooltip', description: 'Tooltip text for the upstream icon when the link is ready to sync.', }, upstreamLinkOverridesAriaLabel: { - defaultMessage: 'This library reference has course overrides applied.', + defaultMessage: 'This library reference has course overrides applied', id: 'upstream-icon.course-overrides.aria-label', description: 'Hint and aria-label for the upstream icon when the link has course overrides.', },