E2E tests for Confluence Cloud Addon

Hello!

I’m looking into adding some e2e tests for our Confluence Cloud addon. I cannot find any official guideline,. tips or tools to do it.

I’m curious on what people have done to solve this issue. Do people use tools like puppeteer and run against dev instances? Create mocks that imitates Confluence behavior?

1 Like

Hi Carlos

Did you find a way to do your e2e tests ? Did you use Selenium ? Robot ? HtmlUnit ? Other ?
Thanks
Laurent

We use Webdriver.io to run e2e tests against multiple Confluence Cloud sites (acceptance / production code).

Thanks Remie

Do you know if it is documented somewhere? Or may you have some examples or skeleton?
I always have some basic errors while opening the home page. I am using the tokenAPI, but I think I am missing something.

Also, additional question, why did you choose WebDriverIO over Selenium?
Regards
Laurent

In the end a lot of test frameworks are just abstraction layers. Webdriver.io can use both Selenium WebDriver protocol as wel as Puppeteer. They expose an API that felt easy to use, but there are lot of other frameworks available with other APIs that might fit better for you.

Given that e2e testing is not specific to Atlassian, there is no official documentation about it. What kind of pointers are you looking for?

Yeah, hopefully it is not specific to Atlassian :smile:

I tested HtmlUnit and WebdriverIO.
In HtmlUnit, this throws an exception in corejs (“TypeError: Cannot modify readonly property: constructor”)

WebClient client = new WebClient(BrowserVersion.FIREFOX);
client.addRequestHeader("user", "username+tokenAPI");
client.getOptions().setJavaScriptEnabled(true);
client.getOptions().setThrowExceptionOnFailingStatusCode(false);
client.waitForBackgroundJavaScript(30000);
page = client.getPage("https://laurent-ry.atlassian.net/wiki");

In WebdriverIO,
in wdio.conf, I put a before

    before: function(capabilities, specs, browser) {
        browser.url(chromeModHeader.getAddHeaderUrl("user", "username+APIToken"))
    },

And in a test file:

describe("Recording 17/10/2022 at 12:24:05", () => {
  it("tests Recording 17/10/2022 at 12:24:05", async () => {
    await browser.url("https://laurent-ry.atlassian.net/jira/your-work")
    await expect(browser).toHaveUrl("https://laurent-ry.atlassian.net/jira/your-work")
    await browser.$("aria/Create").click()
    await browser.$("#summary-field").setValue("qwerty")
    await browser.$("[data-testid=issue-create\\.common\\.ui\\.footer\\.create-button] > span").click()
  });
});

It fails with
Request failed with status 500 due to unknown error: unknown error: net::ERR_NAME_NOT_RESOLVED

So, any point to the really basics to get the first page with a token API is welcome.

Regards
Laurent

Euh yeah… well… we just log in with username/password :man_shrugging:

It’s difficult for me to share code as we have extended the browser with custom commands, but here is the logic for logging in. If you want to use it you will have to rewrite it to use default browser commands

export const loginToConfluence = async (username?: string, password?: string): Promise<void> => {
  const isLoggedIn = await browser.exists('#com-atlassian-confluence', false);
  if (!isLoggedIn && username && password) {
    await browser.setValue('#username', username);
    await browser.click('#login-submit', '#password');
    await browser.setValue('#password', password);
    await browser.click('#login-submit', '#com-atlassian-confluence');
  } else {
    return Promise.reject('Could not log in to Confluence, as the instance is not publicly avaiable and no credentials have been provided');
  }
}

Thanks.

I managed to have something with Java and Selenium.
I will try to post something here for next devs.

Now, I need to figure out for navigating in iframes.

Regards
Laurent

So, for posterity, this works with API token, BUT it does not handle well iframes.
If you use iframes, you need to use real login (with /wiki/login.action and fill the form)

Note: to use firefox with API token, you need to use a Proxy (see BrowserMobProxyServer examples)

private ChromeDriver getChromeDriver() {
        WebDriverManager.chromedriver().setup();

        ChromeOptions options = new ChromeOptions();
        options.setLogLevel(ChromeDriverLogLevel.WARNING);
        options.setHeadless(false); // or true if you want to hide browser

        ChromeDriver driver = new ChromeDriver(options);
        driver.setLogLevel(Level.WARNING);

        DevTools devTools = driver.getDevTools();
        devTools.createSession();

        devTools.send(Network.enable(Optional.of(1000000), Optional.of(1000000), Optional.of(1000000)));
        String token = "myemail:myapitoken";
        String encodedToken = Base64.getEncoder().encodeToString(token.getBytes(StandardCharsets.UTF_8));

        Map<String, Object> headers = Map.of("Authorization", "Basic " + encodedToken);
        devTools.send(Network.setExtraHTTPHeaders(new Headers(headers)));

        return driver;
    }
    private WebDriverWait getWaitDriver(RemoteWebDriver driver) {
        return new WebDriverWait(driver, Duration.ofSeconds(30), Duration.ofSeconds(1));
    }


@Test
void goToPage() {
            RemoteWebDriver driver = getChromeDriver();
            WebDriverWait wait = getWaitDriver(driver);

            driver.get("https://laurent-ry.atlassian.net/wiki");
            String pageTitle = driver.getTitle();

           // Click on a page in the side bar
            List<WebElement> elements = driver.findElements(By.xpath("//a[@aria-label='one page']"));
            WebElement webElement = elements.get(0);
            webElement.click();
            wait.until(webDriver -> webDriver.getTitle().equals("one page - PERF - Confluence"));
            pageTitle = driver.getTitle();

}
2 Likes