← Back to Discord Forum

toBeVisible() and not.toBeVisible() - both pass. Why ?

marcink5356posted in #help-playwright
Open in Discord

I have simple test:

test.("Accept all cookies", async ({ base, cookies }) => {
    await test.step("Open main page", async() => {
        await base.openMainPage();

    await test.step("Accept all cookies", async() => {
        await cookies.acceptAllCookies();

    await test.step("Verify that cookies are not displayed", async() => {
        await expect(cookies.acceptAllCookiesButton).toBeVisible();

Problem is: When I have toBeVisible() - test passed. and when I have not.toBeVisible() - test also passed.

Why ? 🙂 What I should change ?

This thread is trying to answer question "Why do both toBeVisible() and not.toBeVisible() pass in the test case?"

4 replies

It depends on the implementation of the button.Sometimes the buttons stays on the DOM but a class is added to it to make it be hidden. My 2 cents would be that you go look at the DOM when the button is hidden and search for the locator and see if it has the hidden class on it or not


You might try using WaitForSelector() and then expect to be visible.

I guess when you click accept all btn the cookies bar still not close yet and takes about 0.5-1s to be hidden -> toBeVisible still pass. You can put a wait before to debug

This is a pretty generic case of negative expectations in test automation. A good rule of thumb is to add a positive expectation before a negative one.

For example your call to acceptAllCookies() (which I'm assuming is a pretty basic button click?) could allow for the button to be visible in the DOM for any duration of time. So based on your timeout settings, a not expectation would potentially wait up to that timeout for the button to disappear, whereas .toBeVisible() could pass even if the button is displayed for a split second.


Understanding toBeVisible() and not.toBeVisible() in Playwright

In Playwright, toBeVisible() and not.toBeVisible() are web first assertions. They ensure your tests are reliable by waiting for expected conditions to be met before proceeding.

The toBeVisible() Assertion

When you use toBeVisible(), Playwright waits until the expected condition is met. For instance, if your test clicks a button and expects an alert message to appear, toBeVisible() waits for the alert message to be visible before proceeding.

import { test } from '@playwright/test';

test('alert should be visible', async ({ page }) => {
  await page.goto('https://ray.run');
  await page.click('#alertButton');
  await expect(page.locator('#alertMessage')).toBeVisible();

The not.toBeVisible() Assertion

On the contrary, manual assertions like isVisible() don't wait for any condition. They simply check if the locator is there and return immediately. This means that if you use expect(await page.getByText('welcome').isVisible()).toBe(true), it may return true even if the element is not actually visible.

import { test } from '@playwright/test';

test('welcome text should not be visible', async ({ page }) => {
  await page.goto('https://ray.run');
  await expect(await page.getByText('welcome').isVisible()).toBe(true);

In summary, toBeVisible() and not.toBeVisible() pass because they utilize web first assertions provided by Playwright. They ensure your tests wait until expected conditions are met before proceeding.

Related Discord Threads

AboutQuestionsDiscord ForumBrowser ExtensionTagsQA Jobs

Rayrun is a community for QA engineers. I am constantly looking for new ways to add value to people learning Playwright and other browser automation frameworks. If you have feedback, email luc@ray.run.