Add reagent dispenser BUI test (#15443)
This commit is contained in:
35
Content.IntegrationTests/Tests/Chemistry/DispenserTest.cs
Normal file
35
Content.IntegrationTests/Tests/Chemistry/DispenserTest.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Content.IntegrationTests.Tests.Interaction;
|
||||||
|
using Content.Shared.Chemistry;
|
||||||
|
using Content.Shared.Containers.ItemSlots;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Content.IntegrationTests.Tests.Chemistry;
|
||||||
|
|
||||||
|
public sealed class DispenserTest : InteractionTest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Basic test that checks that a beaker can be inserted and ejected from a dispenser.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public async Task InsertEjectBuiTest()
|
||||||
|
{
|
||||||
|
await SpawnTarget("chem_dispenser");
|
||||||
|
ToggleNeedPower();
|
||||||
|
|
||||||
|
// Insert beaker
|
||||||
|
await Interact("Beaker");
|
||||||
|
Assert.IsNull(Hands.ActiveHandEntity);
|
||||||
|
|
||||||
|
// Open BUI
|
||||||
|
await Interact("");
|
||||||
|
|
||||||
|
// Eject beaker via BUI.
|
||||||
|
var ev = new ItemSlotButtonPressedEvent(SharedChemMaster.InputSlotName);
|
||||||
|
await SendBui(ReagentDispenserUiKey.Key, ev);
|
||||||
|
|
||||||
|
// Beaker is back in the player's hands
|
||||||
|
Assert.IsNotNull(Hands.ActiveHandEntity);
|
||||||
|
AssertPrototype("Beaker", Hands.ActiveHandEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,6 +62,10 @@ public abstract partial class InteractionTest
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Converted = true;
|
Converted = true;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(Prototype))
|
||||||
|
return;
|
||||||
|
|
||||||
if (protoMan.HasIndex<StackPrototype>(Prototype))
|
if (protoMan.HasIndex<StackPrototype>(Prototype))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -121,6 +125,6 @@ public abstract partial class InteractionTest
|
|||||||
var meta = SEntMan.GetComponent<MetaDataComponent>(uid);
|
var meta = SEntMan.GetComponent<MetaDataComponent>(uid);
|
||||||
Assert.NotNull(meta.EntityPrototype);
|
Assert.NotNull(meta.EntityPrototype);
|
||||||
|
|
||||||
return new (meta.EntityPrototype.ID, 1) { Converted = true };
|
return new (meta.EntityPrototype!.ID, 1) { Converted = true };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Client.Construction;
|
using Content.Client.Construction;
|
||||||
using Content.Server.Construction.Components;
|
using Content.Server.Construction.Components;
|
||||||
|
using Content.Server.Power.Components;
|
||||||
using Content.Server.Tools.Components;
|
using Content.Server.Tools.Components;
|
||||||
using Content.Shared.Construction.Prototypes;
|
using Content.Shared.Construction.Prototypes;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Log;
|
using Robust.Shared.Log;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
@@ -139,7 +142,7 @@ public abstract partial class InteractionTest
|
|||||||
|
|
||||||
await DeleteHeldEntity();
|
await DeleteHeldEntity();
|
||||||
|
|
||||||
if (entity == null)
|
if (entity == null || string.IsNullOrWhiteSpace(entity.Prototype))
|
||||||
{
|
{
|
||||||
await RunTicks(1);
|
await RunTicks(1);
|
||||||
Assert.That(Hands.ActiveHandEntity == null);
|
Assert.That(Hands.ActiveHandEntity == null);
|
||||||
@@ -238,13 +241,19 @@ public abstract partial class InteractionTest
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Place an entity prototype into the players hand and interact with the given entity (or target position)
|
/// Place an entity prototype into the players hand and interact with the given entity (or target position)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected async Task Interact(string? id, int quantity = 1, bool shouldSucceed = true, bool awaitDoAfters = true)
|
/// <remarks>
|
||||||
=> await Interact(id == null ? null : (id, quantity), shouldSucceed, awaitDoAfters);
|
/// Empty strings imply empty hands.
|
||||||
|
/// </remarks>
|
||||||
|
protected async Task Interact(string id, int quantity = 1, bool shouldSucceed = true, bool awaitDoAfters = true)
|
||||||
|
=> await Interact((id, quantity), shouldSucceed, awaitDoAfters);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Place an entity prototype into the players hand and interact with the given entity (or target position)
|
/// Place an entity prototype into the players hand and interact with the given entity (or target position)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected async Task Interact(EntitySpecifier? entity, bool shouldSucceed = true, bool awaitDoAfters = true)
|
/// <remarks>
|
||||||
|
/// Empty strings imply empty hands.
|
||||||
|
/// </remarks>
|
||||||
|
protected async Task Interact(EntitySpecifier entity, bool shouldSucceed = true, bool awaitDoAfters = true)
|
||||||
{
|
{
|
||||||
// For every interaction, we will also examine the entity, just in case this breaks something, somehow.
|
// For every interaction, we will also examine the entity, just in case this breaks something, somehow.
|
||||||
// (e.g., servers attempt to assemble construction examine hints).
|
// (e.g., servers attempt to assemble construction examine hints).
|
||||||
@@ -376,7 +385,10 @@ public abstract partial class InteractionTest
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Variant of <see cref="InteractUsing"/> that performs several interactions using different entities.
|
/// Variant of <see cref="InteractUsing"/> that performs several interactions using different entities.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected async Task Interact(params EntitySpecifier?[] specifiers)
|
/// <remarks>
|
||||||
|
/// Empty strings imply empty hands.
|
||||||
|
/// </remarks>
|
||||||
|
protected async Task Interact(params EntitySpecifier[] specifiers)
|
||||||
{
|
{
|
||||||
foreach (var spec in specifiers)
|
foreach (var spec in specifiers)
|
||||||
{
|
{
|
||||||
@@ -386,32 +398,60 @@ public abstract partial class InteractionTest
|
|||||||
|
|
||||||
#region Asserts
|
#region Asserts
|
||||||
|
|
||||||
protected void AssertPrototype(string? prototype)
|
protected void AssertPrototype(string? prototype, EntityUid? target = null)
|
||||||
{
|
{
|
||||||
var meta = Comp<MetaDataComponent>();
|
target ??= Target;
|
||||||
|
if (target == null)
|
||||||
|
{
|
||||||
|
Assert.Fail("No target specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var meta = SEntMan.GetComponent<MetaDataComponent>(target.Value);
|
||||||
Assert.That(meta.EntityPrototype?.ID, Is.EqualTo(prototype));
|
Assert.That(meta.EntityPrototype?.ID, Is.EqualTo(prototype));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void AssertAnchored(bool anchored = true)
|
protected void AssertAnchored(bool anchored = true, EntityUid? target = null)
|
||||||
{
|
{
|
||||||
var sXform = SEntMan.GetComponent<TransformComponent>(Target!.Value);
|
target ??= Target;
|
||||||
var cXform = CEntMan.GetComponent<TransformComponent>(Target.Value);
|
if (target == null)
|
||||||
|
{
|
||||||
|
Assert.Fail("No target specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sXform = SEntMan.GetComponent<TransformComponent>(target.Value);
|
||||||
|
var cXform = CEntMan.GetComponent<TransformComponent>(target.Value);
|
||||||
Assert.That(sXform.Anchored, Is.EqualTo(anchored));
|
Assert.That(sXform.Anchored, Is.EqualTo(anchored));
|
||||||
Assert.That(cXform.Anchored, Is.EqualTo(anchored));
|
Assert.That(cXform.Anchored, Is.EqualTo(anchored));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void AssertDeleted(bool deleted = true)
|
protected void AssertDeleted(bool deleted = true, EntityUid? target = null)
|
||||||
{
|
{
|
||||||
Assert.That(SEntMan.Deleted(Target), Is.EqualTo(deleted));
|
target ??= Target;
|
||||||
Assert.That(CEntMan.Deleted(Target), Is.EqualTo(deleted));
|
if (target == null)
|
||||||
|
{
|
||||||
|
Assert.Fail("No target specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.That(SEntMan.Deleted(target), Is.EqualTo(deleted));
|
||||||
|
Assert.That(CEntMan.Deleted(target), Is.EqualTo(deleted));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Assert whether or not the target has the given component.
|
/// Assert whether or not the target has the given component.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected void AssertComp<T>(bool hasComp = true)
|
protected void AssertComp<T>(bool hasComp = true, EntityUid? target = null)
|
||||||
{
|
{
|
||||||
Assert.That(SEntMan.HasComponent<T>(Target), Is.EqualTo(hasComp));
|
target ??= Target;
|
||||||
|
if (target == null)
|
||||||
|
{
|
||||||
|
Assert.Fail("No target specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.That(SEntMan.HasComponent<T>(target), Is.EqualTo(hasComp));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -553,7 +593,6 @@ public abstract partial class InteractionTest
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of currently active DoAfters on the player.
|
/// List of currently active DoAfters on the player.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -563,7 +602,14 @@ public abstract partial class InteractionTest
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convenience method to get components on the target. Returns SERVER-SIDE components.
|
/// Convenience method to get components on the target. Returns SERVER-SIDE components.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected T Comp<T>() => SEntMan.GetComponent<T>(Target!.Value);
|
protected T Comp<T>(EntityUid? target = null)
|
||||||
|
{
|
||||||
|
target ??= Target;
|
||||||
|
if (target == null)
|
||||||
|
Assert.Fail("No target specified");
|
||||||
|
|
||||||
|
return SEntMan.GetComponent<T>(target!.Value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set the tile at the target position to some prototype.
|
/// Set the tile at the target position to some prototype.
|
||||||
@@ -611,4 +657,77 @@ public abstract partial class InteractionTest
|
|||||||
|
|
||||||
protected async Task RunSeconds(float seconds)
|
protected async Task RunSeconds(float seconds)
|
||||||
=> await RunTicks((int) Math.Ceiling(seconds / TickPeriod));
|
=> await RunTicks((int) Math.Ceiling(seconds / TickPeriod));
|
||||||
|
|
||||||
|
#region BUI
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a bui message using the given bui key.
|
||||||
|
/// </summary>
|
||||||
|
protected async Task SendBui(Enum key, BoundUserInterfaceMessage msg, EntityUid? target = null)
|
||||||
|
{
|
||||||
|
if (!TryGetBui(key, out var bui))
|
||||||
|
return;
|
||||||
|
|
||||||
|
await Client.WaitPost(() => bui.SendMessage(msg));
|
||||||
|
|
||||||
|
// allow for client -> server and server -> client messages to be sent.
|
||||||
|
await RunTicks(15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a bui message using the given bui key.
|
||||||
|
/// </summary>
|
||||||
|
protected async Task CloseBui(Enum key, EntityUid? target = null)
|
||||||
|
{
|
||||||
|
if (!TryGetBui(key, out var bui))
|
||||||
|
return;
|
||||||
|
|
||||||
|
await Client.WaitPost(() => bui.Close());
|
||||||
|
|
||||||
|
// allow for client -> server and server -> client messages to be sent.
|
||||||
|
await RunTicks(15);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool TryGetBui(Enum key, [NotNullWhen(true)] out BoundUserInterface? bui, EntityUid? target = null, bool shouldSucceed = true)
|
||||||
|
{
|
||||||
|
bui = null;
|
||||||
|
target ??= Target;
|
||||||
|
if (target == null)
|
||||||
|
{
|
||||||
|
Assert.Fail("No target specified");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CEntMan.TryGetComponent(target, out ClientUserInterfaceComponent? ui))
|
||||||
|
{
|
||||||
|
if (shouldSucceed)
|
||||||
|
Assert.Fail($"Entity {SEntMan.ToPrettyString(target.Value)} does not have a bui component");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var first = ui.Interfaces.First();
|
||||||
|
|
||||||
|
|
||||||
|
bui = ui.Interfaces.FirstOrDefault(x => x.UiKey.Equals(key));
|
||||||
|
if (bui == null)
|
||||||
|
{
|
||||||
|
if (shouldSucceed)
|
||||||
|
Assert.Fail($"Entity {SEntMan.ToPrettyString(target.Value)} does not have an open bui with key {key.GetType()}.{key}.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.That(shouldSucceed, Is.True);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Power
|
||||||
|
|
||||||
|
protected void ToggleNeedPower(EntityUid? target = null)
|
||||||
|
{
|
||||||
|
var comp = Comp<ApcPowerReceiverComponent>(target);
|
||||||
|
comp.NeedsPower = !comp.NeedsPower;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using Content.Shared.Hands.Components;
|
|||||||
using Content.Shared.Hands.EntitySystems;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
@@ -97,11 +98,12 @@ public abstract partial class InteractionTest
|
|||||||
// player components
|
// player components
|
||||||
protected HandsComponent Hands = default!;
|
protected HandsComponent Hands = default!;
|
||||||
protected DoAfterComponent DoAfters = default!;
|
protected DoAfterComponent DoAfters = default!;
|
||||||
|
protected UserInterfaceSystem CUISystem = default!;
|
||||||
|
|
||||||
public float TickPeriod => (float)Timing.TickPeriod.TotalSeconds;
|
public float TickPeriod => (float)Timing.TickPeriod.TotalSeconds;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public async Task Setup()
|
public virtual async Task Setup()
|
||||||
{
|
{
|
||||||
PairTracker = await PoolManager.GetServerClient(new PoolSettings());
|
PairTracker = await PoolManager.GetServerClient(new PoolSettings());
|
||||||
|
|
||||||
@@ -126,6 +128,7 @@ public abstract partial class InteractionTest
|
|||||||
CTestSystem = CEntMan.System<InteractionTestSystem>();
|
CTestSystem = CEntMan.System<InteractionTestSystem>();
|
||||||
CConSys = CEntMan.System<ConstructionSystem>();
|
CConSys = CEntMan.System<ConstructionSystem>();
|
||||||
ExamineSys = CEntMan.System<ExamineSystem>();
|
ExamineSys = CEntMan.System<ExamineSystem>();
|
||||||
|
CUISystem = CEntMan.System<UserInterfaceSystem>();
|
||||||
|
|
||||||
// Setup map.
|
// Setup map.
|
||||||
MapData = await PoolManager.CreateTestMap(PairTracker);
|
MapData = await PoolManager.CreateTestMap(PairTracker);
|
||||||
@@ -189,7 +192,7 @@ public abstract partial class InteractionTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TearDown]
|
[TearDown]
|
||||||
public async Task Cleanup()
|
public virtual async Task Cleanup()
|
||||||
{
|
{
|
||||||
await Server.WaitPost(() => MapMan.DeleteMap(MapId));
|
await Server.WaitPost(() => MapMan.DeleteMap(MapId));
|
||||||
await PairTracker.CleanReturnAsync();
|
await PairTracker.CleanReturnAsync();
|
||||||
|
|||||||
Reference in New Issue
Block a user