Pseudo CSS selectors
These examples are based on the article Meet the Pseudo Class Selectors.
Links
Some of the anchor elements below do not have href
attribute, thus they are not links. Let's select the anchors with href
attributes.
<div data-cy="pseudo-links">
<a href="first">first</a>, <a>second</a>,
<a href="third">third</a>,
</div>
cy.get('[data-cy=pseudo-links]')
.scrollIntoView()
.within(() => {
// by default, "a" returns all 3 elements
cy.get('a').should('have.length', 3)
// select "a" elements with "href" attribute
cy.get('a:link').should('have.length', 2)
// which is equivalent to
cy.get('a[href]').should('have.length', 2)
})
Empty elements
Let's find all elements without any content using :empty
pseudo selector. Notice in the markup below some <P>
elements have no content.
<div data-cy="empty-elements">
<p></p>
<p>Has some text</p>
<p></p>
<p class="nothing"></p>
</div>
cy.get('[data-cy=empty-elements]')
.scrollIntoView()
.within(() => {
cy.get('p:empty')
.should('have.length', 3)
.last()
.should('have.class', 'nothing')
})
First letter
<div data-cy="first-letter">
<p>this is some text, just an example</p>
</div>
<style>
/* make the first letter always stand out */
[data-cy='first-letter'] p::first-letter {
text-transform: uppercase;
font-weight: bold;
}
</style>
cy.get('[data-cy=first-letter]')
.scrollIntoView()
.within(() => {
// Cypress does not recognize the selector "p::first-letter"
// because the jQuery engine does not support them
// thus the following DOES NOT WORK with error
// "Syntax error, unrecognized expression: p::first-letter"
// cy.get('p::first-letter')
})
::after
After content CSS selector <style>
/* add a word after each paragraph */
[data-cy='after-example'] p::after {
content: 'Joe Smith';
margin-left: 1em;
}
</style>
<div data-cy="after-example">
<p>Write more tests</p>
</div>
cy.get('[data-cy=after-example]')
.scrollIntoView()
.within(() => {
// Cypress does not recognize the selector "p::after"
// because the jQuery engine does not support them
// so we get the content through the computed style
// see https://codepen.io/chriscoyier/pen/Pzzawj
cy.window().then((win) => {
cy.contains('more tests').then(($el) => {
const after = win.getComputedStyle($el[0], '::after')
const afterContent = after.getPropertyValue('content')
// the content is a string, thus we need to quote it
expect(afterContent).to.equal('"Joe Smith"')
})
})
})
::after
content using cypress-map
Checking the You can shorten the above code snippet using cypress-map queries
<style>
/* add a word after each paragraph */
[data-cy='after-example'] p::after {
content: 'Joe Smith';
margin-left: 1em;
}
</style>
<div data-cy="after-example">
<p>Write more tests</p>
</div>
cy.get('[data-cy=after-example] p')
// from jQuery object, get the actual element
// and call "window.getComputedStyle(element, '::after')"
.applyToFirstRight(window.getComputedStyle, '::after')
.invoke('getPropertyValue', 'content')
.should('equal', '"Joe Smith"')
::after
exists or not
Checking if <style>
/* add a word after each paragraph */
[data-cy='after-example'] p::after {
margin-left: 1em;
}
[data-cy='after-example'] p.displayed::after {
content: 'Joe and Amy';
}
</style>
<div data-cy="after-example">
<p>Write more tests</p>
<button id="add-after">Click me</button>
</div>
<script>
document
.getElementById('add-after')
.addEventListener('click', () => {
setTimeout(() => {
const el = document.querySelector(
"[data-cy='after-example'] p",
)
el.classList.add('displayed')
}, 1000)
})
</script>
cy.log('**no ::after at first**')
cy.get('[data-cy=after-example] p')
.applyToFirstRight(window.getComputedStyle, '::after')
.invoke('getPropertyValue', 'content')
.should('equal', 'none')
cy.contains('button', 'Click me').click()
cy.log('**new ::after content after some time**')
cy.get('[data-cy=after-example] p')
.applyToFirstRight(window.getComputedStyle, '::after')
.invoke('getPropertyValue', 'content')
.should('equal', '"Joe and Amy"')
::before
Before content CSS selector <style>
/* add a word in front of each paragraph */
[data-cy='before-example'] p::before {
content: 'Greeting';
margin-right: 1em;
}
</style>
<div data-cy="before-example">
<p>Hello, world!</p>
</div>
cy.get('[data-cy=before-example]')
.scrollIntoView()
.within(() => {
// Cypress does not recognize the selector "p::before"
// because the jQuery engine does not support them
// so we get the content through the computed style
// see https://codepen.io/chriscoyier/pen/Pzzawj
cy.window().then((win) => {
cy.contains('Hello').then(($el) => {
const before = win.getComputedStyle($el[0], '::before')
const beforeContent = before.getPropertyValue('content')
// the content is a string, thus we need to quote it
expect(beforeContent).to.equal('"Greeting"')
})
})
})