From c2af461706ae0dbab7271caf45bb9eefde4cdc53 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Fri, 25 Sep 2026 18:54:13 -0500 Subject: [PATCH] test(desktop): fixture where a shared credential arrives with primary: false The existing provider-card cases only ever mark shared profiles primary: true, so the branch where buildProviderKeyGroups must prefer the card's own key over a primary:false alias was uncovered. Add the CN Coding Plan shape: own index-0 var primary, shared DASHSCOPE_API_KEY contributed by the same card as a fallback alias, and assert Save writes the CN-specific var and never the shared one. Also restore the plugins-store named imports the toggle tests use after the rebase onto the catalog refactor. --- .../capabilities/plugins/plugins-tab.test.tsx | 2 +- .../app/settings/providers-settings.test.tsx | 73 ++++++++++++++++++- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/apps/desktop/src/app/capabilities/plugins/plugins-tab.test.tsx b/apps/desktop/src/app/capabilities/plugins/plugins-tab.test.tsx index 39af34ff3f..8373e20601 100644 --- a/apps/desktop/src/app/capabilities/plugins/plugins-tab.test.tsx +++ b/apps/desktop/src/app/capabilities/plugins/plugins-tab.test.tsx @@ -4,7 +4,7 @@ import { type ComponentProps, useState } from 'react' import { MemoryRouter, useLocation } from 'react-router' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { $pluginRecords } from '@/contrib/plugins-store' +import { $pluginDecisions, $pluginRecords, dropPlugin, patchPlugin, publishPlugin } from '@/contrib/plugins-store' import { queryClient } from '@/lib/query-client' import { $agentPlugins, $agentPluginsStatus, type AgentPluginRow } from '@/store/agent-plugins' import { $confirmRequest, settleConfirm } from '@/store/confirm' diff --git a/apps/desktop/src/app/settings/providers-settings.test.tsx b/apps/desktop/src/app/settings/providers-settings.test.tsx index 29e84c7892..8ec2e8f3fe 100644 --- a/apps/desktop/src/app/settings/providers-settings.test.tsx +++ b/apps/desktop/src/app/settings/providers-settings.test.tsx @@ -1,4 +1,4 @@ -import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react' +import { act, cleanup, fireEvent, render, screen, waitFor, within } from '@testing-library/react' import { atom } from 'nanostores' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' @@ -283,6 +283,77 @@ describe('ProvidersSettings', () => { expect((inputs[1] as HTMLInputElement).value).toBe('') }) + it('keeps a card on its own key when a shared credential arrives with primary: false', async () => { + // The CN Coding Plan card's own credential (its index-0 var) plus the + // shared DASHSCOPE_API_KEY, which the catalog contributes as a FALLBACK + // alias (primary: false) because it is index >= 1 for that provider. The + // card's "Paste key" must edit the provider's own key, not the shared one. + getEnvVars.mockResolvedValue({ + ALIBABA_CODING_PLAN_CN_API_KEY: keyVar({ + provider: 'alibaba-coding-plan-cn', + provider_label: 'Alibaba Cloud (Coding Plan, China)', + provider_primary: true + }), + ALIBABA_CODING_PLAN_API_KEY: keyVar({ + provider: 'alibaba-coding-plan-cn', + provider_label: 'Alibaba Cloud (Coding Plan, China)', + provider_primary: false + }), + DASHSCOPE_API_KEY: keyVar({ + provider: 'alibaba', + provider_label: 'Qwen Cloud', + provider_profiles: [ + { + description: 'International DashScope route', + primary: true, + provider: 'alibaba', + provider_label: 'Qwen Cloud', + url: 'https://modelstudio.console.alibabacloud.com/' + }, + { + description: 'Coding Plan fallback alias', + primary: false, + provider: 'alibaba-coding-plan-cn', + provider_label: 'Alibaba Cloud (Coding Plan, China)', + url: 'https://help.aliyun.com/zh/model-studio/' + } + ] + }) + }) + listOAuthProviders.mockResolvedValue({ providers: [] }) + + const { ProvidersSettings } = await import('./providers-settings') + const { container } = render() + + expect(await screen.findByText('Alibaba Cloud (Coding Plan, China)')).toBeTruthy() + + // Exactly one primary "Paste … key" input per card; the CN card's must edit + // ALIBABA_CODING_PLAN_CN_API_KEY, never the shared DASHSCOPE_API_KEY. + const inputs = container.querySelectorAll('input[type="password"]') + const pasteInputs = await screen.findAllByPlaceholderText(/Paste .* key/) + expect(pasteInputs).toHaveLength(2) // Qwen Cloud card + the CN Coding Plan card + + const cnCard = screen + .getAllByText('Alibaba Cloud (Coding Plan, China)') + .map(el => el.closest('[role="button"]') ?? el.closest('div[class*="group/card"]')) + .find(Boolean)! + + const cnInput = cnCard.querySelector('input[type="password"]')! + expect(inputs.length).toBeGreaterThanOrEqual(1) + + fireEvent.focus(cnInput) + fireEvent.change(cnInput, { target: { value: 'cn-tier-secret' } }) + fireEvent.click(within(cnCard as HTMLElement).getByRole('button', { name: 'Save' })) + + // The write names the CN-specific var — never the shared DASHSCOPE_API_KEY. + await waitFor(() => { + const [key, value] = setEnvVar.mock.calls.at(-1) ?? [] + expect(key).toBe('ALIBABA_CODING_PLAN_CN_API_KEY') + expect(value).toBe('cn-tier-secret') + expect(setEnvVar).not.toHaveBeenCalledWith('DASHSCOPE_API_KEY', expect.anything(), expect.anything()) + }) + }) + it('clears the shared reveal when a namespaced provider-card draft is saved', async () => { const varKey = 'DASHSCOPE_API_KEY' const editKey = `Qwen Cloud:${varKey}`