SSO Login in Cypress - javascript

the app that I test has SSO login. So, 1st I am cy.vist(xxx) to one URL then system directs me another cy.visit(yyy). But currently I cant handle the issue that currently I am facing. Can you please help me to figure out?
Thank you
it.only("logs in using env variables", () => {
const username = Cypress.env("username");
const password = Cypress.env("password");
let href;
cy.visit("/");
cy.get(".chakra-stack > .css-1n94901").click()
cy.contains("Login with Carmarket").click();
cy.get(":nth-child(1) > .form-control").type(username);
cy.get(":nth-child(2) > .form-control").type(password);
cy.get(".login > .submit > .button").click({multiple: true,force: true});
cy.url().then((url) => {
href = url;
cy.log("href ", href);
cy.visit(href);
cy.url().should("include", "blabla[][1]][1]"); //assertion of that we are in this url
});
});
});

After clicking the login button, you can directly assert whether url contains some text. Also you can add some timeout as well for the redirection to complete.
cy.url({timeout: 6000}).should("include", "blabla[][1]][1]")
Considering your url is https://example.com/ Within the same test you can work with urls if they have format like https://example.com/something or https://example.com/something/123 or https://superdomain.example.com/. So basically the url should have the same origin. But in case the url is not from the same origin which is in your case, then you have to move to a new test to resolve this. This is a trade-off of cypress and you can read more about it from here. So you can do something like this:
it('logs in using env variables', () => {
const username = Cypress.env('username')
const password = Cypress.env('password')
let href
cy.visit('/')
cy.get('.chakra-stack > .css-1n94901').click()
cy.contains('Login with Carmarket').click()
cy.get(':nth-child(1) > .form-control').type(username)
cy.get(':nth-child(2) > .form-control').type(password)
cy.get('.login > .submit > .button').click({multiple: true, force: true})
})
it('validate content of url', () => {
cy.url({timeout: 6000}).should('include', 'blabla[][1]][1]')
})

Related

How can i add meeting url (session url) in generated ics file? which will appear on join button as joining link(custom event link) on teams calendar?

Right now i have added session link in description properties. I want that session link should display on join link in outlook and teams calendar. Has anybody run into the same situation?
Please let me know if i can achieve this or not ?
let descriptionLink = <div> <div> ${this.state.eventDescription}</div> <a href=${this.state.sessionLink}>Join Session</a> </div>;
let url = [
"BEGIN:VCALENDAR",
"VERSION:2.0",
"BEGIN:VEVENT",
"DTSTART:" + this.formatDate(this.state.startTime),
"DTEND:" + this.formatDate(this.state.endTime),
"SUMMARY:" + this.state.eventTitle,
"LOCATION:" + this.state.location,
"X-ALT-DESC;FMTTYPE=text/html:" + descriptionLink,
"BEGIN:VALARM",
"TRIGGER:-PT15M",
"REPEAT:1",
"DURATION:PT15M",
"ACTION:DISPLAY",
"DESCRIPTION:Reminder",
"END:VALARM",
"END:VEVENT",
"END:VCALENDAR"
].join("\n");
let blob = new Blob([url], { type: 'text/calendar;charset=utf-8' });
if (/msie\s|trident\/|edge\//i.test(window.navigator.userAgent)) {
// Open/Save link in IE and Edge
let tt: any = window.navigator;
tt.msSaveBlob(blob, 'download.ics');
} else {
// Open/Save link in Modern Browsers
window.open(encodeURI("data:text/calendar;charset=utf8," + url));
}

Axios & Cheerio - can't select more than one table row

Have just been playing around with axios & cheerio. I was attempting to scrape table data from the world rugby rankings website. I would like to return the top 10 rows of the table.
https://www.world.rugby/tournaments/rankings/mru
Presently I can only retrieve the first row of the table and I can't figure out why.
const axios = require('axios')
const cheerio = require('cheerio')
async function getWorldRankings() {
try {
const siteUrl = 'https://www.world.rugby/tournaments/rankings/mru'
const { data } = await axios({
method: "GET",
url: siteUrl,
})
const $ = cheerio.load(data)
const elemSelector = 'body > section > div.pageContent.flex-content > div:nth-child(2) > div.column.large-8 > div > section > section > div.fullRankingsContainer.large-7.columns > div > div > table > tbody > tr'
$(elemSelector).each((parentIndex, parentElem) => {
$(parentElem).children().each((childIndex, childElem) => {
console.log($(childElem).text());
})
})
} catch (err) {
console.error(err);
}
}
getWorldRankings()
Result:
>node index.jsx
Position
Teams
Points
For full context and credit I was playing around with this guide:
https://www.youtube.com/watch?v=5YCuUCRS_Ks (I'm using the same code just different url's and css selectors - and I can retrieve table rows as intended with his example coinmarketcap.com and many other websites).
For the world rugby rankings site - even though the html is available in dev tools is the data being injected in some way that makes it unselectable? (I have no idea what I am talking about just throwing out a guess).
Thanks for any help.
node v16.4.2
"axios": "^0.22.0",
"cheerio": "^1.0.0-rc.10",
The data for that table is being loaded later with AJAX and is not initially loaded with the page, you therefore cannot select it with Cheerio. The good news is you don't even need Cheerio for this. If you take a look at the network requests tab in your browser's development tools, you'll see the AJAX request being made uses the following URL to load JSON formatted data --the data you want-- into the page:
https://cmsapi.pulselive.com/rugby/rankings/mru?language=en&client=pulse

