How can I test/validate the header hierarchy of a section in cypress? - html

i want to enforce the structure that headers follow a hierarchy. Meaning if you go from bottom to top of the dom, thr next heading must be <= current or + 1.
Here is the console log of my headings in one of my sections for example:
Yielded:
0: h2.mt-4
1: h3.mt-16.text-base.w-64
2: h4.mt-0.font-normal.text-sm
3: h4.mt-0.font-normal.text-sm
4: h4.mt-0.font-normal.text-sm
5: h3.mt-16.text-base.w-64
6: h4.mt-0.font-normal.text-sm
7: h4.mt-0.font-normal.text-sm
8: h4.mt-0.font-normal.text-sm
9: h4.mt-0.font-normal.text-sm
10: h3.mt-16.text-base.w-64
11: h4.mt-0.font-normal.text-sm
12: h4.mt-0.font-normal.text-sm
This would be valid ^
Yielded:
0: h2.mt-4
1: h3.mt-16.text-base.w-64
2: h4.mt-0.font-normal.text-sm
3: h4.mt-0.font-normal.text-sm
4: h4.mt-0.font-normal.text-sm
5: h3.mt-16.text-base.w-64
6: h4.mt-0.font-normal.text-sm
7: h4.mt-0.font-normal.text-sm
8: h4.mt-0.font-normal.text-sm
9: h4.mt-0.font-normal.text-sm
10: h3.mt-16.text-base.w-64
11: h1.mt-0.font-normal.text-sm
12: h1.mt-0.font-normal.text-sm
And this is not ^^^
So far I can loop through the sections and get each sections headers, but a bit stumped on how to loop through and force that rule. It would require comparing the current header and the next one in the array.
What I have so far:
Cypress.Commands.add("checkHeadingHeirarchy", () => {
cy.get("section").each(($section) => {
cy.get($section).within(() => {
cy.get("h1,h2,h3,h4,h5,h6"); //now what?...
});
});
});
#agoff: The console.log shows us the first $el and then the $list[index + 1]:
This is the $el: jQuery.fn.init [h2.mt-4]
This is the $el: <h3 data-cy=​"header" class=​"mt-16 text-base w-64">​Engineering​</h3>​
#agoff: This works, but its hacky:
Cypress.Commands.add("checkHeadingHeirarchy", () => {
cy.get("section").each(($section) => {
cy.get($section).within(() => {
cy.get("h1,h2,h3,h4,h5,h6").each(($el, index, $list) => {
// Don't run the validation on the last item in the list
if (index !== $list.length - 1) {
// Get the size of the current and next header
const currSize = getHeaderNumber($el);
const nextSize = getHeaderNumber($list, index + 1);
try {
expect(currSize <= nextSize || currSize + 1 === nextSize).to.eql(
true
);
} catch {
console.log("Failed on current size:", currSize);
console.log("Failed on next size:", nextSize);
throw error;
}
}
});
});
});
});
// helper function to get header number
const getHeaderNumber = ($el, index) => {
console.log("Going to parse this:", $el.get(index ?? 0));
try {
console.log("Got this:", parseInt($el.get(index ?? 0).tagName.slice(1)));
return parseInt($el.get(index ?? 0).tagName.slice(1));
} catch {
console.log("ERROR ON:", $el.get(index ?? 0));
}
};

You can yield the index of the elements yielded, as well as the entire list. Using that, we can easily compare the next yielded item.
Cypress.Commands.add("checkHeadingHeirarchy", () => {
cy.get("section").each(($section) => {
cy.wrap($section).within(($sectionWithin) => {
cy.get("h1,h2,h3,h4,h5,h6").each(($el, index, $list) => {
// Don't run the validation on the last item in the list
if (index !== $list.length - 1) {
// Get the size of the current and next header
const currSize = getHeaderNumber($el)
const nextSize = getHeaderNumber($list[index + 1])
expect(currSize <= nextSize || currSize + 1 === nextSize).to.eql(true);
}
});
});
});
});
// helper function to get header number
const getHeaderNumber = ($el) => {
const tagName = $el.prop('tagName') ?? $el.get(0).tagName
return parseInt(tagName.slice(1), 10);
}

Related

retrieving EntryID for Checkbox item in Google Sheets Form not working

