forked from dotnet/aspnetcore
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVirtualizationCspTest.cs
More file actions
147 lines (120 loc) · 6.48 KB
/
Copy pathVirtualizationCspTest.cs
File metadata and controls
147 lines (120 loc) · 6.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using BasicTestApp;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
using Microsoft.AspNetCore.E2ETesting;
using OpenQA.Selenium;
using TestServer;
using Xunit.Abstractions;
namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests;
public class VirtualizationCspTest : ServerTestBase<BasicTestAppServerSiteFixture<ServerStartup>>
{
public VirtualizationCspTest(
BrowserFixture browserFixture,
BasicTestAppServerSiteFixture<ServerStartup> serverFixture,
ITestOutputHelper output)
: base(browserFixture, serverFixture, output)
{
}
[Fact]
public void Virtualize_WithItems_DoesNotViolate_StrictStyleCspPolicy()
{
// strict-style-csp causes ServerStartup to add `Content-Security-Policy: style-src 'self'`.
Navigate($"{ServerPathBase}?strict-style-csp=true");
Browser.MountTestComponent<VirtualizationCsp>();
var container = Browser.Exists(By.Id("csp-container"));
Browser.True(() => container.FindElements(By.CssSelector(".csp-item")).Count > 0);
// Scroll to force spacer style updates which set CSS custom properties via CSSOM.
var js = (IJavaScriptExecutor)Browser;
js.ExecuteScript("document.getElementById('csp-container').scrollTop = 5000;");
// Allow the MutationObserver microtask + CSSOM updates to flush.
Browser.True(() =>
{
var topSpacer = container.FindElements(By.CssSelector(":scope > div"))[0];
var height = topSpacer.GetDomAttribute("data-blazor-virtualize-reserved-height");
return height != null && height != "0";
});
AssertNoStyleCspViolations();
}
[Fact]
public void Virtualize_WithItemsProvider_DoesNotViolate_StrictStyleCspPolicy()
{
// strict-style-csp causes ServerStartup to add `Content-Security-Policy: style-src 'self'`.
Navigate($"{ServerPathBase}?strict-style-csp=true&mode=items-provider");
Browser.MountTestComponent<VirtualizationCsp>();
var container = Browser.Exists(By.Id("csp-container-async"));
// Wait for either placeholders (during in-flight load) or resolved items.
Browser.True(() => container.FindElements(
By.CssSelector(".csp-placeholder, .csp-item-async")).Count > 0);
// Scroll to trigger new placeholder renders and spacer style updates.
var js = (IJavaScriptExecutor)Browser;
js.ExecuteScript("document.getElementById('csp-container-async').scrollTop = 5000;");
// Wait for resolved items after scroll so the placeholder path has executed.
Browser.True(() => container.FindElements(By.CssSelector(".csp-item-async")).Count > 0);
AssertNoStyleCspViolations();
}
[Theory]
[InlineData("url(https://example.invalid/x.png)")] // non-numeric, CSS-like
[InlineData("120px")] // a unit suffix is no longer accepted
[InlineData("abc")] // non-numeric
[InlineData("1e9999")] // overflows to Infinity (not finite)
[InlineData("NaN")] // non-finite
[InlineData("1 2")] // multi-token
[InlineData("")] // empty
public void Virtualize_RejectsUnexpectedLayoutAttributeValues(string invalidValue)
{
// Values that don't parse as a finite number must not propagate to CSS custom properties.
Navigate($"{ServerPathBase}?strict-style-csp=true");
Browser.MountTestComponent<VirtualizationCsp>();
var container = Browser.Exists(By.Id("csp-container"));
Browser.True(() => container.FindElements(By.CssSelector(".csp-item")).Count > 0);
var js = (IJavaScriptExecutor)Browser;
const string spacerSelector = "#csp-container > div:first-of-type";
js.ExecuteScript(
"var el = document.querySelector(arguments[0]);" +
"el.setAttribute('data-blazor-virtualize-reserved-height', arguments[1]);" +
"el.setAttribute('data-blazor-virtualize-loop-breaker-transform', arguments[1]);",
spacerSelector, invalidValue);
// Invalid values must result in the inline style being removed (empty).
Browser.True(() =>
{
var heightStyle = (string)js.ExecuteScript(
"return document.querySelector(arguments[0]).style.height;",
spacerSelector);
var transformStyle = (string)js.ExecuteScript(
"return document.querySelector(arguments[0]).style.transform;",
spacerSelector);
return heightStyle == "" && transformStyle == "";
});
AssertNoStyleCspViolations();
}
[Fact]
public void QuickGrid_WithVirtualize_DoesNotViolate_StrictStyleCspPolicy()
{
// QuickGrid uses Virtualize internally. Validates the integration is CSP-clean end-to-end.
Navigate($"{ServerPathBase}?strict-style-csp=true");
Browser.MountTestComponent<BasicTestApp.QuickGridTest.QuickGridCsp>();
var container = Browser.Exists(By.Id("csp-quickgrid"));
// Wait for QuickGrid to render at least one data row.
Browser.True(() => container.FindElements(By.CssSelector("tbody tr")).Count > 0);
// Scroll to force spacer style updates which set CSS custom properties via CSSOM.
var js = (IJavaScriptExecutor)Browser;
js.ExecuteScript("document.getElementById('csp-quickgrid').scrollTop = 20000;");
// Wait for the top spacer's reserved-height attribute to grow past 0 after scrolling.
Browser.True(() =>
{
var spacers = container.FindElements(By.CssSelector("[data-blazor-virtualize-reserved-height]"));
return spacers.Count > 0
&& spacers[0].GetDomAttribute("data-blazor-virtualize-reserved-height") != "0";
});
AssertNoStyleCspViolations();
}
private void AssertNoStyleCspViolations()
{
const string cspErrorMessage = "violates the following Content Security Policy directive: \"style-src";
var logs = Browser.Manage().Logs.GetLog(LogType.Browser);
var styleErrors = logs.Where(log => log.Message.Contains(cspErrorMessage)).ToList();
Assert.Empty(styleErrors);
}
}