Cypress vs Playwright Advent Calendar Day 8
Completing "todo" items and checking CSS classes
Now that we can add “todo” items to our TodoMVC app, let’s confirm that the completed items get a special class “completed” set.
.todo-list li.completed label {
color: #d9d9d9;
text-decoration: line-through;
}Let’s test it
Playwright class assertions
We will enter 3 “todo” items, toggle the “complete” checkbox on the second item and confirm the changed class name on the second item. For completeness, we will confirm that the first and the third “todo” items remain without class “completed”
test(’completes a todo’, async ({ page }) => {
// common locators
const input = page.getByPlaceholder(’What needs to be done?’)
const todos = page.locator(’.todo-list li’)
await page.goto(’/’)
await page.locator(’body.loaded’).waitFor()
await input.fill(’Write code’)
await input.press(’Enter’)
await input.fill(’Write tests’)
await input.press(’Enter’)
await input.fill(’Make tests pass’)
await input.press(’Enter’)
// complete the middle todo
await todos.nth(1).locator(’.toggle’).click()
// confirm the middle todo is completed
// while the other todos are not
await expect(todos.nth(1)).toHaveClass(/completed/)
await expect(todos.first()).not.toHaveClass(/completed/)
await expect(todos.nth(2)).not.toHaveClass(/completed/)
})Nice. This is the screenshot of the passing test, notice the strikethrough text in the middle “todo” item.
The class check assertion .toHaveClass(/completed/) uses a regular expression because there are several classes on each element: “todo completed”, and by default the assertion checks the entire string! Thus we cannot check a single class presence and instead treat the class attribute as a string that can be checked against the regular expression.
// 🚨 DOES NOT WORK, since the class="todo completed"
await expect(todos.nth(1)).toHaveClass('completed')
// ✅ WORKS
await expect(todos.nth(1)).toHaveClass(/completed/)Cypress class assertions
Cypress uses Chai-jQuery plugin (included) to assert DOM element properties, here is the equivalent test.
it(’completes a todo’, () => {
const input = ‘[placeholder=”What needs to be done?”]’
const todos = ‘.todo-list li’
cy.visit(’/’)
cy.get(’body.loaded’).should(’be.visible’)
cy.get(input)
.type(’Write code{enter}’)
.type(’Write tests{enter}’)
.type(’Make tests pass{enter}’)
// complete the middle todo
cy.get(todos).eq(1).find(’.toggle’).click()
// confirm the middle todo is completed
// while the other todos are not
cy.get(todos).eq(1).should(’have.class’, ‘completed’)
cy.get(todos).first().should(’not.have.class’, ‘completed’)
cy.get(todos).eq(2).should(’not.have.class’, ‘completed’)
})The test is green, and each class name could be checked individually using the .should(’have.class’, ‘completed’) assertion.
If we want to confirm the class names as a single string, we could first execute Chai-jQuery assertion “have.attr”, followed by the standard Chai “match” assertion
// check the entire class attribute as a string
cy.get(todos)
.eq(1)
.should(’have.attr’, ‘class’)
.should(’match’, /completed/i)We can see the value yielded by the .should(’have.attr’, ‘class’) assertion by clicking on the assertion in the open test runner
Because Cypress tests run in the browser, we could validate the class list directly via HTMLElement classList property as shown in this recipe example. For instance, we could could convert the value from DOMTokenList into an Array to run custom predicate functions or array assertions:
cy.get(todos)
.eq(1)
.should(’have.prop’, ‘classList’)
.then(Array.from)
.should(’include’, ‘completed’)Of course, the value of the Array can be dumped into DevTools console by clicking on the assertion with the Test Runner open
Class confirmed.
Update: Playwright v1.52 has added toContainClass assertion that can easily check presence of a single class.
This advent calendar is based on my online course “Cypress vs Playwright“ and open-source workshop bahmutov/cypress-workshop-cy-vs-pw. You can find links to the previous advent calendar days in my blog post “Cypress vs Playwright Advent Calendar 2025“.





