# Provision API

The `provision` object provides easy setup methods for common applications. These methods automatically handle TestDriver initialization, Dashcam recording, and application launching.

## Quick Start

```javascript
import { describe, it, expect } from 'vitest';
import { TestDriver } from 'testdriverai/lib/vitest/hooks.mjs';

describe('My Test Suite', () => {
  it('should test Chrome browser', async (context) => {
    const testdriver = TestDriver(context, ());
    
    await testdriver.provision.chrome({
      url: 'https://example.com'
    });
    
    await testdriver.find('Login button').click();
  });
});
```

## Available Methods

- `provision.chrome()` - Launch Chrome browser with URL
- `provision.vscode()` - Launch VS Code with optional extensions
- `provision.installer()` - Download and install applications
- `provision.electron()` - Launch Electron applications
- `provision.dashcam()` - Initialize Dashcam recording with logging

---

## provision.chrome()

Launch Google Chrome with automatic Dashcam recording.

```javascript
await testdriver.provision.chrome({
  url: 'https://myapp.com',
  maximized: true,
  extensionPath: '/path/to/extension'
});
```

**Options:**
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `url` | string | `'http://testdriver-sandbox.vercel.app/'` | URL to navigate to |
| `maximized` | boolean | `true` | Start browser maximized |
| `extensionPath` | string | - | Path to Chrome extension to load |

**Example:**

```javascript
it('should login to my app', async (context) => {
  const testdriver = TestDriver(context, ());
  
  await testdriver.provision.chrome({
    url: 'https://myapp.com/login'
  });
  
  await testdriver.find('email input').type('user@example.com');
  await testdriver.find('password input').type('password123');
  await testdriver.find('Login button').click();
  
  const result = await testdriver.assert('Dashboard is visible');
  expect(result).toBeTruthy();
});
```

---

## provision.vscode()

Launch Visual Studio Code with optional extension installation. Automatically starts Dashcam recording.

```javascript
await testdriver.provision.vscode({
  workspace: '/path/to/project',
  extensions: ['esbenp.prettier-vscode', 'ms-python.python']
});
```

**Options:**
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `workspace` | string | - | Workspace/folder path to open |
| `extensions` | string[] | `[]` | VS Code extension IDs to install |

**Example - Basic Launch:**

```javascript
it('should launch VS Code', async (context) => {
  const testdriver = TestDriver(context, ());
  
  await testdriver.provision.vscode();
  
  const result = await testdriver.assert(
    'Visual Studio Code window is visible on screen'
  );
  expect(result).toBeTruthy();
});
```

**Example - Install Extensions:**

```javascript
it('should install and use a VS Code extension', async (context) => {
  const testdriver = TestDriver(context, ());
  
  // Launch VS Code with extensions installed
  await testdriver.provision.vscode({
    extensions: ['esbenp.prettier-vscode']
  });
  
  // Open the extensions panel
  await testdriver.pressKeys(['ctrl', 'shift', 'x']);
  await new Promise(resolve => setTimeout(resolve, 2000));
  
  const result = await testdriver.assert(
    'Prettier extension is visible in the extensions panel'
  );
  expect(result).toBeTruthy();
});
```

---

## provision.installer()

Download and install applications from a URL. Automatically detects file type and runs the appropriate install command.

```javascript
const filePath = await testdriver.provision.installer({
  url: 'https://example.com/app.deb',
  appName: 'MyApp'
});
```

**Options:**
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `url` | string | **required** | URL to download the installer from |
| `filename` | string | auto-detected | Filename to save as |
| `appName` | string | - | Application name to focus after install |
| `launch` | boolean | `true` | Whether to launch/focus the app after installation |

**Returns:** `Promise<string>` - Path to the downloaded file

**Supported File Types:**

| Platform | Extensions | Install Command |
|----------|------------|-----------------|
| Linux | `.deb` | `sudo dpkg -i && apt-get install -f -y` |
| Linux | `.rpm` | `sudo rpm -i` |
| Linux | `.appimage` | `chmod +x` |
| Linux | `.sh` | `chmod +x && execute` |
| Windows | `.msi` | `msiexec /i /quiet /norestart` |
| Windows | `.exe` | `Start-Process /S` |
| macOS | `.dmg` | `hdiutil attach && cp to /Applications` |
| macOS | `.pkg` | `installer -pkg -target /` |

**Example - Install .deb Package:**

```javascript
it('should install a .deb package', async (context) => {
  const testdriver = TestDriver(context, ());
  
  const filePath = await testdriver.provision.installer({
    url: 'https://github.com/sharkdp/bat/releases/download/v0.24.0/bat_0.24.0_amd64.deb'
  });
  
  // Verify installation
  await testdriver.exec('sh', 'bat --version', 10000);
});
```

**Example - Download Only (No Auto-Launch):**

```javascript
it('should download a script', async (context) => {
  const testdriver = TestDriver(context, ());
  
  const filePath = await testdriver.provision.installer({
    url: 'https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh',
    launch: false
  });
  
  // Run custom post-download commands
  await testdriver.exec('sh', `source "${filePath}"`, 30000);
});
```

**Example - Custom Post-Install:**

