diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Playthrough.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Playthrough.java
index 12904787e7dd5b99dadd54759b2615e7ab52edee..0433bdbdf3917141aa0e72c7cb124f69b26fafe0 100644
--- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Playthrough.java
+++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Playthrough.java
@@ -70,7 +70,7 @@ public class Playthrough {
             return;
         }
 
-        if (!currentPassage.hasLinks()) {
+        if (currentPassage != null && !currentPassage.hasLinks()) {
             gameState = PlaythroughState.STUCK;
         }
     }
diff --git a/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/PlaythroughTest.java b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/PlaythroughTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..fd49df0b77d10fee055a9072165ac5806dd63a88
--- /dev/null
+++ b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/PlaythroughTest.java
@@ -0,0 +1,46 @@
+package edu.ntnu.idatt2001.group_30.paths.model;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import edu.ntnu.idatt2001.group_30.paths.model.goals.Goal;
+import edu.ntnu.idatt2001.group_30.paths.model.goals.GoldGoal;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class PlaythroughTest {
+
+    private Playthrough playthrough;
+    private Passage openingPassage;
+
+    @BeforeEach
+    void setUp() {
+        openingPassage = new Passage("Opening passage", "This is the opening passage");
+        Player player = new Player("Player", 10, 20, 30);
+        Story story = new Story("My story", openingPassage);
+        List<Goal> goals = List.of(new GoldGoal(50));
+        Game game = new Game(player, story, goals);
+
+        playthrough = new Playthrough(game);
+    }
+
+    @Test
+    void testBeginPlaythrough() {
+        PlaythroughState state = playthrough.beginPlaythrough();
+        assertEquals(PlaythroughState.STUCK, state);
+        assertEquals(openingPassage, playthrough.getCurrentPassage());
+    }
+
+    @Test
+    void testMakeTurn() {
+        playthrough.beginPlaythrough();
+        Link link = new Link("Link", "Passage123");
+        PlaythroughState state = playthrough.makeTurn(link);
+        assertEquals(PlaythroughState.STUCK, state);
+    }
+
+    @Test
+    void testMakeTurnWithNullLink() {
+        assertThrows(NullPointerException.class, () -> playthrough.makeTurn(null));
+    }
+}
diff --git a/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoalFactoryTest.java b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoalFactoryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..04b20f582a43f3bc2bcb498792566a6db1589d5c
--- /dev/null
+++ b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoalFactoryTest.java
@@ -0,0 +1,52 @@
+package edu.ntnu.idatt2001.group_30.paths.model.goals;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.stream.Stream;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class GoalFactoryTest {
+
+    /*
+     * this is a factory class, so the typical beforeEach arrange step is not needed
+     */
+
+    @ParameterizedTest
+    @MethodSource("validGoalTypeAndValueProvider")
+    void getGoal_withValidGoalTypeAndValue_returnsGoalObject() {
+        GoalType goalType = GoalType.GOLD_GOAL;
+        Object goalValue = "100";
+
+        Goal<?> goal = GoalFactory.getGoal(goalType, goalValue);
+
+        assertEquals(GoldGoal.class, goal.getClass());
+    }
+
+    private static Stream<Arguments> validGoalTypeAndValueProvider() {
+        return Stream.of(
+            Arguments.of(GoalType.GOLD_GOAL, "100", GoldGoal.class),
+            Arguments.of(GoalType.HEALTH_GOAL, "50", HealthGoal.class),
+            Arguments.of(GoalType.SCORE_GOAL, "500", ScoreGoal.class)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("invalidGoalTypeAndValueProvider")
+    void getGoal_withInvalidGoalValue_throwsIllegalArgumentException() {
+        GoalType goalType = GoalType.GOLD_GOAL;
+        Object goalValue = "invalid_value";
+
+        assertThrows(IllegalArgumentException.class, () -> GoalFactory.getGoal(goalType, goalValue));
+    }
+
+    private static Stream<Arguments> invalidGoalTypeAndValueProvider() {
+        return Stream.of(
+            Arguments.of(GoalType.GOLD_GOAL, "invalid", GoldGoal.class),
+            Arguments.of(GoalType.HEALTH_GOAL, "-1", HealthGoal.class),
+            Arguments.of(GoalType.SCORE_GOAL, "", ScoreGoal.class)
+        );
+    }
+}
diff --git a/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/utils/TextValidationTest.java b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/utils/TextValidationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..17bc6bbd6f4ec608f511cd5f27ab7311e93ed21b
--- /dev/null
+++ b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/utils/TextValidationTest.java
@@ -0,0 +1,26 @@
+package edu.ntnu.idatt2001.group_30.paths.model.utils;
+
+import javafx.scene.control.TextFormatter;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class TextValidationTest {
+
+    @Test
+    void createIntegerTextFormatter_should_return_formatter_with_default_start_value() {
+        int expectedStartValue = 100;
+
+        TextFormatter<Integer> formatter = TextValidation.createIntegerTextFormatter();
+
+        Assertions.assertEquals(expectedStartValue, formatter.getValue());
+    }
+
+    @Test
+    void createIntegerTextFormatter_should_return_formatter_with_custom_start_value() {
+        int startValue = 50;
+
+        TextFormatter<Integer> formatter = TextValidation.createIntegerTextFormatter(startValue);
+
+        Assertions.assertEquals(startValue, formatter.getValue());
+    }
+}