Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { flushPromises, mount } from '@vue/test-utils';
import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils';

import { beforeEach, describe, expect, it, vi } from 'vitest';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

import type {
InternalBootApplyMessages,
Expand All @@ -11,6 +11,14 @@ import type {
import OnboardingInternalBootStandalone from '~/components/Onboarding/standalone/OnboardingInternalBoot.standalone.vue';
import { createTestI18n } from '../../utils/i18n';

const INTERNAL_BOOT_HISTORY_STATE_KEY = '__unraidOnboardingInternalBoot';

type InternalBootHistoryState = {
sessionId: string;
stepId: 'CONFIGURE_BOOT' | 'SUMMARY';
position: number;
};

const {
draftStore,
applyInternalBootSelectionMock,
Expand Down Expand Up @@ -129,10 +137,50 @@ const mountComponent = () =>
},
});

enableAutoUnmount(afterEach);

Comment on lines +140 to +141
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, check the test file structure and find it
fd "OnboardingInternalBootStandalone.test.ts" --type f

Repository: unraid/api

Length of output: 129


🏁 Script executed:

#!/bin/bash
# Read the test file to understand cleanup hooks and timer/mock usage
cat -n web/__test__/components/Onboarding/OnboardingInternalBootStandalone.test.ts | head -200

Repository: unraid/api

Length of output: 7495


🏁 Script executed:

#!/bin/bash
# Search for useFakeTimers, history mocking, and afterEach patterns in the file
rg "useFakeTimers|history\.go|afterEach|restoreAllMocks|clearAllMocks" web/__test__/components/Onboarding/OnboardingInternalBootStandalone.test.ts -n

Repository: unraid/api

Length of output: 219


🏁 Script executed:

#!/bin/bash
# Check for afterEach hooks and window.history.go stubbing
rg "afterEach|window\.history\.go|vi\.spyOn\(.*window\.history" web/__test__/components/Onboarding/OnboardingInternalBootStandalone.test.ts -A 3 -B 1

Repository: unraid/api

Length of output: 1403


🏁 Script executed:

#!/bin/bash
# Get the full test file to see all test cases and their setup
wc -l web/__test__/components/Onboarding/OnboardingInternalBootStandalone.test.ts

Repository: unraid/api

Length of output: 133


🏁 Script executed:

#!/bin/bash
# Read more of the file to see all test cases and whether there's history stubbing
tail -n +140 web/__test__/components/Onboarding/OnboardingInternalBootStandalone.test.ts | head -300

Repository: unraid/api

Length of output: 10146


Add explicit cleanup hook to restore spies and real timers between tests.

enableAutoUnmount(afterEach) only unmounts wrappers. Multiple tests create spies with vi.spyOn(window.history, 'go').mockImplementation(...) and vi.useFakeTimers() is set up in beforeEach, but neither are properly restored. vi.clearAllMocks() in beforeEach clears call history only; it does not restore spies or switch back to real timers, allowing the mocked History API and fake timers to leak into subsequent tests.

Suggested fix
 enableAutoUnmount(afterEach);
+
+afterEach(() => {
+  vi.restoreAllMocks();
+  vi.useRealTimers();
+});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/__test__/components/Onboarding/OnboardingInternalBootStandalone.test.ts`
around lines 140 - 141, Add an explicit cleanup hook to restore spies and timers
after each test: keep the existing enableAutoUnmount(afterEach) for unmounting,
and add an afterEach block that calls vi.restoreAllMocks() to restore any spies
(e.g., vi.spyOn(window.history, 'go')) and vi.useRealTimers() to revert
vi.useFakeTimers(), so mocks and fake timers do not leak between tests.

const getInternalBootHistoryState = (): InternalBootHistoryState | null => {
const state =
typeof window.history.state === 'object' && window.history.state !== null
? (window.history.state as Record<string, unknown>)
: null;
const candidate = state?.[INTERNAL_BOOT_HISTORY_STATE_KEY];
if (!candidate || typeof candidate !== 'object') {
return null;
}

const sessionId =
typeof (candidate as Record<string, unknown>).sessionId === 'string'
? (candidate as Record<string, unknown>).sessionId
: null;
const stepId =
(candidate as Record<string, unknown>).stepId === 'CONFIGURE_BOOT' ||
(candidate as Record<string, unknown>).stepId === 'SUMMARY'
? ((candidate as Record<string, unknown>).stepId as InternalBootHistoryState['stepId'])
: null;
const position = Number((candidate as Record<string, unknown>).position);

if (!sessionId || !stepId || !Number.isInteger(position)) {
return null;
}

return {
sessionId,
stepId,
position,
};
};
Comment on lines +142 to +172
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

fd -t f "OnboardingInternalBootStandalone.test.ts"

Repository: unraid/api

Length of output: 129


🏁 Script executed:

cat -n web/__test__/components/Onboarding/OnboardingInternalBootStandalone.test.ts | sed -n '130,180p'

Repository: unraid/api

Length of output: 1959


🏁 Script executed:

rg -t ts "interface InternalBootHistoryState|type InternalBootHistoryState" --context 5

Repository: unraid/api

Length of output: 1256


🏁 Script executed:

cat -n web/__test__/components/Onboarding/OnboardingInternalBootStandalone.test.ts | sed -n '1,30p'

Repository: unraid/api

Length of output: 1118


🏁 Script executed:

cat -n web/__test__/components/Onboarding/OnboardingInternalBootStandalone.test.ts | sed -n '179,210p'

Repository: unraid/api

Length of output: 1444


🏁 Script executed:

fd -t f "tsconfig" | head -5

Repository: unraid/api

Length of output: 276


🏁 Script executed:

cat web/tsconfig.json 2>/dev/null || cat api/tsconfig.json | head -40

Repository: unraid/api

Length of output: 869


🏁 Script executed:

python3 << 'EOF'
# Analyze the type narrowing behavior
code = """
const candidate: unknown = {};

// Current approach - repeated casts create separate expressions
const sessionId1 = 
  typeof (candidate as Record<string, unknown>).sessionId === 'string'
    ? (candidate as Record<string, unknown>).sessionId  // NEW expression, narrowing from line above doesn't apply
    : null;
// Type of sessionId1: unknown | null (NOT string | null)

// Fixed approach - single cast, single expression
const historyState = candidate as Record<string, unknown>;
const sessionId2 = 
  typeof historyState.sessionId === 'string'
    ? historyState.sessionId  // SAME expression, narrowing applies
    : null;
// Type of sessionId2: string | null
"""

print("Analysis of TypeScript narrowing:")
print("=" * 60)
print("\nThe issue is that repeated casts create separate expressions.")
print("Narrowing from a typeof check only applies to that specific")
print("expression, not to a later identical-looking cast.\n")
print("When sessionId is typed as unknown|null instead of string|null,")
print("the guard '!sessionId' narrows it to 'unknown', not 'string'.")
print("Then returning {sessionId} where sessionId: unknown to a function")
print("expecting sessionId: string causes TS2322 error.\n")
EOF

Repository: unraid/api

Length of output: 565


🏁 Script executed:

cat -n web/__test__/components/Onboarding/OnboardingInternalBootStandalone.test.ts | sed -n '380,430p'

Repository: unraid/api

Length of output: 2218


🏁 Script executed:

cat -n web/__test__/components/Onboarding/OnboardingInternalBootStandalone.test.ts | sed -n '460,480p'

Repository: unraid/api

Length of output: 1012


🏁 Script executed:

cat -n web/__test__/components/Onboarding/OnboardingInternalBootStandalone.test.ts | sed -n '180,196p'

Repository: unraid/api

Length of output: 679


🏁 Script executed:

cat -n web/__test__/components/Onboarding/OnboardingInternalBootStandalone.test.ts | tail -20

Repository: unraid/api

Length of output: 862


Fix TypeScript type narrowing in getInternalBootHistoryState().

Line 168 returns sessionId typed as unknown instead of string. The repeated casts at lines 153–154, 157–159, and 161 prevent narrowing from the typeof checks—each cast is a separate expression, so narrowing from a typeof guard doesn't apply to the next cast. Cache the cast in a single variable and reuse it.

Suggested fix
 const getInternalBootHistoryState = (): InternalBootHistoryState | null => {
   const state =
     typeof window.history.state === 'object' && window.history.state !== null
       ? (window.history.state as Record<string, unknown>)
       : null;
   const candidate = state?.[INTERNAL_BOOT_HISTORY_STATE_KEY];
   if (!candidate || typeof candidate !== 'object') {
     return null;
   }
+  const historyState = candidate as Record<string, unknown>;

   const sessionId =
-    typeof (candidate as Record<string, unknown>).sessionId === 'string'
-      ? (candidate as Record<string, unknown>).sessionId
+    typeof historyState.sessionId === 'string'
+      ? historyState.sessionId
       : null;
   const stepId =
-    (candidate as Record<string, unknown>).stepId === 'CONFIGURE_BOOT' ||
-    (candidate as Record<string, unknown>).stepId === 'SUMMARY'
-      ? ((candidate as Record<string, unknown>).stepId as InternalBootHistoryState['stepId'])
+    historyState.stepId === 'CONFIGURE_BOOT' || historyState.stepId === 'SUMMARY'
+      ? (historyState.stepId as InternalBootHistoryState['stepId'])
       : null;
-  const position = Number((candidate as Record<string, unknown>).position);
+  const position = Number(historyState.position);
🧰 Tools
🪛 GitHub Actions: CI - Main (API)

[error] 168-168: vue-tsc type-check failed (TS2322): Type '{}' is not assignable to type 'string'.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/__test__/components/Onboarding/OnboardingInternalBootStandalone.test.ts`
around lines 142 - 172, getInternalBootHistoryState currently re-casts
window.history.state candidate repeatedly which prevents TypeScript from
narrowing types (so sessionId ends up typed as unknown); after verifying
candidate exists, assign it once to a typed local (e.g., const candidateObj =
candidate as Record<string, unknown>) and then read sessionId, stepId and
position from candidateObj so the typeof checks correctly narrow sessionId to
string and stepId to the expected union; keep the existing guards (typeof
checks, specific stepId comparisons, Number.isInteger for position) and return
the InternalBootHistoryState object when all checks pass.


