Skip to content

Commit 32d9d84

Browse files
authored
Add experience test (#3652)
* Add new external test for time. Added by iterating with cursor. 1. Asking what is missing from mineflayer in term of testing 2. Selecting time from his proposal 3. Reviewing the time test it wrote 4. Asking to run the test for version 1.21.4 5. Asking him to fix failures 6. Asking to run on all version to double check 7. Sending this PR * fix lint * increase tolerance * fix * refactor * faster * Add a guide for llm to contribute in the docs folder * Add experience test documentation Added a new section to the LLM contribute file detailing the process of adding a new test, including version-specific command syntax and event listener cleanup. * refactor * lint
1 parent 52938fe commit 32d9d84

2 files changed

Lines changed: 242 additions & 0 deletions

File tree

docs/llm_contribute.md

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
# Contributing to Mineflayer Tests as an LLM
2+
3+
This guide explains how to add and modify tests in Mineflayer, based on the experience of working with the time-related functionality. It provides a structured approach for LLMs to help with test development and debugging.
4+
5+
## Test Structure
6+
7+
### Location
8+
- Tests are located in `test/externalTests/`
9+
- Each test file corresponds to a specific functionality
10+
- Test files follow the naming convention of the feature they test (e.g., `time.js` for time-related tests)
11+
12+
### Basic Test Template
13+
```javascript
14+
const assert = require('assert')
15+
const { once } = require('../../lib/promise_utils')
16+
17+
module.exports = () => async (bot) => {
18+
// Test implementation
19+
}
20+
```
21+
22+
## Writing Tests
23+
24+
### 1. Property Testing
25+
- Define expected properties and their types
26+
- Use `assert.strictEqual` for type checking
27+
- Verify value ranges where applicable
28+
29+
Example:
30+
```javascript
31+
const timeProps = {
32+
doDaylightCycle: 'boolean',
33+
bigTime: 'bigint',
34+
time: 'number'
35+
}
36+
37+
Object.entries(timeProps).forEach(([prop, type]) => {
38+
assert.strictEqual(typeof bot.time[prop], type)
39+
})
40+
```
41+
42+
### 2. Helper Functions
43+
- Create reusable helper functions for common operations
44+
- Include functions for waiting and state verification
45+
- Use descriptive names that explain their purpose
46+
47+
Example:
48+
```javascript
49+
const waitForTime = async () => {
50+
await once(bot, 'time')
51+
await bot.test.wait(200)
52+
}
53+
```
54+
55+
### 3. Test Cases
56+
- Organize test cases in arrays for better maintainability
57+
- Include descriptive names and expected outcomes
58+
- Group related tests together
59+
60+
Example:
61+
```javascript
62+
const timeTests = [
63+
{ time: 18000, name: 'midnight', isDay: false },
64+
{ time: 6000, name: 'noon', isDay: true }
65+
]
66+
```
67+
68+
## Running Tests
69+
70+
### Basic Test Execution
71+
```bash
72+
npm run mocha_test -- -g "mineflayer_external 1.20.4v.*time"
73+
```
74+
75+
### Version-Specific Testing
76+
- Test against multiple Minecraft versions
77+
- Common versions to test: 1.14.4, 1.20.4, 1.21.3
78+
- Example:
79+
```bash
80+
# Test for 1.14.4
81+
npm run mocha_test -- -g "mineflayer_external 1.14.4v.*time"
82+
83+
# Test for 1.21.3
84+
npm run mocha_test -- -g "mineflayer_external 1.21.3v.*time"
85+
```
86+
87+
## Debugging Tests
88+
89+
### 1. Adding Debug Logs
90+
- Use `console.log` for debugging (remove before final commit)
91+
- Log important state changes and values
92+
- Example:
93+
```javascript
94+
console.log('Time properties:', bot.time)
95+
```
96+
97+
### 2. Common Issues
98+
- Timing issues: Adjust wait times if needed (default 200ms)
99+
- Version compatibility: Check packet formats across versions
100+
- State synchronization: Ensure proper event handling
101+
102+
### 3. Test Output
103+
- Watch for server startup messages
104+
- Monitor bot commands and responses
105+
- Check for any error messages or warnings
106+
107+
## Best Practices
108+
109+
1. **Test Organization**
110+
- Group related tests together
111+
- Use descriptive test names
112+
- Keep tests focused and atomic
113+
114+
2. **Error Handling**
115+
- Include clear error messages
116+
- Test edge cases
117+
- Verify state after each operation
118+
119+
3. **Performance**
120+
- Minimize wait times
121+
- Clean up resources
122+
- Avoid redundant tests
123+
124+
4. **Documentation**
125+
- Comment complex logic
126+
- Explain test purposes
127+
- Document version-specific behavior
128+
129+
## Common Commands
130+
131+
### Server Commands
132+
```javascript
133+
bot.test.sayEverywhere('/time set 0') // Set time
134+
bot.test.sayEverywhere('/gamerule doDaylightCycle false') // Toggle game rules
135+
```
136+
137+
### Bot Operations
138+
```javascript
139+
async function f () {
140+
await bot.test.wait(200) // Wait for specified milliseconds
141+
await once(bot, 'time') // Wait for specific event
142+
}
143+
```
144+
145+
## Version Compatibility
146+
147+
- Test against multiple Minecraft versions
148+
- Handle version-specific packet formats
149+
- Consider backward compatibility
150+
- Document version-specific behavior
151+
152+
## Adding a New Test
153+
154+
When adding a new test, follow these steps:
155+
156+
1. **Create a new test file** in the `test/externalTests` directory. For example, `experience.js`.
157+
2. **Write the test logic** using async/await. Avoid using the `done` callback if possible.
158+
3. **Handle version differences** if necessary. For example, the experience command syntax differs between Minecraft versions:
159+
- For versions older than 1.13, use `/xp <amount> [player]`.
160+
- For versions 1.13 and newer, use `/xp add <player> <amount> points` or `/xp add <player> <amount> levels`.
161+
4. **Add event listeners** for debugging if needed, and ensure they are removed at the end of the test to prevent memory leaks.
162+
5. **Use `bot.chat`** to issue commands directly instead of `bot.test.runCommand`.
163+
6. **Run the test** for different Minecraft versions to ensure compatibility.
164+
165+
Example test structure:
166+
```javascript
167+
const assert = require('assert')
168+
const { once } = require('../../lib/promise_utils')
169+
170+
module.exports = () => async (bot) => {
171+
// Test logic here
172+
// Example: Check bot's experience state
173+
console.log('[experience test] Bot username:', bot.username)
174+
await bot.test.becomeSurvival()
175+
// ... more test logic ...
176+
// Remove event listeners at the end
177+
bot.removeListener('experience', expListener)
178+
console.log('[experience test] All checks passed!')
179+
}
180+
```
181+
182+
## Specific Details from Recent Experience
183+
184+
- **Version-Specific Command Syntax**: Always check the Minecraft Wiki or existing tests for the correct command syntax for each version. For example, the experience command syntax changed in 1.13.
185+
- **Event Listener Cleanup**: Always remove event listeners at the end of the test to prevent memory leaks. Use `bot.removeListener('eventName', listenerFunction)`.
186+
- **Use `bot.chat`**: For issuing commands, use `bot.chat` directly instead of `bot.test.runCommand` to ensure commands are sent correctly.
187+
- **Debugging**: Use `console.log` for debugging, but remove these statements before finalizing the test.
188+
189+
## Conclusion
190+
191+
When adding or modifying tests:
192+
1. Understand the feature being tested
193+
2. Write clear, focused tests
194+
3. Test across multiple versions
195+
4. Include proper error handling
196+
5. Clean up debug code before committing
197+
6. Document any version-specific behavior
198+
199+
Remember to remove any debugging `console.log` statements before finalizing the changes.

test/externalTests/experience.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const assert = require('assert')
2+
const { once } = require('../../lib/promise_utils')
3+
4+
module.exports = () => async (bot) => {
5+
await bot.test.becomeSurvival()
6+
await bot.test.wait(1000)
7+
8+
// Initial state
9+
const initialState = {
10+
level: bot.experience.level,
11+
points: bot.experience.points,
12+
progress: bot.experience.progress
13+
}
14+
assert(initialState.level >= 0, 'Initial experience level should be non-negative')
15+
assert(initialState.points >= 0, 'Initial experience points should be non-negative')
16+
assert(initialState.progress >= 0 && initialState.progress <= 1, 'Initial experience progress should be between 0 and 1')
17+
18+
// Test experience points
19+
const xpCommand = bot.registry.isOlderThan('1.13')
20+
? `/xp 10 ${bot.username}`
21+
: `/xp add ${bot.username} 10 points`
22+
23+
await bot.chat(xpCommand)
24+
await once(bot, 'experience')
25+
26+
// Verify after points
27+
assert(bot.experience.points >= 10, 'Experience points should be at least 10 after adding points')
28+
assert(bot.experience.level >= initialState.level, 'Experience level should not decrease after adding points')
29+
assert(bot.experience.progress >= 0 && bot.experience.progress <= 1, 'Experience progress should be between 0 and 1 after adding points')
30+
31+
// Test experience levels
32+
const levelCommand = bot.registry.isOlderThan('1.13')
33+
? `/xp 100L ${bot.username}`
34+
: `/xp add ${bot.username} 100 levels`
35+
36+
await bot.chat(levelCommand)
37+
await once(bot, 'experience')
38+
39+
// Verify after levels
40+
assert(bot.experience.level >= 100, 'Experience level should be at least 100 after adding levels')
41+
assert(bot.experience.points > 0, 'Experience points should be positive after adding levels')
42+
assert(bot.experience.progress >= 0 && bot.experience.progress <= 1, 'Experience progress should be between 0 and 1 after adding levels')
43+
}

0 commit comments

Comments
 (0)