Permalink
Browse files

feat(protractor): switch task lets you switch between popup windows

affects: serenity-js
  • Loading branch information...
jan-molak committed Jun 13, 2017
1 parent ead3374 commit fdedf8a85e597590ae4c46374a37cef0c72f0a48
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Non-Angular Popup</title>
</head>
<body>
<p>Yup, it's a pop-up!</p>
<input type="button" onclick="window.close()" value="Cool!" />
</body>
</html>
@@ -1,10 +1,10 @@
<!DOCTYPE html>
<html>
<html ng-app="demo">
<head>
<script src="/js/angular.min.js"></script>
<title>demo app</title>
</head>
<body ng-app="demo">
<body>
<section ng-controller="timeouts" id="timeouts" ng-cloak>
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html ng-app="windows">
<head>
<script type="text/javascript" src="/js/angular.js"></script>
<title>Popups</title>
</head>
<body>
<section id="windows" ng-controller="popup-windows">
<a ng-click="openPopup()">open a popup</a>
</section>
<script type="text/javascript">
angular.module('windows', [])
.controller('popup-windows', ['$scope', '$window', function ($scope, $window) {
var index = 1;
$scope.openPopup = function() {
$window.open("/popup.html", "popup-" + index++, "width=300,height=200");
}
}]);
</script>
</body>
</html>
@@ -0,0 +1,68 @@
import expect = require('../expect');
import { by, protractor } from 'protractor';
import { Actor, BrowseTheWeb, See, Switch, Target, UseAngular } from '../../src/screenplay-protractor';
import { Click, Open, Text } from '../../src/serenity-protractor';
import { AppServer } from '../support/server';
class Popup {
static Trigger = Target.the('pop up trigger').located(by.linkText('open a popup'));
static Text = Target.the('text of the pop-up').located(by.tagName('body'));
static Dismiss = Target.the('dismiss popup button').located(by.tagName('input'));
}
describe ('When demonstrating how to work with popup windows, a test scenario', function() {
this.timeout(10000);
const app = new AppServer();
const james = Actor.named('James').whoCan(BrowseTheWeb.using(protractor.browser));
before(app.start());
before(() => james.attemptsTo(Open.browserOn(app.demonstrating('popups'))));
after(app.stop());
it ('can switch to a newly opened popup window and back', () =>
james.attemptsTo(
Click.on(Popup.Trigger),
UseAngular.disableSynchronisation(),
Switch.toPopupWindow(),
See.if(Text.of(Popup.Text), text => expect(text).to.eventually.equal('Yup, it\'s a pop-up!')),
Click.on(Popup.Dismiss),
UseAngular.enableSynchronisation(),
Switch.toParentWindow(),
See.if(Text.of(Popup.Trigger), text => expect(text).to.eventually.equal('open a popup')),
));
it ('can switch to a specific window identified by its index', () =>
james.attemptsTo(
Click.on(Popup.Trigger),
Click.on(Popup.Trigger),
UseAngular.disableSynchronisation(),
Switch.toWindowNumber(2),
See.if(Text.of(Popup.Text), text => expect(text).to.eventually.equal('Yup, it\'s a pop-up!')),
Click.on(Popup.Dismiss),
Switch.toWindowNumber(1),
See.if(Text.of(Popup.Text), text => expect(text).to.eventually.equal('Yup, it\'s a pop-up!')),
Click.on(Popup.Dismiss),
UseAngular.enableSynchronisation(),
Switch.toParentWindow(),
See.if(Text.of(Popup.Trigger), text => expect(text).to.eventually.equal('open a popup')),
));
it ('complains when you try to switch to a popup that does not exist', () =>
expect(james.attemptsTo(
Switch.toPopupWindow(),
)).to.eventually.be.rejectedWith('No popup window was opened'));
});
@@ -12,6 +12,10 @@ var capabilities = {
build: process.env.BROWSERSTACK_AUTOMATE_BUILD,
project: process.env.BROWSERSTACK_AUTOMATE_PROJECT,
chromeOptions: {
args: ['--disable-infobars']
},
'browserstack.localIdentifier': process.env.BROWSERSTACK_LOCAL_IDENTIFIER,
'browserstack.local': true,
},
@@ -7,6 +7,8 @@ import { Target } from '../ui/target';
export class BrowseTheWeb implements Ability {
private parentWindow?: string;
/**
*
* Instantiates the Ability to BrowseTheWeb, allowing the Actor to interact with a Web UI
@@ -56,6 +58,23 @@ export class BrowseTheWeb implements Ability {
return this.browser.driver.manage();
}
switchToParentWindow(): PromiseLike<void> {
if (! this.parentWindow) {
throw new Error('This window does not have a parent');
}
return this.browser.switchTo().window(this.parentWindow);
}
switchToWindow(handle: (handles: string[]) => string): PromiseLike<void> {
return this.browser.getWindowHandle().then(currentWindow => {
this.parentWindow = currentWindow;
return this.browser.getAllWindowHandles().then(handles => {
return this.browser.switchTo().window(handle(handles));
});
});
}
sleep(millis: number): PromiseLike<void> {
return defer(() => this.browser.sleep(millis));
}
@@ -9,5 +9,6 @@ export * from './open';
export * from './resize_browser_window';
export * from './scroll';
export * from './select';
export * from './switch';
export * from './use_angular';
export * from './wait';
@@ -0,0 +1,34 @@
import { Interaction, UsesAbilities } from '@serenity-js/core/lib/screenplay';
import { BrowseTheWeb } from '../abilities/browse_the_web';
export class Switch {
static toParentWindow = (): Interaction => new SwitchToParentWindow();
static toWindowNumber = (index: number): Interaction => new SwitchToWindow((handles: string[]) => {
if (! handles[index]) {
throw new Error(`Can't switch to window ${index} as there are only ${handles.length}`);
}
return handles[index];
})
static toPopupWindow = (): Interaction => new SwitchToWindow((handles: string[]) => {
if (handles.length === 1) {
throw new Error('No popup window was opened');
}
return handles[handles.length - 1];
})
}
class SwitchToParentWindow implements Interaction {
performAs = (actor: UsesAbilities) => BrowseTheWeb.as(actor).switchToParentWindow();
}
class SwitchToWindow implements Interaction {
constructor(private handle: (handles: string[]) => string) {
}
performAs = (actor: UsesAbilities) => BrowseTheWeb.as(actor).switchToWindow(this.handle);
}

2 comments on commit fdedf8a

@marktigno

This comment has been minimized.

Show comment
Hide comment
@marktigno

marktigno Jun 15, 2017

Hello @jan-molak, this works well when I used this on testing pop-up windows on my end but I have a simple question here. Is there anyway to close the pop-up window before switching back to the parent? My implementation before this update came is using this code:

{
    protractor.browser.getAllWindowHandles().then(function(handles) {
    protractor.browser.switchTo().window(handles[handles.length - 1]).then(function() {
        //some implementing codes
    }),
    protractor.browser.close(), // <--this is what I mean
    protractor.browser.switchTo().window(handles[0])
}

marktigno replied Jun 15, 2017

Hello @jan-molak, this works well when I used this on testing pop-up windows on my end but I have a simple question here. Is there anyway to close the pop-up window before switching back to the parent? My implementation before this update came is using this code:

{
    protractor.browser.getAllWindowHandles().then(function(handles) {
    protractor.browser.switchTo().window(handles[handles.length - 1]).then(function() {
        //some implementing codes
    }),
    protractor.browser.close(), // <--this is what I mean
    protractor.browser.switchTo().window(handles[0])
}
@jan-molak

This comment has been minimized.

Show comment
Hide comment
@jan-molak

jan-molak Jun 15, 2017

Owner

Hey @marktigno - we'll need to add a task for that. Would you mind raising a ticket (or a PR ;-) )

Owner

jan-molak replied Jun 15, 2017

Hey @marktigno - we'll need to add a task for that. Would you mind raising a ticket (or a PR ;-) )

Please sign in to comment.