com.seleniumtests.core.runner.CustomTestNGCucumberRunner.java Source code

Java tutorial

Introduction

Here is the source code for com.seleniumtests.core.runner.CustomTestNGCucumberRunner.java

Source

/**
 * Orignal work: Copyright 2015 www.seleniumtests.com
 * Modified work: Copyright 2016 www.infotel.com
 *             Copyright 2017-2019 B.Hecquet
 *
 * 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.
 */
package com.seleniumtests.core.runner;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FilenameUtils;

import com.seleniumtests.core.SeleniumTestsContextManager;
import com.seleniumtests.customexception.CustomSeleniumTestsException;

import cucumber.api.testng.FeatureResultListener;
import cucumber.runtime.ClassFinder;
import cucumber.runtime.CucumberException;
import cucumber.runtime.Runtime;
import cucumber.runtime.RuntimeOptions;
import cucumber.runtime.RuntimeOptionsFactory;
import cucumber.runtime.io.MultiLoader;
import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.io.ResourceLoaderClassFinder;
import cucumber.runtime.model.CucumberExamples;
import cucumber.runtime.model.CucumberFeature;
import cucumber.runtime.model.CucumberScenario;
import cucumber.runtime.model.CucumberScenarioOutline;
import cucumber.runtime.model.CucumberTagStatement;
import cucumber.runtime.model.StepContainer;
import gherkin.formatter.Formatter;

public class CustomTestNGCucumberRunner {

    private Runtime runtime;
    private List<CucumberFeature> cucumberFeatures;
    private RuntimeOptions runtimeOptions;
    private ResourceLoader resourceLoader;
    private FeatureResultListener resultListener;
    private ClassLoader classLoader;

    /**
     * Bootstrap the cucumber runtime
     *
     * @param clazz Which has the cucumber.api.CucumberOptions and org.testng.annotations.Test annotations
     */
    public CustomTestNGCucumberRunner(Class<?> clazz) {
        classLoader = clazz.getClassLoader();
        resourceLoader = new MultiLoader(classLoader);

        cucumberFeatures = initCucumberOptions(clazz);

        resultListener = new FeatureResultListener(runtimeOptions.reporter(classLoader), runtimeOptions.isStrict());
    }

    private List<CucumberFeature> initCucumberOptions(Class<?> clazz) {
        String cucumberPkg = SeleniumTestsContextManager.getThreadContext().getCucmberPkg();
        if (cucumberPkg == null) {
            throw new CustomSeleniumTestsException(
                    "'cucumberPackage' parameter is not set in test NG XML file (inside <suite> tag), "
                            + "set it to the root package where cucumber implementation resides");
        }

        // get all features, filtered by test name
        System.setProperty("cucumber.options", "'" + SeleniumTestsContextManager.getFeaturePath() + "'");
        List<CucumberFeature> testSelectedFeatures = getFeaturesFromRequestedTests(clazz, resourceLoader);

        // build cucumber option list
        // take into account tag options
        String cucumberOptions = "";
        String tagList = SeleniumTestsContextManager.getThreadContext().getCucumberTags();
        if (tagList != null && !"".equals(tagList)) {
            String tagsOptions = " ";
            for (String tags : tagList.split("AND")) {
                tagsOptions += String.format("--tags %s ", tags.trim());
            }

            cucumberOptions += tagsOptions;
        }

        // add cucumber implementation classes
        cucumberOptions += " --glue classpath:" + cucumberPkg;

        // add feature path
        cucumberOptions += " '" + SeleniumTestsContextManager.getFeaturePath() + "'";

        // get filtered features, based on tags
        runtimeOptions = new RuntimeOptions(cucumberOptions);
        ClassFinder classFinder = new ResourceLoaderClassFinder(resourceLoader, classLoader);
        runtime = new Runtime(resourceLoader, classFinder, classLoader, runtimeOptions);

        // add list of tag filtered features to features selected by tests 
        if (tagList != null && !"".equals(tagList)) {
            testSelectedFeatures.addAll(runtimeOptions.cucumberFeatures(resourceLoader));
        }

        if (testSelectedFeatures.isEmpty()) {
            throw new CustomSeleniumTestsException("No test has been selected");
        }

        return testSelectedFeatures;
    }

    /**
     * Get list of features given their name or their file name
     */
    private List<CucumberFeature> getFeaturesFromRequestedTests(Class<?> clazz, ResourceLoader resourceLoader) {

        RuntimeOptions runtimeOptionsB = new RuntimeOptionsFactory(clazz).create();

        final List<CucumberFeature> allFeatures = runtimeOptionsB.cucumberFeatures(resourceLoader);
        List<CucumberFeature> selectedFeatures = new ArrayList<>();

        // filter features requested for execution
        List<String> testList = SeleniumTestsContextManager.getThreadContext().getCucumberTests();

        selectedFeatures = selectFeatures(allFeatures, selectedFeatures, testList);

        if (selectedFeatures.isEmpty()) {
            // select scenarios in features

            // get only scenarios whose name is in the list of tests
            for (CucumberFeature feature : allFeatures) {

                List<CucumberTagStatement> selectedScenarios = new ArrayList<>();

                selectedScenarios = selectSenario(feature, testList, selectedScenarios);

                feature.getFeatureElements().removeAll(feature.getFeatureElements());
                feature.getFeatureElements().addAll(selectedScenarios);

                if (!selectedScenarios.isEmpty()) {
                    selectedFeatures.add(feature);
                }
            }
        }

        return selectedFeatures;
    }

