You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

App-test.tsx 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. import { screen, waitFor } from '@testing-library/react';
  21. import * as React from 'react';
  22. import { getScannableProjects } from '../../../../api/components';
  23. import BranchesServiceMock from '../../../../api/mocks/BranchesServiceMock';
  24. import ComputeEngineServiceMock from '../../../../api/mocks/ComputeEngineServiceMock';
  25. import CurrentUserContextProvider from '../../../../app/components/current-user/CurrentUserContextProvider';
  26. import { mockBranch, mockMainBranch } from '../../../../helpers/mocks/branch-like';
  27. import { mockComponent } from '../../../../helpers/mocks/component';
  28. import { mockTask } from '../../../../helpers/mocks/tasks';
  29. import { mockCurrentUser, mockLoggedInUser } from '../../../../helpers/testMocks';
  30. import { renderComponent } from '../../../../helpers/testReactTestingUtils';
  31. import { getProjectTutorialLocation } from '../../../../helpers/urls';
  32. import { ComponentQualifier } from '../../../../types/component';
  33. import { TaskStatuses, TaskTypes } from '../../../../types/tasks';
  34. import { App } from '../App';
  35. jest.mock('../../../../api/components', () => ({
  36. ...jest.requireActual('../../../../api/components'),
  37. getScannableProjects: jest.fn().mockResolvedValue({ projects: [] }),
  38. }));
  39. jest.mock('../../../../helpers/urls', () => ({
  40. ...jest.requireActual('../../../../helpers/urls'),
  41. getProjectTutorialLocation: jest.fn().mockResolvedValue({ pathname: '/tutorial' }),
  42. }));
  43. const handlerBranches = new BranchesServiceMock();
  44. const handlerCe = new ComputeEngineServiceMock();
  45. beforeEach(() => {
  46. handlerBranches.reset();
  47. handlerCe.reset();
  48. });
  49. it('should render Empty Overview for Application with no analysis', async () => {
  50. renderApp({ component: mockComponent({ qualifier: ComponentQualifier.Application }) });
  51. await appLoaded();
  52. expect(await screen.findByText('provisioning.no_analysis.application')).toBeInTheDocument();
  53. });
  54. it('should render Empty Overview on main branch with no analysis', async () => {
  55. renderApp({}, mockCurrentUser());
  56. await appLoaded();
  57. expect(
  58. await screen.findByText('provisioning.no_analysis_on_main_branch.main'),
  59. ).toBeInTheDocument();
  60. });
  61. it('should redirect to tutorial when the user can scan a project that has no analysis yet', async () => {
  62. handlerBranches.emptyBranchesAndPullRequest();
  63. handlerBranches.addBranch(mockMainBranch());
  64. jest
  65. .mocked(getScannableProjects)
  66. .mockResolvedValueOnce({ projects: [{ key: 'my-project', name: 'MyProject' }] });
  67. renderApp({}, mockLoggedInUser());
  68. await appLoaded();
  69. await waitFor(() => {
  70. expect(getProjectTutorialLocation).toHaveBeenCalled();
  71. });
  72. });
  73. it('should render Empty Overview on main branch with multiple branches with bad configuration', async () => {
  74. renderApp({ branchLikes: [mockBranch(), mockBranch()] });
  75. await appLoaded();
  76. expect(
  77. await screen.findByText(
  78. 'provisioning.no_analysis_on_main_branch.bad_configuration.main.branches.main_branch',
  79. ),
  80. ).toBeInTheDocument();
  81. });
  82. it('should not render for portfolios and subportfolios', () => {
  83. const rtl = renderApp({
  84. component: mockComponent({ qualifier: ComponentQualifier.Portfolio }),
  85. });
  86. expect(rtl.container).toBeEmptyDOMElement();
  87. rtl.unmount();
  88. renderApp({
  89. component: mockComponent({ qualifier: ComponentQualifier.Portfolio }),
  90. });
  91. expect(rtl.container).toBeEmptyDOMElement();
  92. });
  93. describe('Permission provisioning', () => {
  94. beforeEach(() => {
  95. jest.useFakeTimers({ advanceTimers: true });
  96. });
  97. afterEach(() => {
  98. jest.runOnlyPendingTimers();
  99. jest.useRealTimers();
  100. });
  101. it('should render warning when permission is sync', async () => {
  102. handlerCe.addTask(
  103. mockTask({
  104. componentKey: 'my-project',
  105. type: TaskTypes.GithubProjectPermissionsProvisioning,
  106. status: TaskStatuses.InProgress,
  107. }),
  108. );
  109. renderApp();
  110. await jest.runOnlyPendingTimersAsync();
  111. expect(
  112. await screen.findByText('provisioning.permission_synch_in_progress'),
  113. ).toBeInTheDocument();
  114. handlerCe.clearTasks();
  115. handlerCe.addTask(
  116. mockTask({
  117. componentKey: 'my-project',
  118. type: TaskTypes.GithubProjectPermissionsProvisioning,
  119. status: TaskStatuses.Success,
  120. }),
  121. );
  122. await jest.runOnlyPendingTimersAsync();
  123. expect(screen.queryByText('provisioning.permission_synch_in_progress')).not.toBeInTheDocument();
  124. });
  125. });
  126. const appLoaded = async () => {
  127. await waitFor(() => {
  128. expect(screen.getByText('loading')).toBeInTheDocument();
  129. });
  130. await waitFor(() => {
  131. expect(screen.queryByText('loading')).not.toBeInTheDocument();
  132. });
  133. };
  134. function renderApp(props = {}, userProps = {}) {
  135. return renderComponent(
  136. <CurrentUserContextProvider currentUser={mockCurrentUser({ isLoggedIn: true, ...userProps })}>
  137. <App hasFeature={jest.fn().mockReturnValue(false)} component={mockComponent()} {...props} />
  138. </CurrentUserContextProvider>,
  139. '/?id=my-project',
  140. );
  141. }