Protractor not wait for https.request callback - protractor

I hit a Protractor issue, if I run this within "ts-node demo.js" it works well and can output the response code and response body.
But if I run this in Protractor it block, then can't get the expected output response code and body, seems like Protractor won't wait for the callback.
In this situation, how can I output the response code and boday?
it(Check manifests V2 api, async() => {
const https = require('https')
const options = {
hostname: 'demo-quayecosystem-quay-quay.com',
port: 443,
path: '/v2/quay/multiarchdemo/manifests/latest',
method: 'GET',
headers: {
'Accept': 'application/vnd.docker.distribution.manifest.list.v2+json'
}
}
https.request(options, res => {
browser.getTitle().then(()=>{
console.log("starting.........");
console.log(`statusCode: ${res.statusCode}`)
res.on('data', d => {
process.stdout.write(d)
})
})
})
})

The function above is an async and when you make your function async, then you should use the await keyword in front of the https.request or return it like this.
return https.request...
And another thing that could lead to problems are...
https.request is making a direct HTTP request, without using a browser
broser.getTitle() is using the browser to interact with the web page.
Be aware - browser uses the browser, and http.request uses direct HTTP from node.js - these are two different things. And it will lead to unpredictable things to mix them. So consider if you want to "test as a user" and then use the browser, or if you want to do the fastest possible test and "test as a website or javascript" and use HTTP.request.
Try reading the async/await page on the Protractor website.
https://www.protractortest.org/#/async-await
If you are puzzled about async/await consider seeing the video from Fun Fun Function on promises https://www.youtube.com/watch?v=568g8hxJJp4&t=251s.

Related

Unable to make HTTP Post from custom Karma reporter

I need to publish my Karma test results to a custom REST API. To handle this automatically, I've written a custom Karma reporter. I'm trying to use the run_complete event so that the POST happens after all browsers finish. However, no HTTP call is being made.
I'm using Axios 0.19.2 to do the actual HTTP call, but the same thing happens with node-fetch. The tests are being run by the Angular cli via ng test. My Karma config is lengthy but other than having a million different reporters and possible browser configs, is pretty much standard.
This is my onRunComplete method:
self.onRunComplete = function () {
var report = ... ; // logic to generate a JSON object, not relevant
var url = '...'; // the endpoint for the request
try {
console.log('Sending report to ' + url);
axios.post(url, report, {headers: {'Content-Type': 'application/json'}})
.then(function(response) {
console.log('Success!');
console.log(response);
})
.catch(function(error) {
console.log('Failure!');
console.log(error);
});
} catch (err) {
console.log('Error!');
console.log(err);
}
}
At the end of the test run, it writes to console the 'Sending report to...' message, and then immediately ends. The server does not receive the request at all.
I also tried adding explicit blocking using a 'inProgress' boolean flag and while-loop, but that pretty much just leaves the entire test run hanging since it never completes. (Since the request is never made, the 'inProgress' flag is always true and we never hit the then/catch promise handlers or the catch block.)
I have verified that the Axios POST request works by taking the entire contents of the onRunComplete as shown here, putting it in its own JS file, and calling it directly. The report logs as expected. It's only when I call from inside of Karma that it's somehow blocked.
Since Karma's documentation pretty much boils down to "go read how other people did similar things!" I'm having trouble figuring out how to get this to work. Is there a trick to getting an HTTP request to happen inside of a custom reporter? Why does my implementation not work?
Looks like the post request is made asynchronously - that is the request is made and control resumes almost immediately to the method which completes... try instead:
self.onRunComplete = function () {
var report = ... ; // logic to generate a JSON object, not relevant
var url = '...'; // the endpoint for the request
try {
console.log('Sending report to ' + url);
await axios.post(url, report, {headers: {'Content-Type': 'application/json'}})
...
}
}

Atlassian Jira - 401 only when using query parameters

Currently working on a JIRA addon using the ACE framework. Executing a request using the integrated httpClient.
When I make a request such as this
https://instance.atlassian.net/rest/api/3/search
it works fine using the header Authorization: JWT <token> but when I run the same request with a query parameter like this
https://instance.atlassian.net/rest/api/3/search?maxResults=1
the request fails with a 401. I have confirmed that the JWT is not expired due to reverting the query parameters and seeing success again.
My atlassian-connect.json has scope READ as requested by the endpoint.
Any suggestions?
I was surprised that the rest call "rest/api/2/search?maxResults=1" worked. But it did when I was logged into my instance.
If I try that as JQL in Issue Search (maxResults=1), I get an invalid or unauthorized error message.
My instance is on premise (API V2). Yours appears to be in the cloud (V3). So it may be that the REST search works more like the Issue Search in V3 and is therefore returning the 401
It's a guess that should be easy to test... replace your maxResults=1 with some actual JQL or a filter ID and see if your results change
Since you're using ACE and utilizing httpClient, you might want to try the checkValidToken() route instead. The snippet below worked for me.
app.get('/mySearch', addon.checkValidToken(), function(req, res) {
var httpClient = addon.httpClient(req);
httpClient.get({
url: '/rest/api/3/search?maxResults=1',
headers: {
'X-Atlassian-Token': 'nocheck',
'Content-Type': 'application/json'
}
},
function (err, httpResponse, body) {
if (err) {
return console.error('Search failed:', err);
}
console.log('Search successful:', body);
});
});

Sails v1 new machine-based actions and custom responses

