diff --git a/packages/playwright-core/src/server/frames.ts b/packages/playwright-core/src/server/frames.ts index 400f3881fd..473b11254f 100644 --- a/packages/playwright-core/src/server/frames.ts +++ b/packages/playwright-core/src/server/frames.ts @@ -1181,6 +1181,11 @@ export class Frame extends SdkObject { if (options.expression.endsWith('.array') && expectsEmptyList !== options.isNot) return { matches: expectsEmptyList }; + // expect(listLocator).toHaveCount(0) passes when there are no elements matching. + // expect(listLocator).not.toHaveCount(1) passes when there are no elements matching. + if (options.expression === 'to.have.count') + return { matches: options.expectedNumber === 0, received: options.expectedNumber }; + // When none of the above applies, keep waiting for the element. return continuePolling; } diff --git a/tests/playwright-test/playwright.expect.misc.spec.ts b/tests/playwright-test/playwright.expect.misc.spec.ts index 9ccb38fc56..4986a82ae4 100644 --- a/tests/playwright-test/playwright.expect.misc.spec.ts +++ b/tests/playwright-test/playwright.expect.misc.spec.ts @@ -33,10 +33,41 @@ test('should support toHaveCount', async ({ runInlineTest }) => { await promise; expect(done).toBe(true); }); + + test('pass zero', async ({ page }) => { + await page.setContent('
'); + const locator = page.locator('span'); + await expect(locator).toHaveCount(0); + await expect(locator).not.toHaveCount(1); + }); + + test('eventually pass zero', async ({ page }) => { + await page.setContent(''); + const locator = page.locator('span'); + setTimeout(() => page.evaluate(() => div.textContent = '').catch(() => {}), 200); + await expect(locator).toHaveCount(0); + await expect(locator).not.toHaveCount(1); + }); + + test('fail zero', async ({ page }) => { + await page.setContent('