Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
517e197
Report DOM events to reportError directly instead of rethrowing
sebmarkbage Mar 12, 2024
bec21b2
Never rethrow at the root
sebmarkbage Mar 12, 2024
742aba4
Log fatal errors as they happen
sebmarkbage Mar 22, 2024
54471d4
Report root errors to the browser so they show up as "uncaught"
sebmarkbage Mar 12, 2024
bc5374d
Polyfill dispatching error event
sebmarkbage Mar 13, 2024
c6dd65e
Remove rethrowing in the commit phase
sebmarkbage Mar 13, 2024
0d7615d
Rethrow global errors that happened during an internal act
sebmarkbage Mar 22, 2024
ef549d4
Rethrow uncaught errors from act instead of logging them
sebmarkbage Mar 22, 2024
9f8a43a
Aggregate errors in internal act
sebmarkbage Mar 22, 2024
8fe758b
Aggregate errors in act
sebmarkbage Mar 22, 2024
254af8d
Use shared queue and only track errors once for internalAct/waitFor
sebmarkbage Mar 23, 2024
b4de7d2
Test error logging recovery without act
sebmarkbage Mar 24, 2024
06e4464
Fix tests that failed due to internalAct now rethrowing non-render er…
sebmarkbage Mar 22, 2024
785c32a
Fix tests
sebmarkbage Mar 22, 2024
e32089f
Fix tests that rely on flushSync to throw
sebmarkbage Mar 22, 2024
175484e
Use internal act for prod testing
sebmarkbage Mar 25, 2024
7344587
Build lint process for the reportGlobalError polyfill
sebmarkbage Mar 25, 2024
613ae34
Fix test
sebmarkbage Mar 27, 2024
d3f0b57
Fix legacy tests
rickhanlonii Mar 26, 2024
c06e47d
Fix legacy tests in ReactDOM-test.js
rickhanlonii Mar 26, 2024
45fb81e
Add back React.Children.only
rickhanlonii Mar 26, 2024
8e3c0ae
Fix useSyncExternalStoreShared-test.js
rickhanlonii Mar 26, 2024
7a07e98
Fix ReactFresh-test.js
rickhanlonii Mar 26, 2024
0928d91
Update error messages
sebmarkbage Mar 27, 2024
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
Prev Previous commit
Next Next commit
Fix useSyncExternalStoreShared-test.js
  • Loading branch information
rickhanlonii authored and sebmarkbage committed Mar 27, 2024
commit 8e3c0ae18b0ca17401aaec1352bbb836f39c8cef
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
};
}

