diff --git a/.eslintignore b/.eslintignore index 28f6fcb632..39d2fd8648 100644 --- a/.eslintignore +++ b/.eslintignore @@ -9,4 +9,5 @@ node6-testrunner/* lib/ *.js src/chromium/protocol.d.ts -src/webkit/protocol.d.ts \ No newline at end of file +src/injected/injectedSource.ts +src/webkit/protocol.d.ts diff --git a/.gitignore b/.gitignore index 8d2eb40ef6..a378436416 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ package-lock.json yarn.lock /node6 /src/chromium/protocol.d.ts +/src/injected/injectedSource.ts /src/webkit/protocol.d.ts /utils/browser/playwright-web.js /index.d.ts diff --git a/package.json b/package.json index ce0dfdad43..f88ad41540 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,8 @@ "doc": "node utils/doclint/cli.js", "coverage": "cross-env COVERAGE=true npm run unit", "tsc": "tsc -p .", - "build": "tsc -p .", - "watch": "tsc -w -p .", + "build": "npx webpack --config src/injected/webpack-injected.config.js --mode='production' && tsc -p .", + "watch": "npx webpack --config src/injected/webpack-injected.config.js --mode='development' --watch --silent | tsc -w -p .", "apply-next-version": "node utils/apply_next_version.js", "bundle": "npx browserify -r ./index.js:playwright -o utils/browser/playwright-web.js", "test-types": "node utils/doclint/generate_types && npx -p typescript@2.1 tsc -p utils/doclint/generate_types/test/", @@ -62,7 +62,10 @@ "pixelmatch": "^4.0.2", "pngjs": "^3.3.3", "text-diff": "^1.0.1", - "typescript": "3.6.3" + "ts-loader": "^6.1.2", + "typescript": "3.6.3", + "webpack": "^4.41.0", + "webpack-cli": "^3.3.9" }, "browser": { "./lib/BrowserFetcher.js": false, diff --git a/src/chromium/ExecutionContext.ts b/src/chromium/ExecutionContext.ts index a3bad49c41..0af0df48c4 100644 --- a/src/chromium/ExecutionContext.ts +++ b/src/chromium/ExecutionContext.ts @@ -22,7 +22,7 @@ import { assert, helper } from '../helper'; import { valueFromRemoteObject, getExceptionMessage } from './protocolHelper'; import { createJSHandle, ElementHandle, JSHandle } from './JSHandle'; import { Protocol } from './protocol'; - +import { injectedSource } from '../injected/injectedSource'; export const EVALUATION_SCRIPT_URL = '__playwright_evaluation_script__'; const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m; @@ -30,6 +30,7 @@ const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m; export class ExecutionContext { _client: CDPSession; _world: DOMWorld; + private _injectedPromise: Promise | null = null; private _contextId: number; constructor(client: CDPSession, contextPayload: Protocol.Runtime.ExecutionContextDescription, world: DOMWorld | null) { @@ -159,4 +160,10 @@ export class ExecutionContext { }); return createJSHandle(this, object) as ElementHandle; } + + _injected(): Promise { + if (!this._injectedPromise) + this._injectedPromise = this.evaluateHandle(injectedSource); + return this._injectedPromise; + } } diff --git a/src/injected/injected.ts b/src/injected/injected.ts new file mode 100644 index 0000000000..fd3d27f817 --- /dev/null +++ b/src/injected/injected.ts @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +class Utils { + parentElementOrShadowHost(element: Element): Element | undefined { + if (element.parentElement) + return element.parentElement; + if (!element.parentNode) + return; + if (element.parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE && (element.parentNode as ShadowRoot).host) + return (element.parentNode as ShadowRoot).host; + } + + deepElementFromPoint(document: Document, x: number, y: number): Element | undefined { + let container: Document | ShadowRoot | null = document; + let element: Element | undefined; + while (container) { + const innerElement = container.elementFromPoint(x, y) as Element | undefined; + if (!innerElement || element === innerElement) + break; + element = innerElement; + container = element.shadowRoot; + } + return element; + } +} + +export const utils = new Utils(); diff --git a/src/injected/webpack-injected.config.js b/src/injected/webpack-injected.config.js new file mode 100644 index 0000000000..c59c042ffe --- /dev/null +++ b/src/injected/webpack-injected.config.js @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +const fs = require('fs'); +const path = require('path'); + +class InlineInjectedSource { + apply(compiler) { + compiler.hooks.emit.tapAsync('InlineInjectedSource', (compilation, callback) => { + const source = compilation.assets['injectedSource.js'].source(); + const newSource = 'export const injectedSource = ' + JSON.stringify(source) + ';'; + fs.writeFileSync(path.join(__dirname, 'injectedSource.ts'), newSource); + callback(); + }); + } +} + +module.exports = { + entry: path.join(__dirname, 'injected.ts'), + devtool: 'source-map', + module: { + rules: [ + { + test: /\.tsx?$/, + loader: 'ts-loader', + options: { + transpileOnly: true + }, + exclude: /node_modules/ + } + ] + }, + resolve: { + extensions: [ '.tsx', '.ts', '.js' ] + }, + output: { + filename: 'injectedSource.js', + path: path.resolve(__dirname, '../../lib/injected') + }, + plugins: [ + new InlineInjectedSource(), + ] +};