3 * Copyright (C) 2009-2024 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
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';
34 jest.mock('../../../../api/settings', () => ({
35 getAllValues: jest.fn().mockResolvedValue([]),
38 let tokenMock: UserTokensMock;
41 tokenMock = new UserTokensMock();
48 it('should render correctly and allow token generation', async () => {
49 renderAzurePipelinesTutorial();
50 const user = userEvent.setup();
53 screen.getByRole('heading', { name: 'onboarding.tutorial.with.azure_pipelines.title' }),
54 ).toBeInTheDocument();
57 assertDefaultStepIsCorrectlyRendered();
60 assertServiceEndpointStepIsCorrectlyRendered();
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();
68 expect(lastToken).toBeDefined();
70 expect(lastToken!.type).toBe(TokenType.Global);
72 within(modal).getByText(`users.tokens.new_token_created.${lastToken!.token}`),
73 ).toBeInTheDocument();
74 await clickButton(user, 'continue', modal);
76 // Analysis step: .NET
77 await user.click(getTutorialBuildButtons().dotnetBuildButton.get());
78 assertDotNetStepIsCorrectlyRendered();
80 // Analysis step: Maven
81 await user.click(getTutorialBuildButtons().mavenBuildButton.get());
82 assertMavenStepIsCorrectlyRendered();
84 // Analysis step: Gradle
85 await user.click(getTutorialBuildButtons().gradleBuildButton.get());
86 assertGradleStepIsCorrectlyRendered();
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();
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);
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);
120 // Analysis step: Other
121 await user.click(getTutorialBuildButtons().otherBuildButton.get());
122 assertOtherStepIsCorrectlyRendered();
125 assertFinishStepIsCorrectlyRendered();
128 it('should not offer CFamily analysis if the language is not available', () => {
129 renderAzurePipelinesTutorial(undefined, { languages: {} });
131 expect(getTutorialBuildButtons().dotnetBuildButton.get()).toBeInTheDocument();
132 expect(getTutorialBuildButtons().cppBuildButton.query()).not.toBeInTheDocument();
135 function assertDefaultStepIsCorrectlyRendered() {
137 screen.getByRole('heading', {
138 name: 'onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title',
140 ).toBeInTheDocument();
143 function assertServiceEndpointStepIsCorrectlyRendered() {
145 screen.getByRole('heading', {
146 name: 'onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.title',
148 ).toBeInTheDocument();
149 expect(getCopyToClipboardValue(0, 'Copy to clipboard')).toBe('https://sonarqube.example.com/');
151 screen.getByRole('button', { name: 'onboarding.token.generate.long' }),
152 ).toBeInTheDocument();
155 function assertDotNetStepIsCorrectlyRendered() {
157 screen.getByRole('heading', {
158 name: 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.title',
160 ).toBeInTheDocument();
162 expect(getCopyToClipboardValue(1, 'Copy to clipboard')).toBe('foo');
165 function assertMavenStepIsCorrectlyRendered() {
166 expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('maven, copy additional properties');
169 function assertGradleStepIsCorrectlyRendered() {
170 expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('gradle, copy additional properties');
173 function assertObjCStepIsCorrectlyRendered(os: string, arch: string = 'x86_64') {
174 expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot(
175 `objectivec ${os} ${arch}, copy shell script`,
177 expect(getCopyToClipboardValue(1, 'Copy to clipboard')).toBe('foo');
178 expect(getCopyToClipboardValue(2, 'Copy to clipboard')).toMatchSnapshot(
179 `objectivec ${os} ${arch}, copy additional properties`,
181 expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
182 `objectivec ${os} ${arch}, copy build-wrapper command`,
186 function assertAutomaticCppStepIsCorrectlyRendered() {
187 assertOtherStepIsCorrectlyRendered();
190 function assertManualCppStepIsCorrectlyRendered(os: string, arch: string = 'x86_64') {
191 expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot(
192 `manual-cpp ${os} ${arch}, copy shell script`,
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`,
198 expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
199 `manual-cpp ${os} ${arch}, copy build-wrapper command`,
203 function assertOtherStepIsCorrectlyRendered() {
204 expect(getCopyToClipboardValue(1, 'Copy to clipboard')).toBe('foo');
207 function assertFinishStepIsCorrectlyRendered() {
209 screen.getByRole('heading', {
210 name: 'onboarding.tutorial.ci_outro.done',
212 ).toBeInTheDocument();
215 function renderAzurePipelinesTutorial(
216 props: Partial<AzurePipelinesTutorialProps> = {},
217 { languages = { c: mockLanguage({ key: 'c' }) } }: RenderContext = {},
221 <AzurePipelinesTutorial
222 baseUrl="https://sonarqube.example.com/"
223 component={mockComponent({ key: 'foo' })}
224 currentUser={mockLoggedInUser({ permissions: { global: [Permissions.Scan] } })}
225 willRefreshAutomatically
232 async function clickButton(user: UserEvent, name: string, context?: HTMLElement) {
234 await user.click(within(context).getByRole('button', { name }));
236 await user.click(screen.getByRole('button', { name }));