Skip to content

Commit

Permalink
Merge pull request #32 from grawk/feature-jit-locale
Browse files Browse the repository at this point in the history
Feature jit locale
  • Loading branch information
nikulkarni committed Jun 10, 2015
2 parents 6048a23 + 9d9ea2b commit 6e0aff0
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 36 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# nemo-view changelog

## v1.2.0

* add realtime locale switching support (see https://github.com/paypal/nemo-view/issues/31)

## v1.1.0

* add new methods `[locatorName]TextEquals` and `[locatorName]AttrEquals` (see https://github.com/paypal/nemo-view/pull/29)
* add optional msg parameter to generic methods (see https://github.com/paypal/nemo-view/pull/28)

## v1.0.3

Change API to match `nemo@1.0`

## v0.3.2-beta

Add support for module based locators and path based locators. I.e. you can put locators into commonjs modules as well as into other directory structure
Expand Down
45 changes: 41 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -379,9 +379,46 @@ Other than that, the nemo-view uses nemo-locatex internally, so if you change yo
* value: the expected value for the element
* returns: Promise which resolves to true when the expected text matches

## Using LOCALE specific locators
## Using locator specialization

Please see these sections in the nemo-locatex README:
* https://github.com/paypal/nemo-locatex#changing-your-locator-files
* https://github.com/paypal/nemo-locatex#setting-locale
You can specify different locator strings/strategies based on the `data.locale` configuration value.
To do so, first modify the entry you wish to be specialized:

```js
{
"myLocator": {
"type": "css",
"locator": ".myLocator"
}
}
```

changes to

```js
{
"myLocator": {
"default": {
"type": "css",
"locator": ".myLocator"
},
"DE": {
"type": "css",
"locator": ".meinLocator"
}
}
}
```

You can set the `data.locale` property as follows:

```js
nemo._config.set('data:locale', 'DE');
```

For a working example, refer to the unit tests for the locale feature (found in `test/locale.js`) in this module.

_NOTE: This feature is a carry-over from earlier versions of nemo-view. It is understood now that the above feature does
not actually represent "locale" specificity as defined by bcp47 (https://tools.ietf.org/html/bcp47). See discussion
[here](https://github.com/paypal/nemo-view/pull/32) and issue [here](https://github.com/paypal/nemo-view/issues/33).
Follow along as we discuss a backwards compatible way to resolve this unfortunate nomenclature error.
11 changes: 4 additions & 7 deletions lib/locatex.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
'use strict';

module.exports = function (nemo) {
return function locatex(viewJSON, locatorArray) {
var locale = (nemo.data && nemo.data.locale) ? nemo.data.locale : 'default',
locatr = viewJSON;
locatorArray.forEach(function (level) {
locatr = locatr[level];
});
return locatr[locale] || locatr['default'] || locatr;
return function locatex(locatorJSON) {
var locale = nemo._config.get('data:locale') || 'default';
var localizedLocatorJSON = locatorJSON[locale] || locatorJSON['default'] || locatorJSON;
return localizedLocatorJSON;
};
};
49 changes: 30 additions & 19 deletions lib/locreator.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ var Drivex = require('selenium-drivex');
var Locatex = require('./locatex');
var _ = require('lodash');
var normalize = require('./normalize');
var debug = require('debug');
var log = debug('nemo-view:log');

var Locreator = function (nemo) {
log('creating Locreator instance');
this.nemo = nemo;
this.drivex = Drivex(nemo.driver, nemo.wd);
this.locatex = Locatex(nemo);
Expand All @@ -13,6 +16,7 @@ var Locreator = function (nemo) {
};
};
Locreator.prototype.addGenericMethods = function generics() {
log('adding generic methods');
var normify = this.normify;
var drivex = this.drivex;
var nemo = this.nemo;
Expand Down Expand Up @@ -44,56 +48,63 @@ Locreator.prototype.addGenericMethods = function generics() {
};
};

Locreator.prototype.addStarMethods = function locreator(locatorId, _locator, parentWebElement) {
Locreator.prototype.addStarMethods = function addStarMethods(locatorId, locatorJSON, parentWebElement) {
log('add star methods for %s', locatorId);
var locatorObject = {};
var drivex = this.drivex;
var locator = this.normify(_locator);
var locreator = this;
var locator = function () {
return locreator.normify(locreator.locatex(locatorJSON));
};

//this is an error check. if an error thrown, invalid locatorJSON.
locator();

locatorObject[locatorId] = function () {
return drivex.find(locator, parentWebElement);
return drivex.find(locator(), parentWebElement);
};
locatorObject[locatorId + 'By'] = function () {
return locator;
return locator();
};
locatorObject[locatorId + 'Present'] = function () {
return drivex.present(locator, parentWebElement);
return drivex.present(locator(), parentWebElement);
};
locatorObject[locatorId + 'Wait'] = function (timeout, msg) {
return drivex.waitForElementPromise(locator, timeout || 5000, msg);
return drivex.waitForElementPromise(locator(), timeout || 5000, msg);
};
locatorObject[locatorId + 'WaitVisible'] = function (timeout, msg) {
return drivex.waitForElementVisiblePromise(locator, timeout || 5000, msg);
return drivex.waitForElementVisiblePromise(locator(), timeout || 5000, msg);
};
locatorObject[locatorId + 'Visible'] = function () {
return drivex.visible(locator, parentWebElement);
return drivex.visible(locator(), parentWebElement);
};
locatorObject[locatorId + 'OptionText'] = function (optionText) {
return drivex.selectByOptionText(locator, optionText, parentWebElement);
return drivex.selectByOptionText(locator(), optionText, parentWebElement);
};
locatorObject[locatorId + 'OptionValue'] = function (optionValue) {
return drivex.selectByOptionValue(locator, optionValue, parentWebElement);
return drivex.selectByOptionValue(locator(), optionValue, parentWebElement);
};
locatorObject[locatorId + 'TextEquals'] = function (value) {
return drivex.validateText(locator, parentWebElement, value) ;
return drivex.validateText(locator(), parentWebElement, value) ;
};
locatorObject[locatorId + 'AttrEquals'] = function (attribute, value) {
return drivex.validateAttributeValue(locator, parentWebElement, attribute, value);
return drivex.validateAttributeValue(locator(), parentWebElement, attribute, value);
};
return locatorObject;
};

Locreator.prototype.addGroup = function (viewJSON, locator, locatorId) {
Locreator.prototype.addGroup = function (locatorId, locatorJSON) {
var nemo = this.nemo;
var drivex = this.drivex;
var locatex = this.locatex;
var self = this;
var locreator = this;
return function () { //give back the nemo.view.viewname.list() function
return drivex.finds(normalize(nemo, locator)).then(function (parentWebElements) {
var localizedJSON = locreator.locatex(locatorJSON);
return drivex.finds(locreator.normify(localizedJSON)).then(function (parentWebElements) {
return nemo.wd.promise.map(parentWebElements, function (parentWebElement) {
var parentObject = {};
Object.keys(viewJSON[locatorId].Elements).forEach(function (childLocatorId) {
var childLocator = locatex(viewJSON, [locatorId, 'Elements', childLocatorId]);
var starMethods = self.addStarMethods(childLocatorId, childLocator, parentWebElement);
Object.keys(localizedJSON.Elements).forEach(function (childLocatorId) {
var childLocatorJSON = localizedJSON.Elements[childLocatorId];
var starMethods = locreator.addStarMethods(childLocatorId, childLocatorJSON, parentWebElement);
_.merge(parentObject, starMethods);
});
return parentObject;
Expand Down
4 changes: 3 additions & 1 deletion lib/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ var _splitLocator = function (nemo, locatorString) {
*/
module.exports = function normalize(nemo, _locator) {
var locator = _locator;
var normalizedLocator;
if (_locator.constructor === String) {
locator = _splitLocator(nemo, _locator);
}
return nemo.wd.By[locator.type](locator.locator);
normalizedLocator = nemo.wd.By[locator.type](locator.locator);
return normalizedLocator;
};
8 changes: 4 additions & 4 deletions lib/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ var _ = require('lodash');

module.exports = function View(nemo, locreator, viewJSON) {
return _.transform(viewJSON, function (_viewObject, n, locatorId) {
var locator = locreator.locatex(viewJSON, [locatorId]);
if (viewJSON[locatorId].Elements) {
_viewObject[locatorId] = locreator.addGroup(viewJSON, locator, locatorId);
var locatorJSON = viewJSON[locatorId];
if (locreator.locatex(locatorJSON).Elements) {
_viewObject[locatorId] = locreator.addGroup(locatorId, locatorJSON);
} else {
_.merge(_viewObject, locreator.addStarMethods(locatorId, locator));
_.merge(_viewObject, locreator.addStarMethods(locatorId, locatorJSON));
}
});
};
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nemo-view",
"version": "1.1.0",
"version": "1.2.0",
"description": "View Interface for nemo views (requires nemo-drivex and nemo-locatex plugins)",
"main": "index.js",
"registerAs": "view",
Expand Down
73 changes: 73 additions & 0 deletions test/locale.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* global describe,before,after,beforeEach,it */
'use strict';

var Nemo = require('nemo'),
nemo = {},
path = require('path'),
assert = require('assert'),
util = require(path.resolve(__dirname, 'util'));

describe('nemo-view @locale@', function () {
before(function (done) {
nemo = Nemo({
plugins: {
view: {
module: 'path:../',
arguments: ['path:mocks/locale']
}
}
}, done);
});
after(function (done) {
nemo.driver.quit().then(done);
});
beforeEach(function (done) {
nemo.driver.get(nemo.data.baseUrl);
util.waitForJSReady(nemo).then(util.doneSuccess(done), util.doneError(done));
});
it('works for standard locators', function (done) {
nemo.view.form.text().getAttribute('id').then(function (idValue) {
assert.equal(idValue, 'foo_text');
nemo._config.set('data:locale', 'DE');
}).then(function () {
return nemo.view.form.text().getAttribute('id');
}).then(function (idValue) {
assert.equal(idValue, 'bar_text');
nemo._config.set('data:locale', '');
}).then(function () {
return nemo.view.form.text().getAttribute('id');
}).then(function (idValue) {
assert.equal(idValue, 'foo_text');
done();
});
});
it('works for Elements with inner locale scope', function (done) {
nemo.view.form.boxInnerLocale().then(function (elts) {
return elts[0].elt().getAttribute('type').then(function (typeValue) {
assert.equal(typeValue, 'text');
nemo._config.set('data:locale', 'DE');
return elts[0].elt().getAttribute('type');
});
}).then(function (typeValue) {
assert.equal(typeValue, 'button');
done();
});
});
it('works for Elements with outer locale scope', function (done) {
nemo._config.set('data:locale', null);
nemo.view.form.boxOuterLocale().then(function (elts) {
elts[0].elt().getAttribute('id').then(function (idValue) {
assert.equal(idValue, 'foo_text');
return true;
});
}).then(function (typeValue) {
nemo._config.set('data:locale', 'DE');
nemo.view.form.boxOuterLocale().then(function (elts) {
elts[0].elt().getAttribute('id').then(function (idValue) {
assert.equal(idValue, 'bar_text');
done();
});
});
});
});
});
38 changes: 38 additions & 0 deletions test/mocks/locale/form.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"text": {
"default": {
"locator": "#foo input.texty",
"type": "css"
},
"DE": {
"locator": "#bar input.texty",
"type": "css"
}
},
"boxInnerLocale": {
"locator": "#foo",
"type": "css",
"Elements": {
"elt": {
"default": "input.texty",
"DE": "[type=button]"
}
}
},
"boxOuterLocale": {
"default": {
"locator": "#foo",
"type": "css",
"Elements": {
"elt": "input.texty"
}
},
"DE": {
"locator": "#bar",
"type": "css",
"Elements": {
"elt": "input.texty"
}
}
}
}

0 comments on commit 6e0aff0

Please sign in to comment.