How to access html requests from client with javascript? - javascript

Hello I am trying to access an Httprequest triggerd by a react component from my javascript code in order to test the url?
can anybody help please ?
Screenshot of the httprequest I want to access
Here is an example of the unit test I'am running, I want to add an other unit test that checks if the httprequest is called correctly.
.add('Search with "Occasion" keyword', () => {
const result = search('Iphone Occasion');
specs(() =>
describe('SEO Navigation Links', () => {
it('Should not contain "Occasion" keyword', () => {
const searchValue = result.find(Search).node.state.value.toLowerCase();
const contains = searchValue.includes('occasion');
expect(contains).toBeTruthy();
});
}),
);
return result;
});

The best i can recommend is to "monkey patch" the fetch function (if it uses that)
const realFetch = fetch;
fetch = (...args) => realFetch(...args).then(doStuff);
It creates a "middleware", and when the website tries to call the fetch function, it will call yours
Make sure you make a copy of the original function to avoid infinite recursion

If you install a Service worker, you can run some code client-side on all the requests your page makes. I'm not sure what you need to do in order to test the code you are talking about, but a Service Worker could report the request back to your own test code on the page, or respond with whatever content you want, or modify the server's response.

Related

Cypress - wait for the API response and verify UI changes

I have a component that I want to cover with some e2e tests. This component takes the URL provided by the user in the input, calls the API after the button click and then returns the shortened version of that URL. After that, shortened url is added to the list below the input on the UI and makes some localStorage assertion. I want Cypress to wait for the API response and only then check the UI if the list item was added. I made this working but I hardcoded the wait time in the wait() method. How Can I achieve that programatically ?
describe("Shortener component", () => {
it("Should add the list item and data to localStorage", () => {
cy.visit("http://127.0.0.1:5500"); //Live server extension address
cy.get("#url-input").type("https://facebook.com");
cy.get("#form-submit-button").click();
// wait for the api response and make sure that the value has been added to the localStorage
cy.wait(40000); //todo - wait for the api response instead of hardcoding the wait time
const localStorageData = localStorage.getItem("linksData");
if (JSON.parse(localStorageData)) {
expect(JSON.parse(localStorageData)[0].inputValue).to.eq(
"https://facebook.com"
);
}
// check if the new list item with the corrct value has been addded
cy.get(".shortener-component__list-item")
.contains("https://facebook.com")
.should("be.visible");
//validation mesasge should not be visible
cy.get("#validationMesage")
.contains("Please add a valid link")
.should("not.be.visible");
});
});
I tried with intercept() however I failed. Not sure how to make it working. I also saw some similar SE topics on that but it did not help me.
Any ideas / examples apreciated :)
Thx !
From the order of events you've given
short URL returned
added to localStorage
added to list
just change the order of feature testing
test list - it is last event, but has retriable commands (you can increase the timeout)
now test localStorage, if UI has the short URL so will localStorage
cy.contains('.shortener-component__list-item', 'https://facebook.com', { timeout: 40000 })
.then(() => {
// nested inside .then() so that the above passes first
const localStorageData = localStorage.getItem("linksData");
const linksData = JSON.parse(localStorageData);
expect(linksData).not.to.eq(undefined);
expect(linksData[0].inputValue).to.eq("https://facebook.com");
})
Alternatively, to make use of retry and timeout on the localStorage check,
cy.wrap(localStorage.getItem("linksData"))
.should('not.eq', undefined, { timeout: 40000 }) // will retry the above until true
.then(data => JSON.parse(data))
.should(parsedData => {
expect(parsedData.inputValue).to.eq("https://facebook.com");
});
I guess you should also start the test with
cy.clearLocalStorage("linksData")
There're examples in the documentation, it only takes some reading and experimentation.
In general, you need three commands: cy.intercept(), .as(), and cy.wait():
cy.intercept(your_url).as('getShortenedUrl');
cy.wait('#getShortenedUrl');
you can also use .then() to access the interception object, e.g. a response:
cy.wait('#getShortenedUrl').then(interception => { });
or you can check something in the response using .its():
cy.wait('#getShortenedUrl').its('response.statusCode').should('eq', 200);
The point is that after cy.wait('#getShortenedUrl'), the response has been received.

Cloudflare Workers “Singleton” class

