I’m currently looking at Botium Box, and I’m wondering if it is possible to send an additional request to our endpoint after each test case? Let me give you some background information about how we set up the HTTP(S)/JSON connector in Botium Box and how we are sending information to our bot:
HTTP(S) endpoint:
https://MyChatBotsEndpoint.com/?userinput={{msg.messageText}}
HTTP method: POST
We also send cookies through the header template in the request builder. Like this:
{
"Cookie": "JSESSIONID={{context.sessionId}}"
}
The response is given back in JSON.
When a test ends (when it is successful but also when it fails), we need to send an additional request to our endpoint. The endpoint URL of that request should look like this:
https://MyChatBotsEndpoint.com/endsession
The header should include the cookie as described before.
Is there a way to achieve this in Botium?
Botium has many extension points to plug in your custom functionality. In this case, I guess the SIMPLEREST_STOP_HOOK is the best choice.
Write a small javascript file calling your endpoint, and register is with the SIMPLEREST_STOP_HOOK capability in botium.json. The context (session context from the HTTP/JSON connector) is part of the hook arguments.
in botium.json:
...
"SIMPLEREST_STOP_HOOK": "my-stop-hook.js"
...
my-stop-hook.js:
const request = require('request')
module.exports = ({ context }) => {
return new Promise((resolve, reject) => {
request({
method: 'GET',
uri: 'https://MyChatBotsEndpoint.com/endsession',
headers: {
Cookie: "JSESSIONID=" + context.sessionId
}
}, (err) => {
if (err) reject(err)
else resolve()
})
})
}
Related
I'm trying to follow the example for developing a datasource plugin from Grafana. Ultimately I want my plugin to use Oauth, but even with just the basic Grafana datasource proxy example I seem to be having issues.
I have updated my plugin.json, class and constructor.
I have setup this hard coded example.
in plugin.json
{
"path": "grafana",
"url": "https://github.com"
}
],
And a sample testDataSource()
async testDatasource() {
return getBackendSrv()
.datasourceRequest({
url: this.url + '/grafana/grafana',
method: 'GET',
})
.then(response => {
if (response.status === 200) {
return { status: 'success', message: 'Data source is working', title: 'Success' };
} else {
return { status: 'failure', message: 'Data source is not working: ' + response.status, title: 'Failure' };
}
});
}
When I try and save/test this datasource to call that method, I get in the frontend a
HTTP Error Bad Gateway
And in the logs
t=2021-09-17T14:31:22+0000 lvl=eror msg="Data proxy error" logger=data-proxy-log userId=1 orgId=1 uname=admin path=/api/datasources/proxy/9/grafana/grafana remote_addr=172.17.0.1 referer=http://localhost:3000/datasources/edit/9/ error="http: proxy error: http: no Host in request URL"
I would've expected the request to be routed to the datasource proxy and for that to make the request to github but it seems Grafana is making a request to /api/datasources/proxy/9/grafana/grafana and nothing is picking it up?
Looking up my datasource via API, there's nothing listed for URL.
You will need to render this in your ConfigEditor.tsx
<DataSourceHttpSettings
defaultUrl="http://localhost:8080"
dataSourceConfig={options}
onChange={onOptionsChange}
/>
Which will give you the basic form with URL, whitelist, auth options that you see on most plugins. The URL there I guess should match what you have in your routes.
I had a small node server and I use the framework fastify.
In one of my routes, I want to get the data from a third party API.
I tried the following snippet:
fastify.route({
method: 'GET',
url: 'https://demo.api.com/api/v2/project/',
handler: async function ({ params, body}, reply) {
if (!body) return reply.send({ sucess: false })
console.log('testing')
console.log(body)
return reply.send({ sucess: true })
}
})
Unfortunately, I cannot call the URL by get because GET url's can only start with '/'.
How do i call a third pary api via fastify? do i need a extention?
If you need to define a route (like http://localhost:3000/) that proxies another server you need to use fastify-http-proxy.
Or if you need to call another endpoint and manage the response, there is the fastify.inject() utility but it is designed for testing.
Anyway, I think the best approach is to use some HTTP client like got
const got = require('got') // npm install got
fastify.get('/my-endpoint', async function (request, reply) {
const response = await got('sindresorhus.com')
console.log(response.body)
// DO SOMETHING WITH BODY
return { sucess: true }
})
Proxy your http requests to another server, with fastify hooks.
here is the example in fastify-http-proxy
server.register(require('fastify-http-proxy'), {
upstream: 'http://my-api.example.com',
prefix: '/api', // optional
http2: false // optional
})
https://github.com/fastify/fastify-http-proxy/blob/master/example.js
I mean functional or E2E testing. That's all clear with generic flows, but when it comes to transactional emails (signup confirmations, password resets, purchase notifications and others) it's still bringing questions. After some research I came up with a few ideas. One is to leverage Restmail.net API (here examples with Selenium WebDriver and Cypress - http://dsheiko.com/weblog/testing-sign-up-flow-with-activation-by-email). It's free, but API is public. So it's not really suitable for email messages with potentially sensitive information. Another approach to access Gmail inbox via IMAP bridge or Gmail API (here the explanation and code snippets - https://docs.puppetry.app/testing-emails/example-with-imap-bridge). But again, it's rather a workaround.
I know there are guys like Sendgrid, Mailgun, Email Yak, Postmark. I don't want to pay that much. So how do you folks do it? It it a thing to you?
We're doing this using Mailosaur email addresses for our test users. We then use a cypress custom command to query Mailosaur for the expected email. It was super easy to set up.
Here's the main part of that custom command, which is all we had to add to start doing email testing. You can refer to their API docs for what query, mailosaurServer, and MailosaurApiKey should be.
Cypress.Commands.add("getEmailFromMailService", query => {
return cy
.request({
method: "POST",
url: `https://mailosaur.com/api/messages/await?server=${mailosaurServer}`,
body: query,
headers: { "Content-Type": "application/json" },
auth: { user: mailosaurApiKey },
})
.then(response => {
expect(response.status).to.equal(200);
return response.body;
});
});
You could create a post request for the "forgot your password" and then assert on it.
something like:
cy.visit('yoursite')
cy.get('#forgotpassword').click().then(function (xhr) {
cy.server()
cy.request('POST', 'APIforForgotPassword').as('sucessfullemail)
})
cy.get(#sucessfullemail).then(function (xhr) {
expect(xhr.status).to.eq(200)
Cypress.Commands.add('ConfirmUser', () => {
const confirmationToken = null;
cy.request({
url: 'http://localhost:3000/api/confirmation_token?email=test_user#cypress.com',
followRedirect: false
})
.then((resp) => {
confirmationToken = resp.token
})
cy.visit('/en/confirmation?confirmation_token=token')
})
Create the API that requires the email as a parameter and returns the confirmation-token. call the API from cypress commands as ajax-request and get the response token
I need to retrieve all specified records from an api endpoint using http get request. The information what is the of total records available is in the X-Total response header.
I tried to retrieve the value of X-Total response header with one http request and then passing the value to another http get request as the value of X-Size header - this approach resulted in nested subscribe:
getTotalRecords () {
return this.http.get('http://localhost:4200/api/loans/marketplace?', {
headers: new HttpHeaders({
'X-Size': '1'
}),
params: new HttpParams().set('rating__eq', 'A').set('fields', 'rating,amount'),
observe: 'response'
})
};
getData() {
this.getTotalRecords().subscribe(data => {
this.http.get('http://localhost:4200/api/loans/marketplace?', {
headers: new HttpHeaders({
'X-Size': data.headers.get('X-Total')
}),
params: new HttpParams().set('rating__eq', 'A').set('fields', 'rating,amount'),
observe: 'response'
}).subscribe(data => {
console.log(data.body);
})
})
};
This works but it seems to me like there has to be a better way of doing this. Also I have this code directly in a component because I wasn't able to make a service out of it - I don't know how to return an observable if I have to subscribe to one to create the other.
Thank you
You can use concatMap to invoke the inner Observable and then share before returning the Observable to make sure you won't make multiple HTTP calls when making multiple subscriptions:
getData() {
return this.getTotalRecords().pipe(
concatMap(data => this.http.get(...)),
share(),
);
}
I am trying to load Behance project data via their API. Whether its localhost or prod, I am getting the following error --
Fetch API cannot load XXX. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:5000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Not sure how to solve for this.
My code in the Portfolio component below --
getPortfolio = () => {
const USER_ID = `XXX`,
PROJECT_ID = `XXX`,
API_KEY = `XXX`;
const BEHANCE_URL = `https://api.behance.net/v2/users/${USER_ID}/projects?client_id=${API_KEY}`;
console.log(BEHANCE_URL);
fetch(BEHANCE_URL, {
method: 'get',
dataType: 'jsonp',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then((response) => {
return response.json();
}).then((responseData) => {
return responseData;
}).catch((err) => {
return err;
});
}
UPDATE: Instead of fetch, using jQuery ajax works. --
$.ajax({
url: BEHANCE_URL,
type: "get",
data: {projects: {}},
dataType: "jsonp"
}).done((response) => {
this.setState({
portfolioData: response['projects']
});
}).fail((error) => {
console.log("Ajax request fails")
console.log(error);
});
This seems to have do less with React and more with Behance. What you are getting is a CORS error as you probably figured out. The short explanation is that CORS is a security measure put in on the browser so that websites cannot request other websites from the browser to appear to be the second website. It is a safety measure in place to protect from some phishing attacks.
CORS can be disabled by the server (in this case, Behance) but they decide not to, for legitimate reasons.
Behance would probably allow you to make the request you are trying to make from a server instead. Once you do that, you will need to get the information from your server to your React application, and you will be good to go!