@serenity-js/playwright
Version:
Adapter that integrates @serenity-js/web with Playwright, enabling Serenity/JS reporting and using the Screenplay Pattern to write component and end-to-end test scenarios
229 lines (228 loc) • 8.85 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.PlaywrightPage = void 0;
const node_url_1 = require("node:url");
const core_1 = require("@serenity-js/core");
const web_1 = require("@serenity-js/web");
const scripts = __importStar(require("@serenity-js/web/lib/scripts"));
const promised_1 = require("../promised");
const locators_1 = require("./locators");
const PlaywrightModalDialogHandler_1 = require("./PlaywrightModalDialogHandler");
const PlaywrightPageElement_1 = require("./PlaywrightPageElement");
/**
* Playwright-specific implementation of [`Page`](https://serenity-js.org/api/web/class/Page/).
*
* @group Models
*/
class PlaywrightPage extends web_1.Page {
page;
options;
lastScriptExecutionSummary;
/* eslint-disable unicorn/consistent-function-scoping */
dehydrator = new web_1.ArgumentDehydrator((item) => item instanceof web_1.PageElement, async (item) => {
const nativeElement = await item.nativeElement();
return nativeElement.elementHandle();
});
/* eslint-enable */
static current() {
return super.current();
}
constructor(session, page, options, pageId) {
super(session, new locators_1.PlaywrightRootLocator(page), new PlaywrightModalDialogHandler_1.PlaywrightModalDialogHandler(page), pageId);
this.page = page;
this.options = options;
}
createPageElement(nativeElement) {
return new PlaywrightPageElement_1.PlaywrightPageElement(new locators_1.PlaywrightExistingElementLocator(this.rootLocator, new web_1.ByDeepCss(nativeElement._selector), nativeElement));
}
locate(selector) {
return new PlaywrightPageElement_1.PlaywrightPageElement(new locators_1.PlaywrightLocator(this.rootLocator, selector));
}
locateAll(selector) {
return core_1.List.of(new web_1.PageElementsLocator(new locators_1.PlaywrightLocator(this.rootLocator, selector)));
}
async navigateTo(destination) {
await this.page.goto(destination, { waitUntil: this.options?.defaultNavigationWaitUntil });
await this.resetState();
}
async navigateBack() {
await this.page.goBack({ waitUntil: this.options?.defaultNavigationWaitUntil });
await this.resetState();
}
async navigateForward() {
await this.page.goForward({ waitUntil: this.options?.defaultNavigationWaitUntil });
await this.resetState();
}
async reload() {
await this.page.reload({ waitUntil: this.options?.defaultNavigationWaitUntil });
await this.resetState();
}
async sendKeys(keys) {
const keySequence = keys.map(key => {
if (!web_1.Key.isKey(key)) {
return key;
}
return key.devtoolsName;
});
await this.page.keyboard.press(keySequence.join('+'));
}
async executeScript(script, ...args) {
const serialisedScript = typeof script === 'function'
? String(script)
: String(`function script() { ${script} }`);
const executableScript = new Function(`
const parameters = (${scripts.rehydrate}).apply(null, arguments[0]);
return (${serialisedScript}).apply(null, parameters);
`);
const dehydratedArguments = await this.dehydrator.dehydrate(args);
const result = await this.rootLocator.evaluate(executableScript, dehydratedArguments);
this.lastScriptExecutionSummary = new LastScriptExecutionSummary(result);
return result;
}
async executeAsyncScript(script, ...args) {
const serialisedScript = typeof script === 'function'
? String(script)
: String(`function script() { ${script} }`);
const executableScript = new Function(`
const parameters = (${scripts.rehydrate}).apply(null, arguments[0]);
return new Promise((resolve, reject) => {
try {
return (${serialisedScript}).apply(null, parameters.concat(resolve));
} catch (error) {
return reject(error);
}
})
`);
const dehydratedArguments = await this.dehydrator.dehydrate(args);
const result = await this.rootLocator.evaluate(executableScript, dehydratedArguments);
this.lastScriptExecutionSummary = new LastScriptExecutionSummary(result);
return result;
}
lastScriptExecutionResult() {
if (!this.lastScriptExecutionSummary) {
throw new core_1.LogicError(`Make sure to execute a script before checking on the result`);
}
return this.lastScriptExecutionSummary.result;
}
async takeScreenshot() {
try {
const screenshot = await this.page.screenshot();
return screenshot.toString('base64');
}
catch (error) {
if (error?.message.includes('Target page, context or browser has been closed')) {
throw new web_1.BrowserWindowClosedError(`Couldn't take screenshot since the browser window is already closed`, error);
}
throw error;
}
}
async cookie(name) {
return this.session.cookie(name);
}
async setCookie(cookieData) {
const url = await this.page.url();
const cookie = {
name: cookieData.name,
value: cookieData.value,
domain: cookieData.domain,
path: cookieData.path,
url: !(cookieData.domain && cookieData.path) // eslint-disable-line unicorn/no-negated-condition
? url
: undefined,
secure: cookieData.secure,
httpOnly: cookieData.httpOnly,
expires: cookieData.expiry
? cookieData.expiry.toSeconds()
: undefined,
sameSite: cookieData.sameSite,
};
return this.session.setCookie(cookie);
}
async deleteAllCookies() {
await this.session.deleteAllCookies();
}
async title() {
const currentFrame = await this.currentFrame();
return currentFrame.title();
}
async name() {
const currentFrame = await this.currentFrame();
return currentFrame.evaluate(() => window.name);
}
async url() {
const currentFrame = await this.currentFrame();
return new node_url_1.URL(currentFrame.url());
}
async viewportSize() {
return this.page.viewportSize();
}
async setViewportSize(size) {
await this.page.setViewportSize(size);
}
async close() {
await this.resetState();
await this.modalDialogHandler.discard();
await this.page.close();
}
async closeOthers() {
await this.session.closePagesOtherThan(this);
}
isPresent() {
return (0, promised_1.promised)(!this.page.isClosed());
}
async nativePage() {
return (0, promised_1.promised)(this.page);
}
async resetState() {
this.lastScriptExecutionSummary = undefined;
await this.rootLocator.switchToMainFrame();
await this.modalDialogHandler.reset();
}
async currentFrame() {
return await this.rootLocator.nativeElement();
}
}
exports.PlaywrightPage = PlaywrightPage;
/**
* @package
*/
class LastScriptExecutionSummary {
result;
constructor(result) {
this.result = result;
}
}
//# sourceMappingURL=PlaywrightPage.js.map