Cannot call method 'id' of undefined - protractor

My world.js looks like this:
var protractor = require('protractor');
var webdriver = require('selenium-webdriver');
var driver = new webdriver.Builder().usingServer('xxxxx').
withCapabilities(webdriver.Capabilities.firefox()).build();
driver.manage().timeouts().setScriptTimeout(100000);
module.exports.World = function World(callback) {
this.browser = protractor.wrapDriver(driver);
this.by = protractor.by;
callback();
};
then in steps.js:
{
element(by.id('username')).sendKeys("admin");
}
When I ran it using cucumber.js, the error is:
TypeError: Cannot call method 'id' of undefined
but if I remove world.js and run it using protractor, it works.
How can I fix this?

It looks like you're not exporting by globally. I'm not sure why you're able to use the element function at all - but in any case, you should probably be doing something like:
module.exports.World = function World(callback) {
global.browser = protractor.wrapDriver(driver);
global.by = protractor.by;
};

Related

Protractor test not recognizing global variable defined in onPrepare method within protractor.conf.js

I have defined a global variable within my protractor.conf.js file like this:
onPrepare() {
global.EC = protractor.ExpectedConditions;
}
I am attempting to access this variable within my protractor test like this:
navigateTo(url: string): LoginPage {
browser.get(url);
browser.wait(EC.urlIs(url), 2000);
return this;
}
However, my spec is not recognizing EC. The output log as well as the VS Code intellisense says
Cannot find name EC.
I haven't checked if there are differences in the way globals are exposed through protractor's config, but the way I use it and it works well in our test suite is like this
onPrepare: () => {
EC = protractor.ExpectedConditions;
DEFAULT_TIMEOUT = browser.params['timeout'];
if (!DEFAULT_TIMEOUT) {
DEFAULT_TIMEOUT = 60000;
}
chai = require('chai');
chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
expect = chai.expect;
...
}
So I don't use the "global" but expose directly and use it like this for example:
openCreateDialog() {
let createButton = $('.create-new');
browser.wait(EC.elementToBeClickable(createButton), DEFAULT_TIMEOUT);
createButton.click();
let dialog = new NewDialog();
dialog.waitUntilOpened();
return dialog.getCreatePanel();
}

SAPUI5 this.getView in attachRequestCompleted

I am loading data to my model and have a attachRequestCompleted attached. In there I want to set a value to one field, but it returns this.getView is not a function. This whole thing is inside a an interval:
My code looks like this:
var intervalId = setInterval(this.readRfid.bind(this), 3000);
readRfid: function() {
var oRfidModel = new sap.ui.model.xml.XMLModel();
oRfidModel.loadData("http://localhost/xxxxxxx");
oRfidModel.attachRequestCompleted(function() {
var reader = oRfidModel.oData.children["0"].children["0"].innerHTML;
this.getView().byId("objHdr_det_id1").setNumberUnit(reader);
});
Can I not use this.getView in the function? How can I make it work?
Thanks,
Tim
The this instance is not pointing to the Controller.
You probably need to bind a context to the callback function you've passed to the attachRequestCompleted.
As you can see here you can pass an oListener to this method.
I guess that something like:
var oRfidModel = new sap.ui.model.xml.XMLModel();
oRfidModel.loadData("http://localhost/xxxxxxx");
oRfidModel.attachRequestCompleted(function() {
var reader = oRfidModel.oData.children["0"].children["0"].innerHTML;
this.getView().byId("objHdr_det_id1").setNumberUnit(reader);
}, this);
Would work.
If this does not help you you can bind a context to the callback.

How to globally add a custom locator to Protractor?

I wrote a custom locator for Protractor that finds anchor elements by their ui-sref value. In my specs I just used by.addLocator to add the custom locator, but I figured this might be a cool thing to publish and have other people use it.
The goal is to add this custom locator to the global Protractor object so it can be used in any of your specs.
My initial approach was to add this functionality in the onPrepare block of the Protractor config. Something like the pseudocode below:
onPrepare: function () {
require('ui-sref-locator')(protractor); // The protractor object is available here.
}
That require statement would just execute this function:
function (ptorInstance) {
ptorInstance.by.addLocator('uiSref', function (toState, opt_parentElement) {
var using = opt_parentElement || document;
var possibleAnchors = using.querySelectorAll('a[ui-sref="' + toState +'"]');
var result = undefined;
if (possibleAnchors.length === 0) {
result = null;
} else if (possibleAnchors.length === 1) {
result = possibleAnchors[0];
} else {
result = possibleAnchors;
}
return result;
});
};
The problem is that by is not defined on the protractor object available in the onPrepare block. This means that I cannot use the .addLocator method.
Try the following:
function () {
by.addLocator('uiSref', function (toState, opt_parentElement) {
...
By should be in the global scope.
The protractor object passed to the onPrepare block has a By property. That By property has an inherited enumerable property named addLocator. My understanding of JavaScript is pretty shallow so it really threw me off that when I console.log'ed the protractor.By it returned {}, but if I did for (var propName in protractor.By) it would show me all the "hidden" properties. I'm still struggling to understand that bit.
Working code:
onPrepare: function () {
require('ui-sref-locator')(protractor); // The protractor object is available here.
}
The require would execute the function below:
function (ptor) {
ptor.By.addLocator('linkUiSref', function (toState, opt_parentElement) {
var using = opt_parentElement || document;
var possibleAnchors = using.querySelectorAll('a[ui-sref="' + toState +'"]');
var result = undefined;
if (possibleAnchors.length === 0) {
result = null;
} else if (possibleAnchors.length === 1) {
result = possibleAnchors[0];
} else {
result = possibleAnchors;
}
return result;
});
};

Unable to write to file with phonegap

Using the methods found on the phonegap api I'm trying to write to a file. This works in Android, but on an iOS device the writer is returning an error. Whenever I call writeFile() it returns an error, and the param passed into writeFail is -1. I cannot see why -1 is being passed into the error function, or why it's even failing to begin with. Has anyone else used the fileWriter on an iOS device, or can you see what I might be doing wrong?
function writeFile() {
var paths = navigator.fileMgr.getRootPaths();
var writer = new FileWriter(paths[0] + "write.txt");
writer.onwrite = writeSuccess;
writer.onerror = writeFail;
writer.write("some sample text");
// The file is now 'some sample text'
}
function writeSuccess() {
console.log("Write has succeeded");
}
function writeFail(evt) {
console.log(evt);
console.log(evt.target.error.code);
}
I had the same problem but I crawled through the mailing list and finally found the solution:
var writer = new FileWriter("write.txt");
This is it. Simply don't prepend the "Documents"-path. The documentation is wrong on that (still).
And don't forget to not use "readAsDataURL" as it would silently not work (on iOS). Hope I could help you.
If you want to write to a file this is the function(phonegap 2.5)
function fileWrite(filePath, text) {
var onFSWin = function(fileSystem) {
fileSystem.root.getFile(filePath, {create: true, exclusive: false}, onGetFileWin, onFSFail);
}
var onGetFileWin = function(fileEntry) {
fileEntry.createWriter(gotFileWriter, onFSFail);
}
var gotFileWriter = function(writer) {
writer.write(text);
}
var onFSFail = function(error) {
console.log(error.code);
}
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onFSWin, onFSFail);
}

Using DynamicActivityProperty as OutArgument in ActivityBuilder

Greetings,
I'm trying to create a workflow using a ActivityBuilder, and then get the XAML.
This flow use a custom activity (WaitForInput) to handle bookmarks. This class inherits from NativeActivity.
I'm having a hard time finding a way to set 'Result' property of my WaitForInput activity, which expects a OutArgument.
Creating this same workflow by the VS designer, I could associate the boolean property 'MyResult' InOutArgument called 'wrapper'. Like this : [Wrapper.MyResult]
I would do this by code, and according to my research, I have to use DynamicActivityProperty.
The problem is that I don't know how to use my DynamicActivityProperty as OutArgument in this case.
This is an simplified version of the code:
var wrapper = new DynamicActivityProperty
{
Name = "Wrapper",
Type = typeof(InOutArgument<CommunicationWrapper>),
};
var activityBuilder = new ActivityBuilder();
activityBuilder.Properties.Add(wrapper);
var step1 = new FlowStep
{
//here's my problem
Action = new WaitForInput<bool> { BookmarkName = "step1", Result = ??? }
};
var flow = new Flowchart
{
StartNode = step1,
Nodes = { step1 }
};
I have founded a solution to my own problem
Result = new OutArgument<bool>(new VisualBasicReference<bool>
{ ExpressionText = "Wrapper.MyResult" }); }