]> source.dussan.org Git - sonarqube.git/blob
13b851236a720acdaea17d64cc98f9b303287ae8
[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: Dart
121   await user.click(getTutorialBuildButtons().dartBuildButton.get());
122   assertOtherStepIsCorrectlyRendered();
123
124   // Analysis step: Other
125   await user.click(getTutorialBuildButtons().otherBuildButton.get());
126   assertOtherStepIsCorrectlyRendered();
127
128   // Finish tutorial
129   assertFinishStepIsCorrectlyRendered();
130 });
131
132 it('should not offer CFamily analysis if the language is not available', () => {
133   renderAzurePipelinesTutorial(undefined, { languages: {} });
134
135   expect(getTutorialBuildButtons().dotnetBuildButton.get()).toBeInTheDocument();
136   expect(getTutorialBuildButtons().cppBuildButton.query()).not.toBeInTheDocument();
137 });
138
139 function assertDefaultStepIsCorrectlyRendered() {
140   expect(
141     screen.getByRole('heading', {
142       name: 'onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title',
143     }),
144   ).toBeInTheDocument();
145 }
146
147 function assertServiceEndpointStepIsCorrectlyRendered() {
148   expect(
149     screen.getByRole('heading', {
150       name: 'onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.title',
151     }),
152   ).toBeInTheDocument();
153   expect(getCopyToClipboardValue(0, 'Copy to clipboard')).toBe('https://sonarqube.example.com/');
154   expect(
155     screen.getByRole('button', { name: 'onboarding.token.generate.long' }),
156   ).toBeInTheDocument();
157 }
158
159 function assertDotNetStepIsCorrectlyRendered() {
160   expect(
161     screen.getByRole('heading', {
162       name: 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.title',
163     }),
164   ).toBeInTheDocument();
165
166   expect(getCopyToClipboardValue(1, 'Copy to clipboard')).toBe('foo');
167 }
168
169 function assertMavenStepIsCorrectlyRendered() {
170   expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('maven, copy additional properties');
171 }
172
173 function assertGradleStepIsCorrectlyRendered() {
174   expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('gradle, copy additional properties');
175 }
176
177 function assertObjCStepIsCorrectlyRendered(os: string, arch: string = 'x86_64') {
178   expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot(
179     `objectivec ${os} ${arch}, copy shell script`,
180   );
181   expect(getCopyToClipboardValue(1, 'Copy to clipboard')).toBe('foo');
182   expect(getCopyToClipboardValue(2, 'Copy to clipboard')).toMatchSnapshot(
183     `objectivec ${os} ${arch}, copy additional properties`,
184   );
185   expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
186     `objectivec ${os} ${arch}, copy build-wrapper command`,
187   );
188 }
189
190 function assertAutomaticCppStepIsCorrectlyRendered() {
191   assertOtherStepIsCorrectlyRendered();
192 }
193
194 function assertManualCppStepIsCorrectlyRendered(os: string, arch: string = 'x86_64') {
195   expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot(
196     `manual-cpp ${os} ${arch}, copy shell script`,
197   );
198   expect(getCopyToClipboardValue(1, 'Copy to clipboard')).toBe('foo');
199   expect(getCopyToClipboardValue(2, 'Copy to clipboard')).toMatchSnapshot(
200     `manual-cpp ${os} ${arch}, copy additional properties`,
201   );
202   expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
203     `manual-cpp ${os} ${arch}, copy build-wrapper command`,
204   );
205 }
206
207 function assertOtherStepIsCorrectlyRendered() {
208   expect(getCopyToClipboardValue(1, 'Copy to clipboard')).toBe('foo');
209 }
210
211 function assertFinishStepIsCorrectlyRendered() {
212   expect(
213     screen.getByRole('heading', {
214       name: 'onboarding.tutorial.ci_outro.done',
215     }),
216   ).toBeInTheDocument();
217 }
218
219 function renderAzurePipelinesTutorial(
220   props: Partial<AzurePipelinesTutorialProps> = {},
221   { languages = { c: mockLanguage({ key: 'c' }) } }: RenderContext = {},
222 ) {
223   return renderApp(
224     '/',
225     <AzurePipelinesTutorial
226       baseUrl="https://sonarqube.example.com/"
227       component={mockComponent({ key: 'foo' })}
228       currentUser={mockLoggedInUser({ permissions: { global: [Permissions.Scan] } })}
229       willRefreshAutomatically
230       {...props}
231     />,
232     { languages },
233   );
234 }
235
236 async function clickButton(user: UserEvent, name: string, context?: HTMLElement) {
237   if (context) {
238     await user.click(within(context).getByRole('button', { name }));
239   } else {
240     await user.click(screen.getByRole('button', { name }));
241   }
242 }