diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/NewGameController.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/NewGameController.java
index e92647caf318e0310961557fd40f7d086403c501..6b5741fab46419d3bb8b62d04425da3c156f7f22 100644
--- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/NewGameController.java
+++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/NewGameController.java
@@ -2,8 +2,7 @@ package edu.ntnu.idatt2001.group_30.paths.controller;
 
 import static edu.ntnu.idatt2001.group_30.paths.PathsSingleton.INSTANCE;
 
-import edu.ntnu.idatt2001.group_30.paths.model.filehandling.StoryFileHandler;
-import edu.ntnu.idatt2001.group_30.paths.view.views.NewStoryView;
+import edu.ntnu.idatt2001.group_30.paths.model.filehandling.StoryFileReader;
 import edu.ntnu.idatt2001.group_30.paths.view.views.PlaythroughView;
 import java.io.File;
 import java.io.IOException;
@@ -15,9 +14,9 @@ public class NewGameController extends Controller {
     }
 
     public void setStory(File storyFile) {
-        StoryFileHandler storyFileHandler = new StoryFileHandler();
+        StoryFileReader storyFileReader = new StoryFileReader();
         try {
-            INSTANCE.setStory(storyFileHandler.readStoryFromFile(storyFile));
+            INSTANCE.setStory(storyFileReader.parse(storyFile));
             INSTANCE.setStoryFile(storyFile);
         } catch (IOException | InstantiationException ex) {
             throw new RuntimeException(ex);
diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Link.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Link.java
index 2b2c9b453610492b9ee48116f24d15c0a53e4ea6..1ee84cea842810721cd34736bac990cb36f766b6 100644
--- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Link.java
+++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Link.java
@@ -75,21 +75,4 @@ public class Link {
     public int hashCode() {
         return Objects.hash(reference);
     }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("[").append(text).append("](").append(reference).append(")\n");
-
-        for (Action<?> action : actions) {
-            sb
-                .append("<")
-                .append(action.getClass().getSimpleName())
-                .append(">\\")
-                .append(action.getActionValue())
-                .append("/\n");
-        }
-
-        return sb.toString();
-    }
 }
diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Passage.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Passage.java
index dc8694cbc1ed89879d438b1134afc46324dd31d9..f4a7731655eb703736d01abc9780950a7c50d7d0 100644
--- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Passage.java
+++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Passage.java
@@ -73,17 +73,6 @@ public class Passage {
         return this.links.size() > 0;
     }
 
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-
-        sb.append("::").append(title).append("\n").append(content).append("\n");
-
-        links.forEach(link -> sb.append(link.toString()));
-
-        return sb.toString();
-    }
-
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
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/main/java/edu/ntnu/idatt2001/group_30/paths/model/Story.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Story.java
index 29c8a098a363ac5bb746467d960886828214a9cc..ba897708886ddd97c926abb4f20f1ee1b65e7f0b 100644
--- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Story.java
+++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Story.java
@@ -127,20 +127,6 @@ public class Story {
         return openingPassage;
     }
 
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append(this.title).append("\n\n");
-        sb.append(this.openingPassage.toString()).append("\n");
-
-        this.passages.values()
-            .forEach(passage -> {
-                if (!passage.equals(openingPassage)) sb.append(passage.toString()).append("\n");
-            });
-
-        return sb.toString();
-    }
-
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileHandler.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileReader.java
similarity index 69%
rename from src/main/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileHandler.java
rename to src/main/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileReader.java
index 358227ecd9c0e93c00a7f19f463a6dedc696d541..1234eb3afcb5963b2705b6aacdfe2809d8606f1f 100644
--- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileHandler.java
+++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileReader.java
@@ -8,104 +8,46 @@ import edu.ntnu.idatt2001.group_30.paths.model.Story;
 import edu.ntnu.idatt2001.group_30.paths.model.actions.Action;
 import edu.ntnu.idatt2001.group_30.paths.model.actions.ActionFactory;
 import edu.ntnu.idatt2001.group_30.paths.model.actions.ActionType;
