/
ProtractorBrowsingSession.ts
143 lines (115 loc) · 5.18 KB
/
ProtractorBrowsingSession.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import { CorrelationId } from '@serenity-js/core/lib/model';
import type { BrowserCapabilities } from '@serenity-js/web';
import { BrowsingSession } from '@serenity-js/web';
import type * as protractor from 'protractor';
import { ProtractorPage } from '../models';
import { promised } from '../promised';
import { ProtractorErrorHandler } from './ProtractorErrorHandler';
import { ProtractorModalDialogHandler } from './ProtractorModalDialogHandler';
/**
* Protractor-specific implementation of {@apilink BrowsingSession}.
*
* @group Models
*/
export class ProtractorBrowsingSession extends BrowsingSession<ProtractorPage> {
constructor(protected readonly browser: protractor.ProtractorBrowser) {
super();
}
override async allPages(): Promise<Array<ProtractorPage>> {
// scan all the active window handles and add any newly opened windows if needed
const windowHandles: string[] = await promised(this.browser.getAllWindowHandles());
// remove pages that are no longer open
const closedPageIds = this.registeredPageIds()
.filter(id => ! windowHandles.includes(id.value));
this.deregister(...closedPageIds);
// add any new pages that might have been opened (e.g. popup windows)
const registeredWindowHandles = new Set(this.registeredPageIds().map(id => id.value));
const newlyOpenedWindowHandles = windowHandles.filter(windowHandle => ! registeredWindowHandles.has(windowHandle));
for (const newlyOpenedWindowHandle of newlyOpenedWindowHandles) {
const errorHandler = new ProtractorErrorHandler();
this.register(
new ProtractorPage(
this,
this.browser,
new ProtractorModalDialogHandler(this.browser, errorHandler),
errorHandler,
new CorrelationId(newlyOpenedWindowHandle))
);
}
return super.allPages();
}
/**
* @param page
*/
override async changeCurrentPageTo(page: ProtractorPage): Promise<void> {
const currentPage = await this.currentPage();
// are we already on this page?
if (currentPage.id.equals(page.id)) {
return void 0;
}
// does the new page exist, or has it been closed in the meantime by user action, script, or similar?
if (! await page.isPresent()) {
return void 0;
}
// the page seems to be legit, switch to it
await promised(this.browser.switchTo().window(page.id.value));
// and update the cached reference
await super.changeCurrentPageTo(page);
}
private async activeWindowHandle(): Promise<string> {
try {
return await promised(this.browser.getWindowHandle());
}
catch (error) {
// If the window is closed by user action Protractor will still hold the reference to the closed window.
if (['NoSuchWindowError', 'no such window'].includes(error.name)) {
const allHandles = await promised(this.browser.getAllWindowHandles());
if (allHandles.length > 0) {
const handle = allHandles.at(-1);
await promised(this.browser.switchTo().window(handle));
return handle;
}
}
throw error;
}
}
override async currentPage(): Promise<ProtractorPage> {
const actualCurrentPageHandle = await this.activeWindowHandle();
const actualCurrentPageId = CorrelationId.fromJSON(actualCurrentPageHandle);
if (this.currentBrowserPage && this.currentBrowserPage.id.equals(actualCurrentPageId)) {
return this.currentBrowserPage;
}
// Looks like the actual current page is not what we thought the current page was.
// Is it one of the pages we are aware of?
const allPages = await this.allPages();
const found = allPages.find(page => page.id.equals(actualCurrentPageId));
if (found) {
this.currentBrowserPage = found;
return this.currentBrowserPage;
}
// OK, so that's a handle that we haven't seen before, let's register it and set as current page.
this.currentBrowserPage = await this.registerCurrentPage();
return this.currentBrowserPage;
}
protected override async registerCurrentPage(): Promise<ProtractorPage> {
const windowHandle = await this.browser.getWindowHandle();
const errorHandler = new ProtractorErrorHandler();
const page = new ProtractorPage(
this,
this.browser,
new ProtractorModalDialogHandler(this.browser, errorHandler),
errorHandler,
new CorrelationId(windowHandle)
);
this.register(page)
return page;
}
override async browserCapabilities(): Promise<BrowserCapabilities> {
const capabilities = await promised(this.browser.getCapabilities());
return {
platformName: capabilities.get('platform'),
browserName: capabilities.get('browserName'),
browserVersion: capabilities.get('version'),
};
}
}