I've started using workers for my sites. The purpose of workers on my sites:
mostly inject some code(html/js/css) in different locations of HTML page.
It can be some config data, or some legal text and etc.
So what I do now, is create a config in KV for each website and based on user country/language injecting above html/js and etc.
Below is a Store Class (Singleton pattern), that holds all the info from config, but doesn't work in workers, by doesn't work I mean, after first request, the data is persistent, and after some time it gets updated:
For example 1st request URL: /about
On Second request URL: /es/about/
By output console.log(event.request) will show /es/about , but Store.request outputs: /about/
any workaround for this, to force refresh of data, I thought becuase i don't do it in constructor, but by calling custom method should do the trick but, it doesn't.?
Below is some code example.
import { Store } from "#helpers/store";
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
});
//HTML Rewriter Class
class Head {
element(el) {
el.append(`
<script id="config">
var config = ${Store.export()};
</script>`, {
html: true
});
}
}
async function handleRequest(request) {
let store = await Store.make(request);
const response = await fetch(request);
let html = new HTMLRewriter();
html.on("head", new Head());
return html.transform(response);
}
//src/helpers/store.js
class Store {
constructor(){
this._request = null
this._config = {}
this._url = null
}
async make(request){
let config = {}
this._request = request;
const domain = this.url.hostname.replace(/www\./g, "");
const country = request.headers.get('cf-ipcountry')
const website = await WEBSITES.get(domain, "json"); //WEBSITES is KV namespace
const { license, lang } = website;
this._config = {
country,
domain,
license,
lang
};
return this;
}
export(){
return JSON.stringify(this._config)
}
get request(){
return this._request;
}
get url(){
if(!this._url){
this._url = new URL(this.request.url)
}
return this._url;
}
}
export default new Store()
A single instance of your Worker may handle multiple requests, including concurrent requests. In your code, you are using a singleton instance of Store to store metadata about the current request. But if multiple requests are handled concurrently, then the second request will overwrite the content of Store before the first request completes. This may cause the first request to render its HTML using metadata from the second request.
It seems like the use of a singleton pattern isn't what you want here. Based on the code, it looks like you really want to create a separate instance of Store for every request.
2 issues come to mind:
You are creating a new HTMLRewriter for each call to the worker. This will make for some concurrency issues. The instantiation of the rewriter should be done outside the handleRequst method. For example right after the import statement.
You are importing the Store class and never instantiating it but using its methods like they are static(which they aren't). This will also give you concurrency issues.

Node JS Auto Reload

I want to make a program with javascript or node.js what I want to achieve from the program is when there is a new item in rss that I take it will get a log through the terminal, and for the future I will put the code in firebase hosting, so I need that the code can run by itself the log that I will get maybe I will change it into a text file or stored in a database
so like this
I run the program and get all the items on RSS,
but when there is a new item I don't have to run the node app.js again, so every time there is a new item in the rss it will display the log by itself automatically
so far i made it with js node and i use rss-parser
and the code I use like this:
let Parser = require('rss-parser');
let parser = new Parser();
(async () => {
let feed = await parser.parseURL('https://rss-checker.blogspot.com/feeds/posts/default?alt=rss');
feed.items.forEach(items => {
console.log(items);
})
})();
There are three common ways to achieve this:
Polling
Stream push
Webhook
Based on your code sample I assume that the RSS feeder is request/response. This lends well to polling.
A poll based program will make a request to a resource on an interval. This interval should be informed by resource limits and expected performance from the end user. Ideally the API will accept an offset or a page so you could request all feeds above some ID. This make the program stateful.
setInterval can be used to drive the polling loop. Below shows an example of the poller loop with no state management. It polls at 5 second intervals:
let Parser = require('rss-parser');
let parser = new Parser();
setInterval(async () => {
let feed = await parser.parseURL('https://rss-checker.blogspot.com/feeds/posts/default?alt=rss');
feed.items.forEach(items => {
console.log(items);
})
}), 5000);
This is incomplete because it needs to keep track of already seen posts. Creating a poll loop means you have a stateful process that needs to stay running.

How to add recursive function checking xhr response in testcafe script?

I'm trying to write a test download works, which requires to check if xhr response has status READY. I created a client function in TestCafe, using promises, but it's failing in case of recursion.
How should I fix my code to handle this situation?
P.S. many apologies for newbies questions, I have just started my journey in automation testing.
fixture`Download report works`
test
.requestHooks(logger)//connected a request hook, will wait for logger request
('I should be able to download PDF report from header of the page', async t => {
//recursively check if response status is READY, and then go to assertions
const waitForDownloadResponseStatus = ClientFunction((log) => {
return new Promise((resolve,rejects)=>{
const waitForStatus=()=>{
const arrayFromResponse = JSON.parse(log.response.body);
const responseStatus = arrayFromResponse.status;
if (responseStatus == 'READY')
{
resolve(responseStatus);
}
else {
waitForStatus();
}
}
waitForStatus();
})
});
//page objects
const reportTableRaw = Selector('div.contentcontainer').find('a').withText('April 2019').nth(0);
const downloadPdfButton = Selector('a.sr-button.sr-methodbutton.btn-export').withText('PDF');
//actions.
await t
.navigateTo(url)
.useRole(admin)
.click(reportTableRaw)//went to customise your report layout
.click(downloadPdfButton)
.expect(logger.contains(record => record.response.statusCode === 200))
.ok();//checked if there is something in logger
const logResponse = logger.requests[0];
// const arrayFromResponse = JSON.parse(logResponse.response.body);
// const responseStatus = arrayFromResponse.status;
console.log(logger.requests);
await waitForDownloadResponseStatus(logResponse).then((resp)=>{
console.log(resp);
t.expect(resp).eql('READY');
});
});
When you pass an object as an argument or a dependency to a client function, it will receive a copy of the passed object. Thus it won't be able to detect any changes made by external code. In this particular case, the waitForStatus function won't reach its termination condition because it can't detect changes in the log object made by an external request hook. It means that this function will run indefinitely until it consumes the all available stack memory. After that, it will fail with a stack overflow error.
To avoid this situation, you can check out that response has status READY if you change the predicate argument of the contains function.
Take a look at the following code:
.expect(logger.contains(record => record.response.statusCode === 200 &&
JSON.parse(record.response.body).status === 'READY'))
.ok({ timeout: 5000 });
Also, you can use the timeout option. It's the time (in milliseconds) an assertion can take to pass before the test fails.

Trying to hit an API with JSON data in REACT

I have just started learning to code in ReactJS and have come to the part where I need to hit an API to get back JSON data.
I am running this on a node server on my local which tries to build it each time I make a change - this helps because it shows me where my errors are. Unfortunately it doesn't mean I know why I am getting an error.
This is my code so far:
import React from 'react';
import './App.css';
var GetUnassignedClients = React.createClass({
unassignedClients: function () {
return $.getJSON('http://localhost/backoffice/?action=unassignedClients.getUnassingedClients')
.then((data) => {
this.setState({resultMe: data.results});
});
},
render: function() {
return (
<div>this.state.resultMe</div>
);
}
});
module.exports = GetUnassignedClients;
I will re-paste the bit that seems to be throwing the error:
return $.getJSON('http://localhost/backoffice/?action=unassignedClients.getUnassingedClients')
.then((data) => {
this.setState({resultMe: data.results});
});
The error seems to be pointing at the $ - when I wrap this all in {} then it points to the full stop (.).
Not sure if I am doing something wrong or missing something.
The $in the $.getJSON is referring to jQuery. Do you have it included in your page? Javascript is trying to parse the dollar sign and can't find it. Other possible solution is to use a separate http library (if you don't need jQuery), such as axiois or fetch for example.
Im not sure, but I thought you would hit in this way
fetch(`http://localhost:8088/api/this/is/an/api/call`)
.then(result=> {
this.setState({items:result.json()});
});
Okay turns out I was trying to use $.getJSON which is JQuery - due to building this on my local using a node server JQuery wasn't included on my local development before the production code was built.
So instead I looked into using fetch that seems to be the go to when coding in react.
I also moved this section into a componentDidMount function so the app would be loaded and then the API call would be made - not that I have a lot of data to load but it's good practice for when you do.
My working code for this section:
componentDidMount () {
fetch("http://localhost/dashboard/?action=unassignedUsers.getUnassingedUsers", {
credentials: 'same-origin'
})
.then(response => response.json())
.then(json => this.setState({data: json}));
}
I also came across a couple issues using fetch - if you need a session available to access said data then you need to specifically pass through the credentials or the API call will re-direct to the login page. At first I saw a status 200 but no data - as it successfully re-directed to the login page, but obviously there was no JSON to access here.

Categories

Resources