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 userEvent from '@testing-library/user-event';
21 import React from 'react';
22 import AlmSettingsServiceMock from '../../../../api/mocks/AlmSettingsServiceMock';
23 import UserTokensMock from '../../../../api/mocks/UserTokensMock';
24 import { mockAlmSettingsInstance } from '../../../../helpers/mocks/alm-settings';
25 import { mockComponent } from '../../../../helpers/mocks/component';
26 import { mockLanguage, mockLoggedInUser } from '../../../../helpers/testMocks';
27 import { RenderContext, renderApp } from '../../../../helpers/testReactTestingUtils';
28 import { byRole } from '../../../../sonar-aligned/helpers/testSelector';
29 import { AlmKeys } from '../../../../types/alm-settings';
30 import { Feature } from '../../../../types/features';
33 getCopyToClipboardValue,
34 getTutorialActionButtons,
35 getTutorialBuildButtons,
36 } from '../../test-utils';
37 import { GradleBuildDSL, TutorialModes } from '../../types';
38 import GitHubActionTutorial, { GitHubActionTutorialProps } from '../GitHubActionTutorial';
40 jest.mock('../../../../api/settings', () => ({
41 getAllValues: jest.fn().mockResolvedValue([]),
44 const tokenMock = new UserTokensMock();
45 const almMock = new AlmSettingsServiceMock();
53 ...getCommonNodes(TutorialModes.GitHubActions),
54 ...getTutorialActionButtons(),
55 ...getTutorialBuildButtons(),
58 it('should follow and complete all steps', async () => {
59 const user = userEvent.setup();
60 renderGithubActionTutorial();
62 expect(await ui.secretsStepTitle.find()).toBeInTheDocument();
65 expect(getCopyToClipboardValue(0, 'Copy to clipboard')).toMatchSnapshot('sonar token key');
66 expect(getCopyToClipboardValue(1, 'Copy to clipboard')).toMatchSnapshot('sonarqube host url key');
67 expect(getCopyToClipboardValue(2, 'Copy to clipboard')).toMatchSnapshot(
68 'sonarqube host url value',
71 // Create/update configuration file step
73 await user.click(ui.mavenBuildButton.get());
74 expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('Maven: .github/workflows/build.yml');
77 await user.click(ui.gradleBuildButton.get());
78 expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('Groovy: build.gradle');
79 await user.click(ui.gradleDSLButton(GradleBuildDSL.Kotlin).get());
80 expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('Kotlin: build.gradle.kts');
81 expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot('Gradle: .github/workflows/build.yml');
84 await user.click(ui.dotnetBuildButton.get());
85 expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('.NET: .github/workflows/build.yml');
88 await user.click(ui.cppBuildButton.get());
89 expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot(
90 'C++ (automatic) and other: sonar-project.properties',
92 expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
93 'C++ (automatic) and other: .github/workflows/build.yml',
96 await user.click(ui.autoConfigManual.get());
97 expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('C++: sonar-project.properties');
98 await user.click(ui.linuxButton.get());
99 expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
100 'C++ Linux: .github/workflows/build.yml',
102 await user.click(ui.arm64Button.get());
103 expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
104 'C++ Linux arm64: .github/workflows/build.yml',
106 await user.click(ui.windowsButton.get());
107 expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
108 'C++ Windows: .github/workflows/build.yml',
110 await user.click(ui.macosButton.get());
111 expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
112 'C++ MacOS: .github/workflows/build.yml',
116 await user.click(ui.objCBuildButton.get());
117 expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot(
118 'Objective-C: sonar-project.properties',
121 await user.click(ui.linuxButton.get());
122 await user.click(ui.x86_64Button.get());
123 expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
124 'Objective-C Linux: .github/workflows/build.yml',
126 await user.click(ui.arm64Button.get());
127 expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
128 'Objective-C Linux arm64: .github/workflows/build.yml',
130 await user.click(ui.windowsButton.get());
131 expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
132 'Objective-C Windows: .github/workflows/build.yml',
134 await user.click(ui.macosButton.get());
135 expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
136 'Objective-C MacOS: .github/workflows/build.yml',
140 await user.click(ui.dartBuildButton.get());
141 expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('Dart: .github/workflows/build.yml');
144 await user.click(ui.otherBuildButton.get());
145 expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot(
146 'C++ (automatic) and other: sonar-project.properties',
148 expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot(
149 'C++ (automatic) and other: .github/workflows/build.yml',
152 expect(ui.allSetSentence.get()).toBeInTheDocument();
155 it('should generate/delete a new token or use existing one', async () => {
156 const user = userEvent.setup();
157 renderGithubActionTutorial();
159 expect(await ui.secretsStepTitle.find()).toBeInTheDocument();
162 await user.click(ui.genTokenDialogButton.get());
163 await user.click(ui.generateTokenButton.get());
164 expect(getCopyToClipboardValue()).toEqual('generatedtoken2');
166 // Revoke current token and create new one
167 await user.click(ui.deleteTokenButton.get());
168 await user.type(ui.tokenNameInput.get(), 'newtoken');
170 await user.click(ui.expiresInSelect.get());
171 await user.click(byRole('option', { name: 'users.tokens.expiration.365' }).get());
173 await user.click(ui.generateTokenButton.get());
174 expect(ui.tokenValue.get()).toBeInTheDocument();
175 await user.click(ui.continueButton.getAll()[0]);
176 expect(ui.tokenValue.query()).not.toBeInTheDocument();
179 it('navigates between steps', async () => {
180 const user = userEvent.setup();
181 almMock.handleSetProjectBinding(AlmKeys.GitHub, {
182 almSetting: 'my-project',
183 project: 'my-project',
184 repository: 'my-project',
187 renderGithubActionTutorial({
188 almBinding: mockAlmSettingsInstance({
190 url: 'http://localhost/qube',
194 // If project is bound, link to repo is visible
195 expect(await ui.linkToRepo.find()).toBeInTheDocument();
197 await user.click(ui.mavenBuildButton.get());
198 expect(ui.allSetSentence.get()).toBeInTheDocument();
200 await user.click(ui.ymlFileStepTitle.get());
201 expect(ui.mavenBuildButton.get()).toBeInTheDocument();
202 await user.click(ui.secretsStepTitle.get());
203 expect(ui.genTokenDialogButton.get()).toBeInTheDocument();
206 function renderGithubActionTutorial(
207 overrides: Partial<GitHubActionTutorialProps> = {},
208 { languages = { c: mockLanguage({ key: 'c' }) } }: RenderContext = {},
212 <GitHubActionTutorial
213 baseUrl="http://localhost:9000"
214 mainBranchName="main"
215 component={mockComponent()}
216 currentUser={mockLoggedInUser()}
219 { languages, featureList: [Feature.BranchSupport] },