= {}) => {
+ rtlRender();
+};
+
+describe('ServiceOwnerSelector', () => {
+ it('renders select with all options', async () => {
+ render();
+
+ const select = screen.getByLabelText(textMock('general.service_owner'));
+ expect(
+ within(select).getByRole('option', { name: defaultProps.user.login }),
+ ).toBeInTheDocument();
+ expect(
+ within(select).getByRole('option', { name: defaultProps.organizations[0].username }),
+ ).toBeInTheDocument();
+ });
+
+ it('shows validation errors', async () => {
+ const errorMessage = 'Field cannot be empty';
+
+ render({ errorMessage });
+
+ expect(screen.getByText(errorMessage)).toBeInTheDocument();
+ });
+
+ it('selects the org when the current context is the org', async () => {
+ const selectedOrgOrUser = defaultProps.organizations[0].username;
+
+ render({ selectedOrgOrUser });
+
+ const select = screen.getByLabelText(textMock('general.service_owner'));
+ expect(select).toHaveValue(selectedOrgOrUser);
+ });
+
+ it('selects the user when the current context is the user', async () => {
+ const selectedOrgOrUser = defaultProps.user.login;
+
+ render({ selectedOrgOrUser });
+
+ const select = screen.getByLabelText(textMock('general.service_owner'));
+ expect(select).toHaveValue(selectedOrgOrUser);
+ });
+
+ it('selects the user when the current context is invalid', async () => {
+ const selectedOrgOrUser = 'all';
+
+ render({ selectedOrgOrUser });
+
+ const select = screen.getByLabelText(textMock('general.service_owner'));
+ expect(select).toHaveValue(defaultProps.user.login);
+ });
+});
diff --git a/frontend/dashboard/components/ServiceOwnerSelector/ServiceOwnerSelector.tsx b/frontend/dashboard/components/ServiceOwnerSelector/ServiceOwnerSelector.tsx
index e597a7f936a..a087f162f81 100644
--- a/frontend/dashboard/components/ServiceOwnerSelector/ServiceOwnerSelector.tsx
+++ b/frontend/dashboard/components/ServiceOwnerSelector/ServiceOwnerSelector.tsx
@@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
import type { Organization } from 'app-shared/types/Organization';
import type { User } from 'app-shared/types/Repository';
-type ServiceOwnerSelectorProps = {
+export type ServiceOwnerSelectorProps = {
selectedOrgOrUser: string;
user: User;
organizations: Organization[];
@@ -26,12 +26,22 @@ export const ServiceOwnerSelector = ({
const selectableOrganizations: SelectableItem[] = mapOrganizationToSelectableItems(organizations);
const selectableOptions: SelectableItem[] = [selectableUser, ...selectableOrganizations];
+ const defaultValue: string =
+ selectableOptions.find((item) => item.value === selectedOrgOrUser)?.value ??
+ selectableUser.value;
+
return (
-
+
{selectableOptions.map(({ value, label }) => (
diff --git a/frontend/dashboard/pages/PageLayout/PageLayout.test.tsx b/frontend/dashboard/pages/PageLayout/PageLayout.test.tsx
new file mode 100644
index 00000000000..0592dfb6435
--- /dev/null
+++ b/frontend/dashboard/pages/PageLayout/PageLayout.test.tsx
@@ -0,0 +1,73 @@
+import React from 'react';
+import { render } from '@testing-library/react';
+import { MockServicesContextWrapper } from '../../dashboardTestUtils';
+import type { ServicesContextProps } from 'app-shared/contexts/ServicesContext';
+import { organization, user } from 'app-shared/mocks/mocks';
+import { PageLayout } from './PageLayout';
+import { createQueryClientMock } from 'app-shared/mocks/queryClientMock';
+import { QueryKey } from 'app-shared/types/QueryKey';
+import { DASHBOARD_ROOT_ROUTE } from 'app-shared/constants';
+import { useParams } from 'react-router-dom';
+import { SelectedContextType } from 'app-shared/navigation/main-header/Header';
+
+const mockedNavigate = jest.fn();
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useNavigate: () => mockedNavigate,
+ useParams: jest.fn(),
+}));
+
+const renderWithMockServices = (services?: Partial) => {
+ const queryClient = createQueryClientMock();
+ queryClient.setQueryData(
+ [QueryKey.Organizations],
+ [
+ {
+ ...organization,
+ username: 'ttd',
+ },
+ ],
+ );
+ queryClient.setQueryData([QueryKey.CurrentUser], user);
+
+ render(
+
+
+ ,
+ );
+};
+
+describe('PageLayout', () => {
+ test('should not redirect to root if context is self', async () => {
+ (useParams as jest.Mock).mockReturnValue({
+ selectedContext: SelectedContextType.Self,
+ });
+ renderWithMockServices();
+ expect(mockedNavigate).not.toHaveBeenCalled();
+ });
+
+ test('should not redirect to root if context is all', async () => {
+ (useParams as jest.Mock).mockReturnValue({
+ selectedContext: SelectedContextType.All,
+ });
+ renderWithMockServices();
+ expect(mockedNavigate).not.toHaveBeenCalled();
+ });
+
+ test('should not redirect to root if user have access to selected context', async () => {
+ (useParams as jest.Mock).mockReturnValue({
+ selectedContext: 'ttd',
+ });
+ renderWithMockServices();
+ expect(mockedNavigate).not.toHaveBeenCalled();
+ });
+
+ test('should redirect to root if user does not have access to selected context', async () => {
+ (useParams as jest.Mock).mockReturnValue({
+ selectedContext: 'test',
+ });
+ renderWithMockServices();
+ expect(mockedNavigate).toHaveBeenCalledTimes(1);
+ expect(mockedNavigate).toHaveBeenCalledWith(DASHBOARD_ROOT_ROUTE);
+ });
+});
diff --git a/frontend/dashboard/pages/PageLayout/PageLayout.tsx b/frontend/dashboard/pages/PageLayout/PageLayout.tsx
index 1601a8e0362..86fc643a37b 100644
--- a/frontend/dashboard/pages/PageLayout/PageLayout.tsx
+++ b/frontend/dashboard/pages/PageLayout/PageLayout.tsx
@@ -7,6 +7,7 @@ import type { IHeaderContext } from 'app-shared/navigation/main-header/Header';
import { userHasAccessToSelectedContext } from '../../utils/userUtils';
import { useSelectedContext } from 'dashboard/hooks/useSelectedContext';
+import { DASHBOARD_ROOT_ROUTE } from 'app-shared/constants';
export const PageLayout = () => {
const { data: user } = useUserQuery();
@@ -20,7 +21,7 @@ export const PageLayout = () => {
organizations &&
!userHasAccessToSelectedContext({ selectedContext, orgs: organizations })
) {
- navigate('/');
+ navigate(DASHBOARD_ROOT_ROUTE);
}
}, [organizations, selectedContext, user.login, navigate]);
diff --git a/frontend/packages/shared/src/constants.js b/frontend/packages/shared/src/constants.js
index 05288400180..a5725a3317f 100644
--- a/frontend/packages/shared/src/constants.js
+++ b/frontend/packages/shared/src/constants.js
@@ -1,5 +1,7 @@
+// TODO: Extract/Centralize react-router routes (https://github.com/Altinn/altinn-studio/issues/12624)
export const APP_DEVELOPMENT_BASENAME = '/editor';
export const DASHBOARD_BASENAME = '/dashboard';
+export const DASHBOARD_ROOT_ROUTE = '/';
export const RESOURCEADM_BASENAME = '/resourceadm';
export const PREVIEW_BASENAME = '/preview';
export const STUDIO_ROOT_BASENAME = '/';