TestDataResolver.java

package io.github.giulong.spectrum.extensions.resolvers;

import io.github.giulong.spectrum.types.TestData;
import io.github.giulong.spectrum.utils.Configuration;
import io.github.giulong.spectrum.utils.ContextManager;
import io.github.giulong.spectrum.utils.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.support.TypeBasedParameterResolver;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

import static io.github.giulong.spectrum.extensions.resolvers.ConfigurationResolver.CONFIGURATION;
import static java.util.UUID.randomUUID;
import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.GLOBAL;

@Slf4j
public class TestDataResolver extends TypeBasedParameterResolver<TestData> {

    public static final String TEST_DATA = "testData";

    private final FileUtils fileUtils = FileUtils.getInstance();
    private final ContextManager contextManager = ContextManager.getInstance();

    @Override
    public TestData resolveParameter(final ParameterContext arg0, final ExtensionContext context) {
        log.debug("Resolving {}", TEST_DATA);

        final ExtensionContext.Store store = context.getStore(GLOBAL);
        final Configuration configuration = context.getRoot().getStore(GLOBAL).get(CONFIGURATION, Configuration.class);
        final Configuration.Extent extent = configuration.getExtent();
        final String reportFolder = extent.getReportFolder();
        final Class<?> clazz = context.getRequiredTestClass();
        final String className = clazz.getSimpleName();
        final String methodName = context.getRequiredTestMethod().getName();
        final String classDisplayName = fileUtils.sanitize(getDisplayNameOf(clazz));
        final String displayName = fileUtils.sanitize(joinTestDisplayNamesIn(context));
        final String testId = buildTestIdFrom(className, displayName);
        final String fileName = fileUtils.removeExtensionFrom(extent.getFileName());
        final Path screenshotFolderPath = getScreenshotFolderPathForCurrentTest(reportFolder, fileName, classDisplayName, displayName);
        final Path videoPath = getVideoPathForCurrentTest(configuration.getVideo().isDisabled(), reportFolder, fileName, classDisplayName, displayName);
        final TestData testData = TestData
                .builder()
                .className(className)
                .methodName(methodName)
                .classDisplayName(classDisplayName)
                .displayName(displayName)
                .testId(testId)
                .screenshotFolderPath(screenshotFolderPath)
                .videoPath(videoPath)
                .build();

        store.put(TEST_DATA, testData);
        contextManager.put(context, TEST_DATA, testData);
        return testData;
    }

    public static String buildTestIdFrom(final String className, final String testName) {
        return String.format("%s-%s", transformInKebabCase(className), transformInKebabCase(testName));
    }

    public static String getDisplayNameOf(final Class<?> clazz) {
        return clazz.isAnnotationPresent(DisplayName.class) ? clazz.getAnnotation(DisplayName.class).value() : clazz.getSimpleName();
    }

    public static String joinTestDisplayNamesIn(final ExtensionContext context) {
        final List<String> displayNames = new ArrayList<>();
        ExtensionContext currentContext = context;

        while (currentContext.getParent().orElseThrow().getParent().isPresent()) {
            displayNames.add(currentContext.getDisplayName());
            currentContext = currentContext.getParent().orElseThrow();
        }

        return String.join(" ", displayNames.reversed());
    }

    Path getScreenshotFolderPathForCurrentTest(final String reportsFolder, final String extentFileName, final String className, final String methodName) {
        return fileUtils.deleteContentOf(Path.of(reportsFolder, extentFileName, "screenshots", className, methodName).toAbsolutePath());
    }

    Path getVideoPathForCurrentTest(final boolean disabled, final String reportsFolder, final String extentFileName, final String className, final String methodName) {
        if (disabled) {
            log.trace("Video disabled: avoiding video folder creation");
            return null;
        }

        return fileUtils
                .deleteContentOf(Path.of(reportsFolder, extentFileName, "videos", className, methodName).toAbsolutePath())
                .resolve(String.format("%s.mp4", randomUUID()));
    }

    static String transformInKebabCase(final String string) {
        return string.replaceAll("\\s", "-").toLowerCase();
    }
}