1
0
mirror of https://github.com/ppy/osu.git synced 2026-06-07 14:44:25 +08:00

Migrate sheared overlay tests to ScreenTestScene (#36736)

Part of the screen footer refactor.

Once footer content is being managed by `OsuScreen`, the current tests
which simply create the tested overlay and `ScreenFooter` in a container
will no longer work.

This PR refactors them to use `ScreenTestScene` with the setup being
creating a dedicated testing `OsuScreen` which does the bare minimum to
create the tested overlay and necessary components (eg.
`FooterButtonFreeModsV2` for `TestSceneFreeModsOverlay`).

Most of the changes here can be described as
`%s/<...>Overlay/screen.Overlay/g`, with some minor touchups as
necessary, given that we're now testing a more complete flow which
checks more things that were previously not handled by the tests.

## [Move footer to front in
ScreenTestScene](https://github.com/ppy/osu/commit/f8740e0403b3c0badd60d394c737f2aa912a9ed6)

Self-explanatory. Without it the footer would show below the actual
overlay, breaking tests depending on manual input. For the sake of tests
not breaking in CI, both #36718 and this have this included - would
prefer the former to be merged first since it was already reviewed
there.

## `TestSceneModSelectOverlay`

There were a few tests (`TestColumnHidingOnIsValidChange`,
`TestColumnHidingOnTextFilterChange`, and
`TestHidingOverlayClearsTextSearch`) that would create a custom overlay
instance instead of the globally provided one. I've tested both and the
tests run fine with the default overlay, so they're now using that
instead.

## `TestSceneFreeModSelectOverlay`

Updated to use footer v2.

---------

Co-authored-by: Dean Herbert <pe@ppy.sh>
This commit is contained in:
Krzysztof Gutkowski
2026-02-27 20:22:58 +01:00
committed by GitHub
Unverified
parent c72b6412ea
commit 105342e5bf
5 changed files with 307 additions and 183 deletions
@@ -12,6 +12,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Framework.Localisation;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Configuration;
@@ -25,6 +26,7 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Taiko.Mods;
using osu.Game.Screens;
using osu.Game.Screens.Footer;
using osu.Game.Tests.Mods;
using osuTK;
@@ -33,17 +35,19 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.UserInterface
{
[TestFixture]
public partial class TestSceneModSelectOverlay : OsuManualInputManagerTestScene
public partial class TestSceneModSelectOverlay : ScreenTestScene
{
protected override bool UseFreshStoragePerRun => true;
private RulesetStore rulesetStore = null!;
private TestModSelectOverlay modSelectOverlay = null!;
private TestModSelectOverlayScreen screen = null!;
[Resolved]
private OsuConfigManager configManager { get; set; } = null!;
private ModSelectOverlay modSelectOverlay => screen.Overlay;
[BackgroundDependencyLoader]
private void load()
{
@@ -52,9 +56,10 @@ namespace osu.Game.Tests.Visual.UserInterface
}
[SetUpSteps]
public void SetUpSteps()
public override void SetUpSteps()
{
AddStep("clear contents", Clear);
base.SetUpSteps();
AddStep("reset ruleset", () => Ruleset.Value = rulesetStore.GetRuleset(0));
AddStep("reset mods", () => SelectedMods.SetDefault());
AddStep("reset config", () => configManager.SetValue(OsuSetting.ModSelectTextSearchStartsActive, true));
@@ -97,29 +102,8 @@ namespace osu.Game.Tests.Visual.UserInterface
private void createScreen()
{
AddStep("create screen", () =>
{
var receptor = new ScreenFooter.BackReceptor();
var footer = new ScreenFooter(receptor);
Child = new DependencyProvidingContainer
{
RelativeSizeAxes = Axes.Both,
CachedDependencies = new[] { (typeof(ScreenFooter), (object)footer) },
Children = new Drawable[]
{
receptor,
modSelectOverlay = new TestModSelectOverlay
{
RelativeSizeAxes = Axes.Both,
State = { Value = Visibility.Visible },
Beatmap = { Value = Beatmap.Value },
SelectedMods = { BindTarget = SelectedMods },
},
footer,
}
};
});
AddStep("create screen", () => LoadScreen(screen = new TestModSelectOverlayScreen { SelectedMods = { BindTarget = SelectedMods } }));
AddUntilStep("wait until screen is loaded", () => screen.IsLoaded, () => Is.True);
waitForColumnLoad();
}
@@ -306,29 +290,30 @@ namespace osu.Game.Tests.Visual.UserInterface
[Test]
public void TestSettingsNotCrossPolluting()
{
TestScreenWithTwoOverlays screenWithTwoOverlays = null!;
Bindable<IReadOnlyList<Mod>> selectedMods2 = null!;
ModSelectOverlay modSelectOverlay2 = null!;
createScreen();
AddStep("push screen", () =>
{
selectedMods2 = new Bindable<IReadOnlyList<Mod>>(new Mod[] { new OsuModDifficultyAdjust() });
LoadScreen(screen = screenWithTwoOverlays = new TestScreenWithTwoOverlays
{
SelectedMods = { BindTarget = SelectedMods },
SelectedMods2 = { BindTarget = selectedMods2 },
});
});
AddStep("wait until screen is loaded", () => screenWithTwoOverlays.IsCurrentScreen());
waitForColumnLoad();
AddStep("select difficulty adjust via panel", () => getPanelForMod(typeof(OsuModDifficultyAdjust)).TriggerClick());
AddStep("set setting", () => modSelectOverlay.ChildrenOfType<RoundedSliderBar<float>>().First().Current.Value = 8);
AddStep("set setting", () => screenWithTwoOverlays.Overlay.ChildrenOfType<RoundedSliderBar<float>>().First().Current.Value = 8);
AddAssert("ensure setting is propagated", () => SelectedMods.Value.OfType<OsuModDifficultyAdjust>().Single().CircleSize.Value == 8);
AddStep("create second bindable", () => selectedMods2 = new Bindable<IReadOnlyList<Mod>>(new Mod[] { new OsuModDifficultyAdjust() }));
AddStep("create second overlay", () =>
{
Add(modSelectOverlay2 = new UserModSelectOverlay().With(d =>
{
d.Origin = Anchor.TopCentre;
d.Anchor = Anchor.TopCentre;
d.SelectedMods.BindTarget = selectedMods2;
}));
});
AddStep("show", () => modSelectOverlay2.Show());
AddStep("hide first overlay", () => screenWithTwoOverlays.Overlay.Hide());
AddStep("show second overlay", () => screenWithTwoOverlays.SecondOverlay.Show());
AddAssert("ensure first is unchanged", () => SelectedMods.Value.OfType<OsuModDifficultyAdjust>().Single().CircleSize.Value == 8);
AddAssert("ensure second is default", () => selectedMods2.Value.OfType<OsuModDifficultyAdjust>().Single().CircleSize.Value == null);
@@ -481,6 +466,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("set customized mod externally", () => SelectedMods.Value = new[] { new OsuModDoubleTime { SpeedChange = { Value = 1.01 } } });
AddAssert("setting remains", () => (SelectedMods.Value.SingleOrDefault() as OsuModDoubleTime)?.SpeedChange.Value == 1.01);
AddStep("exit screen", () => Stack.Exit());
createScreen();
AddAssert("setting remains", () => (SelectedMods.Value.SingleOrDefault() as OsuModDoubleTime)?.SpeedChange.Value == 1.01);
}
@@ -797,16 +783,11 @@ namespace osu.Game.Tests.Visual.UserInterface
[Test]
public void TestColumnHidingOnIsValidChange()
{
AddStep("create screen", () => Child = modSelectOverlay = new TestModSelectOverlay
{
RelativeSizeAxes = Axes.Both,
State = { Value = Visibility.Visible },
SelectedMods = { BindTarget = SelectedMods },
IsValidMod = mod => mod.Type == ModType.DifficultyIncrease || mod.Type == ModType.Conversion
});
waitForColumnLoad();
createScreen();
changeRuleset(0);
AddStep("set filter for 2 columns", () => modSelectOverlay.IsValidMod = mod => mod.Type is ModType.DifficultyIncrease or ModType.Conversion);
AddAssert("two columns visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) == 2);
AddStep("unset filter", () => modSelectOverlay.IsValidMod = _ => true);
@@ -816,9 +797,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddAssert("no columns visible", () => this.ChildrenOfType<ModColumn>().All(col => !col.IsPresent));
AddStep("hide", () => modSelectOverlay.Hide());
AddStep("set filter for 3 columns", () => modSelectOverlay.IsValidMod = mod => mod.Type == ModType.DifficultyReduction
|| mod.Type == ModType.Automation
|| mod.Type == ModType.Conversion);
AddStep("set filter for 3 columns", () => modSelectOverlay.IsValidMod = mod => mod.Type is ModType.DifficultyReduction or ModType.Automation or ModType.Conversion);
AddStep("show", () => modSelectOverlay.Show());
AddUntilStep("3 columns visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) == 3);
@@ -830,13 +809,7 @@ namespace osu.Game.Tests.Visual.UserInterface
[Test]
public void TestColumnHidingOnTextFilterChange()
{
AddStep("create screen", () => Child = modSelectOverlay = new TestModSelectOverlay
{
RelativeSizeAxes = Axes.Both,
State = { Value = Visibility.Visible },
SelectedMods = { BindTarget = SelectedMods }
});
waitForColumnLoad();
createScreen();
changeRuleset(0);
AddAssert("all columns visible", () => this.ChildrenOfType<ModColumn>().All(col => col.IsPresent));
@@ -854,13 +827,7 @@ namespace osu.Game.Tests.Visual.UserInterface
[Test]
public void TestHidingOverlayClearsTextSearch()
{
AddStep("create screen", () => Child = modSelectOverlay = new TestModSelectOverlay
{
RelativeSizeAxes = Axes.Both,
State = { Value = Visibility.Visible },
SelectedMods = { BindTarget = SelectedMods }
});
waitForColumnLoad();
createScreen();
changeRuleset(0);
AddAssert("all columns visible", () => this.ChildrenOfType<ModColumn>().All(col => col.IsPresent));
@@ -1019,8 +986,8 @@ namespace osu.Game.Tests.Visual.UserInterface
{
selectedMods = new Bindable<IReadOnlyList<Mod>>([]);
modSelectOverlay.SelectedMods.UnbindFrom(SelectedMods);
modSelectOverlay.SelectedMods.BindTo(selectedMods);
screen.SelectedMods.UnbindFrom(SelectedMods);
screen.SelectedMods.BindTo(selectedMods);
});
AddStep("activate PF", () => selectedMods.Value = [new OsuModPerfect()]);
@@ -1066,11 +1033,79 @@ namespace osu.Game.Tests.Visual.UserInterface
rulesetStore.Dispose();
}
private partial class TestModSelectOverlay : UserModSelectOverlay
private partial class TestModSelectOverlayScreen : OsuScreen
{
public TestModSelectOverlay()
public readonly Bindable<IReadOnlyList<Mod>> SelectedMods = new Bindable<IReadOnlyList<Mod>>();
public override bool ShowFooter => true;
public ModSelectOverlay Overlay = null!;
private IDisposable? firstOverlayRegistration;
[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
[Resolved]
protected IOverlayManager? OverlayManager { get; private set; }
[BackgroundDependencyLoader]
private void load()
{
ShowPresets = true;
LoadComponent(Overlay = new UserModSelectOverlay
{
RelativeSizeAxes = Axes.Both,
State = { Value = Visibility.Visible },
Beatmap = { Value = Beatmap.Value },
SelectedMods = { BindTarget = SelectedMods },
ShowPresets = true,
});
}
protected override void LoadComplete()
{
base.LoadComplete();
firstOverlayRegistration = OverlayManager?.RegisterBlockingOverlay(Overlay);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
firstOverlayRegistration?.Dispose();
}
}
private partial class TestScreenWithTwoOverlays : TestModSelectOverlayScreen
{
public readonly Bindable<IReadOnlyList<Mod>> SelectedMods2 = new Bindable<IReadOnlyList<Mod>>([]);
public ModSelectOverlay SecondOverlay = null!;
private IDisposable? secondOverlayRegistration;
[BackgroundDependencyLoader]
private void load()
{
LoadComponent(SecondOverlay = new UserModSelectOverlay
{
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
SelectedMods = { BindTarget = SelectedMods2 },
});
}
protected override void LoadComplete()
{
base.LoadComplete();
secondOverlayRegistration = OverlayManager?.RegisterBlockingOverlay(SecondOverlay);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
secondOverlayRegistration?.Dispose();
}
}