I'm in the middle of upgrading our API from Sails v0.12 -> v1, which was prompted by the use of self-validating machines for controller actions. After finally getting through a ton of headache replacing deprecated code, I've landed in a rough spot...
With v0.12 (rather, with the older "req, res" controller style), one could use custom response handlers across the board. I've taken advantage of this, and have request logging at the end of all our response types (with some additional sugaring of data). This was done to log all requests in the database, so we can get insights into what our production servers are doing (because they are load-balanced, having a central place to view this is a must, and this was an easy route to take).
So now, my problem is moving forward with "Actions2" machine-style actions. How does one use these custom response types in these things? Are we being forced to repeat ourselves in our exists? I can't find any good documentation to help guide this process, nor can I find a consistent way to "hook" into the end of a response using machines as actions. I can't find any documentation on what kind of options machines can give to Sails.
#Nelson yes, I understand that, but at the time, that isn't what I wanted at all. I wanted all of the benefits of Actions2.
EDIT: While the original, crossed-out comment below does still work, the prefered way to use Actions2 and the custom responses folder paradigm, is to do something similar to the following in an Actions2 file:
module.exports = {
friendlyName: 'Human-friendly name of function',
description: 'Long description of function and what it does.',
inputs: {
userCommand: {
type: 'string',
required: true,
description: 'Long, human-readable description of the input'
}
},
exits: {
success: {
responseType: 'chatbotResponse'
}
},
fn: async function(inputs, exits){
// do some crazy stuff with the inputs, which has already been validated.
return exits.success('Woot');
}
}
This ultimately will route through the responses/chatbotResponse.js, which looks something similar to this:
module.exports = async function chatbotResponse(data){
let res = this.res,
req = this.req;
if (!data) {
data = 'Something didn\'t go as planned...';
}
// how to call a Node Machine style helper with named inputs
await sails.helpers.finalizeRequestLog.with({req: req, res: res, body: {plainString: data}});
return res.json(data);
};
ORIGINAL:
As it turns out, in the Actions2 function, you just need to add the env param async function(inputs, exists, env). The env will give you access to the req and res. So, if you have custom responses, that perform special tasks (like request logging), you can just use return await env.res.customResponse('Hurray, you made a successful call!');

Grails REST plugin using HTTPBuilder for HTTPS

I have a service method in grails that was working fine.
It pulls a JSON via a GET request. After moving to prod we had to change the protocol to HTTPS and now I am getting an exception.
Is there anything I have to change to use the HTTPS protocol? I look all over The HTTPBuilder Documentation and I could not find a single reference to using HTTPS. I also could not find a example on Google.
def reportList = new ArrayList()
def result
//TODO Dynamic PatientKey
def http = new HTTPBuilder( 'https://mydomain/servicename?key=' + key )
reportList = null
http.request( GET, JSON ) { req ->
headers.Accept = 'application/json'
response.success = { resp, reader ->
reportList = reader.getAt("patientReports")
}
}
}
[ reportList : reportList ]
Whats the exception you are getting?
please check that SSL certificate is valid for the website. More here.
http://groovy.codehaus.org/modules/http-builder/doc/ssl.html
This Grails plugin solution works well in a test or local env because Same-Origin Policy will prevent you from implementing a front-end jQuery AJAX call since the domains are different.
In Prod, since HTTPS was used, and since the domains are the same, a jQuery AJAX call works much better then having the logic in the controller and using the REST plugin.
$.getJSON('${YOUR_URL}', function(data){ var yourData = data.yourData; //Operate on data here });

Origin is not allowed by Access-Control-Allow-Origin for HTTP DELETE

I currently playing around with the Facebook JavaScript SDK and the Scores API ( https://developers.facebook.com/docs/score/ ). I wrote a small application to save (post) scores and now I want to delete scores. Posting (saving) them works fine.
My code looks like this:
var deleteHighScoreUrl = 'https://graph.facebook.com/'+facebook.user.id+'/scores?access_token='+facebook.application.id+'|'+facebook.application.secret;
jQuery.ajax(
{
type: 'DELETE',
async: false,
url: deleteHighScoreUrl,
success: function(data, textStatus, jqXHR)
{
console.log('Score deleted.');
}
});
The "facebook" variable is an object that holds my application data. For HTTP POST it works fine but for HTTP DELETE I get the response "NetworkError: 400 Bad Request" in Firebug (with Firefox 10). I saw that Firefox first sends an HTTP OPTIONS (to see if it is allowed to use HTTP DELETE) which leads to this error so I tried the same thing with Google Chrome. Google Chrome sends a real HTTP DELETE which then returns:
"XMLHttpRequest cannot load
https://graph.facebook.com/USER_ID/scores?access_token=APP_ID|APP_SECRET.
Origin MY_DOMAIN is not allowed by Access-Control-Allow-Origin".
I think that this is a classical cross domain issue but how to solve it? I've added my domain to my facebook application (at https://developers.facebook.com/apps) and Facebook has a paragraph which is called "Delete scores for a user". So it must be possible to delete the scores (somehow)?
Because of Cross-Site-Scripting (XSS) a HTTP DELETE is not possible. But you can send a HTTP POST request with the query parameter ?method=delete, which then deletes the score.
Code Sample:
Facebook.prototype.deleteUsersHighScore = function()
{
var deleteHighScoreUrl = 'https://graph.facebook.com/'+this.user.id+'/scores?access_token='+this.application.id+'|'+this.application.secret+'&method=delete';
jQuery.ajax(
{
type: 'POST',
async: false,
url: deleteHighScoreUrl,
success: function(data, textStatus, jqXHR)
{
console.log('Score deleted.');
}
});
}
This is the Cross Domain security issue.
The fact that your error contains the message "Origin MY_DOMAIN" would tell me that somewhere in your code you have copied one of Facebook's examples but not changed the value for MY_DOMAIN to the correct domain you are using.
I would check all of your code for the value "MY_DOMAIN".
Please ignore this advice if you have changed the value to hide your actual domain in your question.