This is an automated email from the ASF dual-hosted git repository.

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new 2f07500ba test(web): cover the auth-session, engine-preference and 
data-mode stores (#5650)
2f07500ba is described below

commit 2f07500ba4c734ad885df8f694967f29e89f01d2
Author: Chstercc <[email protected]>
AuthorDate: Sat Oct 10 12:01:11 2026 +0800

    test(web): cover the auth-session, engine-preference and data-mode stores 
(#5650)
    
    Three store-level test suites from the same author, none of which touched 
production code.
    
    - #5650 `test(auth-store): cover session persistence and reload`
    - #5657 `test(ai): cover engine preference persistence and migration`
    - #5659 `test(data-mode): cover runtime toggles and saved preferences`
    
    3 suites, 15 tests green; prettier and eslint clean.
    
    Folded in #5657, #5659 (same author). Merged through #5650.
---
 web/src/services/dataMode.test.ts  | 64 +++++++++++++++++++++++++++++++
 web/src/stores/authStore.test.ts   | 77 +++++++++++++++++++++++++++++++++++++
 web/src/stores/engineStore.test.ts | 78 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 219 insertions(+)

diff --git a/web/src/services/dataMode.test.ts 
b/web/src/services/dataMode.test.ts
new file mode 100644
index 000000000..11a71a2c7
--- /dev/null
+++ b/web/src/services/dataMode.test.ts
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { afterEach, describe, expect, it, vi } from 'vitest';
+
+async function loadDataMode() {
+  vi.resetModules();
+  const { isMockMode } = await import('./dataMode');
+  const { useDataModeStore } = await import('../stores/dataModeStore');
+  return { isMockMode, store: useDataModeStore };
+}
+
+describe('dataMode service', () => {
+  afterEach(() => {
+    vi.unstubAllEnvs();
+    vi.resetModules();
+    localStorage.clear();
+  });
+
+  it.each(['true', 'false'])('reflectsRuntimeTogglesWithViteUseMock_%sTest', 
async (envValue) => {
+    vi.stubEnv('VITE_USE_MOCK', envValue);
+    const { isMockMode, store } = await loadDataMode();
+    const initialMode = envValue === 'true';
+
+    expect(isMockMode()).toBe(initialMode);
+
+    store.getState().toggle();
+    expect(isMockMode()).toBe(!initialMode);
+
+    store.getState().toggle();
+    expect(isMockMode()).toBe(initialMode);
+  });
+
+  it.each([
+    ['false', true],
+    ['true', false],
+  ] as const)('usesPersistedModeInsteadOfBuildDefault_%sTest', async 
(envValue, persistedMode) => {
+    vi.stubEnv('VITE_USE_MOCK', envValue);
+    localStorage.setItem(
+      'rocketmq-studio-data-mode',
+      JSON.stringify({ state: { useMock: persistedMode }, version: 0 }),
+    );
+    const { isMockMode, store } = await loadDataMode();
+
+    expect(isMockMode()).toBe(persistedMode);
+
+    store.getState().toggle();
+    expect(isMockMode()).toBe(!persistedMode);
+  });
+});
diff --git a/web/src/stores/authStore.test.ts b/web/src/stores/authStore.test.ts
new file mode 100644
index 000000000..d53c65af2
--- /dev/null
+++ b/web/src/stores/authStore.test.ts
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { afterEach, describe, expect, it, vi } from 'vitest';
+
+async function loadStore() {
+  vi.resetModules();
+  return (await import('./authStore')).default;
+}
+
+describe('authStore', () => {
+  afterEach(() => {
+    localStorage.clear();
+    vi.resetModules();
+  });
+
+  it('starts without a display identity when storage is empty', async () => {
+    const store = await loadStore();
+
+    expect(store.getState()).toMatchObject({ user: null, userId: null, admin: 
null });
+  });
+
+  it('updates and persists the display identity on login without storing a 
bearer token', async () => {
+    const store = await loadStore();
+
+    store.getState().login('studio-admin', 7, true);
+
+    expect(store.getState()).toMatchObject({ user: 'studio-admin', userId: 7, 
admin: true });
+    expect(localStorage.getItem('rocketmq-studio-user')).toBe('studio-admin');
+    expect(localStorage.getItem('rocketmq-studio-user-id')).toBe('7');
+    expect(localStorage.getItem('rocketmq-studio-user-admin')).toBe('true');
+    expect(localStorage.getItem('token')).toBeNull();
+  });
+
+  it.each([true, false])(
+    'restores the persisted display identity with admin=%s on reload',
+    async (admin) => {
+      const store = await loadStore();
+      store.getState().login('studio-user', 7, admin);
+
+      const reloadedStore = await loadStore();
+
+      expect(reloadedStore).not.toBe(store);
+      expect(reloadedStore.getState()).toMatchObject({ user: 'studio-user', 
userId: 7, admin });
+    },
+  );
+
+  it('clears the display identity and legacy bearer token on logout, including 
after reload', async () => {
+    const store = await loadStore();
+    store.getState().login('studio-admin', 7, true);
+    localStorage.setItem('token', 'legacy-token');
+
+    store.getState().logout();
+
+    expect(store.getState()).toMatchObject({ user: null, userId: null, admin: 
null });
+    expect(localStorage.getItem('rocketmq-studio-user')).toBeNull();
+    expect(localStorage.getItem('rocketmq-studio-user-id')).toBeNull();
+    expect(localStorage.getItem('rocketmq-studio-user-admin')).toBeNull();
+    expect(localStorage.getItem('token')).toBeNull();
+    const reloadedStore = await loadStore();
+    expect(reloadedStore.getState()).toMatchObject({ user: null, userId: null, 
admin: null });
+  });
+});
diff --git a/web/src/stores/engineStore.test.ts 
b/web/src/stores/engineStore.test.ts
new file mode 100644
index 000000000..117ba8ca0
--- /dev/null
+++ b/web/src/stores/engineStore.test.ts
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { afterEach, describe, expect, it, vi } from 'vitest';
+
+const STORAGE_KEY = 'rocketmq-studio-agent-engine';
+
+async function loadStore() {
+  vi.resetModules();
+  return (await import('./engineStore')).useEngineStore;
+}
+
+describe('engineStore', () => {
+  afterEach(() => {
+    localStorage.clear();
+    vi.resetModules();
+  });
+
+  it('defaultsToClaudeCodeWithoutAPersistedPreferenceTest', async () => {
+    const store = await loadStore();
+
+    expect(store.getState().engine).toBe('claude-code');
+  });
+
+  it.each(['claude-code', 'qoder', 'http'] as const)(
+    'persistsAndRestoresTheSelectedEngine_%sTest',
+    async (engine) => {
+      const store = await loadStore();
+
+      store.getState().setEngine(engine);
+
+      expect(store.getState().engine).toBe(engine);
+      expect(JSON.parse(localStorage.getItem(STORAGE_KEY)!)).toEqual({
+        state: { engine },
+        version: 1,
+      });
+
+      const reloadedStore = await loadStore();
+
+      expect(reloadedStore).not.toBe(store);
+      expect(reloadedStore.getState().engine).toBe(engine);
+    },
+  );
+
+  it.each(['qoder', 'stale-engine'])(
+    'migratesVersionZeroPreference_%sToClaudeCodeTest',
+    async (engine) => {
+      localStorage.setItem(STORAGE_KEY, JSON.stringify({ state: { engine }, 
version: 0 }));
+
+      const store = await loadStore();
+
+      expect(store.getState().engine).toBe('claude-code');
+      expect(JSON.parse(localStorage.getItem(STORAGE_KEY)!)).toEqual({
+        state: { engine: 'claude-code' },
+        version: 1,
+      });
+
+      const reloadedStore = await loadStore();
+
+      expect(reloadedStore).not.toBe(store);
+      expect(reloadedStore.getState().engine).toBe('claude-code');
+    },
+  );
+});

Reply via email to