gratAttributeFrom() method is not returning value. It returns only object,promise - codeceptjs

How to get value using grabAttributeFrom in codecept. It returns only object,promise. How to get the attribute value from it.
let userid_xpath = await I.grabAttributeFrom("//div[#class='mat-form-field-infix']/input[contains(#id,'mat-input')]","id");
var userid = "//*[#id='"+userid_xpath+"']";
I.fillField(userid,"username")
If i use like above and execute the test, i dont get any error. but i saw the debug panel displays like below
Emitted | step.after (I grab attribute from "//mat-label[contains(text(),'UserId')]//ancestor::label//ancestor::span//ancest...
Emitted | step.before (I fill field "//*[#id='[object Promise]']", "username")
How to get the attribute value and use it in a string. If i pass the userid_xpath variable in assert ; it works. but my requirement is to pass it in a string and then use it.

Look carefully in documentation
It returns what it said to return.
Returns Promise<string> attribute value.
Communication between codeceptjs and browser asynchronous.
Codeceptjs looks for synchronisation of actions sent to browser. But it can't look for browser response, so you should manually tell for codeceptjs to wait for result.
In CodeceptJS such implementation is made by Promises
To get value from Promise you should await it by let userid_xpath = await I.grabAttributeFrom(someSelector);
But awaiting of Promise will end up execution due to inner implementation of Codeceptjs. So, as said in docs:
Resumes test execution, so should be used inside async with await operator.
mark you test function as async:
Scenario("should log viewability point, when time and percent are reached", async (I) => {
I.amOnPage(testPage);
const userid_xpath = await I.grabAttributeFrom("//div[#class='mat-form-field-infix']/input[contains(#id,'mat-input')]","id");
const userid = "//*[#id='" + userid_xpath + "']";
I.fillField(userid, "username")
});

Related

Twilio Flex - Send Call To IVR After Reject

Using this plugin as a reference, I have Flex configured to be able to send a call to a Twilio Studio IVR, after an agent has accepted a call.
I'd like to be able to send an incoming call back to Studio when an agent rejects a call (i.e. as soon as they click the reject button). I'm trying to do this by adding a listener to the plugin's init method:
flex.Actions.addListener("afterRejectTask", async (payload, abortFunction) => {
let url: string = payload.task.attributes.transferToIvrUrl;
let menu: string = 'hangup';
await request(url, { CallSid: payload.sid, menu });
});
See here for the full context -- I'm pretty much using that exact code, with the addition of this listener.
I'm getting this error message, and the call is not transferred anywhere.
twilio-flex.unbundled-react.min.js:1574 Error on afterRejectTask: SyntaxError: Unexpected token < in JSON at position 0
Here's additional context from the console, if that's helpful:
Additional info:
The url being requested is a Twilio function, which successfully returns a response like this:
<Response>
<Enqueue workflowSid="WWcc1a650e4175089538d754a6c2e15a98">
<Task>{"transferToIvrUrl": "https://my-twilio-function-service.twil.io/studio-flex-transfer-helper"}</Task>
</Enqueue>
</Response>
Any advice would be appreciated.
Ah, ok, so looking at that plugin I found the example Twilio Function that works with it. From what I can tell, this function is intended to be used in two places, either in Studio to transfer the call to Flex (though I'm not sure it's needed for that) or from Flex to transfer the call back to Studio. The thing that triggers the different response is whether you pass an argument called transferToIVRMenu with the request.
Your current request is not passing that argument, you currently have:
await request(url, { CallSid: payload.sid, menu });
which looks similar to the original plugin's request:
await request(transferToIvrUrl, { CallSid: call_sid, transferToIVRMenu });
The difference is in the second property in the object. When you just pass the name of the variable in an object, it expands to call the property the same name as the variable and set the value to the value within the variable. So the original request expands out to:
await request(transferToIvrUrl, { CallSid: call_sid, transferToIVRMenu: transferToIVRMenu });
but your request only expands to:
await request(url, { CallSid: payload.sid, menu: menu });
So you are passing a parameter called menu not transferToIVRMenu and that triggers the Function on the back end to return TwiML and not to update the call.
To fix this, you can update your plugin code to send the transferToIVRMenu parameter, like:
flex.Actions.addListener("afterRejectTask", async (payload, abortFunction) => {
let url: string = payload.task.attributes.transferToIvrUrl;
let menu: string = 'hangup';
await request(url, { CallSid: payload.sid, transferToIVRMenu: menu });
});

Access session value in gatling checks

I use gatling to send data to an ActiveMQ. The payload is generated in a separate method. The response should also be validated. However, how can I access the session data within the checks
check(bodyString.is()) or simpleCheck(...)? I have also thought about storing the current payload in a separate global variable, but I don't know if this is the right approach. My code's setup looks like this at the moment:
val scn = scenario("Example ActiveMQ Scenario")
.exec(jms("Test").requestReply
.queue(...)
.textMessage{ session => val message = createPayload(); session.set("payload", payload); message}
.check(simpleCheck{message => customCheck(message, ?????? )})) //access stored payload value, alternative: check(bodystring.is(?????)
def customCheck(m: Message, string: String) = {
// check logic goes here
}
Disclaimer: providing example in Java as you don't seem to be a Scala developper, so Java would be a better fit for you (supported since Gatling 3.7).
The way you want to do things can't possibly work.
.textMessage(session -> {
String message = createPayload();
session.set("payload", payload);
return message;
}
)
As explained in the documentation, Session is immutable, so in a function that's supposed to return the payload, you can't also return a new Session.
What you would have to do it first store the payload in the session, then fetch it:
.exec(session -> session.set("payload", createPayload()))
...
.textMessage("#{payload}")
Regarding writing your check, simpleCheck doesn't have access to the Session. You have to use check(bodyString.is()) and pass a function to is, again as explained in the documentation.

When is Microsoft Graph API finished calculating in Excel?

I can see how to trigger the calculation of a spreadsheet using Microsoft Graph API here...
https://learn.microsoft.com/en-us/graph/api/workbookapplication-calculate?view=graph-rest-1.0&tabs=http
But, when I pull the results from the calculations they don't seem to be updated. However, I pull a second or third time, it is usually updated.
I assume this means that calculation hasn't finished b/c of the size of the file or complexity of the calcs.
However, being asynchronous, I'm not finding any way to check to see when the calculations have finished.
Any idea how to do this?
UPDATE 1:
This is the code I'm (now) using to create the session (per #UJJAVAL123-MSFT)
var persistChanges = false;
var wrkbk = await graphClient.Me.Drive.Items[strItemId].Workbook
.CreateSession(persistChanges)
.Request()
.PostAsync();
This will give me a value for 'id' like this...
cluster=US5&session=15.SN3PEPF000074ED1.A82.1.V24.7737Nwad4oPuVafaO%2fpAkiay14.5.en-US5.en-US26.10037ffe965d2cf2-Unlimited1.A1.N16.16.0.12904.3505114.5.en-US5.en-US1.V1.N0.1.A&usid=1b230e8f-3bd0-cdaa-2da6-47db74154075
I'm not exactly sure how/where to use this, or whether I use the entire thing (it looks like a query string) or if I'm supposed to parse and pull out one of the values...
cluster=US5
session=15.SN3PEPF000074ED1.A82.1.V24.xxxxxxxxxxxxxxxxx%2fpAkiay14.5.en-US5.en-US26.10037ffe965d2cf2-Unlimited1.A1.N16.16.0.12904.3505114.5.en-US5.en-US1.V1.N0.1.A
usid=1b230e8f-3bd0-cdaa-2da6-xxxxxxxxxxxx
and this is the code i'm using to trigger the calculation, but not sure how to connect the two...
var calculationType = "FullRebuild";
await graphClient.Me.Drive.Items[strItemId].Workbook.Application
.Calculate(calculationType)
.Request()
.PostAsync();
Also, I'm seeing that it is possible to create, refresh and close a session, but not entirely sure how to check on a specific async process inside that session.
Here is the code I'm using to check a specific range for a value, not sure where we pass the session-id here either...
var result = await graphClient.Me.Drive.Items[strItemId].Workbook.Worksheets[strSheetName]
.Range(strRangeName)
.Request()
.GetAsync();
UPDATE 2:
I can run an API call (presumably) in the same session successfully by passing the workbook-session-id (which is the ENTIRE string shown above) and I get the expected 204 No Content response. However, it is not clear from the c# Code Snippet in the Microsoft Graph Explorer how to pass the workbook-session-id in the request.
Here is the code it provides...
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
await graphClient.Me.Drive.Items["{item-id}"].Workbook.Application
.Calculate(null)
.Request()
.PostAsync();
So the question remains, how can I do a PostAsync or GetAsync and reference the workbook-session-id?
This code does NOT give me an error...
await graphClient.Me.Drive.Items[strItemId].Workbook.Application
.Calculate(calculationType)
.Request()
.Header("workbook-session-id",wrkbk.Id)
.PostAsync();
So now, the question is WHEN do I get the workbook-session-id? Do I get it when I initially open the workbook and then pass it to every call?
You should create a session and pass the session Id with each request. The presence of a
session Id in the requests ensures that you are using the Excel API in the most efficient
way possible.
Check here for API call to get a session
So after a decent amount of testing, i figured it out.
The answer is that you use the CreateSession method (https://learn.microsoft.com/en-us/graph/api/workbook-createsession?view=graph-rest-1.0&tabs=http) to get the workbook info, and you set the persistChanges setting, then you get back info about the workbook session.
Like this...
using Microsoft.Graph;
// strItemId = the id from the microsoft graph api of the item
// strUserId = the id of the user from the microsoft graph api (note: must have permissions set correctly)
public static async Task<WorkbookSessionInfo> GetWorkbookSessionId(string strItemId, string strUserId)
{
// true = you can see changes in the workbook
// false = don't update the workbook, just do calculations
var persistChanges = true;
try
{
var wrkbk = await graphClient.Users[strUserId].Drive.Items[strItemId].Workbook
.CreateSession(persistChanges)
.Request()
.PostAsync();
var result = wrkbk;
return result;
}
catch (Exception ex)
{
Console.WriteLine($"Error getting items: {ex.Message}");
return null;
}
}
And you are returned a WorkbookSessionInfo object, which includes the SessionId for use in subsequent calls. This way, it keeps all your calls in the same session!
https://learn.microsoft.com/en-us/graph/api/resources/workbooksessioninfo?view=graph-rest-1.0

Cannot build up a string using StringBuffer and a server response

I'm trying to fetch data from this link via Dart. Since I'm making use of dart:io library's HttpClientResponse based instance to listen to the data obtained from the above link, therefore I thought that an instance of StringBuffer would be the best option to capture the received data. It would help me to build the response string in an incremental fashion. But it seems like I'm not making proper use of StringBuffer, because in the end the response string (stored in receivedBuffer) remains empty.
Code:
import 'dart:io';
import 'dart:convert';
void main() async
{
StringBuffer receivedBuffer = new StringBuffer("");
String url = "https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty";
HttpClient client = new HttpClient();
HttpClientRequest request = await client.getUrl(Uri.parse(url));
HttpClientResponse response = await request.close();
print("[info] Fetch successful. Proceeding to transform received data ...");
response.transform(utf8.decoder).listen((contents) => receivedBuffer.write(contents));
print("[info] Done. Contents:\n");
print(receivedBuffer);
}
Output :
[info] Fetch successful. Proceeding to transform received data ...
[info] Done. Contents:
Also, instead of receivedBuffer.write(contents), if I were to write print(contents), then all the
required data is printed as one would expect it to. But while trying to write the contents to recievedBuffer it seems like receivedBuffer wasn't even updated once.
I read this article, and tried to incorporate the answer present over there in my code. To be precise, I made use of Completer instance to take care of my issue, but it didn't help.
What's the issue in the above provided code?
You are not waiting for the stream to complete.
In the listen call, you set up a receiver for stream events, but you don't wait for the events to arrive.
You can either add an onDone parameter to the listen call and do something there, but more likely you will want to just wait for it here, and then I recommend:
await response.transform(utf8.decoder).forEach(receivedBuffer.write);
Using forEach is usually what you want when you are calling listen, but not remembering the returned subscription. Alternatively use an await for:
await for (var content in response.transform(utf8.decoder)) {
receivedBuffer.write(content);
}
(which corresponds to a forEach call in most ways).

FacebookRealtimeUpdateController Override Post and return 'OK'

Using Mvc.Facebook.Realtime the FacebookRealtimeUpdateController provides a process for handling user events (HandleUpdateAsync) , but not for page events.
Microsoft.AspNet.Mvc.Facebook.Realtime Namespace
I have managed to process page events by overriding the 'POST'
Public Overrides Function Post() As Task(Of Net.Http.HttpResponseMessage)
Dim content = Request.Content
Dim jsonContent As String = content.ReadAsStringAsync().Result
Dim ConvertedJson As RealTimeEvent = JsonConvert.DeserializeObject(Of RealTimeEvent)(jsonContent)
' Do something with the page events
Return MyBase.Post
End Function
However Facebook resends all events immediately , which I believe is because I am not returning a '200 OK' back to Facebook. (See quote)
First you'll need to prepare the page that will act as your callback URL. This URL will need to be accessible by Facebook servers, and be able to receive both the POST data that is sent when an update happens, but also accept GET requests in order to verify subscriptions.
This URL should always return a 200 OK HTTP response when invoked by Facebook.
I wiresharked my server and I do not see a 200 OK HTTP response, so I believe this something to do with the way I am overloading the post.
Can I somehow return an OK response from my overridden function or maybe it would be better to drop the whole Microsoft.AspNet.Mvc.Facebook.Realtime solution and just handle the Subscription GETs and Posts from facebook myself?
Update: I turned off "only my own code' and I can see an exception occurring in the AspNet.MVC.Facebook.dll.
So new question, How do I isolate this exception?
For others looking.
The issue was actually the HandleUpdateAsync function which must be overridden. This is fired after the 'Post'
If you don't return a valid task the exception is thrown inside AspNet.MVC.Facebook.dll and Facebook is never given a 200 OK.
I was using This blog on how to use the FacebookRealtimeUpdateController but in that version the 'HandleUpdateAsync' does not return a task and the processing is done in the function.
So by creating a task that does nothing , everything appears to be working fine.
Public Overrides Function HandleUpdateAsync(notification As ChangeNotification) As Task
Dim newtask As New Task(New System.Action(Sub()
Dim x As String = ""
End Sub))
Return newtask
End Function
Edit: But it creates a massive memory leak which cannot be cleared even with recycling..
So the real solution is to just create your own controller and forget the FacebookRealtimeUpdateController completely.
Very easy to do and saves allot of hassle!

Resources