New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the capability to perform testing in multiple browser windows #912

Open
inikulin opened this Issue Oct 24, 2016 · 26 comments

Comments

@inikulin
Copy link
Collaborator

inikulin commented Oct 24, 2016

Are you requesting a feature or reporting a bug?

Feature

What is the current behavior?

You can run test only in single window of the browser

What is the expected behavior?

It's useful to run test in multiple windows to simultaneously observe results from different users perspective. E.g. we test online chat or online game. The idea is to spawn new windows in test and switch test context to that window (It also we'll play well with Roles feature):

test('Multi-window', async t => {
     await t
           .switchRole(user1)
           .click('#start-game')

           .switchToWindow(1)   // Spawns new browser window if it wasn't used before
           .switchRole(user2)
           .click('#start-game')
           .click('#shoot')

           .switchToWindow(0); // Return to default window

    expect(await healthbar.value).eql(0);   
});

The syntax is still a subject for bikeshedding. \cc @DevExpress/testcafe

@inikulin inikulin added this to the Planned features milestone Oct 24, 2016

@jakearchibald

This comment has been minimized.

Copy link

jakearchibald commented Oct 24, 2016

Is the as method above part of the proposal, or something existing?

Note that this may need to be two profiles rather than two windows. You may even want to test multiple windows of multiple profiles.

as(user1) would work pretty well if user1 were created with new BrowserProfile(). Since a new profile implicitly means new window, you wouldn't need switchToWindow until you wanted to support multiple windows within the same profile.

@inikulin

This comment has been minimized.

Copy link
Collaborator Author

inikulin commented Oct 24, 2016

Hi Jake.

Note that this may need to be two profiles rather than two windows. You may even want to test multiple windows of multiple profiles.

This is exactly what this function do, it's a part of upcoming Roles functionality.

Update: I've forgot that we decided to use switchRole() instead of as(). I'll edit the example in OP post.

@skogman

This comment has been minimized.

Copy link

skogman commented Jan 17, 2018

Is this still on the list? Multiple browser window support would be awesome for things like auth0/google authentication.
Btw, I love TestCafe <3

@Lukukas

This comment has been minimized.

Copy link

Lukukas commented Jan 17, 2018

I really like testcafe, but this is something I would need to successfully test my application. Our application opens multiple windows and uses them to pass data around. I would also be curious to know the timeline for this particular feature as I'm still in the process of selecting a UI automation framework.

@miherlosev

This comment has been minimized.

Copy link
Collaborator

miherlosev commented Jan 19, 2018

Hi @skogman and @Lukukas
Unfortunately, I cannot provide a strong timeline.
We have plans to investigate the possibility of multiple window testing in one of the nearest sprints. We will publish investigation results as soon as they appear.
At present, you can try this workaround for the 'Logging in via a social network' case.

@vvedachalam

This comment has been minimized.

Copy link

vvedachalam commented Aug 7, 2018

@AndreyBelym This issue was first addressed in Nov 2016... And its the feature thats going to add yet another feather to TC against Selenium. Waiting eagerly for this feature...

@amirse80

This comment has been minimized.

Copy link

amirse80 commented Oct 25, 2018

Hi, does TestCafe support this ".switchToWindow(1)" method?

I am getting "TypeError: t.switchToWindow is not a function"

@AndreyBelym

This comment has been minimized.

Copy link
Collaborator

AndreyBelym commented Oct 25, 2018

@amirse80, this method is not implemented yet.

Today I've found that Xiaomi Mi Browser creates a new tab every time it navigates to a different URL. It means that TestCafe won't work in Mi Browser until this feature is implemented.

@bkd705

This comment has been minimized.

Copy link

bkd705 commented Dec 27, 2018

Any update on this? Looking to test a live chat UI but unsure of how to do that without being able to have multiple instances of the browser running.

@AndreyBelym

This comment has been minimized.

Copy link
Collaborator

AndreyBelym commented Dec 29, 2018

@bkd705, I think this feature is not required if you want to test a live chat.

You can specify two browser instances when starting TestCafe:

testcafe chrome,chrome test.js

Then you can use the test context and conditional operators to perform different actions in different browsers:

const roles = [
    {
        name: 'User1',
        free: true, 
    },
    {
        name: 'User2',
        free: true, 
    },
];

fixture `fixture`
    .page `example.com`
    .beforeEach(async t => {
        const currentRole = roles.filter(role => role.free)[0];
        
        if (!currentRole)
            throw new Error('Found no free role');

        currentRole.free = false;
        t.ctx.roleName = currentRole.name;
    })

function actAsUser1 () {
    console.log('I am User1');
}

function actAsUser2 () {
    console.log('I am User2');
}
   
test('Do things', async t => {
    switch (t.ctx.roleName) {
        case 'User1': return actAsUser1();
        case 'User2': return actAsUser2();
        default:      throw new Error(`Unknown role name "${t.ctx.roleName}"`)
    }
});
@jsdevtom

This comment has been minimized.

Copy link

jsdevtom commented Jan 4, 2019

@AndreyBelym @miherlosev Thank you for your possible solutions. Unfortunately, this still isn't enough for my use case. I need to be able to test client synchronization (like google docs). Having different users act on the same page is not enough. Also how the application behaves offline will need to be tested. Any advice is appreciated 👍 🙏

@jsdevtom

This comment has been minimized.

