Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/react-dom/src/__tests__/ReactDOMAttribute-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,13 @@ describe('ReactDOM unknown attribute', () => {
const test = () =>
testUnknownAttributeAssignment(new TemporalLike(), null);

await expect(test).rejects.toThrowError(new TypeError('prod message'));
if (gate('enableTrustedTypesIntegration') && !__DEV__) {
// TODO: this still throws in DEV even though it's not toString'd in prod.
await expect(test).rejects.toThrowError('2020-01-01');
} else {
await expect(test).rejects.toThrowError(new TypeError('prod message'));
}

assertConsoleErrorDev([
'The provided `unknown` attribute is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.\n' +
Expand Down
16 changes: 16 additions & 0 deletions packages/react-dom/src/__tests__/ReactDOMFloat-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,14 @@ describe('ReactDOMFloat', () => {
'> <script href="foo">\n' +
'\n' +
' in script (at **)',
...(gate('enableTrustedTypesIntegration')
? [
'Encountered a script tag while rendering React component. ' +
'Scripts inside React components are never executed when rendering on the client. ' +
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n' +
' in script (at **)',
]
: []),
]);

root.render(
Expand Down Expand Up @@ -2754,6 +2762,14 @@ body {
'> <script itemProp="foo">\n' +
'\n' +
' in script (at **)',
...(gate('enableTrustedTypesIntegration')
? [
'Encountered a script tag while rendering React component. ' +
'Scripts inside React components are never executed when rendering on the client. ' +
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n' +
' in script (at **)',
]
: []),
]);
});

Expand Down
12 changes: 9 additions & 3 deletions packages/react-dom/src/__tests__/ReactDOMForm-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2285,15 +2285,21 @@ describe('ReactDOMForm', () => {
await submit(formRef.current);
assertLog([actionFn]);

// Everything else is toString-ed
// Everything else is toString-ed, unless trusted types are enabled.
class MyAction {
toString() {
return 'stringified action';
}
}
await act(() => root.render(<Form action={new MyAction()} />));
const instance = new MyAction();

await act(() => root.render(<Form action={instance} />));
await submit(formRef.current);
assertLog(['stringified action']);
assertLog(
gate('enableTrustedTypesIntegration')
? [instance]
: ['stringified action'],
);
});

it('form actions should retain status when nested state changes', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ describe('ReactDOMServerIntegration - Untrusted URLs', () => {
expectedToStringCalls *= 2;
}

if (gate('enableTrustedTypesIntegration') && render === clientCleanRender) {
// Trusted types does another toString.
expectedToStringCalls += 1;
}

let toStringCalls = 0;
const firstIsSafe = {
toString() {
Expand Down
14 changes: 14 additions & 0 deletions packages/react-dom/src/__tests__/ReactEmptyComponent-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ let TogglingComponent;
let act;
let Scheduler;
let assertLog;
let assertConsoleErrorDev;

let container;

Expand All @@ -34,6 +35,7 @@ describe('ReactEmptyComponent', () => {
const InternalTestUtils = require('internal-test-utils');
act = InternalTestUtils.act;
assertLog = InternalTestUtils.assertLog;
assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;

container = document.createElement('div');

Expand Down Expand Up @@ -175,6 +177,17 @@ describe('ReactEmptyComponent', () => {
});
}).not.toThrow();

expect(container.innerHTML).toBe('<script></script>');
if (gate('enableTrustedTypesIntegration')) {
assertConsoleErrorDev([
'Encountered a script tag while rendering React component. ' +
'Scripts inside React components are never executed when rendering on the client. ' +
'Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n' +
' in script (at **)\n' +
' in TogglingComponent (at **)',
]);
}

const container2 = document.createElement('div');
const root2 = ReactDOMClient.createRoot(container2);
expect(() => {
Expand All @@ -189,6 +202,7 @@ describe('ReactEmptyComponent', () => {
'mount SCRIPT',
'update undefined',
]);
expect(container2.innerHTML).toBe('');
});

it(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
describe('when Trusted Types are available in global object', () => {
let React;
let ReactDOMClient;
let ReactFeatureFlags;
let act;
let assertConsoleErrorDev;
let container;
Expand All @@ -33,8 +32,6 @@ describe('when Trusted Types are available in global object', () => {
isScript: () => false,
isScriptURL: () => false,
};
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.enableTrustedTypesIntegration = true;
React = require('react');
ReactDOMClient = require('react-dom/client');
({act, assertConsoleErrorDev} = require('internal-test-utils'));
Expand Down Expand Up @@ -118,7 +115,11 @@ describe('when Trusted Types are available in global object', () => {
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
expect(setAttributeCalls[0][1]).toBe('data-foo');
// Ensure it didn't get stringified when passed to a DOM sink:
expect(setAttributeCalls[0][2]).toBe(ttObject1);
if (gate('enableTrustedTypesIntegration')) {
expect(setAttributeCalls[0][2]).toBe(ttObject1);
} else {
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
}

setAttributeCalls.length = 0;
await act(() => {
Expand All @@ -129,7 +130,11 @@ describe('when Trusted Types are available in global object', () => {
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
expect(setAttributeCalls[0][1]).toBe('data-foo');
// Ensure it didn't get stringified when passed to a DOM sink:
expect(setAttributeCalls[0][2]).toBe(ttObject2);
if (gate('enableTrustedTypesIntegration')) {
expect(setAttributeCalls[0][2]).toBe(ttObject2);
} else {
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
}
} finally {
Element.prototype.setAttribute = setAttribute;
}
Expand All @@ -153,7 +158,11 @@ describe('when Trusted Types are available in global object', () => {
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
expect(setAttributeCalls[0][1]).toBe('class');
// Ensure it didn't get stringified when passed to a DOM sink:
expect(setAttributeCalls[0][2]).toBe(ttObject1);
if (gate('enableTrustedTypesIntegration')) {
expect(setAttributeCalls[0][2]).toBe(ttObject1);
} else {
expect(setAttributeCalls[0][2]).toBe('<b>Hi</b>');
}

setAttributeCalls.length = 0;
await act(() => {
Expand All @@ -164,7 +173,11 @@ describe('when Trusted Types are available in global object', () => {
expect(setAttributeCalls[0][0]).toBe(container.firstChild);
expect(setAttributeCalls[0][1]).toBe('class');
// Ensure it didn't get stringified when passed to a DOM sink:
expect(setAttributeCalls[0][2]).toBe(ttObject2);
if (gate('enableTrustedTypesIntegration')) {
expect(setAttributeCalls[0][2]).toBe(ttObject2);
} else {
expect(setAttributeCalls[0][2]).toBe('<b>Bye</b>');
}
} finally {
Element.prototype.setAttribute = setAttribute;
}
Expand All @@ -189,7 +202,11 @@ describe('when Trusted Types are available in global object', () => {
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
// Ensure it didn't get stringified when passed to a DOM sink:
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
if (gate('enableTrustedTypesIntegration')) {
expect(setAttributeNSCalls[0][3]).toBe(ttObject1);
} else {
expect(setAttributeNSCalls[0][3]).toBe('<b>Hi</b>');
}

setAttributeNSCalls.length = 0;
await act(() => {
Expand All @@ -201,7 +218,11 @@ describe('when Trusted Types are available in global object', () => {
expect(setAttributeNSCalls[0][1]).toBe('http://www.w3.org/1999/xlink');
expect(setAttributeNSCalls[0][2]).toBe('xlink:href');
// Ensure it didn't get stringified when passed to a DOM sink:
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
if (gate('enableTrustedTypesIntegration')) {
expect(setAttributeNSCalls[0][3]).toBe(ttObject2);
} else {
expect(setAttributeNSCalls[0][3]).toBe('<b>Bye</b>');
}
} finally {
Element.prototype.setAttributeNS = setAttributeNS;
}
Expand All @@ -212,13 +233,15 @@ describe('when Trusted Types are available in global object', () => {
await act(() => {
root.render(<script>alert("I am not executed")</script>);
});
assertConsoleErrorDev([
'Encountered a script tag while rendering React component. ' +
'Scripts inside React components are never executed when rendering ' +
'on the client. Consider using template tag instead ' +
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n' +
' in script (at **)',
]);
if (gate('enableTrustedTypesIntegration')) {
assertConsoleErrorDev([
'Encountered a script tag while rendering React component. ' +
'Scripts inside React components are never executed when rendering ' +
'on the client. Consider using template tag instead ' +
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n' +
' in script (at **)',
]);
}

// check that the warning is printed only once
await act(() => {
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/CheckStringCoercion.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ export function checkAttributeStringCoercion(
attributeName: string,
): void | string {
if (__DEV__) {
// TODO: for enableTrustedTypesIntegration we don't toString this
// so we shouldn't need the DEV warning.
if (willCoercionThrow(value)) {
console.error(
'The provided `%s` attribute is an unsupported type %s.' +
Expand Down
3 changes: 1 addition & 2 deletions packages/shared/forks/ReactFeatureFlags.www-dynamic.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,11 @@ export const enableScrollEndPolyfill: boolean = __VARIANT__;
export const enableFragmentRefs: boolean = __VARIANT__;
export const enableFragmentRefsScrollIntoView: boolean = __VARIANT__;
export const enableAsyncDebugInfo: boolean = __VARIANT__;

export const enableInternalInstanceMap: boolean = __VARIANT__;
export const enableTrustedTypesIntegration: boolean = __VARIANT__;

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