|
| 1 | +/* |
| 2 | + * Copyright Red Hat, Inc. |
| 3 | + * |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + * you may not use this file except in compliance with the License. |
| 6 | + * You may obtain a copy of the License at |
| 7 | + * |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | + * |
| 10 | + * Unless required by applicable law or agreed to in writing, software |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + * See the License for the specific language governing permissions and |
| 14 | + * limitations under the License. |
| 15 | + */ |
| 16 | + |
| 17 | +import React from 'react'; |
| 18 | +import { fireEvent, render, screen } from '@testing-library/react'; |
| 19 | +import { createTheme, ThemeProvider } from '@mui/material/styles'; |
| 20 | +import { SandboxCatalogCard } from '../SandboxCatalogCard'; |
| 21 | +import { Product } from '../productData'; |
| 22 | +import { AnsibleStatus } from '../../../utils/aap-utils'; |
| 23 | +import { useSandboxContext } from '../../../hooks/useSandboxContext'; |
| 24 | +import useGreenCorners from '../../../hooks/useGreenCorners'; |
| 25 | + |
| 26 | +jest.useFakeTimers(); // control timers |
| 27 | +// Mock the hooks |
| 28 | +jest.mock('../../../hooks/useGreenCorners'); |
| 29 | +jest.mock('../../../hooks/useSandboxContext'); |
| 30 | + |
| 31 | +const mockCreateAAP = jest.fn(); |
| 32 | +const configMock = { |
| 33 | + createAAP: mockCreateAAP, |
| 34 | +}; |
| 35 | + |
| 36 | +jest.mock('@backstage/core-plugin-api', () => ({ |
| 37 | + ...jest.requireActual('@backstage/core-plugin-api'), |
| 38 | + useApi: jest.fn(() => { |
| 39 | + return configMock; |
| 40 | + }), |
| 41 | +})); |
| 42 | + |
| 43 | +describe('SandboxCatalogCard', () => { |
| 44 | + const theme = createTheme(); |
| 45 | + |
| 46 | + const mockSetGreenCorners = jest.fn(); |
| 47 | + const mockGreenCorners = [{ id: 'openshift-console', show: false }]; |
| 48 | + const mockRefetchUserData = jest.fn(); |
| 49 | + const mockShowGreenCorner = jest.fn(); |
| 50 | + const mockUseSandboxContext = useSandboxContext as jest.MockedFunction< |
| 51 | + typeof useSandboxContext |
| 52 | + >; |
| 53 | + const mockSignupUser = jest.fn(); |
| 54 | + const mockRefetchAAP = jest.fn(); |
| 55 | + |
| 56 | + beforeEach(() => { |
| 57 | + jest.clearAllMocks(); |
| 58 | + // refetching the user data will return the actual user provisioned |
| 59 | + mockRefetchUserData.mockReturnValue({ |
| 60 | + name: 'bob', |
| 61 | + consoleURL: 'https://sandboxcluster.test/', |
| 62 | + cheDashboardURL: 'https://devspaces.test/', |
| 63 | + proxyURL: 'https://api-sandboxcluster.test', |
| 64 | + rhodsMemberURL: 'https://rhods-dashboard.test/', |
| 65 | + apiEndpoint: 'https://api.test:6443', |
| 66 | + clusterName: 'sandboxcluster.test', |
| 67 | + defaultUserNamespace: 'bob-2-dev', |
| 68 | + compliantUsername: 'bob-2', |
| 69 | + username: 'bob', |
| 70 | + status: { |
| 71 | + ready: true, |
| 72 | + reason: 'Provisioned', |
| 73 | + verificationRequired: false, |
| 74 | + }, |
| 75 | + } as any); |
| 76 | + |
| 77 | + mockUseSandboxContext.mockReturnValue({ |
| 78 | + refetchUserData: mockRefetchUserData, |
| 79 | + loading: false, |
| 80 | + userFound: false, |
| 81 | + userReady: false, |
| 82 | + ansibleStatus: AnsibleStatus.UNKNOWN, |
| 83 | + verificationRequired: false, |
| 84 | + userData: undefined, |
| 85 | + signupUser: mockSignupUser, |
| 86 | + refetchAAP: mockRefetchAAP, |
| 87 | + ansibleData: undefined, |
| 88 | + ansibleUIUser: undefined, |
| 89 | + } as any); |
| 90 | + (useGreenCorners as jest.Mock).mockReturnValue({ |
| 91 | + greenCorners: mockGreenCorners, |
| 92 | + setGreenCorners: mockSetGreenCorners, |
| 93 | + }); |
| 94 | + }); |
| 95 | + |
| 96 | + const defaultProps = { |
| 97 | + id: Product.OPENSHIFT_CONSOLE, |
| 98 | + title: 'Openshift', |
| 99 | + image: 'sometestimage.svg', |
| 100 | + description: [ |
| 101 | + { icon: <div>icon 1</div>, value: 'Description 1' }, |
| 102 | + { icon: <div>icon 2</div>, value: 'Description 2' }, |
| 103 | + ], |
| 104 | + link: 'https://openshiftconsole.url.com', |
| 105 | + greenCorner: false, |
| 106 | + showGreenCorner: mockShowGreenCorner, |
| 107 | + }; |
| 108 | + |
| 109 | + const renderCard = (props = {}) => { |
| 110 | + return render( |
| 111 | + <ThemeProvider theme={theme}> |
| 112 | + <SandboxCatalogCard {...defaultProps} {...props} /> |
| 113 | + </ThemeProvider>, |
| 114 | + ); |
| 115 | + }; |
| 116 | + |
| 117 | + it('renders the card', () => { |
| 118 | + renderCard(); |
| 119 | + |
| 120 | + const cards = screen.getAllByTestId('catalog-card'); |
| 121 | + expect(cards).toHaveLength(1); |
| 122 | + expect(screen.getByText('Openshift')).toBeInTheDocument(); // title |
| 123 | + expect(screen.getByText('Description 1')).toBeInTheDocument(); // description |
| 124 | + expect(screen.getByText('Description 2')).toBeInTheDocument(); // description |
| 125 | + expect(screen.getByText('icon 1')).toBeInTheDocument(); // icon |
| 126 | + const img = screen.getByAltText('Openshift') as HTMLImageElement; |
| 127 | + expect(img.src).toContain('sometestimage.svg'); |
| 128 | + expect(screen.getByText('Try it')).toBeInTheDocument(); |
| 129 | + }); |
| 130 | + |
| 131 | + it('opens the link when user signs up', async () => { |
| 132 | + const mockOpen = jest.fn(); |
| 133 | + window.open = mockOpen; // override window.open with mock |
| 134 | + renderCard(); |
| 135 | + |
| 136 | + // Find and click try it button/icon |
| 137 | + const tryItButton = screen.getByRole('button', { name: /Try it/i }); |
| 138 | + fireEvent.click(tryItButton); |
| 139 | + |
| 140 | + // advance timers to trigger all retries |
| 141 | + for (let i = 0; i < 5; i++) { |
| 142 | + jest.advanceTimersByTime(1000); |
| 143 | + await Promise.resolve(); // allow awaiting the timer to flush |
| 144 | + } |
| 145 | + |
| 146 | + expect(mockSignupUser).toHaveBeenCalled(); // check it signs up the user |
| 147 | + expect(mockRefetchUserData).toHaveBeenCalled(); |
| 148 | + expect(mockOpen).toHaveBeenCalledWith( |
| 149 | + 'https://sandboxcluster.test/', |
| 150 | + '_blank', |
| 151 | + ); // check it opens the url after signup |
| 152 | + expect(mockShowGreenCorner).toHaveBeenCalled(); |
| 153 | + }); |
| 154 | + |
| 155 | + it('starts provisioning AAP when user signs up', async () => { |
| 156 | + // AAP product card |
| 157 | + renderCard({ id: Product.AAP }); |
| 158 | + |
| 159 | + // Find and click provision button/icon |
| 160 | + const tryItButton = screen.getByRole('button', { name: /Provision/i }); |
| 161 | + fireEvent.click(tryItButton); |
| 162 | + |
| 163 | + // advance timers to trigger all retries |
| 164 | + for (let i = 0; i < 5; i++) { |
| 165 | + jest.advanceTimersByTime(1000); |
| 166 | + await Promise.resolve(); // allow awaiting the timer to flush |
| 167 | + } |
| 168 | + |
| 169 | + expect(mockSignupUser).toHaveBeenCalled(); // check it signs up the user |
| 170 | + expect(mockRefetchUserData).toHaveBeenCalled(); |
| 171 | + expect(mockRefetchAAP).toHaveBeenCalled(); // check it calls the aap specific functionality |
| 172 | + expect(mockCreateAAP).toHaveBeenCalledWith('bob-2-dev'); // check it creates the app instance in the user namespace |
| 173 | + expect(mockShowGreenCorner).toHaveBeenCalled(); |
| 174 | + }); |
| 175 | +}); |
0 commit comments