Skip to content

Getting Started

Installation

bash
npm install craftdriver --save-dev

Your First Test

typescript
import { Browser } from 'craftdriver';

async function main() {
  // Launch browser
  const browser = await Browser.launch({ browserName: 'chrome' });

  try {
    // Navigate to a page
    await browser.navigateTo('https://example.com');

    // Get page title
    const title = await browser.title();
    console.log('Page title:', title);

    // Click a link
    await browser.click('a');

    // Fill a form
    await browser.fill('#email', 'test@example.com');
    await browser.click('#submit');

    // Assert result
    await browser.expect('#message').toHaveText('Success!');
  } finally {
    await browser.quit();
  }
}

main();

browser.X() vs page.X() — when to use which

browser.click(), browser.find(), browser.fill(), browser.evaluate() and the other DOM-touching shortcuts on Browser are sugar for (await browser.activePage()).X(...). They always target the focused page in browser.defaultContext. They never cross into a Page that lives inside a context returned by browser.newContext().

For single-tab tests this is exactly what you want — the shortcuts keep your code short:

typescript
await browser.navigateTo('https://example.com');
await browser.click('#submit');

For multi-tab or multi-user tests, get a Page explicitly:

typescript
// Multi-tab
const page = await browser.openPage({ url: '/help', type: 'tab' });
await page.click('#close');           // unambiguous

// Multi-user (isolated profiles)
const alice = await browser.newContext();
const aPage = await alice.newPage({ url: '/login' });
await aPage.fill('#user', 'alice');   // browser.fill() would target the
                                      // default context, NOT alice.

If you need to be explicit even in single-tab code, browser.activePage() returns the same Page the shortcuts would target.

Launch Options

typescript
// Chrome (default)
const browser = await Browser.launch({
  browserName: 'chrome', // 'chrome' | 'chromium' | 'firefox'
  storageState: './session.json', // optional: pre-load saved session state
});

// Firefox
const browser = await Browser.launch({
  browserName: 'firefox',
});

Running tests on Firefox

Set BROWSER_NAME=firefox before running your test command:

bash
BROWSER_NAME=firefox npx vitest run
# or use the built-in script if your package.json has it:
npm run test:firefox

Custom WebDriver binary or port

Browser.launch() resolves the driver binary automatically. To pin a specific binary, change the host/port, or pass extra command-line arguments to the driver, construct a ChromeService or FirefoxService and pass it via chromeService / firefoxService:

typescript
import { Browser, ChromeService, FirefoxService } from 'craftdriver';

// Pin a specific chromedriver binary on a fixed port
const browser = await Browser.launch({
  browserName: 'chrome',
  chromeService: new ChromeService({
    binaryPath: '/opt/chromedriver/chromedriver',
    port: 9515,
    hostname: '127.0.0.1',
    args: ['--log-level=ALL'],
  }),
});

// Custom geckodriver path for Firefox
const ff = await Browser.launch({
  browserName: 'firefox',
  firefoxService: new FirefoxService({
    binaryPath: '/usr/local/bin/geckodriver',
  }),
});

Without an explicit binaryPath, both services check (in order) the matching env var (CHROMEDRIVER_PATH / GECKODRIVER_PATH), node_modules/.bin/, then $PATH. If port is omitted, a free port is picked automatically.

With Vitest

typescript
import { describe, it, beforeEach, afterEach } from 'vitest';
import { Browser } from 'craftdriver';

describe('My App', () => {
  let browser: Browser;

  beforeEach(async () => {
    browser = await Browser.launch({ browserName: 'chrome' });
  });

  afterEach(async () => {
    await browser.quit();
  });

  it('shows welcome message after login', async () => {
    await browser.navigateTo('http://localhost:3000/login');
    await browser.fill('#username', 'testuser');
    await browser.fill('#password', 'password123');
    await browser.click('#login-btn');

    await browser.expect('#welcome').toContainText('Hello, testuser');
  });
});

Next Steps

Released under the MIT License.