playwright icon indicating copy to clipboard operation
playwright copied to clipboard

[Feature]: [playwright-vscode] Add means to wrap/change test run command

Open jonathan-mothership opened this issue 1 year ago • 1 comments

🚀 Feature Request

Our app we're testing with Playwright has an environment that is set using a wrapping script. We're using a Worker-scoped fixture that needs to grab some of the app config from the environment. All things Playwright work fine at the CLI where we wrap the playwright test process, but this doesn't seem possible to do with the VSCode Playwright extension.

It is possible to set the environment using other ways, like explicitly defining them in VSCode settings.json, but that would mean maintaining two copies for each of our envs in test. Also possible is to use something like dotenv to pull in a target .env file, but in our case they aren't available/usable without the wrapper script. The script doesn't mutate files, only sets the environment for child processes.

I think this request re-raises the issue in https://github.com/microsoft/playwright/issues/22932. It should be possible to provide some better mechanism here even if it means it doesn't work for all variants of process wrappers.

Example

Ideally there would be a setting we can use to set a "parent" command, which receives the run command as final arguments.

Example: we need something like this at the CLI to get our env set for tests

APP_ENV=test pnpm with-env pnpm exec playwright test

For us, with-env lays down the environment (~100 vars) based on APP_ENV. Works great at the CLI!

I'm imagining a settings.json config to add a command prefix or override the current command used to launch tests.

Motivation

We love the vscode extension's quick test runner, being able to run specific tests from the UI in our monorepo app would be a dream.

jonathan-mothership avatar Aug 28 '24 02:08 jonathan-mothership

Hi! The reasoning why we closed https://github.com/microsoft/playwright/issues/22932 is still true. Let's try to think of a different solution for your usecase.

You mention that the wrapper script only outputs the environment variables to its child process. One idea I have is that you can make that child process echo those environment variables to STDOUT, and then read them programatically from playwright.config.ts. Here's an example script for that:

// playwright.config.ts

import { execSync } from "node:child_process"

const env = JSON.parse(execSync("./wrapper.sh node -p 'JSON.stringify(process.env)'", { encoding: 'utf8' }))
process.env.WRAPPER_SET_VARIABLE = env.WRAPPER_SET_VARIABLE

...

Does that help solve your problem?

Skn0tt avatar Aug 28 '24 08:08 Skn0tt

Ended up getting there somewhat following your suggestion, avoiding adding another package, and after modifying the script to optionally spew to stdout to avoid dumping to a file:

// playwright.config.ts
import { loadEnvFromProcessStdout } from 'playwright/readEnv'
await loadEnvFromProcessStdout('pnpm', ['with-env', '--stdout'])
...
// playwright/readEnv.ts
import { spawn } from 'child_process'
import readline from 'readline'

export function loadEnvFromProcessStdout(command: string, args: Array<string>): Promise<void> {
  return new Promise((resolve, reject) => {
    const childProcess = spawn(command, args)

    const rl = readline.createInterface({
      input: childProcess.stdout,
      crlfDelay: Infinity,
    })

    rl.on('line', (line) => {
      const [key, ...valueParts] = line.split('=')
      if (key && valueParts.length > 0) {
        const value = valueParts.join('=')
        // eslint-disable-next-line no-restricted-properties
        process.env[key.trim()] = value
      }
    })

    childProcess.on('close', (code) => {
      if (code === 0) {
        resolve()
      } else {
        reject(new Error(`Child process exited with code ${code}`))
      }
    })

    childProcess.on('error', (err) => {
      reject(err)
    })
  })
}

Will probably refactor, it's quite unsexy but gets us past this limitation for now.

jonathan-mothership avatar Aug 28 '24 19:08 jonathan-mothership

If it gets the job done, i'd say its beautiful! Happy to hear that you've found a solution. Gonna go ahead and close the issue :)

Skn0tt avatar Aug 29 '24 06:08 Skn0tt