How to compare a CSS value numerically? [duplicate] - cypress

This question already has answers here:
Is there a way to assert if a span element is bold?
(2 answers)
Closed 4 months ago.
This post was edited and submitted for review 4 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I want to test if the text in all selected elements are bold. In a very narrow sense, a text with font-weight 700 is bold. So this seems to work as a test:
cy.get('.foo').should('have.css', 'font-weight', '700');
But IMO very bold is still bold. Thus I would like to test if font-weight is 700 or greater. However, this does not work:
cy.get('.foo').should('have.css', 'font-weight').and('be.gte', 700);
The error says “expected '700' to be a number or a date”.
Any idea how to do it properly?

The font-weight is returned as a string - you can see this in your first code snippet, where you are checking that the font-weight is equal to '700' and not 700.
So, we simply have to parse the string into a number!
cy.get('.foo')
.should('have.css', 'font-weight') // yields the font-weight, as a string
.then(parseInt) // parses the strings
.and('be.gte', 700);
// Alternative if this answer gives you errors in your IDE
cy.get('.foo')
.should('have.css', 'font-weight') // yields the font-weight, as a string
.then((fontWeight) => +fontWeight) // parses the strings
.and('be.gte', 700);
If that seems cumbersome to repeat over and over, you could make a Cypress custom command
Cypress.Commands.add('validateBold', { prevSubject: true }, (subject) => {
return
cy.wrap(subject)
.should('have.css', 'font-weight')
.then((fontWeight) => +fontWeight)
.and('be.gte', 700);
});

Related

Cypress - counting number of elements in an array that contain a specific string

Attempting to confirm that of all the schema in the head of a page exactly 3 of them should have a specific string within them. These schemas have no tags or sub classes to differentiate themselves from each other, only the text within them. I can confirm that the text exists within any of the schema:
cy.get('head > script[type="application/ld+json"]').should('contain', '"#type":"Product"')
But what I need is to confirm that that string exists 3 times, something like this:
cy.get('head > script[type="application/ld+json"]').contains('"#type":"Product"').should('have.length', 3)
And I can't seem to find a way to get this to work since .filter, .find, .contains, etc don't filter down the way I need them to. Any suggestions? At this point it seems like I either need to import a custom library or get someone to add ids to these specific schema. Thanks!
The first thing to note is that .contains() always yields a single result, even when many element match.
It's not very explicit in the docs, but this is what it says
Yields
.contains() yields the new DOM element it found.
If you run
cy.get('head > script[type="application/ld+json"]')
.contains('"#type":"Product"')
.then(console.log) // logs an object with length: 1
and open up the object logged in devtools you'll see length: 1, but if you remove the .contains('"#type":"Product"') the log will show a higher length.
You can avoid this by using the jQuery :contains() selector
cy.get('script[type="application/ld+json"]:contains("#type\": \"Product")')
.then(console.log) // logs an object with length: 3
.should('have.length', 3);
Note the inner parts of the search string have escape chars (\) for quote marks that are part of the search string.
If you want to avoid escape chars, use a bit of javascript inside a .then() to filter
cy.get('script[type="application/ld+json"]')
.then($els => $els.filter((index, el) => el.innerText.includes('"#type": "Product"')) )
.then(console.log) // logs an object with length: 3
.should('have.length', 3);

Cypress, how to check for text typed into a field?

