A browser-based game for learning German grammar with drag-and-drop exercises.
- Interactive drag-and-drop exercises for German articles, pronouns, and verb forms
- Mobile and desktop support
- Progress tracking with localStorage
- Adaptive learning that focuses on challenging areas
- Clone the repository:
git clone <repository-url>
cd german-case-game- Install dependencies:
npm install- Start the development server:
npm run dev- Build for production:
npm run buildThe project includes a comprehensive test suite using Jest and Testing Library.
# Run all tests
npm test
# Run tests in watch mode (for development)
npm run test:watch
# Generate coverage report
npm run test:coverage- Unit Tests: Testing individual utility functions (
utils.test.ts,extracted-utils.test.ts) - Component Tests: Testing the rendering and DOM interactions (
rendering.test.ts) - Integration Tests: Testing game logic and challenge validation (
challenge.test.ts)
The original codebase has been refactored to:
- Extract pure utility functions into a separate module (
src/utils.ts) - Separate game logic from rendering logic
- Make functions more modular and testable
When adding new features, create corresponding test files in the __tests__ directory.
Example:
import { myNewFunction } from '../src/myModule';
describe('My New Feature', () => {
it('should behave as expected', () => {
const result = myNewFunction('input');
expect(result).toBe('expected output');
});
});For full end-to-end testing, consider adding Cypress or Playwright tests:
- Install Cypress:
npm install --save-dev cypress- Add a test script to package.json:
"scripts": {
"cy:open": "cypress open",
"cy:run": "cypress run"
}- Create a basic e2e test for the game:
// cypress/integration/game.spec.js
describe('German Grammar Game', () => {
it('loads the game and displays the first challenge', () => {
cy.visit('/');
cy.get('h2').should('be.visible');
cy.get('.draggable-card').should('have.length.greaterThan', 0);
cy.get('.drop-zone').should('have.length.greaterThan', 0);
});
it('allows dragging cards to drop zones', () => {
cy.visit('/');
// Test drag and drop interaction
cy.get('.draggable-card').first().drag('.drop-zone').first();
cy.get('.drop-zone .draggable-card').should('be.visible');
});
});