mirror of https://github.com/portainer/portainer
				
				
				
			refactor(tests): wrap tests explicitly with provider [EE-6686] (#11090)
							parent
							
								
									27aaf322b2
								
							
						
					
					
						commit
						f8e3d75797
					
				| 
						 | 
					@ -45,6 +45,12 @@ rules:
 | 
				
			||||||
        pathGroupsExcludedImportTypes: ['internal'],
 | 
					        pathGroupsExcludedImportTypes: ['internal'],
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					  no-restricted-imports:
 | 
				
			||||||
 | 
					    - error
 | 
				
			||||||
 | 
					    - patterns:
 | 
				
			||||||
 | 
					        - group:
 | 
				
			||||||
 | 
					            - '@/react/test-utils/*'
 | 
				
			||||||
 | 
					          message: 'These utils are just for test files'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
settings:
 | 
					settings:
 | 
				
			||||||
  'import/resolver':
 | 
					  'import/resolver':
 | 
				
			||||||
| 
						 | 
					@ -113,6 +119,12 @@ overrides:
 | 
				
			||||||
      'no-await-in-loop': 'off'
 | 
					      'no-await-in-loop': 'off'
 | 
				
			||||||
      'react/jsx-no-useless-fragment': ['error', { allowExpressions: true }]
 | 
					      'react/jsx-no-useless-fragment': ['error', { allowExpressions: true }]
 | 
				
			||||||
      'regex/invalid': ['error', [{ 'regex': '<Icon icon="(.*)"', 'message': 'Please directly import the `lucide-react` icon instead of using the string' }]]
 | 
					      'regex/invalid': ['error', [{ 'regex': '<Icon icon="(.*)"', 'message': 'Please directly import the `lucide-react` icon instead of using the string' }]]
 | 
				
			||||||
 | 
					      '@typescript-eslint/no-restricted-imports':
 | 
				
			||||||
 | 
					        - error
 | 
				
			||||||
 | 
					        - patterns:
 | 
				
			||||||
 | 
					            - group:
 | 
				
			||||||
 | 
					                - '@/react/test-utils/*'
 | 
				
			||||||
 | 
					              message: 'These utils are just for test files'
 | 
				
			||||||
    overrides: # allow props spreading for hoc files
 | 
					    overrides: # allow props spreading for hoc files
 | 
				
			||||||
      - files:
 | 
					      - files:
 | 
				
			||||||
          - app/**/with*.ts{,x}
 | 
					          - app/**/with*.ts{,x}
 | 
				
			||||||
| 
						 | 
					@ -126,7 +138,11 @@ overrides:
 | 
				
			||||||
      'vitest/env': true
 | 
					      'vitest/env': true
 | 
				
			||||||
    rules:
 | 
					    rules:
 | 
				
			||||||
      'react/jsx-no-constructed-context-values': off
 | 
					      'react/jsx-no-constructed-context-values': off
 | 
				
			||||||
 | 
					      '@typescript-eslint/no-restricted-imports': off
 | 
				
			||||||
 | 
					      no-restricted-imports: off
 | 
				
			||||||
  - files:
 | 
					  - files:
 | 
				
			||||||
      - app/**/*.stories.*
 | 
					      - app/**/*.stories.*
 | 
				
			||||||
    rules:
 | 
					    rules:
 | 
				
			||||||
      'no-alert': off
 | 
					      'no-alert': off
 | 
				
			||||||
 | 
					      '@typescript-eslint/no-restricted-imports': off
 | 
				
			||||||
 | 
					      no-restricted-imports: off
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,37 +0,0 @@
 | 
				
			||||||
import 'vitest-dom/extend-expect';
 | 
					 | 
				
			||||||
import { render, RenderOptions } from '@testing-library/react';
 | 
					 | 
				
			||||||
import { UIRouter, pushStateLocationPlugin } from '@uirouter/react';
 | 
					 | 
				
			||||||
import { PropsWithChildren, ReactElement } from 'react';
 | 
					 | 
				
			||||||
import { QueryClient, QueryClientProvider } from 'react-query';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function Provider({ children }: PropsWithChildren<unknown>) {
 | 
					 | 
				
			||||||
  return <UIRouter plugins={[pushStateLocationPlugin]}>{children}</UIRouter>;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function customRender(ui: ReactElement, options?: RenderOptions) {
 | 
					 | 
				
			||||||
  return render(ui, { wrapper: Provider, ...options });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// re-export everything
 | 
					 | 
				
			||||||
export * from '@testing-library/react';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// override render method
 | 
					 | 
				
			||||||
export { customRender as render };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function renderWithQueryClient(ui: React.ReactElement) {
 | 
					 | 
				
			||||||
  const testQueryClient = new QueryClient({
 | 
					 | 
				
			||||||
    defaultOptions: { queries: { retry: false } },
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  const { rerender, ...result } = customRender(
 | 
					 | 
				
			||||||
    <QueryClientProvider client={testQueryClient}>{ui}</QueryClientProvider>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    ...result,
 | 
					 | 
				
			||||||
    rerender: (rerenderUi: React.ReactElement) =>
 | 
					 | 
				
			||||||
      rerender(
 | 
					 | 
				
			||||||
        <QueryClientProvider client={testQueryClient}>
 | 
					 | 
				
			||||||
          {rerenderUi}
 | 
					 | 
				
			||||||
        </QueryClientProvider>
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,15 @@
 | 
				
			||||||
import { http, HttpResponse } from 'msw';
 | 
					import { http, HttpResponse } from 'msw';
 | 
				
			||||||
 | 
					import { render, within } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { renderWithQueryClient, within } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
import { server } from '@/setup-tests/server';
 | 
					import { server } from '@/setup-tests/server';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  createMockResourceGroups,
 | 
					  createMockResourceGroups,
 | 
				
			||||||
  createMockSubscriptions,
 | 
					  createMockSubscriptions,
 | 
				
			||||||
} from '@/react-tools/test-mocks';
 | 
					} from '@/react-tools/test-mocks';
 | 
				
			||||||
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { DashboardView } from './DashboardView';
 | 
					import { DashboardView } from './DashboardView';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,7 +107,6 @@ async function renderComponent(
 | 
				
			||||||
  resourceGroupsStatus = 200
 | 
					  resourceGroupsStatus = 200
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
  const user = new UserViewModel({ Username: 'user' });
 | 
					  const user = new UserViewModel({ Username: 'user' });
 | 
				
			||||||
  const state = { user };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  server.use(
 | 
					  server.use(
 | 
				
			||||||
    http.get('/api/endpoints/1', () => HttpResponse.json({})),
 | 
					    http.get('/api/endpoints/1', () => HttpResponse.json({})),
 | 
				
			||||||
| 
						 | 
					@ -135,12 +136,13 @@ async function renderComponent(
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  const renderResult = renderWithQueryClient(
 | 
					
 | 
				
			||||||
    <UserContext.Provider value={state}>
 | 
					  const Wrapped = withTestQueryProvider(
 | 
				
			||||||
      <DashboardView />
 | 
					    withUserProvider(withTestRouter(DashboardView), user)
 | 
				
			||||||
    </UserContext.Provider>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const renderResult = render(<Wrapped />);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await expect(renderResult.findByText(/Home/)).resolves.toBeVisible();
 | 
					  await expect(renderResult.findByText(/Home/)).resolves.toBeVisible();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return renderResult;
 | 
					  return renderResult;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,12 @@
 | 
				
			||||||
import userEvent from '@testing-library/user-event';
 | 
					import userEvent from '@testing-library/user-event';
 | 
				
			||||||
import { HttpResponse } from 'msw';
 | 
					import { HttpResponse, http } from 'msw';
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
import { http, server } from '@/setup-tests/server';
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					import { server } from '@/setup-tests/server';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { CreateContainerInstanceForm } from './CreateContainerInstanceForm';
 | 
					import { CreateContainerInstanceForm } from './CreateContainerInstanceForm';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,12 +21,10 @@ test('submit button should be disabled when name or image is missing', async ()
 | 
				
			||||||
  server.use(http.get('/api/endpoints/5', () => HttpResponse.json({})));
 | 
					  server.use(http.get('/api/endpoints/5', () => HttpResponse.json({})));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const user = new UserViewModel({ Username: 'user' });
 | 
					  const user = new UserViewModel({ Username: 'user' });
 | 
				
			||||||
 | 
					  const Wrapped = withTestQueryProvider(
 | 
				
			||||||
  const { findByText, getByText, getByLabelText } = renderWithQueryClient(
 | 
					    withUserProvider(withTestRouter(CreateContainerInstanceForm), user)
 | 
				
			||||||
    <UserContext.Provider value={{ user }}>
 | 
					 | 
				
			||||||
      <CreateContainerInstanceForm />
 | 
					 | 
				
			||||||
    </UserContext.Provider>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					  const { findByText, getByText, getByLabelText } = render(<Wrapped />);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await expect(findByText(/Azure settings/)).resolves.toBeVisible();
 | 
					  await expect(findByText(/Azure settings/)).resolves.toBeVisible();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
import { render } from '@/react-tools/test-utils';
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Badge } from './Badge';
 | 
					import { Badge } from './Badge';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
import { Rocket } from 'lucide-react';
 | 
					import { Rocket } from 'lucide-react';
 | 
				
			||||||
 | 
					import { render, fireEvent } from '@testing-library/react';
 | 
				
			||||||
import { render, fireEvent } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { BoxSelector } from './BoxSelector';
 | 
					import { BoxSelector } from './BoxSelector';
 | 
				
			||||||
import { BoxSelectorOption, Value } from './types';
 | 
					import { BoxSelectorOption, Value } from './types';
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
import { User } from 'lucide-react';
 | 
					import { User } from 'lucide-react';
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
import { render } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { DashboardItem } from './DashboardItem';
 | 
					import { DashboardItem } from './DashboardItem';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
import { render } from '@/react-tools/test-utils';
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { DetailsTable } from './index';
 | 
					import { DetailsTable } from './index';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,8 @@
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { createMockEnvironment } from '@/react-tools/test-mocks';
 | 
					import { createMockEnvironment } from '@/react-tools/test-mocks';
 | 
				
			||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
 | 
					
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '../test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { EdgeIndicator } from './EdgeIndicator';
 | 
					import { EdgeIndicator } from './EdgeIndicator';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,8 +34,10 @@ async function renderComponent(
 | 
				
			||||||
  environment.EdgeCheckinInterval = checkInInterval;
 | 
					  environment.EdgeCheckinInterval = checkInInterval;
 | 
				
			||||||
  environment.QueryDate = queryDate;
 | 
					  environment.QueryDate = queryDate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const queries = renderWithQueryClient(
 | 
					  const Wrapped = withTestQueryProvider(EdgeIndicator);
 | 
				
			||||||
    <EdgeIndicator environment={environment} showLastCheckInDate />
 | 
					
 | 
				
			||||||
 | 
					  const queries = render(
 | 
				
			||||||
 | 
					    <Wrapped environment={environment} showLastCheckInDate />
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await expect(queries.findByRole('status')).resolves.toBeVisible();
 | 
					  await expect(queries.findByRole('status')).resolves.toBeVisible();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,10 @@
 | 
				
			||||||
import { FormikErrors } from 'formik';
 | 
					import { FormikErrors } from 'formik';
 | 
				
			||||||
import { ComponentProps } from 'react';
 | 
					import { ComponentProps } from 'react';
 | 
				
			||||||
import { HttpResponse } from 'msw';
 | 
					import { HttpResponse } from 'msw';
 | 
				
			||||||
 | 
					import { render, fireEvent } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { renderWithQueryClient, fireEvent } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
import { http, server } from '@/setup-tests/server';
 | 
					import { http, server } from '@/setup-tests/server';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { ImageConfigFieldset } from './ImageConfigFieldset';
 | 
					import { ImageConfigFieldset } from './ImageConfigFieldset';
 | 
				
			||||||
import { Values } from './types';
 | 
					import { Values } from './types';
 | 
				
			||||||
| 
						 | 
					@ -16,20 +17,20 @@ vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
it('should render SimpleForm when useRegistry is true', () => {
 | 
					it('should render SimpleForm when useRegistry is true', () => {
 | 
				
			||||||
  const { getByText } = render({ values: { useRegistry: true } });
 | 
					  const { getByText } = renderComponent({ values: { useRegistry: true } });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  expect(getByText('Advanced mode')).toBeInTheDocument();
 | 
					  expect(getByText('Advanced mode')).toBeInTheDocument();
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
it('should render AdvancedForm when useRegistry is false', () => {
 | 
					it('should render AdvancedForm when useRegistry is false', () => {
 | 
				
			||||||
  const { getByText } = render({ values: { useRegistry: false } });
 | 
					  const { getByText } = renderComponent({ values: { useRegistry: false } });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  expect(getByText('Simple mode')).toBeInTheDocument();
 | 
					  expect(getByText('Simple mode')).toBeInTheDocument();
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
it('should call setFieldValue with useRegistry set to false when "Advanced mode" button is clicked', () => {
 | 
					it('should call setFieldValue with useRegistry set to false when "Advanced mode" button is clicked', () => {
 | 
				
			||||||
  const setFieldValue = vi.fn();
 | 
					  const setFieldValue = vi.fn();
 | 
				
			||||||
  const { getByText } = render({
 | 
					  const { getByText } = renderComponent({
 | 
				
			||||||
    values: { useRegistry: true },
 | 
					    values: { useRegistry: true },
 | 
				
			||||||
    setFieldValue,
 | 
					    setFieldValue,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
| 
						 | 
					@ -41,7 +42,7 @@ it('should call setFieldValue with useRegistry set to false when "Advanced mode"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
it('should call setFieldValue with useRegistry set to true when "Simple mode" button is clicked', () => {
 | 
					it('should call setFieldValue with useRegistry set to true when "Simple mode" button is clicked', () => {
 | 
				
			||||||
  const setFieldValue = vi.fn();
 | 
					  const setFieldValue = vi.fn();
 | 
				
			||||||
  const { getByText } = render({
 | 
					  const { getByText } = renderComponent({
 | 
				
			||||||
    values: { useRegistry: false },
 | 
					    values: { useRegistry: false },
 | 
				
			||||||
    setFieldValue,
 | 
					    setFieldValue,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
| 
						 | 
					@ -51,7 +52,7 @@ it('should call setFieldValue with useRegistry set to true when "Simple mode" bu
 | 
				
			||||||
  expect(setFieldValue).toHaveBeenCalledWith('useRegistry', true);
 | 
					  expect(setFieldValue).toHaveBeenCalledWith('useRegistry', true);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function render({
 | 
					function renderComponent({
 | 
				
			||||||
  values = {
 | 
					  values = {
 | 
				
			||||||
    useRegistry: true,
 | 
					    useRegistry: true,
 | 
				
			||||||
    registryId: 123,
 | 
					    registryId: 123,
 | 
				
			||||||
| 
						 | 
					@ -73,8 +74,10 @@ function render({
 | 
				
			||||||
    http.get('/api/endpoints/:id', () => HttpResponse.json({}))
 | 
					    http.get('/api/endpoints/:id', () => HttpResponse.json({}))
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return renderWithQueryClient(
 | 
					  const Wrapped = withTestQueryProvider(ImageConfigFieldset);
 | 
				
			||||||
    <ImageConfigFieldset
 | 
					
 | 
				
			||||||
 | 
					  return render(
 | 
				
			||||||
 | 
					    <Wrapped
 | 
				
			||||||
      values={{
 | 
					      values={{
 | 
				
			||||||
        useRegistry: true,
 | 
					        useRegistry: true,
 | 
				
			||||||
        registryId: 123,
 | 
					        registryId: 123,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,7 @@
 | 
				
			||||||
import { render } from '@testing-library/react';
 | 
					 | 
				
			||||||
import userEvent from '@testing-library/user-event';
 | 
					import userEvent from '@testing-library/user-event';
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { NavTabs, Option } from './NavTabs';
 | 
					import { NavTabs, Option } from './NavTabs';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,6 +34,7 @@ test('should show selected id content', async () => {
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('should call onSelect when clicked with id', async () => {
 | 
					test('should call onSelect when clicked with id', async () => {
 | 
				
			||||||
 | 
					  const user = userEvent.setup();
 | 
				
			||||||
  const options = [
 | 
					  const options = [
 | 
				
			||||||
    { children: 'Content 1', id: 'option1', label: 'Option 1' },
 | 
					    { children: 'Content 1', id: 'option1', label: 'Option 1' },
 | 
				
			||||||
    { children: 'Content 2', id: 'option2', label: 'Option 2' },
 | 
					    { children: 'Content 2', id: 'option2', label: 'Option 2' },
 | 
				
			||||||
| 
						 | 
					@ -42,7 +45,7 @@ test('should call onSelect when clicked with id', async () => {
 | 
				
			||||||
  const { findByText } = renderComponent(options, options[1].id, onSelect);
 | 
					  const { findByText } = renderComponent(options, options[1].id, onSelect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const heading = await findByText(options[0].label);
 | 
					  const heading = await findByText(options[0].label);
 | 
				
			||||||
  await userEvent.click(heading);
 | 
					  await user.click(heading);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  expect(onSelect).toHaveBeenCalledWith(options[0].id);
 | 
					  expect(onSelect).toHaveBeenCalledWith(options[0].id);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					@ -52,7 +55,9 @@ function renderComponent(
 | 
				
			||||||
  selectedId?: string | number,
 | 
					  selectedId?: string | number,
 | 
				
			||||||
  onSelect?: (id: string | number) => void
 | 
					  onSelect?: (id: string | number) => void
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
 | 
					  const Wrapped = withTestRouter(NavTabs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return render(
 | 
					  return render(
 | 
				
			||||||
    <NavTabs options={options} selectedId={selectedId} onSelect={onSelect} />
 | 
					    <Wrapped options={options} selectedId={selectedId} onSelect={onSelect} />
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
import { render } from '@/react-tools/test-utils';
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Breadcrumbs } from './Breadcrumbs';
 | 
					import { Breadcrumbs } from './Breadcrumbs';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,9 @@
 | 
				
			||||||
import { QueryClient, QueryClientProvider } from 'react-query';
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
import { render } from '@/react-tools/test-utils';
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { HeaderContainer } from './HeaderContainer';
 | 
					import { HeaderContainer } from './HeaderContainer';
 | 
				
			||||||
import { HeaderTitle } from './HeaderTitle';
 | 
					import { HeaderTitle } from './HeaderTitle';
 | 
				
			||||||
| 
						 | 
					@ -14,7 +15,8 @@ test('should not render without a wrapping HeaderContainer', async () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const title = 'title';
 | 
					  const title = 'title';
 | 
				
			||||||
  function renderComponent() {
 | 
					  function renderComponent() {
 | 
				
			||||||
    return render(<HeaderTitle title={title} />);
 | 
					    const Wrapped = withTestQueryProvider(HeaderTitle);
 | 
				
			||||||
 | 
					    return render(<Wrapped title={title} />);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  expect(renderComponent).toThrowErrorMatchingSnapshot();
 | 
					  expect(renderComponent).toThrowErrorMatchingSnapshot();
 | 
				
			||||||
| 
						 | 
					@ -25,19 +27,22 @@ test('should not render without a wrapping HeaderContainer', async () => {
 | 
				
			||||||
test('should display a HeaderTitle', async () => {
 | 
					test('should display a HeaderTitle', async () => {
 | 
				
			||||||
  const username = 'username';
 | 
					  const username = 'username';
 | 
				
			||||||
  const user = new UserViewModel({ Username: username });
 | 
					  const user = new UserViewModel({ Username: username });
 | 
				
			||||||
  const queryClient = new QueryClient();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const title = 'title';
 | 
					  const title = 'title';
 | 
				
			||||||
  const { queryByText } = render(
 | 
					
 | 
				
			||||||
    <QueryClientProvider client={queryClient}>
 | 
					  const Wrapped = withTestQueryProvider(
 | 
				
			||||||
      <UserContext.Provider value={{ user }}>
 | 
					    withUserProvider(
 | 
				
			||||||
 | 
					      withTestRouter(() => (
 | 
				
			||||||
        <HeaderContainer>
 | 
					        <HeaderContainer>
 | 
				
			||||||
          <HeaderTitle title={title} />
 | 
					          <HeaderTitle title={title} />
 | 
				
			||||||
        </HeaderContainer>
 | 
					        </HeaderContainer>
 | 
				
			||||||
      </UserContext.Provider>
 | 
					      )),
 | 
				
			||||||
    </QueryClientProvider>
 | 
					      user
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { queryByText } = render(<Wrapped />);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const heading = queryByText(title);
 | 
					  const heading = queryByText(title);
 | 
				
			||||||
  expect(heading).toBeVisible();
 | 
					  expect(heading).toBeVisible();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,9 @@
 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { PageHeader } from './PageHeader';
 | 
					import { PageHeader } from './PageHeader';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,13 +11,13 @@ test('should display a PageHeader', async () => {
 | 
				
			||||||
  const username = 'username';
 | 
					  const username = 'username';
 | 
				
			||||||
  const user = new UserViewModel({ Username: username });
 | 
					  const user = new UserViewModel({ Username: username });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const title = 'title';
 | 
					  const Wrapped = withTestQueryProvider(
 | 
				
			||||||
  const { queryByText } = renderWithQueryClient(
 | 
					    withUserProvider(withTestRouter(PageHeader), user)
 | 
				
			||||||
    <UserContext.Provider value={{ user }}>
 | 
					 | 
				
			||||||
      <PageHeader title={title} />
 | 
					 | 
				
			||||||
    </UserContext.Provider>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const title = 'title';
 | 
				
			||||||
 | 
					  const { queryByText } = render(<Wrapped title={title} />);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const heading = queryByText(title);
 | 
					  const heading = queryByText(title);
 | 
				
			||||||
  expect(heading).toBeVisible();
 | 
					  expect(heading).toBeVisible();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,11 @@
 | 
				
			||||||
import { http, HttpResponse } from 'msw';
 | 
					import { http, HttpResponse } from 'msw';
 | 
				
			||||||
import { Mock } from 'vitest';
 | 
					import { Mock } from 'vitest';
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Tag, TagId } from '@/portainer/tags/types';
 | 
					import { Tag, TagId } from '@/portainer/tags/types';
 | 
				
			||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
import { server } from '@/setup-tests/server';
 | 
					import { server } from '@/setup-tests/server';
 | 
				
			||||||
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { TagSelector } from './TagSelector';
 | 
					import { TagSelector } from './TagSelector';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,8 +56,10 @@ async function renderComponent(
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
  server.use(http.get('/api/tags', () => HttpResponse.json(tags)));
 | 
					  server.use(http.get('/api/tags', () => HttpResponse.json(tags)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const queries = renderWithQueryClient(
 | 
					  const Wrapped = withTestQueryProvider(withTestRouter(TagSelector));
 | 
				
			||||||
    <TagSelector value={value} allowCreate={allowCreate} onChange={onChange} />
 | 
					
 | 
				
			||||||
 | 
					  const queries = render(
 | 
				
			||||||
 | 
					    <Wrapped value={value} allowCreate={allowCreate} onChange={onChange} />
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const tagElement = await queries.findAllByText('tags', { exact: false });
 | 
					  const tagElement = await queries.findAllByText('tags', { exact: false });
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,34 @@
 | 
				
			||||||
import { render } from '@/react-tools/test-utils';
 | 
					import { UIView } from '@uirouter/react';
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { AddButton } from './AddButton';
 | 
					import { AddButton } from './AddButton';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function renderDefault({
 | 
					function renderDefault({
 | 
				
			||||||
  label = 'default label',
 | 
					  label = 'default label',
 | 
				
			||||||
}: Partial<{ label: string }> = {}) {
 | 
					}: Partial<{ label: string }> = {}) {
 | 
				
			||||||
  return render(<AddButton to="">{label}</AddButton>);
 | 
					  const Wrapped = withTestRouter(AddButton, {
 | 
				
			||||||
 | 
					    stateConfig: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'root',
 | 
				
			||||||
 | 
					        url: '/',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        component: () => (
 | 
				
			||||||
 | 
					          <>
 | 
				
			||||||
 | 
					            <div>Root</div>
 | 
				
			||||||
 | 
					            <UIView />
 | 
				
			||||||
 | 
					          </>
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'root.new',
 | 
				
			||||||
 | 
					        url: 'new',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    route: 'root',
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  return render(<Wrapped to="">{label}</Wrapped>);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('should display a AddButton component', async () => {
 | 
					test('should display a AddButton component', async () => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
import { fireEvent, render } from '@testing-library/react';
 | 
					 | 
				
			||||||
import { PropsWithChildren } from 'react';
 | 
					import { PropsWithChildren } from 'react';
 | 
				
			||||||
 | 
					import { fireEvent, render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Button, Props } from './Button';
 | 
					import { Button, Props } from './Button';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
import { render } from '@testing-library/react';
 | 
					 | 
				
			||||||
import { PropsWithChildren } from 'react';
 | 
					import { PropsWithChildren } from 'react';
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { ButtonGroup, Props } from './ButtonGroup';
 | 
					import { ButtonGroup, Props } from './ButtonGroup';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
import { render } from '@/react-tools/test-utils';
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { LoadingButton } from './LoadingButton';
 | 
					import { LoadingButton } from './LoadingButton';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
import { fireEvent, render } from '@/react-tools/test-utils';
 | 
					import { fireEvent, render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { FileUploadField } from './FileUploadField';
 | 
					import { FileUploadField } from './FileUploadField';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
import { render } from '@/react-tools/test-utils';
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { FileUploadForm } from './FileUploadForm';
 | 
					import { FileUploadForm } from './FileUploadForm';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
import { render } from '@/react-tools/test-utils';
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Slider, Props } from './Slider';
 | 
					import { Slider, Props } from './Slider';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
import { render } from '@testing-library/react';
 | 
					 | 
				
			||||||
import { PropsWithChildren } from 'react';
 | 
					import { PropsWithChildren } from 'react';
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Switch, Props } from './Switch';
 | 
					import { Switch, Props } from './Switch';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
import { render, fireEvent } from '@/react-tools/test-utils';
 | 
					import { render, fireEvent } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { SwitchField, Props } from './SwitchField';
 | 
					import { SwitchField, Props } from './SwitchField';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					import { UISref, UIView } from '@uirouter/react';
 | 
				
			||||||
 | 
					import { render, screen } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function RelativePathLink() {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <UISref to=".custom">
 | 
				
			||||||
 | 
					      <span>Link</span>
 | 
				
			||||||
 | 
					    </UISref>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test.todo('should render a link with relative path', () => {
 | 
				
			||||||
 | 
					  const WrappedComponent = withTestRouter(RelativePathLink, {
 | 
				
			||||||
 | 
					    stateConfig: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'parent',
 | 
				
			||||||
 | 
					        url: '/',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        component: () => (
 | 
				
			||||||
 | 
					          <>
 | 
				
			||||||
 | 
					            <div>parent</div>
 | 
				
			||||||
 | 
					            <UIView />
 | 
				
			||||||
 | 
					          </>
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'parent.custom',
 | 
				
			||||||
 | 
					        url: 'custom',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    route: 'parent',
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  render(<WrappedComponent />);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  expect(screen.getByText('Link')).toBeInTheDocument();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,11 @@
 | 
				
			||||||
import { HttpResponse } from 'msw';
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					import { http, HttpResponse } from 'msw';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
import { http, server } from '@/setup-tests/server';
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					import { server } from '@/setup-tests/server';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { NetworkContainer } from '../types';
 | 
					import { NetworkContainer } from '../types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,15 +34,18 @@ test('Network container values should be visible and the link should be valid',
 | 
				
			||||||
  server.use(http.get('/api/endpoints/1', () => HttpResponse.json({})));
 | 
					  server.use(http.get('/api/endpoints/1', () => HttpResponse.json({})));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const user = new UserViewModel({ Username: 'test', Role: 1 });
 | 
					  const user = new UserViewModel({ Username: 'test', Role: 1 });
 | 
				
			||||||
  const { findByText } = renderWithQueryClient(
 | 
					
 | 
				
			||||||
    <UserContext.Provider value={{ user }}>
 | 
					  const Wrapped = withTestQueryProvider(
 | 
				
			||||||
      <NetworkContainersTable
 | 
					    withUserProvider(withTestRouter(NetworkContainersTable), user)
 | 
				
			||||||
        networkContainers={networkContainers}
 | 
					  );
 | 
				
			||||||
        nodeName=""
 | 
					
 | 
				
			||||||
        environmentId={1}
 | 
					  const { findByText } = render(
 | 
				
			||||||
        networkId="pc8xc9s6ot043vl1q5iz4zhfs"
 | 
					    <Wrapped
 | 
				
			||||||
      />
 | 
					      networkContainers={networkContainers}
 | 
				
			||||||
    </UserContext.Provider>
 | 
					      nodeName=""
 | 
				
			||||||
 | 
					      environmentId={1}
 | 
				
			||||||
 | 
					      networkId="pc8xc9s6ot043vl1q5iz4zhfs"
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await expect(findByText('Containers in network')).resolves.toBeVisible();
 | 
					  await expect(findByText('Containers in network')).resolves.toBeVisible();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,10 @@
 | 
				
			||||||
import { HttpResponse, http } from 'msw';
 | 
					import { HttpResponse, http } from 'msw';
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
import { server } from '@/setup-tests/server';
 | 
					import { server } from '@/setup-tests/server';
 | 
				
			||||||
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { DockerNetwork } from '../types';
 | 
					import { DockerNetwork } from '../types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,7 +27,9 @@ test('Network details values should be visible', async () => {
 | 
				
			||||||
  await expect(findByText(network.Driver)).resolves.toBeVisible();
 | 
					  await expect(findByText(network.Driver)).resolves.toBeVisible();
 | 
				
			||||||
  await expect(findByText(network.Scope)).resolves.toBeVisible();
 | 
					  await expect(findByText(network.Scope)).resolves.toBeVisible();
 | 
				
			||||||
  await expect(
 | 
					  await expect(
 | 
				
			||||||
    findByText(network.IPAM?.Config[0].Gateway || 'not found', { exact: false })
 | 
					    findByText(network.IPAM?.Config[0].Gateway || 'not found', {
 | 
				
			||||||
 | 
					      exact: false,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  ).resolves.toBeVisible();
 | 
					  ).resolves.toBeVisible();
 | 
				
			||||||
  await expect(
 | 
					  await expect(
 | 
				
			||||||
    findByText(network.IPAM?.Config[0].Subnet || 'not found', { exact: false })
 | 
					    findByText(network.IPAM?.Config[0].Subnet || 'not found', { exact: false })
 | 
				
			||||||
| 
						 | 
					@ -55,13 +58,12 @@ async function renderComponent(isAdmin: boolean, network: DockerNetwork) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const user = new UserViewModel({ Username: 'test', Role: isAdmin ? 1 : 2 });
 | 
					  const user = new UserViewModel({ Username: 'test', Role: isAdmin ? 1 : 2 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const queries = renderWithQueryClient(
 | 
					  const Wrapped = withTestQueryProvider(
 | 
				
			||||||
    <UserContext.Provider value={{ user }}>
 | 
					    withUserProvider(NetworkDetailsTable, user)
 | 
				
			||||||
      <NetworkDetailsTable
 | 
					  );
 | 
				
			||||||
        network={network}
 | 
					
 | 
				
			||||||
        onRemoveNetworkClicked={() => {}}
 | 
					  const queries = render(
 | 
				
			||||||
      />
 | 
					    <Wrapped network={network} onRemoveNetworkClicked={() => {}} />
 | 
				
			||||||
    </UserContext.Provider>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await expect(queries.findByText('Network details')).resolves.toBeVisible();
 | 
					  await expect(queries.findByText('Network details')).resolves.toBeVisible();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
import { render } from '@/react-tools/test-utils';
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { NetworkOptions } from '../types';
 | 
					import { NetworkOptions } from '../types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
import { render, screen } from '@/react-tools/test-utils';
 | 
					import { render, screen } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  EnvVarType,
 | 
					  EnvVarType,
 | 
				
			||||||
  TemplateViewModel,
 | 
					  TemplateViewModel,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,6 @@
 | 
				
			||||||
import { vi } from 'vitest';
 | 
					import { vi } from 'vitest';
 | 
				
			||||||
import userEvent from '@testing-library/user-event';
 | 
					import userEvent from '@testing-library/user-event';
 | 
				
			||||||
 | 
					import { render, screen } from '@testing-library/react';
 | 
				
			||||||
import { render, screen } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  EnvVarsFieldset,
 | 
					  EnvVarsFieldset,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
import { vi } from 'vitest';
 | 
					import { vi } from 'vitest';
 | 
				
			||||||
 | 
					import { render, screen } from '@testing-library/react';
 | 
				
			||||||
import { render, screen } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { TemplateNote } from './TemplateNote';
 | 
					import { TemplateNote } from './TemplateNote';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,18 @@
 | 
				
			||||||
import { vi } from 'vitest';
 | 
					import { vi } from 'vitest';
 | 
				
			||||||
import { HttpResponse, http } from 'msw';
 | 
					import { HttpResponse, http } from 'msw';
 | 
				
			||||||
 | 
					import { render, screen } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { renderWithQueryClient, screen } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
import { AppTemplate } from '@/react/portainer/templates/app-templates/types';
 | 
					import { AppTemplate } from '@/react/portainer/templates/app-templates/types';
 | 
				
			||||||
import { CustomTemplate } from '@/react/portainer/templates/custom-templates/types';
 | 
					import { CustomTemplate } from '@/react/portainer/templates/custom-templates/types';
 | 
				
			||||||
import { server } from '@/setup-tests/server';
 | 
					import { server } from '@/setup-tests/server';
 | 
				
			||||||
import selectEvent from '@/react/test-utils/react-select';
 | 
					import selectEvent from '@/react/test-utils/react-select';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { SelectedTemplateValue } from './types';
 | 
					import { SelectedTemplateValue } from './types';
 | 
				
			||||||
import { TemplateSelector } from './TemplateSelector';
 | 
					import { TemplateSelector } from './TemplateSelector';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('renders TemplateSelector component', async () => {
 | 
					test('renders TemplateSelector component', async () => {
 | 
				
			||||||
  render();
 | 
					  renderComponent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const templateSelectorElement = screen.getByLabelText('Template');
 | 
					  const templateSelectorElement = screen.getByLabelText('Template');
 | 
				
			||||||
  expect(templateSelectorElement).toBeInTheDocument();
 | 
					  expect(templateSelectorElement).toBeInTheDocument();
 | 
				
			||||||
| 
						 | 
					@ -30,7 +31,7 @@ test.skip('selects an edge app template', async () => {
 | 
				
			||||||
    categories: ['edge'],
 | 
					    categories: ['edge'],
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const { select } = render({
 | 
					  const { select } = renderComponent({
 | 
				
			||||||
    onChange,
 | 
					    onChange,
 | 
				
			||||||
    appTemplates: [
 | 
					    appTemplates: [
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
| 
						 | 
					@ -59,7 +60,7 @@ test.skip('selects an edge custom template', async () => {
 | 
				
			||||||
    Id: 2,
 | 
					    Id: 2,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const { select } = render({
 | 
					  const { select } = renderComponent({
 | 
				
			||||||
    onChange,
 | 
					    onChange,
 | 
				
			||||||
    customTemplates: [
 | 
					    customTemplates: [
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
| 
						 | 
					@ -75,7 +76,7 @@ test.skip('selects an edge custom template', async () => {
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('renders with error', async () => {
 | 
					test('renders with error', async () => {
 | 
				
			||||||
  render({
 | 
					  renderComponent({
 | 
				
			||||||
    error: 'Invalid template',
 | 
					    error: 'Invalid template',
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -87,7 +88,7 @@ test('renders with error', async () => {
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test.skip('renders TemplateSelector component with no custom templates available', async () => {
 | 
					test.skip('renders TemplateSelector component with no custom templates available', async () => {
 | 
				
			||||||
  render({
 | 
					  renderComponent({
 | 
				
			||||||
    customTemplates: [],
 | 
					    customTemplates: [],
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -102,7 +103,7 @@ test.skip('renders TemplateSelector component with no custom templates available
 | 
				
			||||||
  expect(noCustomTemplatesElement).toBeInTheDocument();
 | 
					  expect(noCustomTemplatesElement).toBeInTheDocument();
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function render({
 | 
					function renderComponent({
 | 
				
			||||||
  onChange = vi.fn(),
 | 
					  onChange = vi.fn(),
 | 
				
			||||||
  appTemplates = [],
 | 
					  appTemplates = [],
 | 
				
			||||||
  customTemplates = [],
 | 
					  customTemplates = [],
 | 
				
			||||||
| 
						 | 
					@ -123,8 +124,10 @@ function render({
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  renderWithQueryClient(
 | 
					  const Wrapped = withTestQueryProvider(TemplateSelector);
 | 
				
			||||||
    <TemplateSelector
 | 
					
 | 
				
			||||||
 | 
					  render(
 | 
				
			||||||
 | 
					    <Wrapped
 | 
				
			||||||
      value={{ template: undefined, type: undefined }}
 | 
					      value={{ template: undefined, type: undefined }}
 | 
				
			||||||
      onChange={onChange}
 | 
					      onChange={onChange}
 | 
				
			||||||
      error={error}
 | 
					      error={error}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,20 +1,17 @@
 | 
				
			||||||
import { http, HttpResponse } from 'msw';
 | 
					import { http, HttpResponse } from 'msw';
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { server } from '@/setup-tests/server';
 | 
					import { server } from '@/setup-tests/server';
 | 
				
			||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
import { isoDate } from '@/portainer/filters/filters';
 | 
					import { isoDate } from '@/portainer/filters/filters';
 | 
				
			||||||
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { BackupFailedPanel } from './BackupFailedPanel';
 | 
					import { BackupFailedPanel } from './BackupFailedPanel';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('when backup failed, should show message', async () => {
 | 
					test('when backup failed, should show message', async () => {
 | 
				
			||||||
  const timestamp = 1500;
 | 
					  const timestamp = 1500;
 | 
				
			||||||
  server.use(
 | 
					 | 
				
			||||||
    http.get('/api/backup/s3/status', () =>
 | 
					 | 
				
			||||||
      HttpResponse.json({ Failed: true, TimestampUTC: timestamp })
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const { findByText } = renderWithQueryClient(<BackupFailedPanel />);
 | 
					  const { findByText } = renderComponent({ failed: true, timestamp });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await expect(
 | 
					  await expect(
 | 
				
			||||||
    findByText(
 | 
					    findByText(
 | 
				
			||||||
| 
						 | 
					@ -27,14 +24,27 @@ test('when backup failed, should show message', async () => {
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("when user is using less nodes then allowed he shouldn't see message", async () => {
 | 
					test("when user is using less nodes then allowed he shouldn't see message", async () => {
 | 
				
			||||||
  server.use(
 | 
					  const { findByText } = renderComponent({ failed: false });
 | 
				
			||||||
    http.get('/api/backup/s3/status', () =>
 | 
					 | 
				
			||||||
      HttpResponse.json({ Failed: false })
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
  const { findByText } = renderWithQueryClient(<BackupFailedPanel />);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await expect(
 | 
					  await expect(
 | 
				
			||||||
    findByText('The latest automated backup has failed at', { exact: false })
 | 
					    findByText('The latest automated backup has failed at', { exact: false })
 | 
				
			||||||
  ).rejects.toBeTruthy();
 | 
					  ).rejects.toBeTruthy();
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function renderComponent({
 | 
				
			||||||
 | 
					  failed,
 | 
				
			||||||
 | 
					  timestamp,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  failed: boolean;
 | 
				
			||||||
 | 
					  timestamp?: number;
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
					  server.use(
 | 
				
			||||||
 | 
					    http.get('/api/backup/s3/status', () =>
 | 
				
			||||||
 | 
					      HttpResponse.json({ Failed: failed, TimestampUTC: timestamp })
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Wrapped = withTestQueryProvider(withTestRouter(BackupFailedPanel));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return render(<Wrapped />);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,16 +1,18 @@
 | 
				
			||||||
import { http, HttpResponse } from 'msw';
 | 
					import { http, HttpResponse } from 'msw';
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  EnvironmentGroup,
 | 
					  EnvironmentGroup,
 | 
				
			||||||
  EnvironmentGroupId,
 | 
					  EnvironmentGroupId,
 | 
				
			||||||
} from '@/react/portainer/environments/environment-groups/types';
 | 
					} from '@/react/portainer/environments/environment-groups/types';
 | 
				
			||||||
import { Environment } from '@/react/portainer/environments/types';
 | 
					import { Environment } from '@/react/portainer/environments/types';
 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
import { Tag } from '@/portainer/tags/types';
 | 
					import { Tag } from '@/portainer/tags/types';
 | 
				
			||||||
import { createMockEnvironment } from '@/react-tools/test-mocks';
 | 
					import { createMockEnvironment } from '@/react-tools/test-mocks';
 | 
				
			||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
import { server } from '@/setup-tests/server';
 | 
					import { server } from '@/setup-tests/server';
 | 
				
			||||||
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { EnvironmentItem } from './EnvironmentItem';
 | 
					import { EnvironmentItem } from './EnvironmentItem';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,15 +45,17 @@ function renderComponent(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  server.use(http.get('/api/tags', () => HttpResponse.json(tags)));
 | 
					  server.use(http.get('/api/tags', () => HttpResponse.json(tags)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return renderWithQueryClient(
 | 
					  const Wrapped = withTestQueryProvider(
 | 
				
			||||||
    <UserContext.Provider value={{ user }}>
 | 
					    withTestRouter(withUserProvider(EnvironmentItem, user))
 | 
				
			||||||
      <EnvironmentItem
 | 
					  );
 | 
				
			||||||
        isActive={false}
 | 
					
 | 
				
			||||||
        onClickBrowse={() => {}}
 | 
					  return render(
 | 
				
			||||||
        onClickDisconnect={() => {}}
 | 
					    <Wrapped
 | 
				
			||||||
        environment={env}
 | 
					      isActive={false}
 | 
				
			||||||
        groupName={group.Name}
 | 
					      onClickBrowse={() => {}}
 | 
				
			||||||
      />
 | 
					      onClickDisconnect={() => {}}
 | 
				
			||||||
    </UserContext.Provider>
 | 
					      environment={env}
 | 
				
			||||||
 | 
					      groupName={group.Name}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,12 @@
 | 
				
			||||||
import { http, HttpResponse } from 'msw';
 | 
					import { http, HttpResponse } from 'msw';
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Environment } from '@/react/portainer/environments/types';
 | 
					import { Environment } from '@/react/portainer/environments/types';
 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
import { server } from '@/setup-tests/server';
 | 
					import { server } from '@/setup-tests/server';
 | 
				
			||||||
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { EnvironmentList } from './EnvironmentList';
 | 
					import { EnvironmentList } from './EnvironmentList';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,10 +51,12 @@ async function renderComponent(
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const queries = renderWithQueryClient(
 | 
					  const Wrapped = withTestQueryProvider(
 | 
				
			||||||
    <UserContext.Provider value={{ user }}>
 | 
					    withUserProvider(withTestRouter(EnvironmentList), user)
 | 
				
			||||||
      <EnvironmentList onClickBrowse={vi.fn()} onRefresh={vi.fn()} />
 | 
					  );
 | 
				
			||||||
    </UserContext.Provider>
 | 
					
 | 
				
			||||||
 | 
					  const queries = render(
 | 
				
			||||||
 | 
					    <Wrapped onClickBrowse={vi.fn()} onRefresh={vi.fn()} />
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await expect(queries.findByText('Environments')).resolves.toBeVisible();
 | 
					  await expect(queries.findByText('Environments')).resolves.toBeVisible();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,8 @@
 | 
				
			||||||
import { http, HttpResponse } from 'msw';
 | 
					import { http, HttpResponse } from 'msw';
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { server } from '@/setup-tests/server';
 | 
					import { server } from '@/setup-tests/server';
 | 
				
			||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { LicenseType } from '../licenses/types';
 | 
					import { LicenseType } from '../licenses/types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +18,7 @@ test('when user is using more nodes then allowed he should see message', async (
 | 
				
			||||||
    http.get('/api/system/nodes', () => HttpResponse.json({ nodes: used }))
 | 
					    http.get('/api/system/nodes', () => HttpResponse.json({ nodes: used }))
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const { findByText } = renderWithQueryClient(<LicenseNodePanel />);
 | 
					  const { findByText } = renderComponent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await expect(
 | 
					  await expect(
 | 
				
			||||||
    findByText(
 | 
					    findByText(
 | 
				
			||||||
| 
						 | 
					@ -36,7 +37,7 @@ test("when user is using less nodes then allowed he shouldn't see message", asyn
 | 
				
			||||||
    http.get('/api/system/nodes', () => HttpResponse.json({ nodes: used }))
 | 
					    http.get('/api/system/nodes', () => HttpResponse.json({ nodes: used }))
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const { findByText } = renderWithQueryClient(<LicenseNodePanel />);
 | 
					  const { findByText } = renderComponent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await expect(
 | 
					  await expect(
 | 
				
			||||||
    findByText(
 | 
					    findByText(
 | 
				
			||||||
| 
						 | 
					@ -44,3 +45,9 @@ test("when user is using less nodes then allowed he shouldn't see message", asyn
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  ).rejects.toBeTruthy();
 | 
					  ).rejects.toBeTruthy();
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function renderComponent() {
 | 
				
			||||||
 | 
					  const Wrapped = withTestQueryProvider(LicenseNodePanel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return render(<Wrapped />);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,10 @@
 | 
				
			||||||
import { Meta, Story } from '@storybook/react';
 | 
					import { Meta, Story } from '@storybook/react';
 | 
				
			||||||
import { useMemo, useState } from 'react';
 | 
					import { useState } from 'react';
 | 
				
			||||||
import { QueryClient, QueryClientProvider } from 'react-query';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
 | 
					import { Role, User } from '@/portainer/users/types';
 | 
				
			||||||
 | 
					import { isPureAdmin } from '@/portainer/users/user.helpers';
 | 
				
			||||||
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { parseAccessControlFormData } from '../utils';
 | 
					import { parseAccessControlFormData } from '../utils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,41 +17,25 @@ const meta: Meta = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default meta;
 | 
					export default meta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum Role {
 | 
					 | 
				
			||||||
  Admin = 1,
 | 
					 | 
				
			||||||
  User,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const testQueryClient = new QueryClient({
 | 
					 | 
				
			||||||
  defaultOptions: { queries: { retry: false } },
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface Args {
 | 
					interface Args {
 | 
				
			||||||
  userRole: Role;
 | 
					  userRole: Role;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function Template({ userRole }: Args) {
 | 
					function Template({ userRole }: Args) {
 | 
				
			||||||
  const isAdmin = userRole === Role.Admin;
 | 
					  const defaults = parseAccessControlFormData(
 | 
				
			||||||
  const defaults = parseAccessControlFormData(isAdmin, 0);
 | 
					    isPureAdmin({ Role: userRole } as User),
 | 
				
			||||||
 | 
					    0
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [value, setValue] = useState(defaults);
 | 
					  const [value, setValue] = useState(defaults);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const userProviderState = useMemo(
 | 
					  const Wrapped = withUserProvider(
 | 
				
			||||||
    () => ({ user: new UserViewModel({ Role: userRole }) }),
 | 
					    AccessControlForm,
 | 
				
			||||||
    [userRole]
 | 
					    new UserViewModel({ Role: userRole })
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <QueryClientProvider client={testQueryClient}>
 | 
					    <Wrapped values={value} onChange={setValue} errors={{}} environmentId={1} />
 | 
				
			||||||
      <UserContext.Provider value={userProviderState}>
 | 
					 | 
				
			||||||
        <AccessControlForm
 | 
					 | 
				
			||||||
          values={value}
 | 
					 | 
				
			||||||
          onChange={setValue}
 | 
					 | 
				
			||||||
          errors={{}}
 | 
					 | 
				
			||||||
          environmentId={1}
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      </UserContext.Provider>
 | 
					 | 
				
			||||||
    </QueryClientProvider>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,5 +46,5 @@ AdminAccessControl.args = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const NonAdminAccessControl: Story<Args> = Template.bind({});
 | 
					export const NonAdminAccessControl: Story<Args> = Template.bind({});
 | 
				
			||||||
NonAdminAccessControl.args = {
 | 
					NonAdminAccessControl.args = {
 | 
				
			||||||
  userRole: Role.User,
 | 
					  userRole: Role.Standard,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,14 @@
 | 
				
			||||||
import { http, HttpResponse } from 'msw';
 | 
					import { http, HttpResponse } from 'msw';
 | 
				
			||||||
 | 
					import { render, within } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { server } from '@/setup-tests/server';
 | 
					import { server } from '@/setup-tests/server';
 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
import { renderWithQueryClient, within } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
import { Team, TeamId } from '@/react/portainer/users/teams/types';
 | 
					import { Team, TeamId } from '@/react/portainer/users/teams/types';
 | 
				
			||||||
import { createMockTeams } from '@/react-tools/test-mocks';
 | 
					import { createMockTeams } from '@/react-tools/test-mocks';
 | 
				
			||||||
import { UserId } from '@/portainer/users/types';
 | 
					import { UserId } from '@/portainer/users/types';
 | 
				
			||||||
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { ResourceControlOwnership, AccessControlFormData } from '../types';
 | 
					import { ResourceControlOwnership, AccessControlFormData } from '../types';
 | 
				
			||||||
import { ResourceControlViewModel } from '../models/ResourceControlViewModel';
 | 
					import { ResourceControlViewModel } from '../models/ResourceControlViewModel';
 | 
				
			||||||
| 
						 | 
					@ -304,7 +306,6 @@ async function renderComponent(
 | 
				
			||||||
  { isAdmin = false, hideTitle = false, teams, users }: AdditionalProps = {}
 | 
					  { isAdmin = false, hideTitle = false, teams, users }: AdditionalProps = {}
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
  const user = new UserViewModel({ Username: 'user', Role: isAdmin ? 1 : 2 });
 | 
					  const user = new UserViewModel({ Username: 'user', Role: isAdmin ? 1 : 2 });
 | 
				
			||||||
  const state = { user };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (teams) {
 | 
					  if (teams) {
 | 
				
			||||||
    server.use(http.get('/api/teams', () => HttpResponse.json(teams)));
 | 
					    server.use(http.get('/api/teams', () => HttpResponse.json(teams)));
 | 
				
			||||||
| 
						 | 
					@ -314,16 +315,18 @@ async function renderComponent(
 | 
				
			||||||
    server.use(http.get('/api/users', () => HttpResponse.json(users)));
 | 
					    server.use(http.get('/api/users', () => HttpResponse.json(users)));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const renderResult = renderWithQueryClient(
 | 
					  const Wrapped = withTestRouter(
 | 
				
			||||||
    <UserContext.Provider value={state}>
 | 
					    withTestQueryProvider(withUserProvider(AccessControlForm, user))
 | 
				
			||||||
      <AccessControlForm
 | 
					  );
 | 
				
			||||||
        environmentId={1}
 | 
					
 | 
				
			||||||
        errors={{}}
 | 
					  const renderResult = render(
 | 
				
			||||||
        values={values}
 | 
					    <Wrapped
 | 
				
			||||||
        onChange={onChange}
 | 
					      environmentId={1}
 | 
				
			||||||
        hideTitle={hideTitle}
 | 
					      errors={{}}
 | 
				
			||||||
      />
 | 
					      values={values}
 | 
				
			||||||
    </UserContext.Provider>
 | 
					      onChange={onChange}
 | 
				
			||||||
 | 
					      hideTitle={hideTitle}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await expect(
 | 
					  await expect(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,13 @@
 | 
				
			||||||
import _ from 'lodash';
 | 
					import _ from 'lodash';
 | 
				
			||||||
import { http, HttpResponse } from 'msw';
 | 
					import { http, HttpResponse } from 'msw';
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { createMockTeams, createMockUsers } from '@/react-tools/test-mocks';
 | 
					import { createMockTeams, createMockUsers } from '@/react-tools/test-mocks';
 | 
				
			||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
import { server } from '@/setup-tests/server';
 | 
					import { server } from '@/setup-tests/server';
 | 
				
			||||||
import { Role } from '@/portainer/users/types';
 | 
					import { Role } from '@/portainer/users/types';
 | 
				
			||||||
import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  ResourceControlOwnership,
 | 
					  ResourceControlOwnership,
 | 
				
			||||||
| 
						 | 
					@ -145,9 +147,11 @@ async function renderComponent(
 | 
				
			||||||
  resourceType: ResourceControlType = ResourceControlType.Container,
 | 
					  resourceType: ResourceControlType = ResourceControlType.Container,
 | 
				
			||||||
  resourceControl?: ResourceControlViewModel
 | 
					  resourceControl?: ResourceControlViewModel
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
  const WithUser = withUserProvider(AccessControlPanelDetails);
 | 
					  const Wrapped = withTestQueryProvider(
 | 
				
			||||||
  const queries = renderWithQueryClient(
 | 
					    withTestRouter(withUserProvider(AccessControlPanelDetails))
 | 
				
			||||||
    <WithUser resourceControl={resourceControl} resourceType={resourceType} />
 | 
					  );
 | 
				
			||||||
 | 
					  const queries = render(
 | 
				
			||||||
 | 
					    <Wrapped resourceControl={resourceControl} resourceType={resourceType} />
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  await expect(queries.findByText('Ownership')).resolves.toBeVisible();
 | 
					  await expect(queries.findByText('Ownership')).resolves.toBeVisible();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,10 @@
 | 
				
			||||||
import userEvent from '@testing-library/user-event';
 | 
					import userEvent from '@testing-library/user-event';
 | 
				
			||||||
 | 
					import { render, waitFor } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { renderWithQueryClient, waitFor } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { CreateUserAccessToken } from './CreateUserAccessToken';
 | 
					import { CreateUserAccessToken } from './CreateUserAccessToken';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,9 +35,9 @@ test('the button is disabled when all fields are blank and enabled when all fiel
 | 
				
			||||||
function renderComponent() {
 | 
					function renderComponent() {
 | 
				
			||||||
  const user = new UserViewModel({ Username: 'user' });
 | 
					  const user = new UserViewModel({ Username: 'user' });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return renderWithQueryClient(
 | 
					  const Wrapped = withTestQueryProvider(
 | 
				
			||||||
    <UserContext.Provider value={{ user }}>
 | 
					    withUserProvider(withTestRouter(CreateUserAccessToken), user)
 | 
				
			||||||
      <CreateUserAccessToken />
 | 
					 | 
				
			||||||
    </UserContext.Provider>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return render(<Wrapped />);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,6 @@
 | 
				
			||||||
import { vi } from 'vitest';
 | 
					import { vi } from 'vitest';
 | 
				
			||||||
import userEvent from '@testing-library/user-event';
 | 
					import userEvent from '@testing-library/user-event';
 | 
				
			||||||
 | 
					import { render, screen } from '@testing-library/react';
 | 
				
			||||||
import { render, screen } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  CustomTemplatesVariablesField,
 | 
					  CustomTemplatesVariablesField,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,6 @@
 | 
				
			||||||
import { vi } from 'vitest';
 | 
					import { vi } from 'vitest';
 | 
				
			||||||
import userEvent from '@testing-library/user-event';
 | 
					import userEvent from '@testing-library/user-event';
 | 
				
			||||||
 | 
					import { render, screen } from '@testing-library/react';
 | 
				
			||||||
import { render, screen } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { VariableFieldItem } from './VariableFieldItem';
 | 
					import { VariableFieldItem } from './VariableFieldItem';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,6 @@
 | 
				
			||||||
import userEvent from '@testing-library/user-event';
 | 
					import userEvent from '@testing-library/user-event';
 | 
				
			||||||
import { PropsWithChildren } from 'react';
 | 
					import { PropsWithChildren } from 'react';
 | 
				
			||||||
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
import { render } from '@/react-tools/test-utils';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { AppTemplatesListItem } from './AppTemplatesListItem';
 | 
					import { AppTemplatesListItem } from './AppTemplatesListItem';
 | 
				
			||||||
import { TemplateViewModel } from './view-model';
 | 
					import { TemplateViewModel } from './view-model';
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { TeamAssociationSelector } from './TeamAssociationSelector';
 | 
					import { TeamAssociationSelector } from './TeamAssociationSelector';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,9 +15,9 @@ test('renders correctly', () => {
 | 
				
			||||||
function renderComponent() {
 | 
					function renderComponent() {
 | 
				
			||||||
  const user = new UserViewModel({ Username: 'user' });
 | 
					  const user = new UserViewModel({ Username: 'user' });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return renderWithQueryClient(
 | 
					  const Wrapped = withTestQueryProvider(
 | 
				
			||||||
    <UserContext.Provider value={{ user }}>
 | 
					    withUserProvider(TeamAssociationSelector, user)
 | 
				
			||||||
      <TeamAssociationSelector users={[]} memberships={[]} teamId={3} />
 | 
					 | 
				
			||||||
    </UserContext.Provider>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return render(<Wrapped users={[]} memberships={[]} teamId={3} />);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { TeamMembersList } from './TeamMembersList';
 | 
					import { TeamMembersList } from './TeamMembersList';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,11 +15,11 @@ test('renders correctly', () => {
 | 
				
			||||||
function renderComponent() {
 | 
					function renderComponent() {
 | 
				
			||||||
  const user = new UserViewModel({ Username: 'user' });
 | 
					  const user = new UserViewModel({ Username: 'user' });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return renderWithQueryClient(
 | 
					  const Wrapped = withTestQueryProvider(
 | 
				
			||||||
    <UserContext.Provider value={{ user }}>
 | 
					    withUserProvider(TeamMembersList, user)
 | 
				
			||||||
      <TeamMembersList users={[]} roles={{}} teamId={3} />
 | 
					 | 
				
			||||||
    </UserContext.Provider>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return render(<Wrapped users={[]} roles={{}} teamId={3} />);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test.todo('when users list is empty, add all users button is disabled');
 | 
					test.todo('when users list is empty, add all users button is disabled');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					import { render } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { UsersList } from './UsersList';
 | 
					import { UsersList } from './UsersList';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,11 +14,10 @@ test('renders correctly', () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function renderComponent() {
 | 
					function renderComponent() {
 | 
				
			||||||
  const user = new UserViewModel({ Username: 'user' });
 | 
					  const user = new UserViewModel({ Username: 'user' });
 | 
				
			||||||
  return renderWithQueryClient(
 | 
					
 | 
				
			||||||
    <UserContext.Provider value={{ user }}>
 | 
					  const Wrapped = withTestQueryProvider(withUserProvider(UsersList, user));
 | 
				
			||||||
      <UsersList users={[]} teamId={3} />
 | 
					
 | 
				
			||||||
    </UserContext.Provider>
 | 
					  return render(<Wrapped users={[]} teamId={3} />);
 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test.todo('when users list is empty, add all users button is disabled');
 | 
					test.todo('when users list is empty, add all users button is disabled');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,15 @@
 | 
				
			||||||
import userEvent from '@testing-library/user-event';
 | 
					import userEvent from '@testing-library/user-event';
 | 
				
			||||||
 | 
					import { render, waitFor } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { renderWithQueryClient, waitFor } from '@/react-tools/test-utils';
 | 
					import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { CreateTeamForm } from './CreateTeamForm';
 | 
					import { CreateTeamForm } from './CreateTeamForm';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('filling the name should make the submit button clickable and emptying it should make it disabled', async () => {
 | 
					test('filling the name should make the submit button clickable and emptying it should make it disabled', async () => {
 | 
				
			||||||
  const { findByLabelText, findByText } = renderWithQueryClient(
 | 
					  const Wrapped = withTestQueryProvider(CreateTeamForm);
 | 
				
			||||||
    <CreateTeamForm users={[]} teams={[]} />
 | 
					
 | 
				
			||||||
 | 
					  const { findByLabelText, findByText } = render(
 | 
				
			||||||
 | 
					    <Wrapped users={[]} teams={[]} />
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const button = await findByText('Create team');
 | 
					  const button = await findByText('Create team');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
import { UserContext } from '@/react/hooks/useUser';
 | 
					import { render, within } from '@testing-library/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { UserViewModel } from '@/portainer/models/user';
 | 
					import { UserViewModel } from '@/portainer/models/user';
 | 
				
			||||||
import { render, within } from '@/react-tools/test-utils';
 | 
					import { withUserProvider } from '@/react/test-utils/withUserProvider';
 | 
				
			||||||
 | 
					import { withTestRouter } from '@/react/test-utils/withRouter';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { TestSidebarProvider } from '../useSidebarState';
 | 
					import { TestSidebarProvider } from '../useSidebarState';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,11 +32,11 @@ test('dashboard items should render correctly', () => {
 | 
				
			||||||
function renderComponent() {
 | 
					function renderComponent() {
 | 
				
			||||||
  const user = new UserViewModel({ Username: 'user' });
 | 
					  const user = new UserViewModel({ Username: 'user' });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Wrapped = withUserProvider(withTestRouter(AzureSidebar), user);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return render(
 | 
					  return render(
 | 
				
			||||||
    <UserContext.Provider value={{ user }}>
 | 
					    <TestSidebarProvider>
 | 
				
			||||||
      <TestSidebarProvider>
 | 
					      <Wrapped environmentId={1} />
 | 
				
			||||||
        <AzureSidebar environmentId={1} />
 | 
					    </TestSidebarProvider>
 | 
				
			||||||
      </TestSidebarProvider>
 | 
					 | 
				
			||||||
    </UserContext.Provider>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,49 @@
 | 
				
			||||||
 | 
					import { ComponentType } from 'react';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  ReactStateDeclaration,
 | 
				
			||||||
 | 
					  UIRouter,
 | 
				
			||||||
 | 
					  UIRouterReact,
 | 
				
			||||||
 | 
					  UIView,
 | 
				
			||||||
 | 
					  hashLocationPlugin,
 | 
				
			||||||
 | 
					  servicesPlugin,
 | 
				
			||||||
 | 
					} from '@uirouter/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A helper function to wrap a component with a UIRouter Provider.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * should only be used in tests
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function withTestRouter<T>(
 | 
				
			||||||
 | 
					  WrappedComponent: ComponentType<T>,
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    route = '/',
 | 
				
			||||||
 | 
					    stateConfig = [],
 | 
				
			||||||
 | 
					  }: { route?: string; stateConfig?: Array<ReactStateDeclaration> } = {}
 | 
				
			||||||
 | 
					): ComponentType<T> {
 | 
				
			||||||
 | 
					  const router = new UIRouterReact();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // router.trace.enable(Category.TRANSITION);
 | 
				
			||||||
 | 
					  router.plugin(servicesPlugin);
 | 
				
			||||||
 | 
					  router.plugin(hashLocationPlugin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Set up your custom state configuration
 | 
				
			||||||
 | 
					  stateConfig.forEach((state) => router.stateRegistry.register(state));
 | 
				
			||||||
 | 
					  router.urlService.rules.initial({ state: route });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Try to create a nice displayName for React Dev Tools.
 | 
				
			||||||
 | 
					  const displayName =
 | 
				
			||||||
 | 
					    WrappedComponent.displayName || WrappedComponent.name || 'Component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function WrapperComponent(props: T & JSX.IntrinsicAttributes) {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <UIRouter router={router}>
 | 
				
			||||||
 | 
					        <UIView />
 | 
				
			||||||
 | 
					        <WrappedComponent {...props} />
 | 
				
			||||||
 | 
					      </UIRouter>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  WrapperComponent.displayName = `withTestRouter(${displayName})`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return WrapperComponent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					import { ComponentType } from 'react';
 | 
				
			||||||
 | 
					import { QueryClient } from 'react-query';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { withReactQuery } from '@/react-tools/withReactQuery';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function withTestQueryProvider<T>(
 | 
				
			||||||
 | 
					  WrappedComponent: ComponentType<T & JSX.IntrinsicAttributes>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					  const testQueryClient = new QueryClient({
 | 
				
			||||||
 | 
					    defaultOptions: { queries: { retry: false } },
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return withReactQuery(WrappedComponent, testQueryClient);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@ import { StatusResponse } from '@/react/portainer/system/useSystemStatus';
 | 
				
			||||||
import { createMockTeams } from '@/react-tools/test-mocks';
 | 
					import { createMockTeams } from '@/react-tools/test-mocks';
 | 
				
			||||||
import { PublicSettingsResponse } from '@/react/portainer/settings/types';
 | 
					import { PublicSettingsResponse } from '@/react/portainer/settings/types';
 | 
				
			||||||
import { UserId } from '@/portainer/users/types';
 | 
					import { UserId } from '@/portainer/users/types';
 | 
				
			||||||
 | 
					import { VersionResponse } from '@/react/portainer/system/useSystemVersion';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { azureHandlers } from './setup-handlers/azure';
 | 
					import { azureHandlers } from './setup-handlers/azure';
 | 
				
			||||||
import { dockerHandlers } from './setup-handlers/docker';
 | 
					import { dockerHandlers } from './setup-handlers/docker';
 | 
				
			||||||
| 
						 | 
					@ -85,6 +86,9 @@ export const handlers = [
 | 
				
			||||||
  http.get<never, never, Partial<StatusResponse>>('/api/status', () =>
 | 
					  http.get<never, never, Partial<StatusResponse>>('/api/status', () =>
 | 
				
			||||||
    HttpResponse.json({})
 | 
					    HttpResponse.json({})
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
 | 
					  http.get<never, never, Partial<VersionResponse>>('/api/system/version', () =>
 | 
				
			||||||
 | 
					    HttpResponse.json({ ServerVersion: 'v2.10.0' })
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
  http.get('/api/teams/:id/memberships', () => HttpResponse.json([])),
 | 
					  http.get('/api/teams/:id/memberships', () => HttpResponse.json([])),
 | 
				
			||||||
  http.get('/api/endpoints/agent_versions', () => HttpResponse.json([])),
 | 
					  http.get('/api/endpoints/agent_versions', () => HttpResponse.json([])),
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					import 'vitest-dom/extend-expect';
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,7 @@ export default defineConfig({
 | 
				
			||||||
  test: {
 | 
					  test: {
 | 
				
			||||||
    globals: true,
 | 
					    globals: true,
 | 
				
			||||||
    environment: 'jsdom',
 | 
					    environment: 'jsdom',
 | 
				
			||||||
    setupFiles: ['./app/setup-tests/setup-msw.ts', './app/setup-tests/stub-modules.ts'],
 | 
					    setupFiles: ['./app/setup-tests/setup-msw.ts', './app/setup-tests/stub-modules.ts', './app/setup-tests/setup.ts'],
 | 
				
			||||||
    coverage: {
 | 
					    coverage: {
 | 
				
			||||||
      reporter: ['text', 'html'],
 | 
					      reporter: ['text', 'html'],
 | 
				
			||||||
      exclude: ['node_modules/', 'app/setup-tests/global-setup.js'],
 | 
					      exclude: ['node_modules/', 'app/setup-tests/global-setup.js'],
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue