@@ -3118,6 +3118,158 @@ describe("ApolloClient", () => {
31183118 await expect ( stream ) . not . toEmitAnything ( ) ;
31193119 } ) ;
31203120
3121+ it ( "keeps the clobbered cache value when a polled result matches the last written result" , async ( ) => {
3122+ const query = gql `
3123+ query {
3124+ hero {
3125+ id
3126+ name
3127+ }
3128+ }
3129+ ` ;
3130+
3131+ const client = new ApolloClient ( {
3132+ cache : new InMemoryCache ( ) ,
3133+ link : new MockLink ( [
3134+ {
3135+ request : { query } ,
3136+ result : {
3137+ data : { hero : { __typename : "Hero" , id : "1" , name : "Luke" } } ,
3138+ } ,
3139+ delay : 20 ,
3140+ maxUsageCount : Number . POSITIVE_INFINITY ,
3141+ } ,
3142+ ] ) ,
3143+ } ) ;
3144+
3145+ const observable = client . watchQuery ( { query, pollInterval : 10 } ) ;
3146+ const stream = new ObservableStream ( observable ) ;
3147+
3148+ await expect ( stream ) . toEmitTypedValue ( {
3149+ data : undefined ,
3150+ dataState : "empty" ,
3151+ loading : true ,
3152+ networkStatus : NetworkStatus . loading ,
3153+ partial : true ,
3154+ } ) ;
3155+
3156+ await expect ( stream ) . toEmitTypedValue ( {
3157+ data : { hero : { __typename : "Hero" , id : "1" , name : "Luke" } } ,
3158+ dataState : "complete" ,
3159+ loading : false ,
3160+ networkStatus : NetworkStatus . ready ,
3161+ partial : false ,
3162+ } ) ;
3163+
3164+ // Another writer clobbers the field this query wrote.
3165+ client . writeQuery ( {
3166+ query,
3167+ data : { hero : { __typename : "Hero" , id : "1" , name : "Clobbered" } } ,
3168+ } ) ;
3169+
3170+ await expect ( stream ) . toEmitTypedValue ( {
3171+ data : { hero : { __typename : "Hero" , id : "1" , name : "Clobbered" } } ,
3172+ dataState : "complete" ,
3173+ loading : false ,
3174+ networkStatus : NetworkStatus . ready ,
3175+ partial : false ,
3176+ } ) ;
3177+
3178+ await expect ( stream ) . toEmitTypedValue ( {
3179+ data : { hero : { __typename : "Hero" , id : "1" , name : "Clobbered" } } ,
3180+ dataState : "complete" ,
3181+ loading : true ,
3182+ networkStatus : NetworkStatus . poll ,
3183+ partial : false ,
3184+ } ) ;
3185+
3186+ await expect ( stream ) . toEmitTypedValue ( {
3187+ data : { hero : { __typename : "Hero" , id : "1" , name : "Luke" } } ,
3188+ dataState : "complete" ,
3189+ loading : false ,
3190+ networkStatus : NetworkStatus . ready ,
3191+ partial : false ,
3192+ } ) ;
3193+
3194+ observable . stopPolling ( ) ;
3195+
3196+ await expect ( stream ) . not . toEmitAnything ( ) ;
3197+ } ) ;
3198+
3199+ it ( "applies read functions when a polled result matches the last written result" , async ( ) => {
3200+ const query = gql `
3201+ query {
3202+ greeting
3203+ }
3204+ ` ;
3205+
3206+ const client = new ApolloClient ( {
3207+ cache : new InMemoryCache ( {
3208+ typePolicies : {
3209+ Query : {
3210+ fields : {
3211+ greeting : {
3212+ read : ( existing : string | undefined ) =>
3213+ existing && existing . toUpperCase ( ) ,
3214+ } ,
3215+ } ,
3216+ } ,
3217+ } ,
3218+ } ) ,
3219+ link : new MockLink ( [
3220+ {
3221+ request : { query } ,
3222+ result : { data : { greeting : "hello" } } ,
3223+ delay : 20 ,
3224+ maxUsageCount : Number . POSITIVE_INFINITY ,
3225+ } ,
3226+ ] ) ,
3227+ } ) ;
3228+
3229+ const observable = client . watchQuery ( { query, pollInterval : 10 } ) ;
3230+ const stream = new ObservableStream ( observable ) ;
3231+
3232+ await expect ( stream ) . toEmitTypedValue ( {
3233+ data : undefined ,
3234+ dataState : "empty" ,
3235+ loading : true ,
3236+ networkStatus : NetworkStatus . loading ,
3237+ partial : true ,
3238+ } ) ;
3239+
3240+ await expect ( stream ) . toEmitTypedValue ( {
3241+ data : { greeting : "HELLO" } ,
3242+ dataState : "complete" ,
3243+ loading : false ,
3244+ networkStatus : NetworkStatus . ready ,
3245+ partial : false ,
3246+ } ) ;
3247+
3248+ await expect ( stream ) . toEmitTypedValue ( {
3249+ data : { greeting : "HELLO" } ,
3250+ dataState : "complete" ,
3251+ loading : true ,
3252+ networkStatus : NetworkStatus . poll ,
3253+ partial : false ,
3254+ } ) ;
3255+
3256+ // The polled result is `hello` again, identical to what this query last
3257+ // wrote, so the cache write is skipped. The emitted result still comes from
3258+ // the cache, so the `read` function is applied instead of delivering the
3259+ // raw network value.
3260+ await expect ( stream ) . toEmitTypedValue ( {
3261+ data : { greeting : "HELLO" } ,
3262+ dataState : "complete" ,
3263+ loading : false ,
3264+ networkStatus : NetworkStatus . ready ,
3265+ partial : false ,
3266+ } ) ;
3267+
3268+ observable . stopPolling ( ) ;
3269+
3270+ await expect ( stream ) . not . toEmitAnything ( ) ;
3271+ } ) ;
3272+
31213273 it ( "should not error when replacing unidentified data with a normalized ID" , async ( ) => {
31223274 const queryWithoutId = gql `
31233275 query {
0 commit comments