Search code examples
selenium-webdriverjunit5

Is there a way to pass parameter that changes its value with @RegisterExtension


I want to use @RegisterExtension in Junit5 to make screenshot on test failure. The driver quits after every test, and a new driver instance is created, but @RegisterExtension still uses the first driver instance, which is null. Is there a way to pass parameter, which changes with @RegisterExtension?

This is the test class:

import Test.OpenPageFactory;
import Test.TakeScreenshotOnFailure;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.openqa.selenium.WebDriver;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class Tests2 extends BaseTest {
    WebDriver driver = initializeBrowser("chrome");
    OpenPageFactory openPageFactory = new OpenPageFactory(driver);

    @RegisterExtension
    public TakeScreenshotOnFailure takeScreenshotOnFailure = new TakeScreenshotOnFailure(driver);

    @BeforeEach
    public void setUp() {
        if (driver.toString().contains("null")) {
            driver = initializeBrowser("chrome");
            openPageFactory = new OpenPageFactory(driver);
        }
    }

    @Test
    public void verifyAllLinksWithNotLoggedInUser() throws InterruptedException {
        openPageFactory.goToHomePage();
    }

    @Test
    public void negativeTestSignInWithInvalidData() throws Exception {
        openPageFactory.goToSignInPage();
    }

And this is the class, which is passed with @RegisterExtension:

import Test.BaseTest;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestWatcher;
import org.openqa.selenium.WebDriver;
import ru.yandex.qatools.ashot.AShot;
import ru.yandex.qatools.ashot.Screenshot;

import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;

public class TakeScreenshotOnFailure2 extends BaseTest implements TestWatcher {
    public WebDriver driver;

    public TakeScreenshotOnFailure2(WebDriver driver) {
        this.driver = driver;
    }

    @Override
    public void testFailed(ExtensionContext context, Throwable cause) {
        String screenShotName = context.getDisplayName();
        String screenShotPath = "\\screenshotPath.png";

        Screenshot screenshot = new AShot()
                .takeScreenshot(driver);
        try {

            ImageIO.write(screenshot.getImage(), "PNG", new File(screenShotPath));
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            driver.quit();
        }
    }

    @Override
    public void testSuccessful(ExtensionContext context) {
        driver.quit();
    }
}

I cannot understand why TakeScreenshotOnFailure2 class doesn't use the new instance of driver parameter.


Solution

  • Your problem is @TestInstance(TestInstance.Lifecycle.PER_CLASS). Since all tests run on the same instance of your test class, the extension is only registered once.

    If you go back to the standard PER_INSTANCE lifecycle, the extension should be instantiated for each test and thus the driver variable contain the appropriate web driver.