```javascript
it('should run AppImage with custom flags', async (context) => {
  const testdriver = TestDriver(context, ());
  
  const filePath = await testdriver.provision.installer({
    url: 'https://example.com/app.AppImage',
    launch: false
  });
  
  // Run with custom arguments
  await testdriver.exec('sh', `"${filePath}" --no-sandbox &`, 10000);
  
  await new Promise(resolve => setTimeout(resolve, 5000));
  
  const result = await testdriver.assert('App window is visible');
  expect(result).toBeTruthy();
});
```

---

## provision.electron()

Launch an Electron application.

```javascript
await testdriver.provision.electron({
  appPath: '/path/to/app',
  args: ['--enable-logging']
});
```

**Options:**
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `appPath` | string | **required** | Path to Electron application |
| `args` | string[] | `[]` | Additional command-line arguments |

**Example:**

```javascript
it('should launch Electron app', async (context) => {
  const testdriver = TestDriver(context, ());
  
  await testdriver.provision.electron({
    appPath: '/path/to/my-electron-app',
    args: ['--enable-logging']
  });
  
  await testdriver.find('main window').click();
});
```

---

## provision.dashcam()

Initialize Dashcam recording with logging. Use this when you want to start Dashcam recording without launching a specific application (e.g., for custom application launches or testing scenarios).

```javascript
await testdriver.provision.dashcam({
  logPath: '/tmp/myapp.log',
  logName: 'My Application Log',
  title: 'Custom Test Recording'
});
```

**Options:**
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `logPath` | string | auto-generated | Path to log file to track |
| `logName` | string | `'TestDriver Log'` | Display name for the log |
| `webLogs` | boolean | `true` | Enable web log tracking |
| `title` | string | - | Custom title for the recording |

**Example - Basic Recording:**

```javascript
it('should record a custom application test', async (context) => {
  const testdriver = TestDriver(context, ());
  
  // Start Dashcam recording
  await testdriver.provision.dashcam();
  
  // Launch your custom application
  await testdriver.exec('sh', './my-custom-app.sh &', 10000);
  
  // Interact with the application
  await testdriver.find('main window').click();
  
  const result = await testdriver.assert('Application is running');
  expect(result).toBeTruthy();
});
```

**Example - Custom Log File:**

```javascript
it('should record with custom log file', async (context) => {
  const testdriver = TestDriver(context, ());
  
  // Start Dashcam with custom log tracking
  await testdriver.provision.dashcam({
    logPath: '/var/log/myapp/application.log',
    logName: 'My App Logs',
    title: 'Custom App Test'
  });
  
  // Your test code here
  await testdriver.exec('sh', 'myapp --start', 30000);
});
```

---

## How Provision Methods Work

When you call a provision method:

1. **Waits for connection** - Calls `ready()` to ensure sandbox is connected
2. **Sets up Dashcam** - Creates log file and adds to Dashcam monitoring
3. **Starts recording** - Automatically starts Dashcam if not already recording
4. **Launches application** - Opens the specified app with your configuration
5. **Focuses window** - Ensures the app is ready for interaction

At test end:
- Dashcam automatically stops and saves replay URL
- TestDriver automatically disconnects
- All cleanup is handled for you

## Complete Example

```javascript
import { describe, it, expect } from 'vitest';
import { TestDriver } from 'testdriverai/lib/vitest/hooks.mjs';

describe('Application Testing', () => {
  it('should test Chrome login flow', async (context) => {
    const testdriver = TestDriver(context, ());
    
    await testdriver.provision.chrome({
      url: 'https://myapp.com/login'
    });
    
    await testdriver.find('email').type('user@example.com');
    await testdriver.find('password').type('password123');
    await testdriver.find('Login').click();
    
    const result = await testdriver.assert('Welcome message is visible');
    expect(result).toBeTruthy();
  });

  it('should test VS Code extension', async (context) => {
    const testdriver = TestDriver(context, ());
    
    await testdriver.provision.vscode({
      extensions: ['ms-python.python']
    });
    
    await testdriver.pressKeys(['ctrl', 'shift', 'p']);
    await testdriver.type('Python: Select Interpreter');
    await testdriver.pressKeys(['enter']);
    
    const result = await testdriver.assert('Python interpreter selector is visible');
    expect(result).toBeTruthy();
  });

  it('should install and test CLI tool', async (context) => {
    const testdriver = TestDriver(context, ());
    
    await testdriver.provision.installer({
      url: 'https://github.com/sharkdp/bat/releases/download/v0.24.0/bat_0.24.0_amd64.deb'
    });
    
    // Verify the tool works
    await testdriver.exec('sh', 'bat --help', 10000);
  });
});
```

## Best Practices

1. **Use clean environments** - Each test gets a fresh sandbox by default
2. **Enable Dashcam** - Great for debugging test failures (enabled by default)
3. **Check assertions** - Always verify the expected state after actions
4. **Use appropriate provision method** - Match the method to your test target
5. **Handle async properly** - All provision methods return Promises

## See Also

- [Hooks API](./hooks.mdx) - TestDriver initialization
- [Find API](../api/find.mdx) - Element finding
- [Exec API](../api/exec.mdx) - Running shell commands
- [Assert API](../api/assert.mdx) - AI-powered assertions
