I have a testcafe test that checks API response JSON for a matching string and no matter what is in the response JSON, the test always passed.
I am running Gherkin/Testcafe integration. Last "Then" step is to check an API response JSON body.
logger = RequestLogger(config.serverUrl + '/api/v1/service', {
logResponseHeaders: true,
logResponseBody: true,
});
await t
.addRequestHooks(logger)
.navigateTo(config.serverUrl + '/admin/integrations')
.expect(logger.contains(record => record.response.statusCode === 200))
.ok();
await t
.expect(
logger.contains(async record => {
// console.log(record.response.headers);
const body =
record.response.headers['content-encoding'] === 'gzip'
? await getBody(record.response.body)
: record.response.body.toString();
const bodyJson = JSON.parse(body);
return bodyJson.filter(node => node.title === "Devtest").length == 1;
})
)
.ok();
In the end, the code should return true/false depending on finding/not finding at least one item containing "Devtest".
However, the test always passes no matter what is the number.
RequestLogger doesn't support the async function for the predicate parameter of the containsfunction.
So, this expectation always passes - await t.expect(logger.contains(async record => false)).ok().
To fix the problem I suggest you split your code into two pars:
const record = request.records.find(r => ...);
const body = record.response.headers['content-encoding'] === 'gzip'
? await getBody(record.response.body)
: record.response.body.toString();
const bodyJson = JSON.parse(body);
await t.expect(bodyJson.filter(node => node.title === "Devtest").length === 1).ok();
I also see that the capability to automatically unzip response bodies can simplify your test code. If you have time you can try to implement this feature and open a pull request in the TestCafe repository.
Related
I have a cloudflare worker that will insert custom CSS into the page if the country is not U.S/Canada. This works perfectly, however - it will break all redirects when the CSS is inserted. Attached below is the worker scripts
addEventListener('fetch', event => {
event.passThroughOnException()
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const country = request.cf.country
if (country != 'US' && country !='CA') {
const response = await fetch(request)
const type = response.headers.get("Content-Type") || "";
if (!type.startsWith("text/html")) {
return response;
}
var html = await response.text()
// Inject scripts
const customScripts = 'styling here'
html = html.replace( /<\/body>/ , customScripts)
// return modified response
return new Response(html, {
headers: response.headers
})
}
}
The redirects are broken because they use a special HTTP status code (usually 301 or 302), but your Worker code is not copying the status code over to the final response, so the final response ends up always having a 200 status code.
Try changing this:
return new Response(html, {
headers: response.headers
})
To this:
return new Response(html, response)
This way, the new response copies over all of the properties of the old response, except for the body. This includes the status property, so the status code will be copied over.
By the way, unrelated to this problem, I notice another issue with your code:
if (country != 'US' && country !='CA') {
It looks like if this condition evaluates to false (that is, if country is either 'US' or 'CA'), then your handleRequest() function doesn't return a response at all. In this case, an exception will be thrown, and the client will see an 1101 error page. I recommend adding an else clause that returns the response that you want users in the US and Canada to see.
I use react-native-ble-plx in my project to communicante with my tool, and I'm trying to monitor one of its characteristics.
The result is rather long so the monitoringCharacteristic function is looping until it has send me everything, but I don't know how to be sure that the loop is done.
Here is my monitoring function :
const scanMyDevice = async (device) => {
const serviceUUID = '569a1-****'
const writeUUID = '569a2-****'
const readUUID = '569a2-****'
await device.discoverAllServicesAndCharacteristics()
await device.characteristicsForService(serviceUUID)
await device.writeCharacteristicWithResponseForService(serviceUUID, writeUUID, 'IzEwCg==')
var tempTrame = ''
const subscription = device.monitorCharacteristicForService(serviceUUID, readUUID, (error, a) => {
if (error) {
console.log(error)
console.log(error.message)
}
else {
tempTrame = tempTrame + base64.decode(a.value)
setTrameResult(tempTrame)
console.log('// INSIDE ///', tempTrame)
}
}, 'idMonitor')
return () => {
subscription.remove();
}
console.log('DONE')
}
In my code, 'DONE' is going to be printed before 'INSIDE trame'.
I tried to put console.log('DONE') inside the return, but then it was never printed.
I tried to put .then( console.log('DONE')) just before return but it sent me an error saying that it has nothing to do here...
Can someone help me please ?
Finally I went around the problem by defining an ending pattern to the info I wanted to send/read via BLE, and then I wrote a loop to continue reading while the ending pattern was not encountered:
let tempTrame = tempTrame + base64.decode(a.value)
let finalTrame = ''
// check if my variable has the end symbols (to be sure that I have all the information) and if it is the first time I get this information
if (tempTrame.includes('#109F')) {
stop = true
// suppress end symbols
tempTrame = tempTrame.replace(endTrame, '')
finalTrame = tempTrame
}
console.log(finalTrame)
I would like to know if I have a context variable like t.ctx.data, is there a way to get that to write the value of t.ctx.data to the TestCafe JSON reporter (or any reporter)?
My code:
// Called within Express.js by a request coming from req
const testMySite = (req, res) => {
process.env.PARAMS = JSON.stringify(req.body)
let testcafe = null;
console.log(`Running test on ports 1341 and 1342`)
createTestCafe('localhost', 1341, 1342, void 0, true)
.then(tc => {
testcafe = tc;
const runner = testcafe.createRunner()
return runner
.src(`${path.dirname(__filename)}/tests/gisTest.js`)
.browsers('firefox:headless')
.reporter('json', 'report.json')
.run()
})
.then(failedCount => {
testcafe.close()
})
res.json({message: `Success! Scraper has begun to process ${req.body}`});
}
My test code:
import { ClientFunction, Selector } from 'testcafe';
const doc = process.env.PARAMS
const newDoc = JSON.parse(process.env.PARAMS)
console.log(`newDoc (from test)`, newDoc)
// const _id = newDoc._id
let data = newDoc.mydata
fixture `My Fixture`
.page('https://www.mysite.co')
.afterEach(async t => {
await t
// how do I get t.ctx.myData into the reporter??
console.log(`t.ctx.myData: `, t.ctx.myData)
})
test(`My Test`, async t => {
const photoIcon = Selector('div#sbtc div.LM8x9c > span')
const photoFieldForPaste = Selector('input#Ycyxxc')
const searchByImageButton = Selector('td#aoghAf > input')
const targetElement = Selector('div#jHnbRc span:nth-child(2) > a')
await t
.wait(1000)
.click(photoIcon)
.typeText(photoFieldForPaste, data, {paste: true})
.click(searchByImageButton)
if(await targetElement.exists && await targetElement.visible) {
await t.ctx.finalData = targetElement.innerText;
}
await t.ctx.finalData = null;
})
Please see the part // how do I get t.ctx.myData into the reporter??.
I am assuming this is the only place where I could potentially get the data from the test into the reporter but I'm not sure exactly how.
If you know how to get the t.ctx.myData variable as shown in the above code to be written to the JSON reporter, I would highly appreciate it.
Even better would be to have a way to send the t.ctx.myData value into the response.
At present, you can add only static metadata to tests and fixtures. This metadata is available in reports. Please refer to the following article to get details: https://devexpress.github.io/testcafe/documentation/guides/basic-guides/organize-tests.html#specify-test-metadata
As for sending dynamic data to the reporter, we keep this feature in mind, however we cannot give any estimates on this. Please track the following issue: https://github.com/DevExpress/testcafe/issues/3584
I'm currently creating a library for an API. The endpoints have optional tags, and so I'm trying to create a way to use them in the functions.
import * as request from "request";
class Api {
key: string;
constructor(userInput: string) {
this.key = userInput;
}
champions(tags: object) {
Object.keys(tags).forEach(function(key) {
console.log(key + " = " + tags[key])
})
request(`https://api.champion.gg/v2/champions?api_key=${this.key}&${tags}`, function (error, response, body) {
if(!error && response.statusCode == 200) {
let info = JSON.parse(body)
}
});
}
}
var test = new Api("key")
test.champions({"champData": ["kda", "damage"], "rawr": ["xd", "lmao"]})
So far, the combining of Object.keys and forEach has allowed me to get the response of champData=kda,damage and rawr=xd,lmao, however, I need to be able to assign these to a variable that's usable in the URL. How can I get this to work?
Another issue that may occur later on is that, between each tag, there needs to be an & symbol, but not at the end. I apologize for throwing multiple problems into one, but because this is my first experience with something like this, I'm having many issues.
You can use Object.entries() and URLSearchParams()
const tags = {a:1, b:2, c:3};
const params = new URLSearchParams();
const key = "def";
Object.entries(tags).forEach(([key, prop]) => params.set(key, prop));
const url = `https://api.champion.gg/v2/champions?api_key=${key}&${params.toString()}`;
console.log(url);
I have a phantomJS script that contains the following:
page.open(url, function (status) {
if (status === "fail") { /* handle failure */ }
});
The status check works sometimes, but the status will still be "success" even if the request returns 500. How can I get the actual request status code?
You can do it something like this:
var page = require('webpage').create(),
system = require('system'),
resources = [];
page.open('http://google.com', function (status) {
console.log('Loaded with http status:', resources[0].status);
phantom.exit();
});
page.onResourceReceived = function(response) {
// check if the resource is done downloading
if (response.stage !== "end") return;
// apply resource filter if needed:
if (response.headers.filter(function(header) {
if (header.name == 'Content-Type' && header.value.indexOf('text/html') == 0) {
return true;
}
return false;
}).length > 0)
resources.push(response);
};
So, if you need to check the status of the first browser's request (in this case google's html page) you should see it as the first one returned in resources[0].status. In onResourceReceived handler you can add more filters for resources you try to get http code from.
UPDATE: thanks to #fotijr, added a check for completed responses
In
page.property('onResourceError', function(res) {
resources variable is undefined,
even if I set it with
var page = require('webpage').create(),
system = require('system'),
resources = [];