Test fixes related to changes in Jest's Fake Timer behavior (#29011)

Summary:
Fixed tests related to changing Jest's fake timer behavior.
And some of the test code in LogBoxData-test.js itself was incorrect so I am fixing it.

LogBoxData-test.js fails when I try to build a new local development environment and fork the React Native source to run a JavaScript test.
The error message is:
runAllImmediates is not available when using modern timers

After checking, runAllImmediates could not be used with the following modification.
71631f6bf9

## Changelog

[Internal] [Fixed] - Test fixes related to changes in Jest's Fake Timer behavior

Pull Request resolved: https://github.com/facebook/react-native/pull/29011

Test Plan: Ran JavaScript Tests locally.

Reviewed By: cpojer

Differential Revision: D22494991

Pulled By: rickhanlonii

fbshipit-source-id: 4deeaf82b5092ff8b60c4606eb45549beb452a5f
This commit is contained in:
makitake2013 2020-07-12 00:27:13 -07:00 коммит произвёл Facebook GitHub Bot
Родитель ec18e35cd3
Коммит 320398afe5
1 изменённых файлов: 85 добавлений и 95 удалений

Просмотреть файл

@ -51,7 +51,7 @@ const observe = () => {
};
};
const addLogs = logs => {
const addLogs = (logs, options) => {
logs.forEach(message => {
LogBoxData.addLog({
level: 'warn',
@ -62,10 +62,13 @@ const addLogs = logs => {
category: message,
componentStack: [],
});
if (options == null || options.flush !== false) {
jest.runOnlyPendingTimers();
}
});
};
const addSoftErrors = errors => {
const addSoftErrors = (errors, options) => {
errors.forEach(error => {
LogBoxData.addException(
Object.assign(
@ -85,10 +88,13 @@ const addSoftErrors = errors => {
: error,
),
);
if (options == null || options.flush !== false) {
jest.runOnlyPendingTimers();
}
});
};
const addFatalErrors = errors => {
const addFatalErrors = (errors, options) => {
errors.forEach(error => {
LogBoxData.addException(
Object.assign(
@ -108,37 +114,43 @@ const addFatalErrors = errors => {
: error,
),
);
if (options == null || options.flush !== false) {
// Errors include two timers, the second is for optimistic symbolication.
jest.runOnlyPendingTimers();
jest.runOnlyPendingTimers();
}
});
};
const addSyntaxError = () => {
addFatalErrors([
const addSyntaxError = options => {
addFatalErrors(
[
{
message: `
197 | });
198 |
> 199 | export default CrashReactApp;
| ^
200 |`,
originalMessage: `TransformError SyntaxError: /path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js: 'import' and 'export' may only appear at the top level (199:0)
197 | });
198 |
> 199 | export default CrashReactApp;
| ^
200 |`,
},
]);
],
options,
);
};
beforeEach(() => {
jest.resetModules();
});
const flushLogs = () => {
jest.runAllImmediates();
jest.runAllTimers();
const flushToObservers = () => {
// Observer updates are debounced and need to advance timers to flush.
jest.runOnlyPendingTimers();
};
describe('LogBoxData', () => {
@ -147,7 +159,6 @@ describe('LogBoxData', () => {
addSoftErrors(['B']);
addFatalErrors(['C']);
addSyntaxError();
flushLogs();
expect(registry().length).toBe(4);
expect(registry()[0]).toBeDefined();
@ -169,10 +180,9 @@ describe('LogBoxData', () => {
addSoftErrors(['C', 'D']);
addFatalErrors(['E', 'F']);
addSyntaxError();
flushLogs();
expect(registry().length).toBe(7);
expect(selectedLogIndex()).toBe(4); // Fatal index.
expect(selectedLogIndex()).toBe(6); // Syntax error index.
LogBoxData.clear();
expect(registry().length).toBe(0);
@ -183,14 +193,13 @@ describe('LogBoxData', () => {
addLogs(['A', 'B']);
addSoftErrors(['C', 'D', 'E']);
addSyntaxError();
flushLogs();
expect(registry().length).toBe(6);
expect(selectedLogIndex()).toBe(5); // Fatal index.
expect(selectedLogIndex()).toBe(5); // Syntax error index.
LogBoxData.clearWarnings();
expect(registry().length).toBe(4);
expect(selectedLogIndex()).toBe(3); // New fatal index.
expect(selectedLogIndex()).toBe(3); // New syntax error index.
});
it('clears errors and fatals, but not syntax errors.', () => {
@ -198,14 +207,13 @@ describe('LogBoxData', () => {
addSoftErrors(['C', 'D', 'E']);
addFatalErrors(['F']);
addSyntaxError();
flushLogs();
expect(registry().length).toBe(7);
expect(selectedLogIndex()).toBe(5); // Fatal index.
expect(selectedLogIndex()).toBe(6); // Syntax error index.
LogBoxData.clearErrors();
expect(registry().length).toBe(3);
expect(selectedLogIndex()).toBe(2); // New Fatal index.
expect(selectedLogIndex()).toBe(2); // New syntax error index.
});
it('clears all types except syntax errors', () => {
@ -213,24 +221,25 @@ describe('LogBoxData', () => {
addSoftErrors(['C', 'D', 'E']);
addFatalErrors(['F']);
addSyntaxError();
flushLogs();
expect(registry().length).toBe(7);
expect(selectedLogIndex()).toBe(5); // Fatal index.
expect(selectedLogIndex()).toBe(6); // Syntax error index.
LogBoxData.clearErrors();
LogBoxData.clearWarnings();
expect(registry().length).toBe(1);
expect(selectedLogIndex()).toBe(0); // New Fatal index.
expect(selectedLogIndex()).toBe(0); // New syntax error index.
});
it('keeps logs in chronological order', () => {
addLogs(['A']);
addSoftErrors(['B']);
addFatalErrors(['C']);
flushLogs();
addLogs(['A'], {flush: false});
addSoftErrors(['B'], {flush: false});
addFatalErrors(['C'], {flush: false});
// Flush logs manually.
jest.runAllTimers();
addLogs(['D']);
flushLogs();
let logs = registry();
expect(logs.length).toBe(4);
@ -240,7 +249,6 @@ describe('LogBoxData', () => {
expect(logs[3].category).toEqual('D');
addLogs(['A']);
jest.runAllImmediates();
// Expect `A` to be added to the end of the registry.
logs = registry();
@ -256,40 +264,39 @@ describe('LogBoxData', () => {
expect(selectedLogIndex()).toBe(-1);
LogBoxData.setSelectedLog(1);
flushLogs();
expect(selectedLogIndex()).toBe(1);
});
it('does not set the selectedLogIndex for warnings', () => {
addLogs(['A']);
flushLogs();
expect(selectedLogIndex()).toBe(-1);
});
it('does not set the selectedLogIndex for soft errors', () => {
addSoftErrors(['A']);
flushLogs();
expect(selectedLogIndex()).toBe(-1);
});
it('sets the selectedLogIndex to the first fatal error (after symbolication)', () => {
addFatalErrors(['A']);
addFatalErrors(['A'], {flush: false});
// Order maters for symbolication before timeout.
flushLogs();
jest.runAllTimers();
// Order maters for testing symbolication before timeout.
jest.runOnlyPendingTimers(); // Trigger appendNewLog.
jest.advanceTimersByTime(10); // Trigger symbolication but not timeout.
jest.runAllTimers(); // Flush remaining.
expect(selectedLogIndex()).toBe(0);
addLogs(['B']);
addFatalErrors(['C']);
addLogs(['B'], {flush: false});
addFatalErrors(['C'], {flush: false});
// Order maters for symbolication before timeout.
flushLogs();
jest.runAllTimers();
// Order maters for testing symbolication before timeout.
jest.runOnlyPendingTimers(); // Trigger appendNewLogs.
jest.advanceTimersByTime(10); // Trigger symbolication.
jest.runAllTimers(); // Flush remaining.
// This should still be 0 (the first fatal exception)
// becuase it is the most likely source of the error.
@ -299,20 +306,22 @@ describe('LogBoxData', () => {
});
it('sets the selectedLogIndex to the first fatal error (hitting timeout limit)', () => {
addFatalErrors(['A']);
addFatalErrors(['A'], {flush: false});
// Order maters for timeout before symbolication.
jest.runAllTimers();
flushLogs();
// Order maters for testing timeout before symbolication.
jest.runOnlyPendingTimers(); // Trigger appendNewLog.
jest.advanceTimersByTime(1001); // Trigger OPTIMISTIC_WAIT_TIME timeout.
jest.runAllTimers(); // Flush remaining.
expect(selectedLogIndex()).toBe(0);
addLogs(['B']);
addFatalErrors(['C']);
// Order maters for timeout before symbolication.
jest.runAllTimers();
flushLogs();
// Order maters for testing timeout before symbolication.
jest.runOnlyPendingTimers(); // Trigger appendNewLogs.
jest.advanceTimersByTime(1001); // Trigger OPTIMISTIC_WAIT_TIME timeout.
jest.runAllTimers(); // Flush remaining.
// This should still be 0 (the first fatal exception)
// becuase it is the most likely source of the error.
@ -323,45 +332,38 @@ describe('LogBoxData', () => {
it('sets the selectedLogIndex to the last syntax error', () => {
addSyntaxError();
flushLogs();
expect(selectedLogIndex()).toBe(0);
addLogs(['B']);
addSyntaxError();
flushLogs();
expect(selectedLogIndex()).toBe(2);
});
it('keeps selectedLogIndex set to the syntax error even when a new fatal is added', () => {
addSyntaxError();
flushLogs();
expect(selectedLogIndex()).toBe(0);
addLogs(['B']);
addFatalErrors(['C']);
flushLogs();
expect(selectedLogIndex()).toBe(0);
});
it('keeps selectedLogIndex set to the syntax error even when explicitly changed', () => {
addSyntaxError();
flushLogs();
expect(selectedLogIndex()).toBe(0);
LogBoxData.setSelectedLog(1);
flushLogs();
expect(selectedLogIndex()).toBe(0);
});
it('increments the count of previous log with matching category (logs)', () => {
addLogs(['A', 'B']);
flushLogs();
let logs = registry();
expect(logs.length).toBe(2);
@ -371,7 +373,6 @@ describe('LogBoxData', () => {
expect(logs[1].count).toBe(1);
addLogs(['B']);
flushLogs();
// Expect `B` to be rolled into the last log.
logs = registry();
@ -384,7 +385,6 @@ describe('LogBoxData', () => {
it('increments the count of previous log with matching category (errors)', () => {
addFatalErrors(['A', 'B']);
flushLogs();
let logs = registry();
expect(logs.length).toBe(2);
@ -394,7 +394,6 @@ describe('LogBoxData', () => {
expect(logs[1].count).toBe(1);
addSoftErrors(['B']);
flushLogs();
// Expect `B` to be rolled into the last log.
logs = registry();
@ -407,14 +406,12 @@ describe('LogBoxData', () => {
it('increments the count of previous log with matching category (syntax)', () => {
addSyntaxError();
flushLogs();
let logs = registry();
expect(logs.length).toBe(1);
expect(logs[0].count).toBe(1);
addSyntaxError();
flushLogs();
logs = registry();
expect(logs.length).toBe(1);
@ -423,7 +420,6 @@ describe('LogBoxData', () => {
it('ignores logs matching patterns (logs)', () => {
addLogs(['A!', 'B?', 'C!']);
flushLogs();
expect(filteredRegistry().length).toBe(3);
@ -437,7 +433,6 @@ describe('LogBoxData', () => {
it('ignores logs matching patterns (errors)', () => {
addSoftErrors(['A!', 'B?']);
addFatalErrors(['C!']);
flushLogs();
expect(filteredRegistry().length).toBe(3);
@ -450,7 +445,6 @@ describe('LogBoxData', () => {
it('ignores matching regexs or pattern (logs)', () => {
addLogs(['There are 4 dogs', 'There are 3 cats', 'There are H cats']);
flushLogs();
expect(filteredRegistry().length).toBe(3);
@ -467,7 +461,6 @@ describe('LogBoxData', () => {
it('ignores matching regexs or pattern (errors)', () => {
addSoftErrors(['There are 4 dogs', 'There are 3 cats']);
addFatalErrors(['There are H cats']);
flushLogs();
expect(filteredRegistry().length).toBe(3);
@ -486,7 +479,6 @@ describe('LogBoxData', () => {
addSoftErrors(['B?']);
addFatalErrors(['C!']);
addSyntaxError();
flushLogs();
expect(registry().length).toBe(4);
expect(disabledState()).toBe(false);
@ -516,7 +508,7 @@ describe('LogBoxData', () => {
expect(observer.mock.calls.length).toBe(1);
addLogs(['A']);
flushLogs();
flushToObservers();
expect(observer.mock.calls.length).toBe(2);
// We expect observers to recieve the same Set object in sequential updates
@ -541,17 +533,17 @@ describe('LogBoxData', () => {
expect(observer.mock.calls.length).toBe(1);
addLogs(['A']);
flushLogs();
flushToObservers();
expect(observer.mock.calls.length).toBe(2);
const lastLog = Array.from(observer.mock.calls[1][0].logs)[0];
LogBoxData.dismiss(lastLog);
jest.runAllImmediates();
flushToObservers();
expect(observer.mock.calls.length).toBe(3);
// Does nothing when category does not exist.
LogBoxData.dismiss(lastLog);
jest.runAllImmediates();
flushToObservers();
expect(observer.mock.calls.length).toBe(3);
});
@ -560,16 +552,16 @@ describe('LogBoxData', () => {
expect(observer.mock.calls.length).toBe(1);
addLogs(['A']);
flushLogs();
flushToObservers();
expect(observer.mock.calls.length).toBe(2);
LogBoxData.clear();
jest.runAllImmediates();
flushToObservers();
expect(observer.mock.calls.length).toBe(3);
// Does nothing when already empty.
LogBoxData.clear();
jest.runAllImmediates();
flushToObservers();
expect(observer.mock.calls.length).toBe(3);
});
@ -581,17 +573,16 @@ describe('LogBoxData', () => {
addSoftErrors(['B']);
addFatalErrors(['C']);
addSyntaxError();
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(2);
expect(observer.mock.calls.length).toBe(5);
LogBoxData.clearWarnings();
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(3);
flushToObservers();
expect(observer.mock.calls.length).toBe(6);
// Does nothing when already empty.
LogBoxData.clearWarnings();
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(3);
flushToObservers();
expect(observer.mock.calls.length).toBe(6);
});
it('updates observers when errors cleared', () => {
@ -602,17 +593,16 @@ describe('LogBoxData', () => {
addSoftErrors(['B']);
addFatalErrors(['C']);
addSyntaxError();
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(2);
expect(observer.mock.calls.length).toBe(5);
LogBoxData.clearErrors();
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(3);
flushToObservers();
expect(observer.mock.calls.length).toBe(6);
// Does nothing when already empty.
LogBoxData.clearErrors();
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(3);
flushToObservers();
expect(observer.mock.calls.length).toBe(6);
});
it('updates observers when an ignore pattern is added', () => {
@ -620,16 +610,16 @@ describe('LogBoxData', () => {
expect(observer.mock.calls.length).toBe(1);
LogBoxData.addIgnorePatterns(['?']);
jest.runAllImmediates();
flushToObservers();
expect(observer.mock.calls.length).toBe(2);
LogBoxData.addIgnorePatterns(['!']);
jest.runAllImmediates();
flushToObservers();
expect(observer.mock.calls.length).toBe(3);
// Does nothing for an existing ignore pattern.
LogBoxData.addIgnorePatterns(['!']);
jest.runAllImmediates();
flushToObservers();
expect(observer.mock.calls.length).toBe(3);
});
@ -638,21 +628,21 @@ describe('LogBoxData', () => {
expect(observer.mock.calls.length).toBe(1);
LogBoxData.setDisabled(true);
jest.runAllImmediates();
flushToObservers();
expect(observer.mock.calls.length).toBe(2);
// Does nothing when already disabled.
LogBoxData.setDisabled(true);
jest.runAllImmediates();
flushToObservers();
expect(observer.mock.calls.length).toBe(2);
LogBoxData.setDisabled(false);
jest.runAllImmediates();
flushToObservers();
expect(observer.mock.calls.length).toBe(3);
// Does nothing when already enabled.
LogBoxData.setDisabled(false);
jest.runAllImmediates();
flushToObservers();
expect(observer.mock.calls.length).toBe(3);
});