]> source.dussan.org Git - sonarqube.git/blob
bdb521f43ec402d9c6f97c3e322d51158c7bd787
[sonarqube.git] /
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, within } from '@testing-library/react';
21 import userEvent from '@testing-library/user-event';
22 import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup';
23 import * as React from 'react';
24 import UserTokensMock from '../../../../api/mocks/UserTokensMock';
25 import { mockComponent } from '../../../../helpers/mocks/component';
26 import { mockLanguage, mockLoggedInUser } from '../../../../helpers/testMocks';
27 import { RenderContext, renderApp } from '../../../../helpers/testReactTestingUtils';
28 import { Permissions } from '../../../../types/permissions';
29 import { TokenType } from '../../../../types/token';
30 import { getCopyToClipboardValue, getTutorialBuildButtons } from '../../test-utils';
31 import { OSs } from '../../types';
32 import AzurePipelinesTutorial, { AzurePipelinesTutorialProps } from '../AzurePipelinesTutorial';
33
34 jest.mock('../../../../api/settings', () => ({
35   getAllValues: jest.fn().mockResolvedValue([]),
36 }));
37
38 let tokenMock: UserTokensMock;
39
40 beforeAll(() => {
41   tokenMock = new UserTokensMock();
42 });
43
44 afterEach(() => {
45   tokenMock.reset();
46 });
47
48 it('should render correctly and allow token generation', async () => {
49   renderAzurePipelinesTutorial();
50   const user = userEvent.setup();
51
52   expect(
53     screen.getByRole('heading', { name: 'onboarding.tutorial.with.azure_pipelines.title' }),
54   ).toBeInTheDocument();
55
56   // Default step.
57   assertDefaultStepIsCorrectlyRendered();
58
59   // Token step.
60   assertServiceEndpointStepIsCorrectlyRendered();
61
62   // Generate a token.
63   await clickButton(user, 'onboarding.token.generate.long');
64   const modal = screen.getByRole('dialog');
65   await clickButton(user, 'onboarding.token.generate', modal);
66   const lastToken = tokenMock.getLastToken();
67
68   expect(lastToken).toBeDefined();
69
70   expect(lastToken!.type).toBe(TokenType.Global);
71   expect(
72     within(modal).getByText(`users.tokens.new_token_created.${lastToken!.token}`),
73   ).toBeInTheDocument();
74   await clickButton(user, 'continue', modal);
75
76   // Analysis step: .NET
77   await user.click(getTutorialBuildButtons().dotnetBuildButton.get());
78   assertDotNetStepIsCorrectlyRendered();
79
80   // Analysis step: Maven
81   await user.click(getTutorialBuildButtons().mavenBuildButton.get());
82   assertMavenStepIsCorrectlyRendered();
83
84   // Analysis step: Gradle
85   await user.click(getTutorialBuildButtons().gradleBuildButton.get());
86   assertGradleStepIsCorrectlyRendered();
87
88   // Analysis step: C Family
89   await user.click(getTutorialBuildButtons().cppBuildButton.get());
90   // Default: Automatic configuration
91   // expect linux/win/macos buttons not to be present
92   expect(getTutorialBuildButtons().linuxButton.query()).not.toBeInTheDocument();
93   expect(getTutorialBuildButtons().windowsButton.query()).not.toBeInTheDocument();
94   expect(getTutorialBuildButtons().macosButton.query()).not.toBeInTheDocument();
95   assertAutomaticCppStepIsCorrectlyRendered();
96
97   // Switch to manual configuration
98   await user.click(getTutorialBuildButtons().autoConfigManual.get());
99   await user.click(getTutorialBuildButtons().linuxButton.get());
100   assertManualCppStepIsCorrectlyRendered(OSs.Linux);
101   await user.click(getTutorialBuildButtons().arm64Button.get());
102   assertManualCppStepIsCorrectlyRendered(OSs.Linux, 'arm64');
103   await user.click(getTutorialBuildButtons().windowsButton.get());
104   assertObjCStepIsCorrectlyRendered(OSs.Windows);
105   await user.click(getTutorialBuildButtons().macosButton.get());
106   assertObjCStepIsCorrectlyRendered(OSs.MacOS);
107
108   // Analysis step: C Family
109   await user.click(getTutorialBuildButtons().objCBuildButton.get());
110   await user.click(getTutorialBuildButtons().linuxButton.get());
111   await user.click(getTutorialBuildButtons().x86_64Button.get());
112   assertObjCStepIsCorrectlyRendered(OSs.Linux);
113   await user.click(getTutorialBuildButtons().arm64Button.get());
114   assertObjCStepIsCorrectlyRendered(OSs.Linux, 'arm64');
115   await user.click(getTutorialBuildButtons().windowsButton.get());
116   assertObjCStepIsCorrectlyRendered(OSs.Windows);
117   await user.click(getTutorialBuildButtons().macosButton.get());
118   assertObjCStepIsCorrectlyRendered(OSs.MacOS);
119
120   // Analysis step: Other
121   await user.click(getTutorialBuildButtons().otherBuildButton.get());
122   assertOtherStepIsCorrectlyRendered();
123
124   // Finish tutorial
125   assertFinishStepIsCorrectlyRendered();
126 });
127
128 it('should not offer CFamily analysis if the language is not available', () => {
129   renderAzurePipelinesTutorial(undefined, { languages: {} });
130
131   expect(getTutorialBuildButtons().dotnetBuildButton.get()).toBeInTheDocument();
132   expect(getTutorialBuildButtons().cppBuildButton.query()).not.toBeInTheDocument();
133 });
134
135 function assertDefaultStepIsCorrectlyRendered() {
136   expect(
137     screen.getByRole('heading', {
138       name: 'onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title',
139     }),
140   ).toBeInTheDocument();
141 }
142
143 function assertServiceEndpointStepIsCorrectlyRendered() {
144   expect(
145     screen.getByRole('heading', {
146       name: 'onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.title',
147     }),
148   ).toBeInTheDocument();
149   expect(getCopyToClipboardValue(0, 'Copy to clipboard')).toBe('https://sonarqube.example.com/');
150   expect(
151     screen.getByRole('button', { name: 'onboarding.token.generate.long' }),
152   ).toBeInTheDocument();
153 }
154
155 function assertDotNetStepIsCorrectlyRendered() {
156   expect(
157     screen.getByRole('heading', {
158       name: 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.title',
159     }),
160   ).toBeInTheDocument();
161
162   expect(getCopyToClipboardValue(1, 'Copy to clipboard')).toBe('foo');
163 }
164
165 function assertMavenStepIsCorrectlyRendered() {
166   expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('maven, copy additional properties');
167 }
168
169 function assertGradleStepIsCorrectlyRendered() {
170   expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('gradle, copy additional properties');
171 }
172
173 function assertObjCStepIsCorrectlyRendered(os: string, arch: string = 'x86_64') {
174   expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot(
175     `objectivec ${os} ${arch}, copy shell script`,
176   );
177   expect(getCopyToClipboardValue(1, 'Copy to clipboard')).toBe('foo');
178   expect(getCopyToClipboardValue(2, 'Copy to clipboard')).toMatchSnapshot(
179     `objectivec ${os} ${arch}, copy additional properties`,
180   );
181   expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
182     `objectivec ${os} ${arch}, copy build-wrapper command`,
183   );
184 }
185
186 function assertAutomaticCppStepIsCorrectlyRendered() {
187   assertOtherStepIsCorrectlyRendered();
188 }
189
190 function assertManualCppStepIsCorrectlyRendered(os: string, arch: string = 'x86_64') {
191   expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot(
192     `manual-cpp ${os} ${arch}, copy shell script`,
193   );
194   expect(getCopyToClipboardValue(1, 'Copy to clipboard')).toBe('foo');
195   expect(getCopyToClipboardValue(2, 'Copy to clipboard')).toMatchSnapshot(
196     `manual-cpp ${os} ${arch}, copy additional properties`,
197   );
198   expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
199     `manual-cpp ${os} ${arch}, copy build-wrapper command`,
200   );
201 }
202
203 function assertOtherStepIsCorrectlyRendered() {
204   expect(getCopyToClipboardValue(1, 'Copy to clipboard')).toBe('foo');
205 }
206
207 function assertFinishStepIsCorrectlyRendered() {
208   expect(
209     screen.getByRole('heading', {
210       name: 'onboarding.tutorial.ci_outro.done',
211     }),
212   ).toBeInTheDocument();
213 }
214
215 function renderAzurePipelinesTutorial(
216   props: Partial<AzurePipelinesTutorialProps> = {},
217   { languages = { c: mockLanguage({ key: 'c' }) } }: RenderContext = {},
218 ) {
219   return renderApp(
220     '/',
221     <AzurePipelinesTutorial
222       baseUrl="https://sonarqube.example.com/"
223       component={mockComponent({ key: 'foo' })}
224       currentUser={mockLoggedInUser({ permissions: { global: [Permissions.Scan] } })}
225       willRefreshAutomatically
226       {...props}
227     />,
228     { languages },
229   );
230 }
231
232 async function clickButton(user: UserEvent, name: string, context?: HTMLElement) {
233   if (context) {
234     await user.click(within(context).getByRole('button', { name }));
235   } else {
236     await user.click(screen.getByRole('button', { name }));
237   }
238 }