diff --git a/Content.IntegrationTests/Tests/Kitchen/HandheldGrinderInteractionTest.cs b/Content.IntegrationTests/Tests/Kitchen/HandheldGrinderInteractionTest.cs
new file mode 100644
index 0000000000..1b693d2802
--- /dev/null
+++ b/Content.IntegrationTests/Tests/Kitchen/HandheldGrinderInteractionTest.cs
@@ -0,0 +1,108 @@
+using System.Linq;
+using Content.IntegrationTests.Tests.Interaction;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Kitchen;
+using Content.Shared.Kitchen.Components;
+using Content.Shared.Kitchen.EntitySystems;
+using Content.Shared.Stacks;
+using Robust.Shared.Prototypes;
+
+namespace Content.IntegrationTests.Tests.Kitchen;
+
+public sealed partial class HandheldGrinderInteractionTest : InteractionTest
+{
+ private static readonly EntProtoId Mortar = "MortarAndPestle";
+ private static readonly EntProtoId Juicer = "HandheldJuicer";
+
+ private static readonly EntProtoId SteelSheet = "SheetSteel1";
+ private const string Banana = "TestFoodBanana";
+
+ [TestPrototypes]
+ private const string Prototypes = @$"
+# A modified banana that can only be juiced.
+- type: entity
+ parent: FoodBanana
+ id: {Banana}
+ components:
+ - type: Extractable
+ grindableSolutionName: null
+";
+
+ ///
+ /// Spawns a mortar and grinds steel in it, then grinds an ungrindable banana.
+ /// Does the same with a juicer, but first a banana and then steel.
+ ///
+ [Test]
+ public async Task GrindAndJuiceInHandheldGrindersTest()
+ {
+ var grinderSys = SEntMan.System();
+ var solutionSys = SEntMan.System();
+ var stackSys = SEntMan.System();
+
+ // Spawn an empty mortar
+ await SpawnTarget(Mortar);
+ var grinderComp = Comp();
+
+ // Spawn steel sheets and get what solution they should grind into.
+ var sheetsEnt = await PlaceInHands(SteelSheet, 2);
+ var expectedGrinderSol = grinderSys.GetGrinderSolution(ToServer(sheetsEnt), GrinderProgram.Grind);
+ Assert.That(expectedGrinderSol, Is.Not.Null); // We expect a solution to exist, would suck if it didn't.
+
+ await Interact();
+
+ Assert.That(grinderComp.GrinderSolution, Is.Not.Null); // The grinder needs to have its valid solution resolved after interaction.
+ Assert.That(expectedGrinderSol.Contents.SequenceEqual(grinderComp.GrinderSolution.Value.Comp.Solution.Contents)); // Check if the solution is the one we expected.
+ Assert.That(stackSys.GetCount(ToServer(sheetsEnt)), Is.EqualTo(1)); // We had 2 steel, now we have one.
+
+ await Interact();
+
+ Assert.That(SEntMan.EntityExists(ToServer(sheetsEnt)), Is.False); // We use the other sheet, so we used all of our steel.
+
+
+ // Spawn a new grinder
+ await SpawnTarget(Mortar);
+ grinderComp = Comp();
+
+ // Manually resolve the solution because the system only resolves it after a VALID interaction, and here we test an invalid one.
+ solutionSys.ResolveSolution(STarget.Value, grinderComp.SolutionName, ref grinderComp.GrinderSolution);
+ Assert.That(grinderComp.GrinderSolution, Is.Not.Null);
+
+ var bananaEnt = await PlaceInHands(Banana);
+
+ await Interact();
+
+ Assert.That(grinderComp.GrinderSolution.Value.Comp.Solution.Volume.Float(), Is.Not.GreaterThan(0f)); // The banana shouldn't have been ground, since it can only be juiced.
+ Assert.That(SEntMan.EntityExists(ToServer(bananaEnt))); // Banana should exist since the interaction failed.
+
+
+ // Now we test the juicer, so we spawn one.
+ await SpawnTarget(Juicer);
+ grinderComp = Comp();
+ bananaEnt = await PlaceInHands(Banana);
+ var expectedJuicerSol = grinderSys.GetGrinderSolution(ToServer(bananaEnt), GrinderProgram.Juice);
+ Assert.That(expectedJuicerSol, Is.Not.Null); // We expect a solution to exist, would suck if it didn't.
+
+ await Interact();
+
+ Assert.That(grinderComp.GrinderSolution, Is.Not.Null); // Juicer has a valid solution.
+ Assert.That(expectedJuicerSol.Contents.SequenceEqual(grinderComp.GrinderSolution.Value.Comp.Solution.Contents)); // The banana has been juiced.
+ Assert.That(SEntMan.EntityExists(ToServer(bananaEnt)), Is.False); // Banana was juiced and therefore should no longer exist.
+
+
+ // Spawn a new juicer
+ await SpawnTarget(Juicer);
+ grinderComp = Comp();
+
+ // Manually resolve the solution because the system only resolves it after a VALID interaction, and here we test an invalid one.
+ solutionSys.ResolveSolution(STarget.Value, grinderComp.SolutionName, ref grinderComp.GrinderSolution);
+ Assert.That(grinderComp.GrinderSolution, Is.Not.Null);
+
+ sheetsEnt = await PlaceInHands(SteelSheet, 2);
+
+ await Interact();
+
+ Assert.That(grinderComp.GrinderSolution.Value.Comp.Solution.Volume.Float() , Is.Not.GreaterThan(0f)); // The steel cannot be juiced.
+ Assert.That(SEntMan.EntityExists(ToServer(sheetsEnt))); // Steel was not used so it should exist.
+ Assert.That(stackSys.GetCount(ToServer(sheetsEnt)), Is.EqualTo(2)); // Steel was not used, we should have two.
+ }
+}
diff --git a/Content.Shared/Kitchen/Components/HandheldGrinderComponent.cs b/Content.Shared/Kitchen/Components/HandheldGrinderComponent.cs
index c32d11ddb8..7bc232bff1 100644
--- a/Content.Shared/Kitchen/Components/HandheldGrinderComponent.cs
+++ b/Content.Shared/Kitchen/Components/HandheldGrinderComponent.cs
@@ -41,7 +41,7 @@ public sealed partial class HandheldGrinderComponent : Component
/// The solution into which the output reagents will go.
///
[DataField, AutoNetworkedField]
- public string SolutionName = "grinderOutput";
+ public string SolutionName = "solution";
///
/// Cached solution from the grinder.
diff --git a/Content.Shared/Kitchen/EntitySystems/HandheldGrinderSystem.cs b/Content.Shared/Kitchen/EntitySystems/HandheldGrinderSystem.cs
index 405083d1ca..c3f853deda 100644
--- a/Content.Shared/Kitchen/EntitySystems/HandheldGrinderSystem.cs
+++ b/Content.Shared/Kitchen/EntitySystems/HandheldGrinderSystem.cs
@@ -13,7 +13,7 @@ using Robust.Shared.Serialization;
namespace Content.Shared.Kitchen.EntitySystems;
-internal sealed partial class HandheldGrinderSystem : EntitySystem
+public sealed partial class HandheldGrinderSystem : EntitySystem
{
[Dependency] private SharedReagentGrinderSystem _reagentGrinder = default!;
[Dependency] private SharedSolutionContainerSystem _solution = default!;