> ## Documentation Index
> Fetch the complete documentation index at: https://plugwright.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Writing Tests

> Learn how to write and structure your Plugwright tests.

## Basic Test Structure

Tests use a simple API similar to Jest:

```javascript theme={null}
import { test, expect } from '@drownek/plugwright';

test('test description', async ({ player }) => {
  // Your test code here
});
```

## Your First Test

Create `src/test/e2e/first.spec.js`:

```javascript theme={null}
import { test, expect } from '@drownek/plugwright';

test('player receives welcome message', async ({ player }) => {
  await expect(player).toHaveReceivedMessage('Welcome');
});
```

## Common Test Patterns

### Testing Commands

```javascript theme={null}
test('help command works', async ({ player }) => {
  player.chat('/help');
  await expect(player).toHaveReceivedMessage('Available commands');
});

test('admin command requires permission', async ({ player }) => {
  player.chat('/admin reload');
  await expect(player).toHaveReceivedMessage('No permission');
});
```

### Testing Economy

```javascript theme={null}
test('player starts with default balance', async ({ player }) => {
  player.chat('/balance');
  await expect(player).toHaveReceivedMessage('$1000');
});

test('player can purchase items', async ({ player, server }) => {
  server.execute(`eco give ${player.username} 500`);
  player.chat('/buy diamond');
  await expect(player).toHaveReceivedMessage('Purchased');
  await expect(player).toContainItem('diamond');
});
```

### Testing Inventory

```javascript theme={null}
test('player inventory has starter items', async ({ player }) => {
  player.chat('/starter');
  await expect(player).toContainItem('diamond_sword');
  await expect(player).toContainItem('bread');
});
```

### Server Operations

```javascript theme={null}
test('server executes commands', async ({ player, server }) => {
  server.execute(`give ${player.username} diamond 64`);
  await expect(player).toContainItem('diamond');
});
```

## API Reference

### Test Context

Each test receives a context object with:

* `player` - The PlayerWrapper instance managing the bot
* `server` - Server control interface

### Player Actions

```javascript theme={null}
player.chat('/command')        // Send chat/command
player.chat('Hello!')          // Send chat message
await player.gui({ title: 'Title' })     // Wait for GUI window
player.inventory                     // Access inventory
player.bot                           // Underlying Mineflayer bot
```

### Assertions

```javascript theme={null}
// Chat message (partial match, 5s timeout)
await expect(player).toHaveReceivedMessage('text')

// Inventory item (5s timeout)
await expect(player).toContainItem('item_name')
```

### Utilities

The framework provides several exported utilities for advanced waiting and polling:

```javascript theme={null}
import { test, sleep, poll, waitForAssertion, waitUntil, waitForStable } from '@drownek/plugwright';

test('advanced waiting', async ({ player }) => {
  // Sleep for 1 second
  await sleep(1000);

  // Wait until a condition remains continuously true for 2 seconds
  await waitForStable(() => player.bot.health === 20, { duration: 2000, timeout: 5000 });
});
```

## Best Practices

1. **Keep tests isolated** - Each test gets a fresh bot
2. **Use descriptive names** - Make test failures easy to understand
3. **Wait for conditions** - Use assertions that auto-retry
4. **Test one thing** - Each test should verify one behavior
5. **Check server logs** - They appear in console during test runs
6. **Add delays when needed** - Use the built-in `sleep()` utility for timing-dependent tests

## Tips

* Tests run sequentially, not in parallel
* Server starts fresh for each test run
* Bot automatically connects to the server
* Server logs are visible in the console output
