From 3338ccfb38a060b7f2e0036c1b31e24eaa31756c Mon Sep 17 00:00:00 2001 From: aribeiro Date: Thu, 4 Mar 2021 11:49:00 +0000 Subject: [PATCH] Add new ui integration test flow New flows for onboarding VNF`s and CNF`s, download and verify if the onboarded package is present Issue-ID: SDC-3507 Signed-off-by: aribeiro Change-Id: Ie53c9ef4ef739d72fa78d3e14511d4107ee7a12a --- .../data/providers/OnboardingDataProviders.java | 24 +++ .../ci/tests/datatypes/enums/XnfTypeEnum.java | 1 + .../ci/tests/utils/general/FileHandling.java | 5 +- .../execute/sanity/EtsiOnboardVnfCnfUiTests.java | 182 +++++++++++++++++++++ .../ci/tests/execute/sanity/OnboardingFlowsUi.java | 6 +- .../sdc/frontend/ci/tests/flow/CreateVlmFlow.java | 126 ++++++++++++++ .../sdc/frontend/ci/tests/flow/CreateVspFlow.java | 4 +- .../ci/tests/flow/DownloadToscaCsarFlow.java | 77 +++++++++ .../sdc/frontend/ci/tests/pages/ComponentPage.java | 51 ++++++ .../frontend/ci/tests/pages/OnboardHomePage.java | 21 ++- .../frontend/ci/tests/pages/TopNavComponent.java | 11 +- .../frontend/ci/tests/pages/VlmCreationModal.java | 122 ++++++++++++++ .../frontend/ci/tests/pages/VlmOverviewPage.java | 100 +++++++++++ .../frontend/ci/tests/pages/VlmSubmitModal.java | 74 +++++++++ .../frontend/ci/tests/pages/VspCommitModal.java | 6 +- .../sdc/frontend/ci/tests/pages/home/HomePage.java | 4 + .../ci/tests/utilities/GeneralUIUtils.java | 2 +- .../frontend/ci/tests/utilities/LoaderHelper.java | 6 +- .../ci/tests/utilities/NotificationComponent.java | 16 +- .../test/resources/Files/ETSI/ETSI-CNF-SAMPLE.csar | Bin 0 -> 21234 bytes .../test/resources/Files/ETSI/ETSI-VNF-SAMPLE.csar | Bin 0 -> 2229 bytes .../ci/testSuites/frontend/onapUiSanity.xml | 6 + 22 files changed, 819 insertions(+), 25 deletions(-) create mode 100644 integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/EtsiOnboardVnfCnfUiTests.java create mode 100644 integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/CreateVlmFlow.java create mode 100644 integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/DownloadToscaCsarFlow.java create mode 100644 integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/ComponentPage.java create mode 100644 integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VlmCreationModal.java create mode 100644 integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VlmOverviewPage.java create mode 100644 integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VlmSubmitModal.java create mode 100644 integration-tests/src/test/resources/Files/ETSI/ETSI-CNF-SAMPLE.csar create mode 100644 integration-tests/src/test/resources/Files/ETSI/ETSI-VNF-SAMPLE.csar diff --git a/integration-tests/src/test/java/org/onap/sdc/backend/ci/tests/data/providers/OnboardingDataProviders.java b/integration-tests/src/test/java/org/onap/sdc/backend/ci/tests/data/providers/OnboardingDataProviders.java index 88b1a661b9..7f8c018c8f 100644 --- a/integration-tests/src/test/java/org/onap/sdc/backend/ci/tests/data/providers/OnboardingDataProviders.java +++ b/integration-tests/src/test/java/org/onap/sdc/backend/ci/tests/data/providers/OnboardingDataProviders.java @@ -27,6 +27,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.onap.sdc.backend.ci.tests.datatypes.enums.XnfTypeEnum; import org.onap.sdc.backend.ci.tests.utils.general.FileHandling; @@ -114,6 +115,29 @@ public final class OnboardingDataProviders { return parametersArray; } + @DataProvider(name = "etsiVnfCnfOnboardPackages", parallel = true) + private static Object[][] etsiVnf() { + final List vnfPackageFileNameList = OnboardingUtils.getXnfNamesFileList(XnfTypeEnum.ETSI); + if (CollectionUtils.isEmpty(vnfPackageFileNameList)) { + fail("Could not create etsiSingleVnfCnf datasource"); + } + final String etsiVnfPackageName = "ETSI-VNF-SAMPLE.csar"; + final String etsiCnfPackageName = "ETSI-CNF-SAMPLE.csar"; + final List etsiPackages = vnfPackageFileNameList.stream() + .filter(packageName -> packageName.equals(etsiVnfPackageName) || packageName.equals(etsiCnfPackageName)) + .collect(Collectors.toList()); + if (CollectionUtils.isEmpty(etsiPackages) || etsiPackages.size() < 2) { + fail(String.format("Could not create etsiSingleVnfCnf datasource, one of the package '%s' was not found", + etsiPackages)); + } + + final String folderPath = FileHandling.getXnfRepositoryPath(XnfTypeEnum.ETSI); + final Object[][] parametersArray = new Object[2][]; + parametersArray[0] = new Object[]{folderPath, etsiPackages.get(0)}; + parametersArray[1] = new Object[]{folderPath, etsiPackages.get(1)}; + return parametersArray; + } + private static Object[][] provideData(final List fileNamesFromFolder, final String folderPath) { final Object[][] parametersArray = new Object[fileNamesFromFolder.size()][]; int index = 0; diff --git a/integration-tests/src/test/java/org/onap/sdc/backend/ci/tests/datatypes/enums/XnfTypeEnum.java b/integration-tests/src/test/java/org/onap/sdc/backend/ci/tests/datatypes/enums/XnfTypeEnum.java index 0ee3e65944..b27e7e308b 100644 --- a/integration-tests/src/test/java/org/onap/sdc/backend/ci/tests/datatypes/enums/XnfTypeEnum.java +++ b/integration-tests/src/test/java/org/onap/sdc/backend/ci/tests/datatypes/enums/XnfTypeEnum.java @@ -22,6 +22,7 @@ package org.onap.sdc.backend.ci.tests.datatypes.enums; public enum XnfTypeEnum { + ETSI ("ETSI"), VNF ("VNF"), PNF ("PNF"), CNF ("CNF"); diff --git a/integration-tests/src/test/java/org/onap/sdc/backend/ci/tests/utils/general/FileHandling.java b/integration-tests/src/test/java/org/onap/sdc/backend/ci/tests/utils/general/FileHandling.java index d4191d7738..17331e8d64 100644 --- a/integration-tests/src/test/java/org/onap/sdc/backend/ci/tests/utils/general/FileHandling.java +++ b/integration-tests/src/test/java/org/onap/sdc/backend/ci/tests/utils/general/FileHandling.java @@ -135,7 +135,8 @@ public class FileHandling { private static EnumMap XNF_REPOSITORY_PATHS_MAP = new EnumMap<>(Map.of( XnfTypeEnum.PNF, getPnfRepositoryPath(), XnfTypeEnum.CNF, getCnfRepositoryPath(), - XnfTypeEnum.VNF, getVnfRepositoryPath() + XnfTypeEnum.VNF, getVnfRepositoryPath(), + XnfTypeEnum.ETSI, getEtsiRepositoryPath() )); public static String getVnfRepositoryPath() { @@ -150,6 +151,8 @@ public class FileHandling { return getFilePath("CNFs"); } + private static String getEtsiRepositoryPath() { return getFilePath("ETSI"); } + public static String getXnfRepositoryPath(XnfTypeEnum xnfTypeEnum) { return XNF_REPOSITORY_PATHS_MAP.get(xnfTypeEnum); } diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/EtsiOnboardVnfCnfUiTests.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/EtsiOnboardVnfCnfUiTests.java new file mode 100644 index 0000000000..55b4f535db --- /dev/null +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/EtsiOnboardVnfCnfUiTests.java @@ -0,0 +1,182 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.frontend.ci.tests.execute.sanity; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.fail; + +import com.aventstack.extentreports.ExtentTest; +import com.aventstack.extentreports.Status; +import java.util.Map; +import java.util.Optional; +import org.junit.jupiter.api.Assertions; +import org.onap.sdc.backend.ci.tests.data.providers.OnboardingDataProviders; +import org.onap.sdc.backend.ci.tests.datatypes.enums.UserRoleEnum; +import org.onap.sdc.backend.ci.tests.utils.general.ElementFactory; +import org.onap.sdc.frontend.ci.tests.exception.UnzipException; +import org.onap.sdc.frontend.ci.tests.execute.setup.DriverFactory; +import org.onap.sdc.frontend.ci.tests.execute.setup.SetupCDTest; +import org.onap.sdc.frontend.ci.tests.flow.CreateResourceFromVspFlow; +import org.onap.sdc.frontend.ci.tests.flow.CreateVlmFlow; +import org.onap.sdc.frontend.ci.tests.flow.CreateVspFlow; +import org.onap.sdc.frontend.ci.tests.flow.DownloadToscaCsarFlow; +import org.onap.sdc.frontend.ci.tests.flow.ImportVspFlow; +import org.onap.sdc.frontend.ci.tests.flow.exception.UiTestFlowRuntimeException; +import org.onap.sdc.frontend.ci.tests.pages.ComponentPage; +import org.onap.sdc.frontend.ci.tests.pages.ResourceCreatePage; +import org.onap.sdc.frontend.ci.tests.pages.ResourceLeftSideMenu; +import org.onap.sdc.frontend.ci.tests.pages.ResourceWorkspaceTopBarComponent; +import org.onap.sdc.frontend.ci.tests.pages.TopNavComponent; +import org.onap.sdc.frontend.ci.tests.pages.component.workspace.ToscaArtifactsPage; +import org.onap.sdc.frontend.ci.tests.utilities.FileHandling; +import org.openqa.selenium.WebDriver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class EtsiOnboardVnfCnfUiTests extends SetupCDTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(EtsiOnboardVnfCnfUiTests.class); + + private WebDriver webDriver; + private TopNavComponent topNavComponent; + + @BeforeMethod + public void init() { + webDriver = DriverFactory.getDriver(); + topNavComponent = new TopNavComponent(webDriver); + } + + @Test + public void createVlm() { + final ExtentTest extendTest = getExtendTest(); + extendTest.log(Status.INFO, String.format("Starting flow to create a VLM")); + final CreateVlmFlow createVlmFlow = new CreateVlmFlow(webDriver); + createVlmFlow.run(); + } + + @Test(dataProviderClass = OnboardingDataProviders.class, dataProvider = "etsiVnfCnfOnboardPackages") + public void onboardEtsiVnfCnfFlow(final String rootFolder, final String vnfFile) { + setLog(vnfFile); + final String resourceName = ElementFactory.addRandomSuffixToName(ElementFactory.getResourcePrefix()); + runOnboardEtsiVnfCnf(resourceName, rootFolder, vnfFile); + } + + /** + * Runs ETSI onboarding VNF/CNF UI flow + * + * @param resourceName VSP name + * @param rootFolder VNF/CNF package location + * @param vnfCnfFile file to be onboarded + */ + public void runOnboardEtsiVnfCnf(final String resourceName, final String rootFolder, final String vnfCnfFile) { + final ExtentTest extendTest = getExtendTest(); + extendTest.log(Status.INFO, + String.format("Creating VSP '%s' by onboarding ETSI VNF/CNF package '%s'", resourceName, vnfCnfFile)); + final CreateVspFlow createVspFlow = new CreateVspFlow(webDriver, resourceName, vnfCnfFile, rootFolder); + createVspFlow.run(topNavComponent); + + extendTest.log(Status.INFO, String.format("Importing VSP '%s'", resourceName)); + final ImportVspFlow importVspFlow = new ImportVspFlow(webDriver, resourceName); + + extendTest.log(Status.INFO, "Creating ResourceCreatePage"); + final ResourceCreatePage resourceCreatePage = importVspFlow.run() + .orElseThrow(() -> new UiTestFlowRuntimeException("Missing expected return ResourceCreatePage")); + + extendTest.log(Status.INFO, String.format("Onboarding '%s' package", vnfCnfFile)); + final CreateResourceFromVspFlow createResourceFlow = new CreateResourceFromVspFlow(webDriver, resourceName); + createResourceFlow.run(resourceCreatePage); + extendTest.log(Status.INFO, String.format("Successfully onboarded the package '%s'", vnfCnfFile)); + + extendTest.log(Status.INFO, "Loading Component Page"); + final ComponentPage componentPage = loadComponentPage(); + extendTest.log(Status.INFO, "Downloading Tosca CSAR generated"); + final DownloadToscaCsarFlow downloadToscaCsarFlow = downloadToscaCsar(componentPage); + final ToscaArtifactsPage toscaArtifactsPage = downloadToscaCsarFlow.getLandedPage() + .orElseThrow(() -> new UiTestFlowRuntimeException("Missing expected ToscaArtifactsPage")); + assertThat("No artifact download was found", toscaArtifactsPage.getDownloadedArtifactList(), not(empty())); + extendTest.log(Status.INFO, "Tosca CSAR was successfully downloaded"); + + final String downloadedCsarName = toscaArtifactsPage.getDownloadedArtifactList().get(0); + extendTest.log(Status.INFO, String + .format("Verifying if the onboarded package is included in the downloaded csar '%s'", downloadedCsarName)); + verifyOnboardedPackage(downloadedCsarName); + } + + /** + * Loads Component Page + * + * @return ComponentPage + */ + private ComponentPage loadComponentPage() { + final ResourceLeftSideMenu resourceLeftSideMenu = new ResourceLeftSideMenu(webDriver); + resourceLeftSideMenu.isLoaded(); + final ResourceWorkspaceTopBarComponent workspaceTopBarComponent = new ResourceWorkspaceTopBarComponent( + webDriver); + workspaceTopBarComponent.isLoaded(); + final ComponentPage componentPage = Optional + .of(new ComponentPage(webDriver, topNavComponent, resourceLeftSideMenu, workspaceTopBarComponent)) + .orElseThrow(() -> new UiTestFlowRuntimeException("Missing expected ComponentPage")); + componentPage.isLoaded(); + return componentPage; + } + + /** + * Download the generated packag + * + * @return DownloadToscaCsarFlow + */ + private DownloadToscaCsarFlow downloadToscaCsar(final ComponentPage componentPage) { + final DownloadToscaCsarFlow downloadToscaCsarFlow = new DownloadToscaCsarFlow(webDriver); + downloadToscaCsarFlow.run(componentPage); + return downloadToscaCsarFlow; + } + + /** + * Verifies if the onboarded package is included in the downloaded csar + * + * @param downloadedCsarName downloaded csar package name + */ + private void verifyOnboardedPackage(final String downloadedCsarName) { + final String downloadFolderPath = getConfig().getDownloadAutomationFolder(); + final Map filesFromZip; + try { + filesFromZip = FileHandling.getFilesFromZip(downloadFolderPath, downloadedCsarName); + final java.util.Optional etsiPackageEntryOpt = + filesFromZip.keySet().stream().filter(s -> s.startsWith("Artifacts/Deployment/ETSI_PACKAGE")) + .findFirst(); + if (etsiPackageEntryOpt.isEmpty()) { + Assertions.fail("Could not find the Onboarded Package in Artifacts/Deployment/ETSI_PACKAGE"); + } + } catch (final UnzipException e) { + final String errorMsg = "Could not unzip the downloaded csar package"; + LOGGER.info(errorMsg, e); + fail(String.format("%s Error: %s", errorMsg, e.getMessage())); + } + } + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } +} diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/OnboardingFlowsUi.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/OnboardingFlowsUi.java index cf562c766f..693302aca1 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/OnboardingFlowsUi.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/OnboardingFlowsUi.java @@ -52,7 +52,6 @@ import org.onap.sdc.frontend.ci.tests.dataProvider.OnbordingDataProviders; import org.onap.sdc.frontend.ci.tests.datatypes.CanvasElement; import org.onap.sdc.frontend.ci.tests.datatypes.CanvasManager; import org.onap.sdc.frontend.ci.tests.datatypes.DataTestIdEnum; -import org.onap.sdc.frontend.ci.tests.datatypes.ResourceCreateData; import org.onap.sdc.frontend.ci.tests.execute.setup.DriverFactory; import org.onap.sdc.frontend.ci.tests.execute.setup.ExtentTestActions; import org.onap.sdc.frontend.ci.tests.execute.setup.SetupCDTest; @@ -113,12 +112,14 @@ public class OnboardingFlowsUi extends SetupCDTest { protected static String filePath = FileHandling.getVnfRepositoryPath(); private Boolean makeDistributionValue; + private WebDriver webDriver; @Parameters({"makeDistribution"}) @BeforeMethod public void beforeTestReadParams(@Optional("true") String makeDistributionReadValue) { LOGGER.debug("makeDistribution parameter is '{}'", makeDistributionReadValue); makeDistributionValue = Boolean.valueOf(makeDistributionReadValue); + webDriver = DriverFactory.getDriver(); } @Test @@ -388,8 +389,7 @@ public class OnboardingFlowsUi extends SetupCDTest { extendTest.log(Status.INFO, String.format("Creating VSP '%s' by onboarding package '%s' with software version '%s'", - resourceName, pnfFile, swVersionsToString) - ); + resourceName, pnfFile, swVersionsToString)); final WebDriver webDriver = DriverFactory.getDriver(); final CreateVspFlow createVspFlow = new CreateVspFlow(webDriver, resourceName, pnfFile, rootFolder); createVspFlow.run(new TopNavComponent(webDriver)); diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/CreateVlmFlow.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/CreateVlmFlow.java new file mode 100644 index 0000000000..c40205c331 --- /dev/null +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/CreateVlmFlow.java @@ -0,0 +1,126 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.frontend.ci.tests.flow; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +import com.aventstack.extentreports.Status; +import java.util.Optional; +import org.apache.commons.lang.RandomStringUtils; +import org.onap.sdc.frontend.ci.tests.execute.setup.ExtentTestActions; +import org.onap.sdc.frontend.ci.tests.pages.OnboardHomePage; +import org.onap.sdc.frontend.ci.tests.pages.PageObject; +import org.onap.sdc.frontend.ci.tests.pages.TopNavComponent; +import org.onap.sdc.frontend.ci.tests.pages.VlmCreationModal; +import org.onap.sdc.frontend.ci.tests.pages.VlmOverviewPage; +import org.onap.sdc.frontend.ci.tests.pages.home.HomePage; +import org.openqa.selenium.WebDriver; + +public class CreateVlmFlow extends AbstractUiTestFlow { + + private HomePage homePage; + + public CreateVlmFlow(WebDriver webDriver) { + super(webDriver); + } + + @Override + public Optional run(PageObject... pageObjects) { + final TopNavComponent topNavComponent = getParameter(pageObjects, TopNavComponent.class) + .orElse(new TopNavComponent(webDriver)); + extendTest.log(Status.INFO, "Accessing the Onboard Home Page to create a VLM"); + topNavComponent.isLoaded(); + final OnboardHomePage onboardHomePage = goToOnboardHomePage(topNavComponent); + final VlmOverviewPage vlmOverviewPage = createNewVlm(onboardHomePage); + submitVlm(vlmOverviewPage); + goToHomePage(topNavComponent); + return Optional.empty(); + } + + @Override + public Optional getLandedPage() { + return Optional.ofNullable(homePage); + } + + /** + * Goes to the onboard home page by clicking in the onboard tab in the top nav component. + * + * @param topNavComponent the top nav component + * @return the onboard home page + */ + private OnboardHomePage goToOnboardHomePage(final TopNavComponent topNavComponent) { + final OnboardHomePage onboardHomePage = topNavComponent.clickOnOnboard(); + onboardHomePage.isLoaded(); + ExtentTestActions.takeScreenshot(Status.INFO, "onboard-homepage", "Onboard homepage is loaded"); + return onboardHomePage; + } + + /** + * Creates a new VLM in the onboard home page. + * + * @param onboardHomePage the onboard home page representation + * @return the Vendor License Model Overview page + */ + private VlmOverviewPage createNewVlm(final OnboardHomePage onboardHomePage) { + final String vendorName = new StringBuilder("CiVlm").append(RandomStringUtils.randomAlphabetic(5)).toString(); + extendTest.log(Status.INFO, "Creating a new VLM"); + final VlmCreationModal vlmCreationModal = onboardHomePage.clickOnCreateNewVlm(); + vlmCreationModal.isLoaded(); + vlmCreationModal.fillCreationForm(vendorName, "My New VLM"); + ExtentTestActions.takeScreenshot(Status.INFO, "vlm-creation-form", + "Creating VLM with given information"); + final VlmOverviewPage vlmOverviewPage = vlmCreationModal.clickOnCreate(); + vlmOverviewPage.isLoaded(); + extendTest.log(Status.INFO, String.format("VLM with vendor name '%s' created", vendorName)); + final String actualVendorName = vlmOverviewPage.getVendorName(); + assertThat(String.format("Should be in the Vendor License Model '%s' page", vendorName), + actualVendorName, is(vendorName)); + return vlmOverviewPage; + } + + /** + * Submits the VLM through the software product view. + * + * @param vlmOverviewPage the Vendor Licence Overview page + */ + private void submitVlm(final VlmOverviewPage vlmOverviewPage) { + extendTest.log(Status.INFO, "Checking if the VLM Overview page is loaded."); + ExtentTestActions.takeScreenshot(Status.INFO, "vlm-overview-page-loaded", "The first VLM version was submitted"); + vlmOverviewPage.overviewScreenIsLoaded(); + extendTest.log(Status.INFO, "Submitting the first VLM version."); + vlmOverviewPage.submit(); + ExtentTestActions.takeScreenshot(Status.INFO, "vlm-submitted", "The first VLM version was submitted"); + } + + /** + * Go to the system home page through the top nav menu. + * + * @param topNavComponent the top nav component + */ + private void goToHomePage(final TopNavComponent topNavComponent) { + extendTest.log(Status.INFO, "Accessing the Home page"); + topNavComponent.isLoaded(); + homePage = topNavComponent.clickOnHome(); + homePage.isLoaded(); + ExtentTestActions.takeScreenshot(Status.INFO, "home-is-loaded", "The Home page is loaded."); + } + +} diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/CreateVspFlow.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/CreateVspFlow.java index 1da45b5397..614dc1a2af 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/CreateVspFlow.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/CreateVspFlow.java @@ -31,7 +31,6 @@ import org.onap.sdc.frontend.ci.tests.pages.SoftwareProductOnboarding; import org.onap.sdc.frontend.ci.tests.pages.TopNavComponent; import org.onap.sdc.frontend.ci.tests.pages.VspCreationModal; import org.onap.sdc.frontend.ci.tests.pages.home.HomePage; -import org.onap.sdc.frontend.ci.tests.utilities.GeneralUIUtils; import org.openqa.selenium.WebDriver; /** @@ -140,8 +139,7 @@ public class CreateVspFlow extends AbstractUiTestFlow { private void goToHomePage(final TopNavComponent topNavComponent) { extendTest.log(Status.INFO, "Accessing the Home page to import the created VSP"); topNavComponent.isLoaded(); - homePage = topNavComponent.clickOnHome(); - GeneralUIUtils.ultimateWait(); + this.homePage = topNavComponent.clickOnHome(); homePage.isLoaded(); ExtentTestActions.takeScreenshot(Status.INFO, "home-is-loaded", "The Home page is loaded."); } diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/DownloadToscaCsarFlow.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/DownloadToscaCsarFlow.java new file mode 100644 index 0000000000..d785c1f3c5 --- /dev/null +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/flow/DownloadToscaCsarFlow.java @@ -0,0 +1,77 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.frontend.ci.tests.flow; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +import com.aventstack.extentreports.Status; +import java.io.File; +import java.time.Duration; +import java.util.Optional; +import org.onap.sdc.frontend.ci.tests.execute.setup.ExtentTestActions; +import org.onap.sdc.frontend.ci.tests.pages.ComponentPage; +import org.onap.sdc.frontend.ci.tests.pages.PageObject; +import org.onap.sdc.frontend.ci.tests.pages.component.workspace.ToscaArtifactsPage; +import org.onap.sdc.frontend.ci.tests.utilities.FileHandling; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.support.ui.FluentWait; + +/** + * UI Flow for downloading Tosca CSAR from a component + */ +public class DownloadToscaCsarFlow extends AbstractUiTestFlow { + + private ToscaArtifactsPage toscaArtifactsPage; + + public DownloadToscaCsarFlow(final WebDriver webDriver) { + super(webDriver); + } + + @Override + public Optional run(final PageObject... pageObjects) { + final ComponentPage componentPage = findParameter(pageObjects, ComponentPage.class); + toscaArtifactsPage = componentPage.goToToscaArtifacts(); + toscaArtifactsPage.isLoaded(); + toscaArtifactsPage.clickOnDownload("Tosca Model"); + + final File downloadedCsar = waitAndGetDownloadedCsar(); + assertThat("The downloaded CSAR should exist", downloadedCsar, is(notNullValue())); + assertThat("The downloaded CSAR should exist", downloadedCsar.exists(), is(true)); + toscaArtifactsPage.addToDownloadedArtifactList(downloadedCsar.getName()); + ExtentTestActions.takeScreenshot(Status.INFO, "tosca-csar-downloaded", "TOSCA CSAR Downloaded"); + + return Optional.of(toscaArtifactsPage); + } + + @Override + public Optional getLandedPage() { + return Optional.ofNullable(toscaArtifactsPage); + } + + private File waitAndGetDownloadedCsar() { + final FluentWait fluentWait = new FluentWait<>("") + .withTimeout(Duration.ofSeconds(5)).pollingEvery(Duration.ofSeconds(1)); + fluentWait.until(s -> FileHandling.getLastModifiedFileNameFromDir() != null); + return FileHandling.getLastModifiedFileNameFromDir(); + } + +} diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/ComponentPage.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/ComponentPage.java new file mode 100644 index 0000000000..13ab884c70 --- /dev/null +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/ComponentPage.java @@ -0,0 +1,51 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.frontend.ci.tests.pages; + +import org.onap.sdc.frontend.ci.tests.pages.component.workspace.ToscaArtifactsPage; +import org.openqa.selenium.WebDriver; + +public class ComponentPage extends AbstractPageObject { + + private final TopNavComponent topNavComponent; + private final ResourceLeftSideMenu resourceLeftSideMenu; + private final ResourceWorkspaceTopBarComponent workspaceTopBarComponent; + + public ComponentPage(final WebDriver webDriver, final TopNavComponent topNavComponent, + final ResourceLeftSideMenu resourceLeftSideMenu, + final ResourceWorkspaceTopBarComponent workspaceTopBarComponent) { + super(webDriver); + this.topNavComponent = topNavComponent; + this.resourceLeftSideMenu = resourceLeftSideMenu; + this.workspaceTopBarComponent = workspaceTopBarComponent; + } + + @Override + public void isLoaded() { + topNavComponent.isLoaded(); + resourceLeftSideMenu.isLoaded(); + workspaceTopBarComponent.isLoaded(); + } + + public ToscaArtifactsPage goToToscaArtifacts() { + return resourceLeftSideMenu.clickOnToscaArtifactsMenuItem(); + } + +} diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/OnboardHomePage.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/OnboardHomePage.java index cd3e34d36e..70af5cdeaa 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/OnboardHomePage.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/OnboardHomePage.java @@ -19,6 +19,7 @@ package org.onap.sdc.frontend.ci.tests.pages; + import lombok.AllArgsConstructor; import lombok.Getter; import org.openqa.selenium.By; @@ -33,6 +34,7 @@ public class OnboardHomePage extends AbstractPageObject { private final OnboardHeaderComponent onboardHeaderComponent; private WebElement createNewVspBtn; + private WebElement createNewVlmBtn; public OnboardHomePage(final WebDriver webDriver, final OnboardHeaderComponent onboardHeaderComponent) { @@ -45,7 +47,8 @@ public class OnboardHomePage extends AbstractPageObject { onboardHeaderComponent.isLoaded(); createNewVspBtn = getWait() .until(ExpectedConditions.visibilityOfElementLocated(By.xpath(XpathSelector.ADD_NEW_VSP_BTN.getXpath()))); - getWait() + + createNewVlmBtn = getWait() .until(ExpectedConditions.visibilityOfElementLocated(By.xpath(XpathSelector.ADD_NEW_VLM_BTN.getXpath()))); } @@ -55,17 +58,31 @@ public class OnboardHomePage extends AbstractPageObject { * @return returns the next vsp creation page object */ public VspCreationModal clickOnCreateNewVsp() { + waitForElementInvisibility(By.xpath(XpathSelector.ONBOARDING_LOADER_DIV.getXpath())); createNewVspBtn.click(); return new VspCreationModal(webDriver); } + + /** + * Clicks on the button create new vlm. + * + * @return returns the next vlm creation page object + */ + public VlmCreationModal clickOnCreateNewVlm() { + waitForElementInvisibility(By.xpath(XpathSelector.ONBOARDING_LOADER_DIV.getXpath())); + createNewVlmBtn.click(); + return new VlmCreationModal(webDriver); + } + /** * Enum that contains identifiers and xpath expressions to elements related to the enclosing page object. */ @AllArgsConstructor private enum XpathSelector { ADD_NEW_VSP_BTN("catalog-add-new-vsp", "//div[@data-test-id='%s']"), - ADD_NEW_VLM_BTN("catalog-add-new-vlm", "//div[@data-test-id='%s']"); + ADD_NEW_VLM_BTN("catalog-add-new-vlm", "//div[@data-test-id='%s']"), + ONBOARDING_LOADER_DIV("onboarding-loader-backdrop","//div[@class='%s']"); @Getter private final String id; diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/TopNavComponent.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/TopNavComponent.java index 33deabbae0..7eb15bbded 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/TopNavComponent.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/TopNavComponent.java @@ -76,10 +76,11 @@ public class TopNavComponent extends AbstractPageObject { public boolean isHomeSelected() { final By homeLinkLocator = By.xpath(XpathSelector.MAIN_MENU_LINK_HOME.getXpath()); - final WebElement homeLinkElement = waitForElementVisibility(homeLinkLocator); + final WebElement homeLinkElement = waitToBeClickable(homeLinkLocator); final WebElement homeLinkParentElement = homeLinkElement.findElement(By.xpath("./..")); - final String aClass = homeLinkParentElement.getAttribute("class"); - return "selected".equals(aClass); + final String homeLinkClass = homeLinkParentElement.getAttribute("class"); + LOGGER.debug(String.format("Home link class '%s'", homeLinkClass)); + return homeLinkClass != null && homeLinkClass.contains("selected"); } /** @@ -116,6 +117,7 @@ public class TopNavComponent extends AbstractPageObject { * @return the next page object */ public OnboardHomePage clickOnOnboard() { + waitForElementInvisibility(By.xpath(XpathSelector.SDC_LOADER_BACKGROUND.getXpath())); wrappingElement.findElement(By.xpath(XpathSelector.MAIN_MENU_ONBOARD_BTN.getXpath())).click(); return new OnboardHomePage(DriverFactory.getDriver(), new OnboardHeaderComponent(DriverFactory.getDriver())); } @@ -146,7 +148,8 @@ public class TopNavComponent extends AbstractPageObject { MAIN_MENU_LINK_HOME("main-menu-button-home", "//*[@data-tests-id='%s']"), ARROW_DROPDOWN("triangle-dropdown", "//li[contains(@class, '%s')]"), MAIN_MENU_ONBOARD_BTN("main-menu-button-onboard", "//a[@data-tests-id='%s']"), - REPOSITORY_ICON("repository-icon", "//*[@data-tests-id='%s']"); + REPOSITORY_ICON("repository-icon", "//*[@data-tests-id='%s']"), + SDC_LOADER_BACKGROUND("sdc-loader-global-wrapper sdc-loader-background", "//div[@class='%s']"); @Getter private final String id; diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VlmCreationModal.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VlmCreationModal.java new file mode 100644 index 0000000000..13c0236ad8 --- /dev/null +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VlmCreationModal.java @@ -0,0 +1,122 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.frontend.ci.tests.pages; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handles the VLM Creation Modal UI actions + */ +public class VlmCreationModal extends AbstractPageObject { + + private static final Logger LOGGER = LoggerFactory.getLogger(VlmCreationModal.class); + + private WebElement wrappingElement; + + public VlmCreationModal(final WebDriver webDriver) { + super(webDriver); + timeoutInSeconds = 5; + } + + @Override + public void isLoaded() { + LOGGER.debug("Finding element with xpath '{}'", XpathSelector.MODAL_XPATH.getXpath()); + wrappingElement = waitForElementVisibility(XpathSelector.MODAL_XPATH.getXpath()); + } + + /** + * Fills VLM mandatory entries + * @param vendorName the VLM vendor name + * @param description the VLM description + */ + public void fillCreationForm(final String vendorName, final String description) { + fillVendorName(vendorName); + fillDescription(description); + } + + /** + * Fills the VLM Vendor Name field + * @param vendorName the VLM vendor name + */ + private void fillVendorName(final String vendorName) { + setInputValue(XpathSelector.VENDOR_NAME_TXT, vendorName); + } + + /** + * Fills the VLM description field. + * + * @param description the VLM description + */ + public void fillDescription(final String description) { + setInputValue(XpathSelector.DESCRIPTION_TXT, description); + } + + /** + * Sets input value to the given Xpath + * @param inputTestId the Xpath selected + * @param value the value + */ + private void setInputValue(final XpathSelector inputTestId, final String value) { + findSubElement(wrappingElement, By.xpath(inputTestId.getXpath())).sendKeys(value); + } + + /** + * Clicks on the create button. + * @return the next page object + */ + public VlmOverviewPage clickOnCreate() { + clickElement(XpathSelector.CREATE_BTN); + return new VlmOverviewPage(webDriver, new VlmSubmitModal(webDriver)); + } + + /** + * Clicks on the given Xpath element + * @param elementTestId the ui element + */ + private void clickElement(final XpathSelector elementTestId) { + wrappingElement.findElement(By.xpath(elementTestId.getXpath())).click(); + } + + /** + * Enum that contains identifiers and xpath expressions to elements related to the enclosing page object. + */ + @AllArgsConstructor + private enum XpathSelector { + MODAL_XPATH("license-model-modal", "//div[@class='%s']"), + VENDOR_NAME_TXT("vendor-name", "//*[@data-test-id='%s']"), + DESCRIPTION_TXT("vendor-description", "//*[@data-test-id='%s']"), + CREATE_BTN("form-submit-button", "//*[@data-test-id='%s']"); + + @Getter + private final String id; + private final String xpathFormat; + + public String getXpath() { + return String.format(xpathFormat, id); + } + } + +} diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VlmOverviewPage.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VlmOverviewPage.java new file mode 100644 index 0000000000..ce3c26b215 --- /dev/null +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VlmOverviewPage.java @@ -0,0 +1,100 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.frontend.ci.tests.pages; + +import static org.hamcrest.MatcherAssert.assertThat; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hamcrest.core.Is; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VlmOverviewPage extends AbstractPageObject { + + private static final Logger LOGGER = LoggerFactory.getLogger(VlmOverviewPage.class); + private static final String DIV_CLASS_XPATH_FORMAT = "//div[@class='%s']"; + private static final String DIV_DATA_TEST_ID_XPATH_FORMAT = "//div[@data-test-id='%s']"; + private final VlmSubmitModal vlmSubmitModal; + private WebElement wrappingElement; + + public VlmOverviewPage(final WebDriver webDriver, + final VlmSubmitModal vlmSubmitModal) { + super(webDriver); + this.vlmSubmitModal = vlmSubmitModal; + timeoutInSeconds = 10; + } + + @Override + public void isLoaded() { + wrappingElement = getWrappingElement(); + } + + public void overviewScreenIsLoaded() { + final String overviewPageXpath = String + .format("%s%s", VlmOverviewPage.XpathSelector.PAGE_MAIN_DIV.getXpath(), XpathSelector.OVERVIEW_PAGE.getXpath()); + waitForElementVisibility(By.xpath(overviewPageXpath)); + final WebElement selectedNavBarGroupItem = + findSubElement(wrappingElement, XpathSelector.SELECTED_NAV_BAR_GROUP_ITEM.getXpath()); + final String selectedNavBarGroupItemTestId = selectedNavBarGroupItem.getAttribute("data-test-id"); + assertThat("Overview page should be selected", selectedNavBarGroupItemTestId, + Is.is(XpathSelector.NAV_BAR_GROUP_ITEM_OVERVIEW.getId())); + } + + public String getVendorName() { + return wrappingElement.findElement(By.xpath(XpathSelector.NAV_BAR_GROUP_NAME_XPATH.getXpath())).getText(); + } + + public void submit() { + findSubElement(wrappingElement, XpathSelector.BNT_SUBMIT.getXpath()).click(); + vlmSubmitModal.isLoaded(); + vlmSubmitModal.confirmSuccess(); + } + + public WebElement getWrappingElement() { + LOGGER.debug("Finding element with xpath '{}'", XpathSelector.PAGE_MAIN_DIV.getXpath()); + return waitForElementVisibility(XpathSelector.PAGE_MAIN_DIV.getXpath()); + } + + /** + * Enum that contains identifiers and xpath expressions to elements related to the enclosing page object. + */ + @AllArgsConstructor + private enum XpathSelector { + PAGE_MAIN_DIV("software-product-view", DIV_CLASS_XPATH_FORMAT), + NAV_BAR_GROUP_ITEM_OVERVIEW("navbar-group-item-LICENSE_MODEL_OVERVIEW", DIV_CLASS_XPATH_FORMAT), + BNT_SUBMIT("vc-submit-btn", DIV_DATA_TEST_ID_XPATH_FORMAT), + NAV_BAR_GROUP_NAME_XPATH("navbar-group-name", DIV_DATA_TEST_ID_XPATH_FORMAT), + SELECTED_NAV_BAR_GROUP_ITEM("navigation-group-item-name selected", DIV_CLASS_XPATH_FORMAT), + OVERVIEW_PAGE("license-model-overview", DIV_CLASS_XPATH_FORMAT); + + @Getter + private final String id; + private final String xpathFormat; + + public String getXpath() { + return String.format(xpathFormat, id); + } + + } + +} diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VlmSubmitModal.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VlmSubmitModal.java new file mode 100644 index 0000000000..112ddc2b5f --- /dev/null +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VlmSubmitModal.java @@ -0,0 +1,74 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.frontend.ci.tests.pages; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handles the VLM Submit Modal UI actions + */ +public class VlmSubmitModal extends AbstractPageObject { + + private static final Logger LOGGER = LoggerFactory.getLogger(VlmSubmitModal.class); + + + public VlmSubmitModal(final WebDriver webDriver) { + super(webDriver); + } + + public void isLoaded() { + LOGGER.debug("Finding element with xpath '{}'", XpathSelector.MODAL_DIV.getXpath()); + waitForElementVisibility(XpathSelector.MODAL_DIV.getXpath()); + } + + /** + * Confirms the success of the modal submission. + */ + public void confirmSuccess() { + final WebElement successModal = waitForElementVisibility(XpathSelector.SUCCESS_MODAL_DIV.getXpath()); + successModal.findElement(By.xpath(XpathSelector.MODAL_CANCEL_BTN.getXpath())).click(); + } + + /** + * Enum that contains identifiers and xpath expressions to elements related to the enclosing page object. + */ + @AllArgsConstructor + private enum XpathSelector { + MODAL_DIV("sdc-modal", "//div[contains(@class, '%s')]"), + SUBMIT_BTN("vc-submit-btn", "//div[@data-test-id='%s']"), + SUCCESS_MODAL_DIV("sdc-modal-type-info", "//div[contains(@class, '%s')]"), + MODAL_CANCEL_BTN("sdc-modal-cancel-button", "//button[@data-test-id='%s']"); + + @Getter + private final String id; + private final String xpath; + + public String getXpath() { + return String.format(xpath, id); + } + } + +} diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VspCommitModal.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VspCommitModal.java index 5c1928cf36..bf57e099a2 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VspCommitModal.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/VspCommitModal.java @@ -21,11 +21,9 @@ package org.onap.sdc.frontend.ci.tests.pages; import lombok.AllArgsConstructor; import lombok.Getter; -import org.onap.sdc.frontend.ci.tests.utilities.GeneralUIUtils; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.ui.ExpectedConditions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,7 +59,6 @@ public class VspCommitModal extends AbstractPageObject { public void submit() { final WebElement commitAndSubmitBtn = wrappingElement.findElement(By.xpath(XpathSelector.COMMIT_AND_SUBMIT_BTN.getXpath())); commitAndSubmitBtn.click(); - GeneralUIUtils.ultimateWait(); confirmSuccess(); } @@ -69,8 +66,7 @@ public class VspCommitModal extends AbstractPageObject { * Confirms the success of the modal submission. */ private void confirmSuccess() { - final WebElement successModal = getWait() - .until(ExpectedConditions.visibilityOfElementLocated(By.xpath(XpathSelector.SUCCESS_MODAL_DIV.getXpath()))); + final WebElement successModal = waitForElementVisibility(By.xpath(XpathSelector.SUCCESS_MODAL_DIV.getXpath()), 60); successModal.findElement(By.xpath(XpathSelector.MODAL_CANCEL_BTN.getXpath())).click(); } diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/home/HomePage.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/home/HomePage.java index 563dd11452..7a0d7a1e6b 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/home/HomePage.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/home/HomePage.java @@ -22,6 +22,7 @@ package org.onap.sdc.frontend.ci.tests.pages.home; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; +import java.time.Duration; import lombok.AllArgsConstructor; import lombok.Getter; import org.onap.sdc.frontend.ci.tests.pages.AbstractPageObject; @@ -31,6 +32,7 @@ import org.onap.sdc.frontend.ci.tests.pages.ResourceWorkspaceTopBarComponent; import org.onap.sdc.frontend.ci.tests.pages.ServiceComponentPage; import org.onap.sdc.frontend.ci.tests.pages.ServiceCreatePage; import org.onap.sdc.frontend.ci.tests.pages.TopNavComponent; +import org.onap.sdc.frontend.ci.tests.utilities.LoaderHelper; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; @@ -51,6 +53,8 @@ public class HomePage extends AbstractPageObject { @Override public void isLoaded() { + new Actions(webDriver).pause(Duration.ofSeconds(2)).perform(); + new LoaderHelper(webDriver).waitForLoaderInvisibility(5); waitToBeClickable(XpathSelector.HOME_RIGHT_CONTAINER.getXpath()); waitToBeClickable(XpathSelector.HOME_SIDE_BAR.getXpath()); topNavComponent.isLoaded(); diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/utilities/GeneralUIUtils.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/utilities/GeneralUIUtils.java index 302edacacb..c0a829af64 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/utilities/GeneralUIUtils.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/utilities/GeneralUIUtils.java @@ -717,7 +717,7 @@ public final class GeneralUIUtils { getDriver().navigate().to(url); } - public static void refreshWebpage() throws Exception { + public static void refreshWebpage() { getExtendTest().log(Status.INFO, "Refreshing Webpage"); getDriver().navigate().refresh(); ultimateWait(); diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/utilities/LoaderHelper.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/utilities/LoaderHelper.java index d8f57db7e6..e5bfc2bbbb 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/utilities/LoaderHelper.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/utilities/LoaderHelper.java @@ -25,7 +25,7 @@ import org.openqa.selenium.WebDriver; public class LoaderHelper extends AbstractPageObject { - private final By loaderLocator = By.xpath("//*[@data-tests-id='loader' or @class='tlv-loader']"); + private final By loaderLocator = By.xpath("//*[@data-tests-id='loader' or @class='tlv-loader' or @class='sdc-loader' or @class='sdc-loader-global-wrapper sdc-loader-background']"); public LoaderHelper(final WebDriver webDriver) { super(webDriver); @@ -36,6 +36,10 @@ public class LoaderHelper extends AbstractPageObject { waitForElementInvisibility(loaderLocator, timeout); } + public void waitForLoaderInvisibility(final int timeout) { + waitForElementInvisibility(loaderLocator, timeout); + } + @Override public void isLoaded() { diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/utilities/NotificationComponent.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/utilities/NotificationComponent.java index 26db4828f7..2ffe658465 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/utilities/NotificationComponent.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/utilities/NotificationComponent.java @@ -19,6 +19,7 @@ package org.onap.sdc.frontend.ci.tests.utilities; + import lombok.AllArgsConstructor; import lombok.Getter; import org.onap.sdc.frontend.ci.tests.pages.AbstractPageObject; @@ -48,9 +49,14 @@ public class NotificationComponent extends AbstractPageObject { } private String getMessageXpath(final NotificationType notificationType) { + final String messageContainerPath = String + .format("%s%s", XpathSelector.MAIN_CONTAINER_DIV.getXpath(), XpathSelector.MESSAGE_CONTENT_DIV.getXpath()); if (notificationType == NotificationType.SUCCESS) { - return String.format("%s%s%s", XpathSelector.MAIN_CONTAINER_DIV.getXpath(), XpathSelector.MESSAGE_CONTENT_DIV.getXpath(), - XpathSelector.MESSAGE_SUCCESS_DIV.getXpath()); + return String.format("%s%s", messageContainerPath, XpathSelector.MESSAGE_SUCCESS_DIV.getXpath()); + } + + if (notificationType == NotificationType.CREATE_OR_UPDATE) { + return String.format("%s%s", messageContainerPath, XpathSelector.MESSAGE_CREATE_UPDATE_DIV.getXpath()); } LOGGER.warn("Xpath for NotificationType {} not yet implemented.", notificationType); @@ -66,8 +72,8 @@ public class NotificationComponent extends AbstractPageObject { private enum XpathSelector { MAIN_CONTAINER_DIV("notification-container", "//div[@class='%s']"), MESSAGE_CONTENT_DIV("msg-content", "//div[@class='%s']"), - MESSAGE_SUCCESS_DIV("message", - "//div[contains(@class, 'message') and (contains(text(),'successfully') or contains(text(), 'Successfully'))]"); + MESSAGE_SUCCESS_DIV("message", "//div[contains(@class, 'message') and (contains(text(),'successfully') or contains(text(), 'Successfully'))]"), + MESSAGE_CREATE_UPDATE_DIV("message", "//div[contains(@class, '%s') and (contains(text(), 'Create/Update') or contains(text(), 'created'))]"); @Getter private final String id; @@ -79,7 +85,7 @@ public class NotificationComponent extends AbstractPageObject { } public enum NotificationType { - SUCCESS; + SUCCESS, CREATE_OR_UPDATE; } } diff --git a/integration-tests/src/test/resources/Files/ETSI/ETSI-CNF-SAMPLE.csar b/integration-tests/src/test/resources/Files/ETSI/ETSI-CNF-SAMPLE.csar new file mode 100644 index 0000000000000000000000000000000000000000..841eddd84dd9c1cf6361154c948c793a8d19d314 GIT binary patch literal 21234 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 literal 0 HcmV?d00001 diff --git a/integration-tests/src/test/resources/Files/ETSI/ETSI-VNF-SAMPLE.csar b/integration-tests/src/test/resources/Files/ETSI/ETSI-VNF-SAMPLE.csar new file mode 100644 index 0000000000000000000000000000000000000000..10c7169ab98629e165ef916d9acb875a0c0eb1de GIT binary patch literal 2229 zcmWIWW@Zs#0D(ER-a%jnl;C1eU~nud$xKU3E-BUz4dG>A{~4f~;1;2p-~z;@72FJr zEH9WD7{EjT*c=W94hF6|ggI6~v&2!%an4B0OHcL5PuDA{C;=OKG*C669J`_1Cr{{v zF)W(Y6Vkfn%%Vp^t(&eadUWQGP3s>M*5gm^gtXo{wPBA*>!T}+Hl2AA(mLtNou)ZQ zCWYAQF$8$CbNE%MiGmye!U*RHB00|!C?kX7y!^bx0^Q`iG~JBUoLs%i#M~UP8!zE@ zqqnE7pWZ1Qjgx22Zw?Ch^u3rTpx|3^@CT2xCqp?rb@c){{Lbi}@C<#VrEyCCw2!AQ z)2gD9Z>2!Kx2{&(3!^K>0gsr#?&WM}N^=9c2;?e=dw~pw2WZj419Y!TYFcJqW=Up# z9yDS~f$k$1F$_pPpUTL_r8p6*Tar?P8V0YeO1D-p)KjeQfa|)Dvo*{Dg zlBz?v<3{~n2Ja9TwTA!ue3B&Rp6NVZ{lFph`v9PP!Lg-H`7*RcpsxXGfPy^}l#yBd^Fj*C-ae zea-7l|MIUVRE_=AfAgH0y)r}f_W{HESEc?lf>KCV%#LM8fME;@4MYlA*N8~KzkxCw zz;J?uO>P=EHLMI*P4K{;VtWI9{f{UJ*y`_JRG!P7Yja|4WWN;u?vGw>RwbRRQVFYn zzh62(&ZLkp<=I~Ien|s~g{>TOQZ(IGM=gw=H}m%FP-zvm_ilF=&0pyzrP3~%x88`0 zn{E5FR)(L9vR#6;7tVd^5iK$2_B-nTp?-s0bxVWN*%qZ&CwDA*W4OHZ+>M!rakd3s z?=^hYEj`lNI)3eS7i60fl{wQZ-TeK5&AV1`oAsx*Y&-Qa$N%PE|2V;-qHz7~u3U@D z9{j1YGW&V@SJ2ZKF}10?A8}6IR<+A=iuZ3`pZ%A6`=c6r7TUxeDEskdmr~u)_=@zz z6H7yXvQ}@NAu#)!VZz*oP&KAw8)|MW5%<(r`^)6}QU7s1IDBniJ>UX{ASe_ODcZ6L z5x$@l&JPUV5dUCjM_u34lEjq6l0-;pvkn-?4D<`g zKLOs1Od`ypvYwgs04+9C5;c!OeVfOg}ELS zPN34K3n|}#N*@?l(#Q#{Z;367V5Wj}BWDv3AC%`{;H_gO3j^sn5D_dO!;#Z0C=bHG dlE!VAh7+G71H4(;Kt_Q==06hy!va + + + + + + -- 2.16.6