Scrape JS site with NodeJS, Nightmare and Cheerio

I am trying to scrape a website to get the scores of each team. I am running into an issue where my script is returning null content. I cannot see where I am going wrong and looking for some help.
JS:
const Nightmare = require('nightmare')
const cheerio = require('cheerio');
const fs = require('fs');
const nightmare = Nightmare({ show: true })
const url = 'https://www.mscl.org/live/scorecard/ed7941919f69b0e11e800fef/mHcehsPR9S86T3zQv';
nightmare
.goto(url)
.wait('body')
.wait('div#summaryTab.tab-pane.fade.in.table-responsive.borderless.active')
.evaluate(() => document.querySelector('div.col-md-6').innerHTML)
.end()
.then(response => {
console.log(getData(response));
}).catch(err => {
console.log(err);
});
let getData = html => {
data = [];
const $ = cheerio.load(html);
$('div').each((i, elem) => {
if(i === 0 ){
console.log($(elem).find('nth-child(1)').html());
}
});
return data;
}
The html I am scraping is here.
https://pastebin.com/R6syWDwD
The line where the scores are: 30 and 32
<div class="col-md-6">
<b>40 Overs Match</b><br>
<b>MVCC Combined</b> won the toss and chose Batting<br>
<b>Umpires: </b>No umpires were selected<br>
<b>Date: </b> 3/24/2021, 5:00:00 PM<br>
<b>Ground: </b>Acton Field 1<br>
<b>Result: TBD</b><br>
<b>MoM: </b> <br>
<hr>
<p><b>MVCC COMBINED XI - 147/10</b> (<b>O:</b> 12.5 | <b>RR:</b> 11.45)</p>
<p><b>MVCC United XI - 23/1</b> (<b>O:</b> 2.0 | <b>RR:</b> 11.50)</p>
<hr>
</div>
When I run this it returns nothing. No errors are being displayed either. What am i missing?
The jQuery Docs for nth-child says
jQuery's implementation of :nth- selectors is strictly derived from the CSS specification
So you propably have to provide an element to your nth-child(1)-pseudo-selector, to tell jQuery from which element it should select the nth-child of. try this:
console.log($(elem).find('b:nth-child(1)').html());
alternatively, just try to prefix nth-child(1) with a colon -> :nth-child(1)
Edit:
I just realized you are using innerHTML on your selected div, which actually returns the contents of the div without the wrapping div itself. But in getData you try to select the div with $('div') which then is actually not found.

How to add event listeners to multiple buttons which each modify different parts of the data

