@@ -188,7 +188,10 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
188188 } )
189189
190190 it ( "supports iteration" , ( ) => {
191- const base = [ { id : 1 , a : 1 } , { id : 2 , a : 1 } ]
191+ const base = [
192+ { id : 1 , a : 1 } ,
193+ { id : 2 , a : 1 }
194+ ]
192195 const findById = ( collection , id ) => {
193196 for ( const item of collection ) {
194197 if ( item . id === id ) return item
@@ -386,7 +389,10 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
386389 } )
387390
388391 it ( "supports 'keys" , ( ) => {
389- const base = new Map ( [ [ "first" , Symbol ( ) ] , [ "second" , Symbol ( ) ] ] )
392+ const base = new Map ( [
393+ [ "first" , Symbol ( ) ] ,
394+ [ "second" , Symbol ( ) ]
395+ ] )
390396 const result = produce ( base , draft => {
391397 expect ( [ ...draft . keys ( ) ] ) . toEqual ( [ "first" , "second" ] )
392398 draft . set ( "third" , Symbol ( ) )
@@ -490,7 +496,7 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
490496 it ( "can use 'delete' to remove items" , ( ) => {
491497 const nextState = produce ( baseState , s => {
492498 expect ( s . aMap . has ( "jedi" ) ) . toBe ( true )
493- s . aMap . delete ( "jedi" )
499+ expect ( s . aMap . delete ( "jedi" ) ) . toBe ( true )
494500 expect ( s . aMap . has ( "jedi" ) ) . toBe ( false )
495501 } )
496502 expect ( nextState . aMap ) . not . toBe ( baseState . aMap )
@@ -535,11 +541,55 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
535541 expect ( base . get ( "first" ) . get ( "second" ) . prop ) . toBe ( "test" )
536542 expect ( result . get ( "first" ) . get ( "second" ) . prop ) . toBe ( "test1" )
537543 } )
544+
545+ it ( "treats void deletes as no-op" , ( ) => {
546+ const base = new Map ( [ [ "x" , 1 ] ] )
547+ const next = produce ( base , d => {
548+ expect ( d . delete ( "y" ) ) . toBe ( false )
549+ } )
550+ expect ( next ) . toBe ( base )
551+ } )
552+
553+ it ( "revokes map proxies" , ( ) => {
554+ let m
555+ produce ( baseState , s => {
556+ m = s . aMap
557+ } )
558+ expect ( ( ) => m . get ( "x" ) ) . toThrow (
559+ "Cannot use a proxy that has been revoked"
560+ )
561+ expect ( ( ) => m . set ( "x" , 3 ) ) . toThrow (
562+ "Cannot use a proxy that has been revoked"
563+ )
564+ } )
565+
566+ it ( "does not draft map keys" , ( ) => {
567+ // anything else would be terribly confusing
568+ const key = { a : 1 }
569+ const map = new Map ( [ [ key , 2 ] ] )
570+ const next = produce ( map , d => {
571+ const dKey = Array . from ( d . keys ( ) ) [ 0 ]
572+ expect ( isDraft ( dKey ) ) . toBe ( false )
573+ expect ( dKey ) . toBe ( key )
574+ dKey . a += 1
575+ d . set ( dKey , d . get ( dKey ) + 1 )
576+ d . set ( key , d . get ( key ) + 1 )
577+ expect ( d . get ( key ) ) . toBe ( 4 )
578+ expect ( key . a ) . toBe ( 2 )
579+ } )
580+ const entries = Array . from ( next . entries ( ) )
581+ expect ( entries ) . toEqual ( [ [ key , 4 ] ] )
582+ expect ( entries [ 0 ] [ 0 ] ) . toBe ( key )
583+ expect ( entries [ 0 ] [ 0 ] . a ) . toBe ( 2 )
584+ } )
538585 } )
539586
540587 describe ( "set drafts" , ( ) => {
541588 it ( "supports iteration" , ( ) => {
542- const base = new Set ( [ { id : 1 , a : 1 } , { id : 2 , a : 1 } ] )
589+ const base = new Set ( [
590+ { id : 1 , a : 1 } ,
591+ { id : 2 , a : 1 }
592+ ] )
543593 const findById = ( set , id ) => {
544594 for ( const item of set ) {
545595 if ( item . id === id ) return item
@@ -553,12 +603,25 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
553603 obj2 . a = 2
554604 } )
555605 expect ( result ) . not . toBe ( base )
556- expect ( base ) . toEqual ( new Set ( [ { id : 1 , a : 1 } , { id : 2 , a : 1 } ] ) )
557- expect ( result ) . toEqual ( new Set ( [ { id : 1 , a : 2 } , { id : 2 , a : 2 } ] ) )
606+ expect ( base ) . toEqual (
607+ new Set ( [
608+ { id : 1 , a : 1 } ,
609+ { id : 2 , a : 1 }
610+ ] )
611+ )
612+ expect ( result ) . toEqual (
613+ new Set ( [
614+ { id : 1 , a : 2 } ,
615+ { id : 2 , a : 2 }
616+ ] )
617+ )
558618 } )
559619
560620 it ( "supports 'entries'" , ( ) => {
561- const base = new Set ( [ { id : 1 , a : 1 } , { id : 2 , a : 1 } ] )
621+ const base = new Set ( [
622+ { id : 1 , a : 1 } ,
623+ { id : 2 , a : 1 }
624+ ] )
562625 const findById = ( set , id ) => {
563626 for ( const [ item1 , item2 ] of set . entries ( ) ) {
564627 expect ( item1 ) . toBe ( item2 )
@@ -573,12 +636,25 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
573636 obj2 . a = 2
574637 } )
575638 expect ( result ) . not . toBe ( base )
576- expect ( base ) . toEqual ( new Set ( [ { id : 1 , a : 1 } , { id : 2 , a : 1 } ] ) )
577- expect ( result ) . toEqual ( new Set ( [ { id : 1 , a : 2 } , { id : 2 , a : 2 } ] ) )
639+ expect ( base ) . toEqual (
640+ new Set ( [
641+ { id : 1 , a : 1 } ,
642+ { id : 2 , a : 1 }
643+ ] )
644+ )
645+ expect ( result ) . toEqual (
646+ new Set ( [
647+ { id : 1 , a : 2 } ,
648+ { id : 2 , a : 2 }
649+ ] )
650+ )
578651 } )
579652
580653 it ( "supports 'values'" , ( ) => {
581- const base = new Set ( [ { id : 1 , a : 1 } , { id : 2 , a : 1 } ] )
654+ const base = new Set ( [
655+ { id : 1 , a : 1 } ,
656+ { id : 2 , a : 1 }
657+ ] )
582658 const findById = ( set , id ) => {
583659 for ( const item of set . values ( ) ) {
584660 if ( item . id === id ) return item
@@ -592,12 +668,25 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
592668 obj2 . a = 2
593669 } )
594670 expect ( result ) . not . toBe ( base )
595- expect ( base ) . toEqual ( new Set ( [ { id : 1 , a : 1 } , { id : 2 , a : 1 } ] ) )
596- expect ( result ) . toEqual ( new Set ( [ { id : 1 , a : 2 } , { id : 2 , a : 2 } ] ) )
671+ expect ( base ) . toEqual (
672+ new Set ( [
673+ { id : 1 , a : 1 } ,
674+ { id : 2 , a : 1 }
675+ ] )
676+ )
677+ expect ( result ) . toEqual (
678+ new Set ( [
679+ { id : 1 , a : 2 } ,
680+ { id : 2 , a : 2 }
681+ ] )
682+ )
597683 } )
598684
599685 it ( "supports 'keys'" , ( ) => {
600- const base = new Set ( [ { id : 1 , a : 1 } , { id : 2 , a : 1 } ] )
686+ const base = new Set ( [
687+ { id : 1 , a : 1 } ,
688+ { id : 2 , a : 1 }
689+ ] )
601690 const findById = ( set , id ) => {
602691 for ( const item of set . keys ( ) ) {
603692 if ( item . id === id ) return item
@@ -611,12 +700,25 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
611700 obj2 . a = 2
612701 } )
613702 expect ( result ) . not . toBe ( base )
614- expect ( base ) . toEqual ( new Set ( [ { id : 1 , a : 1 } , { id : 2 , a : 1 } ] ) )
615- expect ( result ) . toEqual ( new Set ( [ { id : 1 , a : 2 } , { id : 2 , a : 2 } ] ) )
703+ expect ( base ) . toEqual (
704+ new Set ( [
705+ { id : 1 , a : 1 } ,
706+ { id : 2 , a : 1 }
707+ ] )
708+ )
709+ expect ( result ) . toEqual (
710+ new Set ( [
711+ { id : 1 , a : 2 } ,
712+ { id : 2 , a : 2 }
713+ ] )
714+ )
616715 } )
617716
618717 it ( "supports forEach with mutation after reads" , ( ) => {
619- const base = new Set ( [ { id : 1 , a : 1 } , { id : 2 , a : 2 } ] )
718+ const base = new Set ( [
719+ { id : 1 , a : 1 } ,
720+ { id : 2 , a : 2 }
721+ ] )
620722 const result = produce ( base , draft => {
621723 let sum1 = 0
622724 draft . forEach ( ( { a} ) => {
@@ -631,8 +733,18 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
631733 expect ( sum2 ) . toBe ( 23 )
632734 } )
633735 expect ( result ) . not . toBe ( base )
634- expect ( base ) . toEqual ( new Set ( [ { id : 1 , a : 1 } , { id : 2 , a : 2 } ] ) )
635- expect ( result ) . toEqual ( new Set ( [ { id : 1 , a : 11 } , { id : 2 , a : 12 } ] ) )
736+ expect ( base ) . toEqual (
737+ new Set ( [
738+ { id : 1 , a : 1 } ,
739+ { id : 2 , a : 2 }
740+ ] )
741+ )
742+ expect ( result ) . toEqual (
743+ new Set ( [
744+ { id : 1 , a : 11 } ,
745+ { id : 2 , a : 12 }
746+ ] )
747+ )
636748 } )
637749
638750 it ( "state stays the same if the same item is added" , ( ) => {
@@ -669,13 +781,14 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
669781 it ( "can use 'delete' to remove items" , ( ) => {
670782 const nextState = produce ( baseState , s => {
671783 expect ( s . aSet . has ( "Luke" ) ) . toBe ( true )
672- s . aSet . delete ( "Luke" )
784+ expect ( s . aSet . delete ( "Luke" ) ) . toBe ( true )
785+ expect ( s . aSet . delete ( "Luke" ) ) . toBe ( false )
673786 expect ( s . aSet . has ( "Luke" ) ) . toBe ( false )
674787 } )
675788 expect ( nextState . aSet ) . not . toBe ( baseState . aSet )
676- expect ( nextState . aSet . size ) . toBe ( baseState . aSet . size - 1 )
677789 expect ( baseState . aSet . has ( "Luke" ) ) . toBe ( true )
678790 expect ( nextState . aSet . has ( "Luke" ) ) . toBe ( false )
791+ expect ( nextState . aSet . size ) . toBe ( baseState . aSet . size - 1 )
679792 } )
680793
681794 it ( "can use 'clear' to remove items" , ( ) => {
@@ -710,6 +823,32 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
710823 expect ( base ) . toEqual ( new Set ( [ new Set ( [ "Serenity" ] ) ] ) )
711824 expect ( result ) . toEqual ( new Set ( [ new Set ( [ "Serenity" , "Firefly" ] ) ] ) )
712825 } )
826+
827+ it ( "supports has / delete on elements from the original" , ( ) => {
828+ const obj = { }
829+ const set = new Set ( [ obj ] )
830+ const next = produce ( set , d => {
831+ expect ( d . has ( obj ) ) . toBe ( true )
832+ d . add ( 3 )
833+ expect ( d . has ( obj ) ) . toBe ( true )
834+ d . delete ( obj )
835+ expect ( d . has ( obj ) ) . toBe ( false )
836+ } )
837+ expect ( next ) . toEqual ( new Set ( [ 3 ] ) )
838+ } )
839+
840+ it ( "revokes sets" , ( ) => {
841+ let m
842+ produce ( baseState , s => {
843+ m = s . aSet
844+ } )
845+ expect ( ( ) => m . has ( "x" ) ) . toThrow (
846+ "Cannot use a proxy that has been revoked"
847+ )
848+ expect ( ( ) => m . add ( "x" ) ) . toThrow (
849+ "Cannot use a proxy that has been revoked"
850+ )
851+ } )
713852 } )
714853
715854 it ( "supports `immerable` symbol on constructor" , ( ) => {
@@ -1236,6 +1375,20 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
12361375 expect ( result [ 0 ] . a ) . toEqual ( 2 )
12371376 } )
12381377
1378+ it ( "does not draft external data" , ( ) => {
1379+ const externalData = { x : 3 }
1380+ const base = { }
1381+ const next = produce ( base , draft => {
1382+ // potentially, we *could* draft external data automatically, but only if those statements are not switched...
1383+ draft . y = externalData
1384+ draft . y . x += 1
1385+ externalData . x += 1
1386+ } )
1387+ expect ( next ) . toEqual ( { y : { x : 5 } } )
1388+ expect ( externalData . x ) . toBe ( 5 )
1389+ expect ( next . y ) . toBe ( externalData )
1390+ } )
1391+
12391392 autoFreeze &&
12401393 test ( "issue #469, state not frozen" , ( ) => {
12411394 const project = produce (
@@ -1598,7 +1751,10 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
15981751 const c = { c : 3 }
15991752 const set1 = new Set ( [ a , b ] )
16001753 const set2 = new Set ( [ c ] )
1601- const map = new Map ( [ [ "set1" , set1 ] , [ "set2" , set2 ] ] )
1754+ const map = new Map ( [
1755+ [ "set1" , set1 ] ,
1756+ [ "set2" , set2 ]
1757+ ] )
16021758 const base = { map}
16031759
16041760 function first ( set ) {
0 commit comments