I used the code from #contributorpw on this post get Entry ID which is used to pre-populate fields (Items) in a Google Form URL and added the extended list of form types from #SourceFli (in same post).
I get the error message: "Exception: The parameters (String) don't match the method signature for FormApp.CheckboxItem.createResponse". That checkbox has only 1 option: "yes".
The rest of all my form items are only TEXT items and work fine.
function getPreFillEntriesMap(){
var ssOrder = SpreadsheetApp.openById(ORDER_SPREADSHEET_ID);
var orderFormUrl = ssOrder.getFormUrl();
var orderForm = FormApp.openByUrl(orderFormUrl);
var form = orderForm;
// var form = FormApp.openById(id);
var items = form.getItems();
var newFormResponse = form.createResponse();
var itms = [];
for(var i = 0; i < items.length; i++){
var response = getDefaultItemResponse_(items[i]);
if(response){
newFormResponse.withItemResponse(response);
itms.push({
id: items[i].getId(),
entry: null,
title: items[i].getTitle(),
type: "" + items[i].getType()
});
}
}
var ens = newFormResponse.toPrefilledUrl().split("&entry.").map(function(s){
return s.split("=")[0];
});
ens.shift();
return Logger.log(itms.map(function(r, i){
r.entry = this[i];
return r;
}, ens));
}
function getDefaultItemResponse_(item){
switch(item.getType()){
case FormApp.ItemType.TEXT:
return item.asTextItem().createResponse("1");
break;
case FormApp.ItemType.MULTIPLE_CHOICE:
return item.asMultipleChoiceItem()
.createResponse(item.asMultipleChoiceItem().getChoices()[0].getValue());
break;
case FormApp.ItemType.CHECKBOX:
return item.asCheckboxItem()
.createResponse(item.asCheckboxItem().getChoices()[0].getValue());
break;
case FormApp.ItemType.DATETIME:
return item.asDateTimeItem()
.createResponse(new Date());
break;
case FormApp.ItemType.DATE:
return item.asDateItem()
.createResponse(new Date());
break;
case FormApp.ItemType.LIST:
return item.asListItem()
.createResponse(item.asListItem().getChoices()[0].getValue());
break;
case FormApp.ItemType.PARAGRAPH_TEXT:
return item.asParagraphTextItem()
.createResponse(item.asParagraphTextItem().createResponse("some paragraph"));
break;
case FormApp.ItemType.CHECKBOX_GRID:
return item.asCheckboxGridItem()
.createResponse(item.asCheckboxGridItem().createResponse([item.asGridItem().getColumns[0], item.asGridItem().getRows[0]]));
break;
case FormApp.ItemType.DURATION:
return item.asDurationItem()
.createResponse(item.asDurationItem().createResponse(2, 20, 20));
break;
case FormApp.ItemType.GRID:
return item.asGridItem()
.createResponse(item.asGridItem().createResponse([item.asGridItem().getColumns[0], item.asGridItem().getRows[0]]));
break;
case FormApp.ItemType.SCALE:
return item.asScaleItem()
.createResponse(item.asScaleItem().createResponse(1));
break;
case FormApp.ItemType.TIME:
return item.asTimeItem()
.createResponse(item.asTimeItem().createResponse(1, 1));
break;
default:
return undefined;
}
}
response of createResponse(responses) of Class CheckboxItem is String[]. In your script, the string is used. I thought that this might be the reason of your issue. So how about the following modification?
From:
return item.asCheckboxItem()
.createResponse(item.asCheckboxItem().getChoices()[0].getValue());
To:
return item.asCheckboxItem()
.createResponse([item.asCheckboxItem().getChoices()[0].getValue()]);
Reference:
createResponse(responses)

When pressed button in react, console log shows the result but page does not

I am new to react and web. I have an issue when calling the function console shows it but i can not show it in my page.
usePriest = (evt, id) => {
const num = 3;
const { rear,bottom2,bottom3,bottom,player1, player2, player3, player4, mycards } = this.state;
var whichPlayer;
switch(num){
case 1:
whichPlayer = player1[0];
rear[1]=whichPlayer;
rear[0]=card6;
break;
case 2:
whichPlayer = player2[0];
bottom[1]=whichPlayer;
bottom[0]=card6;
break;
case 3:
whichPlayer = player3[0];
bottom2[1]=whichPlayer;
bottom2[0]=card6;
break;
case 4:
whichPlayer = player4[0];
bottom3[1]=whichPlayer;
bottom3[0]=card6;
break;
}
// bottom[1]=whichPlayer;
// bottom[0]=card6;
// console.log(bottom);
}
and i call my function in here
else if (mycards[0]==="/static/media/priest.ae71698d.jpg") {
return ( <div>
<button className="button_card1_use" onClick={(evt) => this.usePriest(evt, 1)}>Use</button>
<button className="button_card1_discard">Discard</button>
<div className="about1"><p>Priest</p>
Player is allowed to see another player's hand. </div></div>
)
}
What should i return in function or do something in order to be able to show it on the page.
You just need to call a setState at the end of the function in order tot reflect the changes -:
usePriest = (evt, id) => {
const num = 3;
// your old code
this.setState({ rear,bottom2,bottom3,bottom,player1, player2, player3, player4, mycards })
}
Actually in JS things get copied by reference, so effectively we are mutating the state directly. This is a better solution for the same -:
usePriest = (evt, id) => {
const num = 3;
const { rear,bottom2,bottom3,bottom,player1, player2, player3, player4, mycards } = this.state;
var whichPlayer;
switch(num){
case 1:
this.setState({whichPlayer: player1[0], rear: [...rear, 0: card6, 1: whichPlayer]});
break;
case 2:
this.setState({whichPlayer: player2[0], bottom: [...bottom, 0: card6, 1: whichPlayer]});
break;
case 3:
this.setState({whichPlayer: player3[0], bottom2: [...bottom2, 0: card6, 1: whichPlayer]});
break;
case 4:
this.setState({whichPlayer: player4[0], bottom3: [...bottom3, 0: card6, 1: whichPlayer]});
break;
}
}

