Skip to content

Commit d4d099f

Browse files
[flags] make enableTrustedTypesIntegration dynamic (#35646)
Co-authored-by: Rick Hanlon <rickhanlonii@meta.com>
1 parent c0c3706 commit d4d099f

8 files changed

Lines changed: 93 additions & 22 deletions

‎packages/react-dom/src/__tests__/ReactDOMAttribute-test.js‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,13 @@ describe('ReactDOM unknown attribute', () => {
171171
consttest=()=>
172172
testUnknownAttributeAssignment(newTemporalLike(),null);
173173

174-
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
174+
if(gate('enableTrustedTypesIntegration')&&!__DEV__){
175+
// TODO: this still throws in DEV even though it's not toString'd in prod.
176+
awaitexpect(test).rejects.toThrowError('2020-01-01');
177+
}else{
178+
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
179+
}
180+
175181
assertConsoleErrorDev([
176182
'The provided `unknown` attribute is an unsupported type TemporalLike.'+
177183
' This value must be coerced to a string before using it here.\n'+

‎packages/react-dom/src/__tests__/ReactDOMFloat-test.js‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,14 @@ describe('ReactDOMFloat', () => {
602602
'> <script href="foo">\n'+
603603
'\n'+
604604
' in script (at **)',
605+
...(gate('enableTrustedTypesIntegration')
606+
? [
607+
'Encountered a script tag while rendering React component. '+
608+
'Scripts inside React components are never executed when rendering on the client. '+
609+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
610+
' in script (at **)',
611+
]
612+
: []),
605613
]);
606614

607615
root.render(
@@ -2745,6 +2753,14 @@ body {
27452753
'> <script itemProp="foo">\n'+
27462754
'\n'+
27472755
' in script (at **)',
2756+
...(gate('enableTrustedTypesIntegration')
2757+
? [
2758+
'Encountered a script tag while rendering React component. '+
2759+
'Scripts inside React components are never executed when rendering on the client. '+
2760+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
2761+
' in script (at **)',
2762+
]
2763+
: []),
27482764
]);
27492765
});
27502766

‎packages/react-dom/src/__tests__/ReactDOMForm-test.js‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,15 +2277,21 @@ describe('ReactDOMForm', () => {
22772277
awaitsubmit(formRef.current);
22782278
assertLog([actionFn]);
22792279

2280-
// Everything else is toString-ed
2280+
// Everything else is toString-ed, unless trusted types are enabled.
22812281
classMyAction{
22822282
toString(){
22832283
return'stringified action';
22842284
}
22852285
}
2286-
awaitact(()=>root.render(<Formaction={newMyAction()}/>));
2286+
constinstance=newMyAction();
2287+
2288+
awaitact(()=>root.render(<Formaction={instance}/>));
22872289
awaitsubmit(formRef.current);
2288-
assertLog(['stringified action']);
2290+
assertLog(
2291+
gate('enableTrustedTypesIntegration')
2292+
? [instance]
2293+
: ['stringified action'],
2294+
);
22892295
});
22902296

22912297
it('form actions should retain status when nested state changes',async()=>{

‎packages/react-dom/src/__tests__/ReactDOMServerIntegrationUntrustedURL-test.js‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ describe('ReactDOMServerIntegration - Untrusted URLs', () => {
212212
expectedToStringCalls*=2;
213213
}
214214

215+
if(gate('enableTrustedTypesIntegration')&&render===clientCleanRender){
216+
// Trusted types does another toString.
217+
expectedToStringCalls+=1;
218+
}
219+
215220
lettoStringCalls=0;
216221
constfirstIsSafe={
217222
toString(){

‎packages/react-dom/src/__tests__/ReactEmptyComponent-test.js‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let TogglingComponent;
1717
letact;
1818
letScheduler;
1919
letassertLog;
20+
letassertConsoleErrorDev;
2021

2122
letcontainer;
2223

@@ -34,6 +35,7 @@ describe('ReactEmptyComponent', () => {
3435
constInternalTestUtils=require('internal-test-utils');
3536
act=InternalTestUtils.act;
3637
assertLog=InternalTestUtils.assertLog;
38+
assertConsoleErrorDev=InternalTestUtils.assertConsoleErrorDev;
3739

3840
container=document.createElement('div');
3941

@@ -175,6 +177,17 @@ describe('ReactEmptyComponent', () => {
175177
});
176178
}).not.toThrow();
177179

180+
expect(container.innerHTML).toBe('<script></script>');
181+
if(gate('enableTrustedTypesIntegration')){
182+
assertConsoleErrorDev([
183+
'Encountered a script tag while rendering React component. '+
184+
'Scripts inside React components are never executed when rendering on the client. '+
185+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
186+
' in script (at **)\n'+
187+
' in TogglingComponent (at **)',
188+
]);
189+
}
190+
178191
constcontainer2=document.createElement('div');
179192
constroot2=ReactDOMClient.createRoot(container2);
180193
expect(()=>{
@@ -189,6 +202,7 @@ describe('ReactEmptyComponent', () => {
189202
'mount SCRIPT',
190203
'update undefined',
191204
]);
205+
expect(container2.innerHTML).toBe('');
192206
});
193207

194208
it(

‎packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js‎

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
describe('when Trusted Types are available in global object',()=>{
1313
letReact;
1414
letReactDOMClient;
15-
letReactFeatureFlags;
1615
letact;
1716
letassertConsoleErrorDev;
1817
letcontainer;
@@ -33,8 +32,6 @@ describe('when Trusted Types are available in global object', () => {
3332
isScript: ()=>false,
3433
isScriptURL: ()=>false,
3534
};
36-
ReactFeatureFlags=require('shared/ReactFeatureFlags');
37-
ReactFeatureFlags.enableTrustedTypesIntegration=true;
3835
React=require('react');
3936
ReactDOMClient=require('react-dom/client');
4037
({act, assertConsoleErrorDev}=require('internal-test-utils'));
@@ -118,7 +115,11 @@ describe('when Trusted Types are available in global object', () => {
118115
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
119116
expect(setAttributeCalls[0][1]).toBe('data-foo');
120117
// Ensure it didn't get stringified when passed to a DOM sink:
121-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
118+
if(gate('enableTrustedTypesIntegration')){
119+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
120+
}else{
121+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
122+
}
122123

123124
setAttributeCalls.length=0;
124125
awaitact(()=>{
@@ -129,7 +130,11 @@ describe('when Trusted Types are available in global object', () => {
129130
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
130131
expect(setAttributeCalls[0][1]).toBe('data-foo');
131132
// Ensure it didn't get stringified when passed to a DOM sink:
132-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
133+
if(gate('enableTrustedTypesIntegration')){
134+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
135+
}else{
136+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
137+
}
133138
}finally{
134139
Element.prototype.setAttribute=setAttribute;
135140
}
@@ -153,7 +158,11 @@ describe('when Trusted Types are available in global object', () => {
153158
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
154159
expect(setAttributeCalls[0][1]).toBe('class');
155160
// Ensure it didn't get stringified when passed to a DOM sink:
156-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
161+
if(gate('enableTrustedTypesIntegration')){
162+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
163+
}else{
164+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
165+
}
157166

158167
setAttributeCalls.length=0;
159168
awaitact(()=>{
@@ -164,7 +173,11 @@ describe('when Trusted Types are available in global object', () => {
164173
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
165174
expect(setAttributeCalls[0][1]).toBe('class');
166175
// Ensure it didn't get stringified when passed to a DOM sink:
167-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
176+
if(gate('enableTrustedTypesIntegration')){
177+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
178+
}else{
179+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
180+
}
168181
}finally{
169182
Element.prototype.setAttribute=setAttribute;
170183
}
@@ -189,7 +202,11 @@ describe('when Trusted Types are available in global object', () => {
189202
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
190203
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
191204
// Ensure it didn't get stringified when passed to a DOM sink:
192-
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
205+
if(gate('enableTrustedTypesIntegration')){
206+
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
207+
}else{
208+
expect(setAttributeNSCalls[0][3]).toBe('<b>Hi</b>');
209+
}
193210

194211
setAttributeNSCalls.length=0;
195212
awaitact(()=>{
@@ -201,7 +218,11 @@ describe('when Trusted Types are available in global object', () => {
201218
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
202219
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
203220
// Ensure it didn't get stringified when passed to a DOM sink:
204-
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
221+
if(gate('enableTrustedTypesIntegration')){
222+
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
223+
}else{
224+
expect(setAttributeNSCalls[0][3]).toBe('<b>Bye</b>');
225+
}
205226
}finally{
206227
Element.prototype.setAttributeNS=setAttributeNS;
207228
}
@@ -212,13 +233,15 @@ describe('when Trusted Types are available in global object', () => {
212233
awaitact(()=>{
213234
root.render(<script>alert("I am not executed")</script>);
214235
});
215-
assertConsoleErrorDev([
216-
'Encountered a script tag while rendering React component. '+
217-
'Scripts inside React components are never executed when rendering '+
218-
'on the client. Consider using template tag instead '+
219-
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
220-
' in script (at **)',
221-
]);
236+
if(gate('enableTrustedTypesIntegration')){
237+
assertConsoleErrorDev([
238+
'Encountered a script tag while rendering React component. '+
239+
'Scripts inside React components are never executed when rendering '+
240+
'on the client. Consider using template tag instead '+
241+
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
242+
' in script (at **)',
243+
]);
244+
}
222245

223246
// check that the warning is printed only once
224247
awaitact(()=>{

‎packages/shared/CheckStringCoercion.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ export function checkAttributeStringCoercion(
7676
attributeName: string,
7777
): void|string{
7878
if(__DEV__){
79+
// TODO: for enableTrustedTypesIntegration we don't toString this
80+
// so we shouldn't need the DEV warning.
7981
if(willCoercionThrow(value)){
8082
console.error(
8183
'The provided `%s` attribute is an unsupported type %s.'+

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@ export const enableScrollEndPolyfill: boolean = __VARIANT__;
3535
exportconstenableFragmentRefs: boolean=__VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableAsyncDebugInfo: boolean=__VARIANT__;
38-
3938
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39+
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4040

4141
// TODO: These flags are hard-coded to the default values used in open source.
4242
// Update the tests so that they pass in either mode, then set these
4343
// to __VARIANT__.
44-
exportconstenableTrustedTypesIntegration: boolean=false;
4544
// You probably *don't* want to add more hardcoded ones.
4645
// Instead, try to add them above with the __VARIANT__ value.

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
[flags] make `enableTrustedTypesIntegration` dynamic (#35646) · react/react@d4d099f · GitHub
Skip to content

Commit d4d099f

Browse files
[flags] make enableTrustedTypesIntegration dynamic (#35646)
Co-authored-by: Rick Hanlon <rickhanlonii@meta.com>
1 parent c0c3706 commit d4d099f

8 files changed

Lines changed: 93 additions & 22 deletions

‎packages/react-dom/src/__tests__/ReactDOMAttribute-test.js‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,13 @@ describe('ReactDOM unknown attribute', () => {
171171
consttest=()=>
172172
testUnknownAttributeAssignment(newTemporalLike(),null);
173173

174-
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
174+
if(gate('enableTrustedTypesIntegration')&&!__DEV__){
175+
// TODO: this still throws in DEV even though it's not toString'd in prod.
176+
awaitexpect(test).rejects.toThrowError('2020-01-01');
177+
}else{
178+
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
179+
}
180+
175181
assertConsoleErrorDev([
176182
'The provided `unknown` attribute is an unsupported type TemporalLike.'+
177183
' This value must be coerced to a string before using it here.\n'+

‎packages/react-dom/src/__tests__/ReactDOMFloat-test.js‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,14 @@ describe('ReactDOMFloat', () => {
602602
'> <script href="foo">\n'+
603603
'\n'+
604604
' in script (at **)',
605+
...(gate('enableTrustedTypesIntegration')
606+
? [
607+
'Encountered a script tag while rendering React component. '+
608+
'Scripts inside React components are never executed when rendering on the client. '+
609+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
610+
' in script (at **)',
611+
]
612+
: []),
605613
]);
606614

607615
root.render(
@@ -2745,6 +2753,14 @@ body {
27452753
'> <script itemProp="foo">\n'+
27462754
'\n'+
27472755
' in script (at **)',
2756+
...(gate('enableTrustedTypesIntegration')
2757+
? [
2758+
'Encountered a script tag while rendering React component. '+
2759+
'Scripts inside React components are never executed when rendering on the client. '+
2760+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
2761+
' in script (at **)',
2762+
]
2763+
: []),
27482764
]);
27492765
});
27502766

‎packages/react-dom/src/__tests__/ReactDOMForm-test.js‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,15 +2277,21 @@ describe('ReactDOMForm', () => {
22772277
awaitsubmit(formRef.current);
22782278
assertLog([actionFn]);
22792279

2280-
// Everything else is toString-ed
2280+
// Everything else is toString-ed, unless trusted types are enabled.
22812281
classMyAction{
22822282
toString(){
22832283
return'stringified action';
22842284
}
22852285
}
2286-
awaitact(()=>root.render(<Formaction={newMyAction()}/>));
2286+
constinstance=newMyAction();
2287+
2288+
awaitact(()=>root.render(<Formaction={instance}/>));
22872289
awaitsubmit(formRef.current);
2288-
assertLog(['stringified action']);
2290+
assertLog(
2291+
gate('enableTrustedTypesIntegration')
2292+
? [instance]
2293+
: ['stringified action'],
2294+
);
22892295
});
22902296

22912297
it('form actions should retain status when nested state changes',async()=>{

‎packages/react-dom/src/__tests__/ReactDOMServerIntegrationUntrustedURL-test.js‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ describe('ReactDOMServerIntegration - Untrusted URLs', () => {
212212
expectedToStringCalls*=2;
213213
}
214214

215+
if(gate('enableTrustedTypesIntegration')&&render===clientCleanRender){
216+
// Trusted types does another toString.
217+
expectedToStringCalls+=1;
218+
}
219+
215220
lettoStringCalls=0;
216221
constfirstIsSafe={
217222
toString(){

‎packages/react-dom/src/__tests__/ReactEmptyComponent-test.js‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let TogglingComponent;
1717
letact;
1818
letScheduler;
1919
letassertLog;
20+
letassertConsoleErrorDev;
2021

2122
letcontainer;
2223

@@ -34,6 +35,7 @@ describe('ReactEmptyComponent', () => {
3435
constInternalTestUtils=require('internal-test-utils');
3536
act=InternalTestUtils.act;
3637
assertLog=InternalTestUtils.assertLog;
38+
assertConsoleErrorDev=InternalTestUtils.assertConsoleErrorDev;
3739

3840
container=document.createElement('div');
3941

@@ -175,6 +177,17 @@ describe('ReactEmptyComponent', () => {
175177
});
176178
}).not.toThrow();
177179

180+
expect(container.innerHTML).toBe('<script></script>');
181+
if(gate('enableTrustedTypesIntegration')){
182+
assertConsoleErrorDev([
183+
'Encountered a script tag while rendering React component. '+
184+
'Scripts inside React components are never executed when rendering on the client. '+
185+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
186+
' in script (at **)\n'+
187+
' in TogglingComponent (at **)',
188+
]);
189+
}
190+
178191
constcontainer2=document.createElement('div');
179192
constroot2=ReactDOMClient.createRoot(container2);
180193
expect(()=>{
@@ -189,6 +202,7 @@ describe('ReactEmptyComponent', () => {
189202
'mount SCRIPT',
190203
'update undefined',
191204
]);
205+
expect(container2.innerHTML).toBe('');
192206
});
193207

194208
it(

‎packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js‎

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
describe('when Trusted Types are available in global object',()=>{
1313
letReact;
1414
letReactDOMClient;
15-
letReactFeatureFlags;
1615
letact;
1716
letassertConsoleErrorDev;
1817
letcontainer;
@@ -33,8 +32,6 @@ describe('when Trusted Types are available in global object', () => {
3332
isScript: ()=>false,
3433
isScriptURL: ()=>false,
3534
};
36-
ReactFeatureFlags=require('shared/ReactFeatureFlags');
37-
ReactFeatureFlags.enableTrustedTypesIntegration=true;
3835
React=require('react');
3936
ReactDOMClient=require('react-dom/client');
4037
({act, assertConsoleErrorDev}=require('internal-test-utils'));
@@ -118,7 +115,11 @@ describe('when Trusted Types are available in global object', () => {
118115
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
119116
expect(setAttributeCalls[0][1]).toBe('data-foo');
120117
// Ensure it didn't get stringified when passed to a DOM sink:
121-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
118+
if(gate('enableTrustedTypesIntegration')){
119+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
120+
}else{
121+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
122+
}
122123

123124
setAttributeCalls.length=0;
124125
awaitact(()=>{
@@ -129,7 +130,11 @@ describe('when Trusted Types are available in global object', () => {
129130
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
130131
expect(setAttributeCalls[0][1]).toBe('data-foo');
131132
// Ensure it didn't get stringified when passed to a DOM sink:
132-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
133+
if(gate('enableTrustedTypesIntegration')){
134+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
135+
}else{
136+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
137+
}
133138
}finally{
134139
Element.prototype.setAttribute=setAttribute;
135140
}
@@ -153,7 +158,11 @@ describe('when Trusted Types are available in global object', () => {
153158
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
154159
expect(setAttributeCalls[0][1]).toBe('class');
155160
// Ensure it didn't get stringified when passed to a DOM sink:
156-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
161+
if(gate('enableTrustedTypesIntegration')){
162+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
163+
}else{
164+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
165+
}
157166

158167
setAttributeCalls.length=0;
159168
awaitact(()=>{
@@ -164,7 +173,11 @@ describe('when Trusted Types are available in global object', () => {
164173
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
165174
expect(setAttributeCalls[0][1]).toBe('class');
166175
// Ensure it didn't get stringified when passed to a DOM sink:
167-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
176+
if(gate('enableTrustedTypesIntegration')){
177+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
178+
}else{
179+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
180+
}
168181
}finally{
169182
Element.prototype.setAttribute=setAttribute;
170183
}
@@ -189,7 +202,11 @@ describe('when Trusted Types are available in global object', () => {
189202
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
190203
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
191204
// Ensure it didn't get stringified when passed to a DOM sink:
192-
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
205+
if(gate('enableTrustedTypesIntegration')){
206+
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
207+
}else{
208+
expect(setAttributeNSCalls[0][3]).toBe('<b>Hi</b>');
209+
}
193210

194211
setAttributeNSCalls.length=0;
195212
awaitact(()=>{
@@ -201,7 +218,11 @@ describe('when Trusted Types are available in global object', () => {
201218
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
202219
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
203220
// Ensure it didn't get stringified when passed to a DOM sink:
204-
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
221+
if(gate('enableTrustedTypesIntegration')){
222+
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
223+
}else{
224+
expect(setAttributeNSCalls[0][3]).toBe('<b>Bye</b>');
225+
}
205226
}finally{
206227
Element.prototype.setAttributeNS=setAttributeNS;
207228
}
@@ -212,13 +233,15 @@ describe('when Trusted Types are available in global object', () => {
212233
awaitact(()=>{
213234
root.render(<script>alert("I am not executed")</script>);
214235
});
215-
assertConsoleErrorDev([
216-
'Encountered a script tag while rendering React component. '+
217-
'Scripts inside React components are never executed when rendering '+
218-
'on the client. Consider using template tag instead '+
219-
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
220-
' in script (at **)',
221-
]);
236+
if(gate('enableTrustedTypesIntegration')){
237+
assertConsoleErrorDev([
238+
'Encountered a script tag while rendering React component. '+
239+
'Scripts inside React components are never executed when rendering '+
240+
'on the client. Consider using template tag instead '+
241+
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
242+
' in script (at **)',
243+
]);
244+
}
222245

223246
// check that the warning is printed only once
224247
awaitact(()=>{

‎packages/shared/CheckStringCoercion.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ export function checkAttributeStringCoercion(
7676
attributeName: string,
7777
): void|string{
7878
if(__DEV__){
79+
// TODO: for enableTrustedTypesIntegration we don't toString this
80+
// so we shouldn't need the DEV warning.
7981
if(willCoercionThrow(value)){
8082
console.error(
8183
'The provided `%s` attribute is an unsupported type %s.'+

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@ export const enableScrollEndPolyfill: boolean = __VARIANT__;
3535
exportconstenableFragmentRefs: boolean=__VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableAsyncDebugInfo: boolean=__VARIANT__;
38-
3938
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39+
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4040

4141
// TODO: These flags are hard-coded to the default values used in open source.
4242
// Update the tests so that they pass in either mode, then set these
4343
// to __VARIANT__.
44-
exportconstenableTrustedTypesIntegration: boolean=false;
4544
// You probably *don't* want to add more hardcoded ones.
4645
// Instead, try to add them above with the __VARIANT__ value.

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [flags] make `enableTrustedTypesIntegration` dynamic (#35646) · react/react@d4d099f · GitHub
Skip to content

Commit d4d099f

Browse files
[flags] make enableTrustedTypesIntegration dynamic (#35646)
Co-authored-by: Rick Hanlon <rickhanlonii@meta.com>
1 parent c0c3706 commit d4d099f

8 files changed

Lines changed: 93 additions & 22 deletions

‎packages/react-dom/src/__tests__/ReactDOMAttribute-test.js‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,13 @@ describe('ReactDOM unknown attribute', () => {
171171
consttest=()=>
172172
testUnknownAttributeAssignment(newTemporalLike(),null);
173173

174-
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
174+
if(gate('enableTrustedTypesIntegration')&&!__DEV__){
175+
// TODO: this still throws in DEV even though it's not toString'd in prod.
176+
awaitexpect(test).rejects.toThrowError('2020-01-01');
177+
}else{
178+
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
179+
}
180+
175181
assertConsoleErrorDev([
176182
'The provided `unknown` attribute is an unsupported type TemporalLike.'+
177183
' This value must be coerced to a string before using it here.\n'+

‎packages/react-dom/src/__tests__/ReactDOMFloat-test.js‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,14 @@ describe('ReactDOMFloat', () => {
602602
'> <script href="foo">\n'+
603603
'\n'+
604604
' in script (at **)',
605+
...(gate('enableTrustedTypesIntegration')
606+
? [
607+
'Encountered a script tag while rendering React component. '+
608+
'Scripts inside React components are never executed when rendering on the client. '+
609+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
610+
' in script (at **)',
611+
]
612+
: []),
605613
]);
606614

607615
root.render(
@@ -2745,6 +2753,14 @@ body {
27452753
'> <script itemProp="foo">\n'+
27462754
'\n'+
27472755
' in script (at **)',
2756+
...(gate('enableTrustedTypesIntegration')
2757+
? [
2758+
'Encountered a script tag while rendering React component. '+
2759+
'Scripts inside React components are never executed when rendering on the client. '+
2760+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
2761+
' in script (at **)',
2762+
]
2763+
: []),
27482764
]);
27492765
});
27502766

‎packages/react-dom/src/__tests__/ReactDOMForm-test.js‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,15 +2277,21 @@ describe('ReactDOMForm', () => {
22772277
awaitsubmit(formRef.current);
22782278
assertLog([actionFn]);
22792279

2280-
// Everything else is toString-ed
2280+
// Everything else is toString-ed, unless trusted types are enabled.
22812281
classMyAction{
22822282
toString(){
22832283
return'stringified action';
22842284
}
22852285
}
2286-
awaitact(()=>root.render(<Formaction={newMyAction()}/>));
2286+
constinstance=newMyAction();
2287+
2288+
awaitact(()=>root.render(<Formaction={instance}/>));
22872289
awaitsubmit(formRef.current);
2288-
assertLog(['stringified action']);
2290+
assertLog(
2291+
gate('enableTrustedTypesIntegration')
2292+
? [instance]
2293+
: ['stringified action'],
2294+
);
22892295
});
22902296

22912297
it('form actions should retain status when nested state changes',async()=>{

‎packages/react-dom/src/__tests__/ReactDOMServerIntegrationUntrustedURL-test.js‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ describe('ReactDOMServerIntegration - Untrusted URLs', () => {
212212
expectedToStringCalls*=2;
213213
}
214214

215+
if(gate('enableTrustedTypesIntegration')&&render===clientCleanRender){
216+
// Trusted types does another toString.
217+
expectedToStringCalls+=1;
218+
}
219+
215220
lettoStringCalls=0;
216221
constfirstIsSafe={
217222
toString(){

‎packages/react-dom/src/__tests__/ReactEmptyComponent-test.js‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let TogglingComponent;
1717
letact;
1818
letScheduler;
1919
letassertLog;
20+
letassertConsoleErrorDev;
2021

2122
letcontainer;
2223

@@ -34,6 +35,7 @@ describe('ReactEmptyComponent', () => {
3435
constInternalTestUtils=require('internal-test-utils');
3536
act=InternalTestUtils.act;
3637
assertLog=InternalTestUtils.assertLog;
38+
assertConsoleErrorDev=InternalTestUtils.assertConsoleErrorDev;
3739

3840
container=document.createElement('div');
3941

@@ -175,6 +177,17 @@ describe('ReactEmptyComponent', () => {
175177
});
176178
}).not.toThrow();
177179

180+
expect(container.innerHTML).toBe('<script></script>');
181+
if(gate('enableTrustedTypesIntegration')){
182+
assertConsoleErrorDev([
183+
'Encountered a script tag while rendering React component. '+
184+
'Scripts inside React components are never executed when rendering on the client. '+
185+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
186+
' in script (at **)\n'+
187+
' in TogglingComponent (at **)',
188+
]);
189+
}
190+
178191
constcontainer2=document.createElement('div');
179192
constroot2=ReactDOMClient.createRoot(container2);
180193
expect(()=>{
@@ -189,6 +202,7 @@ describe('ReactEmptyComponent', () => {
189202
'mount SCRIPT',
190203
'update undefined',
191204
]);
205+
expect(container2.innerHTML).toBe('');
192206
});
193207

194208
it(

‎packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js‎

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
describe('when Trusted Types are available in global object',()=>{
1313
letReact;
1414
letReactDOMClient;
15-
letReactFeatureFlags;
1615
letact;
1716
letassertConsoleErrorDev;
1817
letcontainer;
@@ -33,8 +32,6 @@ describe('when Trusted Types are available in global object', () => {
3332
isScript: ()=>false,
3433
isScriptURL: ()=>false,
3534
};
36-
ReactFeatureFlags=require('shared/ReactFeatureFlags');
37-
ReactFeatureFlags.enableTrustedTypesIntegration=true;
3835
React=require('react');
3936
ReactDOMClient=require('react-dom/client');
4037
({act, assertConsoleErrorDev}=require('internal-test-utils'));
@@ -118,7 +115,11 @@ describe('when Trusted Types are available in global object', () => {
118115
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
119116
expect(setAttributeCalls[0][1]).toBe('data-foo');
120117
// Ensure it didn't get stringified when passed to a DOM sink:
121-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
118+
if(gate('enableTrustedTypesIntegration')){
119+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
120+
}else{
121+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
122+
}
122123

123124
setAttributeCalls.length=0;
124125
awaitact(()=>{
@@ -129,7 +130,11 @@ describe('when Trusted Types are available in global object', () => {
129130
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
130131
expect(setAttributeCalls[0][1]).toBe('data-foo');
131132
// Ensure it didn't get stringified when passed to a DOM sink:
132-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
133+
if(gate('enableTrustedTypesIntegration')){
134+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
135+
}else{
136+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
137+
}
133138
}finally{
134139
Element.prototype.setAttribute=setAttribute;
135140
}
@@ -153,7 +158,11 @@ describe('when Trusted Types are available in global object', () => {
153158
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
154159
expect(setAttributeCalls[0][1]).toBe('class');
155160
// Ensure it didn't get stringified when passed to a DOM sink:
156-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
161+
if(gate('enableTrustedTypesIntegration')){
162+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
163+
}else{
164+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
165+
}
157166

158167
setAttributeCalls.length=0;
159168
awaitact(()=>{
@@ -164,7 +173,11 @@ describe('when Trusted Types are available in global object', () => {
164173
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
165174
expect(setAttributeCalls[0][1]).toBe('class');
166175
// Ensure it didn't get stringified when passed to a DOM sink:
167-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
176+
if(gate('enableTrustedTypesIntegration')){
177+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
178+
}else{
179+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
180+
}
168181
}finally{
169182
Element.prototype.setAttribute=setAttribute;
170183
}
@@ -189,7 +202,11 @@ describe('when Trusted Types are available in global object', () => {
189202
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
190203
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
191204
// Ensure it didn't get stringified when passed to a DOM sink:
192-
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
205+
if(gate('enableTrustedTypesIntegration')){
206+
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
207+
}else{
208+
expect(setAttributeNSCalls[0][3]).toBe('<b>Hi</b>');
209+
}
193210

194211
setAttributeNSCalls.length=0;
195212
awaitact(()=>{
@@ -201,7 +218,11 @@ describe('when Trusted Types are available in global object', () => {
201218
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
202219
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
203220
// Ensure it didn't get stringified when passed to a DOM sink:
204-
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
221+
if(gate('enableTrustedTypesIntegration')){
222+
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
223+
}else{
224+
expect(setAttributeNSCalls[0][3]).toBe('<b>Bye</b>');
225+
}
205226
}finally{
206227
Element.prototype.setAttributeNS=setAttributeNS;
207228
}
@@ -212,13 +233,15 @@ describe('when Trusted Types are available in global object', () => {
212233
awaitact(()=>{
213234
root.render(<script>alert("I am not executed")</script>);
214235
});
215-
assertConsoleErrorDev([
216-
'Encountered a script tag while rendering React component. '+
217-
'Scripts inside React components are never executed when rendering '+
218-
'on the client. Consider using template tag instead '+
219-
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
220-
' in script (at **)',
221-
]);
236+
if(gate('enableTrustedTypesIntegration')){
237+
assertConsoleErrorDev([
238+
'Encountered a script tag while rendering React component. '+
239+
'Scripts inside React components are never executed when rendering '+
240+
'on the client. Consider using template tag instead '+
241+
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
242+
' in script (at **)',
243+
]);
244+
}
222245

223246
// check that the warning is printed only once
224247
awaitact(()=>{

‎packages/shared/CheckStringCoercion.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ export function checkAttributeStringCoercion(
7676
attributeName: string,
7777
): void|string{
7878
if(__DEV__){
79+
// TODO: for enableTrustedTypesIntegration we don't toString this
80+
// so we shouldn't need the DEV warning.
7981
if(willCoercionThrow(value)){
8082
console.error(
8183
'The provided `%s` attribute is an unsupported type %s.'+

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@ export const enableScrollEndPolyfill: boolean = __VARIANT__;
3535
exportconstenableFragmentRefs: boolean=__VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableAsyncDebugInfo: boolean=__VARIANT__;
38-
3938
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39+
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4040

4141
// TODO: These flags are hard-coded to the default values used in open source.
4242
// Update the tests so that they pass in either mode, then set these
4343
// to __VARIANT__.
44-
exportconstenableTrustedTypesIntegration: boolean=false;
4544
// You probably *don't* want to add more hardcoded ones.
4645
// Instead, try to add them above with the __VARIANT__ value.

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [flags] make `enableTrustedTypesIntegration` dynamic (#35646) · react/react@d4d099f · GitHub
Skip to content

Commit d4d099f

Browse files
[flags] make enableTrustedTypesIntegration dynamic (#35646)
Co-authored-by: Rick Hanlon <rickhanlonii@meta.com>
1 parent c0c3706 commit d4d099f

8 files changed

Lines changed: 93 additions & 22 deletions

‎packages/react-dom/src/__tests__/ReactDOMAttribute-test.js‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,13 @@ describe('ReactDOM unknown attribute', () => {
171171
consttest=()=>
172172
testUnknownAttributeAssignment(newTemporalLike(),null);
173173

174-
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
174+
if(gate('enableTrustedTypesIntegration')&&!__DEV__){
175+
// TODO: this still throws in DEV even though it's not toString'd in prod.
176+
awaitexpect(test).rejects.toThrowError('2020-01-01');
177+
}else{
178+
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
179+
}
180+
175181
assertConsoleErrorDev([
176182
'The provided `unknown` attribute is an unsupported type TemporalLike.'+
177183
' This value must be coerced to a string before using it here.\n'+

‎packages/react-dom/src/__tests__/ReactDOMFloat-test.js‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,14 @@ describe('ReactDOMFloat', () => {
602602
'> <script href="foo">\n'+
603603
'\n'+
604604
' in script (at **)',
605+
...(gate('enableTrustedTypesIntegration')
606+
? [
607+
'Encountered a script tag while rendering React component. '+
608+
'Scripts inside React components are never executed when rendering on the client. '+
609+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
610+
' in script (at **)',
611+
]
612+
: []),
605613
]);
606614

607615
root.render(
@@ -2745,6 +2753,14 @@ body {
27452753
'> <script itemProp="foo">\n'+
27462754
'\n'+
27472755
' in script (at **)',
2756+
...(gate('enableTrustedTypesIntegration')
2757+
? [
2758+
'Encountered a script tag while rendering React component. '+
2759+
'Scripts inside React components are never executed when rendering on the client. '+
2760+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
2761+
' in script (at **)',
2762+
]
2763+
: []),
27482764
]);
27492765
});
27502766

‎packages/react-dom/src/__tests__/ReactDOMForm-test.js‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,15 +2277,21 @@ describe('ReactDOMForm', () => {
22772277
awaitsubmit(formRef.current);
22782278
assertLog([actionFn]);
22792279

2280-
// Everything else is toString-ed
2280+
// Everything else is toString-ed, unless trusted types are enabled.
22812281
classMyAction{
22822282
toString(){
22832283
return'stringified action';
22842284
}
22852285
}
2286-
awaitact(()=>root.render(<Formaction={newMyAction()}/>));
2286+
constinstance=newMyAction();
2287+
2288+
awaitact(()=>root.render(<Formaction={instance}/>));
22872289
awaitsubmit(formRef.current);
2288-
assertLog(['stringified action']);
2290+
assertLog(
2291+
gate('enableTrustedTypesIntegration')
2292+
? [instance]
2293+
: ['stringified action'],
2294+
);
22892295
});
22902296

22912297
it('form actions should retain status when nested state changes',async()=>{

‎packages/react-dom/src/__tests__/ReactDOMServerIntegrationUntrustedURL-test.js‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ describe('ReactDOMServerIntegration - Untrusted URLs', () => {
212212
expectedToStringCalls*=2;
213213
}
214214

215+
if(gate('enableTrustedTypesIntegration')&&render===clientCleanRender){
216+
// Trusted types does another toString.
217+
expectedToStringCalls+=1;
218+
}
219+
215220
lettoStringCalls=0;
216221
constfirstIsSafe={
217222
toString(){

‎packages/react-dom/src/__tests__/ReactEmptyComponent-test.js‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let TogglingComponent;
1717
letact;
1818
letScheduler;
1919
letassertLog;
20+
letassertConsoleErrorDev;
2021

2122
letcontainer;
2223

@@ -34,6 +35,7 @@ describe('ReactEmptyComponent', () => {
3435
constInternalTestUtils=require('internal-test-utils');
3536
act=InternalTestUtils.act;
3637
assertLog=InternalTestUtils.assertLog;
38+
assertConsoleErrorDev=InternalTestUtils.assertConsoleErrorDev;
3739

3840
container=document.createElement('div');
3941

@@ -175,6 +177,17 @@ describe('ReactEmptyComponent', () => {
175177
});
176178
}).not.toThrow();
177179

180+
expect(container.innerHTML).toBe('<script></script>');
181+
if(gate('enableTrustedTypesIntegration')){
182+
assertConsoleErrorDev([
183+
'Encountered a script tag while rendering React component. '+
184+
'Scripts inside React components are never executed when rendering on the client. '+
185+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
186+
' in script (at **)\n'+
187+
' in TogglingComponent (at **)',
188+
]);
189+
}
190+
178191
constcontainer2=document.createElement('div');
179192
constroot2=ReactDOMClient.createRoot(container2);
180193
expect(()=>{
@@ -189,6 +202,7 @@ describe('ReactEmptyComponent', () => {
189202
'mount SCRIPT',
190203
'update undefined',
191204
]);
205+
expect(container2.innerHTML).toBe('');
192206
});
193207

194208
it(

‎packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js‎

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
describe('when Trusted Types are available in global object',()=>{
1313
letReact;
1414
letReactDOMClient;
15-
letReactFeatureFlags;
1615
letact;
1716
letassertConsoleErrorDev;
1817
letcontainer;
@@ -33,8 +32,6 @@ describe('when Trusted Types are available in global object', () => {
3332
isScript: ()=>false,
3433
isScriptURL: ()=>false,
3534
};
36-
ReactFeatureFlags=require('shared/ReactFeatureFlags');
37-
ReactFeatureFlags.enableTrustedTypesIntegration=true;
3835
React=require('react');
3936
ReactDOMClient=require('react-dom/client');
4037
({act, assertConsoleErrorDev}=require('internal-test-utils'));
@@ -118,7 +115,11 @@ describe('when Trusted Types are available in global object', () => {
118115
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
119116
expect(setAttributeCalls[0][1]).toBe('data-foo');
120117
// Ensure it didn't get stringified when passed to a DOM sink:
121-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
118+
if(gate('enableTrustedTypesIntegration')){
119+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
120+
}else{
121+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
122+
}
122123

123124
setAttributeCalls.length=0;
124125
awaitact(()=>{
@@ -129,7 +130,11 @@ describe('when Trusted Types are available in global object', () => {
129130
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
130131
expect(setAttributeCalls[0][1]).toBe('data-foo');
131132
// Ensure it didn't get stringified when passed to a DOM sink:
132-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
133+
if(gate('enableTrustedTypesIntegration')){
134+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
135+
}else{
136+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
137+
}
133138
}finally{
134139
Element.prototype.setAttribute=setAttribute;
135140
}
@@ -153,7 +158,11 @@ describe('when Trusted Types are available in global object', () => {
153158
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
154159
expect(setAttributeCalls[0][1]).toBe('class');
155160
// Ensure it didn't get stringified when passed to a DOM sink:
156-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
161+
if(gate('enableTrustedTypesIntegration')){
162+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
163+
}else{
164+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
165+
}
157166

158167
setAttributeCalls.length=0;
159168
awaitact(()=>{
@@ -164,7 +173,11 @@ describe('when Trusted Types are available in global object', () => {
164173
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
165174
expect(setAttributeCalls[0][1]).toBe('class');
166175
// Ensure it didn't get stringified when passed to a DOM sink:
167-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
176+
if(gate('enableTrustedTypesIntegration')){
177+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
178+
}else{
179+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
180+
}
168181
}finally{
169182
Element.prototype.setAttribute=setAttribute;
170183
}
@@ -189,7 +202,11 @@ describe('when Trusted Types are available in global object', () => {
189202
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
190203
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
191204
// Ensure it didn't get stringified when passed to a DOM sink:
192-
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
205+
if(gate('enableTrustedTypesIntegration')){
206+
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
207+
}else{
208+
expect(setAttributeNSCalls[0][3]).toBe('<b>Hi</b>');
209+
}
193210

194211
setAttributeNSCalls.length=0;
195212
awaitact(()=>{
@@ -201,7 +218,11 @@ describe('when Trusted Types are available in global object', () => {
201218
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
202219
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
203220
// Ensure it didn't get stringified when passed to a DOM sink:
204-
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
221+
if(gate('enableTrustedTypesIntegration')){
222+
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
223+
}else{
224+
expect(setAttributeNSCalls[0][3]).toBe('<b>Bye</b>');
225+
}
205226
}finally{
206227
Element.prototype.setAttributeNS=setAttributeNS;
207228
}
@@ -212,13 +233,15 @@ describe('when Trusted Types are available in global object', () => {
212233
awaitact(()=>{
213234
root.render(<script>alert("I am not executed")</script>);
214235
});
215-
assertConsoleErrorDev([
216-
'Encountered a script tag while rendering React component. '+
217-
'Scripts inside React components are never executed when rendering '+
218-
'on the client. Consider using template tag instead '+
219-
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
220-
' in script (at **)',
221-
]);
236+
if(gate('enableTrustedTypesIntegration')){
237+
assertConsoleErrorDev([
238+
'Encountered a script tag while rendering React component. '+
239+
'Scripts inside React components are never executed when rendering '+
240+
'on the client. Consider using template tag instead '+
241+
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
242+
' in script (at **)',
243+
]);
244+
}
222245

223246
// check that the warning is printed only once
224247
awaitact(()=>{

‎packages/shared/CheckStringCoercion.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ export function checkAttributeStringCoercion(
7676
attributeName: string,
7777
): void|string{
7878
if(__DEV__){
79+
// TODO: for enableTrustedTypesIntegration we don't toString this
80+
// so we shouldn't need the DEV warning.
7981
if(willCoercionThrow(value)){
8082
console.error(
8183
'The provided `%s` attribute is an unsupported type %s.'+

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@ export const enableScrollEndPolyfill: boolean = __VARIANT__;
3535
exportconstenableFragmentRefs: boolean=__VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableAsyncDebugInfo: boolean=__VARIANT__;
38-
3938
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39+
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4040

4141
// TODO: These flags are hard-coded to the default values used in open source.
4242
// Update the tests so that they pass in either mode, then set these
4343
// to __VARIANT__.
44-
exportconstenableTrustedTypesIntegration: boolean=false;
4544
// You probably *don't* want to add more hardcoded ones.
4645
// Instead, try to add them above with the __VARIANT__ value.

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' [flags] make `enableTrustedTypesIntegration` dynamic (#35646) · react/react@d4d099f · GitHub
Skip to content

Commit d4d099f

Browse files
[flags] make enableTrustedTypesIntegration dynamic (#35646)
Co-authored-by: Rick Hanlon <rickhanlonii@meta.com>
1 parent c0c3706 commit d4d099f

8 files changed

Lines changed: 93 additions & 22 deletions

‎packages/react-dom/src/__tests__/ReactDOMAttribute-test.js‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,13 @@ describe('ReactDOM unknown attribute', () => {
171171
consttest=()=>
172172
testUnknownAttributeAssignment(newTemporalLike(),null);
173173

174-
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
174+
if(gate('enableTrustedTypesIntegration')&&!__DEV__){
175+
// TODO: this still throws in DEV even though it's not toString'd in prod.
176+
awaitexpect(test).rejects.toThrowError('2020-01-01');
177+
}else{
178+
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
179+
}
180+
175181
assertConsoleErrorDev([
176182
'The provided `unknown` attribute is an unsupported type TemporalLike.'+
177183
' This value must be coerced to a string before using it here.\n'+

‎packages/react-dom/src/__tests__/ReactDOMFloat-test.js‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,14 @@ describe('ReactDOMFloat', () => {
602602
'> <script href="foo">\n'+
603603
'\n'+
604604
' in script (at **)',
605+
...(gate('enableTrustedTypesIntegration')
606+
? [
607+
'Encountered a script tag while rendering React component. '+
608+
'Scripts inside React components are never executed when rendering on the client. '+
609+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
610+
' in script (at **)',
611+
]
612+
: []),
605613
]);
606614

607615
root.render(
@@ -2745,6 +2753,14 @@ body {
27452753
'> <script itemProp="foo">\n'+
27462754
'\n'+
27472755
' in script (at **)',
2756+
...(gate('enableTrustedTypesIntegration')
2757+
? [
2758+
'Encountered a script tag while rendering React component. '+
2759+
'Scripts inside React components are never executed when rendering on the client. '+
2760+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
2761+
' in script (at **)',
2762+
]
2763+
: []),
27482764
]);
27492765
});
27502766

‎packages/react-dom/src/__tests__/ReactDOMForm-test.js‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,15 +2277,21 @@ describe('ReactDOMForm', () => {
22772277
awaitsubmit(formRef.current);
22782278
assertLog([actionFn]);
22792279

2280-
// Everything else is toString-ed
2280+
// Everything else is toString-ed, unless trusted types are enabled.
22812281
classMyAction{
22822282
toString(){
22832283
return'stringified action';
22842284
}
22852285
}
2286-
awaitact(()=>root.render(<Formaction={newMyAction()}/>));
2286+
constinstance=newMyAction();
2287+
2288+
awaitact(()=>root.render(<Formaction={instance}/>));
22872289
awaitsubmit(formRef.current);
2288-
assertLog(['stringified action']);
2290+
assertLog(
2291+
gate('enableTrustedTypesIntegration')
2292+
? [instance]
2293+
: ['stringified action'],
2294+
);
22892295
});
22902296

22912297
it('form actions should retain status when nested state changes',async()=>{

‎packages/react-dom/src/__tests__/ReactDOMServerIntegrationUntrustedURL-test.js‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ describe('ReactDOMServerIntegration - Untrusted URLs', () => {
212212
expectedToStringCalls*=2;
213213
}
214214

215+
if(gate('enableTrustedTypesIntegration')&&render===clientCleanRender){
216+
// Trusted types does another toString.
217+
expectedToStringCalls+=1;
218+
}
219+
215220
lettoStringCalls=0;
216221
constfirstIsSafe={
217222
toString(){

‎packages/react-dom/src/__tests__/ReactEmptyComponent-test.js‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let TogglingComponent;
1717
letact;
1818
letScheduler;
1919
letassertLog;
20+
letassertConsoleErrorDev;
2021

2122
letcontainer;
2223

@@ -34,6 +35,7 @@ describe('ReactEmptyComponent', () => {
3435
constInternalTestUtils=require('internal-test-utils');
3536
act=InternalTestUtils.act;
3637
assertLog=InternalTestUtils.assertLog;
38+
assertConsoleErrorDev=InternalTestUtils.assertConsoleErrorDev;
3739

3840
container=document.createElement('div');
3941

@@ -175,6 +177,17 @@ describe('ReactEmptyComponent', () => {
175177
});
176178
}).not.toThrow();
177179

180+
expect(container.innerHTML).toBe('<script></script>');
181+
if(gate('enableTrustedTypesIntegration')){
182+
assertConsoleErrorDev([
183+
'Encountered a script tag while rendering React component. '+
184+
'Scripts inside React components are never executed when rendering on the client. '+
185+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
186+
' in script (at **)\n'+
187+
' in TogglingComponent (at **)',
188+
]);
189+
}
190+
178191
constcontainer2=document.createElement('div');
179192
constroot2=ReactDOMClient.createRoot(container2);
180193
expect(()=>{
@@ -189,6 +202,7 @@ describe('ReactEmptyComponent', () => {
189202
'mount SCRIPT',
190203
'update undefined',
191204
]);
205+
expect(container2.innerHTML).toBe('');
192206
});
193207

194208
it(

‎packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js‎

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
describe('when Trusted Types are available in global object',()=>{
1313
letReact;
1414
letReactDOMClient;
15-
letReactFeatureFlags;
1615
letact;
1716
letassertConsoleErrorDev;
1817
letcontainer;
@@ -33,8 +32,6 @@ describe('when Trusted Types are available in global object', () => {
3332
isScript: ()=>false,
3433
isScriptURL: ()=>false,
3534
};
36-
ReactFeatureFlags=require('shared/ReactFeatureFlags');
37-
ReactFeatureFlags.enableTrustedTypesIntegration=true;
3835
React=require('react');
3936
ReactDOMClient=require('react-dom/client');
4037
({act, assertConsoleErrorDev}=require('internal-test-utils'));
@@ -118,7 +115,11 @@ describe('when Trusted Types are available in global object', () => {
118115
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
119116
expect(setAttributeCalls[0][1]).toBe('data-foo');
120117
// Ensure it didn't get stringified when passed to a DOM sink:
121-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
118+
if(gate('enableTrustedTypesIntegration')){
119+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
120+
}else{
121+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
122+
}
122123

123124
setAttributeCalls.length=0;
124125
awaitact(()=>{
@@ -129,7 +130,11 @@ describe('when Trusted Types are available in global object', () => {
129130
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
130131
expect(setAttributeCalls[0][1]).toBe('data-foo');
131132
// Ensure it didn't get stringified when passed to a DOM sink:
132-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
133+
if(gate('enableTrustedTypesIntegration')){
134+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
135+
}else{
136+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
137+
}
133138
}finally{
134139
Element.prototype.setAttribute=setAttribute;
135140
}
@@ -153,7 +158,11 @@ describe('when Trusted Types are available in global object', () => {
153158
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
154159
expect(setAttributeCalls[0][1]).toBe('class');
155160
// Ensure it didn't get stringified when passed to a DOM sink:
156-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
161+
if(gate('enableTrustedTypesIntegration')){
162+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
163+
}else{
164+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
165+
}
157166

158167
setAttributeCalls.length=0;
159168
awaitact(()=>{
@@ -164,7 +173,11 @@ describe('when Trusted Types are available in global object', () => {
164173
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
165174
expect(setAttributeCalls[0][1]).toBe('class');
166175
// Ensure it didn't get stringified when passed to a DOM sink:
167-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
176+
if(gate('enableTrustedTypesIntegration')){
177+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
178+
}else{
179+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
180+
}
168181
}finally{
169182
Element.prototype.setAttribute=setAttribute;
170183
}
@@ -189,7 +202,11 @@ describe('when Trusted Types are available in global object', () => {
189202
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
190203
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
191204
// Ensure it didn't get stringified when passed to a DOM sink:
192-
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
205+
if(gate('enableTrustedTypesIntegration')){
206+
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
207+
}else{
208+
expect(setAttributeNSCalls[0][3]).toBe('<b>Hi</b>');
209+
}
193210

194211
setAttributeNSCalls.length=0;
195212
awaitact(()=>{
@@ -201,7 +218,11 @@ describe('when Trusted Types are available in global object', () => {
201218
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
202219
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
203220
// Ensure it didn't get stringified when passed to a DOM sink:
204-
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
221+
if(gate('enableTrustedTypesIntegration')){
222+
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
223+
}else{
224+
expect(setAttributeNSCalls[0][3]).toBe('<b>Bye</b>');
225+
}
205226
}finally{
206227
Element.prototype.setAttributeNS=setAttributeNS;
207228
}
@@ -212,13 +233,15 @@ describe('when Trusted Types are available in global object', () => {
212233
awaitact(()=>{
213234
root.render(<script>alert("I am not executed")</script>);
214235
});
215-
assertConsoleErrorDev([
216-
'Encountered a script tag while rendering React component. '+
217-
'Scripts inside React components are never executed when rendering '+
218-
'on the client. Consider using template tag instead '+
219-
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
220-
' in script (at **)',
221-
]);
236+
if(gate('enableTrustedTypesIntegration')){
237+
assertConsoleErrorDev([
238+
'Encountered a script tag while rendering React component. '+
239+
'Scripts inside React components are never executed when rendering '+
240+
'on the client. Consider using template tag instead '+
241+
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
242+
' in script (at **)',
243+
]);
244+
}
222245

223246
// check that the warning is printed only once
224247
awaitact(()=>{

‎packages/shared/CheckStringCoercion.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ export function checkAttributeStringCoercion(
7676
attributeName: string,
7777
): void|string{
7878
if(__DEV__){
79+
// TODO: for enableTrustedTypesIntegration we don't toString this
80+
// so we shouldn't need the DEV warning.
7981
if(willCoercionThrow(value)){
8082
console.error(
8183
'The provided `%s` attribute is an unsupported type %s.'+

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@ export const enableScrollEndPolyfill: boolean = __VARIANT__;
3535
exportconstenableFragmentRefs: boolean=__VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableAsyncDebugInfo: boolean=__VARIANT__;
38-
3938
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39+
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4040

4141
// TODO: These flags are hard-coded to the default values used in open source.
4242
// Update the tests so that they pass in either mode, then set these
4343
// to __VARIANT__.
44-
exportconstenableTrustedTypesIntegration: boolean=false;
4544
// You probably *don't* want to add more hardcoded ones.
4645
// Instead, try to add them above with the __VARIANT__ value.

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [flags] make `enableTrustedTypesIntegration` dynamic (#35646) · react/react@d4d099f · GitHub
Skip to content

Commit d4d099f

Browse files
[flags] make enableTrustedTypesIntegration dynamic (#35646)
Co-authored-by: Rick Hanlon <rickhanlonii@meta.com>
1 parent c0c3706 commit d4d099f

8 files changed

Lines changed: 93 additions & 22 deletions

‎packages/react-dom/src/__tests__/ReactDOMAttribute-test.js‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,13 @@ describe('ReactDOM unknown attribute', () => {
171171
consttest=()=>
172172
testUnknownAttributeAssignment(newTemporalLike(),null);
173173

174-
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
174+
if(gate('enableTrustedTypesIntegration')&&!__DEV__){
175+
// TODO: this still throws in DEV even though it's not toString'd in prod.
176+
awaitexpect(test).rejects.toThrowError('2020-01-01');
177+
}else{
178+
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
179+
}
180+
175181
assertConsoleErrorDev([
176182
'The provided `unknown` attribute is an unsupported type TemporalLike.'+
177183
' This value must be coerced to a string before using it here.\n'+

‎packages/react-dom/src/__tests__/ReactDOMFloat-test.js‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,14 @@ describe('ReactDOMFloat', () => {
602602
'> <script href="foo">\n'+
603603
'\n'+
604604
' in script (at **)',
605+
...(gate('enableTrustedTypesIntegration')
606+
? [
607+
'Encountered a script tag while rendering React component. '+
608+
'Scripts inside React components are never executed when rendering on the client. '+
609+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
610+
' in script (at **)',
611+
]
612+
: []),
605613
]);
606614

607615
root.render(
@@ -2745,6 +2753,14 @@ body {
27452753
'> <script itemProp="foo">\n'+
27462754
'\n'+
27472755
' in script (at **)',
2756+
...(gate('enableTrustedTypesIntegration')
2757+
? [
2758+
'Encountered a script tag while rendering React component. '+
2759+
'Scripts inside React components are never executed when rendering on the client. '+
2760+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
2761+
' in script (at **)',
2762+
]
2763+
: []),
27482764
]);
27492765
});
27502766

‎packages/react-dom/src/__tests__/ReactDOMForm-test.js‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,15 +2277,21 @@ describe('ReactDOMForm', () => {
22772277
awaitsubmit(formRef.current);
22782278
assertLog([actionFn]);
22792279

2280-
// Everything else is toString-ed
2280+
// Everything else is toString-ed, unless trusted types are enabled.
22812281
classMyAction{
22822282
toString(){
22832283
return'stringified action';
22842284
}
22852285
}
2286-
awaitact(()=>root.render(<Formaction={newMyAction()}/>));
2286+
constinstance=newMyAction();
2287+
2288+
awaitact(()=>root.render(<Formaction={instance}/>));
22872289
awaitsubmit(formRef.current);
2288-
assertLog(['stringified action']);
2290+
assertLog(
2291+
gate('enableTrustedTypesIntegration')
2292+
? [instance]
2293+
: ['stringified action'],
2294+
);
22892295
});
22902296

22912297
it('form actions should retain status when nested state changes',async()=>{

‎packages/react-dom/src/__tests__/ReactDOMServerIntegrationUntrustedURL-test.js‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ describe('ReactDOMServerIntegration - Untrusted URLs', () => {
212212
expectedToStringCalls*=2;
213213
}
214214

215+
if(gate('enableTrustedTypesIntegration')&&render===clientCleanRender){
216+
// Trusted types does another toString.
217+
expectedToStringCalls+=1;
218+
}
219+
215220
lettoStringCalls=0;
216221
constfirstIsSafe={
217222
toString(){

‎packages/react-dom/src/__tests__/ReactEmptyComponent-test.js‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let TogglingComponent;
1717
letact;
1818
letScheduler;
1919
letassertLog;
20+
letassertConsoleErrorDev;
2021

2122
letcontainer;
2223

@@ -34,6 +35,7 @@ describe('ReactEmptyComponent', () => {
3435
constInternalTestUtils=require('internal-test-utils');
3536
act=InternalTestUtils.act;
3637
assertLog=InternalTestUtils.assertLog;
38+
assertConsoleErrorDev=InternalTestUtils.assertConsoleErrorDev;
3739

3840
container=document.createElement('div');
3941

@@ -175,6 +177,17 @@ describe('ReactEmptyComponent', () => {
175177
});
176178
}).not.toThrow();
177179

180+
expect(container.innerHTML).toBe('<script></script>');
181+
if(gate('enableTrustedTypesIntegration')){
182+
assertConsoleErrorDev([
183+
'Encountered a script tag while rendering React component. '+
184+
'Scripts inside React components are never executed when rendering on the client. '+
185+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
186+
' in script (at **)\n'+
187+
' in TogglingComponent (at **)',
188+
]);
189+
}
190+
178191
constcontainer2=document.createElement('div');
179192
constroot2=ReactDOMClient.createRoot(container2);
180193
expect(()=>{
@@ -189,6 +202,7 @@ describe('ReactEmptyComponent', () => {
189202
'mount SCRIPT',
190203
'update undefined',
191204
]);
205+
expect(container2.innerHTML).toBe('');
192206
});
193207

194208
it(

‎packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js‎

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
describe('when Trusted Types are available in global object',()=>{
1313
letReact;
1414
letReactDOMClient;
15-
letReactFeatureFlags;
1615
letact;
1716
letassertConsoleErrorDev;
1817
letcontainer;
@@ -33,8 +32,6 @@ describe('when Trusted Types are available in global object', () => {
3332
isScript: ()=>false,
3433
isScriptURL: ()=>false,
3534
};
36-
ReactFeatureFlags=require('shared/ReactFeatureFlags');
37-
ReactFeatureFlags.enableTrustedTypesIntegration=true;
3835
React=require('react');
3936
ReactDOMClient=require('react-dom/client');
4037
({act, assertConsoleErrorDev}=require('internal-test-utils'));
@@ -118,7 +115,11 @@ describe('when Trusted Types are available in global object', () => {
118115
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
119116
expect(setAttributeCalls[0][1]).toBe('data-foo');
120117
// Ensure it didn't get stringified when passed to a DOM sink:
121-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
118+
if(gate('enableTrustedTypesIntegration')){
119+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
120+
}else{
121+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
122+
}
122123

123124
setAttributeCalls.length=0;
124125
awaitact(()=>{
@@ -129,7 +130,11 @@ describe('when Trusted Types are available in global object', () => {
129130
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
130131
expect(setAttributeCalls[0][1]).toBe('data-foo');
131132
// Ensure it didn't get stringified when passed to a DOM sink:
132-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
133+
if(gate('enableTrustedTypesIntegration')){
134+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
135+
}else{
136+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
137+
}
133138
}finally{
134139
Element.prototype.setAttribute=setAttribute;
135140
}
@@ -153,7 +158,11 @@ describe('when Trusted Types are available in global object', () => {
153158
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
154159
expect(setAttributeCalls[0][1]).toBe('class');
155160
// Ensure it didn't get stringified when passed to a DOM sink:
156-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
161+
if(gate('enableTrustedTypesIntegration')){
162+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
163+
}else{
164+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
165+
}
157166

158167
setAttributeCalls.length=0;
159168
awaitact(()=>{
@@ -164,7 +173,11 @@ describe('when Trusted Types are available in global object', () => {
164173
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
165174
expect(setAttributeCalls[0][1]).toBe('class');
166175
// Ensure it didn't get stringified when passed to a DOM sink:
167-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
176+
if(gate('enableTrustedTypesIntegration')){
177+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
178+
}else{
179+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
180+
}
168181
}finally{
169182
Element.prototype.setAttribute=setAttribute;
170183
}
@@ -189,7 +202,11 @@ describe('when Trusted Types are available in global object', () => {
189202
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
190203
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
191204
// Ensure it didn't get stringified when passed to a DOM sink:
192-
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
205+
if(gate('enableTrustedTypesIntegration')){
206+
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
207+
}else{
208+
expect(setAttributeNSCalls[0][3]).toBe('<b>Hi</b>');
209+
}
193210

194211
setAttributeNSCalls.length=0;
195212
awaitact(()=>{
@@ -201,7 +218,11 @@ describe('when Trusted Types are available in global object', () => {
201218
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
202219
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
203220
// Ensure it didn't get stringified when passed to a DOM sink:
204-
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
221+
if(gate('enableTrustedTypesIntegration')){
222+
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
223+
}else{
224+
expect(setAttributeNSCalls[0][3]).toBe('<b>Bye</b>');
225+
}
205226
}finally{
206227
Element.prototype.setAttributeNS=setAttributeNS;
207228
}
@@ -212,13 +233,15 @@ describe('when Trusted Types are available in global object', () => {
212233
awaitact(()=>{
213234
root.render(<script>alert("I am not executed")</script>);
214235
});
215-
assertConsoleErrorDev([
216-
'Encountered a script tag while rendering React component. '+
217-
'Scripts inside React components are never executed when rendering '+
218-
'on the client. Consider using template tag instead '+
219-
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
220-
' in script (at **)',
221-
]);
236+
if(gate('enableTrustedTypesIntegration')){
237+
assertConsoleErrorDev([
238+
'Encountered a script tag while rendering React component. '+
239+
'Scripts inside React components are never executed when rendering '+
240+
'on the client. Consider using template tag instead '+
241+
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
242+
' in script (at **)',
243+
]);
244+
}
222245

223246
// check that the warning is printed only once
224247
awaitact(()=>{

‎packages/shared/CheckStringCoercion.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ export function checkAttributeStringCoercion(
7676
attributeName: string,
7777
): void|string{
7878
if(__DEV__){
79+
// TODO: for enableTrustedTypesIntegration we don't toString this
80+
// so we shouldn't need the DEV warning.
7981
if(willCoercionThrow(value)){
8082
console.error(
8183
'The provided `%s` attribute is an unsupported type %s.'+

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@ export const enableScrollEndPolyfill: boolean = __VARIANT__;
3535
exportconstenableFragmentRefs: boolean=__VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableAsyncDebugInfo: boolean=__VARIANT__;
38-
3938
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39+
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4040

4141
// TODO: These flags are hard-coded to the default values used in open source.
4242
// Update the tests so that they pass in either mode, then set these
4343
// to __VARIANT__.
44-
exportconstenableTrustedTypesIntegration: boolean=false;
4544
// You probably *don't* want to add more hardcoded ones.
4645
// Instead, try to add them above with the __VARIANT__ value.

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [flags] make `enableTrustedTypesIntegration` dynamic (#35646) · react/react@d4d099f · GitHub
Skip to content

Commit d4d099f

Browse files
[flags] make enableTrustedTypesIntegration dynamic (#35646)
Co-authored-by: Rick Hanlon <rickhanlonii@meta.com>
1 parent c0c3706 commit d4d099f

8 files changed

Lines changed: 93 additions & 22 deletions

‎packages/react-dom/src/__tests__/ReactDOMAttribute-test.js‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,13 @@ describe('ReactDOM unknown attribute', () => {
171171
consttest=()=>
172172
testUnknownAttributeAssignment(newTemporalLike(),null);
173173

174-
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
174+
if(gate('enableTrustedTypesIntegration')&&!__DEV__){
175+
// TODO: this still throws in DEV even though it's not toString'd in prod.
176+
awaitexpect(test).rejects.toThrowError('2020-01-01');
177+
}else{
178+
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
179+
}
180+
175181
assertConsoleErrorDev([
176182
'The provided `unknown` attribute is an unsupported type TemporalLike.'+
177183
' This value must be coerced to a string before using it here.\n'+

‎packages/react-dom/src/__tests__/ReactDOMFloat-test.js‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,14 @@ describe('ReactDOMFloat', () => {
602602
'> <script href="foo">\n'+
603603
'\n'+
604604
' in script (at **)',
605+
...(gate('enableTrustedTypesIntegration')
606+
? [
607+
'Encountered a script tag while rendering React component. '+
608+
'Scripts inside React components are never executed when rendering on the client. '+
609+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
610+
' in script (at **)',
611+
]
612+
: []),
605613
]);
606614

607615
root.render(
@@ -2745,6 +2753,14 @@ body {
27452753
'> <script itemProp="foo">\n'+
27462754
'\n'+
27472755
' in script (at **)',
2756+
...(gate('enableTrustedTypesIntegration')
2757+
? [
2758+
'Encountered a script tag while rendering React component. '+
2759+
'Scripts inside React components are never executed when rendering on the client. '+
2760+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
2761+
' in script (at **)',
2762+
]
2763+
: []),
27482764
]);
27492765
});
27502766

‎packages/react-dom/src/__tests__/ReactDOMForm-test.js‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,15 +2277,21 @@ describe('ReactDOMForm', () => {
22772277
awaitsubmit(formRef.current);
22782278
assertLog([actionFn]);
22792279

2280-
// Everything else is toString-ed
2280+
// Everything else is toString-ed, unless trusted types are enabled.
22812281
classMyAction{
22822282
toString(){
22832283
return'stringified action';
22842284
}
22852285
}
2286-
awaitact(()=>root.render(<Formaction={newMyAction()}/>));
2286+
constinstance=newMyAction();
2287+
2288+
awaitact(()=>root.render(<Formaction={instance}/>));
22872289
awaitsubmit(formRef.current);
2288-
assertLog(['stringified action']);
2290+
assertLog(
2291+
gate('enableTrustedTypesIntegration')
2292+
? [instance]
2293+
: ['stringified action'],
2294+
);
22892295
});
22902296

22912297
it('form actions should retain status when nested state changes',async()=>{

‎packages/react-dom/src/__tests__/ReactDOMServerIntegrationUntrustedURL-test.js‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ describe('ReactDOMServerIntegration - Untrusted URLs', () => {
212212
expectedToStringCalls*=2;
213213
}
214214

215+
if(gate('enableTrustedTypesIntegration')&&render===clientCleanRender){
216+
// Trusted types does another toString.
217+
expectedToStringCalls+=1;
218+
}
219+
215220
lettoStringCalls=0;
216221
constfirstIsSafe={
217222
toString(){

‎packages/react-dom/src/__tests__/ReactEmptyComponent-test.js‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let TogglingComponent;
1717
letact;
1818
letScheduler;
1919
letassertLog;
20+
letassertConsoleErrorDev;
2021

2122
letcontainer;
2223

@@ -34,6 +35,7 @@ describe('ReactEmptyComponent', () => {
3435
constInternalTestUtils=require('internal-test-utils');
3536
act=InternalTestUtils.act;
3637
assertLog=InternalTestUtils.assertLog;
38+
assertConsoleErrorDev=InternalTestUtils.assertConsoleErrorDev;
3739

3840
container=document.createElement('div');
3941

@@ -175,6 +177,17 @@ describe('ReactEmptyComponent', () => {
175177
});
176178
}).not.toThrow();
177179

180+
expect(container.innerHTML).toBe('<script></script>');
181+
if(gate('enableTrustedTypesIntegration')){
182+
assertConsoleErrorDev([
183+
'Encountered a script tag while rendering React component. '+
184+
'Scripts inside React components are never executed when rendering on the client. '+
185+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
186+
' in script (at **)\n'+
187+
' in TogglingComponent (at **)',
188+
]);
189+
}
190+
178191
constcontainer2=document.createElement('div');
179192
constroot2=ReactDOMClient.createRoot(container2);
180193
expect(()=>{
@@ -189,6 +202,7 @@ describe('ReactEmptyComponent', () => {
189202
'mount SCRIPT',
190203
'update undefined',
191204
]);
205+
expect(container2.innerHTML).toBe('');
192206
});
193207

194208
it(

‎packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js‎

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
describe('when Trusted Types are available in global object',()=>{
1313
letReact;
1414
letReactDOMClient;
15-
letReactFeatureFlags;
1615
letact;
1716
letassertConsoleErrorDev;
1817
letcontainer;
@@ -33,8 +32,6 @@ describe('when Trusted Types are available in global object', () => {
3332
isScript: ()=>false,
3433
isScriptURL: ()=>false,
3534
};
36-
ReactFeatureFlags=require('shared/ReactFeatureFlags');
37-
ReactFeatureFlags.enableTrustedTypesIntegration=true;
3835
React=require('react');
3936
ReactDOMClient=require('react-dom/client');
4037
({act, assertConsoleErrorDev}=require('internal-test-utils'));
@@ -118,7 +115,11 @@ describe('when Trusted Types are available in global object', () => {
118115
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
119116
expect(setAttributeCalls[0][1]).toBe('data-foo');
120117
// Ensure it didn't get stringified when passed to a DOM sink:
121-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
118+
if(gate('enableTrustedTypesIntegration')){
119+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
120+
}else{
121+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
122+
}
122123

123124
setAttributeCalls.length=0;
124125
awaitact(()=>{
@@ -129,7 +130,11 @@ describe('when Trusted Types are available in global object', () => {
129130
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
130131
expect(setAttributeCalls[0][1]).toBe('data-foo');
131132
// Ensure it didn't get stringified when passed to a DOM sink:
132-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
133+
if(gate('enableTrustedTypesIntegration')){
134+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
135+
}else{
136+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
137+
}
133138
}finally{
134139
Element.prototype.setAttribute=setAttribute;
135140
}
@@ -153,7 +158,11 @@ describe('when Trusted Types are available in global object', () => {
153158
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
154159
expect(setAttributeCalls[0][1]).toBe('class');
155160
// Ensure it didn't get stringified when passed to a DOM sink:
156-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
161+
if(gate('enableTrustedTypesIntegration')){
162+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
163+
}else{
164+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
165+
}
157166

158167
setAttributeCalls.length=0;
159168
awaitact(()=>{
@@ -164,7 +173,11 @@ describe('when Trusted Types are available in global object', () => {
164173
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
165174
expect(setAttributeCalls[0][1]).toBe('class');
166175
// Ensure it didn't get stringified when passed to a DOM sink:
167-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
176+
if(gate('enableTrustedTypesIntegration')){
177+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
178+
}else{
179+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
180+
}
168181
}finally{
169182
Element.prototype.setAttribute=setAttribute;
170183
}
@@ -189,7 +202,11 @@ describe('when Trusted Types are available in global object', () => {
189202
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
190203
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
191204
// Ensure it didn't get stringified when passed to a DOM sink:
192-
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
205+
if(gate('enableTrustedTypesIntegration')){
206+
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
207+
}else{
208+
expect(setAttributeNSCalls[0][3]).toBe('<b>Hi</b>');
209+
}
193210

194211
setAttributeNSCalls.length=0;
195212
awaitact(()=>{
@@ -201,7 +218,11 @@ describe('when Trusted Types are available in global object', () => {
201218
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
202219
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
203220
// Ensure it didn't get stringified when passed to a DOM sink:
204-
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
221+
if(gate('enableTrustedTypesIntegration')){
222+
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
223+
}else{
224+
expect(setAttributeNSCalls[0][3]).toBe('<b>Bye</b>');
225+
}
205226
}finally{
206227
Element.prototype.setAttributeNS=setAttributeNS;
207228
}
@@ -212,13 +233,15 @@ describe('when Trusted Types are available in global object', () => {
212233
awaitact(()=>{
213234
root.render(<script>alert("I am not executed")</script>);
214235
});
215-
assertConsoleErrorDev([
216-
'Encountered a script tag while rendering React component. '+
217-
'Scripts inside React components are never executed when rendering '+
218-
'on the client. Consider using template tag instead '+
219-
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
220-
' in script (at **)',
221-
]);
236+
if(gate('enableTrustedTypesIntegration')){
237+
assertConsoleErrorDev([
238+
'Encountered a script tag while rendering React component. '+
239+
'Scripts inside React components are never executed when rendering '+
240+
'on the client. Consider using template tag instead '+
241+
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
242+
' in script (at **)',
243+
]);
244+
}
222245

223246
// check that the warning is printed only once
224247
awaitact(()=>{

‎packages/shared/CheckStringCoercion.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ export function checkAttributeStringCoercion(
7676
attributeName: string,
7777
): void|string{
7878
if(__DEV__){
79+
// TODO: for enableTrustedTypesIntegration we don't toString this
80+
// so we shouldn't need the DEV warning.
7981
if(willCoercionThrow(value)){
8082
console.error(
8183
'The provided `%s` attribute is an unsupported type %s.'+

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@ export const enableScrollEndPolyfill: boolean = __VARIANT__;
3535
exportconstenableFragmentRefs: boolean=__VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableAsyncDebugInfo: boolean=__VARIANT__;
38-
3938
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39+
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4040

4141
// TODO: These flags are hard-coded to the default values used in open source.
4242
// Update the tests so that they pass in either mode, then set these
4343
// to __VARIANT__.
44-
exportconstenableTrustedTypesIntegration: boolean=false;
4544
// You probably *don't* want to add more hardcoded ones.
4645
// Instead, try to add them above with the __VARIANT__ value.

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); [flags] make `enableTrustedTypesIntegration` dynamic (#35646) · react/react@d4d099f · GitHub
Skip to content

Commit d4d099f

Browse files
[flags] make enableTrustedTypesIntegration dynamic (#35646)
Co-authored-by: Rick Hanlon <rickhanlonii@meta.com>
1 parent c0c3706 commit d4d099f

8 files changed

Lines changed: 93 additions & 22 deletions

‎packages/react-dom/src/__tests__/ReactDOMAttribute-test.js‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,13 @@ describe('ReactDOM unknown attribute', () => {
171171
consttest=()=>
172172
testUnknownAttributeAssignment(newTemporalLike(),null);
173173

174-
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
174+
if(gate('enableTrustedTypesIntegration')&&!__DEV__){
175+
// TODO: this still throws in DEV even though it's not toString'd in prod.
176+
awaitexpect(test).rejects.toThrowError('2020-01-01');
177+
}else{
178+
awaitexpect(test).rejects.toThrowError(newTypeError('prod message'));
179+
}
180+
175181
assertConsoleErrorDev([
176182
'The provided `unknown` attribute is an unsupported type TemporalLike.'+
177183
' This value must be coerced to a string before using it here.\n'+

‎packages/react-dom/src/__tests__/ReactDOMFloat-test.js‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,14 @@ describe('ReactDOMFloat', () => {
602602
'> <script href="foo">\n'+
603603
'\n'+
604604
' in script (at **)',
605+
...(gate('enableTrustedTypesIntegration')
606+
? [
607+
'Encountered a script tag while rendering React component. '+
608+
'Scripts inside React components are never executed when rendering on the client. '+
609+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
610+
' in script (at **)',
611+
]
612+
: []),
605613
]);
606614

607615
root.render(
@@ -2745,6 +2753,14 @@ body {
27452753
'> <script itemProp="foo">\n'+
27462754
'\n'+
27472755
' in script (at **)',
2756+
...(gate('enableTrustedTypesIntegration')
2757+
? [
2758+
'Encountered a script tag while rendering React component. '+
2759+
'Scripts inside React components are never executed when rendering on the client. '+
2760+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
2761+
' in script (at **)',
2762+
]
2763+
: []),
27482764
]);
27492765
});
27502766

‎packages/react-dom/src/__tests__/ReactDOMForm-test.js‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,15 +2277,21 @@ describe('ReactDOMForm', () => {
22772277
awaitsubmit(formRef.current);
22782278
assertLog([actionFn]);
22792279

2280-
// Everything else is toString-ed
2280+
// Everything else is toString-ed, unless trusted types are enabled.
22812281
classMyAction{
22822282
toString(){
22832283
return'stringified action';
22842284
}
22852285
}
2286-
awaitact(()=>root.render(<Formaction={newMyAction()}/>));
2286+
constinstance=newMyAction();
2287+
2288+
awaitact(()=>root.render(<Formaction={instance}/>));
22872289
awaitsubmit(formRef.current);
2288-
assertLog(['stringified action']);
2290+
assertLog(
2291+
gate('enableTrustedTypesIntegration')
2292+
? [instance]
2293+
: ['stringified action'],
2294+
);
22892295
});
22902296

22912297
it('form actions should retain status when nested state changes',async()=>{

‎packages/react-dom/src/__tests__/ReactDOMServerIntegrationUntrustedURL-test.js‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ describe('ReactDOMServerIntegration - Untrusted URLs', () => {
212212
expectedToStringCalls*=2;
213213
}
214214

215+
if(gate('enableTrustedTypesIntegration')&&render===clientCleanRender){
216+
// Trusted types does another toString.
217+
expectedToStringCalls+=1;
218+
}
219+
215220
lettoStringCalls=0;
216221
constfirstIsSafe={
217222
toString(){

‎packages/react-dom/src/__tests__/ReactEmptyComponent-test.js‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let TogglingComponent;
1717
letact;
1818
letScheduler;
1919
letassertLog;
20+
letassertConsoleErrorDev;
2021

2122
letcontainer;
2223

@@ -34,6 +35,7 @@ describe('ReactEmptyComponent', () => {
3435
constInternalTestUtils=require('internal-test-utils');
3536
act=InternalTestUtils.act;
3637
assertLog=InternalTestUtils.assertLog;
38+
assertConsoleErrorDev=InternalTestUtils.assertConsoleErrorDev;
3739

3840
container=document.createElement('div');
3941

@@ -175,6 +177,17 @@ describe('ReactEmptyComponent', () => {
175177
});
176178
}).not.toThrow();
177179

180+
expect(container.innerHTML).toBe('<script></script>');
181+
if(gate('enableTrustedTypesIntegration')){
182+
assertConsoleErrorDev([
183+
'Encountered a script tag while rendering React component. '+
184+
'Scripts inside React components are never executed when rendering on the client. '+
185+
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
186+
' in script (at **)\n'+
187+
' in TogglingComponent (at **)',
188+
]);
189+
}
190+
178191
constcontainer2=document.createElement('div');
179192
constroot2=ReactDOMClient.createRoot(container2);
180193
expect(()=>{
@@ -189,6 +202,7 @@ describe('ReactEmptyComponent', () => {
189202
'mount SCRIPT',
190203
'update undefined',
191204
]);
205+
expect(container2.innerHTML).toBe('');
192206
});
193207

194208
it(

‎packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js‎

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
describe('when Trusted Types are available in global object',()=>{
1313
letReact;
1414
letReactDOMClient;
15-
letReactFeatureFlags;
1615
letact;
1716
letassertConsoleErrorDev;
1817
letcontainer;
@@ -33,8 +32,6 @@ describe('when Trusted Types are available in global object', () => {
3332
isScript: ()=>false,
3433
isScriptURL: ()=>false,
3534
};
36-
ReactFeatureFlags=require('shared/ReactFeatureFlags');
37-
ReactFeatureFlags.enableTrustedTypesIntegration=true;
3835
React=require('react');
3936
ReactDOMClient=require('react-dom/client');
4037
({act, assertConsoleErrorDev}=require('internal-test-utils'));
@@ -118,7 +115,11 @@ describe('when Trusted Types are available in global object', () => {
118115
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
119116
expect(setAttributeCalls[0][1]).toBe('data-foo');
120117
// Ensure it didn't get stringified when passed to a DOM sink:
121-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
118+
if(gate('enableTrustedTypesIntegration')){
119+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
120+
}else{
121+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
122+
}
122123

123124
setAttributeCalls.length=0;
124125
awaitact(()=>{
@@ -129,7 +130,11 @@ describe('when Trusted Types are available in global object', () => {
129130
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
130131
expect(setAttributeCalls[0][1]).toBe('data-foo');
131132
// Ensure it didn't get stringified when passed to a DOM sink:
132-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
133+
if(gate('enableTrustedTypesIntegration')){
134+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
135+
}else{
136+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
137+
}
133138
}finally{
134139
Element.prototype.setAttribute=setAttribute;
135140
}
@@ -153,7 +158,11 @@ describe('when Trusted Types are available in global object', () => {
153158
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
154159
expect(setAttributeCalls[0][1]).toBe('class');
155160
// Ensure it didn't get stringified when passed to a DOM sink:
156-
expect(setAttributeCalls[0][2]).toBe(ttObject1);
161+
if(gate('enableTrustedTypesIntegration')){
162+
expect(setAttributeCalls[0][2]).toBe(ttObject1);
163+
}else{
164+
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
165+
}
157166

158167
setAttributeCalls.length=0;
159168
awaitact(()=>{
@@ -164,7 +173,11 @@ describe('when Trusted Types are available in global object', () => {
164173
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
165174
expect(setAttributeCalls[0][1]).toBe('class');
166175
// Ensure it didn't get stringified when passed to a DOM sink:
167-
expect(setAttributeCalls[0][2]).toBe(ttObject2);
176+
if(gate('enableTrustedTypesIntegration')){
177+
expect(setAttributeCalls[0][2]).toBe(ttObject2);
178+
}else{
179+
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
180+
}
168181
}finally{
169182
Element.prototype.setAttribute=setAttribute;
170183
}
@@ -189,7 +202,11 @@ describe('when Trusted Types are available in global object', () => {
189202
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
190203
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
191204
// Ensure it didn't get stringified when passed to a DOM sink:
192-
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
205+
if(gate('enableTrustedTypesIntegration')){
206+
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
207+
}else{
208+
expect(setAttributeNSCalls[0][3]).toBe('<b>Hi</b>');
209+
}
193210

194211
setAttributeNSCalls.length=0;
195212
awaitact(()=>{
@@ -201,7 +218,11 @@ describe('when Trusted Types are available in global object', () => {
201218
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
202219
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
203220
// Ensure it didn't get stringified when passed to a DOM sink:
204-
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
221+
if(gate('enableTrustedTypesIntegration')){
222+
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
223+
}else{
224+
expect(setAttributeNSCalls[0][3]).toBe('<b>Bye</b>');
225+
}
205226
}finally{
206227
Element.prototype.setAttributeNS=setAttributeNS;
207228
}
@@ -212,13 +233,15 @@ describe('when Trusted Types are available in global object', () => {
212233
awaitact(()=>{
213234
root.render(<script>alert("I am not executed")</script>);
214235
});
215-
assertConsoleErrorDev([
216-
'Encountered a script tag while rendering React component. '+
217-
'Scripts inside React components are never executed when rendering '+
218-
'on the client. Consider using template tag instead '+
219-
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
220-
' in script (at **)',
221-
]);
236+
if(gate('enableTrustedTypesIntegration')){
237+
assertConsoleErrorDev([
238+
'Encountered a script tag while rendering React component. '+
239+
'Scripts inside React components are never executed when rendering '+
240+
'on the client. Consider using template tag instead '+
241+
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n'+
242+
' in script (at **)',
243+
]);
244+
}
222245

223246
// check that the warning is printed only once
224247
awaitact(()=>{

‎packages/shared/CheckStringCoercion.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ export function checkAttributeStringCoercion(
7676
attributeName: string,
7777
): void|string{
7878
if(__DEV__){
79+
// TODO: for enableTrustedTypesIntegration we don't toString this
80+
// so we shouldn't need the DEV warning.
7981
if(willCoercionThrow(value)){
8082
console.error(
8183
'The provided `%s` attribute is an unsupported type %s.'+

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@ export const enableScrollEndPolyfill: boolean = __VARIANT__;
3535
exportconstenableFragmentRefs: boolean=__VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableAsyncDebugInfo: boolean=__VARIANT__;
38-
3938
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39+
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4040

4141
// TODO: These flags are hard-coded to the default values used in open source.
4242
// Update the tests so that they pass in either mode, then set these
4343
// to __VARIANT__.
44-
exportconstenableTrustedTypesIntegration: boolean=false;
4544
// You probably *don't* want to add more hardcoded ones.
4645
// Instead, try to add them above with the __VARIANT__ value.

0 commit comments

Comments
 (0)