Skip to content

Commit 8f4200b

Browse files
committed
feat: replace Puppeteer with Playwright
Playwright offers better auto-waiting, a more intuitive locator-based API, and built-in debugging tools like trace viewer and inspector. Puppeteer's auto-download of Chrome via postinstall scripts poses security risks. Key changes: - Add "sf browserforce playwright" wrapper command - Use locators instead of selectors and eliminate evaluate() calls - Leverage "await using" for automatic page cleanup - Enable trace capture via BROWSERFORCE_TRACE - Increase viewport to 1280x1536 to reduce scrolling - Re-enable Slack and UserAccessPolicies tests Huge kudos to @itkevin for initiating this migration and providing documentation! Closes #706 Co-authored-by: Kevin Lindecke <kevin@lindecke.co> BREAKING CHANGE: Puppeteer has been replaced with Playwright. Browsers are no longer installed automatically. Install a browser explicitly: ```shell sf browserforce playwright -- install chromium ``` Or configure an existing browser via any of these environment variables: ```shell BROWSERFORCE_BROWSER_CHANNEL="chrome" BROWSERFORCE_BROWSER_EXECUTABLE_PATH="/usr/bin/google-chrome" CHROME_BIN="/usr/bin/google-chrome" ```
1 parent a8da2e7 commit 8f4200b

File tree

94 files changed

+4387
-4309
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+4387
-4309
lines changed

.github/workflows/default.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ jobs:
2929
run: |
3030
npm ci --ignore-scripts
3131
npm install --ignore-scripts --global @salesforce/cli@${SF_CLI_VERSION:-"latest"}
32-
npx puppeteer browsers install chrome
3332
- name: Run unit tests
3433
run: npm run test
3534
- name: Check formatting
@@ -46,6 +45,15 @@ jobs:
4645
if: always()
4746
run: |
4847
sf org delete scratch --no-prompt
48+
- name: Upload Playwright traces
49+
if: always()
50+
uses: actions/upload-artifact@v6
51+
with:
52+
name: playwright-traces
53+
path: trace-*.zip
54+
compression-level: 0
55+
if-no-files-found: ignore
56+
retention-days: 14
4957
release:
5058
needs: test
5159
if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/next' }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ coverage/
1414
.vscode/settings.json
1515

1616
/oclif.manifest.json
17+
18+
# Playwright traces
19+
trace-*.zip

CONTRIBUTING.md

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
2222
```shell
2323
npm ci
24+
npx playwright install chromium
2425
```
2526

2627
## Scaffolding a new plugin
@@ -31,7 +32,7 @@ Please note that this is only an example. In fact this is supported in the Metad
3132
You can scaffold a new plugin by running:
3233

3334
```shell
34-
npm run generate:plugin --name AdminsCanLogInAsAnyUser
35+
npm run generate:plugin -- --name AdminsCanLogInAsAnyUser
3536
```
3637

3738
Bravo 👏, you have just generated a working browserforce plugin!
@@ -56,8 +57,8 @@ npm run develop
5657
and now we can run it:
5758

5859
```shell
59-
BROWSER_DEBUG=true ./bin/run browserforce apply -f src/plugins/admins-can-log-in-as-any-user/enable.json
60-
BROWSER_DEBUG=true ./bin/run browserforce apply -f src/plugins/admins-can-log-in-as-any-user/disable.json
60+
BROWSERFORCE_HEADLESS=false ./bin/run browserforce apply -f src/plugins/admins-can-log-in-as-any-user/enable.json
61+
BROWSERFORCE_HEADLESS=false ./bin/run browserforce apply -f src/plugins/admins-can-log-in-as-any-user/disable.json
6162
```
6263

6364
> [!TIP]
@@ -133,8 +134,8 @@ This allows to run multiple actions (from multiple plugins) using a single confi
133134

