Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix underlying frame.waitForSelector #1534

Merged
merged 2 commits into from
Nov 12, 2024
Merged

Fix underlying frame.waitForSelector #1534

merged 2 commits into from
Nov 12, 2024

Conversation

ankur22
Copy link
Collaborator

@ankur22 ankur22 commented Nov 11, 2024

What?

This fixes an issue with APIs that use the underlying frame.waitForSelector. It does this by reusing frame.waitFor which contains a fix to retry on certain errors which can occur when a navigation is taking place while also waiting for the selector.

Why?

This makes several APIs more robust when called during or after a navigation to a new page. I believe the list covers most of the APIs that this fix applies to:

  • frame.WaitForSelector
  • locator.IsChecked
  • locator.DispatchEvent
  • locator.Fill
  • locator.Focus
  • locator.GetAttribute
  • locator.InnerHTML
  • locator.InnerText
  • locator.InputValue
  • locator.IsEditable
  • locator.IsEnabled
  • locator.IsDisabled
  • locator.Press
  • locator.SelectOption
  • frame.SetInputFiles
  • page.TextContent
  • locator.Type
  • locator.Click
  • locator.Check
  • locator.SetChecked
  • locator.Uncheck
  • locator.DblClick
  • locator.Hover
  • locator.Tap
Tests that works with fix (but not without)

Test that used to fail on reading the textContent of the h2 header.

import { browser } from 'k6/browser';
import { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';

export const options = {
  scenarios: {
    ui: {
      executor: 'shared-iterations',
      options: {
        browser: {
            type: 'chromium',
        },
      },
    },
  },
  thresholds: {
    checks: ["rate==1.0"]
  }
}

export default async function() {
  const context = await browser.newContext();
  const page = await context.newPage();

  try {
    await page.goto('https://test.k6.io/', { waitUntil: 'networkidle' });

    const wait1 = page.locator('input[name="login"]').waitFor();
    await page.locator('a[href="/my_messages.php"]').click()
    await wait1;

    await page.locator('input[name="login"]').type('admin');
    await page.locator('input[name="password"]').type("123");

    const wait2 = page.locator('h2').waitFor();
    await page.locator('input[type="submit"]').click();
    await wait2;

    await check(page.locator('h2'), {
      'header': async lo => {
        return await lo.textContent() == 'Welcome, admin!'
      }
    });
  } finally {
    await page.close();
  }
}

Test that used to fail when working with waitForSelector.

import { browser } from 'k6/browser';
import { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';

export const options = {
  scenarios: {
    ui: {
      executor: 'shared-iterations',
      options: {
        browser: {
            type: 'chromium',
        },
      },
    },
  },
  thresholds: {
    checks: ["rate==1.0"]
  }
}

export default async function() {
  const context = await browser.newContext();
  const page = await context.newPage();

  try {
    await page.goto('https://test.k6.io/', { waitUntil: 'networkidle' });

    const wait1 = page.waitForSelector('input[name="login"]');
    await page.locator('a[href="/my_messages.php"]').click()
    await wait1;

    await page.locator('input[name="login"]').type('admin');
    await page.locator('input[name="password"]').type("123");

    const wait2 = page.waitForSelector('h2');
    await page.locator('input[type="submit"]').click();
    await wait2;

    await check(page.locator('h2'), {
      'header': async lo => {
        return await lo.textContent() == 'Welcome, admin!'
      }
    });
  } finally {
    await page.close();
  }
}

Checklist

  • I have performed a self-review of my code
  • I have added tests for my changes
  • I have commented on my code, particularly in hard-to-understand areas

Related PR(s)/Issue(s)

Related: #1469
Fixes: grafana/k6#4048

@ankur22 ankur22 requested a review from a team as a code owner November 11, 2024 15:39
@ankur22 ankur22 requested review from inancgumus and joanlopez and removed request for a team November 11, 2024 15:39
@ankur22 ankur22 marked this pull request as draft November 11, 2024 15:39
@ankur22 ankur22 marked this pull request as ready for review November 11, 2024 15:43
@ankur22 ankur22 force-pushed the fix/waitForSelector branch from de7dce3 to 765868c Compare November 11, 2024 15:43
Copy link
Member

@inancgumus inancgumus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🚀

The fix requires the reuse of waitFor, but it also requires the handle
value to be returned. This refactors waitFor to return Handle.
The fix is in waitFor, and waitForSelector just needs to call waitFor
to enable the fix.

It basically will auto retry up to 20 times when certain errors are
received from chrome. This can happens when the underlying DOM is
changing due to a navigation, and the expected element that matches the
selector is in the newly navigated DOM.
@ankur22 ankur22 force-pushed the fix/waitForSelector branch from 765868c to 982cab9 Compare November 12, 2024 10:38
@ankur22 ankur22 merged commit 1974b8a into main Nov 12, 2024
23 checks passed
@ankur22 ankur22 deleted the fix/waitForSelector branch November 12, 2024 13:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

k6/browser does not able to handle multiple navigations when script click on a link or button
2 participants