From 8352ee74e8a437c1f4a4dadb75d63049f45b164b Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Tue, 8 Sep 2026 16:25:11 -0400 Subject: add back workarounds sections, scope out of now playing --- tests/steamLaunchOptions.test.ts | 288 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 tests/steamLaunchOptions.test.ts (limited to 'tests/steamLaunchOptions.test.ts') diff --git a/tests/steamLaunchOptions.test.ts b/tests/steamLaunchOptions.test.ts new file mode 100644 index 0000000..8ecfa77 --- /dev/null +++ b/tests/steamLaunchOptions.test.ts @@ -0,0 +1,288 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { + applyWorkaroundChange, + applyWorkaroundState, + cleanupLegacyWrapper, + getDefaultWorkaroundState, + isLegacyWrapperToken, + parseWorkaroundOptions, + readSteamLaunchOptions, + updateSteamLaunchOptions, +} from "../src/utils/steamLaunchOptions.ts"; + +test("maps the supported workarounds to current launch variables", () => { + const options = applyWorkaroundState('gamemoderun %command% --profile "high quality"', { + dxvkFrameRate: 30, + disableGamescopeWsi: true, + disableSteamdeckMode: true, + disableVkbasalt: true, + enableZink: true, + }); + + assert.equal( + options, + 'ENABLE_GAMESCOPE_WSI=0 SteamDeck=0 DISABLE_VKBASALT=1 MESA_LOADER_DRIVER_OVERRIDE=zink DXVK_CONFIG="dxvk.maxFrameRate = 30" gamemoderun %command% --profile "high quality"', + ); + assert.deepEqual(parseWorkaroundOptions(options), { + state: { + dxvkFrameRate: 30, + disableGamescopeWsi: true, + disableSteamdeckMode: true, + disableVkbasalt: true, + enableZink: true, + }, + issues: [], + }); +}); + +test("uses SteamDeck=0 before %command% without a wrapper", () => { + assert.equal( + applyWorkaroundChange("", "disableSteamdeckMode", true), + "SteamDeck=0 %command%", + ); +}); + +test("keeps WSI disable opt-in and does not add HDR assignments", () => { + const defaults = getDefaultWorkaroundState(); + assert.equal(applyWorkaroundState("%command%", defaults), "%command%"); + assert.equal(parseWorkaroundOptions("%command%").state.disableGamescopeWsi, false); + assert.equal( + applyWorkaroundChange("%command%", "disableGamescopeWsi", true), + "ENABLE_GAMESCOPE_WSI=0 %command%", + ); + assert.equal( + applyWorkaroundChange("ENABLE_GAMESCOPE_WSI=0 %command%", "disableGamescopeWsi", false), + "%command%", + ); + + const legacy = parseWorkaroundOptions("ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 %command%"); + assert.equal(legacy.state.disableGamescopeWsi, true); + assert.deepEqual(legacy.issues, []); + assert.equal( + applyWorkaroundChange("ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 %command%", "disableGamescopeWsi", false), + "%command%", + ); + + const invalid = parseWorkaroundOptions("ENABLE_GAMESCOPE_WSI=maybe %command%"); + assert.equal(invalid.state.disableGamescopeWsi, false); + assert.equal(invalid.issues.length, 1); + const conflicting = parseWorkaroundOptions("DISABLE_GAMESCOPE_WSI=1 ENABLE_GAMESCOPE_WSI=1 %command%"); + assert.equal(conflicting.state.disableGamescopeWsi, true); + assert.match(conflicting.issues.join(" "), /conflicting/); +}); + +test("preserves unrelated prefixes, quoted tokens, suffix arguments, and dropped variables", () => { + const options = applyWorkaroundChange( + 'PROTON_USE_WOW64=1 MANGOHUD=1 MANGOHUD_CONFIG="alpha=0.01" ENABLE_VKBASALT=1 VK_INSTANCE_LAYERS="one:two" FOO="hello world" gamemoderun %command% --flag "two words"', + "disableSteamdeckMode", + true, + ); + assert.equal( + options, + 'SteamDeck=0 PROTON_USE_WOW64=1 MANGOHUD=1 MANGOHUD_CONFIG="alpha=0.01" ENABLE_VKBASALT=1 VK_INSTANCE_LAYERS="one:two" FOO="hello world" gamemoderun %command% --flag "two words"', + ); + assert.deepEqual(parseWorkaroundOptions(options).issues, []); + + assert.equal( + applyWorkaroundChange("FOO=bar --flag", "disableSteamdeckMode", true), + "SteamDeck=0 FOO=bar %command% --flag", + ); + assert.equal( + applyWorkaroundChange("FOO=1 %command% MANGOHUD=1", "disableSteamdeckMode", false), + "FOO=1 %command% MANGOHUD=1", + ); + assert.equal( + applyWorkaroundChange('FOO=bar --literal "%command%"', "disableSteamdeckMode", true), + 'SteamDeck=0 FOO=bar %command% --literal "%command%"', + ); + assert.equal( + applyWorkaroundChange("gamemoderun SteamDeck=1 %command%", "disableSteamdeckMode", true), + "SteamDeck=0 gamemoderun SteamDeck=1 %command%", + ); + assert.equal(parseWorkaroundOptions("gamemoderun SteamDeck=0 %command%").state.disableSteamdeckMode, false); +}); + +test("uses DXVK_CONFIG for the base cap and preserves other DXVK settings", () => { + assert.equal( + applyWorkaroundChange("%command%", "dxvkFrameRate", 60), + 'DXVK_CONFIG="dxvk.maxFrameRate = 60" %command%', + ); + assert.equal(parseWorkaroundOptions('DXVK_CONFIG="dxvk.maxFrameRate = 60" %command%').state.dxvkFrameRate, 60); + assert.equal( + applyWorkaroundChange( + 'DXVK_CONFIG="dxgi.syncInterval = 0; dxvk.maxFrameRate = 30" %command%', + "dxvkFrameRate", + 0, + ), + 'DXVK_CONFIG="dxgi.syncInterval = 0" %command%', + ); + assert.equal( + applyWorkaroundChange("DXVK_FRAME_RATE=30 %command%", "dxvkFrameRate", 45), + 'DXVK_CONFIG="dxvk.maxFrameRate = 45" %command%', + ); + assert.equal( + applyWorkaroundChange("DXVK_FRAME_RATE=30 %command%", "dxvkFrameRate", 0), + "%command%", + ); + + const apiSpecific = parseWorkaroundOptions( + 'DXVK_CONFIG="dxgi.maxFrameRate = 30; d3d9.maxFrameRate = 30" %command%', + ); + assert.equal(apiSpecific.state.dxvkFrameRate, 30); + assert.deepEqual(apiSpecific.issues, []); + const partial = parseWorkaroundOptions('DXVK_CONFIG="dxgi.maxFrameRate = 30" %command%'); + assert.equal(partial.state.dxvkFrameRate, 30); + assert.match(partial.issues.join(" "), /only caps one DirectX API/); + const conflicting = parseWorkaroundOptions( + 'DXVK_CONFIG="dxgi.maxFrameRate = 30; d3d9.maxFrameRate = 60" %command%', + ); + assert.equal(conflicting.state.dxvkFrameRate, 0); + assert.match(conflicting.issues.join(" "), /conflicting/); +}); + +test("reports invalid and malformed FPS values instead of treating them as off", () => { + const invalid = parseWorkaroundOptions('DXVK_CONFIG="dxvk.maxFrameRate = 61" %command%'); + assert.equal(invalid.state.dxvkFrameRate, 0); + assert.match(invalid.issues.join(" "), /outside the supported 0-60 range/); + const malformed = parseWorkaroundOptions('DXVK_CONFIG="dxvk.maxFrameRate" %command%'); + assert.equal(malformed.state.dxvkFrameRate, 0); + assert.match(malformed.issues.join(" "), /malformed/); + const obsolete = parseWorkaroundOptions("DXVK_FRAME_RATE=wat %command%"); + assert.equal(obsolete.state.dxvkFrameRate, 0); + assert.match(obsolete.issues.join(" "), /obsolete/); + assert.throws(() => applyWorkaroundChange("%command%", "dxvkFrameRate", 61), /0 to 60/); + assert.throws(() => applyWorkaroundChange("%command%", "dxvkFrameRate", 1.5), /0 to 60/); +}); + +test("keeps vkBasalt disable mutually exclusive while preserving the dropped enable flag otherwise", () => { + assert.equal( + applyWorkaroundChange("ENABLE_VKBASALT=1 %command%", "disableSteamdeckMode", true), + "SteamDeck=0 ENABLE_VKBASALT=1 %command%", + ); + const disabled = applyWorkaroundChange("ENABLE_VKBASALT=1 %command%", "disableVkbasalt", true); + assert.equal(disabled, "DISABLE_VKBASALT=1 %command%"); + assert.equal( + applyWorkaroundChange(disabled, "disableVkbasalt", false), + "%command%", + ); + const conflict = parseWorkaroundOptions("ENABLE_VKBASALT=1 DISABLE_VKBASALT=1 %command%"); + assert.equal(conflict.state.disableVkbasalt, true); + assert.match(conflict.issues.join(" "), /conflicting/); +}); + +test("handles current and legacy Zink forms and reports partial state", () => { + const enabled = applyWorkaroundChange("%command%", "enableZink", true); + assert.equal(enabled, "MESA_LOADER_DRIVER_OVERRIDE=zink %command%"); + assert.equal(parseWorkaroundOptions(enabled).state.enableZink, true); + + const legacy = parseWorkaroundOptions( + "__GLX_VENDOR_LIBRARY_NAME=mesa MESA_LOADER_DRIVER_OVERRIDE=zink GALLIUM_DRIVER=zink %command%", + ); + assert.equal(legacy.state.enableZink, true); + assert.deepEqual(legacy.issues, []); + + const partial = parseWorkaroundOptions("__GLX_VENDOR_LIBRARY_NAME=mesa MESA_LOADER_DRIVER_OVERRIDE=zink %command%"); + assert.equal(partial.state.enableZink, true); + assert.match(partial.issues.join(" "), /partially configured/); + assert.equal( + applyWorkaroundChange( + "__GLX_VENDOR_LIBRARY_NAME=mesa MESA_LOADER_DRIVER_OVERRIDE=zink GALLIUM_DRIVER=zink %command%", + "enableZink", + false, + ), + "%command%", + ); +}); + +test("cleans only the known legacy wrapper and preserves launch options", () => { + assert.equal( + cleanupLegacyWrapper('FOO=bar ~/lsfg %command% --arg "~/lsfg"'), + 'FOO=bar %command% --arg "~/lsfg"', + ); + assert.equal(cleanupLegacyWrapper("/home/deck/lsfg %command%"), "%command%"); + assert.equal( + cleanupLegacyWrapper("DXVK_FRAME_RATE=30 LSFG_PROCESS=decky-lsfg-vk %command%"), + "DXVK_FRAME_RATE=30 LSFG_PROCESS=decky-lsfg-vk %command%", + ); + assert.equal( + cleanupLegacyWrapper("LSFG_PROCESS=decky-lsfg-vk %command%"), + "LSFG_PROCESS=decky-lsfg-vk %command%", + ); + assert.equal(isLegacyWrapperToken("/home/kurt/lsfg"), false); +}); + +test("is idempotent", () => { + const first = applyWorkaroundChange("gamemoderun %command%", "enableZink", true); + assert.equal(applyWorkaroundState(first, parseWorkaroundOptions(first).state), first); + assert.equal(applyWorkaroundChange(first, "enableZink", true), first); + const capped = applyWorkaroundChange(first, "dxvkFrameRate", 30); + assert.equal(applyWorkaroundChange(capped, "dxvkFrameRate", 30), capped); +}); + +test("reads and writes the matching Steam app-details launch-option field", async () => { + const previousWindow = (globalThis as Record).window; + const previousSteamClient = (globalThis as Record).SteamClient; + let normalOptions = "FOO=bar %command%"; + let shortcutOptions = "--windowed"; + const normalWrites: string[] = []; + const shortcutWrites: string[] = []; + const unregisters: number[] = []; + + const windowShim = { setTimeout, clearTimeout }; + const apps = { + RegisterForAppDetails(appId: number, callback: (details: SteamAppDetails) => void) { + if (appId === 42) { + callback({ strLaunchOptions: normalOptions, strShortcutLaunchOptions: "must-not-be-read" }); + } else { + callback({ + strShortcutExe: "/usr/bin/example-game", + strShortcutLaunchOptions: shortcutOptions, + strLaunchOptions: "must-not-be-read", + }); + } + return { unregister: () => unregisters.push(appId) }; + }, + SetAppLaunchOptions(appId: number, options: string) { + assert.equal(appId, 42); + normalWrites.push(options); + normalOptions = options.replaceAll(" ", " "); + }, + SetShortcutLaunchOptions(appId: number, options: string) { + assert.equal(appId, 43); + shortcutWrites.push(options); + shortcutOptions = options; + }, + }; + + (globalThis as Record).window = windowShim; + (globalThis as Record).SteamClient = { Apps: apps }; + try { + const normalBefore = await readSteamLaunchOptions(42, false); + assert.equal(normalBefore.options, "FOO=bar %command%"); + const normalAfter = await updateSteamLaunchOptions( + 42, + false, + (options) => applyWorkaroundChange(options, "disableSteamdeckMode", true), + ); + assert.equal(normalWrites.length, 1); + assert.equal(shortcutWrites.length, 0); + assert.equal(normalAfter.options, "SteamDeck=0 FOO=bar %command%"); + + const shortcutAfter = await updateSteamLaunchOptions( + 43, + true, + (options) => applyWorkaroundChange(options, "disableGamescopeWsi", true), + ); + assert.equal(shortcutWrites.length, 1); + assert.equal(shortcutWrites[0], "ENABLE_GAMESCOPE_WSI=0 %command% --windowed"); + assert.equal(shortcutAfter.options, shortcutWrites[0]); + assert.ok(unregisters.includes(42)); + assert.ok(unregisters.includes(43)); + } finally { + if (previousWindow === undefined) delete (globalThis as Record).window; + else (globalThis as Record).window = previousWindow; + if (previousSteamClient === undefined) delete (globalThis as Record).SteamClient; + else (globalThis as Record).SteamClient = previousSteamClient; + } +}); -- cgit v1.2.3 From bec26fe025c97c00d398e7a4fb571195706b9e76 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Tue, 8 Sep 2026 16:56:57 -0400 Subject: feat: more launch arg janitoring --- tests/steamLaunchOptions.test.ts | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'tests/steamLaunchOptions.test.ts') diff --git a/tests/steamLaunchOptions.test.ts b/tests/steamLaunchOptions.test.ts index 8ecfa77..0662fbb 100644 --- a/tests/steamLaunchOptions.test.ts +++ b/tests/steamLaunchOptions.test.ts @@ -3,9 +3,11 @@ import test from "node:test"; import { applyWorkaroundChange, applyWorkaroundState, + cleanupLegacyLaunchOptions, cleanupLegacyWrapper, getDefaultWorkaroundState, isLegacyWrapperToken, + normalizeLaunchOptions, parseWorkaroundOptions, readSteamLaunchOptions, updateSteamLaunchOptions, @@ -45,7 +47,7 @@ test("uses SteamDeck=0 before %command% without a wrapper", () => { test("keeps WSI disable opt-in and does not add HDR assignments", () => { const defaults = getDefaultWorkaroundState(); - assert.equal(applyWorkaroundState("%command%", defaults), "%command%"); + assert.equal(applyWorkaroundState("%command%", defaults), ""); assert.equal(parseWorkaroundOptions("%command%").state.disableGamescopeWsi, false); assert.equal( applyWorkaroundChange("%command%", "disableGamescopeWsi", true), @@ -53,7 +55,7 @@ test("keeps WSI disable opt-in and does not add HDR assignments", () => { ); assert.equal( applyWorkaroundChange("ENABLE_GAMESCOPE_WSI=0 %command%", "disableGamescopeWsi", false), - "%command%", + "", ); const legacy = parseWorkaroundOptions("ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 %command%"); @@ -61,7 +63,7 @@ test("keeps WSI disable opt-in and does not add HDR assignments", () => { assert.deepEqual(legacy.issues, []); assert.equal( applyWorkaroundChange("ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 %command%", "disableGamescopeWsi", false), - "%command%", + "", ); const invalid = parseWorkaroundOptions("ENABLE_GAMESCOPE_WSI=maybe %command%"); @@ -123,7 +125,7 @@ test("uses DXVK_CONFIG for the base cap and preserves other DXVK settings", () = ); assert.equal( applyWorkaroundChange("DXVK_FRAME_RATE=30 %command%", "dxvkFrameRate", 0), - "%command%", + "", ); const apiSpecific = parseWorkaroundOptions( @@ -164,7 +166,7 @@ test("keeps vkBasalt disable mutually exclusive while preserving the dropped ena assert.equal(disabled, "DISABLE_VKBASALT=1 %command%"); assert.equal( applyWorkaroundChange(disabled, "disableVkbasalt", false), - "%command%", + "", ); const conflict = parseWorkaroundOptions("ENABLE_VKBASALT=1 DISABLE_VKBASALT=1 %command%"); assert.equal(conflict.state.disableVkbasalt, true); @@ -191,7 +193,7 @@ test("handles current and legacy Zink forms and reports partial state", () => { "enableZink", false, ), - "%command%", + "", ); }); @@ -200,7 +202,7 @@ test("cleans only the known legacy wrapper and preserves launch options", () => cleanupLegacyWrapper('FOO=bar ~/lsfg %command% --arg "~/lsfg"'), 'FOO=bar %command% --arg "~/lsfg"', ); - assert.equal(cleanupLegacyWrapper("/home/deck/lsfg %command%"), "%command%"); + assert.equal(cleanupLegacyWrapper("/home/deck/lsfg %command%"), ""); assert.equal( cleanupLegacyWrapper("DXVK_FRAME_RATE=30 LSFG_PROCESS=decky-lsfg-vk %command%"), "DXVK_FRAME_RATE=30 LSFG_PROCESS=decky-lsfg-vk %command%", @@ -212,6 +214,13 @@ test("cleans only the known legacy wrapper and preserves launch options", () => assert.equal(isLegacyWrapperToken("/home/kurt/lsfg"), false); }); +test("canonicalizes a bare command token without removing real arguments", () => { + assert.equal(normalizeLaunchOptions("%command%"), ""); + assert.equal(normalizeLaunchOptions("%COMMAND%"), ""); + assert.equal(normalizeLaunchOptions("FOO=bar %command%"), "FOO=bar %command%"); + assert.equal(normalizeLaunchOptions("%command% --windowed"), "%command% --windowed"); +}); + test("is idempotent", () => { const first = applyWorkaroundChange("gamemoderun %command%", "enableZink", true); assert.equal(applyWorkaroundState(first, parseWorkaroundOptions(first).state), first); -- cgit v1.2.3 From 790132668c4421c68c32bdc8fc9792b0d6028f97 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Tue, 8 Sep 2026 22:18:13 -0400 Subject: I really dont want to but here you go little guy --- tests/steamLaunchOptions.test.ts | 73 ++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 11 deletions(-) (limited to 'tests/steamLaunchOptions.test.ts') diff --git a/tests/steamLaunchOptions.test.ts b/tests/steamLaunchOptions.test.ts index 0662fbb..c4dede3 100644 --- a/tests/steamLaunchOptions.test.ts +++ b/tests/steamLaunchOptions.test.ts @@ -4,6 +4,7 @@ import { applyWorkaroundChange, applyWorkaroundState, cleanupLegacyLaunchOptions, + cleanupPluginLaunchOptions, cleanupLegacyWrapper, getDefaultWorkaroundState, isLegacyWrapperToken, @@ -17,6 +18,7 @@ test("maps the supported workarounds to current launch variables", () => { const options = applyWorkaroundState('gamemoderun %command% --profile "high quality"', { dxvkFrameRate: 30, disableGamescopeWsi: true, + disableHdr: true, disableSteamdeckMode: true, disableVkbasalt: true, enableZink: true, @@ -24,12 +26,13 @@ test("maps the supported workarounds to current launch variables", () => { assert.equal( options, - 'ENABLE_GAMESCOPE_WSI=0 SteamDeck=0 DISABLE_VKBASALT=1 MESA_LOADER_DRIVER_OVERRIDE=zink DXVK_CONFIG="dxvk.maxFrameRate = 30" gamemoderun %command% --profile "high quality"', + 'ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 SteamDeck=0 DISABLE_VKBASALT=1 MESA_LOADER_DRIVER_OVERRIDE=zink DXVK_CONFIG="dxvk.maxFrameRate = 30" gamemoderun %command% --profile "high quality"', ); assert.deepEqual(parseWorkaroundOptions(options), { state: { dxvkFrameRate: 30, disableGamescopeWsi: true, + disableHdr: true, disableSteamdeckMode: true, disableVkbasalt: true, enableZink: true, @@ -45,10 +48,24 @@ test("uses SteamDeck=0 before %command% without a wrapper", () => { ); }); -test("keeps WSI disable opt-in and does not add HDR assignments", () => { +test("defaults new profiles to disable Gamescope WSI and HDR", () => { const defaults = getDefaultWorkaroundState(); - assert.equal(applyWorkaroundState("%command%", defaults), ""); + assert.equal(defaults.disableGamescopeWsi, true); + assert.equal(defaults.disableHdr, true); + assert.equal( + applyWorkaroundState("%command%", defaults), + "ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 %command%", + ); assert.equal(parseWorkaroundOptions("%command%").state.disableGamescopeWsi, false); + assert.equal(parseWorkaroundOptions("%command%").state.disableHdr, false); + assert.equal( + parseWorkaroundOptions(applyWorkaroundState("%command%", defaults)).state.disableGamescopeWsi, + true, + ); + assert.equal( + parseWorkaroundOptions(applyWorkaroundState("%command%", defaults)).state.disableHdr, + true, + ); assert.equal( applyWorkaroundChange("%command%", "disableGamescopeWsi", true), "ENABLE_GAMESCOPE_WSI=0 %command%", @@ -58,14 +75,6 @@ test("keeps WSI disable opt-in and does not add HDR assignments", () => { "", ); - const legacy = parseWorkaroundOptions("ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 %command%"); - assert.equal(legacy.state.disableGamescopeWsi, true); - assert.deepEqual(legacy.issues, []); - assert.equal( - applyWorkaroundChange("ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 %command%", "disableGamescopeWsi", false), - "", - ); - const invalid = parseWorkaroundOptions("ENABLE_GAMESCOPE_WSI=maybe %command%"); assert.equal(invalid.state.disableGamescopeWsi, false); assert.equal(invalid.issues.length, 1); @@ -74,6 +83,27 @@ test("keeps WSI disable opt-in and does not add HDR assignments", () => { assert.match(conflicting.issues.join(" "), /conflicting/); }); +test("manages DXVK HDR independently from Gamescope WSI", () => { + assert.equal( + applyWorkaroundChange("%command%", "disableHdr", true), + "DXVK_HDR=0 %command%", + ); + assert.equal(parseWorkaroundOptions("DXVK_HDR=0 %command%").state.disableHdr, true); + assert.equal(parseWorkaroundOptions("DXVK_HDR=1 %command%").state.disableHdr, false); + assert.equal( + applyWorkaroundChange("DXVK_HDR=0 %command%", "disableHdr", false), + "", + ); + assert.equal( + applyWorkaroundChange("DXVK_HDR=0 %command%", "disableGamescopeWsi", true), + "ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 %command%", + ); + + const invalid = parseWorkaroundOptions("DXVK_HDR=maybe %command%"); + assert.equal(invalid.state.disableHdr, false); + assert.match(invalid.issues.join(" "), /Disable HDR has an unsupported value/); +}); + test("preserves unrelated prefixes, quoted tokens, suffix arguments, and dropped variables", () => { const options = applyWorkaroundChange( 'PROTON_USE_WOW64=1 MANGOHUD=1 MANGOHUD_CONFIG="alpha=0.01" ENABLE_VKBASALT=1 VK_INSTANCE_LAYERS="one:two" FOO="hello world" gamemoderun %command% --flag "two words"', @@ -203,6 +233,8 @@ test("cleans only the known legacy wrapper and preserves launch options", () => 'FOO=bar %command% --arg "~/lsfg"', ); assert.equal(cleanupLegacyWrapper("/home/deck/lsfg %command%"), ""); + assert.equal(cleanupLegacyWrapper("mako-run %command%"), ""); + assert.equal(cleanupLegacyWrapper("mako-launch %command%"), ""); assert.equal( cleanupLegacyWrapper("DXVK_FRAME_RATE=30 LSFG_PROCESS=decky-lsfg-vk %command%"), "DXVK_FRAME_RATE=30 LSFG_PROCESS=decky-lsfg-vk %command%", @@ -214,6 +246,25 @@ test("cleans only the known legacy wrapper and preserves launch options", () => assert.equal(isLegacyWrapperToken("/home/kurt/lsfg"), false); }); +test("removes plugin-managed launch options when a profile is removed", () => { + assert.equal( + cleanupPluginLaunchOptions( + 'FOO="keep this" ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 SteamDeck=0 DISABLE_VKBASALT=1 MESA_LOADER_DRIVER_OVERRIDE=zink DXVK_CONFIG="dxgi.syncInterval = 0; dxvk.maxFrameRate = 30" ~/lsfg %command% --windowed', + ), + 'DXVK_CONFIG="dxgi.syncInterval = 0" FOO="keep this" %command% --windowed', + ); + assert.equal( + cleanupPluginLaunchOptions( + 'PROTON_USE_WOW64=1 MANGOHUD=1 MANGOHUD_CONFIG="alpha=0.01" LSFG_PROCESS=decky-lsfg-vk %command%', + ), + 'PROTON_USE_WOW64=1 MANGOHUD=1 MANGOHUD_CONFIG="alpha=0.01" LSFG_PROCESS=decky-lsfg-vk %command%', + ); + assert.equal( + cleanupPluginLaunchOptions('DXVK_CONFIG="dxvk.maxFrameRate = 30" %command%'), + "", + ); +}); + test("canonicalizes a bare command token without removing real arguments", () => { assert.equal(normalizeLaunchOptions("%command%"), ""); assert.equal(normalizeLaunchOptions("%COMMAND%"), ""); -- cgit v1.2.3 From 1b932fd69c3dba925e0cbf027e05508b2daf5e8c Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Wed, 9 Sep 2026 01:01:42 -0400 Subject: add back launcher script and correct pathing --- tests/steamLaunchOptions.test.ts | 434 +++++++++++++-------------------------- 1 file changed, 148 insertions(+), 286 deletions(-) (limited to 'tests/steamLaunchOptions.test.ts') diff --git a/tests/steamLaunchOptions.test.ts b/tests/steamLaunchOptions.test.ts index c4dede3..3170fe8 100644 --- a/tests/steamLaunchOptions.test.ts +++ b/tests/steamLaunchOptions.test.ts @@ -1,342 +1,138 @@ import assert from "node:assert/strict"; import test from "node:test"; import { - applyWorkaroundChange, - applyWorkaroundState, - cleanupLegacyLaunchOptions, + cleanupPluginAssignments, cleanupPluginLaunchOptions, cleanupLegacyWrapper, - getDefaultWorkaroundState, + hasWrapperLaunchIntegration, + installWrapperIntegration, + installWrapperLaunchOption, isLegacyWrapperToken, normalizeLaunchOptions, - parseWorkaroundOptions, readSteamLaunchOptions, - updateSteamLaunchOptions, + removeWrapperIntegration, + removeWrapperLaunchOption, } from "../src/utils/steamLaunchOptions.ts"; -test("maps the supported workarounds to current launch variables", () => { - const options = applyWorkaroundState('gamemoderun %command% --profile "high quality"', { - dxvkFrameRate: 30, - disableGamescopeWsi: true, - disableHdr: true, - disableSteamdeckMode: true, - disableVkbasalt: true, - enableZink: true, - }); +const wrapper = "~/.lsfg"; - assert.equal( - options, - 'ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 SteamDeck=0 DISABLE_VKBASALT=1 MESA_LOADER_DRIVER_OVERRIDE=zink DXVK_CONFIG="dxvk.maxFrameRate = 30" gamemoderun %command% --profile "high quality"', - ); - assert.deepEqual(parseWorkaroundOptions(options), { - state: { - dxvkFrameRate: 30, - disableGamescopeWsi: true, - disableHdr: true, - disableSteamdeckMode: true, - disableVkbasalt: true, - enableZink: true, - }, - issues: [], +test("inserts one wrapper immediately before an existing command macro", () => { + assert.deepEqual(installWrapperLaunchOption('gamemoderun %command% --profile "high quality"', wrapper), { + options: 'gamemoderun ~/.lsfg %command% --profile "high quality"', + commandTokenAdded: false, + }); + assert.equal(hasWrapperLaunchIntegration(`gamemoderun ${wrapper} %command%`, wrapper), true); + assert.deepEqual(installWrapperLaunchOption(`gamemoderun ${wrapper} %command%`, wrapper), { + options: `gamemoderun ${wrapper} %command%`, + commandTokenAdded: false, }); }); -test("uses SteamDeck=0 before %command% without a wrapper", () => { - assert.equal( - applyWorkaroundChange("", "disableSteamdeckMode", true), - "SteamDeck=0 %command%", - ); -}); - -test("defaults new profiles to disable Gamescope WSI and HDR", () => { - const defaults = getDefaultWorkaroundState(); - assert.equal(defaults.disableGamescopeWsi, true); - assert.equal(defaults.disableHdr, true); - assert.equal( - applyWorkaroundState("%command%", defaults), - "ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 %command%", - ); - assert.equal(parseWorkaroundOptions("%command%").state.disableGamescopeWsi, false); - assert.equal(parseWorkaroundOptions("%command%").state.disableHdr, false); - assert.equal( - parseWorkaroundOptions(applyWorkaroundState("%command%", defaults)).state.disableGamescopeWsi, - true, - ); - assert.equal( - parseWorkaroundOptions(applyWorkaroundState("%command%", defaults)).state.disableHdr, - true, - ); - assert.equal( - applyWorkaroundChange("%command%", "disableGamescopeWsi", true), - "ENABLE_GAMESCOPE_WSI=0 %command%", - ); - assert.equal( - applyWorkaroundChange("ENABLE_GAMESCOPE_WSI=0 %command%", "disableGamescopeWsi", false), - "", - ); - - const invalid = parseWorkaroundOptions("ENABLE_GAMESCOPE_WSI=maybe %command%"); - assert.equal(invalid.state.disableGamescopeWsi, false); - assert.equal(invalid.issues.length, 1); - const conflicting = parseWorkaroundOptions("DISABLE_GAMESCOPE_WSI=1 ENABLE_GAMESCOPE_WSI=1 %command%"); - assert.equal(conflicting.state.disableGamescopeWsi, true); - assert.match(conflicting.issues.join(" "), /conflicting/); -}); - -test("manages DXVK HDR independently from Gamescope WSI", () => { - assert.equal( - applyWorkaroundChange("%command%", "disableHdr", true), - "DXVK_HDR=0 %command%", - ); - assert.equal(parseWorkaroundOptions("DXVK_HDR=0 %command%").state.disableHdr, true); - assert.equal(parseWorkaroundOptions("DXVK_HDR=1 %command%").state.disableHdr, false); - assert.equal( - applyWorkaroundChange("DXVK_HDR=0 %command%", "disableHdr", false), - "", - ); - assert.equal( - applyWorkaroundChange("DXVK_HDR=0 %command%", "disableGamescopeWsi", true), - "ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 %command%", - ); - - const invalid = parseWorkaroundOptions("DXVK_HDR=maybe %command%"); - assert.equal(invalid.state.disableHdr, false); - assert.match(invalid.issues.join(" "), /Disable HDR has an unsupported value/); -}); - -test("preserves unrelated prefixes, quoted tokens, suffix arguments, and dropped variables", () => { - const options = applyWorkaroundChange( - 'PROTON_USE_WOW64=1 MANGOHUD=1 MANGOHUD_CONFIG="alpha=0.01" ENABLE_VKBASALT=1 VK_INSTANCE_LAYERS="one:two" FOO="hello world" gamemoderun %command% --flag "two words"', - "disableSteamdeckMode", - true, - ); - assert.equal( - options, - 'SteamDeck=0 PROTON_USE_WOW64=1 MANGOHUD=1 MANGOHUD_CONFIG="alpha=0.01" ENABLE_VKBASALT=1 VK_INSTANCE_LAYERS="one:two" FOO="hello world" gamemoderun %command% --flag "two words"', - ); - assert.deepEqual(parseWorkaroundOptions(options).issues, []); - - assert.equal( - applyWorkaroundChange("FOO=bar --flag", "disableSteamdeckMode", true), - "SteamDeck=0 FOO=bar %command% --flag", - ); - assert.equal( - applyWorkaroundChange("FOO=1 %command% MANGOHUD=1", "disableSteamdeckMode", false), - "FOO=1 %command% MANGOHUD=1", - ); - assert.equal( - applyWorkaroundChange('FOO=bar --literal "%command%"', "disableSteamdeckMode", true), - 'SteamDeck=0 FOO=bar %command% --literal "%command%"', - ); - assert.equal( - applyWorkaroundChange("gamemoderun SteamDeck=1 %command%", "disableSteamdeckMode", true), - "SteamDeck=0 gamemoderun SteamDeck=1 %command%", - ); - assert.equal(parseWorkaroundOptions("gamemoderun SteamDeck=0 %command%").state.disableSteamdeckMode, false); -}); - -test("uses DXVK_CONFIG for the base cap and preserves other DXVK settings", () => { - assert.equal( - applyWorkaroundChange("%command%", "dxvkFrameRate", 60), - 'DXVK_CONFIG="dxvk.maxFrameRate = 60" %command%', - ); - assert.equal(parseWorkaroundOptions('DXVK_CONFIG="dxvk.maxFrameRate = 60" %command%').state.dxvkFrameRate, 60); - assert.equal( - applyWorkaroundChange( - 'DXVK_CONFIG="dxgi.syncInterval = 0; dxvk.maxFrameRate = 30" %command%', - "dxvkFrameRate", - 0, - ), - 'DXVK_CONFIG="dxgi.syncInterval = 0" %command%', - ); - assert.equal( - applyWorkaroundChange("DXVK_FRAME_RATE=30 %command%", "dxvkFrameRate", 45), - 'DXVK_CONFIG="dxvk.maxFrameRate = 45" %command%', - ); - assert.equal( - applyWorkaroundChange("DXVK_FRAME_RATE=30 %command%", "dxvkFrameRate", 0), - "", - ); - - const apiSpecific = parseWorkaroundOptions( - 'DXVK_CONFIG="dxgi.maxFrameRate = 30; d3d9.maxFrameRate = 30" %command%', - ); - assert.equal(apiSpecific.state.dxvkFrameRate, 30); - assert.deepEqual(apiSpecific.issues, []); - const partial = parseWorkaroundOptions('DXVK_CONFIG="dxgi.maxFrameRate = 30" %command%'); - assert.equal(partial.state.dxvkFrameRate, 30); - assert.match(partial.issues.join(" "), /only caps one DirectX API/); - const conflicting = parseWorkaroundOptions( - 'DXVK_CONFIG="dxgi.maxFrameRate = 30; d3d9.maxFrameRate = 60" %command%', - ); - assert.equal(conflicting.state.dxvkFrameRate, 0); - assert.match(conflicting.issues.join(" "), /conflicting/); -}); - -test("reports invalid and malformed FPS values instead of treating them as off", () => { - const invalid = parseWorkaroundOptions('DXVK_CONFIG="dxvk.maxFrameRate = 61" %command%'); - assert.equal(invalid.state.dxvkFrameRate, 0); - assert.match(invalid.issues.join(" "), /outside the supported 0-60 range/); - const malformed = parseWorkaroundOptions('DXVK_CONFIG="dxvk.maxFrameRate" %command%'); - assert.equal(malformed.state.dxvkFrameRate, 0); - assert.match(malformed.issues.join(" "), /malformed/); - const obsolete = parseWorkaroundOptions("DXVK_FRAME_RATE=wat %command%"); - assert.equal(obsolete.state.dxvkFrameRate, 0); - assert.match(obsolete.issues.join(" "), /obsolete/); - assert.throws(() => applyWorkaroundChange("%command%", "dxvkFrameRate", 61), /0 to 60/); - assert.throws(() => applyWorkaroundChange("%command%", "dxvkFrameRate", 1.5), /0 to 60/); -}); - -test("keeps vkBasalt disable mutually exclusive while preserving the dropped enable flag otherwise", () => { - assert.equal( - applyWorkaroundChange("ENABLE_VKBASALT=1 %command%", "disableSteamdeckMode", true), - "SteamDeck=0 ENABLE_VKBASALT=1 %command%", - ); - const disabled = applyWorkaroundChange("ENABLE_VKBASALT=1 %command%", "disableVkbasalt", true); - assert.equal(disabled, "DISABLE_VKBASALT=1 %command%"); - assert.equal( - applyWorkaroundChange(disabled, "disableVkbasalt", false), - "", - ); - const conflict = parseWorkaroundOptions("ENABLE_VKBASALT=1 DISABLE_VKBASALT=1 %command%"); - assert.equal(conflict.state.disableVkbasalt, true); - assert.match(conflict.issues.join(" "), /conflicting/); +test("normalizes blank and argument-only fields while refusing ambiguous launchers", () => { + assert.deepEqual(installWrapperLaunchOption("", wrapper), { + options: `${wrapper} %command%`, + commandTokenAdded: true, + }); + assert.deepEqual(installWrapperLaunchOption("FOO=bar --windowed", wrapper), { + options: `FOO=bar ${wrapper} %command% --windowed`, + commandTokenAdded: true, + }); + assert.throws(() => installWrapperLaunchOption("gamemoderun --windowed", wrapper), /refusing to guess/); + assert.throws(() => installWrapperLaunchOption('"%command%"', wrapper), /refusing to guess/); }); -test("handles current and legacy Zink forms and reports partial state", () => { - const enabled = applyWorkaroundChange("%command%", "enableZink", true); - assert.equal(enabled, "MESA_LOADER_DRIVER_OVERRIDE=zink %command%"); - assert.equal(parseWorkaroundOptions(enabled).state.enableZink, true); - - const legacy = parseWorkaroundOptions( - "__GLX_VENDOR_LIBRARY_NAME=mesa MESA_LOADER_DRIVER_OVERRIDE=zink GALLIUM_DRIVER=zink %command%", - ); - assert.equal(legacy.state.enableZink, true); - assert.deepEqual(legacy.issues, []); - - const partial = parseWorkaroundOptions("__GLX_VENDOR_LIBRARY_NAME=mesa MESA_LOADER_DRIVER_OVERRIDE=zink %command%"); - assert.equal(partial.state.enableZink, true); - assert.match(partial.issues.join(" "), /partially configured/); +test("preserves assignments, quoting, suffixes, and unrelated values", () => { + const options = 'FOO="hello world" VK_INSTANCE_LAYERS="one:two" gamemoderun %command% --flag "two words"'; assert.equal( - applyWorkaroundChange( - "__GLX_VENDOR_LIBRARY_NAME=mesa MESA_LOADER_DRIVER_OVERRIDE=zink GALLIUM_DRIVER=zink %command%", - "enableZink", - false, - ), - "", + installWrapperLaunchOption(options, wrapper).options, + 'FOO="hello world" VK_INSTANCE_LAYERS="one:two" gamemoderun ~/.lsfg %command% --flag "two words"', ); + assert.equal(removeWrapperLaunchOption(`${wrapper} %command% --arg "${wrapper}"`, wrapper, true), `--arg "${wrapper}"`); + assert.equal(normalizeLaunchOptions(" FOO=bar %COMMAND% --flag "), "FOO=bar %COMMAND% --flag"); }); -test("cleans only the known legacy wrapper and preserves launch options", () => { - assert.equal( - cleanupLegacyWrapper('FOO=bar ~/lsfg %command% --arg "~/lsfg"'), - 'FOO=bar %command% --arg "~/lsfg"', - ); - assert.equal(cleanupLegacyWrapper("/home/deck/lsfg %command%"), ""); - assert.equal(cleanupLegacyWrapper("mako-run %command%"), ""); - assert.equal(cleanupLegacyWrapper("mako-launch %command%"), ""); - assert.equal( - cleanupLegacyWrapper("DXVK_FRAME_RATE=30 LSFG_PROCESS=decky-lsfg-vk %command%"), - "DXVK_FRAME_RATE=30 LSFG_PROCESS=decky-lsfg-vk %command%", - ); - assert.equal( - cleanupLegacyWrapper("LSFG_PROCESS=decky-lsfg-vk %command%"), - "LSFG_PROCESS=decky-lsfg-vk %command%", - ); - assert.equal(isLegacyWrapperToken("/home/kurt/lsfg"), false); +test("cleans current, legacy, and bare Mako wrappers without touching suffix arguments", () => { + for (const token of ["~/lsfg", "/home/deck/lsfg", "mako-run", "mako-launch"]) { + assert.equal(cleanupLegacyWrapper(`FOO=bar ${token} %command% --arg "${token}"`), `FOO=bar %command% --arg "${token}"`); + } + assert.equal(cleanupLegacyWrapper(`FOO=bar ${wrapper} %command%`), "FOO=bar %command%"); + assert.equal(isLegacyWrapperToken("/home/kurt/lsfg"), true); + assert.equal(isLegacyWrapperToken("/opt/tools/lsfg"), false); + assert.equal(removeWrapperLaunchOption(`FOO=bar ${wrapper} %command% --arg`, wrapper), "FOO=bar %command% --arg"); }); -test("removes plugin-managed launch options when a profile is removed", () => { +test("removes only old plugin assignments and preserves DXVK settings", () => { assert.equal( - cleanupPluginLaunchOptions( - 'FOO="keep this" ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 SteamDeck=0 DISABLE_VKBASALT=1 MESA_LOADER_DRIVER_OVERRIDE=zink DXVK_CONFIG="dxgi.syncInterval = 0; dxvk.maxFrameRate = 30" ~/lsfg %command% --windowed', + cleanupPluginAssignments( + 'FOO="keep this" ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 SteamDeck=0 DISABLE_VKBASALT=1 MESA_LOADER_DRIVER_OVERRIDE=zink DXVK_CONFIG="dxgi.syncInterval = 0; dxvk.maxFrameRate = 30" %command%', ), - 'DXVK_CONFIG="dxgi.syncInterval = 0" FOO="keep this" %command% --windowed', + 'FOO="keep this" DXVK_CONFIG="dxgi.syncInterval = 0" %command%', ); assert.equal( - cleanupPluginLaunchOptions( - 'PROTON_USE_WOW64=1 MANGOHUD=1 MANGOHUD_CONFIG="alpha=0.01" LSFG_PROCESS=decky-lsfg-vk %command%', - ), - 'PROTON_USE_WOW64=1 MANGOHUD=1 MANGOHUD_CONFIG="alpha=0.01" LSFG_PROCESS=decky-lsfg-vk %command%', + cleanupPluginLaunchOptions(`DXVK_FRAME_RATE=30 ${wrapper} %command%`, wrapper), + "%command%", ); assert.equal( - cleanupPluginLaunchOptions('DXVK_CONFIG="dxvk.maxFrameRate = 30" %command%'), - "", + cleanupPluginAssignments("PROTON_USE_WOW64=1 MANGOHUD=1 MANGOHUD_CONFIG=alpha %command%"), + "PROTON_USE_WOW64=1 MANGOHUD=1 MANGOHUD_CONFIG=alpha %command%", ); }); -test("canonicalizes a bare command token without removing real arguments", () => { - assert.equal(normalizeLaunchOptions("%command%"), ""); - assert.equal(normalizeLaunchOptions("%COMMAND%"), ""); - assert.equal(normalizeLaunchOptions("FOO=bar %command%"), "FOO=bar %command%"); - assert.equal(normalizeLaunchOptions("%command% --windowed"), "%command% --windowed"); -}); - -test("is idempotent", () => { - const first = applyWorkaroundChange("gamemoderun %command%", "enableZink", true); - assert.equal(applyWorkaroundState(first, parseWorkaroundOptions(first).state), first); - assert.equal(applyWorkaroundChange(first, "enableZink", true), first); - const capped = applyWorkaroundChange(first, "dxvkFrameRate", 30); - assert.equal(applyWorkaroundChange(capped, "dxvkFrameRate", 30), capped); -}); - -test("reads and writes the matching Steam app-details launch-option field", async () => { +test("reads the matching app-details field and installs/removes Steam integration", async () => { const previousWindow = (globalThis as Record).window; const previousSteamClient = (globalThis as Record).SteamClient; - let normalOptions = "FOO=bar %command%"; + let appOptions = "FOO=bar %command%"; let shortcutOptions = "--windowed"; - const normalWrites: string[] = []; + let shortcutTarget = "/usr/bin/example-game"; + const appWrites: string[] = []; const shortcutWrites: string[] = []; + const targetWrites: string[] = []; const unregisters: number[] = []; - - const windowShim = { setTimeout, clearTimeout }; const apps = { RegisterForAppDetails(appId: number, callback: (details: SteamAppDetails) => void) { - if (appId === 42) { - callback({ strLaunchOptions: normalOptions, strShortcutLaunchOptions: "must-not-be-read" }); - } else { - callback({ - strShortcutExe: "/usr/bin/example-game", - strShortcutLaunchOptions: shortcutOptions, - strLaunchOptions: "must-not-be-read", - }); - } + callback(appId === 42 + ? { strLaunchOptions: appOptions, strShortcutLaunchOptions: "wrong-field" } + : { strShortcutExe: shortcutTarget, strShortcutLaunchOptions: shortcutOptions, strLaunchOptions: "wrong-field" }); return { unregister: () => unregisters.push(appId) }; }, SetAppLaunchOptions(appId: number, options: string) { assert.equal(appId, 42); - normalWrites.push(options); - normalOptions = options.replaceAll(" ", " "); + appWrites.push(options); + appOptions = options.replaceAll(" ", " "); }, SetShortcutLaunchOptions(appId: number, options: string) { assert.equal(appId, 43); shortcutWrites.push(options); shortcutOptions = options; }, + SetShortcutExe(appId: number, executable: string) { + assert.equal(appId, 43); + targetWrites.push(executable); + shortcutTarget = executable; + }, }; - - (globalThis as Record).window = windowShim; + (globalThis as Record).window = { setTimeout, clearTimeout }; (globalThis as Record).SteamClient = { Apps: apps }; try { - const normalBefore = await readSteamLaunchOptions(42, false); - assert.equal(normalBefore.options, "FOO=bar %command%"); - const normalAfter = await updateSteamLaunchOptions( - 42, - false, - (options) => applyWorkaroundChange(options, "disableSteamdeckMode", true), - ); - assert.equal(normalWrites.length, 1); + const normal = await readSteamLaunchOptions(42, false); + assert.equal(normal.options, "FOO=bar %command%"); + const installed = await installWrapperIntegration(42, false, wrapper); + assert.equal(installed.snapshot.options, `FOO=bar ${wrapper} %command%`.replaceAll(" ", " ")); + assert.equal(installed.commandTokenAdded, false); + assert.equal(appWrites.length, 1); assert.equal(shortcutWrites.length, 0); - assert.equal(normalAfter.options, "SteamDeck=0 FOO=bar %command%"); - const shortcutAfter = await updateSteamLaunchOptions( - 43, - true, - (options) => applyWorkaroundChange(options, "disableGamescopeWsi", true), - ); - assert.equal(shortcutWrites.length, 1); - assert.equal(shortcutWrites[0], "ENABLE_GAMESCOPE_WSI=0 %command% --windowed"); - assert.equal(shortcutAfter.options, shortcutWrites[0]); + const shortcut = await installWrapperIntegration(43, true, wrapper); + assert.equal(shortcut.originalExecutable, "/usr/bin/example-game"); + assert.equal(shortcut.snapshot.target, wrapper); + assert.deepEqual(targetWrites, [wrapper]); + const restored = await removeWrapperIntegration(43, true, wrapper, shortcut.originalExecutable); + assert.equal(restored.target, "/usr/bin/example-game"); + assert.deepEqual(targetWrites, [wrapper, "/usr/bin/example-game"]); + assert.equal(shortcutWrites.length, 0); + + const cleaned = await removeWrapperIntegration(42, false, wrapper, undefined, installed.commandTokenAdded); + assert.equal(cleaned.options, "FOO=bar %command%".replaceAll(" ", " ")); assert.ok(unregisters.includes(42)); assert.ok(unregisters.includes(43)); } finally { @@ -346,3 +142,69 @@ test("reads and writes the matching Steam app-details launch-option field", asyn else (globalThis as Record).SteamClient = previousSteamClient; } }); + +test("fails closed when shortcut Target ownership or setters are unavailable", async () => { + const previousWindow = (globalThis as Record).window; + const previousSteamClient = (globalThis as Record).SteamClient; + (globalThis as Record).window = { setTimeout, clearTimeout }; + (globalThis as Record).SteamClient = { + Apps: { + RegisterForAppDetails(_appId: number, callback: (details: SteamAppDetails) => void) { + callback({ strShortcutExe: "/usr/bin/other", strShortcutLaunchOptions: "" }); + return { unregister() {} }; + }, + }, + }; + try { + await assert.rejects(installWrapperIntegration(99, true, wrapper), /Target API is unavailable/); + await assert.rejects(removeWrapperIntegration(99, true, wrapper, "/usr/bin/original"), /Target changed externally/); + } finally { + if (previousWindow === undefined) delete (globalThis as Record).window; + else (globalThis as Record).window = previousWindow; + if (previousSteamClient === undefined) delete (globalThis as Record).SteamClient; + else (globalThis as Record).SteamClient = previousSteamClient; + } +}); + +test("restores launch options and shortcut Target when a setter fails after changing them", async () => { + const previousWindow = (globalThis as Record).window; + const previousSteamClient = (globalThis as Record).SteamClient; + let appOptions = "FOO=bar %command%"; + let shortcutTarget = "/usr/bin/original"; + const appWrites: string[] = []; + const targetWrites: string[] = []; + const apps = { + RegisterForAppDetails(appId: number, callback: (details: SteamAppDetails) => void) { + callback(appId === 42 + ? { strLaunchOptions: appOptions } + : { strShortcutExe: shortcutTarget, strShortcutLaunchOptions: "" }); + return { unregister() {} }; + }, + SetAppLaunchOptions(_appId: number, options: string) { + appWrites.push(options); + appOptions = options; + if (options.includes(wrapper)) throw new Error("simulated launch-option write failure"); + }, + SetShortcutExe(_appId: number, executable: string) { + targetWrites.push(executable); + shortcutTarget = executable; + if (executable === wrapper) throw new Error("simulated Target write failure"); + }, + }; + (globalThis as Record).window = { setTimeout, clearTimeout }; + (globalThis as Record).SteamClient = { Apps: apps }; + try { + await assert.rejects(installWrapperIntegration(42, false, wrapper), /simulated launch-option write failure/); + assert.equal(appOptions, "FOO=bar %command%"); + assert.deepEqual(appWrites, [`FOO=bar ${wrapper} %command%`, "FOO=bar %command%"]); + + await assert.rejects(installWrapperIntegration(43, true, wrapper), /simulated Target write failure/); + assert.equal(shortcutTarget, "/usr/bin/original"); + assert.deepEqual(targetWrites, [wrapper, "/usr/bin/original"]); + } finally { + if (previousWindow === undefined) delete (globalThis as Record).window; + else (globalThis as Record).window = previousWindow; + if (previousSteamClient === undefined) delete (globalThis as Record).SteamClient; + else (globalThis as Record).SteamClient = previousSteamClient; + } +}); -- cgit v1.2.3 From b197e25b45d53c6c7175a45dd0b14642f2aab198 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Thu, 10 Sep 2026 11:51:22 -0400 Subject: fixes for appimage and flatpak --- tests/steamLaunchOptions.test.ts | 62 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 5 deletions(-) (limited to 'tests/steamLaunchOptions.test.ts') diff --git a/tests/steamLaunchOptions.test.ts b/tests/steamLaunchOptions.test.ts index 3170fe8..215e3f7 100644 --- a/tests/steamLaunchOptions.test.ts +++ b/tests/steamLaunchOptions.test.ts @@ -37,6 +37,10 @@ test("normalizes blank and argument-only fields while refusing ambiguous launche options: `FOO=bar ${wrapper} %command% --windowed`, commandTokenAdded: true, }); + assert.deepEqual(installWrapperLaunchOption('FOO=bar "/home/deck/game.AppImage"', wrapper, true), { + options: 'FOO=bar ~/.lsfg %command% "/home/deck/game.AppImage"', + commandTokenAdded: true, + }); assert.throws(() => installWrapperLaunchOption("gamemoderun --windowed", wrapper), /refusing to guess/); assert.throws(() => installWrapperLaunchOption('"%command%"', wrapper), /refusing to guess/); }); @@ -122,11 +126,11 @@ test("reads the matching app-details field and installs/removes Steam integratio assert.equal(appWrites.length, 1); assert.equal(shortcutWrites.length, 0); - const shortcut = await installWrapperIntegration(43, true, wrapper); + const shortcut = await installWrapperIntegration(43, true, wrapper, false, "flatpak"); assert.equal(shortcut.originalExecutable, "/usr/bin/example-game"); assert.equal(shortcut.snapshot.target, wrapper); assert.deepEqual(targetWrites, [wrapper]); - const restored = await removeWrapperIntegration(43, true, wrapper, shortcut.originalExecutable); + const restored = await removeWrapperIntegration(43, true, wrapper, shortcut.originalExecutable, false, "flatpak"); assert.equal(restored.target, "/usr/bin/example-game"); assert.deepEqual(targetWrites, [wrapper, "/usr/bin/example-game"]); assert.equal(shortcutWrites.length, 0); @@ -143,6 +147,54 @@ test("reads the matching app-details field and installs/removes Steam integratio } }); +test("uses shortcut launch options for a host shortcut without changing its Target", async () => { + const previousWindow = (globalThis as Record).window; + const previousSteamClient = (globalThis as Record).SteamClient; + const originalOptions = 'DESKTOPINTEGRATION=1 "/home/deck/AppImages/dusk.appimage"'; + let shortcutOptions = originalOptions; + let shortcutTarget = "env"; + const shortcutWrites: string[] = []; + const targetWrites: string[] = []; + const apps = { + RegisterForAppDetails(_appId: number, callback: (details: SteamAppDetails) => void) { + callback({ strShortcutExe: shortcutTarget, strShortcutLaunchOptions: shortcutOptions }); + return { unregister() {} }; + }, + SetShortcutLaunchOptions(_appId: number, options: string) { + shortcutWrites.push(options); + shortcutOptions = options; + }, + SetShortcutExe(_appId: number, executable: string) { + targetWrites.push(executable); + shortcutTarget = executable; + }, + }; + (globalThis as Record).window = { setTimeout, clearTimeout }; + (globalThis as Record).SteamClient = { Apps: apps }; + try { + const installed = await installWrapperIntegration(44, true, wrapper, false, "host"); + assert.equal(installed.originalExecutable, undefined); + assert.equal(installed.snapshot.target, "env"); + assert.equal(installed.snapshot.options, 'DESKTOPINTEGRATION=1 ~/.lsfg %command% "/home/deck/AppImages/dusk.appimage"'); + assert.deepEqual(targetWrites, []); + assert.deepEqual(shortcutWrites, [installed.snapshot.options]); + + const secondInstall = await installWrapperIntegration(44, true, wrapper, false, "host"); + assert.equal(secondInstall.snapshot.options, installed.snapshot.options); + assert.deepEqual(shortcutWrites, [installed.snapshot.options]); + + const restored = await removeWrapperIntegration(44, true, wrapper, undefined, installed.commandTokenAdded, "host"); + assert.equal(restored.target, "env"); + assert.equal(restored.options, originalOptions); + assert.deepEqual(targetWrites, []); + } finally { + if (previousWindow === undefined) delete (globalThis as Record).window; + else (globalThis as Record).window = previousWindow; + if (previousSteamClient === undefined) delete (globalThis as Record).SteamClient; + else (globalThis as Record).SteamClient = previousSteamClient; + } +}); + test("fails closed when shortcut Target ownership or setters are unavailable", async () => { const previousWindow = (globalThis as Record).window; const previousSteamClient = (globalThis as Record).SteamClient; @@ -156,8 +208,8 @@ test("fails closed when shortcut Target ownership or setters are unavailable", a }, }; try { - await assert.rejects(installWrapperIntegration(99, true, wrapper), /Target API is unavailable/); - await assert.rejects(removeWrapperIntegration(99, true, wrapper, "/usr/bin/original"), /Target changed externally/); + await assert.rejects(installWrapperIntegration(99, true, wrapper, false, "flatpak"), /Target API is unavailable/); + await assert.rejects(removeWrapperIntegration(99, true, wrapper, "/usr/bin/original", false, "flatpak"), /Target changed externally/); } finally { if (previousWindow === undefined) delete (globalThis as Record).window; else (globalThis as Record).window = previousWindow; @@ -198,7 +250,7 @@ test("restores launch options and shortcut Target when a setter fails after chan assert.equal(appOptions, "FOO=bar %command%"); assert.deepEqual(appWrites, [`FOO=bar ${wrapper} %command%`, "FOO=bar %command%"]); - await assert.rejects(installWrapperIntegration(43, true, wrapper), /simulated Target write failure/); + await assert.rejects(installWrapperIntegration(43, true, wrapper, false, "flatpak"), /simulated Target write failure/); assert.equal(shortcutTarget, "/usr/bin/original"); assert.deepEqual(targetWrites, [wrapper, "/usr/bin/original"]); } finally { -- cgit v1.2.3 From 670f36e8cc75da9c8b1b174c24e722657bbf2a56 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Thu, 10 Sep 2026 12:15:05 -0400 Subject: cleanup flatpak handles --- tests/steamLaunchOptions.test.ts | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'tests/steamLaunchOptions.test.ts') diff --git a/tests/steamLaunchOptions.test.ts b/tests/steamLaunchOptions.test.ts index 215e3f7..456d9d0 100644 --- a/tests/steamLaunchOptions.test.ts +++ b/tests/steamLaunchOptions.test.ts @@ -37,10 +37,6 @@ test("normalizes blank and argument-only fields while refusing ambiguous launche options: `FOO=bar ${wrapper} %command% --windowed`, commandTokenAdded: true, }); - assert.deepEqual(installWrapperLaunchOption('FOO=bar "/home/deck/game.AppImage"', wrapper, true), { - options: 'FOO=bar ~/.lsfg %command% "/home/deck/game.AppImage"', - commandTokenAdded: true, - }); assert.throws(() => installWrapperLaunchOption("gamemoderun --windowed", wrapper), /refusing to guess/); assert.throws(() => installWrapperLaunchOption('"%command%"', wrapper), /refusing to guess/); }); @@ -126,11 +122,11 @@ test("reads the matching app-details field and installs/removes Steam integratio assert.equal(appWrites.length, 1); assert.equal(shortcutWrites.length, 0); - const shortcut = await installWrapperIntegration(43, true, wrapper, false, "flatpak"); + const shortcut = await installWrapperIntegration(43, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }); assert.equal(shortcut.originalExecutable, "/usr/bin/example-game"); assert.equal(shortcut.snapshot.target, wrapper); assert.deepEqual(targetWrites, [wrapper]); - const restored = await removeWrapperIntegration(43, true, wrapper, shortcut.originalExecutable, false, "flatpak"); + const restored = await removeWrapperIntegration(43, true, wrapper, shortcut.originalExecutable, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }); assert.equal(restored.target, "/usr/bin/example-game"); assert.deepEqual(targetWrites, [wrapper, "/usr/bin/example-game"]); assert.equal(shortcutWrites.length, 0); @@ -172,18 +168,18 @@ test("uses shortcut launch options for a host shortcut without changing its Targ (globalThis as Record).window = { setTimeout, clearTimeout }; (globalThis as Record).SteamClient = { Apps: apps }; try { - const installed = await installWrapperIntegration(44, true, wrapper, false, "host"); + const installed = await installWrapperIntegration(44, true, wrapper, false, { kind: "host" }); assert.equal(installed.originalExecutable, undefined); assert.equal(installed.snapshot.target, "env"); assert.equal(installed.snapshot.options, 'DESKTOPINTEGRATION=1 ~/.lsfg %command% "/home/deck/AppImages/dusk.appimage"'); assert.deepEqual(targetWrites, []); assert.deepEqual(shortcutWrites, [installed.snapshot.options]); - const secondInstall = await installWrapperIntegration(44, true, wrapper, false, "host"); + const secondInstall = await installWrapperIntegration(44, true, wrapper, false, { kind: "host" }); assert.equal(secondInstall.snapshot.options, installed.snapshot.options); assert.deepEqual(shortcutWrites, [installed.snapshot.options]); - const restored = await removeWrapperIntegration(44, true, wrapper, undefined, installed.commandTokenAdded, "host"); + const restored = await removeWrapperIntegration(44, true, wrapper, undefined, installed.commandTokenAdded, { kind: "host" }); assert.equal(restored.target, "env"); assert.equal(restored.options, originalOptions); assert.deepEqual(targetWrites, []); @@ -208,8 +204,8 @@ test("fails closed when shortcut Target ownership or setters are unavailable", a }, }; try { - await assert.rejects(installWrapperIntegration(99, true, wrapper, false, "flatpak"), /Target API is unavailable/); - await assert.rejects(removeWrapperIntegration(99, true, wrapper, "/usr/bin/original", false, "flatpak"), /Target changed externally/); + await assert.rejects(installWrapperIntegration(99, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /Target API is unavailable/); + await assert.rejects(removeWrapperIntegration(99, true, wrapper, "/usr/bin/original", false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /Target changed externally/); } finally { if (previousWindow === undefined) delete (globalThis as Record).window; else (globalThis as Record).window = previousWindow; @@ -250,7 +246,7 @@ test("restores launch options and shortcut Target when a setter fails after chan assert.equal(appOptions, "FOO=bar %command%"); assert.deepEqual(appWrites, [`FOO=bar ${wrapper} %command%`, "FOO=bar %command%"]); - await assert.rejects(installWrapperIntegration(43, true, wrapper, false, "flatpak"), /simulated Target write failure/); + await assert.rejects(installWrapperIntegration(43, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /simulated Target write failure/); assert.equal(shortcutTarget, "/usr/bin/original"); assert.deepEqual(targetWrites, [wrapper, "/usr/bin/original"]); } finally { -- cgit v1.2.3 From 9902135e53be129bd6096d51d5e510ab298c1ae2 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Thu, 10 Sep 2026 12:19:40 -0400 Subject: fix: handle bare Flatpak shortcut targets --- tests/steamLaunchOptions.test.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'tests/steamLaunchOptions.test.ts') diff --git a/tests/steamLaunchOptions.test.ts b/tests/steamLaunchOptions.test.ts index 456d9d0..c799907 100644 --- a/tests/steamLaunchOptions.test.ts +++ b/tests/steamLaunchOptions.test.ts @@ -83,7 +83,7 @@ test("reads the matching app-details field and installs/removes Steam integratio const previousSteamClient = (globalThis as Record).SteamClient; let appOptions = "FOO=bar %command%"; let shortcutOptions = "--windowed"; - let shortcutTarget = "/usr/bin/example-game"; + let shortcutTarget = '"flatpak"'; const appWrites: string[] = []; const shortcutWrites: string[] = []; const targetWrites: string[] = []; @@ -123,12 +123,12 @@ test("reads the matching app-details field and installs/removes Steam integratio assert.equal(shortcutWrites.length, 0); const shortcut = await installWrapperIntegration(43, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }); - assert.equal(shortcut.originalExecutable, "/usr/bin/example-game"); + assert.equal(shortcut.originalExecutable, "/usr/bin/flatpak"); assert.equal(shortcut.snapshot.target, wrapper); assert.deepEqual(targetWrites, [wrapper]); const restored = await removeWrapperIntegration(43, true, wrapper, shortcut.originalExecutable, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }); - assert.equal(restored.target, "/usr/bin/example-game"); - assert.deepEqual(targetWrites, [wrapper, "/usr/bin/example-game"]); + assert.equal(restored.target, "/usr/bin/flatpak"); + assert.deepEqual(targetWrites, [wrapper, "/usr/bin/flatpak"]); assert.equal(shortcutWrites.length, 0); const cleaned = await removeWrapperIntegration(42, false, wrapper, undefined, installed.commandTokenAdded); @@ -198,12 +198,13 @@ test("fails closed when shortcut Target ownership or setters are unavailable", a (globalThis as Record).SteamClient = { Apps: { RegisterForAppDetails(_appId: number, callback: (details: SteamAppDetails) => void) { - callback({ strShortcutExe: "/usr/bin/other", strShortcutLaunchOptions: "" }); + callback({ strShortcutExe: _appId === 99 ? "/usr/bin/flatpak" : "garbage", strShortcutLaunchOptions: "" }); return { unregister() {} }; }, }, }; try { + await assert.rejects(installWrapperIntegration(98, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /supported executable/); await assert.rejects(installWrapperIntegration(99, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /Target API is unavailable/); await assert.rejects(removeWrapperIntegration(99, true, wrapper, "/usr/bin/original", false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /Target changed externally/); } finally { @@ -218,7 +219,7 @@ test("restores launch options and shortcut Target when a setter fails after chan const previousWindow = (globalThis as Record).window; const previousSteamClient = (globalThis as Record).SteamClient; let appOptions = "FOO=bar %command%"; - let shortcutTarget = "/usr/bin/original"; + let shortcutTarget = "/usr/bin/flatpak"; const appWrites: string[] = []; const targetWrites: string[] = []; const apps = { @@ -247,8 +248,8 @@ test("restores launch options and shortcut Target when a setter fails after chan assert.deepEqual(appWrites, [`FOO=bar ${wrapper} %command%`, "FOO=bar %command%"]); await assert.rejects(installWrapperIntegration(43, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /simulated Target write failure/); - assert.equal(shortcutTarget, "/usr/bin/original"); - assert.deepEqual(targetWrites, [wrapper, "/usr/bin/original"]); + assert.equal(shortcutTarget, "/usr/bin/flatpak"); + assert.deepEqual(targetWrites, [wrapper, "/usr/bin/flatpak"]); } finally { if (previousWindow === undefined) delete (globalThis as Record).window; else (globalThis as Record).window = previousWindow; -- cgit v1.2.3 From 92cffa96763448b83d5e762020631e3346d6e9da Mon Sep 17 00:00:00 2001 From: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Date: Thu, 10 Sep 2026 15:49:29 -0400 Subject: test: cover explicit direct flatpak target integration --- tests/steamLaunchOptions.test.ts | 177 ++++++++++++++++----------------------- 1 file changed, 74 insertions(+), 103 deletions(-) (limited to 'tests/steamLaunchOptions.test.ts') diff --git a/tests/steamLaunchOptions.test.ts b/tests/steamLaunchOptions.test.ts index c799907..93d37df 100644 --- a/tests/steamLaunchOptions.test.ts +++ b/tests/steamLaunchOptions.test.ts @@ -28,7 +28,7 @@ test("inserts one wrapper immediately before an existing command macro", () => { }); }); -test("normalizes blank and argument-only fields while refusing ambiguous launchers", () => { +test("normalizes blank and argument-only shortcut fields", () => { assert.deepEqual(installWrapperLaunchOption("", wrapper), { options: `${wrapper} %command%`, commandTokenAdded: true, @@ -41,7 +41,7 @@ test("normalizes blank and argument-only fields while refusing ambiguous launche assert.throws(() => installWrapperLaunchOption('"%command%"', wrapper), /refusing to guess/); }); -test("preserves assignments, quoting, suffixes, and unrelated values", () => { +test("preserves assignments quoting suffixes and released wrapper cleanup", () => { const options = 'FOO="hello world" VK_INSTANCE_LAYERS="one:two" gamemoderun %command% --flag "two words"'; assert.equal( installWrapperLaunchOption(options, wrapper).options, @@ -49,36 +49,28 @@ test("preserves assignments, quoting, suffixes, and unrelated values", () => { ); assert.equal(removeWrapperLaunchOption(`${wrapper} %command% --arg "${wrapper}"`, wrapper, true), `--arg "${wrapper}"`); assert.equal(normalizeLaunchOptions(" FOO=bar %COMMAND% --flag "), "FOO=bar %COMMAND% --flag"); -}); - -test("cleans current, legacy, and bare Mako wrappers without touching suffix arguments", () => { for (const token of ["~/lsfg", "/home/deck/lsfg", "mako-run", "mako-launch"]) { assert.equal(cleanupLegacyWrapper(`FOO=bar ${token} %command% --arg "${token}"`), `FOO=bar %command% --arg "${token}"`); } - assert.equal(cleanupLegacyWrapper(`FOO=bar ${wrapper} %command%`), "FOO=bar %command%"); assert.equal(isLegacyWrapperToken("/home/kurt/lsfg"), true); assert.equal(isLegacyWrapperToken("/opt/tools/lsfg"), false); - assert.equal(removeWrapperLaunchOption(`FOO=bar ${wrapper} %command% --arg`, wrapper), "FOO=bar %command% --arg"); }); -test("removes only old plugin assignments and preserves DXVK settings", () => { +test("removes only managed assignments and preserves unrelated values", () => { assert.equal( cleanupPluginAssignments( 'FOO="keep this" ENABLE_GAMESCOPE_WSI=0 DXVK_HDR=0 SteamDeck=0 DISABLE_VKBASALT=1 MESA_LOADER_DRIVER_OVERRIDE=zink DXVK_CONFIG="dxgi.syncInterval = 0; dxvk.maxFrameRate = 30" %command%', ), 'FOO="keep this" DXVK_CONFIG="dxgi.syncInterval = 0" %command%', ); - assert.equal( - cleanupPluginLaunchOptions(`DXVK_FRAME_RATE=30 ${wrapper} %command%`, wrapper), - "%command%", - ); + assert.equal(cleanupPluginLaunchOptions(`DXVK_FRAME_RATE=30 ${wrapper} %command%`, wrapper), "%command%"); assert.equal( cleanupPluginAssignments("PROTON_USE_WOW64=1 MANGOHUD=1 MANGOHUD_CONFIG=alpha %command%"), "PROTON_USE_WOW64=1 MANGOHUD=1 MANGOHUD_CONFIG=alpha %command%", ); }); -test("reads the matching app-details field and installs/removes Steam integration", async () => { +test("uses launch options for Steam and MAKO-style Target wrapping for direct Flatpak", async () => { const previousWindow = (globalThis as Record).window; const previousSteamClient = (globalThis as Record).SteamClient; let appOptions = "FOO=bar %command%"; @@ -120,18 +112,22 @@ test("reads the matching app-details field and installs/removes Steam integratio assert.equal(installed.snapshot.options, `FOO=bar ${wrapper} %command%`.replaceAll(" ", " ")); assert.equal(installed.commandTokenAdded, false); assert.equal(appWrites.length, 1); - assert.equal(shortcutWrites.length, 0); - const shortcut = await installWrapperIntegration(43, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }); - assert.equal(shortcut.originalExecutable, "/usr/bin/flatpak"); - assert.equal(shortcut.snapshot.target, wrapper); - assert.deepEqual(targetWrites, [wrapper]); - const restored = await removeWrapperIntegration(43, true, wrapper, shortcut.originalExecutable, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }); + const shortcut = await installWrapperIntegration(43, true, wrapper, false, true); + assert.equal(shortcut.snapshot.target, '~/.lsfg "/usr/bin/flatpak"'); + assert.deepEqual(targetWrites, ['~/.lsfg "/usr/bin/flatpak"']); + assert.equal(shortcut.snapshot.options, "--windowed"); + assert.deepEqual(shortcutWrites, []); + + const second = await installWrapperIntegration(43, true, wrapper, false, true); + assert.equal(second.changed, false); + assert.deepEqual(targetWrites, ['~/.lsfg "/usr/bin/flatpak"']); + + const restored = await removeWrapperIntegration(43, true, wrapper, false, true); assert.equal(restored.target, "/usr/bin/flatpak"); - assert.deepEqual(targetWrites, [wrapper, "/usr/bin/flatpak"]); - assert.equal(shortcutWrites.length, 0); + assert.deepEqual(targetWrites, ['~/.lsfg "/usr/bin/flatpak"', "/usr/bin/flatpak"]); - const cleaned = await removeWrapperIntegration(42, false, wrapper, undefined, installed.commandTokenAdded); + const cleaned = await removeWrapperIntegration(42, false, wrapper, installed.commandTokenAdded); assert.equal(cleaned.options, "FOO=bar %command%".replaceAll(" ", " ")); assert.ok(unregisters.includes(42)); assert.ok(unregisters.includes(43)); @@ -143,46 +139,54 @@ test("reads the matching app-details field and installs/removes Steam integratio } }); -test("uses shortcut launch options for a host shortcut without changing its Target", async () => { +test("AppImage and EmuDeck script shortcuts stay launch-option based", async () => { const previousWindow = (globalThis as Record).window; const previousSteamClient = (globalThis as Record).SteamClient; - const originalOptions = 'DESKTOPINTEGRATION=1 "/home/deck/AppImages/dusk.appimage"'; - let shortcutOptions = originalOptions; - let shortcutTarget = "env"; - const shortcutWrites: string[] = []; - const targetWrites: string[] = []; - const apps = { - RegisterForAppDetails(_appId: number, callback: (details: SteamAppDetails) => void) { - callback({ strShortcutExe: shortcutTarget, strShortcutLaunchOptions: shortcutOptions }); - return { unregister() {} }; + const cases = [ + { + target: "env", + options: 'DESKTOPINTEGRATION=1 "/home/deck/AppImages/dusk.appimage"', + expected: 'DESKTOPINTEGRATION=1 ~/.lsfg %command% "/home/deck/AppImages/dusk.appimage"', }, - SetShortcutLaunchOptions(_appId: number, options: string) { - shortcutWrites.push(options); - shortcutOptions = options; + { + target: '"/home/deck/Emulation/tools/launchers/retroarch.sh" -L core rom.z64', + options: "", + expected: "~/.lsfg %command%", }, - SetShortcutExe(_appId: number, executable: string) { - targetWrites.push(executable); - shortcutTarget = executable; - }, - }; + ]; (globalThis as Record).window = { setTimeout, clearTimeout }; - (globalThis as Record).SteamClient = { Apps: apps }; try { - const installed = await installWrapperIntegration(44, true, wrapper, false, { kind: "host" }); - assert.equal(installed.originalExecutable, undefined); - assert.equal(installed.snapshot.target, "env"); - assert.equal(installed.snapshot.options, 'DESKTOPINTEGRATION=1 ~/.lsfg %command% "/home/deck/AppImages/dusk.appimage"'); - assert.deepEqual(targetWrites, []); - assert.deepEqual(shortcutWrites, [installed.snapshot.options]); - - const secondInstall = await installWrapperIntegration(44, true, wrapper, false, { kind: "host" }); - assert.equal(secondInstall.snapshot.options, installed.snapshot.options); - assert.deepEqual(shortcutWrites, [installed.snapshot.options]); - - const restored = await removeWrapperIntegration(44, true, wrapper, undefined, installed.commandTokenAdded, { kind: "host" }); - assert.equal(restored.target, "env"); - assert.equal(restored.options, originalOptions); - assert.deepEqual(targetWrites, []); + for (const [index, item] of cases.entries()) { + let shortcutTarget = item.target; + let shortcutOptions = item.options; + const targetWrites: string[] = []; + const shortcutWrites: string[] = []; + (globalThis as Record).SteamClient = { + Apps: { + RegisterForAppDetails(_appId: number, callback: (details: SteamAppDetails) => void) { + callback({ strShortcutExe: shortcutTarget, strShortcutLaunchOptions: shortcutOptions }); + return { unregister() {} }; + }, + SetShortcutLaunchOptions(_appId: number, options: string) { + shortcutWrites.push(options); + shortcutOptions = options; + }, + SetShortcutExe(_appId: number, executable: string) { + targetWrites.push(executable); + shortcutTarget = executable; + }, + }, + }; + const installed = await installWrapperIntegration(100 + index, true, wrapper, false, false); + assert.equal(installed.snapshot.target, item.target); + assert.equal(installed.snapshot.options, item.expected); + assert.deepEqual(targetWrites, []); + assert.deepEqual(shortcutWrites, [item.expected]); + const restored = await removeWrapperIntegration(100 + index, true, wrapper, installed.commandTokenAdded, false); + assert.equal(restored.target, item.target); + assert.equal(restored.options, item.options); + assert.deepEqual(targetWrites, []); + } } finally { if (previousWindow === undefined) delete (globalThis as Record).window; else (globalThis as Record).window = previousWindow; @@ -191,65 +195,32 @@ test("uses shortcut launch options for a host shortcut without changing its Targ } }); -test("fails closed when shortcut Target ownership or setters are unavailable", async () => { +test("direct Flatpak fails closed and rolls Target writes back", async () => { const previousWindow = (globalThis as Record).window; const previousSteamClient = (globalThis as Record).SteamClient; + let shortcutTarget = "/usr/bin/flatpak"; + const targetWrites: string[] = []; (globalThis as Record).window = { setTimeout, clearTimeout }; (globalThis as Record).SteamClient = { Apps: { RegisterForAppDetails(_appId: number, callback: (details: SteamAppDetails) => void) { - callback({ strShortcutExe: _appId === 99 ? "/usr/bin/flatpak" : "garbage", strShortcutLaunchOptions: "" }); + callback({ strShortcutExe: shortcutTarget, strShortcutLaunchOptions: "" }); return { unregister() {} }; }, + SetShortcutExe(_appId: number, executable: string) { + targetWrites.push(executable); + shortcutTarget = executable; + if (executable.startsWith(wrapper)) throw new Error("simulated Target write failure"); + }, }, }; try { - await assert.rejects(installWrapperIntegration(98, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /supported executable/); - await assert.rejects(installWrapperIntegration(99, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /Target API is unavailable/); - await assert.rejects(removeWrapperIntegration(99, true, wrapper, "/usr/bin/original", false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /Target changed externally/); - } finally { - if (previousWindow === undefined) delete (globalThis as Record).window; - else (globalThis as Record).window = previousWindow; - if (previousSteamClient === undefined) delete (globalThis as Record).SteamClient; - else (globalThis as Record).SteamClient = previousSteamClient; - } -}); - -test("restores launch options and shortcut Target when a setter fails after changing them", async () => { - const previousWindow = (globalThis as Record).window; - const previousSteamClient = (globalThis as Record).SteamClient; - let appOptions = "FOO=bar %command%"; - let shortcutTarget = "/usr/bin/flatpak"; - const appWrites: string[] = []; - const targetWrites: string[] = []; - const apps = { - RegisterForAppDetails(appId: number, callback: (details: SteamAppDetails) => void) { - callback(appId === 42 - ? { strLaunchOptions: appOptions } - : { strShortcutExe: shortcutTarget, strShortcutLaunchOptions: "" }); - return { unregister() {} }; - }, - SetAppLaunchOptions(_appId: number, options: string) { - appWrites.push(options); - appOptions = options; - if (options.includes(wrapper)) throw new Error("simulated launch-option write failure"); - }, - SetShortcutExe(_appId: number, executable: string) { - targetWrites.push(executable); - shortcutTarget = executable; - if (executable === wrapper) throw new Error("simulated Target write failure"); - }, - }; - (globalThis as Record).window = { setTimeout, clearTimeout }; - (globalThis as Record).SteamClient = { Apps: apps }; - try { - await assert.rejects(installWrapperIntegration(42, false, wrapper), /simulated launch-option write failure/); - assert.equal(appOptions, "FOO=bar %command%"); - assert.deepEqual(appWrites, [`FOO=bar ${wrapper} %command%`, "FOO=bar %command%"]); - - await assert.rejects(installWrapperIntegration(43, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /simulated Target write failure/); + await assert.rejects(installWrapperIntegration(43, true, wrapper, false, true), /simulated Target write failure/); assert.equal(shortcutTarget, "/usr/bin/flatpak"); - assert.deepEqual(targetWrites, [wrapper, "/usr/bin/flatpak"]); + assert.deepEqual(targetWrites, ['~/.lsfg "/usr/bin/flatpak"', "/usr/bin/flatpak"]); + + shortcutTarget = "garbage"; + await assert.rejects(installWrapperIntegration(43, true, wrapper, false, true), /supported direct Flatpak/); } finally { if (previousWindow === undefined) delete (globalThis as Record).window; else (globalThis as Record).window = previousWindow; -- cgit v1.2.3 From af7202363bbe4ec5c3d40197cf88c306fa06ee46 Mon Sep 17 00:00:00 2001 From: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Date: Thu, 10 Sep 2026 16:40:50 -0400 Subject: test: cover launch-options-only steam integration --- tests/steamLaunchOptions.test.ts | 77 ++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 51 deletions(-) (limited to 'tests/steamLaunchOptions.test.ts') diff --git a/tests/steamLaunchOptions.test.ts b/tests/steamLaunchOptions.test.ts index 93d37df..40aeb3c 100644 --- a/tests/steamLaunchOptions.test.ts +++ b/tests/steamLaunchOptions.test.ts @@ -70,21 +70,19 @@ test("removes only managed assignments and preserves unrelated values", () => { ); }); -test("uses launch options for Steam and MAKO-style Target wrapping for direct Flatpak", async () => { +test("uses launch options for Steam and non-Steam shortcuts without a Target API", async () => { const previousWindow = (globalThis as Record).window; const previousSteamClient = (globalThis as Record).SteamClient; let appOptions = "FOO=bar %command%"; let shortcutOptions = "--windowed"; - let shortcutTarget = '"flatpak"'; const appWrites: string[] = []; const shortcutWrites: string[] = []; - const targetWrites: string[] = []; const unregisters: number[] = []; const apps = { RegisterForAppDetails(appId: number, callback: (details: SteamAppDetails) => void) { callback(appId === 42 ? { strLaunchOptions: appOptions, strShortcutLaunchOptions: "wrong-field" } - : { strShortcutExe: shortcutTarget, strShortcutLaunchOptions: shortcutOptions, strLaunchOptions: "wrong-field" }); + : { strShortcutLaunchOptions: shortcutOptions, strLaunchOptions: "wrong-field" }); return { unregister: () => unregisters.push(appId) }; }, SetAppLaunchOptions(appId: number, options: string) { @@ -97,11 +95,6 @@ test("uses launch options for Steam and MAKO-style Target wrapping for direct Fl shortcutWrites.push(options); shortcutOptions = options; }, - SetShortcutExe(appId: number, executable: string) { - assert.equal(appId, 43); - targetWrites.push(executable); - shortcutTarget = executable; - }, }; (globalThis as Record).window = { setTimeout, clearTimeout }; (globalThis as Record).SteamClient = { Apps: apps }; @@ -113,19 +106,12 @@ test("uses launch options for Steam and MAKO-style Target wrapping for direct Fl assert.equal(installed.commandTokenAdded, false); assert.equal(appWrites.length, 1); - const shortcut = await installWrapperIntegration(43, true, wrapper, false, true); - assert.equal(shortcut.snapshot.target, '~/.lsfg "/usr/bin/flatpak"'); - assert.deepEqual(targetWrites, ['~/.lsfg "/usr/bin/flatpak"']); - assert.equal(shortcut.snapshot.options, "--windowed"); - assert.deepEqual(shortcutWrites, []); + const shortcut = await installWrapperIntegration(43, true, wrapper); + assert.equal(shortcut.snapshot.options, `~/.lsfg %command% --windowed`); + assert.deepEqual(shortcutWrites, [`~/.lsfg %command% --windowed`]); - const second = await installWrapperIntegration(43, true, wrapper, false, true); - assert.equal(second.changed, false); - assert.deepEqual(targetWrites, ['~/.lsfg "/usr/bin/flatpak"']); - - const restored = await removeWrapperIntegration(43, true, wrapper, false, true); - assert.equal(restored.target, "/usr/bin/flatpak"); - assert.deepEqual(targetWrites, ['~/.lsfg "/usr/bin/flatpak"', "/usr/bin/flatpak"]); + const restored = await removeWrapperIntegration(43, true, wrapper, shortcut.commandTokenAdded); + assert.equal(restored.options, "--windowed"); const cleaned = await removeWrapperIntegration(42, false, wrapper, installed.commandTokenAdded); assert.equal(cleaned.options, "FOO=bar %command%".replaceAll(" ", " ")); @@ -139,53 +125,45 @@ test("uses launch options for Steam and MAKO-style Target wrapping for direct Fl } }); -test("AppImage and EmuDeck script shortcuts stay launch-option based", async () => { +test("AppImage EmuDeck and direct Flatpak shortcuts all stay launch-option based", async () => { const previousWindow = (globalThis as Record).window; const previousSteamClient = (globalThis as Record).SteamClient; const cases = [ { - target: "env", options: 'DESKTOPINTEGRATION=1 "/home/deck/AppImages/dusk.appimage"', expected: 'DESKTOPINTEGRATION=1 ~/.lsfg %command% "/home/deck/AppImages/dusk.appimage"', }, { - target: '"/home/deck/Emulation/tools/launchers/retroarch.sh" -L core rom.z64', options: "", expected: "~/.lsfg %command%", }, + { + options: "run org.example.Game", + expected: "~/.lsfg %command% run org.example.Game", + }, ]; (globalThis as Record).window = { setTimeout, clearTimeout }; try { for (const [index, item] of cases.entries()) { - let shortcutTarget = item.target; let shortcutOptions = item.options; - const targetWrites: string[] = []; const shortcutWrites: string[] = []; (globalThis as Record).SteamClient = { Apps: { RegisterForAppDetails(_appId: number, callback: (details: SteamAppDetails) => void) { - callback({ strShortcutExe: shortcutTarget, strShortcutLaunchOptions: shortcutOptions }); + callback({ strShortcutLaunchOptions: shortcutOptions }); return { unregister() {} }; }, SetShortcutLaunchOptions(_appId: number, options: string) { shortcutWrites.push(options); shortcutOptions = options; }, - SetShortcutExe(_appId: number, executable: string) { - targetWrites.push(executable); - shortcutTarget = executable; - }, }, }; - const installed = await installWrapperIntegration(100 + index, true, wrapper, false, false); - assert.equal(installed.snapshot.target, item.target); + const installed = await installWrapperIntegration(100 + index, true, wrapper); assert.equal(installed.snapshot.options, item.expected); - assert.deepEqual(targetWrites, []); assert.deepEqual(shortcutWrites, [item.expected]); - const restored = await removeWrapperIntegration(100 + index, true, wrapper, installed.commandTokenAdded, false); - assert.equal(restored.target, item.target); + const restored = await removeWrapperIntegration(100 + index, true, wrapper, installed.commandTokenAdded); assert.equal(restored.options, item.options); - assert.deepEqual(targetWrites, []); } } finally { if (previousWindow === undefined) delete (globalThis as Record).window; @@ -195,32 +173,29 @@ test("AppImage and EmuDeck script shortcuts stay launch-option based", async () } }); -test("direct Flatpak fails closed and rolls Target writes back", async () => { +test("launch option write failure rolls back the original value", async () => { const previousWindow = (globalThis as Record).window; const previousSteamClient = (globalThis as Record).SteamClient; - let shortcutTarget = "/usr/bin/flatpak"; - const targetWrites: string[] = []; + let appOptions = "FOO=bar %command%"; + const writes: string[] = []; (globalThis as Record).window = { setTimeout, clearTimeout }; (globalThis as Record).SteamClient = { Apps: { RegisterForAppDetails(_appId: number, callback: (details: SteamAppDetails) => void) { - callback({ strShortcutExe: shortcutTarget, strShortcutLaunchOptions: "" }); + callback({ strLaunchOptions: appOptions }); return { unregister() {} }; }, - SetShortcutExe(_appId: number, executable: string) { - targetWrites.push(executable); - shortcutTarget = executable; - if (executable.startsWith(wrapper)) throw new Error("simulated Target write failure"); + SetAppLaunchOptions(_appId: number, options: string) { + writes.push(options); + appOptions = options; + if (options.includes(wrapper)) throw new Error("simulated launch option failure"); }, }, }; try { - await assert.rejects(installWrapperIntegration(43, true, wrapper, false, true), /simulated Target write failure/); - assert.equal(shortcutTarget, "/usr/bin/flatpak"); - assert.deepEqual(targetWrites, ['~/.lsfg "/usr/bin/flatpak"', "/usr/bin/flatpak"]); - - shortcutTarget = "garbage"; - await assert.rejects(installWrapperIntegration(43, true, wrapper, false, true), /supported direct Flatpak/); + await assert.rejects(installWrapperIntegration(42, false, wrapper), /simulated launch option failure/); + assert.equal(appOptions, "FOO=bar %command%"); + assert.deepEqual(writes, [`FOO=bar ${wrapper} %command%`, "FOO=bar %command%"]); } finally { if (previousWindow === undefined) delete (globalThis as Record).window; else (globalThis as Record).window = previousWindow; -- cgit v1.2.3 From 81feb03288166755545401b9df2ff2c9bc3ae7d7 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Fri, 11 Sep 2026 16:48:35 -0400 Subject: handle flatpak grey, id proton and exclusions --- tests/steamLaunchOptions.test.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'tests/steamLaunchOptions.test.ts') diff --git a/tests/steamLaunchOptions.test.ts b/tests/steamLaunchOptions.test.ts index 40aeb3c..1d2f762 100644 --- a/tests/steamLaunchOptions.test.ts +++ b/tests/steamLaunchOptions.test.ts @@ -28,7 +28,7 @@ test("inserts one wrapper immediately before an existing command macro", () => { }); }); -test("normalizes blank and argument-only shortcut fields", () => { +test("normalizes blank, malformed, and argument-only launch fields", () => { assert.deepEqual(installWrapperLaunchOption("", wrapper), { options: `${wrapper} %command%`, commandTokenAdded: true, @@ -37,8 +37,22 @@ test("normalizes blank and argument-only shortcut fields", () => { options: `FOO=bar ${wrapper} %command% --windowed`, commandTokenAdded: true, }); - assert.throws(() => installWrapperLaunchOption("gamemoderun --windowed", wrapper), /refusing to guess/); - assert.throws(() => installWrapperLaunchOption('"%command%"', wrapper), /refusing to guess/); + assert.deepEqual(installWrapperLaunchOption("gamemoderun --windowed", wrapper), { + options: `${wrapper} %command% gamemoderun --windowed`, + commandTokenAdded: true, + }); + assert.deepEqual(installWrapperLaunchOption('"%command%"', wrapper), { + options: `${wrapper} %command%`, + commandTokenAdded: false, + }); + assert.deepEqual(installWrapperLaunchOption(`${wrapper} %command`, wrapper), { + options: `${wrapper} %command%`, + commandTokenAdded: false, + }); + assert.deepEqual(installWrapperLaunchOption(`${wrapper} --windowed`, wrapper), { + options: `${wrapper} %command% --windowed`, + commandTokenAdded: true, + }); }); test("preserves assignments quoting suffixes and released wrapper cleanup", () => { -- cgit v1.2.3