Copy link

jsdevtom commented Jan 5, 2019

@bkd705 @inikulin The best solution that I have come up with is to use puppeteer for the other browser instance(s). Here is an example with the PageObject pattern:

test(`It should show the added question in the UI when the user adds a question
        in a different client`, async t => {
  const browser = await puppeteer.launch({ headless: false, ignoreHTTPSErrors: true });
  const page: Page = await browser.newPage();
  await page.goto('http://localhost:4200/login');
  const questionText = 'Does this work?';

  await t.expect(questionPage.dashboardQuestionCard.exists).notOk();

  await loginPage.loginWithPuppeteer(page, username, password);
  await questionPage.addQuestionPuppeteer(page, questionText, ['i hope so']);

  await t.expect(questionPage.dashboardQuestionCard.exists).ok();
  await t.expect(questionPage.dashboardQuestionCard.innerText).contains(questionText);
});
@rmkranack

This comment has been minimized.

Copy link

rmkranack commented Jan 18, 2019

Any updates on this? Our sites are moving over to Google SSO for authentication and we will no longer be able to use TestCafe if we cannot get past the authentication.

@LavrovArtem

This comment has been minimized.

Copy link
Collaborator

LavrovArtem commented Jan 21, 2019

@rmkranack
Currently, we are researching if there is some workaround. We will inform you once we get any information.

@LavrovArtem

This comment has been minimized.

Copy link
Collaborator

LavrovArtem commented Jan 22, 2019

@rmkranack,
I've created a simple example that shows how to authorize using Google SSO. Please try it and inform us of your results.

import { Selector, Role } from 'testcafe'

const signInButton = Selector('.abcRioButtonContentWrapper');
const googleAccUser = Role('https://google-developers.appspot.com/identity/sign-in/web/demos/signin_contextual_simple?hl=en', async t => {
    await t
        .click(signInButton)
        .typeText('input[type="email"]', '<your username>')
        .click('#identifierNext')
        .typeText('input[type="password"]', '<your password>')
        .click('#passwordNext')
        .wait(2000)
        .navigateTo('https://google-developers.appspot.com/identity/sign-in/web/demos/signin_contextual_simple?hl=en');
}, { preserveUrl: true });

fixture `Google Sign-In`
    .page`https://google-developers.appspot.com/identity/sign-in/web/demos/signin_contextual_simple?hl=en`

test('first test', async t => {
    await t
        .expect(signInButton.innerText).eql('Sign in')
        .useRole(googleAccUser)
        .expect(signInButton.innerText).eql('Signed in');
});

test('second test', async t => {
    await t
        .useRole(googleAccUser)
        .expect(signInButton.innerText).eql('Signed in');
});
@rmkranack

This comment has been minimized.

Copy link

rmkranack commented Jan 22, 2019

@LavrovArtem

This comment has been minimized.

Copy link
Collaborator

LavrovArtem commented Jan 23, 2019

@rmkranack,
Could you please provide me with your site url and test? I cannot help much without this information.

@rmkranack

This comment has been minimized.

Copy link

rmkranack commented Jan 23, 2019

@LavrovArtem

This comment has been minimized.

Copy link
Collaborator

LavrovArtem commented Feb 1, 2019

@rmkranack,
I apologize for the delayed response.

I've tried to rewrite my example to use your web site, but was not able to test it, as Google asks for a phone number for two-factor authentication. However, I have noticed that you did not change the page url and the role url in the code you provided. I suggest that you modify it as follows:

import { Selector, Role } from 'testcafe'

const googleAccUser = Role('https://coach-hub-ui-exos-coachhub.exos.biz/account/login', async t => {
    await t
        .click('button[class="btn mb-1 btn-primary btn-block"]')
        .typeText('input[type="email"]', 'exos.test@teamexos.com')
        .click('#identifierNext')
        .typeText('input[type="password"]', 'Changeme!')
        .click('#passwordNext')
        .wait(2000)
        .navigateTo('https://coach-hub-ui-exos-coachhub.exos.biz/');
}, { preserveUrl: true });

fixture `Google Sign-In`
    .page`https://coach-hub-ui-exos-coachhub.exos.biz/`

test('first test', async t => {
    await t
        .useRole(googleAccUser)
        .expect(Selector('div[class="page-header border-bottom"]').exists).ok();;
});
@rmkranack

This comment has been minimized.

Copy link

rmkranack commented Feb 1, 2019

@LavrovArtem

This comment has been minimized.

Copy link
Collaborator

LavrovArtem commented Feb 6, 2019

We do not have a recovery phone or email on this test account. It looks like Google blocked you. Should be okay now.

@rmkranack I'm still not able to test it as Google asks for a phone to validate your account. Try to increase the waiting time in the role before navigating to the home page.

"Verify it's you" screenshot

y2dujq28_oa

@rmkranack

This comment has been minimized.

Copy link

rmkranack commented Feb 6, 2019

@rmkranack

This comment has been minimized.

Copy link

rmkranack commented Feb 7, 2019

Just realized the recovery email didn't save. It is added now.

@LavrovArtem

This comment has been minimized.

Copy link
Collaborator

LavrovArtem commented Feb 12, 2019

@rmkranack,
Unfortunately, I could not find a workaround for your site to overcome the google authentication mechanism. At the moment, I'm out of ideas on how I may find a solution for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment