My framework contain common step definitions which calls from different feature files. I want to set the locators base on the step definition calls from feature file.
For example below Steps calling step Definition from common module.
A1.feature
Then I click on "Save" button
B2.feature
Then I click on "Save" button
Common step definition
const A1= require('../../../support/locators/A1-loc.cy')
const B2= require('../../../support/locators/B2-loc.cy')
Then ('I click on {string} button', (buttonName)=>{
clickOnButton(getButtonLocator(fromButtonNameAndFeatureFileName)
})
I want to choose the different locators for save button base on different feature file.
Means if A1.feature file calls then point to A1-loc.cy and if B2.feature file calls then points to B2-loc.cy
I dont know how to identify the calling feature file?
I know, how to identify the calling file? And below functions works perfectly well for the same. But calling from feature file, No idea. Kindly help me..:
module.exports._getCallerFile=()=> {
var filename;
var _pst = Error.prepareStackTrace
Error.prepareStackTrace = function (err, stack) { return stack; };
try {
var err = new Error();
var callerfile;
var currentfile;
currentfile = err.stack.shift().getFileName();
while (err.stack.length) {
callerfile = err.stack.shift().getFileName();
if(currentfile !== callerfile) {
filename = callerfile;
break;
}
}
} catch (err) {}
Error.prepareStackTrace = _pst;
console.log(filename)
return filename;
}
Why shouldn't you try to use different step text identifying from which feature file it's called?
For example, "Then I click on "Save" button from A feature"
Related
I am trying to listen for a javascript callback from a 3rd party app on my site. The app is minified so it is quite hard to reverse engineer. However, having used the Chrome debugger, the callback I want to capture is below, is there any way, I can trigger a function when that 'CollectEvent' callback is fired, with access to the 'email' variable? You can see in the console, that the callbacks are being created on the window, although of course they are named differently each time the code runs.
Recognising that I cannot edit that code directly as it is part of a 3rd party library.
!function() {
var _0x14bdc8 = {
'CollectEvent': function(_0x4a9e64, _0x3ac5b7) {
if (_0x4a9e64) {
_0x14bdc8[_0x304d('0xa7')] && (_0x30053a('COUPON_CODE_COOKIE_NAME', _0x4a9e64[_0x304d('0xd7')], 0x1),
_0x14bdc8[_0x304d('0x6a')]());
var _0x562cf7 = {
'shopId': _0x14bdc8[_0x304d('0xc2')],
'campaignId': _0x14bdc8[_0x304d('0x79')],
'email': encodeURIComponent(_0x4a9e64[_0x304d('0x23')]),
'code': _0x4a9e64['code'],
'customFields': encodeURIComponent(JSON[_0x304d('0x3')](_0x3ac5b7)),
'domain': window[_0x304d('0x73')][_0x304d('0x4a')],
'currentUrl': window[_0x304d('0x73')][_0x304d('0x6b')]
};
_0x14bdc8[_0x304d('0xa0')](_0x986b46 + '/api/wheelioapp/collectemail', _0x562cf7, function(_0xea4ea9) {
_0xea4ea9[_0x304d('0x89')] && _0x14bdc8[_0x304d('0x8f')](!0x1, !0x1, !0x0, !0x1);
});
} else
alert(_0x304d('0x80'));
},
...
}
}
You can see here the Wheelio app object in the console and the callbacks which have been created (although they have different names each session).
I just need to log it
Well, ok. We can't change functions created on-the-fly, but we can change other window functions.
For example we can use encodeURIComponent. See this line:
'email': encodeURIComponent(_0x4a9e64[_0x304d('0x23')]),
It means that somehow the email will go into the encodeURIComponent. Good, because we can read it there:
/* At the beginning */
// This is helper function, detects correct email:
function validateEmail(email) {
const re = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase());
}
// Keep old function
let oldEncodeURIComponent = window.encodeURIComponent;
// Crete new one
window.encodeURIComponent = (data) => {
if (validateEmail(data)) {
// Gotcha!
console.log('[encodeURIComponent]', data);
}
return oldEncodeURIComponent(data);
}
/* Here program works as normal, but creates lots of logs... */
/* In the end */
// If we can understand when we need to stop looking for email,
// we will disconnect our function:
window.encodeURIComponent = oldEncodeURIComponent;
So the idea is to read all data passing thru encodeURIComponent.
P.S. Email validator is here
I'm working on a Google Docs Add-On based on Google's Quickstart tutorial. I'm trying to change the workflow of the Add On in the tutorial to append a new page and then insert a translation on that new page rather than the line-by-line workflow.
I have a script working in single documents but I'm having a hard time moving it to the Add On architecture. I think it's something to do with passing selections from client-side JS to the server-side script doing the translation.
Here's the translate script
function translate(origin, dest, savePrefs) {
Logger.log('Starting the script');
if (savePrefs == true) {
var userProperties = PropertiesService.getUserProperties();
userProperties.setProperty('originLang', origin);
userProperties.setProperty('destLang', dest);
Logger.log(origin,dest);
}
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
// Add a page break for the translated material.
body.appendPageBreak();
// Get the number of elements in the document
var elements = body.getNumChildren();
Logger.log('Got the page elements');
// Use the number to loop through each element in the document.
for( var i=0;i<elements;i++) {
var element = body.getChild(i).copy();
var type = element.getType();
Logger.log('Element Types were successful. Starting tests.');
// Test each type for a child element and run script based on the result
// Images are nested in a paragraph as a child, so the second `if` makes
// sure there is no image present before moving to the next paragraph.
if( type == DocumentApp.ElementType.PARAGRAPH ){
if(element.asParagraph().getNumChildren() != 0 && element.asParagraph().getChild(0).getType() == DocumentApp.ElementType.INLINE_IMAGE) {
var img = element.asParagraph().getChild(0).asInlineImage().getBlob();
body.appendImage(img);
} else if(element.asParagraph().getNumChildren() !=0 && element.asParagraph().getChild(0).getType() == DocumentApp.ElementType.INLINE_DRAWING) {
var drawing = element.asParagraph().copy();
body.appendParagraph(drawing);
} else {
var text = element.asParagraph().getText();
Logger.log(text);
var spn = LanguageApp.translate(text, origin, dest);
body.appendParagraph(spn);
}
} else if(type == DocumentApp.ElementType.TABLE) {
element.asTable().copy();
body.appendTable(element);
} else if(type == DocumentApp.ElementType.LIST_ITEM) {
var list = element.asListItem().getText();
body.appendListItem(LanguageApp.translate(list, origin, dest));
}
}
The client-side JS is:
$(function() {
$('#run-translation').click(loadPreferences);
google.script.run(runTranslation)
});
function runTranslation() {
this.disabled = true;
var origin = $('input[name=origin]:checked').val();
var dest = $('input[name=dest]:checked').val();
var savePrefs = $('#save-prefs').is(':checked');
google.script.run
.runTranslation(origin, dest, savePrefs);
}
If I hard-code the languages to use in translation into the server-side script, it works. But as soon as I try to use variables from the radio buttons, it doesn't run. I don't see any errors in the console and I can't run scripts from the editor to check the logs. How can I debug this code?
Calling server-side functions from client Javascript
You've got a minor syntax error with google.run:
google.script.run(runTranslation)
It should be:
google.script.run
.withFailureHander(failFunc) // Optional
.withSuccessHander(succFunc) // Optional
.serverFunction(optionalParams...);
The two Handler methods assign callback functions from your client-side JavaScript to be invoked in the case of success or failure of the server-side function. In both cases, the client-side function is provided as the only parameter.
The server-side function you want to communicate with is presented as if it is a method itself, with optional parameters to be passed across the divide.
The simplest case for you is:
google.script.run
.translate(origin, dest, savePrefs);
(You had runTranslation in your posted code, but the server-side function is named translate()... I assume that's the right one.)
Now, this might will not take care of all your problems, so you wisely asked about debugging...
Debugging asynchronous client / server code in Google Apps Script
The provided debug environment isn't enough for debugging this sort of client / server exchange. There are also weaknesses in the Debugger for use with asynchronous execution - you can read more about that in Not seeing logs from onEdit trigger.
The simplest tool to get you debugging in this case would be to write logs to a spreadsheet
/**
* Write message and timestamp to log spreadsheet.
* From: https://stackoverflow.com/a/32212124/1677912
*/
function myLog( message ) {
var ss = SpreadsheetApp.openById( logSpreadsheetId );
var logSheet = ss.getSheetByName("Log") || ss.insertSheet("Log");
logSheet.appendRow([ new Date(), message );
}
You can call this from your client-side Javascript thusly:
google.script.run.myLog( "CLIENT: " + message );
That's a basic approach, but you can extend it more through use of utility functions and the BetterLog library. See more about that in my blog entry Did you know? (You can log to a spreadsheet from client JavaScript!)
I have written code that parses a dictionary returned from Firebase containing images encoded using base64. I want it to simply write these images to file, and it does, but I receive the following error after my writes finish:
smalloc.cc:280: void node::smalloc::SliceOnto(const v8::FunctionCallbackInfo<v8::Value>&): Assertion `end <= source_len' failed.
This is my code:
// Iterate through each key in each page if each request
for (var key in request) {
var obj = request[key];
if (typeof (obj) == "object") {
for (var prop in obj) {
item++;
if(obj.hasOwnProperty(prop)) {
switch (prop) {
case "img":
var media = new ReceivedMedia(obj[prop]);
var filename = transaction.tid + "-" + item + "." + media.extension;
filename = filename.slice(10);
require('fs').writeFileSync(filename, media.b64, 'base64', function(err) {
if (err) throw err;
});
break;
}
}
}
}
}
My images come out fine, but the error is a little weird and I would prefer to not to occur. Would anyone have an idea as to why this is happening? That would be super helpful :)
Note: ReceivedMedia is a class I defined as:
function ReceivedMedia(media) {
this.b64 = media.b64;
this.extension = media.extension;
this.posx = media.posx;
this.posy = media.posy;
}
Side question: If I use writeFile instead of writeFileSync one of my images is corrupted and the other contains no data. If after that happens I run my node script again, the files save correctly. I would also like some explanation as to why that happens, from my understanding one of these is synchronous (writeFileSync I am guessing) and the other is asynchronous (writeFile I am assuming).
A Google search for your error message description found this discussion of the issue in io.js and this discussion in node.js and it sounds like it is a bug that has been fixed (not sure if the fix has been released in a full build yet).
The node.js fix is here.
If you were desparate to fix it now in your own build, you'd have to apply the fix to your own code tree and rebuild it. Otherwise, you'll have to investigate or inquire when this fix will get into an official release (I'm not personally sure how that process works for node.js).
function gbid(s) {
return document.getElementById(s);
}
function GetData(cell,row) {
var excel = new ActiveXObject("Excel.Application");
var excel_file = excel.Workbooks.Open("Z:/SunCenter/Medicare Customer Experience/Hub/CaliforniaHUB/Plans/H0562_2013_082_EOC.xlsx");
var excel_sheet = excel.Worksheets("Sheet1");
gbid('span1').innerText = excel_sheet.Cells(1191,1).Value;
gbid('span2').innerText = excel_sheet.Cells(1192,1).Value;
gbid('span3').innerText = excel_sheet.Cells(1192,3).Value;
excel_file.Close()
excel.Quit()
}
Whenever the javascript runs (onload) it creates a process in the taskmanager/Processes. The problem is that it wont close it after use. When I run it again, it creates another one. Right now it's just pulling info from an excel file which is working just fine, but it just wont close the exe file in the taskmanager. I thought that excel_file.close would do it and I even put in another one, excel.quit, just in case. Sorry, I just wanted to make sure it worked. I've even taken one away now just in case of conflict but nada. Any help?
You need to call excel.Application.Quit(); instead of just excel.Quit();
According to Microsoft, because you're still holding a reference to excel when you call Quit(), Excel can't cleanly shut down. The recommendation is to call Quit(), set excel = null, then run CollectGarbage after a brief wait:
var idTmr = "";
function GetData() {
//...
excel.Quit();
excel = null;
idTmr = window.setInterval("Cleanup();",1);
}
function Cleanup() {
window.clearInterval(idTmr);
CollectGarbage();
}
Original sources:
http://support.microsoft.com/kb/266088
Windows 7 Gadget not releasing ActiveX object
Is there a way to get the ScriptNode that initiated a state in an Activiti workflow in Alfresco? I have a ScriptTask in my workflow, and it has a Alfresco Script Listener set up for the Start event. When the script is called, I'd like the ScriptNode that transitioned into the ScriptTask in the workflow to be passed as a parameter to the function defined as the listener. Is that possible?
Editing for clarity:
Here's a screenshot of Eclispe with the Activiti plugin.
http://i.imgur.com/DAKtq.jpg
This workflow gets started by another workflow with webscripts.
var props = new Object();
var dd = new Date();
props[EL_PROP_WORK_UNIT_NAME] = "testNode" + DateISOString( dd );
props[EL_PROP_WORK_UNIT_SOURCE_CODE] = "ROB";
props[EL_PROP_WORK_UNIT_DELIVERY_DATE] = dd;
node = getHome().createNode(name, EL_TYPE_WORK_UNIT, props);
var EL_WORKFLOW = "activiti$The-workflow";
var activeWfs = node.activeWorkflows;
if( activeWfs === null || activeWfs.length === 0 )
{
var workflowPackage = workflow.createPackage();
workflowPackage.addNode( node );
var workflowDef = workflow.getDefinitionByName(EL_WORKFLOW);
var workflowPath = workflowDef.startWorkflow( workflowPackage, new Object());
}
So the listener calls another javascript method...
function artPDFRename()
{
logger.log("==============================");
logger.log("<START> artPDFRename");
var workflowDef = workflow.getDefinitionByName(EL_WORKFLOW);
var activeInstance = workflowDef.getActiveInstances();
// ????
}
The goal is to have this handling be automatic. We're trying to design this with as little of manual intervention as possible, and are not assigning tasks to users to perform. Yes, there's probably another way to rename a PDF file, but I can't seem to figure out from the documentation listed here how to get a pointer to the node I put in the bpm_package object. That's the question.
Or am I so far off base on how we're developing this that it makes no sense?
As an example check the ScriptTaskListener class. Here all the workflow variables are put in a map.
The following code is interesting:
// Add all workflow variables to model
Map variables = delegateTask.getExecution().getVariables();
for (Entry<String, Object> varEntry : variables.entrySet())
{
scriptModel.put(varEntry.getKey(), varEntry.getValue());
}
So with this you could use bpm_package as an object within your script within the workflow script task.
So if you need the node were the workflow has run on, the following code should work (where task is your delegateTask from your notify method of the Listener:
delegateTask.getVariable("bpm_package");
// or like the example above
delegateTask.getExecution().getVariable("bpm_package");
This will be a list so take the first one and that will be your node.
---------update
If you're using the javascript from alfresco then you can directly use the parent object bpm_package.
So in your case it would be best to do the following:
var node = bpm_package.children[0]; //or you could check if the
package isn't null
// Then send the node into your
artPDFRename(node); //or you could just add the bpm_package code in
your js file