playwright
playwright copied to clipboard
[Feature] Allow to set launchPersistentContext in playwright.config file
Note from maintainers
If you are here for Chrome Extensions testing, take a look at this guide.
On one of our projects, we need to run tests with extensions. To launch extensions, we have to set browserType.launchPersistentContext
in the beforeAll
section of each test.
It would be convenient to set launchPersistentContext
in a playwright.config
file, for instance:
use: {
launchPersistentContext: {
userDataDir: '/tmp/test-user-data-dir',
args: [
`--disable-extensions-except=${path.join(__dirname, './my-extension')}`,
`--load-extension=${path.join(__dirname, './my-extension')}`
]
}
}
Yesterday, I also started an attempt to use Playwright Test for writing E2E tests for a Chrome Extension. But because the browser (by default) is launched in incognito, extensions don't work.
It would be very helpful if it was made possible to define the browser(s) to launch with a persistent context. And/or in a more generic way, if it was possible to add a way to use a (factory) function that returns a browser instance upon invoking. Something like:
// playwright.config.ts
import { PlaywrightTestConfig, devices } from '@playwright/test';
const config: PlaywrightTestConfig = {
projects: [
{
name: 'chromium-from-a-factory-fn',
use: () => { // returns a browser instance when invoked },
},
],
};
export default config;
@serembon I would be interested in how you set the browserType.launchPersistentContext
in the beforeAll
section of each test. Could you show an example?
@schmkr Extension should be unpacked. Here is an example:
test.describe('Open Chrome with loaded extension', () => {
let context: BrowserContext;
let page: Page;
test.beforeAll(async () => {
context = await chromium.launchPersistentContext('/tmp/test-user-data', {
headless: false,
channel: 'chrome',
args: [
`--disable-extensions-except=${path.join(__dirname, '../files/my-extenstion')}`,
`--load-extension=${path.join(__dirname, '../files/my-extenstion')}`,
],
});
page = await context.newPage();
});
test('Open extensions page', async () => {
await page.goto('chrome://extensions/');
await page.pause();
});
});
This would be a major improvement for us, we've been watching the numerous requests on this topic as it would unlock the opportunity to use Playwright for our needs, where we can't at the moment.
Have a similar issue but a different problem) I want to implement playwright component testing in my team, and playwright gives us excellent developer experience. But there is one missing point for me. When I debug my test, the browser opens in incognito mode, and I can not open vue devtools to debug my component.
This would be a huge feature for the project I am working on as well. The ability to globally not be in incognito mode is mission critical.
I would like to:
- Share the solution I found building on @pitops's code from How to load a chrome extension in playwright
- Offer to create a PR to add this to the docs
--
Here's the solution I've found that should help.
We can add an option to the Playwright configuration file using the "option" fixtures. This allows us to declare what extensions to load in the configuration file once.
The page
, context
, and browser
provided to each test are called test fixtures. Using test.extend
we can create a new test
object that modifies the context, calling launchPersistentContext
and loading the extensions. Any tests that want to use the Chrome extensions must import test
from a test fixture, otherwise the extensions are not loaded.
--
Let's start with the configuration file. The chromeExtensions
"option" fixture allows us to set the optional userDataDir
and paths
to the extensions to load:
playwright.config.ts
import { join } from 'path';
import type { PlaywrightTestConfig } from '@playwright/test';
import { ChromeExtensionOptions } from './tests/fixtures/chrome-extension';
const config: PlaywrightTestConfig<ChromeExtensionOptions> = {
// ^
// Provide types for the "option" fixture
projects: [
{
use: {
browserName: 'chromium',
chromeExtensions: {
paths: [join(__dirname, 'example-extension')],
},
// ^
// Provide the paths to one or more extensions. On MacOS, spaces in paths are handled OK.
},
},
],
};
export default config;
--
The test fixture extends the test
object to add the chromeExtensions
option and modifies the context
to start the browser with the expected extensions in headed mode:
tests/fixtures/chrome-extension.ts
import { test as base, chromium } from "@playwright/test";
export type ChromeExtensionOptions = {
chromeExtensions: {
paths: Array<string>;
userDataDir?: string;
};
};
export const test = base.extend<ChromeExtensionOptions>({
chromeExtensions: [{ paths: [] }, { option: true }],
context: [
async ({ chromeExtensions }, use) => {
const { paths, userDataDir = "" } = chromeExtensions;
const launchOptions = {
headless: false,
args:
paths.length === 0
? []
: [
`--disable-extensions-except=${paths.join(",")}`,
...paths.map((path) => `--load-extension=${path}`),
],
};
const context = await chromium.launchPersistentContext(
userDataDir,
launchOptions
);
await use(context);
await context.close();
},
{ scope: "test", timeout: 2_500 },
// ^
// This is my preference. The default 30s timeout is too long to wait if there is a manifest issue.
],
});
--
To write a test using the Chrome extensions, import test
from the test fixture:
tests/example.spec.ts
- import { test, expect } from '@playwright/test';
+ import { expect } from '@playwright/test';
+ import { test } from './fixtures/chrome-extension';
test('The Chrome extension should be visible on the Extensions page', async ({ page }) => {
Feature request reached 65 likes. Any chance of being included in upcoming releases?
Everybody: there's now a new doc for chrome extension testing fixture: https://playwright.dev/docs/next/chrome-extensions#testing
Does it solve all your issues? Let us know if not!
I need this feature not only for extensions testing, but mainly to run browser in non-incognito mode (without browser setup in tests). I really hope it'll be implemented soon.
@schmkr Extension should be unpacked. Here is an example:
test.describe('Open Chrome with loaded extension', () => { let context: BrowserContext; let page: Page; test.beforeAll(async () => { context = await chromium.launchPersistentContext('/tmp/test-user-data', { headless: false, channel: 'chrome', args: [ `--disable-extensions-except=${path.join(__dirname, '../files/my-extenstion')}`, `--load-extension=${path.join(__dirname, '../files/my-extenstion')}`, ], }); page = await context.newPage(); }); test('Open extensions page', async () => { await page.goto('chrome://extensions/'); await page.pause(); }); });
In my case I'm able to launch and open the extension in chrome tab, but when I try to hit my website (google.com), the google.com page loads first and then the extension page loads, therefore I'm not able to switch back to the google.com page and work on it. Somehow the extension page blocks. How did you swicth back to the previous page after loading extension? Here;s my code :
import { test as base, expect, chromium } from '@playwright/test';
import path from 'path';
const extensionPath = path.join(__dirname, '../Myextensions/nkbihfbeogaeaoehlefnkodbefgpgknn/10.23.2_0') // make sure this is correct
const test = base.extend({
context: async ({ browserName }, use) => {
const browserTypes = {chromium}
const launchOptions = {
headless: false,
args: [
--disable-extensions-except=${extensionPath}
],
viewport: {
width: 1920,
height: 1080
}
}
const context = await browserTypes[browserName].launchPersistentContext(
'',
launchOptions
)
await use(context)
} })
test('Google page loads', async ({ page }) => { await page.waitForLoadState(); await page.goto( 'https://google.com/' ) // Click the button
await page.click('.btn-primary');
await page.waitForTimeout(3000) // this is here so that it won't automatically close the browser window
})
It would be really helpful having the possibility to set launchPersistentContext in the playwright.config file.
It would be really helpful having the possibility to set launchPersistentContext in the playwright.config file.
Yes this would be a big improvement. I also think it should be configurable on project level. Since projects are often used to test different user agents they might need different treatment.
Agree with the comments above on incorporating a flag into the playwright.config file. We use web workers to load specific data across the application. The web worker requests are not intercepted correctly in incognito mode. Ideally a flag is made available to turn off incognito for a whole playwright project. Seems like this has been a request for over a year. Can we see some progress?
To better help you with configuring the persistent context, we would like to know how and why you use it. Please upvote a respective comment below, or reply with your own version.
- Using persistent context to test a Chrome extension.
- Using persistent context to test a page with some extension installed.
- Using persistent context for some other reason (please specify).
- Need a separate persistent context for each test - slower but isolated.
- Need a single persistent context for each file/project - faster but tests are not isolated.
Please upvote this comment if you are using persistent context to test a Chrome extension.
Please upvote this comment if you are using persistent context to test a page with some extension installed.
Please upvote this comment if you are using persistent context for some other reason. Reply explaining your specific use case if possible.
Please upvote this comment if you need a separate persistent context for each test - slower but isolated.
Please upvote this comment if you need a single persistent context for each file/project - faster but tests are not isolated.
Thank you @dgozman for looking into this. I have upvoted both "Using persistent context to test a Chrome extension." and "Using persistent context to test a page with some extension installed.", although I was not completely sure how they are different?
When you want to test a Chrome Extension, that testing happens on a page anyway, right? Or maybe I don't understand what the difference is between them?
For context, our use case is we develop a Chrome Extension that interacts with Gmail. So we want to test that extension within Gmail.
Everybody: please vote in this poll so that we can react accordingly!
Please upvote this comment if you are using persistent context for some other reason. Reply explaining your specific use case if possible.
I am using persistent context to download pdf files. In non persistent context if i click on the button to download the pdf then in that case the pdf is not download and instead its is opened in chrome's internal pdf viewer.
with persistent context i am able to pass the arguments which doesn't let chrome open the pdf and forces it to download it
We could use a persistent context to be able to download a pdf and save the file, which apparently isn't working in incognito mode, and then open the pdf using pdf2json to validate the contents. I'll continue trying to see why incognito mode isn't always saving the file but I suspect this is why.
Everybody: please vote in https://github.com/microsoft/playwright/issues/11833#issuecomment-1635088534 so that we can react accordingly!
Please upvote this comment if you are using persistent context for some other reason. Reply explaining your specific use case if possible.
@dgozman Testing chrome extensions for multiple contexts (=> incognito mode). Requires changing settings at "chrome://extensions" automated. That url however can only be accessed outside of incognito:)
2 years passed. Are there any plans to solve this?