11// npx vitest src/core/config/__tests__/importExport.spec.ts
22
3+ import { describe , it , expect , vi , beforeEach } from "vitest"
34import fs from "fs/promises"
45import * as path from "path"
56
@@ -8,7 +9,13 @@ import * as vscode from "vscode"
89import type { ProviderName } from "@roo-code/types"
910import { TelemetryService } from "@roo-code/telemetry"
1011
11- import { importSettings , importSettingsFromFile , importSettingsWithFeedback , exportSettings } from "../importExport"
12+ import {
13+ importSettings ,
14+ importSettingsFromFile ,
15+ importSettingsFromContent ,
16+ importSettingsWithFeedback ,
17+ exportSettings ,
18+ } from "../importExport"
1219import { ProviderSettingsManager } from "../ProviderSettingsManager"
1320import { ContextProxy } from "../ContextProxy"
1421import { CustomModesManager } from "../CustomModesManager"
@@ -263,7 +270,9 @@ describe("importExport", () => {
263270 } )
264271
265272 expect ( result . success ) . toBe ( false )
266- expect ( result . error ) . toMatch ( / ^ E x p e c t e d p r o p e r t y n a m e o r ' } ' i n J S O N a t p o s i t i o n 2 / )
273+ if ( ! result . success ) {
274+ expect ( result . error ) . toMatch ( / ^ E x p e c t e d p r o p e r t y n a m e o r ' } ' i n J S O N a t p o s i t i o n 2 / )
275+ }
267276 expect ( fs . readFile ) . toHaveBeenCalledWith ( "/mock/path/settings.json" , "utf-8" )
268277 expect ( mockProviderSettingsManager . import ) . not . toHaveBeenCalled ( )
269278 expect ( mockContextProxy . setValues ) . not . toHaveBeenCalled ( )
@@ -426,7 +435,7 @@ describe("importExport", () => {
426435 customModesManager : mockCustomModesManager ,
427436 provider : mockProvider ,
428437 } ,
429- filePath ,
438+ { filePath } ,
430439 )
431440
432441 expect ( vscode . window . showOpenDialog ) . not . toHaveBeenCalled ( )
@@ -436,6 +445,178 @@ describe("importExport", () => {
436445
437446 showErrorMessageSpy . mockRestore ( )
438447 } )
448+
449+ it ( "should import settings successfully from provided fileContents" , async ( ) => {
450+ const mockFileContent = JSON . stringify ( {
451+ providerProfiles : {
452+ currentApiConfigName : "test" ,
453+ apiConfigs : { test : { apiProvider : "openai" as ProviderName , apiKey : "test-key" , id : "test-id" } } ,
454+ } ,
455+ globalSettings : { mode : "code" , autoApprovalEnabled : true } ,
456+ } )
457+
458+ const previousProviderProfiles = {
459+ currentApiConfigName : "default" ,
460+ apiConfigs : { default : { apiProvider : "anthropic" as ProviderName , id : "default-id" } } ,
461+ }
462+
463+ mockProviderSettingsManager . export . mockResolvedValue ( previousProviderProfiles )
464+ mockProviderSettingsManager . listConfig . mockResolvedValue ( [
465+ { name : "test" , id : "test-id" , apiProvider : "openai" as ProviderName } ,
466+ { name : "default" , id : "default-id" , apiProvider : "anthropic" as ProviderName } ,
467+ ] )
468+ mockContextProxy . export . mockResolvedValue ( { mode : "code" } )
469+
470+ const result = await importSettingsFromContent ( mockFileContent , {
471+ providerSettingsManager : mockProviderSettingsManager ,
472+ contextProxy : mockContextProxy ,
473+ customModesManager : mockCustomModesManager ,
474+ } )
475+
476+ expect ( result . success ) . toBe ( true )
477+ expect ( mockProviderSettingsManager . export ) . toHaveBeenCalled ( )
478+ expect ( mockProviderSettingsManager . import ) . toHaveBeenCalledWith ( {
479+ currentApiConfigName : "test" ,
480+ apiConfigs : {
481+ default : { apiProvider : "anthropic" as ProviderName , id : "default-id" } ,
482+ test : { apiProvider : "openai" as ProviderName , apiKey : "test-key" , id : "test-id" } ,
483+ } ,
484+ modeApiConfigs : { } ,
485+ } )
486+ expect ( mockContextProxy . setValues ) . toHaveBeenCalledWith ( { mode : "code" , autoApprovalEnabled : true } )
487+ expect ( mockContextProxy . setValue ) . toHaveBeenCalledWith ( "currentApiConfigName" , "test" )
488+ expect ( mockContextProxy . setValue ) . toHaveBeenCalledWith ( "listApiConfigMeta" , [
489+ { name : "test" , id : "test-id" , apiProvider : "openai" as ProviderName } ,
490+ { name : "default" , id : "default-id" , apiProvider : "anthropic" as ProviderName } ,
491+ ] )
492+ } )
493+
494+ it ( "should return success: false when fileContents is not valid JSON" , async ( ) => {
495+ const mockInvalidJson = "{ this is not valid JSON }"
496+
497+ const result = await importSettingsFromContent ( mockInvalidJson , {
498+ providerSettingsManager : mockProviderSettingsManager ,
499+ contextProxy : mockContextProxy ,
500+ customModesManager : mockCustomModesManager ,
501+ } )
502+
503+ expect ( result . success ) . toBe ( false )
504+ if ( ! result . success ) {
505+ expect ( result . error ) . toMatch ( / ^ E x p e c t e d p r o p e r t y n a m e o r ' } ' i n J S O N a t p o s i t i o n 2 / )
506+ }
507+ expect ( mockProviderSettingsManager . import ) . not . toHaveBeenCalled ( )
508+ expect ( mockContextProxy . setValues ) . not . toHaveBeenCalled ( )
509+ } )
510+
511+ it ( "should return success: false when fileContents is missing required fields" , async ( ) => {
512+ // Invalid content (missing required fields)
513+ const mockInvalidContent = JSON . stringify ( {
514+ providerProfiles : { apiConfigs : { } } ,
515+ globalSettings : { } ,
516+ } )
517+
518+ const result = await importSettingsFromContent ( mockInvalidContent , {
519+ providerSettingsManager : mockProviderSettingsManager ,
520+ contextProxy : mockContextProxy ,
521+ customModesManager : mockCustomModesManager ,
522+ } )
523+
524+ expect ( result . success ) . toBe ( false )
525+ if ( ! result . success ) {
526+ expect ( result . error ) . toBe ( "[providerProfiles.currentApiConfigName]: Required" )
527+ }
528+ expect ( mockProviderSettingsManager . import ) . not . toHaveBeenCalled ( )
529+ expect ( mockContextProxy . setValues ) . not . toHaveBeenCalled ( )
530+ } )
531+
532+ it ( "should import settings successfully using importSettingsWithFeedback with fileContents" , async ( ) => {
533+ const mockFileContent = JSON . stringify ( {
534+ providerProfiles : {
535+ currentApiConfigName : "test" ,
536+ apiConfigs : { test : { apiProvider : "openai" as ProviderName , apiKey : "test-key" , id : "test-id" } } ,
537+ } ,
538+ globalSettings : { mode : "code" , autoApprovalEnabled : true } ,
539+ } )
540+
541+ const previousProviderProfiles = {
542+ currentApiConfigName : "default" ,
543+ apiConfigs : { default : { apiProvider : "anthropic" as ProviderName , id : "default-id" } } ,
544+ }
545+
546+ mockProviderSettingsManager . export . mockResolvedValue ( previousProviderProfiles )
547+ mockProviderSettingsManager . listConfig . mockResolvedValue ( [
548+ { name : "test" , id : "test-id" , apiProvider : "openai" as ProviderName } ,
549+ { name : "default" , id : "default-id" , apiProvider : "anthropic" as ProviderName } ,
550+ ] )
551+ mockContextProxy . export . mockResolvedValue ( { mode : "code" } )
552+
553+ const mockProvider = {
554+ settingsImportedAt : 0 ,
555+ postStateToWebview : vi . fn ( ) . mockResolvedValue ( undefined ) ,
556+ }
557+
558+ const showInformationMessageSpy = vi
559+ . spyOn ( vscode . window , "showInformationMessage" )
560+ . mockResolvedValue ( undefined )
561+
562+ await importSettingsWithFeedback (
563+ {
564+ providerSettingsManager : mockProviderSettingsManager ,
565+ contextProxy : mockContextProxy ,
566+ customModesManager : mockCustomModesManager ,
567+ provider : mockProvider ,
568+ } ,
569+ { fileContents : mockFileContent } ,
570+ )
571+
572+ expect ( vscode . window . showOpenDialog ) . not . toHaveBeenCalled ( )
573+ expect ( fs . readFile ) . not . toHaveBeenCalled ( )
574+ expect ( mockProviderSettingsManager . import ) . toHaveBeenCalledWith ( {
575+ currentApiConfigName : "test" ,
576+ apiConfigs : {
577+ default : { apiProvider : "anthropic" as ProviderName , id : "default-id" } ,
578+ test : { apiProvider : "openai" as ProviderName , apiKey : "test-key" , id : "test-id" } ,
579+ } ,
580+ modeApiConfigs : { } ,
581+ } )
582+ expect ( mockContextProxy . setValues ) . toHaveBeenCalledWith ( { mode : "code" , autoApprovalEnabled : true } )
583+ expect ( mockProvider . settingsImportedAt ) . toBeGreaterThan ( 0 )
584+ expect ( mockProvider . postStateToWebview ) . toHaveBeenCalled ( )
585+ expect ( showInformationMessageSpy ) . toHaveBeenCalledWith ( expect . stringContaining ( "info.settings_imported" ) )
586+
587+ showInformationMessageSpy . mockRestore ( )
588+ } )
589+
590+ it ( "should show error message when importSettingsWithFeedback fails with invalid fileContents" , async ( ) => {
591+ const mockInvalidJson = "{ this is not valid JSON }"
592+
593+ const mockProvider = {
594+ settingsImportedAt : 0 ,
595+ postStateToWebview : vi . fn ( ) . mockResolvedValue ( undefined ) ,
596+ }
597+
598+ const showErrorMessageSpy = vi . spyOn ( vscode . window , "showErrorMessage" ) . mockResolvedValue ( undefined )
599+
600+ await importSettingsWithFeedback (
601+ {
602+ providerSettingsManager : mockProviderSettingsManager ,
603+ contextProxy : mockContextProxy ,
604+ customModesManager : mockCustomModesManager ,
605+ provider : mockProvider ,
606+ } ,
607+ { fileContents : mockInvalidJson } ,
608+ )
609+
610+ expect ( vscode . window . showOpenDialog ) . not . toHaveBeenCalled ( )
611+ expect ( fs . readFile ) . not . toHaveBeenCalled ( )
612+ expect ( mockProviderSettingsManager . import ) . not . toHaveBeenCalled ( )
613+ expect ( mockContextProxy . setValues ) . not . toHaveBeenCalled ( )
614+ expect ( mockProvider . settingsImportedAt ) . toBe ( 0 )
615+ expect ( mockProvider . postStateToWebview ) . not . toHaveBeenCalled ( )
616+ expect ( showErrorMessageSpy ) . toHaveBeenCalledWith ( expect . stringContaining ( "errors.settings_import_failed" ) )
617+
618+ showErrorMessageSpy . mockRestore ( )
619+ } )
439620 } )
440621
441622 describe ( "exportSettings" , ( ) => {
0 commit comments