I am working on my first personal project and I am almost finished, but I am struggling to get some buttons to work. My project is one where bookmarks can be saved, and there is a column for bookmarks that are favorites, and a column for the other saved bookmarks. These buttons each correspond to an item retrieved from the database (I'm using Firestore for my database, but for this post I have modified it to eliminate the need for Firestore), and hence are not hardcoded into the html file. When a new bookmark is saved, it has a name (such as "Reddit"), a url ("www.reddit.com"), and a boolean for its favorite status (true if it is a favorite, false if otherwise). I want each bookmark to have an associated button which can be clicked to move the bookmark to the other column. I am stuck on how to add an event listener to each item in the database that only modifies the data from that one item. The code is below (there is more explanation at the bottom.
The full code can be found here (includes everything you need to run the program in full): https://github.com/matt-manning/Bookmarker
Here is a minimized version (still sufficient enough to be used on its own):
const bookmarkList = document.querySelector('#other-list');
const favoriteList = document.querySelector('#favorite-list');
const form = document.querySelector('#add-bookmark');
function start() {
const db = [
{website: 'Reddit', url: 'www.reddit.com', favorite: true},
{website: 'Google', url: 'www.google.com', favorite: false},
{website: 'Netflix', url: 'www.netflix.com', favorite: true},
{website: 'YouTube', url: 'www.youtube.com', favorite: false}
];
const bookmarkData = setupBookmarks(db);
registerBookmarkEventListeners(db, bookmarkData);
}
const setupBookmarks = (data) => {
let favoritesHTML, bookmarksHTML = '';
const bookmarkData = [];
if (data && data.length) {
data.forEach(doc => {
const bookmarkId = Math.floor(Math.random() * 10000000);
const bookmark = doc;
if (bookmark.favorite) {
favoritesHTML += bookmarkHTML(bookmark, bookmarkId);
} else {
bookmarksHTML += bookmarkHTML(bookmark, bookmarkId);
}
bookmarkData.push({bookmark, bookmarkId});
})
}
favoriteList.innerHTML = favoritesHTML;
bookmarkList.innerHTML = bookmarksHTML;
return bookmarkData;
}
const bookmarkHTML = (bookmark, bookmarkId) => {
let html = '';
// cut for minimizing; here is a potentially relevant snippet. Full code can be found in the github link above.
const li =
`<li>
<button class='btn-flat waves-light btn-small right listener' id='${bookmarkId}'>
<i class='material-icons left'>compare_arrows</i>switch</button>
<li>`;
html += li;
return html;
}
My problems lie in the registerBookmarkEventListeners function. What I want this function to do is add an event listener to a button on each bookmark, and when the button is clicked, the 'favorite' boolean in said bookmark changes to the opposite, which would then make the bookmark switch to the other column.
Here are a couple attempts I have made (more attempts can be found in the github link):
const registerBookmarkEventListeners = (data, bookmarkData) => {
document.querySelectorAll('.listener').forEach(elem => {
elem.addEventListener('click', e => {
e.preventDefault();
const bookmark = elem;
if (bookmark.favorite) {
bookmark.favorite = false;
} else {
bookmark.favorite = true;
}
})
})
}
const registerBookmarkEventListeners = (data, bookmarkData) => {
const {bookmark, bookmarkId} = bookmarkData;
bookmarkData.forEach(item => {
const btnElement = document.querySelector(`#${bookmarkId}`);
btnElement.addEventListener('click', e => {
e.preventDefault();
if (bookmark.favorite) {
bookmark.favorite = false;
} else {
bookmark.favorite = true;
}
})
})
}
I understand why my attempts above don't work. The first one doesn't even use either of the parameters given with the data from the database. The second one uses bookmarkId, but it doesn't 'connect' (if that is the right word) to the data it is supposed to be modifying. I'm struggling to find out how to make this addEventListener work.
So, how do I add event listeners to buttons through a loop which each directly modify a different part of the data?
Thanks for any help.
Also, for completeness, here is the relevant HTML needed to run the program:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bookmarker</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<div class='row logged-in show-none'>
<div class="col s6">
<h5>Favorites</h5>
<ul id='favorite-list'></ul>
</div>
<div class="col s6">
<h5>Bookmarks</h5>
<ul id='other-list'></ul>
</div>
</div>
<script src='script.js'></script>
</body>
</html>
If you get the item in bookmarkData.forEach(item => ... then you should put the destructuring in that brace and have something like
const { bookmarkId, bookmark } = item;
The way I've done that:
Pass data with id's to registerBookmarkEventListeners function.
ForEach on every element.
Find button with id that match data id and add listener.
Change favorite of that element.
Below you can find code if you stuck. Notice that I changed id's of buttons in your html code by adding 'x' before number and you still need to figure how to render items after change.
registerBookmarkEventListeners(bookmarkData); // 1
const registerBookmarkEventListeners = (data) => {
data.forEach(bookmark => { // 2
document.querySelector(`#x${bookmark.bookmarkId}`).addEventListener('click', (e) => { // 3
bookmark.bookmark.favorite = !bookmark.bookmark.favorite; // 4
console.log(bookmark);
})
})
}

collections keeps retrieving me "undefined"

I just cant seem to get the snapshot docs to show me the data from the server.
i have checked the collection. it is called "creaciones" without uppercase. I have 1 document and I have files written already. I've made no spelling mistakes whatsoever. I made this work before and now i cant.
db.collection('usuarios').get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc){
console.log(doc.data);
});
setupGrilla(snapshot.docs);
});
//Setup grilla
const setupGrilla = (data) => {
let html = '';
data.forEach(doc => {
const grilla = doc.data();
const creacion = `
<div>
<img src='jpg/${grilla.tipoCreacion}.png' alt='tipoCreacion'>
<h2>${grilla.nombreCreacion}</h2>
<img src='Imagenes/${grilla.nombreFoto}' alt='nombrefoto' class='imagen'>
<span>piezas: ${grilla.piezas}</span>
<span class='separador'></span>
<span>tiempo: ${grilla.tiempo} minutos</span>
<p>padre: ${grilla.ayuda} </p>
<p class='puntos'>Puntos: ${grilla.puntos} </p>
</div>
`;
html += creacion;
});
}
//get Data
db.collection('creaciones').get().then(snapshot => {
setupGrilla(snapshot.docs);
console.log(snapshot.docs);
});
I expect it to show fetch the database data.
db.collection('usuarios').get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc){
console.log(doc.data);
});
setupGrilla(snapshot.docs);
});
That code is just what I have tried before. No need to look into that because I don't have it written at the moment.
You are calling setupGrilla with a snapshot.docs argument, but snapshot is never defined.
Try querySnapshot.docs instead, or rename querySnapshot in snapshot.
You are also passing the wrong argument to your method
db.collection('usuarios').get().then(function(snapshot) {
snapshot.forEach(function(doc){
console.log(doc.data);
});
setupGrilla(snapshot); // <-- Here
});

Categories

Resources