@@ -6,7 +6,17 @@ import {
66 afterEach ,
77} from 'react-native-harness' ;
88import { Platform } from 'react-native' ;
9- import { MMKV , createMMKV , deleteMMKV , existsMMKV } from 'react-native-mmkv' ;
9+ import {
10+ backupAllMMKV ,
11+ backupMMKV ,
12+ MMKV ,
13+ createMMKV ,
14+ deleteMMKV ,
15+ existsMMKV ,
16+ restoreAllMMKV ,
17+ restoreMMKV ,
18+ } from 'react-native-mmkv' ;
19+ import { getPlatformContext } from '../../packages/react-native-mmkv/src/getMMKVFactory' ;
1020
1121const skipOnWeb = ( reason : string ) : boolean => {
1222 if ( Platform . OS === 'web' ) {
@@ -16,6 +26,22 @@ const skipOnWeb = (reason: string): boolean => {
1626 return false ;
1727} ;
1828
29+ const getAndroidMMKVBasePath = ( reason : string ) : string | undefined => {
30+ if ( Platform . OS !== 'android' ) {
31+ console . log ( `[skip · ${ Platform . OS } ] ${ reason } ` ) ;
32+ return undefined ;
33+ }
34+
35+ createMMKV ( { id : 'backup-restore-base-path-probe' } ) . clearAll ( ) ;
36+ return getPlatformContext ( ) . getBaseDirectory ( ) ;
37+ } ;
38+
39+ const getAndroidTestPath = ( basePath : string , name : string ) : string => {
40+ return `${ basePath } /mmkv-${ name } -${ Date . now ( ) } -${ Math . random ( )
41+ . toString ( 36 )
42+ . slice ( 2 ) } `;
43+ } ;
44+
1945const waitForNextTick = async ( ) => {
2046 await new Promise < void > ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
2147} ;
@@ -929,6 +955,111 @@ describe('MMKV Storage Management', () => {
929955 } ) ;
930956} ) ;
931957
958+ describe ( 'MMKV Backup & Restore' , ( ) => {
959+ it ( 'should back up and restore a single instance with top-level APIs' , ( ) => {
960+ const basePath = getAndroidMMKVBasePath (
961+ 'backup/restore needs a writable native filesystem path' ,
962+ ) ;
963+ if ( basePath == null ) return ;
964+
965+ const rootPath = getAndroidTestPath ( basePath , 'backup-root' ) ;
966+ const backupDirectory = basePath ;
967+ const id = `backup-single-${ Date . now ( ) } ` ;
968+ const storage = createMMKV ( { id, path : rootPath } ) ;
969+
970+ storage . set ( 'name' , 'before-backup' ) ;
971+ storage . set ( 'count' , 1 ) ;
972+
973+ expect (
974+ backupMMKV ( {
975+ id,
976+ destinationDirectory : backupDirectory ,
977+ rootPath,
978+ } ) ,
979+ ) . toStrictEqual ( true ) ;
980+
981+ storage . set ( 'name' , 'after-backup' ) ;
982+ storage . set ( 'count' , 2 ) ;
983+
984+ expect (
985+ restoreMMKV ( {
986+ id,
987+ sourceDirectory : backupDirectory ,
988+ rootPath,
989+ } ) ,
990+ ) . toStrictEqual ( true ) ;
991+ expect ( storage . getString ( 'name' ) ) . toStrictEqual ( 'before-backup' ) ;
992+ expect ( storage . getNumber ( 'count' ) ) . toStrictEqual ( 1 ) ;
993+ } ) ;
994+
995+ it ( 'should back up and restore a single instance with instance APIs' , ( ) => {
996+ const basePath = getAndroidMMKVBasePath (
997+ 'backup/restore needs a writable native filesystem path' ,
998+ ) ;
999+ if ( basePath == null ) return ;
1000+
1001+ const rootPath = getAndroidTestPath ( basePath , 'instance-backup-root' ) ;
1002+ const backupDirectory = basePath ;
1003+ const storage = createMMKV ( {
1004+ id : `backup-instance-${ Date . now ( ) } ` ,
1005+ path : rootPath ,
1006+ } ) ;
1007+
1008+ storage . set ( 'string' , 'original' ) ;
1009+ storage . set ( 'number' , 42 ) ;
1010+ storage . set ( 'boolean' , true ) ;
1011+
1012+ expect ( storage . backupToDirectory ( backupDirectory ) ) . toStrictEqual ( true ) ;
1013+
1014+ storage . set ( 'string' , 'changed' ) ;
1015+ storage . set ( 'number' , 24 ) ;
1016+ storage . set ( 'boolean' , false ) ;
1017+
1018+ expect ( storage . restoreFromDirectory ( backupDirectory ) ) . toStrictEqual ( true ) ;
1019+ expect ( storage . getString ( 'string' ) ) . toStrictEqual ( 'original' ) ;
1020+ expect ( storage . getNumber ( 'number' ) ) . toStrictEqual ( 42 ) ;
1021+ expect ( storage . getBoolean ( 'boolean' ) ) . toStrictEqual ( true ) ;
1022+ } ) ;
1023+
1024+ it ( 'should back up and restore all instances in a custom root path' , ( ) => {
1025+ const basePath = getAndroidMMKVBasePath (
1026+ 'backup/restore needs a writable native filesystem path' ,
1027+ ) ;
1028+ if ( basePath == null ) return ;
1029+
1030+ const rootPath = getAndroidTestPath ( basePath , 'backup-all-root' ) ;
1031+ const backupDirectory = basePath ;
1032+ const first = createMMKV ( {
1033+ id : `backup-all-first-${ Date . now ( ) } ` ,
1034+ path : rootPath ,
1035+ } ) ;
1036+ const second = createMMKV ( {
1037+ id : `backup-all-second-${ Date . now ( ) } ` ,
1038+ path : rootPath ,
1039+ } ) ;
1040+
1041+ first . set ( 'value' , 'first-original' ) ;
1042+ second . set ( 'value' , 'second-original' ) ;
1043+
1044+ const backupCount = backupAllMMKV ( {
1045+ destinationDirectory : backupDirectory ,
1046+ rootPath,
1047+ } ) ;
1048+ expect ( backupCount ) . toBeGreaterThanOrEqual ( 2 ) ;
1049+
1050+ first . set ( 'value' , 'first-changed' ) ;
1051+ second . set ( 'value' , 'second-changed' ) ;
1052+
1053+ const restoreCount = restoreAllMMKV ( {
1054+ sourceDirectory : backupDirectory ,
1055+ rootPath,
1056+ } ) ;
1057+ expect ( restoreCount ) . toBeGreaterThanOrEqual ( 2 ) ;
1058+ expect ( first . getString ( 'value' ) ) . toStrictEqual ( 'first-original' ) ;
1059+ expect ( second . getString ( 'value' ) ) . toStrictEqual ( 'second-original' ) ;
1060+ } ) ;
1061+ } ) ;
1062+
9321063describe ( 'MMKV Multi-Process Mode' , ( ) => {
9331064 afterEach ( ( ) => {
9341065 try {
0 commit comments