-import java.io.*;
-import java.util.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 /**
- * This class maintains the storage and retrieval of a Story file. This is done through a Buffered
- * writer and reader.
+ * The StoryFileReader class is responsible for reading a story file and parsing it to create a story object.
+ * It is also responsible for validating the file.
+ *
+ * @author Trym Hamer Gudvangen, Nicolai H. Brand.
  */
-public class StoryFileHandler {
+public class StoryFileReader {
 
     private final Pattern LINK_PATTERN = Pattern.compile("\\[.*]\\(.*\\)");
     private final Pattern ACTION_PATTERN = Pattern.compile("<.*>\\\\.*/");
 
-    /**
-     * This method takes a story and writes its contents to a .paths file. The story information is transcribed
-     * in the given format:
-     * <pre>
-     *  Story title
-     *
-     *  ::Opening Passage Title
-     *  Opening Passage Content
-     *  [Link Text](Link Reference)
-     *
-     *  ::Another Passage Title
-     *  Passage Content
-     *  [Link Text](Link Reference)
-     *  {@code <Action Type>}\Action Value/
-     *  [Link Text](Link Reference)
-     *
-     *  ...
-     * </pre>
-     * @param story         The story to be saved, given as a Story object.
-     * @param fileName      The name of the file the story will be saved to, given as a String.
-     * @throws IOException  This exception is thrown if an I/O error occurs with the writer.
-     */
-    public void createStoryFile(Story story, String fileName) throws IOException {
-        Objects.requireNonNull(fileName, "File name cannot be null");
-        File file = FileHandler.createFile(fileName);
-        createStoryFile(story, file);
-    }
-
-    //TODO: add test for story files...
-
-    /**
-     * This method takes a story and writes its contents to a .paths file. The story information is transcribed
-     * in the given format:
-     * <pre>
-     *  Story title
-     *
-     *  ::Opening Passage Title
-     *  Opening Passage Content
-     *  [Link Text](Link Reference)
-     *
-     *  ::Another Passage Title
-     *  Passage Content
-     *  [Link Text](Link Reference)
-     *  {@code <Action Type>}\Action Value/
-     *  [Link Text](Link Reference)
-     *
-     *  ...
-     * </pre>
-     * @param story         The story to be saved, given as a Story object.
-     * @param file          The file the story will be saved to, given as a File object.
-     * @throws IOException  This exception is thrown if an I/O error occurs with the writer.
-     */
-    public void createStoryFile(Story story, File file) throws IOException {
-        Objects.requireNonNull(story, "Story cannot be null");
-        Objects.requireNonNull(file, "File cannot be null");
-        if (FileHandler.fileExists(file)) throw new IllegalArgumentException(
-                "You cannot overwrite a pre-existing story file"
-        );
-        try (BufferedWriter storyBufferedWriter = new BufferedWriter(new FileWriter(file))) {
-            storyBufferedWriter.write(story.toString());
-        }
-    }
-
     /**
      * This method takes a story file and parses it to create a story object.
      * @param fileName      The name of the story file, given as a String.
      * @return              The story from the file, given as a Story object.
      * @throws IOException  This exception is thrown if an I/O error occurs with the reader.
      */
-    public Story readStoryFromFile(String fileName) throws IOException, InstantiationException {
+    public Story parse(String fileName) throws IOException, InstantiationException {
         Objects.requireNonNull(fileName, "File name cannot be null");
         File file = new File(FileHandler.getFileSourcePath(fileName));
-        return readStoryFromFile(file);
+        return parse(file);
     }
 
-    //TODO: test new readStory method... basically same as earlier
-
     /**
      * This method takes a story file and parses it to create a story object.
      * @param file      The story file, given as a File object.
      * @return              The story from the file, given as a Story object.
      * @throws IOException  This exception is thrown if an I/O error occurs with the reader.
      */
-    public Story readStoryFromFile(File file) throws IOException, InstantiationException {
+    public Story parse(File file) throws IOException, InstantiationException {
         Objects.requireNonNull(file, "File does not exist");
         if (!FileHandler.fileExists(file)) throw new IllegalArgumentException("There is no story file with that name!");
         Story story;
diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileWriter.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..40256fd7981c102e3eb8f9d8a2a9b6a1f83ce154
--- /dev/null
+++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileWriter.java
@@ -0,0 +1,112 @@
+package edu.ntnu.idatt2001.group_30.paths.model.filehandling;
+
+import edu.ntnu.idatt2001.group_30.paths.model.Link;
+import edu.ntnu.idatt2001.group_30.paths.model.Passage;
+import edu.ntnu.idatt2001.group_30.paths.model.Story;
+import edu.ntnu.idatt2001.group_30.paths.model.actions.Action;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.FileAlreadyExistsException;
+import java.util.*;
+
+/**
+ * This class is responsible for writing a story to a file.
+ *
+ * @author Trym Hamer Gudvangen, Nicolai H. Brand.
+ */
+public class StoryFileWriter {
+
+    /**
+     * Creates a new story file with the given name and writes the story to it.
+     * @param story    The story to be written to the file.
+     * @param fileName The name of the file to be created.
+     * @throws IOException if an I/O error occurs with the writer, or if the file already exists.
+     */
+    public void create(Story story, String fileName) throws IOException {
+        Objects.requireNonNull(story, "Story cannot be null");
+        Objects.requireNonNull(fileName, "File name cannot be null");
+
+        File file = FileHandler.createFile(fileName);
+        if (FileHandler.fileExists(file)) throw new FileAlreadyExistsException(
+            "You cannot overwrite a pre-existing story file"
+        );
+
+        /* propagate any errors while writing */
+        writeStory(story, file);
+    }
+
+    /**
+     * Writes the story to the given file.
+     * @param story The story to be written to the file.
+     * @param file The file to be written to.
+     * @throws IOException if an I/O error occurs with the writer.
+     */
+    private void writeStory(Story story, File file) throws IOException {
+        try (BufferedWriter writer = new BufferedWriter(new FileWriter(file, StandardCharsets.UTF_8))) {
+            writer.write(story.getTitle());
+            writer.newLine();
+            writer.newLine();
+
+            /* write all passages to the file */
+            List<Passage> passages = new ArrayList<>(story.getPassages());
+            for (Passage passage : passages) {
+                writePassage(passage, writer);
+            }
+        }
+    }
+
+    /**
+     * Writes a passage to the file.
+     * @param passage The passage to be written to the file.
+     * @param writer The writer to be used.
+     * @throws IOException if an I/O error occurs with the writer.
+     */
+    private void writePassage(Passage passage, BufferedWriter writer) throws IOException {
+        writer.write("::" + passage.getTitle());
+        writer.newLine();
+        writer.write(passage.getContent());
+        writer.newLine();
+
+        for (Link link : passage.getLinks()) {
+            writeLink(link, writer);
+        }
+        writer.newLine();
+    }
+
+    /**
+     * Writes a link to the file.
+     * @param link  The link to be written to the file.
+     * @param writer The writer to be used.
+     * @throws IOException if an I/O error occurs with the writer.
+     */
+    private void writeLink(Link link, BufferedWriter writer) throws IOException {
+        writer.write("[");
+        writer.write(link.getText());
+        writer.write("](");
+        writer.write(link.getReference());
+        writer.write(")");
+        writer.newLine();
+
+        for (Action<?> action : link.getActions()) {
+            writeAction(action, writer);
+        }
+    }
+
+    /**
+     * Writes an action to the file.
+     * @param action The action to be written to the file.
+     * @param writer The writer to be used.
+     * @throws IOException  if an I/O error occurs with the writer.
+     */
+    private void writeAction(Action<?> action, BufferedWriter writer) throws IOException {
+        writer.write("<");
+        writer.write(action.getClass().getSimpleName());
+        writer.write(">\\");
+        writer.write(action.getActionValue().toString());
+        writer.write("/");
+        writer.newLine();
+    }
+}
diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/StoryDisplay.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/StoryDisplay.java
index 9fbe46a32dfa7fe38f53f2a803c0f04ab9777282..0ef5e184defa013b60cb6b9db158008c44b60088 100644
--- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/StoryDisplay.java
+++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/StoryDisplay.java
@@ -2,7 +2,7 @@ package edu.ntnu.idatt2001.group_30.paths.view.components;
 
 import edu.ntnu.idatt2001.group_30.paths.model.Story;
 import edu.ntnu.idatt2001.group_30.paths.model.filehandling.FileHandler;
-import edu.ntnu.idatt2001.group_30.paths.model.filehandling.StoryFileHandler;
+import edu.ntnu.idatt2001.group_30.paths.model.filehandling.StoryFileReader;
 import edu.ntnu.idatt2001.group_30.paths.view.components.pane.PaneSpacing;
 import java.io.File;
 import java.io.IOException;
@@ -137,7 +137,7 @@ public class StoryDisplay extends VBox {
          */
         private void setStoryInformation() throws IOException, InstantiationException {
             this.location = String.valueOf(FileHandler.createFile(this.storyFileName).toPath());
-            this.story = new StoryFileHandler().readStoryFromFile(this.storyFileName);
+            this.story = new StoryFileReader().parse(this.storyFileName);
         }
 
         /**
diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/HelpView.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/HelpView.java
index 902171288bd77b406a5976ca30cf613a7177eb69..715e930126add6ef7e7fc5dcaa394da14d1c6c0c 100644
--- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/HelpView.java
+++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/HelpView.java
@@ -4,11 +4,18 @@ import edu.ntnu.idatt2001.group_30.paths.controller.HelpController;
 import edu.ntnu.idatt2001.group_30.paths.controller.StageManager;
 import edu.ntnu.idatt2001.group_30.paths.view.components.common.DefaultButton;
 import edu.ntnu.idatt2001.group_30.paths.view.components.common.DefaultText;
+import java.util.ArrayList;
+import java.util.List;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.ScrollPane;
 import javafx.scene.layout.VBox;
 import javafx.scene.text.Text;
 
 /**
- * Unfinished Help page.
+ * The Help page for the application.
+ * This page contains information on how to play the game.
+ * It also contains buttons for going back to the home page.
  * @author Nicolai H. Brand.
  */
 public class HelpView extends View<VBox> {
@@ -17,19 +24,52 @@ public class HelpView extends View<VBox> {
 
     public HelpView() {
         super(VBox.class);
+        VBox parent = getParentPane();
+        parent.setAlignment(Pos.TOP_CENTER);
+        parent.setSpacing(20);
+        parent.setPadding(new javafx.geometry.Insets(50));
+
+        add(DefaultText.big("Help"));
         add(helpText());
-        add(DefaultButton.medium("Home", controller.goTo(HomeView.class)));
-        add(
-            DefaultButton.medium("Go back to " + StageManager.getInstance().getPreviousViewName(), controller.goBack())
-        );
+        addAll(getButtons());
     }
 
-    public Text helpText() {
+    /**
+     * Creates a scroll pane containing the help text.
+     * @return A scroll pane containing the help text.
+     */
+    private Node helpText() {
+        ScrollPane scrollPane = new ScrollPane();
+        scrollPane.prefWidth(600);
         String howToPlay =
             """
-                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, nisl eget aliquam tincidunt, nisl nisl aliquet nisl, eget aliquam nis
+                New game:
+                
+                First you must create your own player. You can customize your outfit and enter your name. If you press the Stats button you can enter in your starting stats. If you press the Goals button you can set the goals for the play-trough. Once you are happy with your player, click continue.
+                
+                Then you need to load or create a new story by pressing the respective buttons. After a story has been selected or created, click Start game.
+                
+                During a play through, you will find the current passage to the left of the screen with its links to the bottom. In order to make a turn in the game you must press a link. A dialog pop-up will appear if you win or lose the game. If you want to restart a game or go back to home, you can press the restart and or home buttons in the top right corner.
                 """;
+        Text help = DefaultText.medium(howToPlay);
+        help.wrappingWidthProperty().bind(scrollPane.widthProperty().multiply(0.85));
+        scrollPane.setContent(help);
 
-        return DefaultText.medium(howToPlay);
+        return scrollPane;
+    }
+
+    /**
+     * Creates the buttons for the help page.
+     * The buttons are for going back to the home page and going back to the previous page.
+     * The previous page is the page the user was on before going to the help page.
+     * @return A list of buttons for the help page.
+     */
+    private List<Node> getButtons() {
+        List<Node> buttons = new ArrayList<>();
+        add(DefaultButton.medium("Home", controller.goTo(HomeView.class)));
+        add(
+            DefaultButton.medium("Go back to " + StageManager.getInstance().getPreviousViewName(), controller.goBack())
+        );
+        return buttons;
     }
 }
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/filehandling/StoryFileReaderImplTest.java b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileReaderImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6e2fbe034909ddc30c381bb37532a512ae8bf62
--- /dev/null
+++ b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileReaderImplTest.java
@@ -0,0 +1,148 @@
+package edu.ntnu.idatt2001.group_30.paths.model.filehandling;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import edu.ntnu.idatt2001.group_30.paths.exceptions.CorruptFileException;
+import edu.ntnu.idatt2001.group_30.paths.exceptions.CorruptLinkException;
+import edu.ntnu.idatt2001.group_30.paths.model.Link;
+import edu.ntnu.idatt2001.group_30.paths.model.Passage;
+import edu.ntnu.idatt2001.group_30.paths.model.Story;
+import edu.ntnu.idatt2001.group_30.paths.model.actions.GoldAction;
+import edu.ntnu.idatt2001.group_30.paths.model.actions.HealthAction;
+import edu.ntnu.idatt2001.group_30.paths.model.actions.InventoryAction;
+import edu.ntnu.idatt2001.group_30.paths.model.actions.ScoreAction;
+import java.io.*;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+public class StoryFileReaderImplTest {
+
+    @BeforeAll
+    static void setFileHandlerPath() {
+        Path defaultPath = FileSystems.getDefault().getPath("src", "test", "resources", "storytestfiles");
+        FileHandler.changeDefaultPath(defaultPath);
+    }
+
+    StoryFileReader storyFileReader = new StoryFileReader();
+
+    public File getValidFile(String fileName) {
+        return FileHandler.createFile(fileName);
+    }
+
+    static Story validStory() {
+        Story story = new Story("Lord of the rings", new Passage("Beginning", "Once upon a time..."));
+        Passage secondChapter = new Passage("The Great Barrier", "After having completed the arduous...");
+        story.addPassage(secondChapter);
+        story.getOpeningPassage().addLink(new Link(secondChapter.getTitle(), secondChapter.getTitle()));
+        story.getOpeningPassage().getLinks().forEach(link -> link.addAction(new GoldAction(5)));
+        story.getOpeningPassage().getLinks().get(0).addAction(new ScoreAction(5));
+        story.getOpeningPassage().getLinks().get(0).addAction(new HealthAction(6));
+        story.getOpeningPassage().getLinks().get(0).addAction(new InventoryAction("Sword"));
+        return story;
+    }
+
+    @Nested
+    public class A_StoryFile_properly_reads_a_story_if_it {
+
+        @Test
+        void constructs_a_Story_correctly_when_read() throws IOException, InstantiationException {
+            Story expectedStory = validStory();
+
+            Story actualStory = storyFileReader.parse("Lord of the rings");
+
+            assertEquals(expectedStory, actualStory);
+        }
+    }
+
+    @Nested
+    public class A_StoryFile_with_invalid_information_such_as {
+
+        @Test
+        void a_null_file_name_when_reading_file_will_throw_NullPointerException() {
+            Assertions.assertThrows(
+                NullPointerException.class,
+                () -> {
+                    Story story = storyFileReader.parse((String) null);
+                }
+            );
+        }
+
+        //TODO: change this actually test the link information
+        @Test
+        void corrupt_link_information_throws_CorruptLinkException_when_read() {
+            Story expectedStory = validStory();
+
+            Assertions.assertThrows(
+                CorruptLinkException.class,
+                () -> {
+                    Story actualStory = storyFileReader.parse("Corrupt Link File");
+                    assertNotEquals(expectedStory, actualStory);
+                }
+            );
+        }
+
+        @Test
+        void file_with_improper_format_throws_CorruptFileException() {
+            Story expectedStory = validStory();
+
+            Assertions.assertThrows(
+                CorruptFileException.class,
+                () -> {
+                    Story actualStory = storyFileReader.parse("Corrupt .paths Format");
+                }
+            );
+        }
+
+        @Test
+        void not_existing_throws_IllegalArgumentException() {
+            Story expectedStory = validStory();
+
+            Assertions.assertThrows(
+                IllegalArgumentException.class,
+                () -> {
+                    Story actualStory = storyFileReader.parse("File that does not exist");
+                }
+            );
+        }
+
+        @Test
+        void action_class_throws_InstantiationException() {
+            Story expectedStory = validStory();
+
+            Assertions.assertThrows(
+                InstantiationException.class,
+                () -> {
+                    Story actualStory = storyFileReader.parse("Corrupt Action Class");
+                }
+            );
+        }
+
+        @Test
+        void corrupt_action_format_throws_CorruptLinkException() {
+            Story expectedStory = validStory();
+
+            Assertions.assertThrows(
+                CorruptLinkException.class,
+                () -> {
+                    Story actualStory = storyFileReader.parse("Corrupt Action");
+                }
+            );
+        }
+
+        @Test
+        void valid_action_class_but_invalid_value_throws_IllegalArgumentException() {
+            Story expectedStory = validStory();
+
+            Assertions.assertThrows(
+                IllegalArgumentException.class,
+                () -> {
+                    Story actualStory = storyFileReader.parse("Corrupt Action Value");
+                }
+            );
+        }
+    }
+}
diff --git a/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileHandlerTest.java b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileWriterImplTest.java
similarity index 61%
rename from src/test/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileHandlerTest.java
rename to src/test/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileWriterImplTest.java
index f32e1eee340bcd7d25b1457af0e2a4a5f9d637c1..d6815495ee00802ed3a0bc64e5d0f9c02c2c5161 100644
--- a/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileHandlerTest.java
+++ b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileWriterImplTest.java
@@ -2,17 +2,12 @@ package edu.ntnu.idatt2001.group_30.paths.model.filehandling;
 
 import static org.junit.jupiter.api.Assertions.*;
 
-import edu.ntnu.idatt2001.group_30.paths.exceptions.CorruptFileException;
-import edu.ntnu.idatt2001.group_30.paths.exceptions.CorruptLinkException;
 import edu.ntnu.idatt2001.group_30.paths.model.Link;
 import edu.ntnu.idatt2001.group_30.paths.model.Passage;
 import edu.ntnu.idatt2001.group_30.paths.model.Story;
-import edu.ntnu.idatt2001.group_30.paths.model.actions.Action;
-import edu.ntnu.idatt2001.group_30.paths.model.actions.GoldAction;
-import edu.ntnu.idatt2001.group_30.paths.model.actions.HealthAction;
-import edu.ntnu.idatt2001.group_30.paths.model.actions.InventoryAction;
-import edu.ntnu.idatt2001.group_30.paths.model.actions.ScoreAction;
+import edu.ntnu.idatt2001.group_30.paths.model.actions.*;
 import java.io.*;
+import java.nio.file.FileAlreadyExistsException;
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
 import java.util.List;
@@ -23,7 +18,10 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.ValueSource;
 
-class StoryFileHandlerTest {
+public class StoryFileWriterImplTest {
+
+    final StoryFileWriter storyFileWriter = new StoryFileWriter();
+    final StoryFileReader storyFileReader = new StoryFileReader();
 
     @BeforeAll
     static void setFileHandlerPath() {
@@ -31,8 +29,6 @@ class StoryFileHandlerTest {
         FileHandler.changeDefaultPath(defaultPath);
     }
 
-    StoryFileHandler storyFileHandler = new StoryFileHandler();
-
     public File getValidFile(String fileName) {
         return FileHandler.createFile(fileName);
     }
@@ -58,16 +54,20 @@ class StoryFileHandlerTest {
             Story story = validStory();
 
             try {
-                storyFileHandler.createStoryFile(story, fileName);
+                storyFileWriter.create(story, fileName);
             } catch (Exception e) {
-                if (!e.getMessage().equals("You cannot overwrite a pre-existing story file")) {
+                if (
+                    !(
+                        e.getMessage().equals("You cannot overwrite a pre-existing story file") &&
+                        e instanceof FileAlreadyExistsException
+                    )
+                ) {
                     System.out.println(e.getMessage());
                     fail("An exception was thrown when it shouldn't have.");
                 }
             }
 
             File expectedFileCreated = getValidFile(fileName);
-
             Assertions.assertTrue(expectedFileCreated.isFile());
             expectedFileCreated.delete();
         }
@@ -78,13 +78,12 @@ class StoryFileHandlerTest {
             Story story = validStory();
 
             try {
-                storyFileHandler.createStoryFile(story, fileName);
+                storyFileWriter.create(story, fileName);
             } catch (Exception e) {
                 fail("An exception was thrown when it shouldn't have. " + e.getMessage());
             }
 
             File expectedFileCreated = getValidFile(fileName);
-
             Assertions.assertTrue(expectedFileCreated.canRead());
             expectedFileCreated.delete();
         }
@@ -96,7 +95,7 @@ class StoryFileHandlerTest {
             boolean fileDoesNotExistAtStart = !getValidFile(fileName).exists();
 
             try {
-                storyFileHandler.createStoryFile(story, fileName);
+                storyFileWriter.create(story, fileName);
             } catch (Exception e) {
                 fail("An exception was thrown when it shouldn't have.");
             }
@@ -118,8 +117,8 @@ class StoryFileHandlerTest {
             File preexistingFile = getValidFile(fileName);
             if (getValidFile(fileName).isFile()) {
                 Assertions.assertThrows(
-                    IllegalArgumentException.class,
-                    () -> storyFileHandler.createStoryFile(story, fileName)
+                    FileAlreadyExistsException.class,
+                    () -> storyFileWriter.create(story, fileName)
                 );
             } else fail("The file check for doesn't exist, so this test is invalid");
         }
@@ -134,8 +133,8 @@ class StoryFileHandlerTest {
             Story story = validStory();
             String expectedTitle = story.getTitle();
 
-            storyFileHandler.createStoryFile(story, fileName);
-            Story storyReadFromFile = storyFileHandler.readStoryFromFile(fileName);
+            storyFileWriter.create(story, fileName);
+            Story storyReadFromFile = storyFileReader.parse(fileName);
             String actualTitle = storyReadFromFile.getTitle();
 
             Assertions.assertEquals(expectedTitle, actualTitle);
@@ -150,9 +149,11 @@ class StoryFileHandlerTest {
             Story story = validStory();
             Passage expectedOpeningPassage = story.getOpeningPassage();
 
-            storyFileHandler.createStoryFile(story, fileName);
-            Story storyReadFromFile = storyFileHandler.readStoryFromFile(fileName);
+            storyFileWriter.create(story, fileName);
+            Story storyReadFromFile = storyFileReader.parse(fileName);
             Passage actualOpeningPassage = storyReadFromFile.getOpeningPassage();
+            System.out.println(actualOpeningPassage.getTitle() + actualOpeningPassage.getContent());
+            System.out.println(expectedOpeningPassage.getTitle() + expectedOpeningPassage.getContent());
 
             Assertions.assertEquals(expectedOpeningPassage, actualOpeningPassage);
 
@@ -166,8 +167,8 @@ class StoryFileHandlerTest {
             Story story = validStory();
             List<Link> expectedOpeningPassageLinks = story.getOpeningPassage().getLinks();
 
-            storyFileHandler.createStoryFile(story, fileName);
-            Story storyReadFromFile = storyFileHandler.readStoryFromFile(fileName);
+            storyFileWriter.create(story, fileName);
+            Story storyReadFromFile = storyFileReader.parse(fileName);
             List<Link> actualOpeningPassageLinks = storyReadFromFile.getOpeningPassage().getLinks();
 
             Assertions.assertEquals(expectedOpeningPassageLinks, actualOpeningPassageLinks);
@@ -182,8 +183,8 @@ class StoryFileHandlerTest {
             Story story = validStory();
             List<Action<?>> expectedOpeningPassageActions = story.getOpeningPassage().getLinks().get(0).getActions();
 
-            storyFileHandler.createStoryFile(story, fileName);
-            Story storyReadFromFile = storyFileHandler.readStoryFromFile(fileName);
+            storyFileWriter.create(story, fileName);
+            Story storyReadFromFile = storyFileReader.parse(fileName);
             List<Action<?>> actualOpeningPassageActions = storyReadFromFile
                 .getOpeningPassage()
                 .getLinks()
@@ -197,19 +198,6 @@ class StoryFileHandlerTest {
         }
     }
 
-    @Nested
-    public class A_StoryFile_properly_reads_a_story_if_it {
-
-        @Test
-        void constructs_a_Story_correctly_when_read() throws IOException, InstantiationException {
-            Story expectedStory = validStory();
-
-            Story actualStory = storyFileHandler.readStoryFromFile("The Hobbit");
-
-            assertEquals(expectedStory, actualStory);
-        }
-    }
-
     @Nested
     public class A_StoryFile_with_invalid_information_such_as {
 
@@ -220,7 +208,7 @@ class StoryFileHandlerTest {
             Assertions.assertThrows(
                 NullPointerException.class,
                 () -> {
-                    storyFileHandler.createStoryFile(story, "Null story test");
+                    storyFileWriter.create(story, "Null story test");
                 }
             );
         }
@@ -232,91 +220,7 @@ class StoryFileHandlerTest {
             Assertions.assertThrows(
                 NullPointerException.class,
                 () -> {
-                    storyFileHandler.createStoryFile(story, (String) null);
-                }
-            );
-        }
-
-        @Test
-        void a_null_file_name_when_reading_file_will_throw_NullPointerException() {
-            Assertions.assertThrows(
-                NullPointerException.class,
-                () -> {
-                    Story story = storyFileHandler.readStoryFromFile((String) null);
-                }
-            );
-        }
-
-        //TODO: change this actually test the link information
-        @Test
-        void corrupt_link_information_throws_CorruptLinkException_when_read() {
-            Story expectedStory = validStory();
-
-            Assertions.assertThrows(
-                CorruptLinkException.class,
-                () -> {
-                    Story actualStory = storyFileHandler.readStoryFromFile("Corrupt Link File");
-                    assertNotEquals(expectedStory, actualStory);
-                }
-            );
-        }
-
-        @Test
-        void file_with_improper_format_throws_CorruptFileException() {
-            Story expectedStory = validStory();
-
-            Assertions.assertThrows(
-                CorruptFileException.class,
-                () -> {
-                    Story actualStory = storyFileHandler.readStoryFromFile("Corrupt .paths Format");
-                }
-            );
-        }
-
-        @Test
-        void not_existing_throws_IllegalArgumentException() {
-            Story expectedStory = validStory();
-
-            Assertions.assertThrows(
-                IllegalArgumentException.class,
-                () -> {
-                    Story actualStory = storyFileHandler.readStoryFromFile("File that does not exist");
-                }
-            );
-        }
-
-        @Test
-        void action_class_throws_InstantiationException() {
-            Story expectedStory = validStory();
-
-            Assertions.assertThrows(
-                InstantiationException.class,
-                () -> {
-                    Story actualStory = storyFileHandler.readStoryFromFile("Corrupt Action Class");
-                }
-            );
-        }
-
-        @Test
-        void corrupt_action_format_throws_CorruptLinkException() {
-            Story expectedStory = validStory();
-
-            Assertions.assertThrows(
-                CorruptLinkException.class,
-                () -> {
-                    Story actualStory = storyFileHandler.readStoryFromFile("Corrupt Action");
-                }
-            );
-        }
-
-        @Test
-        void valid_action_class_but_invalid_value_throws_IllegalArgumentException() {
-            Story expectedStory = validStory();
-
-            Assertions.assertThrows(
-                IllegalArgumentException.class,
-                () -> {
-                    Story actualStory = storyFileHandler.readStoryFromFile("Corrupt Action Value");
+                    storyFileWriter.create(story, 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());
+    }
+}
diff --git a/src/test/resources/storytestfiles/The Hobbit.paths b/src/test/resources/storytestfiles/Lord of the rings.paths
similarity index 92%
rename from src/test/resources/storytestfiles/The Hobbit.paths
rename to src/test/resources/storytestfiles/Lord of the rings.paths
index 51531969e0ba640f31514f0485bf262f1d2b2502..7bf88a1183e1b3e1a51f556df176f2e523280691 100644
--- a/src/test/resources/storytestfiles/The Hobbit.paths	
+++ b/src/test/resources/storytestfiles/Lord of the rings.paths	
@@ -1,4 +1,4 @@
-The Hobbit
+Lord of the rings
 
 ::Beginning
 Once upon a time...