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

[Feature] Make test execution speed (option slowMo) adjustable during test execution #5900

Closed
klhex opened this issue Mar 22, 2021 · 23 comments

Comments

@klhex
Copy link
Contributor

klhex commented Mar 22, 2021

Currently, you can only artificially lower Playwright's execution speed for the entirety of a test execution, using the browserType.launch option "slowMo" (see https://playwright.dev/docs/api/class-browsertype#browsertypelaunchoptions):

image

However, in many debugging situations you're only interested in watching Playwright doing it slowly during specific parts of your test while the remainder of your test execution could very well be executed at normal (warp) speed in order to save your precious test development/debugging time (e.g. you're testing an app consisting of 6 pages and you only want to watch the last page being tested in slow motion).

Therefore, it would be very handy if you could slow Playwright temporarily down for specific parts of your test code only, for example via await page.slow(30) and then resetting it via await page.slow(0) or something comparable.

@thernstig
Copy link
Contributor

That sounds great! Could be used with the Inspector if one has also set await page.paus() to then directly in the Inspector set the slow speed (without even having to use await page.slow(30). I.e. you could use that, but when you hit that location the Inspector has a field where you see the normal speed change to 30, but you can then also further change it if wanted to another speed direclty.

@klhex klhex changed the title [Feature] Make slowMo adjustable during text execution [Feature] Make slowMo adjustable during test execution Mar 22, 2021
@klhex
Copy link
Contributor Author

klhex commented Mar 22, 2021

Actually, API-wise, maybe something like page.debug( { slowMo: 60 } ) would be better in order to cater for future debug-related options.

@thernstig
Copy link
Contributor

If so, then I assume page.pause() should be put into that as well. I'd maybe rather have page.debug.slowMo(60) then as I find it faster to type and easier for auto-completion. But I suppose all this is up to the Playwright peeps :)

@klhex
Copy link
Contributor Author

klhex commented Mar 22, 2021

@thernstig Yes, indeed, in that case it would make sense to integrate page.pause() into page.debug(...) as well, good hint!

@LanderBeeuwsaert
Copy link

Jep, for us, a slowMo per page + (optionally that you can set dynamically) would be what we are looking for.

@klhex klhex changed the title [Feature] Make slowMo adjustable during test execution [Feature] Make test execution speed (option slowMo) adjustable during test execution Apr 22, 2021
@tommyh
Copy link

tommyh commented Jul 28, 2021

While this is collecting feedback, I'd like to discuss something related: it'd be amazing if I could have a set of configuration options which automatically get called when I call page.pause().

Use-case: I call pause so that I can experiment and figure out the best selector for an element. I will be poking around the page and the test fails because it hits the 30 second timeout. Right now, I either disable the timeout on the cli npx playwright test --timeout=0 or I set the test timeout in the test:

const { test, expect } = require('@playwright/test');

test('my test name here', async ({ page }) => {
  await page.goto('http://example.com');

  test.setTimeout(0);
  await page.pause();
});

Example implementation:

module.exports = {
   timeout: 30000,
   pauseOptions: {
      timeout: 0,
      slowMo: 200,
   },
};

@raptoria
Copy link

raptoria commented Sep 7, 2021

+1. the above would be awesome ^

@ani-im
Copy link

ani-im commented Mar 3, 2022

Do you have any updates deadlines for this?

@Zoltanpetrik
Copy link

It seems like this affects typing into input fields, so a slowmo of 2000 makes typing extremely slow.

Overriding typing speed is not possible with this parameter:

*locator*.type(text, {
  delay: 10
})

@alexn-s
Copy link

alexn-s commented Apr 27, 2022

would be really helpful +1

@ivanvison
Copy link

Definitely a must! +1
Currently getting trained in Playwright and my training lead me here.

@klhex
Copy link
Contributor Author

klhex commented May 13, 2022

Since this issue is approaching is first birthday, I'm using this opportunity to ping @pavelfeldman, @arjunattam and @mxschmitt to highlight people's interest in this feature. 👀 🙏

@aardvarkk
Copy link

Here's a hack I wrote to get this functionality going without any changes required to the Playwright codebase.

For context, I wanted to "slow down" certain operations in the tests so I could record videos that didn't blaze through the operations so they could be used to show people for training purposes.

Waiting per-operation is easy in a test by just wrapping the request in a Promise that delays a certain amount of time, but I wanted to be able to enable/disable the delay with a small code change instead of having to change every line of the test to wait a certain amount of time.

Here's what I came up with (it's in TypeScript). It wraps the page.locator function with a version that replaces click and fill to be artificially slowed.