    /**
     * 
     * @param allFeatures
     * @param selectedFeatures
     * @param testList
     * @return Cucumber feature list of selected tests
     */
    private List<CucumberFeature> selectFeatures(final List<CucumberFeature> allFeatures,
            List<CucumberFeature> selectedFeatures, List<String> testList) {
        for (CucumberFeature feature : allFeatures) {
            String featureName = feature.getGherkinFeature().getName();
            String featureFileName = FilenameUtils.getBaseName(feature.getPath());

            for (String test : testList) {
                if (featureName.matches(test) || test.equals(featureFileName)) {
                    selectedFeatures.add(feature);
                    break;
                }
            }
        }
        return selectedFeatures;
    }

    /**
     * 
     * @param feature
     * @param testList
     * @param selectedScenarios
     * @return Cucumber statement list of selected tests
     */
    private List<CucumberTagStatement> selectSenario(CucumberFeature feature, List<String> testList,
            List<CucumberTagStatement> selectedScenarios) {
        for (CucumberTagStatement stmt : feature.getFeatureElements()) {

            for (String test : testList) {
                if (stmt.getGherkinModel().getName().equals(test)
                        || stmt.getGherkinModel().getName().matches(test)) {
                    selectedScenarios.add(stmt);
                }
            }
        }
        return selectedScenarios;
    }

    public void runScenario(CucumberScenarioWrapper cucumberScenarioWrapper) {

        resultListener.startFeature();

        Formatter formatter = runtimeOptions.formatter(classLoader);
        CucumberScenario cucumberScenario = cucumberScenarioWrapper.getCucumberScenario();

        try {
            Field field = StepContainer.class.getDeclaredField("cucumberFeature");
            field.setAccessible(true);
            CucumberFeature cucumberFeature = (CucumberFeature) field.get(cucumberScenario);
            formatter.uri(cucumberFeature.getPath());
            formatter.feature(cucumberFeature.getGherkinFeature());

            cucumberScenario.run(runtimeOptions.formatter(classLoader), resultListener, runtime);
            formatter.eof();
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new CucumberException("Could not run scenario: " + e.getMessage());
        }

        if (!resultListener.isPassed()) {
            throw new CucumberException(resultListener.getFirstError());
        }
    }

    public void finish() {
        Formatter formatter = runtimeOptions.formatter(classLoader);
        formatter.done();
        formatter.close();
        runtime.printSummary();
        if (!runtime.getSnippets().isEmpty()) {
            throw new CucumberException("Some steps could not be found");
        }
    }

    /**
     * @return List of detected cucumber features
     */
    public List<CucumberFeature> getFeatures() {
        return cucumberFeatures;
    }

    public Object[][] provideScenarios() {
        List<CucumberScenarioWrapper> scenarioList = new ArrayList<>();
        for (CucumberFeature feature : getFeatures()) {

            // get scenario / scenario outline
            for (CucumberTagStatement cucumberTagStatement : feature.getFeatureElements()) {

                scenarioList = getScenarioWrapper(cucumberTagStatement, scenarioList);
            }
        }

        List<Object[]> newScenarioList = new ArrayList<>();
        for (CucumberScenarioWrapper scenarioWrapper : scenarioList) {
            newScenarioList.add(new Object[] { scenarioWrapper });
        }

        return newScenarioList.toArray(new Object[][] {});
    }

    /**
     * 
     * @param cucumberTagStatement
     * @param scenarioList
     * @return list of cucumber scenario wrapper
     */
    private List<CucumberScenarioWrapper> getScenarioWrapper(CucumberTagStatement cucumberTagStatement,
            List<CucumberScenarioWrapper> scenarioList) {
        if (cucumberTagStatement instanceof CucumberScenarioOutline) {
            for (CucumberExamples cucumberExamples : ((CucumberScenarioOutline) cucumberTagStatement)
                    .getCucumberExamplesList()) {
                for (CucumberScenario exampleScenario : cucumberExamples.createExampleScenarios()) {
                    CucumberScenarioWrapper scenarioWrapper = new CucumberScenarioWrapper(exampleScenario);
                    scenarioList.add(scenarioWrapper);
                }
            }
        } else {
            CucumberScenarioWrapper scenarioWrapper = new CucumberScenarioWrapper(
                    (CucumberScenario) cucumberTagStatement);
            if (!scenarioList.contains(scenarioWrapper)) {
                scenarioList.add(scenarioWrapper);
            }
        }
        return scenarioList;
    }

}