3
3
4
4
using System ;
5
5
using System . Collections . Generic ;
6
+ using System . Linq ;
6
7
using System . Threading . Tasks ;
7
8
using Microsoft . AspNetCore . Components . Rendering ;
8
9
using Microsoft . AspNetCore . Components . Test . Helpers ;
9
10
using Microsoft . AspNetCore . Components . Web ;
11
+ using Microsoft . Extensions . DependencyInjection ;
12
+ using Microsoft . JSInterop ;
13
+ using Moq ;
10
14
using Xunit ;
11
15
12
16
namespace Microsoft . AspNetCore . Components . Virtualization
13
17
{
14
18
public class VirtualizeTest
15
19
{
16
- // TODO: Functional tests.
17
20
[ Fact ]
18
- public void Virtualize_ThrowsWhenGivenNonPositiveItemSize ( )
21
+ public async void Virtualize_ThrowsWhenGivenNonPositiveItemSize ( )
19
22
{
20
23
var rootComponent = new VirtualizeTestHostcomponent
21
24
{
22
- InnerContent = BuildVirtualize (
23
- i => builder => { } ,
24
- null ,
25
- context => builder => { } ,
26
- 0f ,
27
- null ,
28
- new List < int > ( ) )
25
+ InnerContent = BuildVirtualize ( 0f , EmptyItemsProvider < int > , null )
29
26
} ;
30
27
31
- var testRenderer = new TestRenderer ( ) ;
28
+ var serviceProvider = new ServiceCollection ( )
29
+ . AddTransient ( ( sp ) => Mock . Of < IJSRuntime > ( ) )
30
+ . BuildServiceProvider ( ) ;
31
+
32
+ var testRenderer = new TestRenderer ( serviceProvider ) ;
33
+ var componentId = testRenderer . AssignRootComponentId ( rootComponent ) ;
34
+
35
+ var ex = await Assert . ThrowsAsync < InvalidOperationException > ( async ( ) => await testRenderer . RenderRootComponentAsync ( componentId ) ) ;
36
+ Assert . Contains ( "requires a positive value for parameter" , ex . Message ) ;
37
+ }
38
+
39
+ [ Fact ]
40
+ public async void Virtualize_ThrowsWhenGivenMultipleItemSources ( )
41
+ {
42
+ var rootComponent = new VirtualizeTestHostcomponent
43
+ {
44
+ InnerContent = BuildVirtualize ( 10f , EmptyItemsProvider < int > , new List < int > ( ) )
45
+ } ;
46
+
47
+ var serviceProvider = new ServiceCollection ( )
48
+ . AddTransient ( ( sp ) => Mock . Of < IJSRuntime > ( ) )
49
+ . BuildServiceProvider ( ) ;
50
+
51
+ var testRenderer = new TestRenderer ( serviceProvider ) ;
52
+ var componentId = testRenderer . AssignRootComponentId ( rootComponent ) ;
53
+
54
+ var ex = await Assert . ThrowsAsync < InvalidOperationException > ( async ( ) => await testRenderer . RenderRootComponentAsync ( componentId ) ) ;
55
+ Assert . Contains ( "can only accept one item source from its parameters" , ex . Message ) ;
56
+ }
57
+
58
+ [ Fact ]
59
+ public async void Virtualize_ThrowsWhenGivenNoItemSources ( )
60
+ {
61
+ var rootComponent = new VirtualizeTestHostcomponent
62
+ {
63
+ InnerContent = BuildVirtualize < int > ( 10f , null , null )
64
+ } ;
65
+
66
+ var serviceProvider = new ServiceCollection ( )
67
+ . AddTransient ( ( sp ) => Mock . Of < IJSRuntime > ( ) )
68
+ . BuildServiceProvider ( ) ;
69
+
70
+ var testRenderer = new TestRenderer ( serviceProvider ) ;
71
+ var componentId = testRenderer . AssignRootComponentId ( rootComponent ) ;
72
+
73
+ var ex = await Assert . ThrowsAsync < InvalidOperationException > ( async ( ) => await testRenderer . RenderRootComponentAsync ( componentId ) ) ;
74
+ Assert . Contains ( "parameters to be specified and non-null" , ex . Message ) ;
75
+ }
76
+
77
+ [ Fact ]
78
+ public async void Virtualize_DispatchesExceptionsFromItemsProviderThroughRenderer ( )
79
+ {
80
+ Virtualize < int > renderedVirtualize = null ;
81
+
82
+ var rootComponent = new VirtualizeTestHostcomponent
83
+ {
84
+ InnerContent = BuildVirtualize ( 10f , AlwaysThrowsItemsProvider < int > , null , virtualize => renderedVirtualize = virtualize )
85
+ } ;
86
+
87
+ var serviceProvider = new ServiceCollection ( )
88
+ . AddTransient ( ( sp ) => Mock . Of < IJSRuntime > ( ) )
89
+ . BuildServiceProvider ( ) ;
90
+
91
+ var testRenderer = new TestRenderer ( serviceProvider ) ;
32
92
var componentId = testRenderer . AssignRootComponentId ( rootComponent ) ;
33
93
34
- var ex = Assert . Throws < InvalidOperationException > ( ( ) => testRenderer . RenderRootComponent ( componentId ) ) ;
94
+ // Render to populate the component reference.
95
+ await testRenderer . RenderRootComponentAsync ( componentId ) ;
96
+
97
+ Assert . NotNull ( renderedVirtualize ) ;
98
+
99
+ // Simulate a JS spacer callback.
100
+ ( ( IVirtualizeJsCallbacks ) renderedVirtualize ) . OnAfterSpacerVisible ( 10f , 100f ) ;
101
+
102
+ // Validate that the exception is dispatched through the renderer.
103
+ var ex = await Assert . ThrowsAsync < InvalidOperationException > ( async ( ) => await testRenderer . RenderRootComponentAsync ( componentId ) ) ;
104
+ Assert . Equal ( "Thrown from items provider." , ex . Message ) ;
35
105
}
36
106
37
- public RenderFragment BuildVirtualize < TItem > (
38
- RenderFragment < TItem > childContent ,
39
- RenderFragment < TItem > item ,
40
- RenderFragment < PlaceholderContext > placeholder ,
107
+ private ValueTask < ItemsProviderResult < TItem > > EmptyItemsProvider < TItem > ( ItemsProviderRequest request )
108
+ => ValueTask . FromResult ( new ItemsProviderResult < TItem > ( Enumerable . Empty < TItem > ( ) , 0 ) ) ;
109
+
110
+ private ValueTask < ItemsProviderResult < TItem > > AlwaysThrowsItemsProvider < TItem > ( ItemsProviderRequest request )
111
+ => throw new InvalidOperationException ( "Thrown from items provider." ) ;
112
+
113
+ private RenderFragment BuildVirtualize < TItem > (
41
114
float itemSize ,
42
115
ItemsProviderDelegate < TItem > itemsProvider ,
43
- ICollection < TItem > items )
116
+ ICollection < TItem > items ,
117
+ Action < Virtualize < TItem > > captureRenderedVirtualize = null )
44
118
=> builder =>
45
119
{
46
120
builder . OpenComponent < Virtualize < TItem > > ( 0 ) ;
47
- builder . AddAttribute ( 1 , "ChildContent" , childContent ) ;
48
- builder . AddAttribute ( 2 , "Item" , item ) ;
49
- builder . AddAttribute ( 3 , "Placeholder" , placeholder ) ;
50
- builder . AddAttribute ( 4 , "ItemSize" , itemSize ) ;
51
- builder . AddAttribute ( 5 , "ItemsProvider" , itemsProvider ) ;
52
- builder . AddAttribute ( 6 , "Items" , items ) ;
121
+ builder . AddAttribute ( 1 , "ItemSize" , itemSize ) ;
122
+ builder . AddAttribute ( 2 , "ItemsProvider" , itemsProvider ) ;
123
+ builder . AddAttribute ( 3 , "Items" , items ) ;
124
+
125
+ if ( captureRenderedVirtualize != null )
126
+ {
127
+ builder . AddComponentReferenceCapture ( 4 , component => captureRenderedVirtualize ( component as Virtualize < TItem > ) ) ;
128
+ }
129
+
53
130
builder . CloseComponent ( ) ;
54
131
} ;
55
132
@@ -61,7 +138,7 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
61
138
{
62
139
builder . OpenElement ( 0 , "div" ) ;
63
140
builder . AddAttribute ( 1 , "style" , "overflow: auto; height: 800px;" ) ;
64
- builder . AddAttribute ( 2 , "ChildContent" , InnerContent ) ;
141
+ builder . AddContent ( 2 , InnerContent ) ;
65
142
builder . CloseElement ( ) ;
66
143
}
67
144
}
0 commit comments