import { Locator, Page } from "@playwright/test";

// Return a "slow" page locator that waits before 'click' and 'fill' requests
function slowLocator(
  page: Page,
  waitInMs: number
): (...args: any[]) => Locator {
  // Grab original
  const l = page.locator.bind(page);

  // Return a new function that uses the original locator but remaps certain functions
  return (locatorArgs) => {
    const locator = l(locatorArgs);

    locator.click = async (args) => {
      await new Promise((r) => setTimeout(r, waitInMs));
      return l(locatorArgs).click(args);
    };

    locator.fill = async (args) => {
      await new Promise((r) => setTimeout(r, waitInMs));
      return l(locatorArgs).fill(args);
    };

    return locator;
  };
}

Now, I just put this at the start of my test:

test("sample test", async ({ page }) => {
  // Overwrite page.locator to give us back a version that waits 500ms before `click` and `fill`
  page.locator = slowLocator(page, 500);

  await page.locator('input).fill();
  await page.locator('button').click();
});

It should be pretty trivial to add delays to methods on the locator other than click and fill by following the pattern.

Now if you want the original/fast version of the locator, just comment out the one line that resets the page.locator and you get back your speedy tests. If you want to record a slowed-down video you can just uncomment the line (or add it in temporarily) to get a more relaxed version.

@krishnaaSundaram-QaStack-1989
page.locator = slowLocator(page, 500);

Can I get the same for expect assertions with tobevisible or tobeenabled combination

@luucamay
Copy link

does anyone know if this feature has been added to the options when running test from command line?

@snackattas
Copy link

Here's a hack I wrote to get this functionality going without any changes required to the Playwright codebase.

For context, I wanted to "slow down" certain operations in the tests so I could record videos that didn't blaze through the operations so they could be used to show people for training purposes.

Waiting per-operation is easy in a test by just wrapping the request in a Promise that delays a certain amount of time, but I wanted to be able to enable/disable the delay with a small code change instead of having to change every line of the test to wait a certain amount of time.

Here's what I came up with (it's in TypeScript). It wraps the page.locator function with a version that replaces click and fill to be artificially slowed.

import { Locator, Page } from "@playwright/test";

// Return a "slow" page locator that waits before 'click' and 'fill' requests
function slowLocator(
  page: Page,
  waitInMs: number
): (...args: any[]) => Locator {
  // Grab original
  const l = page.locator.bind(page);

  // Return a new function that uses the original locator but remaps certain functions
  return (locatorArgs) => {
    const locator = l(locatorArgs);

    locator.click = async (args) => {
      await new Promise((r) => setTimeout(r, waitInMs));
      return l(locatorArgs).click(args);
    };

    locator.fill = async (args) => {
      await new Promise((r) => setTimeout(r, waitInMs));
      return l(locatorArgs).fill(args);
    };

    return locator;
  };
}

Now, I just put this at the start of my test:

test("sample test", async ({ page }) => {
  // Overwrite page.locator to give us back a version that waits 500ms before `click` and `fill`
  page.locator = slowLocator(page, 500);

  await page.locator('input).fill();
  await page.locator('button').click();
});

It should be pretty trivial to add delays to methods on the locator other than click and fill by following the pattern.

Now if you want the original/fast version of the locator, just comment out the one line that resets the page.locator and you get back your speedy tests. If you want to record a slowed-down video you can just uncomment the line (or add it in temporarily) to get a more relaxed version.

Do you know if there's a way to do this with the python bindings?

@ATARARHRB
Copy link

+1 for this issue. I'm using getAttribute to get all the attributes of 90+ elements to verify if they are filled in or not, while the rest is just ordinary navigating and clicking. The getAttribute loop grinds to a halt with a slowmo of 1 second, while the rest could benefit from taking a second to be able to see what is going on. Being able to selectively pass a slowmo for a test step or certain sections would be useful rather than having to toggle it for a test.

@MobileTester
Copy link

Here's a hack I wrote to get this functionality going without any changes required to the Playwright codebase.

For context, I wanted to "slow down" certain operations in the tests so I could record videos that didn't blaze through the operations so they could be used to show people for training purposes.

Waiting per-operation is easy in a test by just wrapping the request in a Promise that delays a certain amount of time, but I wanted to be able to enable/disable the delay with a small code change instead of having to change every line of the test to wait a certain amount of time.

Here's what I came up with (it's in TypeScript). It wraps the page.locator function with a version that replaces click and fill to be artificially slowed.