test('basic usage', async () => {
it('basic usage', async () => {
const store = createExternalStore('Initial');

function App() {
Expand All @@ -165,7 +165,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
expect(container.textContent).toEqual('Updated');
});

test('skips re-rendering if nothing changes', async () => {
it('skips re-rendering if nothing changes', async () => {
const store = createExternalStore('Initial');

function App() {
Expand All @@ -189,7 +189,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
expect(container.textContent).toEqual('Initial');
});

test('switch to a different store', async () => {
it('switch to a different store', async () => {
const storeA = createExternalStore(0);
const storeB = createExternalStore(0);

Expand Down Expand Up @@ -242,7 +242,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
expect(container.textContent).toEqual('1');
});

test('selecting a specific value inside getSnapshot', async () => {
it('selecting a specific value inside getSnapshot', async () => {
const store = createExternalStore({a: 0, b: 0});

function A() {
Expand Down Expand Up @@ -290,7 +290,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
// In React 18, you can't observe in between a sync render and its
// passive effects, so this is only relevant to legacy roots
// @gate enableUseSyncExternalStoreShim
test(
it(
"compares to current state before bailing out, even when there's a " +
'mutation in between the sync and passive effects',
async () => {
Expand Down Expand Up @@ -334,7 +334,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
},
);

test('mutating the store in between render and commit when getSnapshot has changed', async () => {
it('mutating the store in between render and commit when getSnapshot has changed', async () => {
const store = createExternalStore({a: 1, b: 1});

const getSnapshotA = () => store.getState().a;
Expand Down Expand Up @@ -394,7 +394,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
expect(container.textContent).toEqual('B2');
});

test('mutating the store in between render and commit when getSnapshot has _not_ changed', async () => {
it('mutating the store in between render and commit when getSnapshot has _not_ changed', async () => {
// Same as previous test, but `getSnapshot` does not change
const store = createExternalStore({a: 1, b: 1});

Expand Down Expand Up @@ -453,7 +453,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
expect(container.textContent).toEqual('A1');
});

test("does not bail out if the previous update hasn't finished yet", async () => {
it("does not bail out if the previous update hasn't finished yet", async () => {
const store = createExternalStore(0);

function Child1() {
Expand Down Expand Up @@ -492,7 +492,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
expect(container.textContent).toEqual('00');
});

test('uses the latest getSnapshot, even if it changed in the same batch as a store update', async () => {
it('uses the latest getSnapshot, even if it changed in the same batch as a store update', async () => {
const store = createExternalStore({a: 0, b: 0});

const getSnapshotA = () => store.getState().a;
Expand Down Expand Up @@ -523,7 +523,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
expect(container.textContent).toEqual('2');
});

test('handles errors thrown by getSnapshot', async () => {
it('handles errors thrown by getSnapshot', async () => {
class ErrorBoundary extends React.Component {
state = {error: null};
static getDerivedStateFromError(error) {
Expand Down Expand Up @@ -568,23 +568,41 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
expect(container.textContent).toEqual('0');

// Update that throws in a getSnapshot. We can catch it with an error boundary.
await act(() => {
store.set({value: 1, throwInGetSnapshot: true, throwInIsEqual: false});
});
if (gate(flags => !flags.enableUseSyncExternalStoreShim)) {
assertLog([
'Error in getSnapshot',
// In a concurrent root, React renders a second time to attempt to
// recover from the error.
'Error in getSnapshot',
]);
if (__DEV__ && gate(flags => flags.enableUseSyncExternalStoreShim)) {
// In 17, the error is re-thrown in DEV.
await expect(async () => {
await act(() => {
store.set({
value: 1,
throwInGetSnapshot: true,
throwInIsEqual: false,
});
});
}).rejects.toThrow('Error in getSnapshot');
} else {
assertLog(['Error in getSnapshot']);
await act(() => {
store.set({
value: 1,
throwInGetSnapshot: true,
throwInIsEqual: false,
});
});
}

assertLog(
gate(flags => flags.enableUseSyncExternalStoreShim)
? ['Error in getSnapshot']
: [
'Error in getSnapshot',
// In a concurrent root, React renders a second time to attempt to
// recover from the error.
'Error in getSnapshot',
],
);
expect(container.textContent).toEqual('Error in getSnapshot');
});

test('Infinite loop if getSnapshot keeps returning new reference', async () => {
it('Infinite loop if getSnapshot keeps returning new reference', async () => {
const store = createExternalStore({});

function App() {
Expand All @@ -608,7 +626,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
}).toErrorDev(
gate(flags => flags.enableUseSyncExternalStoreShim)
? [
'Uncaught [',
'Maximum update depth exceeded. ',
'The result of getSnapshot should be cached to avoid an infinite loop',
'The above error occurred in the',
]
Expand All @@ -627,7 +645,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
);
});

test('getSnapshot can return NaN without infinite loop warning', async () => {
it('getSnapshot can return NaN without infinite loop warning', async () => {
const store = createExternalStore('not a number');

function App() {
Expand Down Expand Up @@ -657,7 +675,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
describe('extra features implemented in user-space', () => {
// The selector implementation uses the lazy ref initialization pattern
// @gate !(enableUseRefAccessWarning && __DEV__)
test('memoized selectors are only called once per update', async () => {
it('memoized selectors are only called once per update', async () => {
const store = createExternalStore({a: 0, b: 0});

function selector(state) {
Expand Down Expand Up @@ -700,7 +718,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {

// The selector implementation uses the lazy ref initialization pattern
// @gate !(enableUseRefAccessWarning && __DEV__)
test('Using isEqual to bailout', async () => {
it('Using isEqual to bailout', async () => {
const store = createExternalStore({a: 0, b: 0});

function A() {
Expand Down Expand Up @@ -759,7 +777,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
expect(container.textContent).toEqual('A1B1');
});

test('basic server hydration', async () => {
it('basic server hydration', async () => {
const store = createExternalStore('client');

const ref = React.createRef();
Expand Down Expand Up @@ -812,7 +830,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
});
});

test('regression test for #23150', async () => {
it('regression test for #23150', async () => {
const store = createExternalStore('Initial');

function App() {
Expand Down Expand Up @@ -841,7 +859,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {

// The selector implementation uses the lazy ref initialization pattern
// @gate !(enableUseRefAccessWarning && __DEV__)
test('compares selection to rendered selection even if selector changes', async () => {
it('compares selection to rendered selection even if selector changes', async () => {
const store = createExternalStore({items: ['A', 'B']});

const shallowEqualArray = (a, b) => {
Expand Down Expand Up @@ -960,15 +978,31 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {

expect(container.textContent).toEqual('A');

await expect(async () => {
await act(() => {
store.set({});
});
}).toWarnDev(
ReactFeatureFlags.enableUseRefAccessWarning
? ['Warning: App: Unsafe read of a mutable value during render.']
: [],
);
if (__DEV__ && gate(flags => flags.enableUseSyncExternalStoreShim)) {
// In 17, the error is re-thrown in DEV.
await expect(async () => {
await expect(async () => {
await act(() => {
store.set({});
});
}).rejects.toThrow('Malformed state');
}).toWarnDev(
ReactFeatureFlags.enableUseRefAccessWarning
? ['Warning: App: Unsafe read of a mutable value during render.']
: [],
);
} else {
await expect(async () => {
await act(() => {
store.set({});
});
}).toWarnDev(
ReactFeatureFlags.enableUseRefAccessWarning
? ['Warning: App: Unsafe read of a mutable value during render.']
: [],
);
}

expect(container.textContent).toEqual('Malformed state');
});

Expand Down Expand Up @@ -1005,15 +1039,31 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {

expect(container.textContent).toEqual('A');

await expect(async () => {
await act(() => {
store.set({});
});
}).toWarnDev(
ReactFeatureFlags.enableUseRefAccessWarning
? ['Warning: App: Unsafe read of a mutable value during render.']
: [],
);
if (__DEV__ && gate(flags => flags.enableUseSyncExternalStoreShim)) {
// In 17, the error is re-thrown in DEV.
await expect(async () => {
await expect(async () => {
await act(() => {
store.set({});
});
}).rejects.toThrow('Malformed state');
}).toWarnDev(
ReactFeatureFlags.enableUseRefAccessWarning
? ['Warning: App: Unsafe read of a mutable value during render.']
: [],
);
} else {
await expect(async () => {
await act(() => {
store.set({});
});
}).toWarnDev(
ReactFeatureFlags.enableUseRefAccessWarning
? ['Warning: App: Unsafe read of a mutable value during render.']
: [],
);
}

expect(container.textContent).toEqual('Malformed state');
});
});
Expand Down