3 * Copyright (C) 2009-2022 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';
23 import * as React from 'react';
24 import UserTokensMock from '../../../../api/mocks/UserTokensMock';
25 import { mockComponent } from '../../../../helpers/mocks/component';
26 import { mockAppState, mockLanguage, mockLoggedInUser } from '../../../../helpers/testMocks';
27 import { renderApp, RenderContext } from '../../../../helpers/testReactTestingUtils';
28 import { Permissions } from '../../../../types/permissions';
29 import { TokenType } from '../../../../types/token';
30 import AzurePipelinesTutorial, { AzurePipelinesTutorialProps } from '../AzurePipelinesTutorial';
32 jest.mock('../../../../api/user-tokens');
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 navigating between the different steps', async () => {
49 renderAzurePipelinesTutorial();
50 const user = userEvent.setup();
53 screen.getByRole('heading', { name: 'onboarding.tutorial.with.azure_pipelines.title' })
54 ).toBeInTheDocument();
57 assertDefaultStepIsCorrectlyRendered();
60 await goToNextStep(user);
63 assertServiceEndpointStepIsCorrectlyRendered();
66 await clickButton(user, 'onboarding.token.generate.long');
67 const modal = screen.getByRole('dialog');
68 await clickButton(user, 'onboarding.token.generate', modal);
69 const lastToken = tokenMock.getLastToken();
70 if (lastToken === undefined) {
71 throw new Error("Couldn't find the latest generated token.");
73 expect(lastToken.type).toBe(TokenType.Global);
74 expect(within(modal).getByRole('alert')).toHaveTextContent(
75 `users.tokens.new_token_created.${lastToken.token}`
77 await clickButton(user, 'continue', modal);
80 await goToNextStep(user);
82 //// Analysis step: .NET
83 await clickButton(user, 'onboarding.build.dotnet');
84 assertDotNetStepIsCorrectlyRendered();
86 //// Analysis step: Maven
87 await clickButton(user, 'onboarding.build.maven');
88 assertMavenStepIsCorrectlyRendered();
90 //// Analysis step: Gradle
91 await clickButton(user, 'onboarding.build.gradle');
92 assertGradleStepIsCorrectlyRendered();
94 //// Analysis step: Gradle
95 await clickButton(user, 'onboarding.build.gradle');
96 assertGradleStepIsCorrectlyRendered();
98 //// Analysis step: C Family
99 await clickButton(user, 'onboarding.build.cfamily');
102 await clickButton(user, 'onboarding.build.other.os.linux');
103 assertCFamilyLinuxStepIsCorrectlyRendered();
106 await clickButton(user, 'onboarding.build.other.os.win');
107 assertCFamilyWindowsStepIsCorrectlyRendered();
110 await clickButton(user, 'onboarding.build.other.os.mac');
111 assertCFamilyMacOSStepIsCorrectlyRendered();
113 //// Analysis step: Other
114 await clickButton(user, 'onboarding.build.other');
115 assertOtherStepIsCorrectlyRendered();
118 await clickButton(user, 'tutorials.finish');
119 assertFinishStepIsCorrectlyRendered();
122 it('allows to navigate back to a previous step', async () => {
123 renderAzurePipelinesTutorial();
124 const user = userEvent.setup();
126 // No clickable steps.
128 screen.queryByRole('button', {
129 name: '1 onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title'
131 ).not.toBeInTheDocument();
133 // Go to the next steps.
134 await goToNextStep(user);
135 await goToNextStep(user);
137 // The first 2 steps become clickable.
139 screen.getByRole('button', {
140 name: '1 onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title'
142 ).toBeInTheDocument();
144 screen.getByRole('button', {
145 name: '2 onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.title'
147 ).toBeInTheDocument();
149 // Navigate back to the first step.
150 await clickButton(user, '1 onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title');
152 // No more clickable steps.
154 screen.queryByRole('button', {
155 name: '1 onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title'
157 ).not.toBeInTheDocument();
160 it('should not offer CFamily analysis if the language is not available', async () => {
161 renderAzurePipelinesTutorial(undefined, { languages: {} });
162 const user = userEvent.setup();
164 // Go to the analysis step.
165 await goToNextStep(user);
166 await goToNextStep(user);
168 expect(screen.getByRole('button', { name: 'onboarding.build.dotnet' })).toBeInTheDocument();
170 screen.queryByRole('button', { name: 'onboarding.build.cfamily' })
171 ).not.toBeInTheDocument();
174 function renderAzurePipelinesTutorial(
175 props: Partial<AzurePipelinesTutorialProps> = {},
177 appState = mockAppState({ branchesEnabled: true }),
178 languages = { c: mockLanguage({ key: 'c' }) }
179 }: RenderContext = {}
183 <AzurePipelinesTutorial
184 baseUrl="http://localhost:9000"
185 component={mockComponent()}
186 currentUser={mockLoggedInUser({ permissions: { global: [Permissions.Scan] } })}
187 willRefreshAutomatically={true}
190 { appState, languages }
194 async function clickButton(user: UserEvent, name: string, context?: HTMLElement) {
196 await user.click(within(context).getByRole('button', { name }));
198 await user.click(screen.getByRole('button', { name }));
202 async function goToNextStep(user: UserEvent) {
203 await clickButton(user, 'continue');
206 function assertDefaultStepIsCorrectlyRendered() {
208 screen.getByRole('heading', {
209 name: 'onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title'
211 ).toBeInTheDocument();
212 expect(screen.getByTestId('azure-tutorial__extension')).toMatchSnapshot('extension step');
215 function assertServiceEndpointStepIsCorrectlyRendered() {
217 screen.getByRole('heading', {
218 name: 'onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.title'
220 ).toBeInTheDocument();
221 expect(screen.getByTestId('azure-tutorial__service-endpoint')).toMatchSnapshot(
222 'service endpoint step'
224 expect(screen.getByRole('button', { name: 'copy_to_clipboard' })).toBeInTheDocument();
226 screen.getByRole('button', { name: 'onboarding.token.generate.long' })
227 ).toBeInTheDocument();
230 function assertDotNetStepIsCorrectlyRendered() {
232 screen.getByRole('heading', {
233 name: 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.title'
235 ).toBeInTheDocument();
237 expect(screen.getByTestId('azure-tutorial__analysis-command')).toMatchSnapshot('dotnet step');
238 expect(screen.getByRole('button', { name: 'copy_to_clipboard' })).toBeInTheDocument();
241 function assertMavenStepIsCorrectlyRendered() {
242 expect(screen.getByTestId('azure-tutorial__analysis-command')).toMatchSnapshot('maven step');
243 expect(screen.getByRole('button', { name: 'copy_to_clipboard' })).toBeInTheDocument();
246 function assertGradleStepIsCorrectlyRendered() {
247 expect(screen.getByTestId('azure-tutorial__analysis-command')).toMatchSnapshot('gradle step');
248 expect(screen.getByRole('button', { name: 'copy_to_clipboard' })).toBeInTheDocument();
251 function assertCFamilyLinuxStepIsCorrectlyRendered() {
252 expect(screen.getByTestId('azure-tutorial__analysis-command')).toMatchSnapshot(
255 expect(screen.getAllByRole('button', { name: 'copy_to_clipboard' })).toHaveLength(4);
258 function assertCFamilyWindowsStepIsCorrectlyRendered() {
259 expect(screen.getByTestId('azure-tutorial__analysis-command')).toMatchSnapshot(
260 'cfamily windows step'
262 expect(screen.getAllByRole('button', { name: 'copy_to_clipboard' })).toHaveLength(4);
265 function assertCFamilyMacOSStepIsCorrectlyRendered() {
266 expect(screen.getByTestId('azure-tutorial__analysis-command')).toMatchSnapshot(
269 expect(screen.getAllByRole('button', { name: 'copy_to_clipboard' })).toHaveLength(4);
272 function assertOtherStepIsCorrectlyRendered() {
273 expect(screen.getByTestId('azure-tutorial__analysis-command')).toMatchSnapshot('other step');
274 expect(screen.getByRole('button', { name: 'copy_to_clipboard' })).toBeInTheDocument();
277 function assertFinishStepIsCorrectlyRendered() {
279 screen.getByRole('heading', {
280 name: 'onboarding.tutorial.ci_outro.all_set.title'
282 ).toBeInTheDocument();
283 expect(screen.getByTestId('azure-tutorial__all-set')).toMatchSnapshot('all set step');