diff --git a/packages/playwright-core/src/server/frames.ts b/packages/playwright-core/src/server/frames.ts
index c1a23f100f..85239919fe 100644
--- a/packages/playwright-core/src/server/frames.ts
+++ b/packages/playwright-core/src/server/frames.ts
@@ -1381,9 +1381,10 @@ export class Frame extends SdkObject {
private async _expectInternal(metadata: CallMetadata, selector: string, options: FrameExpectParams, oneShot: boolean, timeout: number, lastIntermediateResult: { received?: any, isSet: boolean }): Promise<{ matches: boolean, received?: any, log?: string[], timedOut?: boolean }> {
const controller = new ProgressController(metadata, this);
return controller.run(async progress => {
- if (oneShot)
+ if (oneShot) {
progress.log(`${metadata.apiName}${timeout ? ` with timeout ${timeout}ms` : ''}`);
- progress.log(`waiting for ${this._asLocator(selector)}`);
+ progress.log(`waiting for ${this._asLocator(selector)}`);
+ }
return await this.retryWithProgressAndTimeouts(progress, [100, 250, 500, 1000], async continuePolling => {
const selectorInFrame = await this.selectors.resolveFrameForSelector(selector, { strict: true });
progress.throwIfAborted();
diff --git a/tests/page/expect-misc.spec.ts b/tests/page/expect-misc.spec.ts
index 9bb771858d..afdb8e8803 100644
--- a/tests/page/expect-misc.spec.ts
+++ b/tests/page/expect-misc.spec.ts
@@ -341,3 +341,32 @@ test.describe('toBeInViewport', () => {
await expect(page.locator('h1')).toBeInViewport();
});
});
+
+test('toHaveCount should not produce logs twice', async ({ page }) => {
+ await page.setContent('One ');
+ const error = await expect(page.locator('option')).toHaveCount(2, { timeout: 2000 }).catch(e => e);
+ const waitingForMessage = `waiting for locator('option')`;
+ expect(error.message).toContain(waitingForMessage);
+ expect(error.message).toContain(`locator resolved to 1 element`);
+ expect(error.message).toContain(`unexpected value "1"`);
+ expect(error.message.replace(waitingForMessage, '')).not.toContain(waitingForMessage);
+});
+
+test('toHaveText should not produce logs twice', async ({ page }) => {
+ await page.setContent('hello
');
+ const error = await expect(page.locator('div')).toHaveText('world', { timeout: 2000 }).catch(e => e);
+ const waitingForMessage = `waiting for locator('div')`;
+ expect(error.message).toContain(waitingForMessage);
+ expect(error.message).toContain(`locator resolved to hello
`);
+ expect(error.message).toContain(`unexpected value "hello"`);
+ expect(error.message.replace(waitingForMessage, '')).not.toContain(waitingForMessage);
+});
+
+test('toHaveText that does not match should not produce logs twice', async ({ page }) => {
+ await page.setContent('hello
');
+ const error = await expect(page.locator('span')).toHaveText('world', { timeout: 2000 }).catch(e => e);
+ const waitingForMessage = `waiting for locator('span')`;
+ expect(error.message).toContain(waitingForMessage);
+ expect(error.message).not.toContain('locator resolved to');
+ expect(error.message.replace(waitingForMessage, '')).not.toContain(waitingForMessage);
+});