134135
Plugins are written in [Typescript](https://www.typescriptlang.org), just like `sf` and most of the available sf plugins.
135136

136-
[Puppeteer](https://pptr.dev) is being used as a library for browser automation.
137-
If you need more inspiration regarding Puppeteer, checkout [this curated list](https://github.com/transitive-bullshit/awesome-puppeteer) of awesome Puppeteer resources.
137+
[Playwright](https://playwright.dev) is being used as a library for browser automation.
138+
If you need more inspiration regarding Playwright, checkout the [official documentation](https://playwright.dev/docs/intro) and our [best practices guide](./docs/PLAYWRIGHT.md).
138139

139140
The simplified browserforce plugin lifecycle can be described as follows
140141

@@ -196,3 +197,41 @@ for i in {1..7}; do npm run test:e2e -- -g "AdminsCanLogInAsAnyUser"; done
196197
## Debugging
197198

198199
The [Salesforce CLI Plug-In Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_plugins.meta/sfdx_cli_plugins/cli_plugins_debug.htm) describes debugging sfdx plugins using VS Code very well.
200+
201+
### Playwright Debugging and Tracing
202+
203+
When developing or debugging Playwright-based plugins, you have several tools at your disposal:
204+
205+
#### Visual Debugging
206+
207+
To see the browser while tests run:
208+
209+
```bash
210+
BROWSERFORCE_HEADLESS=false npm run test:e2e -- --grep "YourPlugin"
211+
```
212+
213+
To slow down execution for better observation (value in milliseconds):
214+
215+
```bash
216+
BROWSERFORCE_SLOWMO=1000 npm run test:e2e -- --grep "YourPlugin"
217+
```
218+
219+
#### Playwright Tracing
220+
221+
Playwright tracing captures detailed information about test execution including screenshots, DOM snapshots, network activity, and console logs. This is invaluable for debugging test failures.
222+
223+
To generate a trace for a specific test:
224+
225+
```bash
226+
BROWSERFORCE_TRACE=true npm run test:e2e -- --grep "YourPlugin"
227+
```
228+
229+
After the test completes, a trace file will be saved with a timestamp (e.g., `trace-2025-11-23T19-00-00-000Z.zip`).
230+
231+
To view the trace:
232+
233+
```bash
234+
npx playwright show-trace trace-2025-11-23T19-00-00-000Z.zip
235+
```
236+
237+
This opens an interactive viewer in your browser where you can step through each action, view screenshots and DOM snapshots, inspect network requests, and review console logs.

README.md

Lines changed: 135 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
# sfdx-browserforce-plugin
22

3-
> sfdx plugin to apply settings in the Salesforce Setup Menu using browser automation
3+
> sf plugin to apply settings in the Salesforce Setup Menu using browser automation
44
55
[![Actions Status](https://github.com/amtrack/sfdx-browserforce-plugin/actions/workflows/default.yml/badge.svg?branch=main)](https://github.com/amtrack/sfdx-browserforce-plugin/actions?query=branch:main)
66

7+
> [!NOTE]
8+
> Since v6 we're using Playwright instead of Puppeteer. Please see the [release notes](https://github.com/amtrack/sfdx-browserforce-plugin/releases) for migration instructions.
9+
710
✅ Most settings in the Salesforce Setup Menu are represented as [Settings](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_settings.htm) in the Metadata API.
811

912
For example, the highlighted checkbox "Show View Hierarchy link on account pages" in Account Settings is indeed represented in the Metadata `AccountSettings` as `showViewHierarchyLink`.
@@ -54,7 +57,7 @@ $ sf browserforce apply -f ./config/currency.json --target-org myOrg@example.com
5457

5558
- 🔧 configuration using JSON Schema (similar to the [Scratch Org Definition Configuration](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_def_file.htm))
5659
- 🧠 idempotency of the `apply` command only applies what's necessary and allows re-execution (concept similar to [terraform](https://www.terraform.io/docs/commands/apply.html))
57-
- 🏎️ browser automation powered by Puppeteer and "Chrome for Testing", [learn more about Puppeteer and Browserforce](#puppeteer)
60+
- 🏎️ browser automation powered by Playwright, [learn more about Playwright and Browserforce](#playwright)
5861

5962
## Supported Browserforce Settings
6063

@@ -77,79 +80,165 @@ But there's more:
7780

7881
## Installation
7982

80-
There are several different methods to install `sfdx-browserforce-plugin`:
81-
8283
```shell
83-
# as an sf plugin globally
8484
sf plugins install sfdx-browserforce-plugin
85+
```
8586

86-
# or standalone globally
87-
npm install --global sfdx-browserforce-plugin
87+
> [!IMPORTANT]
88+
> Playwright does not come with a browser automatically
8889
89-
# or standalone locally (as a dependency in your Node.js project)
90-
npm install --save-dev sfdx-browserforce-plugin
91-
```
90+
You might need to install a browser explicitly or configure Browserforce to use an existing browser.
9291

93-
## Usage
92+
> [!TIP]
93+
> If you're using Browserforce on GitHub Actions with the `ubuntu-latest` (v24) Docker image, we can use the preinstalled Google Chrome automatically.
94+
> No further configuration and installation needed, because the `CHROME_BIN` environment variable is already set.
9495
95-
Depending on your choice of installation, you can find the `browserforce` namespace:
96+
### Option 1: Install a browser using our Playwright wrapper command
9697

9798
```shell
98-
# globally in the sf cli
99-
sf browserforce
99+
sf browserforce playwright -- install chromium
100+
```
101+
102+
> [!IMPORTANT]
103+
> The two hyphens `--` are intentional and separate the sf command from the arguments to be passed to the playwright executable.
104+
105+
### Option 2: Configure Browserforce to use an existing browser
100106

101-
# globally in the sfdx-browserforce-plugin executable
102-
sfdx-browserforce-plugin browserforce
107+
You can use any of the following environment variables:
103108

104-
# locally in the sfdx-browserforce-plugin executable (npx is awesome!)
105-
npx sfdx-browserforce-plugin browserforce
109+
```shell
110+
BROWSERFORCE_BROWSER_CHANNEL="chrome"
111+
BROWSERFORCE_BROWSER_CHANNEL="chromium"
112+
BROWSERFORCE_BROWSER_EXECUTABLE_PATH="/usr/bin/google-chrome"
113+
CHROME_BIN="/usr/bin/google-chrome"
106114
```
107115

108-
```console
109-
$ sfdx-browserforce browserforce -h
110-
browser automation
116+
## Usage
111117

118+
<!-- commands -->
119+
* [`sf browserforce apply`](#sf-browserforce-apply)
120+
* [`sf browserforce playwright`](#sf-browserforce-playwright)
121+
122+
## `sf browserforce apply`
123+
124+
apply a plan from a config file
125+
126+
```
112127
USAGE
113-
$ sfdx-browserforce-plugin browserforce COMMAND
128+
$ sf browserforce apply -o <value> [--json] [--flags-dir <value>] [-f <value>] [-d] [--headless] [--slow-mo <value>]
129+
[--timeout <value>] [--trace] [--browser-executable-path <value>] [--browser-channel <value>] [--max-retries
130+
<value>] [--retry-timeout <value>]
131+
132+
FLAGS
133+
-d, --dry-run [env: BROWSERFORCE_DRY_RUN] dry run
134+
-f, --definitionfile=<value> path to a browserforce config file
135+
-o, --target-org=<value> (required) Username or alias of the target org. Not required if the `target-org`
136+
configuration variable is already set.
137+
138+
BROWSER CONFIGURATION FLAGS
139+
--browser-channel=<value> [env: BROWSERFORCE_BROWSER_CHANNEL] the channel (e.g. chromium or chrome) to use
140+
--browser-executable-path=<value> [env: BROWSERFORCE_BROWSER_EXECUTABLE_PATH] the path to a browser executable
141+
--[no-]headless [env: BROWSERFORCE_HEADLESS] run in headless mode (default: true)
142+
--slow-mo=<value> [env: BROWSERFORCE_SLOWMO] slow motion in milliseconds (default: 0)
143+
--timeout=<value> [default: 90000, env: BROWSERFORCE_NAVIGATION_TIMEOUT_MS] the default navigation
144+
timeout in milliseconds
145+
--trace [env: BROWSERFORCE_TRACE] create a Playwright trace file
146+
147+
GLOBAL FLAGS
148+
--flags-dir=<value> Import flag values from a directory.
149+
--json Format output as json.
150+
151+
RETRY CONFIGURATION FLAGS
152+
--max-retries=<value> [default: 6, env: BROWSERFORCE_RETRY_MAX_RETRIES] the maximum number of retries for retryable
153+
actions
154+
--retry-timeout=<value> [default: 4000, env: BROWSERFORCE_RETRY_TIMEOUT_MS] the inital timeout in milliseconds for
155+
retryable actions (exponentially increased)
156+
157+
DESCRIPTION
158+
apply a plan from a config file
159+
160+
EXAMPLES
161+
$ sf browserforce apply -f ./config/currency.json --target-org myOrg@example.com
162+
logging in... done
163+
Applying config file ./config/currency.json to org myOrg@example.com
164+
[CompanyInformation] retrieving state... done
165+
[CompanyInformation] changing 'defaultCurrencyIsoCode' to '"English (South Africa) - ZAR"'... done
166+
logging out... done
167+
168+
169+
FLAG DESCRIPTIONS
170+
-d, --dry-run dry run
171+
172+
Retrieve the config and show the diff, but don't apply it.
114173
115-
COMMANDS
116-
browserforce apply apply a plan from a definition file
117-
browserforce plan retrieve state and generate plan file
174+
--browser-channel=<value> the channel (e.g. chromium or chrome) to use
175+
176+
Playwright will try to figure out the path to the browser executable automatically.
177+
178+
--browser-executable-path=<value> the path to a browser executable
179+
180+
Note: The environment variable CHROME_BIN can also be used. On GitHub Actions with ubuntu-latest, CHROME_BIN is set
181+
to /usr/bin/google-chrome.
182+
183+
--trace create a Playwright trace file
184+
185+
The trace file can be viewed with "sf browserforce playwright -- show-trace trace-<date>.zip".
118186
```
119187

120-
Both the `browserforce apply` and `browserforce plan` commands expect a config file and a target username or alias for the org.
188+
_See code: [src/commands/browserforce/apply.ts](https://github.com/amtrack/sfdx-browserforce-plugin/blob/v0.0.0-development/src/commands/browserforce/apply.ts)_
121189

122-
## Environment Variables
190+
## `sf browserforce playwright`
123191

124-
- `BROWSER_DEBUG` run in non-headless mode (default: `false`)
125-
- `BROWSERFORCE_NAVIGATION_TIMEOUT_MS`: adjustable for slow internet connections (default: `90000`)
126-
- `BROWSERFORCE_RETRY_MAX_RETRIES`: number of retries on failures opening a page (default: `4`)
127-
- `BROWSERFORCE_RETRY_TIMEOUT_MS`: initial time between retries in exponential mode (default: `4000`)
192+
access the Playwright CLI
128193

129-
## Puppeteer
194+
```
195+
USAGE
196+
$ sf browserforce playwright
130197
131-
We use [Puppeteer](https://github.com/puppeteer/puppeteer) for browser automation which comes with its own "Chrome for Testing" browser.
198+
DESCRIPTION
199+
access the Playwright CLI
132200
133-
The puppeteer [installation doc](https://github.com/puppeteer/puppeteer#installation) describes how this works:
201+
EXAMPLES
202+
$ sf browserforce playwright -- --help
134203
135-
> When you install Puppeteer, it automatically downloads a recent version of
136-
> [Chrome for Testing](https://goo.gle/chrome-for-testing) (~170MB macOS, ~282MB Linux, ~280MB Windows) that is [guaranteed to
137-
> work](https://pptr.dev/faq#q-why-doesnt-puppeteer-vxxx-work-with-chromium-vyyy)
138-
> with Puppeteer. The browser is downloaded to the `$HOME/.cache/puppeteer` folder
139-
> by default (starting with Puppeteer v19.0.0).
204+
$ sf browserforce playwright -- --version
140205
141-
In most of the cases this just works! If you still want to skip the download and use another browser installation, you can do this as follows:
206+
$ sf browserforce playwright -- install --list
142207
143-
```console
144-
export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
145-
sf plugins install sfdx-browserforce-plugin
146-
export PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
147-
sf browserforce:apply ...
208+
$ sf browserforce playwright -- install chromium
209+
```
210+
211+
_See code: [src/commands/browserforce/playwright.ts](https://github.com/amtrack/sfdx-browserforce-plugin/blob/v0.0.0-development/src/commands/browserforce/playwright.ts)_
212+
<!-- commandsstop -->
213+
214+
## Playwright
215+
216+
We use [Playwright](https://playwright.dev/) for browser automation.
217+
218+
For more information on browser automation best practices, see the [Playwright documentation](./docs/PLAYWRIGHT.md).
219+
220+
## Alternative Installation
221+
222+
You can also install the `sfdx-browserforce-plugin` NPM package without `sf`. The package exports a `sfdx-browserforce-plugin` executable:
223+
224+
Example:
225+
226+
```shell
227+
npm install --save-dev sfdx-browserforce-plugin
228+
npx sfdx-browserforce-plugin browserforce -h
148229
```
149230

150231
## Troubleshooting
151232

152-
- The installation is triggered via the `postinstall` hook of npm/yarn. If you've disabled running scripts with npm (`--ignore-scripts` or via config file), it will not download the browser.
233+
If no browser is installed or launching fails, you'll get an error message from Playwright with a suggestion.
234+
235+
Typically this will guide you to install a browser.
236+
If you've installed sfdx-browserforce-plugin using `sf`, you can replace the following:
237+
238+
```diff
239+
- npx playwright install chromium
240+
+ sf browserforce playwright -- install chromium
241+
```
153242

154243
## Contributing
155244

_templates/plugin/new/index.e2e-spec.ejs.t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { type Config, <%= h.changeCase.pascalCase(name) %> } from './index.js';
77
describe(<%= h.changeCase.pascalCase(name) %>.name, function() {
88
let plugin: <%= h.changeCase.pascalCase(name) %>;
99
before(() => {
10-
plugin = new <%= h.changeCase.pascalCase(name) %>(global.bf);
10+
plugin = new <%= h.changeCase.pascalCase(name) %>(global.browserforce);
1111
});
1212

1313
const configEnabled: Config = {

0 commit comments

Comments
 (0)