Cypress - cy.intercept catching wrong url - javascript

i try to mock my API routes with intercept but i don't know why it's the wrong route which triggered (i'm on cypress#6.2.1)
i have two intercepts :
one for /contacts and second /contacts/Contact-ARandomId
cy.intercept('GET', 'http://localhost:5000/contacts', {statusCode: 200, body: dataMultiple})
cy.intercept('GET', 'http://localhost:5000/contacts/Contact-ARandomId', {statusCode: 200, body: dataARandomId})

Ref Matching URL
You can provide a substring of the URL to match
// will match any request that contains "users" substring, like
// GET /users?_limit=3 and POST /users
cy.intercept('users')
so 'http://localhost:5000/contacts' matches because it is the first defined, and partial matching applies.
You could just reverse the order of the intercepts, set the more specific URL first (sort of like routes on a SPA).
Alternatively, take a look at Set an alias dynamically.
You can use javascript to refine the response
cy.intercept('GET', 'http://localhost:5000/contacts', (req) => {
const isContactById = req.url.split('/') // split into parts
.pop() // take last part
.startsWith('Contact-'); // check if has id prefix
const bodyStub = isContactById ? dataARandomId : dataMultiple;
req.reply(200, bodyStub);
})

Related

How to handle null URL parameters with Express.js

I'm working on an assignment for my web services class and can't figure out how to handle a null URL parameter. Here is my code:
app.get('/nachos/:x/:cheese/:tomatoes/:salsa/:hotsauce', (req, res) => {
var x = parseInt(req.params['x'])
var cheese = (req.params['cheese'])
var tomatoes = (req.params['tomatoes'])
var salsa = (req.params['salsa'])
var hotsauce = (req.params['hotsauce'])
res.send('You ordered ' + x + ' nacho(s) with ' + cheese + ', ' + tomatoes + ', ' + salsa + ', '
+ hotsauce + '.')})
This code works fine with all parameters filled. But how do I handle a null parameter if I don't want, for example, salsa and type in the url localhost:port/nachos/1/cheese/tomatoes/hotsauce
If I'm reading correctly the question is:
How do I handle a null parameter if I don't want, for example,
salsa and type in the url localhost:port/nachos/1/cheese/tomatoes/hotsauce
You won't get null it simply won't match the route.
You can make params optional like:
app.get('/nachos/:x?/:cheese?/:tomatoes?/:salsa?/:hotsauce?', (req, res) => {
or add routes to match, which could get out of hand.
app.get([
//...
'/nachos/:x/:cheese/:tomatoes',
'/nachos/:x/:cheese/:tomatoes/:hotsauce',
'/nachos/:x/:cheese/:tomatoes/:salsa/:hotsauce',
//...
], (req, res) => {
You don't really do optional arguments in a route definition that looks like this:
/nachos/:x/:cheese/:tomatoes/:salsa/:hotsauce
because in order for the route to match, every one of the parameters must be present and for req.params to contain the right option, they must all be in the correct order. If these are variations, some of which are entirely optional, then matching them the way you were is just not the proper URL design and matching a varying URL like that in Express will be a bit of a pain.
The simplest way I can think of is to just put the optional ingredients in a query string as in:
/nachos/2?cheese=yes&tomatoes=yes&salsa=yes&hotsauce=yes
Then, you just match the route: /nachos/:x as the only required options for the URL and everything else can be optionally specified in the querystring and you can write your code so that it defaults to "no" if the option is not present. So, an order without hotsauce could be either of these:
/nachos/2?cheese=yes&tomatoes=yes&salsa=yes&hotsauce=no
/nachos/2?cheese=yes&tomatoes=yes&salsa=yes
An order without hotsauce or salsa could just be this:
/nachos/2?cheese=yes&tomatoes=yes
Then, your request handler would look like this:
const orderOptions = ["cheese", "tomatoes", "salsa", "hotsauce"];
app.get('/nachos/:x', (req, res) => {
console.log(req.query);
let text = orderOptions.map(item => {
return req.query[item] === "yes" ? item : null;
}).filter(item => !!item).join(", ");
res.send(`You ordered ${req.params.x} nacho(s) with ${text}.`);
});
I should mention that if this request is actually specifying an order, then it should probably be a POST, not a GET and the options should be in the body of the POST and they would take the same form as the querystring, probably encoded just like application/x-www-form-urlencoded from form POSTs.
Passing parameters this way request to the API user to send the parameters in the correct order. To handle the case you want (an ingredient missing), you would need to create another route to handle it. But you can do this in another way, like passing the parameters as query strings or even sending them on the request body (for non-GET routers preferably).

How can I retrieve the full path to a child node using orderByChild equalTo?

Is it possible to retrieve the full path to a Child node from a firebase query with orderByChild .equalTo? I have .indexOn: "city"
My data is structured as such:
I have tried:
firebase.database().ref('users').orderByChild('city').equalTo('calgary').once("value", function(snapshot) {
console.log(snapshot.ref.toString());
});
I have also tried:
console.log(snapshot.ref.toString());
//outputs: https://xxxx.firebaseio.com/users <-- WRONG, not full path.
console.log(snapshot.ref.path.toString());
//outputs /users <-- WRONG, not full path.
How can I get the full path - working up from the found key?
Expected: /users/uid/location/
To get the full qualified URL for data, you can call DatabaseReference.toString().
To just get the path to that same data, you can substract the root path from the full path:
snapshot.ref.toString().substring(snapshot.ref.root.toString().length - 1)
Also see: how to get firebase.database.Reference full path, which I'm going to mark your question as a duplicate off.
Since you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
You need to loop over those results, and then can get the path to each individual node:
firebase.database.ref('users').orderByChild('city').equalTo('calgary').once("value", function(snapshot) {
var rootPath = snapshot.ref.root.toString();
snapshot.forEach(function(child) {
console.log(child.ref.toString().substring(rootPath.length - 1));
})
});
It turns out your search is wrong. Since you're trying to order/filter on location/city, that's what you should also user in orderByChild():
firebase.database().ref('users').orderByChild('location/city').equalTo('calgary')

cypress: comparing information in 2 sites

I'm starting with cypress and need to compare 2 different environments.
I did a script, but is not working properly.
My goal is:
1 - search for a specific selector value at 2 different environments.
2 - get it's value (in both env) , and then compare it if equal.
The below comparision work, but seems very poor code and it stop in first error assert and can't query reference selector, just text.
Any help is appreciated.
describe('Testing Page', function() {
//urls i need to test
var relative_urls = [
'/products/test1',
'/products/test2',
]
relative_urls.forEach((url) => {
//each url is compared here...
var productInfo = [];
//here goes the environments URL.
var testURL = 'https://www.myurl.com' + url;
var referenceURL = 'http://test.myurl.com' + url;
it('Comparing data from url:' + url, function() {
cy.visit(testURL)
//get data from selector and add it to array
cy.get('body').find(".myselector h1").should(($input) => {
productInfo.push($input.val())
})
cy.get('body').find(".myselector h2").should(($input) => {
productInfo.push($input.val())
})
//requesting second url
cy.request(referenceURL)
.its('body').should( ($input) => {
for (var j=0;j<productInfo.length;j++) {
//expect works, but compares to all site, and i need to search in a specific selector.
//Also, when it gets the first error, it stops and do not search all elements of array
expect($input.includes(productInfo[j]), 'Notice: ' + productInfo[j]).to.be.true
}
}
})
})
})
})
From reading the documentation, cy.request is really making a plain HTTP request without doing any parsing, which means you basically have to parse the body of the response yourself. cy.visit will actually get the DOM elements so you can use Cypress's query syntax to navigate the page.
I think once you have the element values from the first page you should just do cy.visit again and parse the second page.
EDIT: Apparently you can't use cy.visit cross-domain. In that case, maybe you could try parsing the response body into a DOM node like this:
var el = document.createElement( 'html' );
el.innerHTML = request.body // you can get the request object from cy.request;
Then use el.querySelector to navigate the DOM tree using CSS syntax.

Contentful JS: Unable to retrieve entries by matching Reference field

I am using Contentful's Javascript API to build a project. Currently, I'm having an issue where I get "undefined" as a return for the following call.
const query = {
content_type: "vehicle",
include: 2,
select: "fields",
"fields.site.fields.siteName[match]": id
};
I've set up "vehicle" as a model which uses a "site" reference with names, addresses and so forth. It seems to be possible to use [exist] on the first level, like
"fields.site[exists]": true
which works, but is unsatisfactory for what I need.
What I need are any Vehicles that belong to a named Site. Obviously, I've made sure to add the relevant content, and I can indeed see the data when omitting the "fields.site.fields..." line. For security purposes, I would very much not have vehicles for other sites showing up in the response.
Am I missing something? Upping the "include" level does not do anything either.
👋🏻
I believed you didn't see one sentence in the docs.
Second is fields.brand.sys.contentType.sys.id=sFzTZbSuM8coEwygeUYes which you use to to filter on fields of entries from content type 2PqfXUJwE8qSYKuM0U6w8M.
So basically to make your query work you have also to define the content type of the entry your search query is matching against.
I quickly prototyped your case in Node.js.
const { createClient } = require('contentful');
const client = createClient({
space: '...',
accessToken: '...'
});
client.getEntries({
content_type: 'vehicle',
select: 'fields',
// this is the line you're missing
'fields.site.sys.contentType.sys.id': 'site',
'fields.site.fields.siteName': 'vw-site'
}).then(({items}) => {
console.log(items);
}).catch(e => console.log(e));
You can find a detailed example in the docs
Hope that helps :)

Fetch Api get params

I am trying to make a "GET" request using window.fetch, and I need to pass in a param which takes in an entire array as the value. For example, the request url should look like this
'https://someapi/production?moves=[]'
I have the following segment, which ends up in a 400 request, because the array gets evaluated to empty
let url = new URL('https://someapi/production');
let params = {moves: []};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
console.log(url);
fetch(url.href)
.then(res => res.json())
.then(val => {
console.log(val);
});
Upon inspecting the url.href looks like
https://someapi/production?moves=
where as I want it to be
https://someapi/production?moves=[]
Any suggestions on how I can achieve this?
Because the second argument of url.searchParams.append(key, params[key]) is not a string, URLSearchParams.append will result in the value being stringified. I assume that's by calling the Array.prototype.toString() method on it, which omits the array brackets.
So, you'll either need to concatenate some brackets onto that string, or call a different method (like JSON.stringify mentioned in the comments) to keep the brackets.

Categories

Resources