Skip to content

Commit

Permalink
transform all locators
Browse files Browse the repository at this point in the history
  • Loading branch information
christian-bromann committed Apr 14, 2021
1 parent 9973c9e commit 58cb7f5
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 35 deletions.
30 changes: 29 additions & 1 deletion protractor/constants.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,32 @@
exports.SUPPORTED_SELECTORS = ['id', 'model', 'css', 'binding', 'cssContainingText']
const { format } = require('util')

const UNSUPPORTED_SELECTOR_STRATEGY_ERROR = 'The selector "%s" is not supported, please consider refactor this line.'
exports.UNSUPPORTED_SELECTOR_STRATEGIES = {
binding: format(UNSUPPORTED_SELECTOR_STRATEGY_ERROR, 'by.binding'),
deepCss: 'WebdriverIO does not natively support deep CSS queries yet (https://github.com/webdriverio/webdriverio/issues/6709). We advise to use this plugin: https://github.com/Georgegriff/query-selector-shadow-dom.',
exactRepeater: format(UNSUPPORTED_SELECTOR_STRATEGY_ERROR, 'by.exactRepeater'),
repeater: format(UNSUPPORTED_SELECTOR_STRATEGY_ERROR, 'by.repeater'),
exactBinding: format(UNSUPPORTED_SELECTOR_STRATEGY_ERROR, 'by.exactBinding')
}

exports.SUPPORTED_SELECTORS = [
...Object.keys(exports.UNSUPPORTED_SELECTOR_STRATEGIES),
'id',
'model',
'css',
'className',
'cssContainingText',
'xpath',
'tagName',
'partialLinkText',
'name',
'js',
'linkText',
'options',
'buttonText',
'partialButtonText'
]

