---id: parameterize-teststitle: Parameterize Tests---You can simply parameterize tests on a test level, via simple `for` loops e.g.:```ts title=example.spec.jsconst people = ['Alice', 'Bob']describe('my tests', () => {for (const name of people) {it(`testing with ${name}`, async () => {// ...})}})```or by extracting tests into dynamic functions, e.g.:```js title=dynamic.spec.jsimport { browser } from '@wdio/globals'function testComponent(componentName, options) {it(`should test my ${componentName}`, async () => {await browser.url(`/${componentName}`)await expect($('input')).toHaveValue(options.expectedValue)})}describe('page components', () => {testComponent('component-a', { expectedValue: 'some expected value' })testComponent('component-b', { expectedValue: 'some other expected value' })})```## Passing Environment VariablesYou can use environment variables to configure tests from the command line.For example, consider the following test file that needs a username and a password. It is usually a good idea not to store your secrets in the source code, so we'll need a way to pass secrets from outside.```ts title=example.spec.tsit(`example test`, async () => {// ...await $('#username').setValue(process.env.USERNAME)await $('#password').setValue(process.env.PASSWORD)})```You can run this test with your secret username and password set in the command line.<TabsdefaultValue="bash"values={[{label: 'Bash', value: 'bash'},{label: 'Powershell', value: 'powershell'},{label: 'Batch', value: 'batch'},]}><TabItem value="bash">```shUSERNAME=me PASSWORD=secret npx wdio run wdio.conf.js```</TabItem><TabItem value="powershell">```sh$env:USERNAME=me$env:PASSWORD=secretnpx wdio run wdio.conf.js```</TabItem><TabItem value="batch">```shset USERNAME=meset PASSWORD=secretnpx wdio run wdio.conf.js```</TabItem></Tabs>Similarly, configuration file can also read environment variables passed through the command line.```ts title=wdio.config.jsexport const config = {// ...baseURL: process.env.STAGING === '1'? 'http://staging.example.test/': 'http://example.test/',// ...}```Now, you can run tests against a staging or a production environment:<TabsdefaultValue="bash"values={[{label: 'Bash', value: 'bash'},{label: 'Powershell', value: 'powershell'},{label: 'Batch', value: 'batch'},]}><TabItem value="bash">```shSTAGING=1 npx wdio run wdio.conf.js```</TabItem><TabItem value="powershell">```sh$env:STAGING=1npx wdio run wdio.conf.js```</TabItem><TabItem value="batch">```shset STAGING=1npx wdio run wdio.conf.js```</TabItem></Tabs>## `.env` filesTo make environment variables easier to manage, consider something like `.env` files. WebdriverIO loads `.env` files automatically into your environment. Instead of defining the environment variable as part of the command call, you can define the following `.env`:```bash title=".env"# .env fileSTAGING=0USERNAME=mePASSWORD=secret```Run tests as usual, your environment variables should be picked up.```shnpx wdio run wdio.conf.js```## Create tests via a CSV fileThe WebdriverIO test-runner runs in Node.js, this means you can directly read files from the file system and parse them with your preferred CSV library.See for example this CSV file, in our example input.csv:```csv"test_case","some_value","some_other_value""value 1","value 11","foobar1""value 2","value 22","foobar21""value 3","value 33","foobar321""value 4","value 44","foobar4321"```Based on this we'll generate some tests by using the csv-parse library from NPM:```js title=test.spec.tsimport fs from 'node:fs'import path from 'node:path'import { parse } from 'csv-parse/sync'const records = parse(fs.readFileSync(path.join(__dirname, 'input.csv')), {columns: true,skip_empty_lines: true})describe('my test suite', () => {for (const record of records) {it(`foo: ${record.test_case}`, async () => {console.log(record.test_case, record.some_value, record.some_other_value)})}})```