@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 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
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pilaf/framework",
3
- "version": "1.0.1",
3
+ "version": "1.2.0",
4
4
  "main": "lib/index.js",
5
5
  "repository": {
6
6
  "type": "git",