diff --git a/packages/manager/apps/vrack-services/package.json b/packages/manager/apps/vrack-services/package.json index 685c8e08e29e..dc62cadc6bb6 100644 --- a/packages/manager/apps/vrack-services/package.json +++ b/packages/manager/apps/vrack-services/package.json @@ -12,20 +12,20 @@ "author": "OVH SAS", "scripts": { "beta-test:e2e": "tsc && node ../../../../scripts/run-playwright-bdd.js", - "beta-test:e2e:ci": "tsc && node ../../../../scripts/run-playwright-bdd.js --ci", + "beta-test:e2e:cii": "tsc && node ../../../../scripts/run-playwright-bdd.js --ci", "build": "tsc && vite build", + "coverage": "vitest run --coverage", "dev": "tsc && vite", "start": "lerna exec --stream --scope='@ovh-ux/manager-vrack-services-app' --include-dependencies -- npm run build --if-present", "start:dev": "lerna exec --stream --scope='@ovh-ux/manager-vrack-services-app' --include-dependencies -- npm run dev --if-present", "start:watch": "lerna exec --stream --parallel --scope='@ovh-ux/manager-vrack-services-app' --include-dependencies -- npm run dev:watch --if-present", "test": "vitest run", - "test:coverage": "vitest run --coverage", - "test:e2e": "tsc && node ../../../../scripts/run-playwright-bdd.js", - "test:e2e:cii": "tsc && node ../../../../scripts/run-playwright-bdd.js --ci" + "test:coverage": "vitest run --coverage" }, "dependencies": { "@ovh-ux/manager-config": "^8.0.0", "@ovh-ux/manager-core-api": "^0.9.0", + "@ovh-ux/manager-core-utils": "*", "@ovh-ux/manager-module-order": "^0.8.0", "@ovh-ux/manager-react-components": "^1.41.1", "@ovh-ux/manager-react-core-application": "^0.11.1", @@ -51,17 +51,22 @@ "@ovh-ux/manager-vite-config": "^0.8.3", "@playwright/test": "^1.41.2", "@tanstack/react-query-devtools": "^5.51.21", + "@testing-library/jest-dom": "^6.5.0", + "@testing-library/react": "^16.0.1", + "@testing-library/user-event": "^14.5.2", "@types/jest": "27.x", - "@vitejs/plugin-react": "^4.2.1", - "@vitest/coverage-v8": "^1.2.0", + "@vitejs/plugin-react": "^4.3.0", + "@vitest/coverage-v8": "^2.1.4", "c8": "^9.1.0", + "element-internals-polyfill": "^1.3.11", "jest": "27.x", "msw": "2.1.7", "ts-jest": "27.x", "ts-loader": "^9.5.1", "ts-node": "^10.9.1", + "typescript": "^4.3.2", "vite": "^5.2.13", - "vitest": "^1.2.0" + "vitest": "^2.1.4" }, "msw": { "workerDirectory": "./public" diff --git a/packages/manager/apps/vrack-services/playwright.config.ts b/packages/manager/apps/vrack-services/playwright.config.ts index 4a033cc8d87d..feb249bcbe3f 100644 --- a/packages/manager/apps/vrack-services/playwright.config.ts +++ b/packages/manager/apps/vrack-services/playwright.config.ts @@ -12,4 +12,9 @@ export default defineConfig({ // Collect trace when retrying the failed test. trace: 'retain-on-failure', }, + testMatch: '**/*.e2e.ts', + webServer: { + command: 'yarn run dev', + url: 'http://localhost:9000/', + }, }); diff --git a/packages/manager/apps/vrack-services/setupTests.ts b/packages/manager/apps/vrack-services/setupTests.ts new file mode 100644 index 000000000000..bbdaae5c93ac --- /dev/null +++ b/packages/manager/apps/vrack-services/setupTests.ts @@ -0,0 +1,29 @@ +import { vi } from 'vitest'; +import '@testing-library/jest-dom'; + +vi.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: (translationKey: string) => translationKey, + i18n: { language: 'fr_FR' }, + }), +})); + +vi.mock('@ovh-ux/manager-react-shell-client', async (importOriginal) => { + const original: typeof import('@ovh-ux/manager-react-shell-client') = await importOriginal(); + return { + ...original, + useOvhTracking: () => ({ trackClick: vi.fn(), trackPage: vi.fn() }), + }; +}); + +vi.mock('react-router-dom', async (importOriginal) => { + const original: typeof import('react-router-dom') = await importOriginal(); + return { + ...original, + useSearchParams: () => [{ get: (str: string) => str }], + useNavigate: vi.fn(), + useLocation: vi.fn().mockReturnValue({ + pathname: 'pathname', + }), + }; +}); diff --git a/packages/manager/apps/vrack-services/src/components/Breadcrumb.spec.tsx b/packages/manager/apps/vrack-services/src/components/Breadcrumb.spec.tsx new file mode 100644 index 000000000000..4f3afced0e88 --- /dev/null +++ b/packages/manager/apps/vrack-services/src/components/Breadcrumb.spec.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { describe, expect, it, vi } from 'vitest'; +import { render, waitFor } from '@testing-library/react'; +import { Breadcrumb, BreadcrumbProps } from './Breadcrumb.component'; + +/** Render */ +const renderComponent = ({ items, overviewUrl }: BreadcrumbProps) => { + return render(); +}; + +/** END RENDER */ + +describe('Breadcrumb Component', () => { + it('should display ODS breadcrumb', async () => { + const { getByRole } = renderComponent({ + items: [], + }); + + await waitFor(() => { + expect(getByRole('navigation')).toBeDefined(); + }); + }); +}); diff --git a/packages/manager/apps/vrack-services/src/components/CreateVrack.spec.tsx b/packages/manager/apps/vrack-services/src/components/CreateVrack.spec.tsx new file mode 100644 index 000000000000..b8f428ecafdd --- /dev/null +++ b/packages/manager/apps/vrack-services/src/components/CreateVrack.spec.tsx @@ -0,0 +1,106 @@ +import React from 'react'; +import { describe, expect, it, vi } from 'vitest'; +import { render, fireEvent, waitFor, act } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { DetailedOrder } from '@ovh-ux/manager-module-order'; +import { + ShellContext, + ShellContextType, +} from '@ovh-ux/manager-react-shell-client'; +import { CreateVrack, CreateVrackProps } from './CreateVrack.component'; +import { createVrackOnlyCart } from '@/utils/cart'; + +const queryClient = new QueryClient(); + +const shellContext = { + environment: { + user: { ovhSubsidiary: 'FR' }, + }, +}; + +const renderComponent = ({ closeModal }: CreateVrackProps) => { + return render( + + + + + , + ); +}; + +/** MOCKS */ +const closeModalMock = vi.fn(); + +vi.mock('@/utils/cart', async (importOriginal) => { + const original: typeof import('@/utils/cart') = await importOriginal(); + return { + ...original, + createVrackOnlyCart: vi.fn(), + }; +}); + +vi.mock('@ovh-ux/manager-module-order', async (importOriginal) => { + const original: typeof import('@ovh-ux/manager-module-order') = await importOriginal(); + return { + ...original, + useOrderPollingStatus: () => ({ + data: [] as DetailedOrder[], + }), + }; +}); + +/** END MOCKS */ + +describe('CreateVrack Component', () => { + it('should display the contracts after click the button create a vrack', async () => { + vi.mocked(createVrackOnlyCart).mockResolvedValue({ + contractList: [ + { + name: 'test', + url: 'test', + content: 'test', + }, + { + name: 'test2', + url: 'test2', + content: 'test2', + }, + ], + cartId: '1', + }); + + const { getByText } = renderComponent({ closeModal: closeModalMock }); + const button = await getByText('modalCreateNewVrackButtonLabel'); + await act(() => { + fireEvent.click(button); + }); + + await waitFor(() => { + expect(createVrackOnlyCart).toHaveBeenCalledWith('FR'); + expect(getByText('modalConfirmContractsCheckboxLabel')).not.toBeNull(); + expect( + getByText('modalVrackCreationSubmitOrderButtonLabel'), + ).toBeDefined(); + }); + }); + + it('should display an error message if cart creation fail', async () => { + vi.mocked(createVrackOnlyCart).mockRejectedValue({ + response: { data: { message: 'api-error' } }, + }); + + const { getByText } = renderComponent({ closeModal: closeModalMock }); + const button = await getByText('modalCreateNewVrackButtonLabel'); + + await act(() => { + fireEvent.click(button); + }); + + await waitFor(() => { + expect(createVrackOnlyCart).toHaveBeenCalledWith('FR'); + expect(getByText('api-error')).toBeDefined(); + }); + }); +}); diff --git a/packages/manager/apps/vrack-services/src/components/DeliveringMessages.spec.tsx b/packages/manager/apps/vrack-services/src/components/DeliveringMessages.spec.tsx new file mode 100644 index 000000000000..619cc6522736 --- /dev/null +++ b/packages/manager/apps/vrack-services/src/components/DeliveringMessages.spec.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { describe, expect, it, vi } from 'vitest'; +import { render } from '@testing-library/react'; +import { + ShellContext, + ShellContextType, +} from '@ovh-ux/manager-react-shell-client'; +import { DetailedOrder } from '@ovh-ux/manager-module-order'; +import { ErrorBannerProps, ErrorPage } from './ErrorPage.component'; +import { + DeliveringMessages, + DeliveringMessagesProps, +} from './DeliveringMessages.component'; + +/** MOCKS */ +vi.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: (translationKey: string, params?: any) => { + const flattenParams = params + ? Object.keys(params).reduce((previous, current) => { + return `${previous} | ${current}:${params[current]}`; + }, '') + : undefined; + return flattenParams + ? `${translationKey}${flattenParams}` + : translationKey; + }, + i18n: { language: 'fr_FR' }, + }), +})); +/** END MOCKS */ +/** Render */ +const renderComponent = ({ orders }: { orders?: DetailedOrder[] }) => { + return render(); +}; + +/** END RENDER */ + +describe('DeliveringMessages Component', () => { + it('should display list of ongoing orders', async () => { + const { getByText } = renderComponent({ + orders: [ + { + date: '2024-12-06T12:10:00.000Z', + orderId: 1, + status: 'delivering', + } as DetailedOrder, + ], + }); + + const date = new Date('2024-12-06T12:10:00.000Z'); + + expect( + getByText( + `order-text | date:${date.toLocaleDateString( + 'fr-FR', + )} | time:${date.getHours()}:${date.getMinutes()} | status:orderStatus-delivering`, + ), + ).toBeDefined(); + }); +}); diff --git a/packages/manager/apps/vrack-services/src/components/ErrorPage.spec.tsx b/packages/manager/apps/vrack-services/src/components/ErrorPage.spec.tsx new file mode 100644 index 000000000000..30e951790792 --- /dev/null +++ b/packages/manager/apps/vrack-services/src/components/ErrorPage.spec.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { describe, expect, it, vi } from 'vitest'; +import { render } from '@testing-library/react'; +import { + ShellContext, + ShellContextType, +} from '@ovh-ux/manager-react-shell-client'; +import { ErrorBannerProps, ErrorPage } from './ErrorPage.component'; + +/** Render */ +const shellContext = { + environment: { + user: { ovhSubsidiary: 'FR' }, + }, + shell: { + tracking: { + trackClick: vi.fn(), + trackPage: vi.fn(), + init: vi.fn(), + }, + }, +}; + +const renderComponent = ({ error }: ErrorBannerProps) => { + return render( + + + , + ); +}; + +/** END RENDER */ + +describe('ErrorPage Component', () => { + it('should display an api error message with queryid', async () => { + const { getByText } = renderComponent({ + error: { + response: { + data: { message: 'api-error-message' }, + headers: { + 'x-ovh-queryid': 'api-error-queryid', + }, + }, + }, + }); + expect(getByText('api-error-message')).toBeDefined(); + expect(getByText('api-error-queryid', { exact: false })).toBeDefined(); + }); +}); diff --git a/packages/manager/apps/vrack-services/src/components/FormField.component.tsx b/packages/manager/apps/vrack-services/src/components/FormField.component.tsx index 70fa05b1b2f5..e464b591ce62 100644 --- a/packages/manager/apps/vrack-services/src/components/FormField.component.tsx +++ b/packages/manager/apps/vrack-services/src/components/FormField.component.tsx @@ -51,7 +51,7 @@ export const FormField: React.FC = ({ {children} {helperText && (
- {label} + {helperText}
)} {visualHint && ( diff --git a/packages/manager/apps/vrack-services/src/components/FormField.spec.tsx b/packages/manager/apps/vrack-services/src/components/FormField.spec.tsx new file mode 100644 index 000000000000..69cee02065e1 --- /dev/null +++ b/packages/manager/apps/vrack-services/src/components/FormField.spec.tsx @@ -0,0 +1,72 @@ +import React from 'react'; +import { describe, expect, it, vi } from 'vitest'; +import { render, waitFor } from '@testing-library/react'; +import { FormField } from './FormField.component'; + +const renderComponent = ({ + children, + label, + className = '', + fullWidth, + isLoading, + helperText, + visualHint, + error, +}: React.PropsWithChildren<{ + className?: string; + label: string; + fullWidth?: boolean; + isLoading?: boolean; + helperText?: string; + visualHint?: string; + error?: string; +}>) => { + return render( + + {children} + , + ); +}; + +describe('FormField Component', () => { + it('should display an inline form field', async () => { + const { getByText } = renderComponent({ + label: 'form-field-label', + children: 'form-field-children', + helperText: 'form-field-helper-text', + visualHint: 'form-field-visual-hint', + }); + + await waitFor(() => { + const labelElement = getByText('form-field-label'); + expect(labelElement).toBeInTheDocument(); + const OsdsFormField = labelElement.closest('osds-form-field'); + expect(OsdsFormField).toHaveAttribute('inline'); + expect(getByText('form-field-children')).toBeDefined(); + expect(getByText('form-field-helper-text')).toBeDefined(); + expect(getByText('form-field-visual-hint')).toBeDefined(); + }); + }); + + it('should display form field', async () => { + const { getByText } = renderComponent({ + label: 'form-field-label', + fullWidth: true, + }); + + await waitFor(() => { + const labelElement = getByText('form-field-label'); + expect(labelElement).toBeInTheDocument(); + const OsdsFormField = labelElement.closest('osds-form-field'); + expect(OsdsFormField).not.toHaveAttribute('inline'); + }); + }); +}); diff --git a/packages/manager/apps/vrack-services/src/components/LoadingText.component.tsx b/packages/manager/apps/vrack-services/src/components/LoadingText.component.tsx index 9eed7ea3aa8f..6b89f02a57d9 100644 --- a/packages/manager/apps/vrack-services/src/components/LoadingText.component.tsx +++ b/packages/manager/apps/vrack-services/src/components/LoadingText.component.tsx @@ -17,7 +17,11 @@ export const LoadingText: React.FC = ({ description, }) => (
- +
{ + return render(); +}; + +describe('LoadingText Component', () => { + it('should display a loader with a text aside and a description', async () => { + const { getByTestId, getByText } = renderComponent({ + title: 'test', + description: 'description', + }); + expect(getByTestId('loading-text-spinner')).toBeDefined(); + expect(getByText('test')).toBeDefined(); + expect(getByText('description')).toBeDefined(); + }); +}); diff --git a/packages/manager/apps/vrack-services/src/components/OrderSubmitModalContent.spec.tsx b/packages/manager/apps/vrack-services/src/components/OrderSubmitModalContent.spec.tsx new file mode 100644 index 000000000000..e8953db6475c --- /dev/null +++ b/packages/manager/apps/vrack-services/src/components/OrderSubmitModalContent.spec.tsx @@ -0,0 +1,94 @@ +import React from 'react'; +import { describe, expect, it, vi } from 'vitest'; +import { act, fireEvent, render, waitFor } from '@testing-library/react'; +import { + ShellContext, + ShellContextType, +} from '@ovh-ux/manager-react-shell-client'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { postOrderCartCartIdCheckout } from '@ovh-ux/manager-module-order'; +import userEvent from '@testing-library/user-event'; +import { OrderSubmitModalContent } from './OrderSubmitModalContent.component'; + +/** MOCKS */ + +const onErrorMock = vi.fn(); + +vi.mock('@ovh-ux/manager-module-order', async (importOriginal) => { + const original: typeof import('@ovh-ux/manager-module-order') = await importOriginal(); + return { + ...original, + postOrderCartCartIdCheckout: vi.fn(), + }; +}); + +/** END MOCKS */ + +/** RENDER */ +const queryClient = new QueryClient(); + +const shellContext = { + environment: { + user: { ovhSubsidiary: 'FR' }, + }, +}; + +const renderComponent = ({ onError }: { onError: () => void }) => { + return render( + + + + , + + , + ); +}; + +/** END RENDER */ +/** TESTS */ +describe('OrderSubmitModalContent Component', () => { + it('should display an error message if order fail', async () => { + const user = userEvent.setup(); + + vi.mocked(postOrderCartCartIdCheckout).mockRejectedValue({ + response: { data: { message: 'api-error' } }, + }); + + const { getByText } = renderComponent({ onError: onErrorMock }); + + const button = getByText('order-submit-modal-button-label'); + const checkbox = getByText('modalConfirmContractsCheckboxLabel'); + + expect(button).toHaveAttribute('disabled'); + + await act(() => { + user.click(checkbox); + }); + + await waitFor(() => { + expect(button).not.toHaveAttribute('disabled'); + }); + + await act(() => { + fireEvent.click(button); + }); + + await waitFor(() => { + expect(postOrderCartCartIdCheckout).toHaveBeenCalledWith({ + cartId: '1', + autoPayWithPreferredPaymentMethod: true, + waiveRetractationPeriod: true, + }); + expect(getByText('api-error')).toBeDefined(); + expect(onErrorMock).toHaveBeenCalledOnce(); + }); + }); +}); diff --git a/packages/manager/apps/vrack-services/src/components/ProductStatusChip.component.tsx b/packages/manager/apps/vrack-services/src/components/ProductStatusChip.component.tsx index a412a447cbf3..d5d1661bc2d0 100644 --- a/packages/manager/apps/vrack-services/src/components/ProductStatusChip.component.tsx +++ b/packages/manager/apps/vrack-services/src/components/ProductStatusChip.component.tsx @@ -24,6 +24,10 @@ export const ProductStatusChip: React.FC = ({ {t(productStatus)} ) : ( - + ); }; diff --git a/packages/manager/apps/vrack-services/src/components/ProductStatusChip.spec.tsx b/packages/manager/apps/vrack-services/src/components/ProductStatusChip.spec.tsx new file mode 100644 index 000000000000..c4b745550475 --- /dev/null +++ b/packages/manager/apps/vrack-services/src/components/ProductStatusChip.spec.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { describe, expect, it, vi } from 'vitest'; +import { act, fireEvent, render } from '@testing-library/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { + ProductStatusChip, + ProductStatusChipProps, +} from './ProductStatusChip.component'; +import { ProductStatus } from '@/data'; + +const renderComponent = ({ productStatus }: ProductStatusChipProps) => { + return render(); +}; + +describe('ProductStatusChip Component', () => { + it.each([ + [ProductStatus.ACTIVE, ODS_THEME_COLOR_INTENT.success], + [ProductStatus.SUSPENDED, ODS_THEME_COLOR_INTENT.default], + [ProductStatus.DRAFT, ODS_THEME_COLOR_INTENT.info], + ])('should display the %s status in the %s color', (status, color) => { + const { getByText } = renderComponent({ productStatus: status }); + expect(getByText(status)).toHaveAttribute('color', color); + }); + + it('should display a loader if status not available', async () => { + const { getByTestId } = renderComponent({ productStatus: undefined }); + expect(getByTestId('status-chip-spinner')).toBeDefined(); + }); +}); diff --git a/packages/manager/apps/vrack-services/src/components/display-name/DisplayName.component.tsx b/packages/manager/apps/vrack-services/src/components/display-name/DisplayName.component.tsx index d4c738e25fcf..c92d1cef41c0 100644 --- a/packages/manager/apps/vrack-services/src/components/display-name/DisplayName.component.tsx +++ b/packages/manager/apps/vrack-services/src/components/display-name/DisplayName.component.tsx @@ -38,6 +38,7 @@ export const DisplayName: React.FC = ({ }); navigate(urls.overview.replace(':id', vs.id)); }} + data-testid="display-name-link" > {name} @@ -55,6 +56,7 @@ export const DisplayName: React.FC = ({ }); navigate(urls.overviewEdit.replace(':id', vs.id)); }} + data-testid="display-name-edit-button" > {name} diff --git a/packages/manager/apps/vrack-services/src/components/display-name/DisplayName.spec.tsx b/packages/manager/apps/vrack-services/src/components/display-name/DisplayName.spec.tsx new file mode 100644 index 000000000000..2945e63e3df2 --- /dev/null +++ b/packages/manager/apps/vrack-services/src/components/display-name/DisplayName.spec.tsx @@ -0,0 +1,59 @@ +import React from 'react'; +import { describe, expect, it, vi } from 'vitest'; +import { act, fireEvent, render } from '@testing-library/react'; +import { DisplayName } from '@/components/display-name/DisplayName.component'; +import vrackServicesList from '../../../mocks/vrack-services/get-vrack-services.json'; +import { VrackServicesWithIAM } from '@/data'; + +const defaultVs = vrackServicesList[0] as VrackServicesWithIAM; + +const renderComponent = ({ + isListing, + vs = defaultVs, +}: { + isListing?: boolean; + vs?: VrackServicesWithIAM; +}) => { + return render(); +}; + +describe('DisplayName Component', () => { + it('In listing, should display the display name with link', async () => { + const { getByText, queryByTestId } = renderComponent({ isListing: true }); + + expect(queryByTestId('display-name-link')).toBeDefined(); + expect(getByText(defaultVs.iam.displayName)).toBeDefined(); + expect(queryByTestId('display-name-edit-button')).toBeNull(); + }); + + it('In listing, should display the display name with info icon', async () => { + const { queryByTestId } = renderComponent({ + isListing: true, + vs: vrackServicesList[2] as VrackServicesWithIAM, + }); + expect(queryByTestId('warning-icon')).toBeDefined(); + }); + + it('In listing, should display the display name with loader', async () => { + const { queryByTestId } = renderComponent({ + isListing: true, + vs: vrackServicesList[3] as VrackServicesWithIAM, + }); + expect(queryByTestId('vs-loader-operation-in-progress')).toBeDefined(); + }); + + it('In Dashboard, should display the display name with edit action', async () => { + const { getByText, queryByTestId } = renderComponent({}); + + expect(getByText(defaultVs.iam.displayName)).toBeDefined(); + expect(queryByTestId('edit-button')).toBeDefined(); + expect(queryByTestId('display-name-link')).toBeNull(); + }); + + it('In Dashboard, should display the display name with disabled edit action', async () => { + const { queryByTestId } = renderComponent({ + vs: vrackServicesList[2] as VrackServicesWithIAM, + }); + expect(queryByTestId('edit-button')).toHaveProperty('disabled'); + }); +}); diff --git a/packages/manager/apps/vrack-services/src/components/display-name/EditButton.component.tsx b/packages/manager/apps/vrack-services/src/components/display-name/EditButton.component.tsx index 153de57716d7..b6e118fcad94 100644 --- a/packages/manager/apps/vrack-services/src/components/display-name/EditButton.component.tsx +++ b/packages/manager/apps/vrack-services/src/components/display-name/EditButton.component.tsx @@ -43,6 +43,7 @@ export const EditButton: React.FC = ({ size={ODS_BUTTON_SIZE.sm} {...handleClick(onClick)} disabled={disabled || undefined} + data-testid="edit-button" > = ({ className, vs }) => { color={ODS_THEME_COLOR_INTENT.warning} size={size} name={ODS_ICON_NAME.WARNING_CIRCLE} + data-testid="warning-icon" /> ) : ( )} diff --git a/packages/manager/apps/vrack-services/src/components/vrack-id/VrackId.spec.tsx b/packages/manager/apps/vrack-services/src/components/vrack-id/VrackId.spec.tsx new file mode 100644 index 000000000000..fc841bed3ab3 --- /dev/null +++ b/packages/manager/apps/vrack-services/src/components/vrack-id/VrackId.spec.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import { describe, expect, it, vi } from 'vitest'; +import { render, waitFor } from '@testing-library/react'; +import { + ShellContext, + ShellContextType, +} from '@ovh-ux/manager-react-shell-client'; +import { VrackId } from './VrackId.component'; +import { VrackServicesWithIAM } from '@/data'; +import vrackServicesList from '../../../mocks/vrack-services/get-vrack-services.json'; + +const defaultVs = vrackServicesList[5] as VrackServicesWithIAM; +const vsWithoutVrack = vrackServicesList[0] as VrackServicesWithIAM; + +/** Render */ + +const shellContext = { + environment: { + user: { ovhSubsidiary: 'FR' }, + }, + shell: { + tracking: { + trackClick: vi.fn(), + trackPage: vi.fn(), + init: vi.fn(), + }, + navigation: { + getURL: vi.fn().mockResolvedValue('link-to-vrack'), + }, + }, +}; + +const renderComponent = ({ + isListing, + vs, +}: { + isListing?: boolean; + vs: VrackServicesWithIAM; +}) => { + return render( + + + , + ); +}; + +/** END RENDER */ + +describe('VrackId Component', () => { + it('should display link to vrack if associated', async () => { + const { getByText, queryByText } = renderComponent({ vs: defaultVs }); + + await waitFor(() => { + expect(getByText(defaultVs.currentState.vrackId)).toBeDefined(); + expect(getByText(defaultVs.currentState.vrackId)).toHaveAttribute( + 'href', + 'link-to-vrack', + ); + expect(getByText('vrackActionAssociateToAnother')).toBeDefined(); + expect(getByText('vrackActionDissociate')).toBeDefined(); + expect(queryByText('associateVrackButtonLabel')).toBeNull(); + }); + }); + + it('should display action to link vrack if not associated', async () => { + const { getByText, queryByText } = renderComponent({ vs: vsWithoutVrack }); + + await waitFor(() => { + expect(queryByText('vrackActionAssociateToAnother')).toBeNull(); + expect(queryByText('vrackActionDissociate')).toBeNull(); + expect(getByText('associateVrackButtonLabel')).toBeDefined(); + }); + }); +}); diff --git a/packages/manager/apps/vrack-services/tailwind.config.js b/packages/manager/apps/vrack-services/tailwind.config.js index d54ec991a400..657ab11bb87d 100644 --- a/packages/manager/apps/vrack-services/tailwind.config.js +++ b/packages/manager/apps/vrack-services/tailwind.config.js @@ -1,3 +1,4 @@ +import path from 'path'; import config from '@ovh-ux/manager-tailwind-config'; /** @type {import('tailwindcss').Config} */ @@ -5,6 +6,9 @@ module.exports = { ...config, content: [ './src/**/*.{js,jsx,ts,tsx}', - '../../../manager-react-components/src/**/*.{js,jsx,ts,tsx}', + path.join( + path.dirname(require.resolve('@ovh-ux/manager-react-components')), + '**/*.{js,jsx,ts,tsx}', + ), ], }; diff --git a/packages/manager/apps/vrack-services/tsconfig.json b/packages/manager/apps/vrack-services/tsconfig.json index 148b6ca3f83b..a92d6883f770 100644 --- a/packages/manager/apps/vrack-services/tsconfig.json +++ b/packages/manager/apps/vrack-services/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "lib": ["dom", "es2020"], + "lib": ["dom", "es2021"], "noEmit": true, "target": "es2020", - "types": ["vite/client", "node", "jest"], + "types": ["vite/client", "node"], "module": "ES2020", "moduleResolution": "node", "removeComments": true, @@ -19,11 +19,9 @@ "jsx": "react", "baseUrl": ".", "paths": { - "@/*": ["./src/*"], - "@playwright-helpers": ["../../../../playwright-helpers/index"], - "@playwright-helpers/*": ["../../../../playwright-helpers/*"] + "@/*": ["./src/*"] } }, - "include": ["**/*.ts", "**/*.tsx"], - "exclude": ["node_modules", "dist", "types", "src/__tests__", "*.spec.ts"] + "include": ["src"], + "exclude": ["node_modules", "dist", "types"] } diff --git a/packages/manager/apps/vrack-services/vite.config.mjs b/packages/manager/apps/vrack-services/vite.config.mjs index 2b63c8229ae8..f33ab6dc98cd 100644 --- a/packages/manager/apps/vrack-services/vite.config.mjs +++ b/packages/manager/apps/vrack-services/vite.config.mjs @@ -2,12 +2,7 @@ import { defineConfig } from 'vite'; import { getBaseConfig } from '@ovh-ux/manager-vite-config'; import { resolve } from 'path'; -const config = getBaseConfig({}); - export default defineConfig({ - ...config, + ...getBaseConfig(), root: resolve(process.cwd()), - resolve: { - ...config.resolve, - }, }); diff --git a/packages/manager/apps/vrack-services/vitest.config.js b/packages/manager/apps/vrack-services/vitest.config.js index 3fffd533bc02..a5e80ab7f4a3 100644 --- a/packages/manager/apps/vrack-services/vitest.config.js +++ b/packages/manager/apps/vrack-services/vitest.config.js @@ -8,8 +8,28 @@ export default defineConfig({ test: { globals: true, environment: 'jsdom', + setupFiles: './setupTests.ts', coverage: { - include: ['src/utils'], + include: ['src'], + exclude: [ + 'src/types', + 'src/test-utils', + 'src/vite-*.ts', + 'src/App.tsx', + 'src/index.tsx', + 'src/tracking.constant.ts', + ], + }, + testTimeout: 60000, + fileParallelism: false, + maxWorkers: 1, + pollOptions: { + forks: { + singleFork: true, + }, + threads: { + singleThread: true, + }, }, }, resolve: {