@@ -2537,7 +2537,6 @@ async def reports_one_cached_shared_failure_when_a_nested_fragment_is_announced(
25372537 },
25382538 ]
25392539
2540- @pytest .mark .xfail (strict = True , reason = "lost shared result" )
25412540 @pytest .mark .parametrize ("early_execution" , [False , True ])
25422541 async def delivers_a_buffered_shared_value_after_its_other_fragment_fails (
25432542 early_execution ,
@@ -2612,9 +2611,300 @@ async def delivers_a_buffered_shared_value_after_its_other_fragment_fails(
26122611 "hasNext" : False ,
26132612 }
26142613
2615- with pytest .raises (StopAsyncIteration ): # pragma: no cover
2614+ with pytest .raises (StopAsyncIteration ):
2615+ await anext (iterator )
2616+
2617+ async def delivers_a_shared_value_before_another_fragment_finishes_its_field ():
2618+ """Delivers a shared value before another fragment finishes its field
2619+
2620+ Delivers a shared value before another fragment finishes its separate field.
2621+ """
2622+ document = parse (
2623+ """
2624+ {
2625+ hero {
2626+ ... @defer(label: "R") {
2627+ nonNullName
2628+ id
2629+ }
2630+ ... @defer(label: "P") {
2631+ name
2632+ ... @defer(label: "C") {
2633+ id
2634+ }
2635+ }
2636+ }
2637+ }
2638+ """
2639+ )
2640+ name_future : Future [str ] = Future ()
2641+ non_null_name_future : Future [str ] = Future ()
2642+
2643+ result = experimental_execute_incrementally (
2644+ schema ,
2645+ document ,
2646+ {
2647+ "hero" : {
2648+ "id" : 1 ,
2649+ "name" : name_future ,
2650+ "nonNullName" : non_null_name_future ,
2651+ }
2652+ },
2653+ )
2654+ assert isinstance (result , ExperimentalIncrementalExecutionResults )
2655+
2656+ assert result .initial_result .formatted == {
2657+ "data" : {"hero" : {}},
2658+ "pending" : [
2659+ {"id" : "0" , "path" : ["hero" ], "label" : "R" },
2660+ {"id" : "1" , "path" : ["hero" ], "label" : "P" },
2661+ ],
2662+ "hasNext" : True ,
2663+ }
2664+
2665+ iterator = result .subsequent_results
2666+
2667+ name_future .set_result ("Luke" )
2668+
2669+ assert (await anext (iterator )).formatted == {
2670+ "pending" : [{"id" : "2" , "path" : ["hero" ], "label" : "C" }],
2671+ "incremental" : [
2672+ {"data" : {"name" : "Luke" }, "id" : "1" },
2673+ {"data" : {"id" : "1" }, "id" : "2" },
2674+ ],
2675+ "completed" : [{"id" : "1" }, {"id" : "2" }],
2676+ "hasNext" : True ,
2677+ }
2678+
2679+ non_null_name_future .set_result ("Luke" )
2680+
2681+ assert (await anext (iterator )).formatted == {
2682+ "incremental" : [{"data" : {"nonNullName" : "Luke" }, "id" : "0" }],
2683+ "completed" : [{"id" : "0" }],
2684+ "hasNext" : False ,
2685+ }
2686+
2687+ with pytest .raises (StopAsyncIteration ):
2688+ await anext (iterator )
2689+
2690+ async def delivers_shared_child_data_when_second_parent_finishes_first ():
2691+ """Delivers shared child data when second parent finishes before first child
2692+
2693+ Delivers shared child data when the second parent finishes before the first
2694+ child.
2695+ """
2696+ document = parse (
2697+ """
2698+ {
2699+ hero {
2700+ ... @defer(label: "P1") {
2701+ name
2702+ ... @defer(label: "C1") {
2703+ id
2704+ friends { name }
2705+ }
2706+ }
2707+ ... @defer(label: "P2") {
2708+ nonNullName
2709+ ... @defer(label: "C2") {
2710+ id
2711+ }
2712+ }
2713+ }
2714+ }
2715+ """
2716+ )
2717+ name_future : Future [str ] = Future ()
2718+ friends_future : Future [list [Friend ]] = Future ()
2719+
2720+ result = experimental_execute_incrementally (
2721+ schema ,
2722+ document ,
2723+ {
2724+ "hero" : {
2725+ "id" : 1 ,
2726+ "name" : "Luke" ,
2727+ "nonNullName" : name_future ,
2728+ "friends" : friends_future ,
2729+ }
2730+ },
2731+ )
2732+ assert isinstance (result , ExperimentalIncrementalExecutionResults )
2733+
2734+ assert result .initial_result .formatted == {
2735+ "data" : {"hero" : {}},
2736+ "pending" : [
2737+ {"id" : "0" , "path" : ["hero" ], "label" : "P1" },
2738+ {"id" : "1" , "path" : ["hero" ], "label" : "P2" },
2739+ ],
2740+ "hasNext" : True ,
2741+ }
2742+
2743+ iterator = result .subsequent_results
2744+
2745+ assert (await anext (iterator )).formatted == {
2746+ "pending" : [{"id" : "2" , "path" : ["hero" ], "label" : "C1" }],
2747+ "incremental" : [{"data" : {"name" : "Luke" }, "id" : "0" }],
2748+ "completed" : [{"id" : "0" }],
2749+ "hasNext" : True ,
2750+ }
2751+
2752+ name_future .set_result ("Luke" )
2753+
2754+ assert (await anext (iterator )).formatted == {
2755+ "pending" : [{"id" : "3" , "path" : ["hero" ], "label" : "C2" }],
2756+ "incremental" : [
2757+ {"data" : {"nonNullName" : "Luke" }, "id" : "1" },
2758+ {"data" : {"id" : "1" }, "id" : "3" },
2759+ ],
2760+ "completed" : [{"id" : "1" }, {"id" : "3" }],
2761+ "hasNext" : True ,
2762+ }
2763+
2764+ friends_future .set_result (friends )
2765+
2766+ assert (await anext (iterator )).formatted == {
2767+ "incremental" : [
2768+ {
2769+ "data" : {
2770+ "friends" : [
2771+ {"name" : "Han" },
2772+ {"name" : "Leia" },
2773+ {"name" : "C-3PO" },
2774+ ]
2775+ },
2776+ "id" : "2" ,
2777+ },
2778+ ],
2779+ "completed" : [{"id" : "2" }],
2780+ "hasNext" : False ,
2781+ }
2782+
2783+ with pytest .raises (StopAsyncIteration ):
26162784 await anext (iterator )
26172785
2786+ async def finishes_a_later_shared_owner_without_repeating_delivered_data ():
2787+ """Finishes a later shared owner without repeating data
2788+
2789+ Finishes a later shared owner without repeating data delivered after
2790+ another owner failed.
2791+ """
2792+ document = parse (
2793+ """
2794+ {
2795+ hero {
2796+ ... @defer(label: "R") {
2797+ nonNullName
2798+ id
2799+ }
2800+ ... @defer(label: "P1") {
2801+ name
2802+ ... @defer(label: "C1") {
2803+ id
2804+ }
2805+ }
2806+ ... @defer(label: "P2") {
2807+ nestedObject { name }
2808+ ... @defer(label: "C2") {
2809+ id
2810+ friends { name }
2811+ }
2812+ }
2813+ }
2814+ }
2815+ """
2816+ )
2817+ name_future : Future [str ] = Future ()
2818+ object_future : Future [dict [str , str ]] = Future ()
2819+ id_calls = 0
2820+
2821+ def id_ (_info ):
2822+ nonlocal id_calls
2823+ id_calls += 1
2824+ return 1
2825+
2826+ result = experimental_execute_incrementally (
2827+ schema ,
2828+ document ,
2829+ {
2830+ "hero" : {
2831+ "id" : id_ ,
2832+ "name" : name_future ,
2833+ "nonNullName" : None ,
2834+ "nestedObject" : object_future ,
2835+ "friends" : friends ,
2836+ }
2837+ },
2838+ )
2839+ assert isinstance (result , ExperimentalIncrementalExecutionResults )
2840+
2841+ assert result .initial_result .formatted == {
2842+ "data" : {"hero" : {}},
2843+ "pending" : [
2844+ {"id" : "0" , "path" : ["hero" ], "label" : "R" },
2845+ {"id" : "1" , "path" : ["hero" ], "label" : "P1" },
2846+ {"id" : "2" , "path" : ["hero" ], "label" : "P2" },
2847+ ],
2848+ "hasNext" : True ,
2849+ }
2850+
2851+ iterator = result .subsequent_results
2852+
2853+ assert (await anext (iterator )).formatted == {
2854+ "completed" : [
2855+ {
2856+ "id" : "0" ,
2857+ "errors" : [
2858+ {
2859+ "message" : "Cannot return null"
2860+ " for non-nullable field Hero.nonNullName." ,
2861+ "locations" : [{"line" : 5 , "column" : 19 }],
2862+ "path" : ["hero" , "nonNullName" ],
2863+ },
2864+ ],
2865+ },
2866+ ],
2867+ "hasNext" : True ,
2868+ }
2869+
2870+ name_future .set_result ("Luke" )
2871+
2872+ assert (await anext (iterator )).formatted == {
2873+ "pending" : [{"id" : "3" , "path" : ["hero" ], "label" : "C1" }],
2874+ "incremental" : [
2875+ {"data" : {"name" : "Luke" }, "id" : "1" },
2876+ {"data" : {"id" : "1" }, "id" : "3" },
2877+ ],
2878+ "completed" : [{"id" : "1" }, {"id" : "3" }],
2879+ "hasNext" : True ,
2880+ }
2881+
2882+ object_future .set_result ({"name" : "parent" })
2883+
2884+ assert (await anext (iterator )).formatted == {
2885+ "pending" : [{"id" : "4" , "path" : ["hero" ], "label" : "C2" }],
2886+ "incremental" : [
2887+ {"data" : {"nestedObject" : {"name" : "parent" }}, "id" : "2" },
2888+ {
2889+ "data" : {
2890+ "friends" : [
2891+ {"name" : "Han" },
2892+ {"name" : "Leia" },
2893+ {"name" : "C-3PO" },
2894+ ]
2895+ },
2896+ "id" : "4" ,
2897+ },
2898+ ],
2899+ "completed" : [{"id" : "2" }, {"id" : "4" }],
2900+ "hasNext" : False ,
2901+ }
2902+
2903+ with pytest .raises (StopAsyncIteration ):
2904+ await anext (iterator )
2905+
2906+ assert id_calls == 1
2907+
26182908 async def handles_cancelling_child_deferred_fragments_if_parent_fragment_fails ():
26192909 """Handles cancelling child deferred fragments if parent fragment fails"""
26202910 document = parse (
0 commit comments