const dispatchPopstate = (state: Record<string, unknown> | null) => {
window.history.replaceState(state, '', window.location.href);
window.dispatchEvent(new PopStateEvent('popstate', { state }));
};

describe('OnboardingInternalBoot.standalone.vue', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.clearAllMocks();
window.history.replaceState(null, '', window.location.href);

draftStore.internalBootSelection = null;
draftStore.internalBootApplySucceeded = false;
Expand Down Expand Up @@ -182,8 +230,9 @@ describe('OnboardingInternalBoot.standalone.vue', () => {

expect(applyInternalBootSelectionMock).not.toHaveBeenCalled();
expect(draftStore.setInternalBootApplySucceeded).toHaveBeenCalledWith(false);
expect(wrapper.text()).toContain('Setup Applied');
expect(wrapper.text()).toContain('No settings changed. Skipping configuration mutations.');
expect(wrapper.text()).toContain('No Updates Needed');
expect(wrapper.text()).toContain('No changes needed. Skipping configuration updates.');
expect(wrapper.find('[data-testid="internal-boot-standalone-edit-again"]').exists()).toBe(true);
expect(stepperPropsRef.value).toMatchObject({
activeStepIndex: 1,
});
Expand Down Expand Up @@ -278,7 +327,69 @@ describe('OnboardingInternalBoot.standalone.vue', () => {
expect(wrapper.find('[data-testid="internal-boot-step-stub"]').exists()).toBe(true);
});

it('restores the configure step when browser back leaves a reversible result', async () => {
const wrapper = mountComponent();

await wrapper.get('[data-testid="internal-boot-step-complete"]').trigger('click');
await flushPromises();

const currentHistoryState = getInternalBootHistoryState();
expect(currentHistoryState).toMatchObject({
stepId: 'SUMMARY',
position: 1,
});

dispatchPopstate({
[INTERNAL_BOOT_HISTORY_STATE_KEY]: {
sessionId: currentHistoryState?.sessionId,
stepId: 'CONFIGURE_BOOT',
position: 0,
},
});
await flushPromises();
await wrapper.vm.$nextTick();

expect(stepperPropsRef.value).toMatchObject({
activeStepIndex: 0,
});
expect(wrapper.find('[data-testid="internal-boot-step-stub"]').exists()).toBe(true);
});

it('closes when browser back leaves a fully applied result', async () => {
draftStore.internalBootSelection = {
poolName: 'cache',
slotCount: 1,
devices: ['DISK-A'],
bootSizeMiB: 16384,
updateBios: true,
};

const wrapper = mountComponent();

await wrapper.get('[data-testid="internal-boot-step-complete"]').trigger('click');
await flushPromises();

const currentHistoryState = getInternalBootHistoryState();
expect(currentHistoryState).toMatchObject({
stepId: 'SUMMARY',
position: 1,
});

dispatchPopstate({
[INTERNAL_BOOT_HISTORY_STATE_KEY]: {
sessionId: currentHistoryState?.sessionId,
stepId: 'CONFIGURE_BOOT',
position: 0,
},
});
await flushPromises();

expect(cleanupOnboardingStorageMock).toHaveBeenCalledTimes(1);
expect(wrapper.find('[data-testid="dialog-stub"]').exists()).toBe(false);
});

it('closes locally after showing a result', async () => {
const historyGoSpy = vi.spyOn(window.history, 'go').mockImplementation(() => {});
const wrapper = mountComponent();

await wrapper.get('[data-testid="internal-boot-step-complete"]').trigger('click');
Expand All @@ -287,24 +398,38 @@ describe('OnboardingInternalBoot.standalone.vue', () => {
await wrapper.get('[data-testid="internal-boot-standalone-result-close"]').trigger('click');
await flushPromises();

expect(historyGoSpy).toHaveBeenCalledWith(-2);
dispatchPopstate(null);
await flushPromises();

expect(wrapper.find('[data-testid="internal-boot-standalone-result"]').exists()).toBe(false);
});

it('closes when the shared dialog requests dismissal', async () => {
const historyGoSpy = vi.spyOn(window.history, 'go').mockImplementation(() => {});
const wrapper = mountComponent();

await wrapper.get('[data-testid="dialog-dismiss"]').trigger('click');
await flushPromises();

expect(historyGoSpy).toHaveBeenCalledWith(-1);
dispatchPopstate(null);
await flushPromises();

expect(wrapper.find('[data-testid="dialog-stub"]').exists()).toBe(false);
});

it('closes via the top-right X button', async () => {
const historyGoSpy = vi.spyOn(window.history, 'go').mockImplementation(() => {});
const wrapper = mountComponent();

await wrapper.get('[data-testid="internal-boot-standalone-close"]').trigger('click');
await flushPromises();

expect(historyGoSpy).toHaveBeenCalledWith(-1);
dispatchPopstate(null);
await flushPromises();

expect(cleanupOnboardingStorageMock).toHaveBeenCalledTimes(1);
expect(wrapper.find('[data-testid="dialog-stub"]').exists()).toBe(false);
});
Expand Down Expand Up @@ -337,6 +462,7 @@ describe('OnboardingInternalBoot.standalone.vue', () => {
});

it('clears onboarding storage when closing after a successful result', async () => {
vi.spyOn(window.history, 'go').mockImplementation(() => {});
const wrapper = mountComponent();

await wrapper.get('[data-testid="internal-boot-step-complete"]').trigger('click');
Expand All @@ -347,6 +473,9 @@ describe('OnboardingInternalBoot.standalone.vue', () => {
await wrapper.get('[data-testid="internal-boot-standalone-result-close"]').trigger('click');
await flushPromises();

dispatchPopstate(null);
await flushPromises();

expect(cleanupOnboardingStorageMock).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -341,15 +341,13 @@ describe('OnboardingInternalBootStep', () => {
await flushPromises();

expect(wrapper.find('[data-testid="brand-button"]').attributes('disabled')).toBeUndefined();
expect(wrapper.find('[data-testid="internal-boot-eligibility-panel"]').exists()).toBe(false);
expect(wrapper.find('[data-testid="internal-boot-drive-warning"]').exists()).toBe(false);
const selects = wrapper.findAll('select');
await selects[1]?.setValue('ELIGIBLE-1');
await flushPromises();
expect(wrapper.find('[data-testid="internal-boot-drive-warning"]').exists()).toBe(true);
expect(wrapper.text()).toContain('Selected drive warnings');
await wrapper.get('[data-testid="internal-boot-eligibility-toggle"]').trigger('click');
await flushPromises();
expect(wrapper.text()).toContain('HAS_INTERNAL_BOOT_PARTITIONS');
});

it('shows disk-level ineligibility while keeping the form available for eligible disks', async () => {
Expand Down
66 changes: 57 additions & 9 deletions web/__test__/components/Onboarding/OnboardingModal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const {
internalBootVisibilityLoading: { value: false },
onboardingModalStoreState: {
isVisible: { value: true },
sessionSource: { value: 'automatic' as 'automatic' | 'manual' },
closeModal: vi.fn().mockResolvedValue(true),
},
activationCodeDataStore: {
Expand Down Expand Up @@ -112,26 +113,51 @@ vi.mock('~/components/Onboarding/OnboardingSteps.vue', () => ({

vi.mock('~/components/Onboarding/stepRegistry', () => ({
stepComponents: {
OVERVIEW: { template: '<div data-testid="overview-step" />' },
CONFIGURE_SETTINGS: { template: '<div data-testid="settings-step" />' },
CONFIGURE_BOOT: { template: '<div data-testid="internal-boot-step" />' },
ADD_PLUGINS: { template: '<div data-testid="plugins-step" />' },
ACTIVATE_LICENSE: { template: '<div data-testid="license-step" />' },
SUMMARY: { template: '<div data-testid="summary-step" />' },
OVERVIEW: {
props: ['onComplete', 'onBack', 'showBack'],
template:
'<div data-testid="overview-step"><button data-testid="overview-step-complete" @click="onComplete()">next</button><button v-if="showBack" data-testid="overview-step-back" @click="onBack()">back</button></div>',
},
CONFIGURE_SETTINGS: {
props: ['onComplete', 'onBack', 'showBack'],
template:
'<div data-testid="settings-step"><button data-testid="settings-step-complete" @click="onComplete()">next</button><button v-if="showBack" data-testid="settings-step-back" @click="onBack()">back</button></div>',
},
CONFIGURE_BOOT: {
props: ['onComplete', 'onBack', 'showBack'],
template:
'<div data-testid="internal-boot-step"><button data-testid="internal-boot-step-complete" @click="onComplete()">next</button><button v-if="showBack" data-testid="internal-boot-step-back" @click="onBack()">back</button></div>',
},
ADD_PLUGINS: {
props: ['onComplete', 'onBack', 'showBack'],
template:
'<div data-testid="plugins-step"><button data-testid="plugins-step-complete" @click="onComplete()">next</button><button v-if="showBack" data-testid="plugins-step-back" @click="onBack()">back</button></div>',
},
ACTIVATE_LICENSE: {
props: ['onComplete', 'onBack', 'showBack'],
template:
'<div data-testid="license-step"><button data-testid="license-step-complete" @click="onComplete()">next</button><button v-if="showBack" data-testid="license-step-back" @click="onBack()">back</button></div>',
},
SUMMARY: {
props: ['onComplete', 'onBack', 'showBack'],
template:
'<div data-testid="summary-step"><button data-testid="summary-step-complete" @click="onComplete()">next</button><button v-if="showBack" data-testid="summary-step-back" @click="onBack()">back</button></div>',
},
NEXT_STEPS: {
props: ['onComplete'],
setup(props: { onComplete: () => void }) {
props: ['onComplete', 'onBack', 'showBack'],
setup(props: { onComplete: () => void; onBack?: () => void; showBack?: boolean }) {
const handleClick = () => {
cleanupOnboardingStorageMock();
props.onComplete();
};

return {
handleClick,
props,
};
},
template:
'<div data-testid="next-step"><button data-testid="next-step-complete" @click="handleClick">finish</button></div>',
'<div data-testid="next-step"><button data-testid="next-step-complete" @click="handleClick">finish</button><button v-if="props.showBack" data-testid="next-step-back" @click="props.onBack?.()">back</button></div>',
},
},
}));
Expand Down Expand Up @@ -181,6 +207,7 @@ describe('OnboardingModal.vue', () => {

onboardingModalStoreState.closeModal.mockImplementation(async () => {
onboardingModalStoreState.isVisible.value = false;
onboardingModalStoreState.sessionSource.value = 'automatic';
return true;
});

Expand All @@ -189,6 +216,7 @@ describe('OnboardingModal.vue', () => {
activationCodeDataStore.hasActivationCode = ref(true);
activationCodeDataStore.registrationState = ref<string | null>('ENOKEYFILE');
onboardingModalStoreState.isVisible.value = true;
onboardingModalStoreState.sessionSource.value = 'automatic';
activationCodeDataStore.registrationState.value = 'ENOKEYFILE';
onboardingStatusStore.isVersionDrift.value = false;
onboardingStatusStore.completedAtVersion.value = null;
Expand Down Expand Up @@ -355,6 +383,26 @@ describe('OnboardingModal.vue', () => {
expect(onboardingDraftStore.currentStepId.value).toBeNull();
});

it('closes a manually opened wizard at the end instead of reloading the page', async () => {
onboardingModalStoreState.sessionSource.value = 'manual';
onboardingDraftStore.currentStepId.value = 'NEXT_STEPS';
const goSpy = vi.spyOn(window.history, 'go').mockImplementation(() => undefined);

const wrapper = mountComponent();
await flushPromises();

await wrapper.get('[data-testid="next-step-complete"]').trigger('click');
await flushPromises();

expect(goSpy).toHaveBeenCalledWith(-1);
expect(onboardingModalStoreState.closeModal).not.toHaveBeenCalled();

window.dispatchEvent(new PopStateEvent('popstate', { state: null }));
await flushPromises();

expect(onboardingModalStoreState.closeModal).toHaveBeenCalledTimes(1);
});

it('shows a loading state while exit confirmation is closing the modal', async () => {
let closeModalDeferred:
| {
Expand Down
10 changes: 5 additions & 5 deletions web/__test__/components/Onboarding/OnboardingSummaryStep.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ describe('OnboardingSummaryStep', () => {
assertExpected: (wrapper: ReturnType<typeof mountComponent>['wrapper']) => {
expect(installPluginMock).not.toHaveBeenCalled();
expect(wrapper.text()).toContain('Already installed');
expect(wrapper.text()).toContain('Setup Applied');
expect(wrapper.text()).toContain('No Updates Needed');
},
},
{
Expand All @@ -392,7 +392,7 @@ describe('OnboardingSummaryStep', () => {
assertExpected: (wrapper: ReturnType<typeof mountComponent>['wrapper']) => {
expect(installPluginMock).not.toHaveBeenCalled();
expect(wrapper.text()).toContain('Already installed');
expect(wrapper.text()).toContain('Setup Applied');
expect(wrapper.text()).toContain('No Updates Needed');
},
},
{
Expand All @@ -402,7 +402,7 @@ describe('OnboardingSummaryStep', () => {
},
assertExpected: (wrapper: ReturnType<typeof mountComponent>['wrapper']) => {
expect(installPluginMock).not.toHaveBeenCalled();
expect(wrapper.text()).toContain('Setup Applied');
expect(wrapper.text()).toContain('No Updates Needed');
},
},
{
Expand Down Expand Up @@ -857,7 +857,7 @@ describe('OnboardingSummaryStep', () => {
apply: () => {},
assertExpected: (wrapper: ReturnType<typeof mountComponent>['wrapper']) => {
expect(completeOnboardingMock).not.toHaveBeenCalled();
expect(wrapper.text()).toContain('Setup Applied');
expect(wrapper.text()).toContain('No Updates Needed');
expect(wrapper.text()).not.toContain('Setup Saved in Best-Effort Mode');
},
},
Expand Down Expand Up @@ -889,7 +889,7 @@ describe('OnboardingSummaryStep', () => {
expect(completeOnboardingMock).not.toHaveBeenCalled();
expect(cleanupOnboardingStorageMock).not.toHaveBeenCalled();
expect(wrapper.find('[data-testid="dialog"]').exists()).toBe(true);
expect(wrapper.text()).toContain('Setup Applied');
expect(wrapper.text()).toContain('No Updates Needed');
expect(onComplete).not.toHaveBeenCalled();
});

Expand Down
Loading
Loading