diff --git a/code/datums/tutorial/_tutorial.dm b/code/datums/tutorial/_tutorial.dm
index 5423453bbdb9..7dd7ac85c04d 100644
--- a/code/datums/tutorial/_tutorial.dm
+++ b/code/datums/tutorial/_tutorial.dm
@@ -52,6 +52,7 @@ GLOBAL_LIST_EMPTY_TYPED(ongoing_tutorials, /datum/tutorial)
reservation = SSmapping.RequestBlockReservation(initial(tutorial_template.width), initial(tutorial_template.height))
if(!reservation)
+ abort_tutorial()
return FALSE
var/turf/bottom_left_corner_reservation = locate(reservation.bottom_left_coords[1], reservation.bottom_left_coords[2], reservation.bottom_left_coords[3])
diff --git a/code/datums/tutorial/_tutorial_menu.dm b/code/datums/tutorial/_tutorial_menu.dm
index 42eb3f6aabfa..951b9654ef0e 100644
--- a/code/datums/tutorial/_tutorial_menu.dm
+++ b/code/datums/tutorial/_tutorial_menu.dm
@@ -79,5 +79,6 @@
return
path = new path
- path.start_tutorial(usr)
- return TRUE
+ if(path.start_tutorial(usr))
+ ui.close()
+ return TRUE
diff --git a/code/datums/tutorial/xenomorph/_xenomorph.dm b/code/datums/tutorial/xenomorph/_xenomorph.dm
index bd85cdb35f44..caa33d8eed43 100644
--- a/code/datums/tutorial/xenomorph/_xenomorph.dm
+++ b/code/datums/tutorial/xenomorph/_xenomorph.dm
@@ -22,6 +22,10 @@
// We don't want people talking to other xenomorphs across tutorials
new_character.can_hivemind_speak = FALSE
+ // No age prefix or HUD element
+ new_character.age = XENO_NO_AGE
+ new_character.show_age_prefix = FALSE
+ new_character.generate_name()
tutorial_mob = new_character
xeno = new_character
diff --git a/code/datums/tutorial/xenomorph/xenomorph_basic.dm b/code/datums/tutorial/xenomorph/xenomorph_basic.dm
index 0415977835aa..e91c85e1e1e4 100644
--- a/code/datums/tutorial/xenomorph/xenomorph_basic.dm
+++ b/code/datums/tutorial/xenomorph/xenomorph_basic.dm
@@ -4,6 +4,7 @@
name = "Xenomorph - Basic"
desc = "A tutorial to get you acquainted with the very basics of how to play a xenomorph."
icon_state = "xeno"
+ tutorial_id = "xeno_basic_1"
tutorial_template = /datum/map_template/tutorial/s12x12
starting_xenomorph_type = /mob/living/carbon/xenomorph/drone
@@ -105,7 +106,7 @@
UnregisterSignal(human_dummy, COMSIG_MOB_DEATH)
message_to_player("Well done. Killing humans is one of many ways to help the hive.")
- message_to_player("Another way is to capture them. This will grow a new xenomorph inside them which will eventually burst into a new playable xenomorph!")
+ message_to_player("Another way is to capture them. This will grow a new xenomorph inside them which will eventually burst into a new playable xenomorph!")
addtimer(CALLBACK(human_dummy, TYPE_PROC_REF(/mob/living, rejuvenate)), 8 SECONDS)
addtimer(CALLBACK(src, PROC_REF(proceed_to_tackle_phase)), 10 SECONDS)
@@ -227,3 +228,5 @@
/datum/tutorial/xenomorph/basic/init_map()
loc_from_corner(9,0).ChangeTurf(/turf/closed/wall/resin/tutorial)
+
+#undef WAITING_HEALTH_THRESHOLD
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
index 90040ec9acf9..3967ee70e391 100644
--- a/code/modules/unit_tests/_unit_tests.dm
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -74,19 +74,23 @@
/// A trait source when adding traits through unit tests
#define TRAIT_SOURCE_UNIT_TESTS "unit_tests"
+// Unit tests
#include "autowiki.dm"
+#include "check_runtimes.dm"
#include "create_and_destroy.dm"
-#include "focus_only_tests.dm"
+#include "emote_panels.dm"
#include "missing_icons.dm"
#include "resist.dm"
+#include "spawn_humans.dm"
#include "spritesheets.dm"
#include "subsystem_init.dm"
#include "tgui_create_message.dm"
#include "timer_sanity.dm"
+#include "tutorials.dm"
+
+// Unit tests backend
+#include "focus_only_tests.dm"
#include "unit_test.dm"
-#include "spawn_humans.dm"
-#include "check_runtimes.dm"
-#include "emote_panels.dm"
#undef TEST_ASSERT
#undef TEST_ASSERT_EQUAL
diff --git a/code/modules/unit_tests/tutorials.dm b/code/modules/unit_tests/tutorials.dm
new file mode 100644
index 000000000000..d835a4f272cb
--- /dev/null
+++ b/code/modules/unit_tests/tutorials.dm
@@ -0,0 +1,19 @@
+/datum/unit_test/tutorials
+
+/datum/unit_test/tutorials/Run()
+ var/datum/tutorial/base_path = /datum/tutorial
+ for(var/datum/tutorial/tutorial_path as anything in subtypesof(base_path))
+ if(initial(tutorial_path.parent_path) == tutorial_path)
+ continue
+
+ // Make sure these variables are overridden on any subtypes.
+ TEST_ASSERT_NOTEQUAL(initial(tutorial_path.name), initial(base_path.name),
+ "[tutorial_path] does not have a name set.")
+ TEST_ASSERT_NOTEQUAL(initial(tutorial_path.tutorial_id), initial(base_path.tutorial_id),
+ "[tutorial_path] does not have a tutorial_id set.")
+ TEST_ASSERT_NOTEQUAL(initial(tutorial_path.desc), initial(base_path.desc),
+ "[tutorial_path] does not have a desc set.")
+ TEST_ASSERT_NOTEQUAL(initial(tutorial_path.icon_state), initial(base_path.icon_state),
+ "[tutorial_path] does not have an icon_state set.")
+
+// TODO: Add a test verifying that a basic tutorial can be started and completed. (Requires unit test client handling)