added comments and integration test

main
plush2408 2024-06-18 01:46:57 +02:00
parent f6fa31196e
commit 5ebe14df32
12 changed files with 290 additions and 77 deletions

View File

@ -8,15 +8,16 @@ void main() {
);
}
// Main application widget
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: halloweenTheme,
home: const PlayerRegistry(),
debugShowCheckedModeBanner: false,
theme: halloweenTheme, // Apply custom theme
home: const PlayerRegistry(), // Set initial screen to PlayerRegistry
debugShowCheckedModeBanner: false, // Disable debug banner
);
}
}

View File

@ -1,14 +1,22 @@
import 'package:werwolf/models/role.dart';
import 'player.dart';
class Game {
// List to store player objects
List<Player> players = [];
// List to store player names
List playernames = [];
// Initial number of werewolves
int numWolves = 1;
// Map to store special roles and their activation status
Map specialRoles = <Role, bool>{};
// Constructor to initialize the game with player names
Game({required this.playernames}) {
// Initialize specialRoles map, setting all special roles to false
for (Role role in Role.values) {
if (role != Role.dorfbewohner && role != Role.werwolf) {
specialRoles[role] = false;
@ -16,43 +24,64 @@ class Game {
}
}
// Method to increment the number of werewolves
void incrementWolves() {
// Increment only if conditions are met: enough players and balance maintained
if (numWolves < playernames.length - 1 &&
(playernames.length) >= ((numWolves + 1) * 3)) {
numWolves++;
}
}
// Method to decrement the number of werewolves
void decrementWolves() {
// Decrement only if there's more than one werewolf
if (numWolves > 1) {
numWolves--;
}
}
// Method to get the current number of werewolves
int getWolves() {
return numWolves;
}
// Method to get all players with their assigned roles
List<Player> getAllPlayers() {
// Clear the players list to start fresh
players.clear();
// List to hold roles randomly assigned to players
List<Role> randomRoles = [];
// Add werewolf roles to the list
for (var i = 0; i < numWolves; i++) {
randomRoles.add(Role.werwolf);
}
// Add active special roles to the list
for (var specialRole in specialRoles.keys) {
if (specialRoles[specialRole]) {
randomRoles.add(specialRole);
}
}
// Fill the remaining roles with dorfbewohner
for (var i = randomRoles.length; i < playernames.length; i++) {
randomRoles.add(Role.dorfbewohner);
}
// Shuffle the roles to ensure randomness
randomRoles.shuffle();
// Assign roles to players and create Player objects
for (var playerName in playernames) {
players
.add(Player(name: playerName, role: randomRoles.last, isDead: false));
randomRoles.removeLast();
}
// Return the list of players with their roles
return players;
}
}

View File

@ -1,9 +1,14 @@
import 'package:werwolf/models/role.dart';
// Define a class named Player
class Player {
// Declare a string variable to store the player's name
String name;
// Declare a variable of type Role to store the player's role
Role role;
// Declare a boolean variable to indicate whether the player is dead
bool isDead;
// Constructor for the Player class with required parameters for name, role, and isDead status
Player({required this.name, required this.role, required this.isDead});
}

View File

@ -1,18 +1,21 @@
// Enum representing different roles in the game
enum Role { dorfbewohner, werwolf, joker, seher, doctor }
// Extension on the Role enum to provide string representations
extension RoleExtension on Role {
// Getter to convert enum value to its string representation
String get stringValue {
switch (this) {
case Role.dorfbewohner:
return 'Dorfbewohner';
return 'Dorfbewohner'; // Returns 'Dorfbewohner' for the dorfbewohner role
case Role.werwolf:
return 'Werwolf';
return 'Werwolf'; // Returns 'Werwolf' for the werwolf role
case Role.joker:
return 'Joker';
return 'Joker'; // Returns 'Joker' for the joker role
case Role.seher:
return 'Seher';
return 'Seher'; // Returns 'Seher' for the seher role
case Role.doctor:
return 'Doctor';
return 'Doctor'; // Returns 'Doctor' for the doctor role
}
}
}

View File

@ -7,6 +7,7 @@ import 'package:werwolf/screens/gameboard.dart';
import '../models/player.dart';
import '../models/role.dart';
// FlipingCard is a StatefulWidget that takes a list of players as input
class FlipingCard extends StatefulWidget {
final List<Player> players;
const FlipingCard({required this.players, super.key});
@ -15,17 +16,19 @@ class FlipingCard extends StatefulWidget {
State<FlipingCard> createState() => _FlipingCardState();
}
// State class for FlipingCard
class _FlipingCardState extends State<FlipingCard> {
int index = 0;
int index = 0; // Index to keep track of the current player
late FlipCardController _controller;
late FlipCardController _controller; // Controller for the flip card
@override
void initState() {
super.initState();
_controller = FlipCardController();
_controller = FlipCardController(); // Initialize the flip card controller
}
// Method to render the content of the flip card
_renderContent(context) {
return Card(
elevation: 0.0,
@ -56,7 +59,7 @@ class _FlipingCardState extends State<FlipingCard> {
),
),
const Text(
'Klick um deine Rolle zu sehen!',
'Click to see your role!',
textAlign: TextAlign.center,
),
],
@ -124,14 +127,14 @@ class _FlipingCardState extends State<FlipingCard> {
onPressed: () {
setState(() {
if (index > 0 && index <= widget.players.length) {
index--;
index--; // Go to the previous player
if (!_controller.state!.isFront) {
_controller.toggleCardWithoutAnimation();
}
}
});
},
child: const Text("Zurück"),
child: const Text("Back"),
),
),
Flexible(
@ -139,11 +142,12 @@ class _FlipingCardState extends State<FlipingCard> {
onPressed: () {
setState(() {
if (index >= 0 && index < widget.players.length - 1) {
index++;
index++; // Go to the next player
if (!_controller.state!.isFront) {
_controller.toggleCardWithoutAnimation();
}
} else if (index == widget.players.length - 1) {
// Navigate to the game board if it's the last player
Navigator.push(
context,
MaterialPageRoute(
@ -155,8 +159,8 @@ class _FlipingCardState extends State<FlipingCard> {
});
},
child: Text(index != widget.players.length - 1
? "Nächster Spieler"
: "Spiel anfangen!"),
? "Next Player"
: "Start Game!"),
),
),
],

View File

@ -3,6 +3,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import '../models/player.dart';
import '../models/role.dart';
// Main widget for displaying the player grid
class PlayerGridView extends StatefulWidget {
final List<Player> players;
@ -14,7 +15,7 @@ class PlayerGridView extends StatefulWidget {
}
class _PlayerGridViewState extends State<PlayerGridView> {
bool isNight = true;
bool isNight = true; // Variable to track whether it is night or day
@override
void initState() {
@ -35,7 +36,7 @@ class _PlayerGridViewState extends State<PlayerGridView> {
),
const SizedBox(width: 10),
Text(
isNight ? 'Nacht' : 'Tag',
isNight ? 'Nacht' : 'Tag', // Display whether it is night or day
),
],
),
@ -44,21 +45,21 @@ class _PlayerGridViewState extends State<PlayerGridView> {
IconButton(
icon: const Icon(Icons.info),
onPressed: () {
_showRolesDialog();
_showRolesDialog(); // Show dialog with player roles
},
),
],
leading: IconButton(
icon: const Icon(FontAwesomeIcons.xmark),
onPressed: () {
Navigator.popUntil(context, ModalRoute.withName('/'));
Navigator.popUntil(context, ModalRoute.withName('/')); // Return to main screen
},
),
),
body: Container(
color: isNight
? const Color(0xff2d2d2d)
: const Color.fromARGB(255, 194, 216, 225),
: const Color.fromARGB(255, 194, 216, 225), // Set background color based on night/day
padding: const EdgeInsets.only(left: 15, right: 15),
child: Column(
children: [
@ -66,7 +67,7 @@ class _PlayerGridViewState extends State<PlayerGridView> {
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount:
MediaQuery.of(context).size.shortestSide < 600 ? 2 : 4,
MediaQuery.of(context).size.shortestSide < 600 ? 2 : 4, // Adjust grid based on screen size
mainAxisSpacing: 10,
crossAxisSpacing: 10,
),
@ -78,14 +79,14 @@ class _PlayerGridViewState extends State<PlayerGridView> {
onTap: () {
setState(() {
if (!widget.players[index].isDead) {
_killPlayer(widget.players[index]);
_killPlayer(widget.players[index]); // Mark player as dead
}
});
},
child: Card(
color: widget.players[index].isDead
? Colors.grey
: Theme.of(context).colorScheme.primary,
: Theme.of(context).colorScheme.primary, // Change card color based on player status
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@ -98,7 +99,7 @@ class _PlayerGridViewState extends State<PlayerGridView> {
),
if (widget.players[index].isDead)
const Icon(Icons.close,
color: Colors.red, size: 48),
color: Colors.red, size: 48), // Show icon if player is dead
],
),
),
@ -113,7 +114,7 @@ class _PlayerGridViewState extends State<PlayerGridView> {
Padding(
padding: const EdgeInsets.only(bottom: 60, top: 10),
child: ElevatedButton(
onPressed: _changePhase,
onPressed: _changePhase, // Change phase between night and day
child: Text(isNight ? 'Tag skippen' : 'Nacht skippen'),
),
),
@ -127,14 +128,14 @@ class _PlayerGridViewState extends State<PlayerGridView> {
if (isNight) {
if (player.role != Role.werwolf) {
player.isDead = true;
_checkWinCondition();
_checkWinCondition(); // Check win condition after killing player
isNight = false;
}
} else {
player.isDead = true;
_checkWinCondition();
_checkWinCondition(); // Check win condition after killing player
if (player.role == Role.joker) {
_showWinDialog('Der Joker hat gewonnen!');
_showWinDialog('Der Joker hat gewonnen!'); // Show win dialog for Joker
}
isNight = true;
}
@ -142,11 +143,7 @@ class _PlayerGridViewState extends State<PlayerGridView> {
}
void _changePhase() {
if (isNight) {
isNight = false;
} else {
isNight = true;
}
isNight = !isNight; // Toggle between night and day
setState(() {});
}
@ -159,9 +156,9 @@ class _PlayerGridViewState extends State<PlayerGridView> {
.length;
if (countWolves == 0) {
_showWinDialog('Die Dorfbewohner haben gewonnen!');
_showWinDialog('Die Dorfbewohner haben gewonnen!'); // Show win dialog for villagers
} else if (countWolves >= countVillagers) {
_showWinDialog('Die Werwölfe haben gewonnen!');
_showWinDialog('Die Werwölfe haben gewonnen!'); // Show win dialog for werewolves
}
}
@ -176,7 +173,7 @@ class _PlayerGridViewState extends State<PlayerGridView> {
TextButton(
child: const Text('Spiel beenden'),
onPressed: () {
Navigator.popUntil(context, ModalRoute.withName('/'));
Navigator.popUntil(context, ModalRoute.withName('/')); // Return to main screen
},
),
],
@ -217,7 +214,7 @@ class _PlayerGridViewState extends State<PlayerGridView> {
TextButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).pop(); // Close dialog
},
),
],

View File

@ -1,25 +1,28 @@
import 'package:flutter/material.dart';
import 'package:werwolf/screens/settings.dart';
// Define the PlayerRegistry StatefulWidget
class PlayerRegistry extends StatefulWidget {
const PlayerRegistry({super.key});
@override
// Create the state for the PlayerRegistry widget
// ignore: library_private_types_in_public_api
_PlayerRegistryState createState() => _PlayerRegistryState();
}
// Define the state for the PlayerRegistry widget
class _PlayerRegistryState extends State<PlayerRegistry> {
final TextEditingController _playerController = TextEditingController();
final _formKey = GlobalKey<FormState>();
String _errorMessage = "";
List<String> playernames = [];
final TextEditingController _playerController = TextEditingController(); // Controller for player name input
final _formKey = GlobalKey<FormState>(); // Key for form validation
String _errorMessage = ""; // Error message string
List<String> playernames = []; // List to store player names
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Werwolf"),
title: const Text("Werwolf"), // App bar title
centerTitle: true,
),
body: Padding(
@ -32,8 +35,8 @@ class _PlayerRegistryState extends State<PlayerRegistry> {
key: _formKey,
controller: _playerController,
decoration: InputDecoration(
errorText: _errorMessage == "" ? null : _errorMessage,
labelText: 'Spielername',
errorText: _errorMessage == "" ? null : _errorMessage, // Display error message if exists
labelText: 'Spielername', // Label for text field
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.primary),
@ -54,14 +57,14 @@ class _PlayerRegistryState extends State<PlayerRegistry> {
onSubmitted: (value) {
setState(() {
if (_playerController.text.isEmpty) {
_errorMessage = "Spielername ist leer!";
_errorMessage = "Spielername ist leer!"; // Error for empty name
} else if (playernames.contains(value)) {
_errorMessage = "Dieser Spieler existiert bereits";
_errorMessage = "Dieser Spieler existiert bereits"; // Error for duplicate name
_playerController.clear();
} else {
_errorMessage = "";
_playerController.clear();
playernames.add(value);
playernames.add(value); // Add valid player name to list
}
});
},
@ -73,15 +76,15 @@ class _PlayerRegistryState extends State<PlayerRegistry> {
itemBuilder: (context, index) {
return ListTile(
title: Text(
playernames[index],
playernames[index], // Display player name
),
trailing: IconButton(
onPressed: () {
setState(() {
playernames.remove(playernames[index]);
playernames.remove(playernames[index]); // Remove player name from list
});
},
icon: const Icon(Icons.remove)),
icon: const Icon(Icons.remove)), // Remove icon button
);
},
),
@ -93,16 +96,16 @@ class _PlayerRegistryState extends State<PlayerRegistry> {
context,
MaterialPageRoute(
builder: (context) => GameSettings(
playernames: playernames,
playernames: playernames, // Pass player names to next screen
),
));
} else {
setState(() {
_errorMessage = "Es müssen mindestens 6 Spieler sein!";
_errorMessage = "Es müssen mindestens 6 Spieler sein!"; // Error for not enough players
});
}
},
child: const Text('Spiel einstellen'),
child: const Text('Spiel einstellen'), // Button to start game settings
),
const Padding(padding: EdgeInsets.all(30))
],

View File

@ -4,6 +4,7 @@ import 'package:werwolf/screens/flippingcards.dart';
import '../models/game.dart';
import '../models/role.dart';
// Main widget for game settings
class GameSettings extends StatefulWidget {
final List<String> playernames;
const GameSettings({required this.playernames, super.key});
@ -17,7 +18,7 @@ class _GameSettingsState extends State<GameSettings> {
@override
void initState() {
game = Game(playernames: widget.playernames);
game = Game(playernames: widget.playernames); // Initialize the game with player names
super.initState();
}
@ -27,7 +28,7 @@ class _GameSettingsState extends State<GameSettings> {
appBar: AppBar(
title: Text(
"Werwolf",
style: Theme.of(context).textTheme.titleLarge,
style: Theme.of(context).textTheme.titleLarge, // Use large title style from theme
),
centerTitle: true,
),
@ -36,8 +37,8 @@ class _GameSettingsState extends State<GameSettings> {
child: Column(
children: [
Text(
"Anzahl der Spieler ${widget.playernames.length}",
style: Theme.of(context).textTheme.titleLarge,
"Anzahl der Spieler ${widget.playernames.length}", // Display number of players
style: Theme.of(context).textTheme.titleLarge, // Use large title style from theme
),
const Divider(
height: 60,
@ -47,14 +48,13 @@ class _GameSettingsState extends State<GameSettings> {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"Anzahl der Werwölfe ${game.getWolves()}",
style:
Theme.of(context).textTheme.bodyLarge,
"Anzahl der Werwölfe ${game.getWolves()}", // Display number of werewolves
style: Theme.of(context).textTheme.bodyLarge, // Use large body style from theme
),
IconButton(
onPressed: () {
setState(() {
game.decrementWolves();
game.decrementWolves(); // Decrease the number of werewolves
});
},
icon: const Icon(Icons.remove, color: Colors.white),
@ -62,7 +62,7 @@ class _GameSettingsState extends State<GameSettings> {
IconButton(
onPressed: () {
setState(() {
game.incrementWolves();
game.incrementWolves(); // Increase the number of werewolves
});
},
icon: const Icon(Icons.add, color: Colors.white),
@ -75,9 +75,8 @@ class _GameSettingsState extends State<GameSettings> {
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 20),
child: Text(
"Spezielle Rollen",
style:
Theme.of(context).textTheme.titleLarge,
"Spezielle Rollen", // Display special roles section
style: Theme.of(context).textTheme.titleLarge, // Use large title style from theme
),
),
Expanded(
@ -89,22 +88,20 @@ class _GameSettingsState extends State<GameSettings> {
Role role = Role.values[index];
return ListTile(
title: Text(
role.stringValue,
style: Theme.of(context)
.textTheme
.bodyLarge,
role.stringValue, // Display role name
style: Theme.of(context).textTheme.bodyLarge, // Use large body style from theme
),
trailing: Switch(
value: game.specialRoles[role],
onChanged: (bool value) {
setState(() {
game.specialRoles[role] = value;
game.specialRoles[role] = value; // Toggle special role
});
},
),
);
}
return Container();
return Container(); // Return empty container if not a special role
},
),
),
@ -113,13 +110,12 @@ class _GameSettingsState extends State<GameSettings> {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
FlipingCard(players: game.getAllPlayers()),
builder: (context) => FlipingCard(players: game.getAllPlayers()), // Start game
),
);
},
child: const Text(
'Spiel starten!',
'Spiel starten!', // Start game button text
),
),
const Padding(padding: EdgeInsets.all(30)),

View File

@ -118,6 +118,11 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_driver:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
flutter_lints:
dependency: "direct dev"
description:
@ -147,6 +152,11 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.0"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
glob:
dependency: transitive
description:
@ -171,6 +181,11 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.2"
integration_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
io:
dependency: transitive
description:
@ -283,6 +298,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.0"
platform:
dependency: transitive
description:
name: platform
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
url: "https://pub.dev"
source: hosted
version: "3.1.4"
pool:
dependency: transitive
description:
@ -291,6 +314,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.5.1"
process:
dependency: transitive
description:
name: process
sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32"
url: "https://pub.dev"
source: hosted
version: "5.0.2"
pub_semver:
dependency: transitive
description:
@ -384,6 +415,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.0"
sync_http:
dependency: transitive
description:
name: sync_http
sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
url: "https://pub.dev"
source: hosted
version: "0.3.1"
term_glyph:
dependency: transitive
description:
@ -464,6 +503,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.4.5"
webdriver:
dependency: transitive
description:
name: webdriver
sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e"
url: "https://pub.dev"
source: hosted
version: "3.0.3"
webkit_inspection_protocol:
dependency: transitive
description:

View File

@ -17,6 +17,8 @@ dev_dependencies:
sdk: flutter
flutter_lints: ^2.0.0
test: ^1.25.2
integration_test:
sdk: flutter
flutter:
uses-material-design: true

View File

@ -0,0 +1,76 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:werwolf/main.dart' as app;
import 'package:werwolf/screens/playerregistry.dart';
import 'package:werwolf/screens/settings.dart';
import 'package:werwolf/screens/flippingcards.dart';
import 'package:werwolf/screens/gameboard.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Werwolf Game Integration Tests', () {
testWidgets('Complete game flow', (WidgetTester tester) async {
app.main();
await tester.pumpAndSettle();
// Ensure we are on the PlayerRegistry screen
expect(find.byType(PlayerRegistry), findsOneWidget);
// Add players
for (int i = 0; i < 6; i++) {
await tester.enterText(find.byType(TextField), 'Player $i');
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle();
}
// Ensure all players are added
for (int i = 0; i < 6; i++) {
expect(find.text('Player $i'), findsOneWidget);
}
// Navigate to GameSettings screen
await tester.tap(find.text('Spiel einstellen'));
await tester.pumpAndSettle();
expect(find.byType(GameSettings), findsOneWidget);
// Ensure the number of players and wolves are displayed correctly
expect(find.text('Anzahl der Spieler 6'), findsOneWidget);
expect(find.text('Anzahl der Werwölfe 1'), findsOneWidget);
// Toggle a special role
await tester.tap(find.byType(Switch).first);
await tester.pumpAndSettle();
expect((tester.widget(find.byType(Switch).first) as Switch).value, true);
// Navigate to FlipingCard screen
await tester.tap(find.text('Spiel starten!'));
await tester.pumpAndSettle();
expect(find.byType(FlipingCard), findsOneWidget);
// Flip through all players
for (int i = 0; i < 6; i++) {
await tester.tap(find.text('Klick um deine Rolle zu sehen!'));
await tester.pumpAndSettle();
await tester.tap(find.text('Nächster Spieler'));
await tester.pumpAndSettle();
}
// Ensure we navigate to the game board
await tester.tap(find.text('Spiel anfangen!'));
await tester.pumpAndSettle();
expect(find.byType(PlayerGridView), findsOneWidget);
// Tap to kill a player
await tester.tap(find.text('Player 0'));
await tester.pumpAndSettle();
expect(find.byIcon(Icons.close), findsOneWidget);
// Skip phase
await tester.tap(find.text('Tag skippen'));
await tester.pumpAndSettle();
expect(find.text('Nacht skippen'), findsOneWidget);
});
});
}

View File

@ -0,0 +1,50 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:werwolf/screens/settings.dart';
import 'package:werwolf/screens/flippingcards.dart';
void main() {
group('GameSettings Tests', () {
List<String> playerNames = ['Alice', 'Bob', 'Charlie', 'Dave', 'Eve', 'Frank'];
testWidgets('Displays number of players', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(home: GameSettings(playernames: playerNames)));
expect(find.text('Anzahl der Spieler 6'), findsOneWidget);
});
testWidgets('Displays number of wolves and increments/decrements correctly', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(home: GameSettings(playernames: playerNames)));
expect(find.text('Anzahl der Werwölfe 1'), findsOneWidget);
await tester.tap(find.byIcon(Icons.add));
await tester.pumpAndSettle();
expect(find.text('Anzahl der Werwölfe 2'), findsOneWidget);
await tester.tap(find.byIcon(Icons.remove));
await tester.pumpAndSettle();
expect(find.text('Anzahl der Werwölfe 1'), findsOneWidget);
});
testWidgets('Displays special roles and toggles switches', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(home: GameSettings(playernames: playerNames)));
expect(find.text('Spezielle Rollen'), findsOneWidget);
await tester.tap(find.byType(Switch).first);
await tester.pumpAndSettle();
expect((tester.widget(find.byType(Switch).first) as Switch).value, true);
});
testWidgets('Navigates to FlipingCard screen on start', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(home: GameSettings(playernames: playerNames)));
await tester.tap(find.text('Spiel starten!'));
await tester.pumpAndSettle();
expect(find.byType(FlipingCard), findsOneWidget);
});
});
}