feat(FN-2611): merge fusion/fn-2611 (auto-resolved)
- feat(FN-2611): complete Step 4 — add changeset and docs - test(FN-2611): complete Step 2 — cover legacy alias cleanup payload - feat(FN-2611): complete Step 1 — normalize legacy experimental aliases
This commit is contained in:
5
.changeset/fix-dev-server-experimental-toggle.md
Normal file
5
.changeset/fix-dev-server-experimental-toggle.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@runfusion/fusion": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix experimental feature save normalization so disabling Dev Server clears the legacy `devServer` alias (`null` delete) alongside canonical `devServerView`, preventing stale nav visibility after save.
|
||||||
@@ -126,16 +126,22 @@ function isExperimentalFeatureEnabled(features: Record<string, boolean>, key: st
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeExperimentalFeaturesForSave(features?: Record<string, boolean>): Record<string, boolean> {
|
function normalizeExperimentalFeaturesForSave(features?: Record<string, boolean>): Record<string, boolean | null> {
|
||||||
if (!features) {
|
if (!features) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalized: Record<string, boolean> = {};
|
const normalized: Record<string, boolean | null> = {};
|
||||||
for (const [key, enabled] of Object.entries(features)) {
|
for (const [key, enabled] of Object.entries(features)) {
|
||||||
normalized[getCanonicalExperimentalFeatureKey(key)] = enabled;
|
normalized[getCanonicalExperimentalFeatureKey(key)] = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const [legacyKey, canonicalKey] of Object.entries(EXPERIMENTAL_FEATURE_LEGACY_ALIASES)) {
|
||||||
|
if (normalized[canonicalKey] !== undefined && !(legacyKey in normalized)) {
|
||||||
|
normalized[legacyKey] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1191,7 +1191,7 @@ describe("SettingsModal", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("normalizes legacy devServer flag to canonical devServerView on save", async () => {
|
it("sends canonical devServerView=false and devServer=null when disabling legacy dev server flag", async () => {
|
||||||
mockFetchSettings.mockResolvedValue({
|
mockFetchSettings.mockResolvedValue({
|
||||||
...defaultSettings,
|
...defaultSettings,
|
||||||
experimentalFeatures: { devServer: true },
|
experimentalFeatures: { devServer: true },
|
||||||
@@ -1204,6 +1204,9 @@ describe("SettingsModal", () => {
|
|||||||
const devServerToggle = screen.getByLabelText("Dev Server") as HTMLInputElement;
|
const devServerToggle = screen.getByLabelText("Dev Server") as HTMLInputElement;
|
||||||
expect(devServerToggle).toBeChecked();
|
expect(devServerToggle).toBeChecked();
|
||||||
|
|
||||||
|
await userEvent.click(devServerToggle);
|
||||||
|
expect(devServerToggle).not.toBeChecked();
|
||||||
|
|
||||||
await userEvent.click(screen.getByText("Save"));
|
await userEvent.click(screen.getByText("Save"));
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
@@ -1211,7 +1214,27 @@ describe("SettingsModal", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const payload = mockUpdateSettings.mock.calls[0][0];
|
const payload = mockUpdateSettings.mock.calls[0][0];
|
||||||
expect(payload.experimentalFeatures).toEqual({ devServerView: true });
|
expect(payload.experimentalFeatures).toEqual({ devServerView: false, devServer: null });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not emit legacy alias null deletes when canonical key is absent", async () => {
|
||||||
|
mockFetchSettings.mockResolvedValue({
|
||||||
|
...defaultSettings,
|
||||||
|
experimentalFeatures: { insights: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
renderModal();
|
||||||
|
|
||||||
|
await openExperimentalFeaturesSection();
|
||||||
|
|
||||||
|
await userEvent.click(screen.getByText("Save"));
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(mockUpdateSettings).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
const payload = mockUpdateSettings.mock.calls[0][0];
|
||||||
|
expect(payload.experimentalFeatures).toEqual({ insights: true });
|
||||||
expect(payload.experimentalFeatures.devServer).toBeUndefined();
|
expect(payload.experimentalFeatures.devServer).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user