Puppeteer - how to click a link with certain text

I want to click a link with certain text using Puppeteer.
<a class="text-major ev-pick-this-event"
href="/cgi-bin/ncommerce3/SEGetEventInfo?ticketCode=GS%3AAMTX%3AHUSKERS%3ASLP2%3A&linkID=BQFN80-AMTX&shopperContext=&pc=&caller=&appCode=&groupCode=SLP&cgc=&dataAccId=129&locale=en_US&siteId=ev_BQFN80-AMTX">
HUSKERS - SLP2 - Ranges
</a>
It can be done with XPath's contains() and text() methods, for example:
const [link] = await page.$x('//a[contains(text(), "certain text")]') // returns an array, as the first element will be used it can be destructured
await link.click()
let click = await page.evaluate(() => {
try {
const getText = e => (e ? e.innerText.trim() : '')
let links = document.querySelectorAll('nav a')
for (let i = 0, n = links.length; i < n; i++) {
if (getText(links[i]) === 'Home') {
links[i].click()
return getText(links[i])
}
}
} catch (e) {
return e.toString()
}
})
console.log({ click })

dynamic view of the syncfusion schedule angular component

In the parameterization of the Schedule to Angular component I would like to know if it is possible to somehow define the start time and end time for a day.
I would like to define for each day what is the start time and the end time.
As this example I realized that the start time and end time is for every day, I would like to set the start time and end time for each day.
const resourceObject = {
text: p.nome, id: p.id,
color: '#848484', workDays: daysNumber,
startHour: '13:00', endHour: '18:00'
};
We have prepared the below sample to have different work hours per day using DataBinding event.
https://stackblitz.com/edit/angular-fxqnrc-njutc8?file=app.component.ts
Please refer below UG.
https://ej2.syncfusion.com/angular/documentation/api/schedule/#setworkhours
if (this.flag) {
if (
this.scheduleObj.currentView !== "Month" &&
this.scheduleObj.currentView !== "Agenda"
) {
var currentViewDates = this.scheduleObj.getCurrentViewDates();
for (var i = 0; i < currentViewDates.length; i++) {
switch ((currentViewDates[i] as any).getDay()) {
case 0:
this.scheduleObj.setWorkHours(
[currentViewDates[i]],
"06:00",
"14:00"
);
break;
case 1:
this.scheduleObj.setWorkHours(
[currentViewDates[i]],
"08:00",
"14:00"
);
break;
case 2:
this.scheduleObj.setWorkHours(
[currentViewDates[i]],
"07:00",
"20:00"
);
break;
case 3:
debugger;
this.scheduleObj.setWorkHours(
[currentViewDates[i]],
"09:00",
"13:00"
);
break;
case 4:
debugger
this.scheduleObj.setWorkHours(
[currentViewDates[i]],
"06:00",
"14:00"
);
break;
case 5:
debugger
this.scheduleObj.setWorkHours(
[currentViewDates[i]],
"08:00",
"15:00"
);
break;
case 6:
this.scheduleObj.setWorkHours(
[currentViewDates[i]],
"07:00",
"19:00"
);
}
}
}
this.flag = false;
}

Mixing razor code with HTML

Hi my mark up has snippets like below
<thead>
<tr class="">
<th data-field="firstname">First Name</th>
#{
foreach (MapDetail geMapDetailHead in Model.mapDetails)
{
string firstText, secText, thirdText;
if (geMapDetailHead.ResultTypeIDs.Equals("-9999"))
{
foreach (string rt in geMapDetailHead.ResultTypeIDs.Split(','))
{
firstText = #geMapDetailHead.Name;
string tab = geMapDetailHead.year;
int? month = geMapDetailHead.Month != 0 ? geMapDetailHead.Month : (geMapDetailHead.mapheader.Month != 0 ? geMapDetailHead.mapheader.Month : 0);
//switch (month.GetValueOrDefault())
//{
// default:
// tab += "";
// break;
// case 1:
// tab += " Jan";
// break;
// case 2:
// tab += " Feb";
// break;
// case 3:
// tab += " Mar";
// break;
// case 4:
// tab += " Apr";
// break;
// case 5:
// tab += " May";
// break;
// case 6:
// tab += " Jun";
// break;
// case 7:
// tab += " Jul";
// break;
// case 8:
// tab += " Aug";
// break;
// case 9:
// tab += " Sep";
// break;
// case 10:
// tab += " Oct";
// break;
// case 11:
// tab += " Nov";
// break;
// case 12:
// tab += " Dec";
// break;
//}
//secText = tab;
<th id=#geMapDetailHead.MapDetailID>#firstText #secText</th>
} #*end for loop*#
}
} #*end for loop*#
}
</tr>
</thead>
As soon as i un comment the switch statement it stops recognizing tag as markup. i have also tried putting
#:<th id=#geMapDetailHead.MapDetailID>#firstText #secText</th>
but did not work. How can i mix both the code and markup?
Well turned out that i had applied 1 extra # in the following line
firstText = #geMapDetailHead.Name;
I changed it to
firstText = geMapDetailHead.Name;
and BINGO!!
Cheers