import { Locator, Page } from "@playwright/test";

// Return a "slow" page locator that waits before 'click' and 'fill' requests
function slowLocator(
  page: Page,
  waitInMs: number
): (...args: any[]) => Locator {
  // Grab original
  const l = page.locator.bind(page);

  // Return a new function that uses the original locator but remaps certain functions
  return (locatorArgs) => {
    const locator = l(locatorArgs);

    locator.click = async (args) => {
      await new Promise((r) => setTimeout(r, waitInMs));
      return l(locatorArgs).click(args);
    };

    locator.fill = async (args) => {
      await new Promise((r) => setTimeout(r, waitInMs));
      return l(locatorArgs).fill(args);
    };

    return locator;
  };
}

Now, I just put this at the start of my test:

test("sample test", async ({ page }) => {
  // Overwrite page.locator to give us back a version that waits 500ms before `click` and `fill`
  page.locator = slowLocator(page, 500);

  await page.locator('input).fill();
  await page.locator('button').click();
});

It should be pretty trivial to add delays to methods on the locator other than click and fill by following the pattern.

Now if you want the original/fast version of the locator, just comment out the one line that resets the page.locator and you get back your speedy tests. If you want to record a slowed-down video you can just uncomment the line (or add it in temporarily) to get a more relaxed version.

Is it possible to write similar wrapper for getByRole ?

@edelreal
Copy link

When running a test manually and watching the browser in headed mode, it would be very convenient to set the "speed" (slowMo) in the command line, rather than editing the test or creating a config file.

@vitalets
Copy link
Contributor

vitalets commented Sep 8, 2023

does anyone know if this feature has been added to the options when running test from command line?

This is my workaround to automatically set slowMo when running in --headed mode (that is usually helpful):

export default defineConfig({
  use: {
    launchOptions: { 
      slowMo: isHeadedMode() ? 1000 : undefined
    }
  }
});

function isHeadedMode() {
  // important to use env var - for workers
  if (process.argv.includes('--headed')) process.env.HEADED_MODE = '1';
  return Boolean(process.env.HEADED_MODE);
}

@jshet
Copy link

jshet commented Nov 10, 2023

Has anyone solved this with Python?

@basickarl
Copy link

Bumping, this would be super useful. I currently have concurrent process happening. I have a MutationObserver that looks for DOM changes and then takes a screenshot via an exposed function. The screenshot however is too slow as the UI changes and updates the UI. I'd like a hook or setting that would be able to slow down all commands except the screenshot which is running in another thread.

@mxschmitt
Copy link
Member

mxschmitt commented Sep 25, 2024

Closing for now since we offer better tools for debugging and recommend these instead of extending the slowMo API which is often misused to "fix" flaky/racy tests:

  • Playwright Trace Viewer: This one allows you to debug local and remote tests including full snapshot and screenshots to see how the page behaved.
  • Visual Studio Code extension: This one allows you to run tests and set breakpoints during the test execution and inspect the actual page state.
  • Using page.pause(): This one will pause the test execution and open the Playwright Inspector to inspect the page state. Inspect and Verify Locators etc.

For slowing down videos, we recommend instead looking at a specific Trace. You can upload the zip at trace.playwright.dev and they contain many more information, including network, console, snapshot, screenshot, actions etc.

@mxschmitt mxschmitt closed this as not planned Won't fix, can't repro, duplicate, stale Sep 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests