Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb7774b325 | ||
|
|
3e4eb21d8c |
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
@@ -9,9 +9,6 @@ on:
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node: [18, 20]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -20,7 +17,7 @@ jobs:
|
||||
- name: Setup Nodejs
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Validate package-lock.json changes
|
||||
|
||||
3
package-lock.json
generated
3
package-lock.json
generated
@@ -49,7 +49,8 @@
|
||||
"@openedx/paragon": ">= 21.5.7 < 23.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^16.9.0 || ^17.0.0",
|
||||
"react-dom": "^16.9.0 || ^17.0.0"
|
||||
"react-dom": "^16.9.0 || ^17.0.0",
|
||||
"react-router-dom": "^6.14.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@adobe/css-tools": {
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
"@openedx/paragon": ">= 21.5.7 < 23.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^16.9.0 || ^17.0.0",
|
||||
"react-dom": "^16.9.0 || ^17.0.0"
|
||||
"react-dom": "^16.9.0 || ^17.0.0",
|
||||
"react-router-dom": "^6.14.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const BrandNav = ({
|
||||
studioBaseUrl,
|
||||
logo,
|
||||
logoAltText,
|
||||
}) => (
|
||||
<a href={studioBaseUrl}>
|
||||
<Link to={studioBaseUrl}>
|
||||
<img
|
||||
src={logo}
|
||||
alt={logoAltText}
|
||||
className="d-block logo"
|
||||
/>
|
||||
</a>
|
||||
</Link>
|
||||
);
|
||||
|
||||
BrandNav.propTypes = {
|
||||
|
||||
40
src/studio-header/BrandNav.test.jsx
Normal file
40
src/studio-header/BrandNav.test.jsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import BrandNav from './BrandNav';
|
||||
|
||||
const studioBaseUrl = 'https://example.com/';
|
||||
const logo = 'logo.png';
|
||||
const logoAltText = 'Example Logo';
|
||||
|
||||
const RootWrapper = () => (
|
||||
<MemoryRouter>
|
||||
<BrandNav
|
||||
studioBaseUrl={studioBaseUrl}
|
||||
logo={logo}
|
||||
logoAltText={logoAltText}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
describe('BrandNav Component', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders the logo with the correct alt text', () => {
|
||||
render(<RootWrapper />);
|
||||
|
||||
const img = screen.getByAltText(logoAltText);
|
||||
expect(img).toHaveAttribute('src', logo);
|
||||
});
|
||||
|
||||
it('displays a link that navigates to studioBaseUrl', () => {
|
||||
render(<RootWrapper />);
|
||||
|
||||
const link = screen.getByRole('link');
|
||||
expect(link.href).toBe(studioBaseUrl);
|
||||
});
|
||||
});
|
||||
@@ -5,6 +5,8 @@ import {
|
||||
OverlayTrigger,
|
||||
Tooltip,
|
||||
} from '@openedx/paragon';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
const CourseLockUp = ({
|
||||
@@ -23,15 +25,15 @@ const CourseLockUp = ({
|
||||
</Tooltip>
|
||||
)}
|
||||
>
|
||||
<a
|
||||
<Link
|
||||
className="course-title-lockup mr-2"
|
||||
href={outlineLink}
|
||||
to={outlineLink}
|
||||
aria-label={intl.formatMessage(messages['header.label.courseOutline'])}
|
||||
data-testid="course-lock-up-block"
|
||||
>
|
||||
<span className="d-block small m-0 text-gray-800" data-testid="course-org-number">{org} {number}</span>
|
||||
<span className="d-block m-0 font-weight-bold text-gray-800" data-testid="course-title">{title}</span>
|
||||
</a>
|
||||
</Link>
|
||||
</OverlayTrigger>
|
||||
);
|
||||
|
||||
|
||||
58
src/studio-header/CourseLockUp.test.jsx
Normal file
58
src/studio-header/CourseLockUp.test.jsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import CourseLockUp from './CourseLockUp';
|
||||
import messages from './messages';
|
||||
|
||||
const mockProps = {
|
||||
number: '101',
|
||||
org: 'EDX',
|
||||
title: 'Course Title',
|
||||
outlineLink: 'https://example.com/course-outline',
|
||||
};
|
||||
|
||||
const RootWrapper = (props) => (
|
||||
<MemoryRouter>
|
||||
<IntlProvider locale="en" messages={messages}>
|
||||
<CourseLockUp {...props} />
|
||||
</IntlProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
describe('CourseLockUp Component', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders course org, number, and title', () => {
|
||||
render(<RootWrapper {...mockProps} />);
|
||||
|
||||
const courseOrgNumber = screen.getByTestId('course-org-number');
|
||||
const courseTitle = screen.getByTestId('course-title');
|
||||
|
||||
expect(courseOrgNumber).toBeInTheDocument();
|
||||
expect(courseOrgNumber).toHaveTextContent(`${mockProps.org} ${mockProps.number}`);
|
||||
expect(courseTitle).toBeInTheDocument();
|
||||
expect(courseTitle).toHaveTextContent(mockProps.title);
|
||||
});
|
||||
|
||||
it('renders the link with correct aria-label', () => {
|
||||
render(<RootWrapper {...mockProps} />);
|
||||
|
||||
const link = screen.getByTestId('course-lock-up-block');
|
||||
expect(link).toHaveAttribute(
|
||||
'aria-label',
|
||||
messages['header.label.courseOutline'].defaultMessage,
|
||||
);
|
||||
});
|
||||
|
||||
it('navigates to an absolute URL when clicked', () => {
|
||||
render(<RootWrapper {...mockProps} />);
|
||||
|
||||
const link = screen.getByTestId('course-lock-up-block');
|
||||
expect(link.href).toBe(mockProps.outlineLink);
|
||||
});
|
||||
});
|
||||
@@ -103,7 +103,12 @@ const HeaderBody = ({
|
||||
{mainMenuDropdowns.map(dropdown => {
|
||||
const { id, buttonTitle, items } = dropdown;
|
||||
return (
|
||||
<NavDropdownMenu key={id} {...{ id, buttonTitle, items }} />
|
||||
<NavDropdownMenu
|
||||
key={id}
|
||||
{...{
|
||||
id, buttonTitle, items,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Nav>
|
||||
|
||||
102
src/studio-header/HeaderBody.test.jsx
Normal file
102
src/studio-header/HeaderBody.test.jsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import HeaderBody from './HeaderBody';
|
||||
import messages from './messages';
|
||||
|
||||
const mockOnNavigate = jest.fn();
|
||||
const mockSearchButtonAction = jest.fn();
|
||||
const mockToggleModalPopup = jest.fn();
|
||||
const mockSetModalPopupTarget = jest.fn();
|
||||
|
||||
const defaultProps = {
|
||||
studioBaseUrl: 'https://example.com',
|
||||
logoutUrl: 'https://example.com/logout',
|
||||
onNavigate: mockOnNavigate,
|
||||
setModalPopupTarget: mockSetModalPopupTarget,
|
||||
toggleModalPopup: mockToggleModalPopup,
|
||||
searchButtonAction: mockSearchButtonAction,
|
||||
username: 'testuser',
|
||||
authenticatedUserAvatar: 'avatar.png',
|
||||
isAdmin: true,
|
||||
isMobile: false,
|
||||
isHiddenMainMenu: false,
|
||||
mainMenuDropdowns: [],
|
||||
logo: 'logo.png',
|
||||
logoAltText: 'Test Logo',
|
||||
number: '101',
|
||||
org: 'EDX',
|
||||
title: 'Test Course',
|
||||
outlineLink: '/courses/edx/course-101',
|
||||
};
|
||||
|
||||
const RootWrapper = (props) => (
|
||||
<MemoryRouter>
|
||||
<IntlProvider locale="en" messages={messages}>
|
||||
<HeaderBody {...props} />
|
||||
</IntlProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
describe('HeaderBody Component', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders the logo and brand navigation', () => {
|
||||
render(<RootWrapper {...defaultProps} />);
|
||||
|
||||
const logoImage = screen.getByAltText(defaultProps.logoAltText);
|
||||
expect(logoImage).toBeInTheDocument();
|
||||
expect(logoImage).toHaveAttribute('src', defaultProps.logo);
|
||||
});
|
||||
|
||||
it('renders course lockup information', () => {
|
||||
render(<RootWrapper {...defaultProps} />);
|
||||
|
||||
const courseTitle = screen.getByText(defaultProps.title);
|
||||
const courseOrgNumber = screen.getByText(`${defaultProps.org} ${defaultProps.number}`);
|
||||
|
||||
expect(courseTitle).toBeInTheDocument();
|
||||
expect(courseOrgNumber).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders a course lock-up link with the correct outline URL', () => {
|
||||
render(<RootWrapper {...defaultProps} />);
|
||||
|
||||
const courseLockUpLink = screen.getByTestId('course-lock-up-block');
|
||||
expect(courseLockUpLink.getAttribute('href')).toBe(defaultProps.outlineLink);
|
||||
});
|
||||
|
||||
it('displays search button and triggers searchButtonAction on click', () => {
|
||||
render(<RootWrapper {...defaultProps} />);
|
||||
|
||||
const searchButton = screen.getByLabelText(messages['header.label.search.nav'].defaultMessage);
|
||||
expect(searchButton).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(searchButton);
|
||||
expect(mockSearchButtonAction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('displays user menu with username and avatar', () => {
|
||||
render(<RootWrapper {...defaultProps} />);
|
||||
|
||||
const userMenu = screen.getByText(defaultProps.username);
|
||||
const avatarImage = screen.getByAltText(defaultProps.username);
|
||||
|
||||
expect(userMenu).toBeInTheDocument();
|
||||
expect(avatarImage).toHaveAttribute('src', defaultProps.authenticatedUserAvatar);
|
||||
});
|
||||
|
||||
it('toggles mobile menu popup when button is clicked in mobile view', () => {
|
||||
render(<RootWrapper {...defaultProps} isMobile isModalPopupOpen={false} />);
|
||||
|
||||
const menuButton = screen.getByTestId('mobile-menu-button');
|
||||
fireEvent.click(menuButton);
|
||||
|
||||
expect(mockToggleModalPopup).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -1,10 +1,9 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Collapsible } from '@openedx/paragon';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const MobileMenu = ({
|
||||
mainMenuDropdowns,
|
||||
}) => (
|
||||
const MobileMenu = ({ mainMenuDropdowns }) => (
|
||||
<div
|
||||
className="ml-4 p-2 bg-light-100 border border-gray-200 small rounded"
|
||||
data-testid="mobile-menu"
|
||||
@@ -21,9 +20,9 @@ const MobileMenu = ({
|
||||
<ul className="p-0" style={{ listStyleType: 'none' }}>
|
||||
{items.map(item => (
|
||||
<li className="mobile-menu-item">
|
||||
<a href={item.href}>
|
||||
<Link to={item.href}>
|
||||
{item.title}
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
81
src/studio-header/MobileMenu.test.jsx
Normal file
81
src/studio-header/MobileMenu.test.jsx
Normal file
@@ -0,0 +1,81 @@
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import MobileMenu from './MobileMenu';
|
||||
|
||||
const mockOnNavigate = jest.fn();
|
||||
|
||||
const defaultProps = {
|
||||
mainMenuDropdowns: [
|
||||
{
|
||||
id: 'menu1',
|
||||
buttonTitle: 'Menu 1',
|
||||
items: [
|
||||
{ href: '/menu1/item1', title: 'Item 1' },
|
||||
{ href: '/menu1/item2', title: 'Item 2' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'menu2',
|
||||
buttonTitle: 'Menu 2',
|
||||
items: [
|
||||
{ href: 'https://external-link.com', title: 'External Link' },
|
||||
],
|
||||
},
|
||||
],
|
||||
onNavigate: mockOnNavigate,
|
||||
};
|
||||
|
||||
const RootWrapper = (props) => (
|
||||
<MemoryRouter>
|
||||
<MobileMenu {...props} />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
describe('MobileMenu Component', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('renders the mobile menu with dropdowns and items', () => {
|
||||
render(<RootWrapper {...defaultProps} />);
|
||||
|
||||
const menu1Title = screen.getByText('Menu 1');
|
||||
const menu2Title = screen.getByText('Menu 2');
|
||||
|
||||
expect(menu1Title).toBeInTheDocument();
|
||||
expect(menu2Title).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('navigates to internal URL when item is clicked', () => {
|
||||
render(<RootWrapper {...defaultProps} />);
|
||||
|
||||
const menu1Title = screen.getByText(defaultProps.mainMenuDropdowns[0].buttonTitle);
|
||||
fireEvent.click(menu1Title);
|
||||
|
||||
const menuItem = screen.getByText(defaultProps.mainMenuDropdowns[0].items[0].title);
|
||||
expect(menuItem.getAttribute('href')).toBe(defaultProps.mainMenuDropdowns[0].items[0].href);
|
||||
});
|
||||
|
||||
test('navigates to an external URL when external link is clicked', () => {
|
||||
render(<RootWrapper {...defaultProps} />);
|
||||
|
||||
const menu2Title = screen.getByText(defaultProps.mainMenuDropdowns[1].buttonTitle);
|
||||
fireEvent.click(menu2Title);
|
||||
|
||||
const externalLink = screen.getByText(defaultProps.mainMenuDropdowns[1].items[0].title);
|
||||
expect(externalLink.getAttribute('href')).toBe(defaultProps.mainMenuDropdowns[1].items[0].href);
|
||||
});
|
||||
|
||||
test('renders empty state when there are no dropdowns', () => {
|
||||
render(<RootWrapper mainMenuDropdowns={[]} onNavigate={mockOnNavigate} />);
|
||||
|
||||
const mobileMenu = screen.getByTestId('mobile-menu');
|
||||
expect(mobileMenu).toBeInTheDocument();
|
||||
|
||||
const menuItems = screen.queryAllByRole('listitem');
|
||||
expect(menuItems.length).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
Dropdown,
|
||||
DropdownButton,
|
||||
} from '@openedx/paragon';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const NavDropdownMenu = ({
|
||||
id,
|
||||
@@ -18,8 +19,9 @@ const NavDropdownMenu = ({
|
||||
>
|
||||
{items.map(item => (
|
||||
<Dropdown.Item
|
||||
as={Link}
|
||||
key={`${item.title}-dropdown-item`}
|
||||
href={item.href}
|
||||
to={item.href}
|
||||
className="small"
|
||||
>
|
||||
{item.title}
|
||||
@@ -32,8 +34,8 @@ NavDropdownMenu.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
buttonTitle: PropTypes.node.isRequired,
|
||||
items: PropTypes.arrayOf(PropTypes.shape({
|
||||
href: PropTypes.string,
|
||||
title: PropTypes.node,
|
||||
href: PropTypes.string.isRequired,
|
||||
title: PropTypes.node.isRequired,
|
||||
})).isRequired,
|
||||
};
|
||||
|
||||
|
||||
67
src/studio-header/NavDropdownMenu.test.jsx
Normal file
67
src/studio-header/NavDropdownMenu.test.jsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import NavDropdownMenu from './NavDropdownMenu';
|
||||
|
||||
const defaultProps = {
|
||||
id: 'menu-id',
|
||||
buttonTitle: 'Menu',
|
||||
items: [
|
||||
{ href: '/item1', title: 'Item 1' },
|
||||
{ href: 'https://external.com', title: 'External Link' },
|
||||
],
|
||||
};
|
||||
|
||||
const RootWrapper = (props) => (
|
||||
<MemoryRouter>
|
||||
<NavDropdownMenu {...props} />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
describe('NavDropdownMenu Component', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('renders the dropdown button with correct title', () => {
|
||||
render(<NavDropdownMenu {...defaultProps} />);
|
||||
|
||||
const dropdownButton = screen.getByRole('button', { name: defaultProps.buttonTitle });
|
||||
expect(dropdownButton).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('renders all dropdown items', () => {
|
||||
render(<RootWrapper {...defaultProps} />);
|
||||
|
||||
const dropdownButton = screen.getByRole('button', { name: defaultProps.buttonTitle });
|
||||
fireEvent.click(dropdownButton);
|
||||
|
||||
const item1 = screen.getByText(defaultProps.items[0].title);
|
||||
const externalLink = screen.getByText(defaultProps.items[1].title);
|
||||
|
||||
expect(item1).toBeInTheDocument();
|
||||
expect(externalLink).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('calls onNavigate with the correct URL for internal link', () => {
|
||||
render(<RootWrapper {...defaultProps} />);
|
||||
|
||||
const dropdownButton = screen.getByRole('button', { name: defaultProps.buttonTitle });
|
||||
fireEvent.click(dropdownButton);
|
||||
|
||||
const item1 = screen.getByText(defaultProps.items[0].title);
|
||||
expect(item1.getAttribute('href')).toBe(defaultProps.items[0].href);
|
||||
});
|
||||
|
||||
test('navigates to external URL when external link is clicked', () => {
|
||||
render(<RootWrapper {...defaultProps} />);
|
||||
|
||||
const dropdownButton = screen.getByRole('button', { name: defaultProps.buttonTitle });
|
||||
fireEvent.click(dropdownButton);
|
||||
|
||||
const externalLink = screen.getByText(defaultProps.items[1].title);
|
||||
expect(externalLink.getAttribute('href')).toBe(defaultProps.items[1].href);
|
||||
});
|
||||
});
|
||||
@@ -16,7 +16,8 @@ ensureConfig([
|
||||
], 'Studio Header component');
|
||||
|
||||
const StudioHeader = ({
|
||||
number, org, title, containerProps, isHiddenMainMenu, mainMenuDropdowns, outlineLink, searchButtonAction,
|
||||
number, org, title, containerProps, isHiddenMainMenu, mainMenuDropdowns,
|
||||
outlineLink, searchButtonAction, isNewHomePage,
|
||||
}) => {
|
||||
const { authenticatedUser, config } = useContext(AppContext);
|
||||
const props = {
|
||||
@@ -29,7 +30,7 @@ const StudioHeader = ({
|
||||
username: authenticatedUser?.username,
|
||||
isAdmin: authenticatedUser?.administrator,
|
||||
authenticatedUserAvatar: authenticatedUser?.avatar,
|
||||
studioBaseUrl: config.STUDIO_BASE_URL,
|
||||
studioBaseUrl: isNewHomePage ? '/home' : config.STUDIO_BASE_URL,
|
||||
logoutUrl: config.LOGOUT_URL,
|
||||
isHiddenMainMenu,
|
||||
mainMenuDropdowns,
|
||||
@@ -66,6 +67,7 @@ StudioHeader.propTypes = {
|
||||
})),
|
||||
outlineLink: PropTypes.string,
|
||||
searchButtonAction: PropTypes.func,
|
||||
isNewHomePage: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
StudioHeader.defaultProps = {
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import { AppContext } from '@edx/frontend-platform/react';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { Context as ResponsiveContext } from 'react-responsive';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import StudioHeader from './StudioHeader';
|
||||
import messages from './messages';
|
||||
@@ -40,15 +41,17 @@ const RootWrapper = ({
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line react/jsx-no-constructed-context-values, react/prop-types
|
||||
<IntlProvider locale="en">
|
||||
<AppContext.Provider value={appContextValue}>
|
||||
<ResponsiveContext.Provider value={responsiveContextValue}>
|
||||
<StudioHeader
|
||||
{...props}
|
||||
/>
|
||||
</ResponsiveContext.Provider>
|
||||
</AppContext.Provider>
|
||||
</IntlProvider>
|
||||
<MemoryRouter>
|
||||
<IntlProvider locale="en">
|
||||
<AppContext.Provider value={appContextValue}>
|
||||
<ResponsiveContext.Provider value={responsiveContextValue}>
|
||||
<StudioHeader
|
||||
{...props}
|
||||
/>
|
||||
</ResponsiveContext.Provider>
|
||||
</AppContext.Provider>
|
||||
</IntlProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -70,6 +73,7 @@ const props = {
|
||||
],
|
||||
outlineLink: 'tEsTLInK',
|
||||
searchButtonAction: null,
|
||||
isNewHomePage: true,
|
||||
};
|
||||
|
||||
describe('Header', () => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import messages from './messages';
|
||||
|
||||
const getUserMenuItems = ({
|
||||
@@ -21,7 +22,7 @@ const getUserMenuItems = ({
|
||||
href: `${studioBaseUrl}`,
|
||||
title: intl.formatMessage(messages['header.user.menu.studio']),
|
||||
}, {
|
||||
href: `${studioBaseUrl}/maintenance`,
|
||||
href: `${getConfig().STUDIO_BASE_URL}/maintenance`,
|
||||
title: intl.formatMessage(messages['header.user.menu.maintenance']),
|
||||
}, {
|
||||
href: `${logoutUrl}`,
|
||||
|
||||
Reference in New Issue
Block a user