mirror of
https://github.com/microsoft/playwright.git
synced 2024-11-10 12:57:42 +03:00
feat(selectors): add id selectors (#270)
This commit is contained in:
parent
8828228702
commit
48be99a56e
@ -6,8 +6,6 @@ import * as input from './input';
|
||||
import * as js from './javascript';
|
||||
import * as types from './types';
|
||||
import * as injectedSource from './generated/injectedSource';
|
||||
import * as cssSelectorEngineSource from './generated/cssSelectorEngineSource';
|
||||
import * as xpathSelectorEngineSource from './generated/xpathSelectorEngineSource';
|
||||
import * as zsSelectorEngineSource from './generated/zsSelectorEngineSource';
|
||||
import { assert, helper, debugError } from './helper';
|
||||
import Injected from './injected/injected';
|
||||
@ -38,10 +36,10 @@ export class FrameExecutionContext extends js.ExecutionContext {
|
||||
|
||||
_injected(): Promise<js.JSHandle> {
|
||||
if (!this._injectedPromise) {
|
||||
const engineSources = [cssSelectorEngineSource.source, xpathSelectorEngineSource.source, zsSelectorEngineSource.source];
|
||||
const additionalEngineSources = [zsSelectorEngineSource.source];
|
||||
const source = `
|
||||
new (${injectedSource.source})([
|
||||
${engineSources.join(',\n')}
|
||||
${additionalEngineSources.join(',\n')},
|
||||
])
|
||||
`;
|
||||
this._injectedPromise = this.evaluateHandle(source);
|
||||
@ -417,7 +415,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||
|
||||
function normalizeSelector(selector: string): string {
|
||||
const eqIndex = selector.indexOf('=');
|
||||
if (eqIndex !== -1 && selector.substring(0, eqIndex).trim().match(/^[a-zA-Z_0-9]+$/))
|
||||
if (eqIndex !== -1 && selector.substring(0, eqIndex).trim().match(/^[a-zA-Z_0-9-]+$/))
|
||||
return selector;
|
||||
if (selector.startsWith('//'))
|
||||
return 'xpath=' + selector;
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
import { SelectorEngine, SelectorRoot } from './selectorEngine';
|
||||
|
||||
const CSSEngine: SelectorEngine = {
|
||||
export const CSSEngine: SelectorEngine = {
|
||||
name: 'css',
|
||||
|
||||
create(root: SelectorRoot, targetElement: Element): string | undefined {
|
||||
@ -74,5 +74,3 @@ const CSSEngine: SelectorEngine = {
|
||||
return Array.from(root.querySelectorAll(selector));
|
||||
}
|
||||
};
|
||||
|
||||
export default CSSEngine;
|
||||
|
@ -1,32 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
const path = require('path');
|
||||
const InlineSource = require('./webpack-inline-source-plugin.js');
|
||||
|
||||
module.exports = {
|
||||
entry: path.join(__dirname, 'cssSelectorEngine.ts'),
|
||||
devtool: 'source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
transpileOnly: true
|
||||
},
|
||||
exclude: /node_modules/
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: [ '.tsx', '.ts', '.js' ]
|
||||
},
|
||||
output: {
|
||||
filename: 'cssSelectorEngineSource.js',
|
||||
path: path.resolve(__dirname, '../../lib/injected/generated')
|
||||
},
|
||||
plugins: [
|
||||
new InlineSource(path.join(__dirname, '..', 'generated', 'cssSelectorEngineSource.ts')),
|
||||
]
|
||||
};
|
@ -3,6 +3,31 @@
|
||||
|
||||
import { SelectorEngine, SelectorRoot } from './selectorEngine';
|
||||
import { Utils } from './utils';
|
||||
import { CSSEngine } from './cssSelectorEngine';
|
||||
import { XPathEngine } from './xpathSelectorEngine';
|
||||
|
||||
function createAttributeEngine(attribute: string): SelectorEngine {
|
||||
const engine: SelectorEngine = {
|
||||
name: attribute,
|
||||
|
||||
create(root: SelectorRoot, target: Element): string | undefined {
|
||||
const value = target.getAttribute(attribute);
|
||||
if (!value)
|
||||
return;
|
||||
if (root.querySelector(`[${attribute}=${value}]`) === target)
|
||||
return value;
|
||||
},
|
||||
|
||||
query(root: SelectorRoot, selector: string): Element | undefined {
|
||||
return root.querySelector(`[${attribute}=${selector}]`) || undefined;
|
||||
},
|
||||
|
||||
queryAll(root: SelectorRoot, selector: string): Element[] {
|
||||
return Array.from(root.querySelectorAll(`[${attribute}=${selector}]`));
|
||||
}
|
||||
};
|
||||
return engine;
|
||||
}
|
||||
|
||||
type ParsedSelector = { engine: SelectorEngine, selector: string }[];
|
||||
|
||||
@ -10,10 +35,18 @@ class Injected {
|
||||
readonly utils: Utils;
|
||||
readonly engines: Map<string, SelectorEngine>;
|
||||
|
||||
constructor(engines: SelectorEngine[]) {
|
||||
constructor(customEngines: SelectorEngine[]) {
|
||||
const defaultEngines = [
|
||||
CSSEngine,
|
||||
XPathEngine,
|
||||
createAttributeEngine('id'),
|
||||
createAttributeEngine('data-testid'),
|
||||
createAttributeEngine('data-test-id'),
|
||||
createAttributeEngine('data-test'),
|
||||
];
|
||||
this.utils = new Utils();
|
||||
this.engines = new Map();
|
||||
for (const engine of engines)
|
||||
for (const engine of [...defaultEngines, ...customEngines])
|
||||
this.engines.set(engine.name, engine);
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import { SelectorEngine, SelectorType, SelectorRoot } from './selectorEngine';
|
||||
const maxTextLength = 80;
|
||||
const minMeaningfulSelectorLegth = 100;
|
||||
|
||||
const XPathEngine: SelectorEngine = {
|
||||
export const XPathEngine: SelectorEngine = {
|
||||
name: 'xpath',
|
||||
|
||||
create(root: SelectorRoot, targetElement: Element, type: SelectorType): string | undefined {
|
||||
@ -175,5 +175,3 @@ function createNoText(root: SelectorRoot, targetElement: Element): string {
|
||||
|
||||
return '/' + steps.join('/');
|
||||
}
|
||||
|
||||
export default XPathEngine;
|
||||
|
@ -1,32 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
const path = require('path');
|
||||
const InlineSource = require('./webpack-inline-source-plugin.js');
|
||||
|
||||
module.exports = {
|
||||
entry: path.join(__dirname, 'xpathSelectorEngine.ts'),
|
||||
devtool: 'source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
transpileOnly: true
|
||||
},
|
||||
exclude: /node_modules/
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: [ '.tsx', '.ts', '.js' ]
|
||||
},
|
||||
output: {
|
||||
filename: 'xpathSelectorEngineSource.js',
|
||||
path: path.resolve(__dirname, '../../lib/injected/generated')
|
||||
},
|
||||
plugins: [
|
||||
new InlineSource(path.join(__dirname, '..', 'generated', 'xpathSelectorEngineSource.ts')),
|
||||
]
|
||||
};
|
@ -26,6 +26,26 @@ module.exports.addTests = function({testRunner, expect, product, FFOX, CHROME, W
|
||||
const idAttribute = await page.$eval('css=section', e => e.id);
|
||||
expect(idAttribute).toBe('testAttribute');
|
||||
});
|
||||
it('should work with id selector', async({page, server}) => {
|
||||
await page.setContent('<section id="testAttribute">43543</section>');
|
||||
const idAttribute = await page.$eval('id=testAttribute', e => e.id);
|
||||
expect(idAttribute).toBe('testAttribute');
|
||||
});
|
||||
it('should work with data-test selector', async({page, server}) => {
|
||||
await page.setContent('<section data-test=foo id="testAttribute">43543</section>');
|
||||
const idAttribute = await page.$eval('data-test=foo', e => e.id);
|
||||
expect(idAttribute).toBe('testAttribute');
|
||||
});
|
||||
it('should work with data-testid selector', async({page, server}) => {
|
||||
await page.setContent('<section data-testid=foo id="testAttribute">43543</section>');
|
||||
const idAttribute = await page.$eval('data-testid=foo', e => e.id);
|
||||
expect(idAttribute).toBe('testAttribute');
|
||||
});
|
||||
it('should work with data-test-id selector', async({page, server}) => {
|
||||
await page.setContent('<section data-test-id=foo id="testAttribute">43543</section>');
|
||||
const idAttribute = await page.$eval('data-test-id=foo', e => e.id);
|
||||
expect(idAttribute).toBe('testAttribute');
|
||||
});
|
||||
it('should work with zs selector', async({page, server}) => {
|
||||
await page.setContent('<section id="testAttribute">43543</section>');
|
||||
const idAttribute = await page.$eval('zs="43543"', e => e.id);
|
||||
|
@ -5,8 +5,6 @@ const child_process = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
const files = [
|
||||
path.join('src', 'injected', 'cssSelectorEngine.webpack.config.js'),
|
||||
path.join('src', 'injected', 'xpathSelectorEngine.webpack.config.js'),
|
||||
path.join('src', 'injected', 'zsSelectorEngine.webpack.config.js'),
|
||||
path.join('src', 'injected', 'injected.webpack.config.js'),
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user