exports.ELEMENT_COMMANDS = [
'sendKeys',
'isPresent',
Expand Down
1 change: 1 addition & 0 deletions protractor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ module.exports = function transformer(file, api) {
root.find(j.ExpressionStatement)
.filter((path) => (
path.value.expression.callee &&
path.value.expression.callee.property &&
COMMANDS_TO_REMOVE.includes(path.value.expression.callee.property.name)
))
.replaceWith((path) => null)
Expand Down
83 changes: 50 additions & 33 deletions protractor/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { format } = require('util')
const {
IGNORED_CONFIG_PROPERTIES,
UNSUPPORTED_CONFIG_OPTION_ERROR,
UNSUPPORTED_SELECTOR_STRATEGIES,
REPLACE_CONFIG_KEYS,
IGNORED_CAPABILITIES
} = require('./constants')
Expand Down Expand Up @@ -33,49 +34,65 @@ class TransformError extends Error {
}

function getSelectorArgument (j, path, callExpr, file) {
const args = []
const bySelector = callExpr.callee.property.name
const arg = callExpr.arguments[0]

if (bySelector === 'id') {
args.push(j.literal(`#${callExpr.arguments[0].value}`))
if (Object.keys(UNSUPPORTED_SELECTOR_STRATEGIES).includes(bySelector)) {
throw new TransformError(
UNSUPPORTED_SELECTOR_STRATEGIES[bySelector],
path.value,
file
)
} else if (bySelector === 'id') {
return [j.literal(`#${arg.value}`)]
} else if (bySelector === 'model') {
args.push(j.literal(`*[ng-model="${callExpr.arguments[0].value}"]`))
return [j.literal(`*[ng-model="${arg.value}"]`)]
} else if (bySelector === 'css') {
args.push(...callExpr.arguments)
return [...callExpr.arguments]
} else if (bySelector === 'cssContainingText') {
const selector = callExpr.arguments[0]
const text = callExpr.arguments[1]

if (text.type === 'Literal') {
args.push(j.literal(`${selector.value}=${text.value}`))
} else if (text.type === 'Identifier') {
args.push(
j.binaryExpression(
'+',
j.literal(selector.value + '='),
j.identifier(text.name)
)
)
} else {
throw new TransformError('expect 2nd parameter of cssContainingText to be a literal or identifier', path.value, file)
if (text.type === 'Literal') {
return [j.literal(`${arg.value}=${text.value}`)]
} else if (text.type === 'Identifier') {
return [
j.binaryExpression(
'+',
j.literal(arg.value + '='),
j.identifier(text.name)
)
]
} if (text.regex) {
throw new TransformError('this codemod does not support RegExp in cssContainingText', path.value, file)
} else {
throw new TransformError('expect 2nd parameter of cssContainingText to be a literal or identifier', path.value, file)
}
} else if (bySelector === 'xpath' || bySelector === 'tagName' || bySelector === 'js') {
return [arg]
} else if (bySelector === 'linkText') {
return [j.literal(`=${arg.value}`)]
} else if (bySelector === 'partialLinkText') {
return [j.literal(`*=${arg.value}`)]
} else if (bySelector === 'name') {
return [j.literal(`*[name="${arg.value}"]`)]
} else if (bySelector === 'className') {
return [j.literal(`.${arg.value}`)]
} else if (bySelector === 'options') {
return [j.literal(`select[ng-options="${arg.value}"] option`)]
} else if (bySelector === 'buttonText') {
return [j.literal(`button=${arg.value}`)]
} else if (bySelector === 'partialButtonText') {
return [j.literal(`button*=${arg.value}`)]
}

if (text.regex) {
throw new TransformError('this codemod does not support RegExp in cssContainingText', path.value, file)
}
} else if (bySelector === 'binding') {
throw new TransformError('Binding selectors (by.binding) are not supported, please consider refactor this line', path.value, file)
} else {
// we assume a custom locator strategy
const selectorStrategyName = callExpr.callee.property.name
const selector = callExpr.arguments[0].value
args.push(
j.literal(selectorStrategyName),
j.literal(selector)
)
}

return args
// we assume a custom locator strategy
const selectorStrategyName = callExpr.callee.property.name
const selector = callExpr.arguments[0].value
return [
j.literal(selectorStrategyName),
j.literal(selector)
]
}

function matchesSelectorExpression (path) {
Expand Down
17 changes: 17 additions & 0 deletions test/__fixtures__/protractor/source/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,20 @@ $('body').allowAnimations(false);
var liDog = element(by.css('.dog')).getWebElement();
var liCat = liDog.getDriver().findElement(by.css('.cat'));
var lis = liDog.getDriver().findElements(by.css('li'));

var li = element(by.xpath('//ul/li/a'));
expect(element(by.tagName('a')).getText()).toBe('Google');
var doge = element(by.partialLinkText('Doge'));
var dog = element(by.name('dog_name'));
var wideElement = element(by.js(function() {
var spans = document.querySelectorAll('span');
for (var i = 0; i < spans.length; ++i) {
if (spans[i].offsetWidth > 100) {
return spans[i];
}
}
}));
expect(element(by.linkText('Google')).getTagName()).toBe('a');
var allOptions = element.all(by.options('c for c in colors'));
element(by.partialButtonText('Save'));
element(by.buttonText('Save'));
6 changes: 6 additions & 0 deletions test/__fixtures__/protractor/source/failing_selector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
expect(element(by.exactBinding('person.name')).isPresent()).toBe(true);
expect(element(by.exactBinding('person-email')).isPresent()).toBe(true);
expect(element(by.exactBinding('person')).isPresent()).toBe(false);
expect(element(by.exactBinding('person_phone')).isPresent()).toBe(true);
expect(element(by.exactBinding('person_phone|uppercase')).isPresent()).toBe(true);
expect(element(by.exactBinding('phone')).isPresent()).toBe(false);
17 changes: 17 additions & 0 deletions test/__fixtures__/protractor/transformed/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,20 @@ browser.$('.parent');
var liDog = $('.dog');
var liCat = liDog.parentElement().$('.cat');
var lis = liDog.parentElement().$$('li');

var li = $('//ul/li/a');
expect($('a').getText()).toBe('Google');
var doge = $("*=Doge");
var dog = $("*[name=\"dog_name\"]");
var wideElement = $(function() {
var spans = document.querySelectorAll('span');
for (var i = 0; i < spans.length; ++i) {
if (spans[i].offsetWidth > 100) {
return spans[i];
}
}
});
expect($("=Google").getTagName()).toBe('a');
var allOptions = $$("select[ng-options=\"c for c in colors\"] option");
$("button*=Save");
$("button=Save");
3 changes: 2 additions & 1 deletion test/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const frameworkTests = {
['./failing_unsupported.js'],
['./failing_evaluate.js'],
['./failing_getCssValue.js'],
['./failing_expectedConditions.js']
['./failing_expectedConditions.js'],
['./failing_selector.js']
]
}

Expand Down

0 comments on commit 58cb7f5

Please sign in to comment.