I can verify text appears "somewhere" on the results page with
it.only('can verify an input element has certain text typed into it', function() {
cy.visit('http://google.com')
cy.get("input[name=q]").type('abc123{enter}') // with or without the {enter}
cy.contains('abc123') // Anywhere on the page :(
})
but how can I verify the text I type in the input text box?
I tried chaining to the element with
it.only('can verify an input element has certain text typed into it', function() {
cy.visit('http://google.com')
cy.get("input[name=q]").type('abc123{enter}')
cy.get("input[name=q]").contains('abc123')
})
but I get
CypressError: Timed out retrying: Expected to find content: 'abc123' within the element: <input.gLFyf.gsfi> but never did.
I tried cy.get("input[name=q]").contains('abc123') and
cy.contains('input[name=q]', 'abc123')
but both time out and fail.
Change .contains to use .should('have.value'...
cy.get("input[name=q]").type('abc123{enter}')
cy.get("input[name=q]").should('have.value', 'abc123')
You may not like this idea but here is just a suggestion so you don't have to keep calling cy.get each time.
You could always set a const value for your input name (could be in an external file) so:
export const inputField = () => cy.get('input[name=q]');
This will do the get whenever you call inputField.
so then your call would be:
inputField.type('abc123{enter}').should('have.value', 'abc123');
Thats just more a setup thing than an actual soluton, as I know you solved the issue yourself, but the above is quite a nice way so you don't have to keep doing cy.get on the same field.
Instead of using contains, you can read the text you already entered in the input field using "then()". Here's how:
cy.get("input[name=q]").type('abc123').then(function($input){ const value = $input.text() expect(value.includes('abc123')).to.be.true })

Request only method returns original request array [duplicate]

This question already has answers here:
Laravel change input value
(7 answers)
Closed 3 years ago.
So I'm manipulating Request and setting an object to new value.
$assignable = ['seats'];
$request->seats = $this->myMethod($request->seats);
var_dump($request->seats); //works
$data = $request->only($assignable);
var_dump($data['seats']); // returns the initial value of 'seats' (without passing through $this->myMethod)
Now I know I could first convert the request object to array and then manipulate the '$data', but the above code is a sample and the real code is much more complicated, it would require to change the whole architecture to do that way.
Has anyone experienced anything like this?
Instead of this:
$request->seats = $this->myMethod($request->seats);
Try this:
$request->merge(['seats' => $this->myMethod($request->seats)]);

Selecting an element not equal to a certain string

I am trying to select an incorrect answer (radio button) to get an error message to appear, but the answers are random (except the correct answer).
How can I say get the radio buttons, and then click one that does not equal "correct answer" using cypress assertions?
cy.get('[data-cy="multipleChoiceQuestionAnswer"]')
.should('not.contain', 'correct answer')//.find('label').not('corect answer')//.not.includes('correct answer')
.click()
I would like to be able to select one of the two radio buttons for the incorrect answers, right now I can only select the correct answer.
well:
be aware that .should('not.contain', 'correct answer') is an assertion, is not a way to filter/get some elements.
It's, essentially, just a way to check (aka "assert") that something is like you expect it to be.
An assertion like yours is useful just to get the Cypress log print something like this
Read it like if you are telling
"Ehy Cypress, I selected an element, could you check that it doesn't contain the correct answer, please?"
What are assertions useful for? They aren't useful when everything goes right but when the test goes wrong.
Because without assertions, you can find yourself behind a broken test with Cypress telling you that "there isn't the element" but you can't know which element Cypress isn't finding.
Placing some "key point" assertions allows you to understand why a test failed in short time.
Anyway: if your HTML is something like this
<div data-cy="multipleChoiceQuestionAnswer"><label>correct answer<input type="checkbox"/></label></div>
<div data-cy="multipleChoiceQuestionAnswer"><label>no<input type="checkbox"/></label></div>
<div data-cy="multipleChoiceQuestionAnswer"><label>nope<input type="checkbox"/></label></div>
you can accomplish your goal making:
cy.get('[data-cy="multipleChoiceQuestionAnswer"]').then(els => {
// `els` is a jQuery instance, let's parse the various elements
let $el;
for(let i = 0, n = els.length; i < n; i++) {
// it transforms every element in a jQuery instance
$el = Cypress.$(els[i]);
// it uses jQuery to get the label text
if($el.find("label").text() !== "correct answer") {
// it stops as soon as the answer isn't the correct one
break;
}
}
// returns the element to be clicked
return $el.find("input");
})
// it assert about it (to have a useful hint in the Cypress command log)
.should("not.contain", "correct answer")
// clicks it
.click();
I hope the code is self-explanatory (in case it isn't, ask me some more clarifications) 😊

Why does .css work with this Nokogiri object but not XPath? [duplicate]

This question already has answers here:
Selecting a css class with xpath
(6 answers)
Closed 6 years ago.
Why does the CSS selector return the correct info, but the XPath does not?
source = "<hgroup class='page-header channel post-head' data-channel='tech' data-section='sec0=tech&sec1=index&sec2='><h2>Tech</h2></hgroup>"
doc = Nokogiri::HTML(source)
doc.xpath('//hgroup[case_insensitive_equals(#class,"post-head")]//h2', XpathFunctions.new)
=> []
doc.css("hgroup.post-head")[0].css("h2")
=> [#<Nokogiri::XML::Element:0x6c2b824 name="h2" children=[#<Nokogiri::XML::Text:0x6c2b554 "Tech">]>]
Assuming case_insensitive_equals does what its name suggests, it is because the class attribute isn’t equal to post-head (case insensitively or not), but it does contain it. XPath treats class attributes as plain strings, it doesn’t split them and handle the classes individually as CSS does.
A simple XPath that would work would be:
doc.xpath('//hgroup[contains(#class, "post-head")]//h2')
(I’ve removed the custom function, you will need to write your own to do this case insensitively.)
This isn’t quite the same though, as it will also match classes such as not-post-head. A more complete XPath would be something like this:
doc.xpath('//hgroup[contains(concat(" ", normalize-space(#class), " "), " post-head ")]//h2')

Resources