There is 1 comment.
 
 
XWiki Platform / cid:jira-generated-image-avatar-1f92c535-e308-468a-8116-dd5a95ae7633 XWIKI-22272 Open

Add support for testing with multiple users/browsers

 
View issue   ยท   Add comment
 

1 comment

 
cid:jira-generated-image-avatar-933aee2e-9285-4eb7-a896-2e1094de232a Marius Dumitru Florea on 18/Jun/24 14:06
 

I tried to work around this problem by saving and restoring the cookies whenever we switch the browser tab:

/**
 * Open a new browser tab, after saving the authenticated user from the current tab (so that we can restore it when
 * switching back).
 *
 * @param setup the test setup
 * @return the handle of the new tab
 */
protected String openNewBrowserTab(TestUtils setup)
{
    // Save the authenticated user from the current tab before moving to the new tab in order to be able to restore
    // it later when we switch back to the current tab.
    saveAuthenticatedUser(setup);
    return setup.getDriver().switchTo().newWindow(WindowType.TAB).getWindowHandle();
}

/**
 * Switch to another (existing) browser tab, restoring its authenticated user (that was saved when the tab was
 * left).
 *
 * @param setup the test setup
 * @param tabHandle the tab to switch to
 */
protected void switchToBrowserTab(TestUtils setup, String tabHandle)
{
    // Save the authenticated user from the current tab before moving to the specified tab in order to be able to
    // restore it later when we switch back to the current tab.
    saveAuthenticatedUser(setup);
    setup.getDriver().switchTo().window(tabHandle);
    restoreAuthenticatedUser(setup);
}

private void saveAuthenticatedUser(TestUtils setup)
{
    WebDriver driver = setup.getDriver();
    String currentTabHandle = driver.getWindowHandle();
    this.cookiesByTab.put(currentTabHandle, driver.manage().getCookies());
    this.secretTokenByTab.put(currentTabHandle, setup.getSecretToken());
}

private void restoreAuthenticatedUser(TestUtils setup)
{
    WebDriver driver = setup.getDriver();
    String currentTabHandle = driver.getWindowHandle();
    driver.manage().deleteAllCookies();
    this.cookiesByTab.get(currentTabHandle).forEach(cookie -> driver.manage().addCookie(cookie));
    setup.setSecretToken(this.secretTokenByTab.get(currentTabHandle));
}

This worked fine for a simple test like this:

@Test
@Order(1)
void multiUser(TestUtils setup, TestReference testReference) throws Exception
{
    setup.loginAsSuperAdmin();
    setup.rest().savePage(testReference, "{{velocity}}XXX: $xcontext.userReference.name{{/velocity}}", "xwiki/2.1",
        "", "");
    ViewPage viewPage = setup.gotoPage(testReference);
    assertEquals("XXX: superadmin", viewPage.getContent());

    String secondTabHandle = openNewBrowserTab(setup);
    setup.createUserAndLogin("alice", "pass");
    viewPage = setup.gotoPage(testReference);
    assertEquals("XXX: alice", viewPage.getContent());

    switchToBrowserTab(setup, firstTabHandle);
    viewPage = setup.gotoPage(testReference);
    assertEquals("XXX: superadmin", viewPage.getContent());

    switchToBrowserTab(setup, secondTabHandle);
    viewPage = setup.gotoPage(testReference);
    assertEquals("XXX: alice", viewPage.getContent());
}

BUT it can't be used to test realtime editing with multiple users because: when you insert a rendering macro from the first tab (with the first user) the second tab (with the second user) receives this change while the first tab is still active, and this triggers a content refresh using CKEditor's HTMLConverter service which checks the CSRF token against the currently authenticated user. The second tab sends the CSRF token of the second user, but the currently authenticated user is the first user (because the first tab is still active). This cookie save / restore hack can be used only if the changes made in one tab don't trigger updates on the other tabs (especially updates that require a CSRF token).