@pilaf/framework 1.0.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -0
- package/lib/index.js +10 -1
- package/lib/test-context.js +104 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,42 @@ pnpm add @pilaf/framework
|
|
|
16
16
|
pnpm add -D jest@^29.0.0
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
## Quick Start - Bot Player Testing
|
|
20
|
+
|
|
21
|
+
The simplest way to test with bot players:
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
const { createTestContext, cleanupTestContext } = require('@pilaf/framework');
|
|
25
|
+
|
|
26
|
+
describe('My Plugin Tests', () => {
|
|
27
|
+
let context;
|
|
28
|
+
|
|
29
|
+
beforeAll(async () => {
|
|
30
|
+
// Creates RCON connection + bot player in one call
|
|
31
|
+
context = await createTestContext({
|
|
32
|
+
username: 'TestPlayer',
|
|
33
|
+
host: 'localhost',
|
|
34
|
+
gamePort: 25565,
|
|
35
|
+
rconPort: 25575,
|
|
36
|
+
rconPassword: 'minecraft'
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
afterAll(async () => {
|
|
41
|
+
await cleanupTestContext(context);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should execute command as bot', async () => {
|
|
45
|
+
// Use bot.chat() for player commands
|
|
46
|
+
context.bot.chat('/gamemode creative');
|
|
47
|
+
|
|
48
|
+
// Use backend.sendCommand() for RCON commands
|
|
49
|
+
const result = await context.backend.sendCommand('seed');
|
|
50
|
+
expect(result.raw).toContain('Seed');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
19
55
|
## StoryRunner
|
|
20
56
|
|
|
21
57
|
The `StoryRunner` executes declarative test stories against Minecraft servers.
|
|
@@ -171,6 +207,84 @@ module.exports = {
|
|
|
171
207
|
|
|
172
208
|
## Helpers
|
|
173
209
|
|
|
210
|
+
### Test Context Helper
|
|
211
|
+
|
|
212
|
+
The `createTestContext()` helper provides a simplified way to create bot players for testing. It sets up both RCON and Mineflayer backends simultaneously.
|
|
213
|
+
|
|
214
|
+
**Why use this?**
|
|
215
|
+
|
|
216
|
+
When testing Minecraft plugins with bot players, you need TWO separate connections:
|
|
217
|
+
1. **Bot player** - For executing player commands (via `bot.chat()`)
|
|
218
|
+
2. **RCON** - For server commands that return responses (via `rcon.send()`)
|
|
219
|
+
|
|
220
|
+
The `MineflayerBackend.sendCommand()` method only sends commands via bot chat and **always returns empty** responses. You need RCON to get actual server responses for commands like `/data get`, `/teleport`, etc.
|
|
221
|
+
|
|
222
|
+
```javascript
|
|
223
|
+
const { createTestContext, cleanupTestContext } = require('@pilaf/framework');
|
|
224
|
+
|
|
225
|
+
describe('My Plugin', () => {
|
|
226
|
+
let context;
|
|
227
|
+
|
|
228
|
+
beforeAll(async () => {
|
|
229
|
+
context = await createTestContext({
|
|
230
|
+
username: 'TestPlayer',
|
|
231
|
+
rconPassword: 'dragon123'
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
afterAll(async () => {
|
|
236
|
+
await cleanupTestContext(context);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('should verify entity position after teleport', async () => {
|
|
240
|
+
// Get position BEFORE (using RCON - returns actual data!)
|
|
241
|
+
const beforeResult = await context.rcon.send('data get entity TestPlayer Pos');
|
|
242
|
+
const beforePos = parsePosition(beforeResult);
|
|
243
|
+
|
|
244
|
+
// Execute ability (using bot chat)
|
|
245
|
+
context.bot.chat('/myplugin teleport 100 64 100');
|
|
246
|
+
await wait(1000);
|
|
247
|
+
|
|
248
|
+
// Get position AFTER (using RCON - returns actual data!)
|
|
249
|
+
const afterResult = await context.rcon.send('data get entity TestPlayer Pos');
|
|
250
|
+
const afterPos = parsePosition(afterResult);
|
|
251
|
+
|
|
252
|
+
// Verify teleportation
|
|
253
|
+
expect(afterPos.x).toBeCloseTo(100, 0);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**API Reference:**
|
|
259
|
+
|
|
260
|
+
```javascript
|
|
261
|
+
const context = await createTestContext({
|
|
262
|
+
username: 'TestPlayer', // Bot username (default: 'TestPlayer')
|
|
263
|
+
host: 'localhost', // Server host (default: 'localhost')
|
|
264
|
+
gamePort: 25565, // Game port (default: 25565)
|
|
265
|
+
rconPort: 25575, // RCON port (default: 25575)
|
|
266
|
+
rconPassword: 'minecraft', // RCON password (default: 'minecraft')
|
|
267
|
+
auth: 'offline' // Auth mode (default: 'offline')
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Returns:
|
|
271
|
+
{
|
|
272
|
+
backend: MineflayerBackend, // For bot control
|
|
273
|
+
rcon: RconBackend, // For server commands WITH RESPONSES
|
|
274
|
+
bot: Object, // The bot player instance
|
|
275
|
+
playerName: string // Bot's username
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Use RCON for commands that need responses
|
|
279
|
+
const result = await context.rcon.send('data get entity TestPlayer Pos');
|
|
280
|
+
|
|
281
|
+
// Use bot chat for player commands
|
|
282
|
+
context.bot.chat('/mycommand');
|
|
283
|
+
|
|
284
|
+
// Cleanup when done
|
|
285
|
+
await cleanupTestContext(context);
|
|
286
|
+
```
|
|
287
|
+
|
|
174
288
|
### State Management
|
|
175
289
|
|
|
176
290
|
```javascript
|
package/lib/index.js
CHANGED
|
@@ -4,6 +4,7 @@ const { StoryRunner } = require('./StoryRunner');
|
|
|
4
4
|
const { waitForEvents, captureEvents } = require('./helpers/events');
|
|
5
5
|
const { captureState, compareStates } = require('./helpers/state');
|
|
6
6
|
const { toHaveReceivedLightningStrikes } = require('./matchers/game-matchers');
|
|
7
|
+
const { createTestContext, cleanupTestContext } = require('./test-context');
|
|
7
8
|
|
|
8
9
|
const { PilafBackendFactory } = require('@pilaf/backends');
|
|
9
10
|
|
|
@@ -34,6 +35,10 @@ module.exports = {
|
|
|
34
35
|
// Story Runner
|
|
35
36
|
StoryRunner,
|
|
36
37
|
|
|
38
|
+
// Test Context Helper
|
|
39
|
+
createTestContext,
|
|
40
|
+
cleanupTestContext,
|
|
41
|
+
|
|
37
42
|
// Main API
|
|
38
43
|
pilaf,
|
|
39
44
|
rcon,
|
|
@@ -46,5 +51,9 @@ module.exports = {
|
|
|
46
51
|
compareStates,
|
|
47
52
|
|
|
48
53
|
// Matchers
|
|
49
|
-
toHaveReceivedLightningStrikes
|
|
54
|
+
toHaveReceivedLightningStrikes,
|
|
55
|
+
|
|
56
|
+
// Test Context
|
|
57
|
+
createTestContext,
|
|
58
|
+
cleanupTestContext
|
|
50
59
|
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Context Helper
|
|
3
|
+
*
|
|
4
|
+
* Provides a simplified way to create bot players for testing
|
|
5
|
+
* This combines RCON and Mineflayer backends for seamless testing
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: Returns TWO backends:
|
|
8
|
+
* - rcon: RconBackend for server commands that return responses
|
|
9
|
+
* - backend: MineflayerBackend for bot player control
|
|
10
|
+
*
|
|
11
|
+
* Use context.rcon.send() for commands like /data get, /teleport, etc.
|
|
12
|
+
* Use context.bot.chat() for player commands
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const { MineflayerBackend } = require('../../backends/lib/mineflayer-backend.js');
|
|
16
|
+
const { RconBackend } = require('../../backends/lib/rcon-backend.js');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Create a test context with both RCON and a bot player
|
|
20
|
+
* This is the recommended way to set up tests that need player commands
|
|
21
|
+
*
|
|
22
|
+
* @param {Object} config - Configuration
|
|
23
|
+
* @param {string} config.username - Bot username (default: 'TestPlayer')
|
|
24
|
+
* @param {string} config.host - Server host (default: 'localhost')
|
|
25
|
+
* @param {number} config.gamePort - Server game port (default: 25565)
|
|
26
|
+
* @param {number} config.rconPort - RCON port (default: 25575)
|
|
27
|
+
* @param {string} config.rconPassword - RCON password (default: 'minecraft')
|
|
28
|
+
* @param {string} config.auth - Auth mode (default: 'offline')
|
|
29
|
+
* @returns {Promise<TestContext>} Test context with rcon, backend, and bot
|
|
30
|
+
*/
|
|
31
|
+
async function createTestContext(config = {}) {
|
|
32
|
+
const username = config.username || 'TestPlayer';
|
|
33
|
+
const host = config.host || 'localhost';
|
|
34
|
+
const gamePort = config.gamePort || 25565;
|
|
35
|
+
const rconPort = config.rconPort || 25575;
|
|
36
|
+
const rconPassword = config.rconPassword || 'minecraft';
|
|
37
|
+
const auth = config.auth || 'offline';
|
|
38
|
+
|
|
39
|
+
// Create RCON backend for server commands (returns responses)
|
|
40
|
+
const rcon = new RconBackend();
|
|
41
|
+
await rcon.connect({
|
|
42
|
+
host,
|
|
43
|
+
port: rconPort,
|
|
44
|
+
password: rconPassword
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Create Mineflayer backend for bot players
|
|
48
|
+
const backend = new MineflayerBackend();
|
|
49
|
+
|
|
50
|
+
// Connect to server
|
|
51
|
+
await backend.connect({
|
|
52
|
+
host,
|
|
53
|
+
port: gamePort,
|
|
54
|
+
auth,
|
|
55
|
+
rconHost: host,
|
|
56
|
+
rconPort,
|
|
57
|
+
rconPassword
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Wait for server to be ready
|
|
61
|
+
await backend.waitForServerReady({ timeout: 60000 });
|
|
62
|
+
|
|
63
|
+
// Create bot player
|
|
64
|
+
const bot = await backend.createBot({
|
|
65
|
+
username,
|
|
66
|
+
auth
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
return { backend, rcon, bot, playerName: username };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Disconnect and cleanup test context
|
|
74
|
+
*
|
|
75
|
+
* @param {TestContext} context - The test context to cleanup
|
|
76
|
+
*/
|
|
77
|
+
async function cleanupTestContext(context) {
|
|
78
|
+
if (!context) return;
|
|
79
|
+
|
|
80
|
+
if (context.bot && context.backend) {
|
|
81
|
+
await context.backend.quitBot(context.bot);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (context.backend) {
|
|
85
|
+
await context.backend.disconnect();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (context.rcon) {
|
|
89
|
+
await context.rcon.disconnect();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @typedef {Object} TestContext
|
|
95
|
+
* @property {MineflayerBackend} backend - The Mineflayer backend instance (for bot control)
|
|
96
|
+
* @property {RconBackend} rcon - The RCON backend instance (for server commands with responses)
|
|
97
|
+
* @property {Object} bot - The bot player instance
|
|
98
|
+
* @property {string} playerName - The bot's username
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
module.exports = {
|
|
102
|
+
createTestContext,
|
|
103
|
+
cleanupTestContext
|
|
104
|
+
};
|