Overview
Lichess has comprehensive test coverage for both backend and frontend:- Backend tests: Scala tests using munit and scalacheck
- Frontend tests: TypeScript tests using Node.js test runner
Backend Testing
Test Framework
Lichess uses munit as the primary testing framework:Property-Based Testing
scalacheck is used for property-based testing:Running Tests
All Tests
Run all tests in the project:Module Tests
Test specific modules:Specific Test Class
Run a single test class:Pattern Matching
Run tests matching a pattern:Single Test
Run a specific test within a class:Test Organization
Tests are located in each module’s test directory:Test Dependencies
Test utilities are available via thetests.bundle:
- munit
- scalacheck
- munitCheck (integration)
- chess.testKit
Test-Only Dependencies
Access test utilities from other modules:common module.
Writing Tests
package lila.mymodule
import munit.FunSuite
class MyTest extends FunSuite:
test("feature works correctly"):
val result = MyClass.doSomething()
assertEquals(result, expected)
import scala.concurrent.Future
test("async operation".ignore): // TODO remove ignore
val futureResult = MyClass.asyncOperation()
futureResult.map: result =>
assertEquals(result, expected)
class GameTest extends FunSuite:
val testGame = FunFixture[Game](
setup = _ => Game.make(...),
teardown = _ => ()
)
testGame.test("game logic"): game =>
assertEquals(game.turns, 0)
Test Coverage
Modules with extensive test coverage:- game: Game logic, PGN, move validation
- rating: Glicko-2 calculations
- user: User accounts, authentication
- tournament: Pairing algorithms
- study: Analysis board logic
- puzzle: Puzzle rating
Frontend Testing
Test Framework
Frontend tests use Node.js built-in test runner:Running Tests
Use theui/test script:
Test Location
Tests are intests/ subdirectories:
Example Test
Test Build Process
The test runner:- Compiles TypeScript tests to JavaScript
- Runs tests with Node.js test runner
- Reports results
Watch Mode
Continuously run tests on file changes:Integration Testing
Manual Testing
For full integration testing:Browser Testing
Lichess uses Browserstack for cross-browser testing. Supported browsers:- Firefox 115+
- Chrome/Chromium 112+
- Edge 109+
- Safari 13.1+
- Opera 91+
Continuous Integration
GitHub Actions
Tests run automatically on every commit:Pre-commit Hooks
Run tests before committing:Test-Driven Development
Recommended TDD workflow:Debugging Tests
Backend Test Debugging
Add debug output:Frontend Test Debugging
Use Node.js debugger:Performance Testing
Backend Performance
Benchmark critical code paths:Frontend Performance
Time-based assertions:Test Best Practices
Do
- ✅ Write tests for new features
- ✅ Test edge cases and error conditions
- ✅ Keep tests fast and focused
- ✅ Use descriptive test names
- ✅ Test behavior, not implementation
- ✅ Run tests before committing
Don’t
- ❌ Test private implementation details
- ❌ Write tests that depend on external services (without mocks)
- ❌ Create flaky tests that pass/fail randomly
- ❌ Ignore failing tests
- ❌ Write tests that are slower than the code they test
Troubleshooting
Tests Fail Locally but Pass in CI
- Check for environment-specific issues
- Verify dependencies are up-to-date
- Check system time/timezone settings
Flaky Tests
- Add
.ignoreto investigate later: - Increase timeouts for async tests
- Avoid tests that depend on timing
Slow Tests
Next Steps
- Review development setup
- Understand the module structure
- Learn about building the project

