Best JavaScript code snippet using playwright-internal
SchedulerDOM-test.js
Source:SchedulerDOM-test.js
...89 describe('scheduleCallback', () => {90 it('calls the callback within the frame when not blocked', () => {91 const {unstable_scheduleCallback: scheduleCallback} = Scheduler;92 const cb = jest.fn();93 scheduleCallback(cb);94 advanceOneFrame({timeLeftInFrame: 15});95 expect(cb).toHaveBeenCalledTimes(1);96 });97 it('inserts its rAF callback as early into the queue as possible', () => {98 const {unstable_scheduleCallback: scheduleCallback} = Scheduler;99 const log = [];100 const useRAFCallback = () => {101 log.push('userRAFCallback');102 };103 scheduleCallback(() => {104 // Call rAF while idle work is being flushed.105 requestAnimationFrame(useRAFCallback);106 });107 advanceOneFrame({timeLeftInFrame: 1});108 // There should be two callbacks: the one scheduled by Scheduler at the109 // beginning of the frame, and the one scheduled later during that frame.110 expect(rAFCallbacks.length).toBe(2);111 // The user callback should be the second callback.112 rAFCallbacks[1]();113 expect(log).toEqual(['userRAFCallback']);114 });115 describe('with multiple callbacks', () => {116 it('accepts multiple callbacks and calls within frame when not blocked', () => {117 const {unstable_scheduleCallback: scheduleCallback} = Scheduler;118 const callbackLog = [];119 const callbackA = jest.fn(() => callbackLog.push('A'));120 const callbackB = jest.fn(() => callbackLog.push('B'));121 scheduleCallback(callbackA);122 // initially waits to call the callback123 expect(callbackLog).toEqual([]);124 // waits while second callback is passed125 scheduleCallback(callbackB);126 expect(callbackLog).toEqual([]);127 // after a delay, calls as many callbacks as it has time for128 advanceOneFrame({timeLeftInFrame: 15});129 expect(callbackLog).toEqual(['A', 'B']);130 });131 it("accepts callbacks between animationFrame and postMessage and doesn't stall", () => {132 const {unstable_scheduleCallback: scheduleCallback} = Scheduler;133 const callbackLog = [];134 const callbackA = jest.fn(() => callbackLog.push('A'));135 const callbackB = jest.fn(() => callbackLog.push('B'));136 const callbackC = jest.fn(() => callbackLog.push('C'));137 scheduleCallback(callbackA);138 // initially waits to call the callback139 expect(callbackLog).toEqual([]);140 runRAFCallbacks();141 // this should schedule work *after* the requestAnimationFrame but before the message handler142 scheduleCallback(callbackB);143 expect(callbackLog).toEqual([]);144 // now it should drain the message queue and do all scheduled work145 runPostMessageCallbacks({timeLeftInFrame: 15});146 expect(callbackLog).toEqual(['A', 'B']);147 // advances timers, now with an empty queue of work (to ensure they don't deadlock)148 advanceOneFrame({timeLeftInFrame: 15});149 // see if more work can be done now.150 scheduleCallback(callbackC);151 expect(callbackLog).toEqual(['A', 'B']);152 advanceOneFrame({timeLeftInFrame: 15});153 expect(callbackLog).toEqual(['A', 'B', 'C']);154 });155 it(156 'schedules callbacks in correct order and' +157 'keeps calling them if there is time',158 () => {159 const {unstable_scheduleCallback: scheduleCallback} = Scheduler;160 const callbackLog = [];161 const callbackA = jest.fn(() => {162 callbackLog.push('A');163 scheduleCallback(callbackC);164 });165 const callbackB = jest.fn(() => {166 callbackLog.push('B');167 });168 const callbackC = jest.fn(() => {169 callbackLog.push('C');170 });171 scheduleCallback(callbackA);172 // initially waits to call the callback173 expect(callbackLog).toEqual([]);174 // continues waiting while B is scheduled175 scheduleCallback(callbackB);176 expect(callbackLog).toEqual([]);177 // after a delay, calls the scheduled callbacks,178 // and also calls new callbacks scheduled by current callbacks179 advanceOneFrame({timeLeftInFrame: 15});180 expect(callbackLog).toEqual(['A', 'B', 'C']);181 },182 );183 it('schedules callbacks in correct order when callbacks have many nested scheduleCallback calls', () => {184 const {unstable_scheduleCallback: scheduleCallback} = Scheduler;185 const callbackLog = [];186 const callbackA = jest.fn(() => {187 callbackLog.push('A');188 scheduleCallback(callbackC);189 scheduleCallback(callbackD);190 });191 const callbackB = jest.fn(() => {192 callbackLog.push('B');193 scheduleCallback(callbackE);194 scheduleCallback(callbackF);195 });196 const callbackC = jest.fn(() => {197 callbackLog.push('C');198 });199 const callbackD = jest.fn(() => {200 callbackLog.push('D');201 });202 const callbackE = jest.fn(() => {203 callbackLog.push('E');204 });205 const callbackF = jest.fn(() => {206 callbackLog.push('F');207 });208 scheduleCallback(callbackA);209 scheduleCallback(callbackB);210 // initially waits to call the callback211 expect(callbackLog).toEqual([]);212 // while flushing callbacks, calls as many as it has time for213 advanceOneFrame({timeLeftInFrame: 15});214 expect(callbackLog).toEqual(['A', 'B', 'C', 'D', 'E', 'F']);215 });216 it('schedules callbacks in correct order when they use scheduleCallback to schedule themselves', () => {217 const {unstable_scheduleCallback: scheduleCallback} = Scheduler;218 const callbackLog = [];219 let callbackAIterations = 0;220 const callbackA = jest.fn(() => {221 if (callbackAIterations < 1) {222 scheduleCallback(callbackA);223 }224 callbackLog.push('A' + callbackAIterations);225 callbackAIterations++;226 });227 const callbackB = jest.fn(() => callbackLog.push('B'));228 scheduleCallback(callbackA);229 // initially waits to call the callback230 expect(callbackLog).toEqual([]);231 scheduleCallback(callbackB);232 expect(callbackLog).toEqual([]);233 // after a delay, calls the latest callback passed234 advanceOneFrame({timeLeftInFrame: 15});235 expect(callbackLog).toEqual(['A0', 'B', 'A1']);236 });237 });238 describe('when callbacks time out: ', () => {239 // USEFUL INFO:240 // startOfLatestFrame is a global that goes up every time rAF runs241 // currentTime defaults to startOfLatestFrame inside rAF callback242 // and currentTime defaults to 15 before next frame inside idleTick243 describe('when there is no more time left in the frame', () => {244 it('calls any callback which has timed out, waits for others', () => {245 const {unstable_scheduleCallback: scheduleCallback} = Scheduler;246 startOfLatestFrame = 1000000000000;247 currentTime = startOfLatestFrame - 10;248 const callbackLog = [];249 // simple case of one callback which times out, another that won't.250 const callbackA = jest.fn(() => callbackLog.push('A'));251 const callbackB = jest.fn(() => callbackLog.push('B'));252 const callbackC = jest.fn(() => callbackLog.push('C'));253 scheduleCallback(callbackA); // won't time out254 scheduleCallback(callbackB, {timeout: 100}); // times out later255 scheduleCallback(callbackC, {timeout: 2}); // will time out fast256 // push time ahead a bit so that we have no idle time257 advanceOneFrame({timePastFrameDeadline: 16});258 // callbackC should have timed out259 expect(callbackLog).toEqual(['C']);260 // push time ahead a bit so that we have no idle time261 advanceOneFrame({timePastFrameDeadline: 16});262 // callbackB should have timed out263 expect(callbackLog).toEqual(['C', 'B']);264 // let's give ourselves some idle time now265 advanceOneFrame({timeLeftInFrame: 16});266 // we should have run callbackA in the idle time267 expect(callbackLog).toEqual(['C', 'B', 'A']);268 });269 });270 describe('when there is some time left in the frame', () => {271 it('calls timed out callbacks and then any more pending callbacks, defers others if time runs out', () => {272 const {unstable_scheduleCallback: scheduleCallback} = Scheduler;273 startOfLatestFrame = 1000000000000;274 currentTime = startOfLatestFrame - 10;275 const callbackLog = [];276 // simple case of one callback which times out, others that won't.277 const callbackA = jest.fn(() => {278 callbackLog.push('A');279 // time passes, causing us to run out of idle time280 currentTime += 25;281 });282 const callbackB = jest.fn(() => callbackLog.push('B'));283 const callbackC = jest.fn(() => callbackLog.push('C'));284 const callbackD = jest.fn(() => callbackLog.push('D'));285 scheduleCallback(callbackA, {timeout: 100}); // won't time out286 scheduleCallback(callbackB, {timeout: 100}); // times out later287 scheduleCallback(callbackC, {timeout: 2}); // will time out fast288 scheduleCallback(callbackD, {timeout: 200}); // won't time out289 advanceOneFrame({timeLeftInFrame: 15}); // runs rAF and postMessage callbacks290 // callbackC should have timed out291 // we should have had time to call A also, then we run out of time292 expect(callbackLog).toEqual(['C', 'A']);293 // push time ahead a bit so that we have no idle time294 advanceOneFrame({timePastFrameDeadline: 16});295 // callbackB should have timed out296 // but we should not run callbackD because we have no idle time297 expect(callbackLog).toEqual(['C', 'A', 'B']);298 advanceOneFrame({timeLeftInFrame: 15}); // runs rAF and postMessage callbacks299 // we should have run callbackD in the idle time300 expect(callbackLog).toEqual(['C', 'A', 'B', 'D']);301 advanceOneFrame({timeLeftInFrame: 15}); // runs rAF and postMessage callbacks302 // we should not have run anything again, nothing is scheduled303 expect(callbackLog).toEqual(['C', 'A', 'B', 'D']);304 });305 });306 });307 });308 describe('cancelCallback', () => {309 it('cancels the scheduled callback', () => {310 const {311 unstable_scheduleCallback: scheduleCallback,312 unstable_cancelCallback: cancelCallback,313 } = Scheduler;314 const cb = jest.fn();315 const callbackId = scheduleCallback(cb);316 expect(cb).toHaveBeenCalledTimes(0);317 cancelCallback(callbackId);318 advanceOneFrame({timeLeftInFrame: 15});319 expect(cb).toHaveBeenCalledTimes(0);320 });321 describe('with multiple callbacks', () => {322 it('when called more than once', () => {323 const {324 unstable_scheduleCallback: scheduleCallback,325 unstable_cancelCallback: cancelCallback,326 } = Scheduler;327 const callbackLog = [];328 const callbackA = jest.fn(() => callbackLog.push('A'));329 const callbackB = jest.fn(() => callbackLog.push('B'));330 const callbackC = jest.fn(() => callbackLog.push('C'));331 scheduleCallback(callbackA);332 const callbackId = scheduleCallback(callbackB);333 scheduleCallback(callbackC);334 cancelCallback(callbackId);335 cancelCallback(callbackId);336 cancelCallback(callbackId);337 // Initially doesn't call anything338 expect(callbackLog).toEqual([]);339 advanceOneFrame({timeLeftInFrame: 15});340 // Should still call A and C341 expect(callbackLog).toEqual(['A', 'C']);342 expect(callbackB).toHaveBeenCalledTimes(0);343 });344 it('when one callback cancels the next one', () => {345 const {346 unstable_scheduleCallback: scheduleCallback,347 unstable_cancelCallback: cancelCallback,348 } = Scheduler;349 const callbackLog = [];350 let callbackBId;351 const callbackA = jest.fn(() => {352 callbackLog.push('A');353 cancelCallback(callbackBId);354 });355 const callbackB = jest.fn(() => callbackLog.push('B'));356 scheduleCallback(callbackA);357 callbackBId = scheduleCallback(callbackB);358 // Initially doesn't call anything359 expect(callbackLog).toEqual([]);360 advanceOneFrame({timeLeftInFrame: 15});361 // B should not get called because A cancelled B362 expect(callbackLog).toEqual(['A']);363 expect(callbackB).toHaveBeenCalledTimes(0);364 });365 });366 });367 describe('when callbacks throw errors', () => {368 describe('when some callbacks throw', () => {369 /**370 * + +371 * | rAF postMessage |372 * | |373 * | +---------------------+ |374 * | | paint/layout | cbA() cbB() cbC() cbD() cbE() |375 * | +---------------------+ ^ ^ |376 * | | | |377 * + | | +378 * + +379 * throw errors380 *381 *382 */383 it('still calls all callbacks within same frame', () => {384 const {unstable_scheduleCallback: scheduleCallback} = Scheduler;385 const callbackLog = [];386 const callbackA = jest.fn(() => callbackLog.push('A'));387 const callbackB = jest.fn(() => {388 callbackLog.push('B');389 throw new Error('B error');390 });391 const callbackC = jest.fn(() => callbackLog.push('C'));392 const callbackD = jest.fn(() => {393 callbackLog.push('D');394 throw new Error('D error');395 });396 const callbackE = jest.fn(() => callbackLog.push('E'));397 scheduleCallback(callbackA);398 scheduleCallback(callbackB);399 scheduleCallback(callbackC);400 scheduleCallback(callbackD);401 scheduleCallback(callbackE);402 // Initially doesn't call anything403 expect(callbackLog).toEqual([]);404 catchPostMessageErrors = true;405 advanceOneFrame({timeLeftInFrame: 15});406 // calls all callbacks407 expect(callbackLog).toEqual(['A', 'B', 'C', 'D', 'E']);408 // errors should still get thrown409 const postMessageErrorMessages = postMessageErrors.map(e => e.message);410 expect(postMessageErrorMessages).toEqual(['B error', 'D error']);411 catchPostMessageErrors = false;412 });413 /**414 * timed out415 * + + +--+416 * + rAF postMessage | | | +417 * | | | | |418 * | +---------------------+ v v v |419 * | | paint/layout | cbA() cbB() cbC() cbD() cbE() |420 * | +---------------------+ ^ ^ |421 * | | | |422 * + | | +423 * + +424 * throw errors425 *426 *427 */428 it('and with some timed out callbacks, still calls all callbacks within same frame', () => {429 const {unstable_scheduleCallback: scheduleCallback} = Scheduler;430 const callbackLog = [];431 const callbackA = jest.fn(() => {432 callbackLog.push('A');433 throw new Error('A error');434 });435 const callbackB = jest.fn(() => callbackLog.push('B'));436 const callbackC = jest.fn(() => callbackLog.push('C'));437 const callbackD = jest.fn(() => {438 callbackLog.push('D');439 throw new Error('D error');440 });441 const callbackE = jest.fn(() => callbackLog.push('E'));442 scheduleCallback(callbackA);443 scheduleCallback(callbackB);444 scheduleCallback(callbackC, {timeout: 2}); // times out fast445 scheduleCallback(callbackD, {timeout: 2}); // times out fast446 scheduleCallback(callbackE, {timeout: 2}); // times out fast447 // Initially doesn't call anything448 expect(callbackLog).toEqual([]);449 catchPostMessageErrors = true;450 advanceOneFrame({timeLeftInFrame: 15});451 // calls all callbacks; calls timed out ones first452 expect(callbackLog).toEqual(['C', 'D', 'E', 'A', 'B']);453 // errors should still get thrown454 const postMessageErrorMessages = postMessageErrors.map(e => e.message);455 expect(postMessageErrorMessages).toEqual(['D error', 'A error']);456 catchPostMessageErrors = false;457 });458 });459 describe('when all scheduled callbacks throw', () => {460 /**461 * + +462 * | rAF postMessage |463 * | |464 * | +---------------------+ |465 * | | paint/layout | cbA() cbB() cbC() cbD() cbE() |466 * | +---------------------+ ^ ^ ^ ^ ^ |467 * | | | | | | |468 * + | | | | | +469 * | + + + +470 * + all callbacks throw errors471 *472 *473 */474 it('still calls all callbacks within same frame', () => {475 const {unstable_scheduleCallback: scheduleCallback} = Scheduler;476 const callbackLog = [];477 const callbackA = jest.fn(() => {478 callbackLog.push('A');479 throw new Error('A error');480 });481 const callbackB = jest.fn(() => {482 callbackLog.push('B');483 throw new Error('B error');484 });485 const callbackC = jest.fn(() => {486 callbackLog.push('C');487 throw new Error('C error');488 });489 const callbackD = jest.fn(() => {490 callbackLog.push('D');491 throw new Error('D error');492 });493 const callbackE = jest.fn(() => {494 callbackLog.push('E');495 throw new Error('E error');496 });497 scheduleCallback(callbackA);498 scheduleCallback(callbackB);499 scheduleCallback(callbackC);500 scheduleCallback(callbackD);501 scheduleCallback(callbackE);502 // Initially doesn't call anything503 expect(callbackLog).toEqual([]);504 catchPostMessageErrors = true;505 advanceOneFrame({timeLeftInFrame: 15});506 // calls all callbacks507 expect(callbackLog).toEqual(['A', 'B', 'C', 'D', 'E']);508 // errors should still get thrown509 const postMessageErrorMessages = postMessageErrors.map(e => e.message);510 expect(postMessageErrorMessages).toEqual([511 'A error',512 'B error',513 'C error',514 'D error',515 'E error',516 ]);517 catchPostMessageErrors = false;518 });519 /**520 * postMessage521 * + +522 * | rAF all callbacks time out |523 * | |524 * | +---------------------+ |525 * | | paint/layout | cbA() cbB() cbC() cbD() cbE() |526 * | +---------------------+ ^ ^ ^ ^ ^ |527 * | | | | | | |528 * + | | | | | +529 * | + + + +530 * + all callbacks throw errors531 *532 *533 */534 it('and with all timed out callbacks, still calls all callbacks within same frame', () => {535 const {unstable_scheduleCallback: scheduleCallback} = Scheduler;536 const callbackLog = [];537 const callbackA = jest.fn(() => {538 callbackLog.push('A');539 throw new Error('A error');540 });541 const callbackB = jest.fn(() => {542 callbackLog.push('B');543 throw new Error('B error');544 });545 const callbackC = jest.fn(() => {546 callbackLog.push('C');547 throw new Error('C error');548 });549 const callbackD = jest.fn(() => {550 callbackLog.push('D');551 throw new Error('D error');552 });553 const callbackE = jest.fn(() => {554 callbackLog.push('E');555 throw new Error('E error');556 });557 scheduleCallback(callbackA, {timeout: 2}); // times out fast558 scheduleCallback(callbackB, {timeout: 2}); // times out fast559 scheduleCallback(callbackC, {timeout: 2}); // times out fast560 scheduleCallback(callbackD, {timeout: 2}); // times out fast561 scheduleCallback(callbackE, {timeout: 2}); // times out fast562 // Initially doesn't call anything563 expect(callbackLog).toEqual([]);564 catchPostMessageErrors = true;565 advanceOneFrame({timeLeftInFrame: 15});566 // calls all callbacks567 expect(callbackLog).toEqual(['A', 'B', 'C', 'D', 'E']);568 // errors should still get thrown569 const postMessageErrorMessages = postMessageErrors.map(e => e.message);570 expect(postMessageErrorMessages).toEqual([571 'A error',572 'B error',573 'C error',574 'D error',575 'E error',576 ]);577 catchPostMessageErrors = false;578 });579 });580 describe('when callbacks throw over multiple frames', () => {581 /**582 *583 * **Detail View of Frame 1**584 *585 * + +586 * | rAF postMessage |587 * | |588 * | +---------------------+ |589 * | | paint/layout | cbA() cbB() | ... Frame 2590 * | +---------------------+ ^ ^ |591 * | | | |592 * + + | +593 * errors |594 * +595 * takes long time596 * and pushes rest of597 * callbacks into598 * next frame ->599 *600 *601 *602 * **Overview of frames 1-4**603 *604 *605 * + + + + +606 * | | | | |607 * | +--+ | +--+ | +--+ | +--+ |608 * | +--+ A,B+-> +--+ C,D+-> +--+ E,F+-> +--+ G |609 * + ^ + ^ + ^ + +610 * | | |611 * error error error612 *613 *614 */615 it('still calls all callbacks within same frame', () => {616 const {unstable_scheduleCallback: scheduleCallback} = Scheduler;617 startOfLatestFrame = 1000000000000;618 currentTime = startOfLatestFrame - 10;619 catchPostMessageErrors = true;620 const callbackLog = [];621 const callbackA = jest.fn(() => {622 callbackLog.push('A');623 throw new Error('A error');624 });625 const callbackB = jest.fn(() => {626 callbackLog.push('B');627 // time passes, causing us to run out of idle time628 currentTime += 25;629 });630 const callbackC = jest.fn(() => {631 callbackLog.push('C');632 throw new Error('C error');633 });634 const callbackD = jest.fn(() => {635 callbackLog.push('D');636 // time passes, causing us to run out of idle time637 currentTime += 25;638 });639 const callbackE = jest.fn(() => {640 callbackLog.push('E');641 throw new Error('E error');642 });643 const callbackF = jest.fn(() => {644 callbackLog.push('F');645 // time passes, causing us to run out of idle time646 currentTime += 25;647 });648 const callbackG = jest.fn(() => callbackLog.push('G'));649 scheduleCallback(callbackA);650 scheduleCallback(callbackB);651 scheduleCallback(callbackC);652 scheduleCallback(callbackD);653 scheduleCallback(callbackE);654 scheduleCallback(callbackF);655 scheduleCallback(callbackG);656 // does nothing initially657 expect(callbackLog).toEqual([]);658 // frame 1;659 // callback A runs and throws, callback B takes up rest of frame660 advanceOneFrame({timeLeftInFrame: 15}); // runs rAF and postMessage callbacks661 // calls A and B662 expect(callbackLog).toEqual(['A', 'B']);663 // error was thrown from A664 let postMessageErrorMessages = postMessageErrors.map(e => e.message);665 expect(postMessageErrorMessages).toEqual(['A error']);666 // frame 2;667 // callback C runs and throws, callback D takes up rest of frame668 advanceOneFrame({timeLeftInFrame: 15}); // runs rAF and postMessage callbacks669 // calls C and D...
Scheduler-test.js
Source:Scheduler-test.js
...36 getCurrentPriorityLevel = Scheduler.unstable_getCurrentPriorityLevel;37 shouldYield = Scheduler.unstable_shouldYield;38 });39 it('flushes work incrementally', () => {40 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('A'));41 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('B'));42 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('C'));43 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('D'));44 expect(Scheduler).toFlushAndYieldThrough(['A', 'B']);45 expect(Scheduler).toFlushAndYieldThrough(['C']);46 expect(Scheduler).toFlushAndYield(['D']);47 });48 it('cancels work', () => {49 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('A'));50 const callbackHandleB = scheduleCallback(NormalPriority, () =>51 Scheduler.unstable_yieldValue('B'),52 );53 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('C'));54 cancelCallback(callbackHandleB);55 expect(Scheduler).toFlushAndYield([56 'A',57 // B should have been cancelled58 'C',59 ]);60 });61 it('executes the highest priority callbacks first', () => {62 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('A'));63 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('B'));64 // Yield before B is flushed65 expect(Scheduler).toFlushAndYieldThrough(['A']);66 scheduleCallback(UserBlockingPriority, () =>67 Scheduler.unstable_yieldValue('C'),68 );69 scheduleCallback(UserBlockingPriority, () =>70 Scheduler.unstable_yieldValue('D'),71 );72 // C and D should come first, because they are higher priority73 expect(Scheduler).toFlushAndYield(['C', 'D', 'B']);74 });75 it('expires work', () => {76 scheduleCallback(NormalPriority, didTimeout => {77 Scheduler.unstable_advanceTime(100);78 Scheduler.unstable_yieldValue(`A (did timeout: ${didTimeout})`);79 });80 scheduleCallback(UserBlockingPriority, didTimeout => {81 Scheduler.unstable_advanceTime(100);82 Scheduler.unstable_yieldValue(`B (did timeout: ${didTimeout})`);83 });84 scheduleCallback(UserBlockingPriority, didTimeout => {85 Scheduler.unstable_advanceTime(100);86 Scheduler.unstable_yieldValue(`C (did timeout: ${didTimeout})`);87 });88 // Advance time, but not by enough to expire any work89 Scheduler.unstable_advanceTime(249);90 expect(Scheduler).toHaveYielded([]);91 // Schedule a few more callbacks92 scheduleCallback(NormalPriority, didTimeout => {93 Scheduler.unstable_advanceTime(100);94 Scheduler.unstable_yieldValue(`D (did timeout: ${didTimeout})`);95 });96 scheduleCallback(NormalPriority, didTimeout => {97 Scheduler.unstable_advanceTime(100);98 Scheduler.unstable_yieldValue(`E (did timeout: ${didTimeout})`);99 });100 // Advance by just a bit more to expire the user blocking callbacks101 Scheduler.unstable_advanceTime(1);102 expect(Scheduler).toHaveYielded([103 'B (did timeout: true)',104 'C (did timeout: true)',105 ]);106 // Expire A107 Scheduler.unstable_advanceTime(4600);108 expect(Scheduler).toHaveYielded(['A (did timeout: true)']);109 // Flush the rest without expiring110 expect(Scheduler).toFlushAndYield([111 'D (did timeout: false)',112 'E (did timeout: true)',113 ]);114 });115 it('has a default expiration of ~5 seconds', () => {116 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('A'));117 Scheduler.unstable_advanceTime(4999);118 expect(Scheduler).toHaveYielded([]);119 Scheduler.unstable_advanceTime(1);120 expect(Scheduler).toHaveYielded(['A']);121 });122 it('continues working on same task after yielding', () => {123 scheduleCallback(NormalPriority, () => {124 Scheduler.unstable_advanceTime(100);125 Scheduler.unstable_yieldValue('A');126 });127 scheduleCallback(NormalPriority, () => {128 Scheduler.unstable_advanceTime(100);129 Scheduler.unstable_yieldValue('B');130 });131 let didYield = false;132 const tasks = [['C1', 100], ['C2', 100], ['C3', 100]];133 const C = () => {134 while (tasks.length > 0) {135 const [label, ms] = tasks.shift();136 Scheduler.unstable_advanceTime(ms);137 Scheduler.unstable_yieldValue(label);138 if (shouldYield()) {139 didYield = true;140 return C;141 }142 }143 };144 scheduleCallback(NormalPriority, C);145 scheduleCallback(NormalPriority, () => {146 Scheduler.unstable_advanceTime(100);147 Scheduler.unstable_yieldValue('D');148 });149 scheduleCallback(NormalPriority, () => {150 Scheduler.unstable_advanceTime(100);151 Scheduler.unstable_yieldValue('E');152 });153 // Flush, then yield while in the middle of C.154 expect(didYield).toBe(false);155 expect(Scheduler).toFlushAndYieldThrough(['A', 'B', 'C1']);156 expect(didYield).toBe(true);157 // When we resume, we should continue working on C.158 expect(Scheduler).toFlushAndYield(['C2', 'C3', 'D', 'E']);159 });160 it('continuation callbacks inherit the expiration of the previous callback', () => {161 const tasks = [['A', 125], ['B', 124], ['C', 100], ['D', 100]];162 const work = () => {163 while (tasks.length > 0) {164 const [label, ms] = tasks.shift();165 Scheduler.unstable_advanceTime(ms);166 Scheduler.unstable_yieldValue(label);167 if (shouldYield()) {168 return work;169 }170 }171 };172 // Schedule a high priority callback173 scheduleCallback(UserBlockingPriority, work);174 // Flush until just before the expiration time175 expect(Scheduler).toFlushAndYieldThrough(['A', 'B']);176 // Advance time by just a bit more. This should expire all the remaining work.177 Scheduler.unstable_advanceTime(1);178 expect(Scheduler).toHaveYielded(['C', 'D']);179 });180 it('continuations are interrupted by higher priority work', () => {181 const tasks = [['A', 100], ['B', 100], ['C', 100], ['D', 100]];182 const work = () => {183 while (tasks.length > 0) {184 const [label, ms] = tasks.shift();185 Scheduler.unstable_advanceTime(ms);186 Scheduler.unstable_yieldValue(label);187 if (tasks.length > 0 && shouldYield()) {188 return work;189 }190 }191 };192 scheduleCallback(NormalPriority, work);193 expect(Scheduler).toFlushAndYieldThrough(['A']);194 scheduleCallback(UserBlockingPriority, () => {195 Scheduler.unstable_advanceTime(100);196 Scheduler.unstable_yieldValue('High pri');197 });198 expect(Scheduler).toFlushAndYield(['High pri', 'B', 'C', 'D']);199 });200 it(201 'continuations are interrupted by higher priority work scheduled ' +202 'inside an executing callback',203 () => {204 const tasks = [['A', 100], ['B', 100], ['C', 100], ['D', 100]];205 const work = () => {206 while (tasks.length > 0) {207 const task = tasks.shift();208 const [label, ms] = task;209 Scheduler.unstable_advanceTime(ms);210 Scheduler.unstable_yieldValue(label);211 if (label === 'B') {212 // Schedule high pri work from inside another callback213 Scheduler.unstable_yieldValue('Schedule high pri');214 scheduleCallback(UserBlockingPriority, () => {215 Scheduler.unstable_advanceTime(100);216 Scheduler.unstable_yieldValue('High pri');217 });218 }219 if (tasks.length > 0 && shouldYield()) {220 Scheduler.unstable_yieldValue('Yield!');221 return work;222 }223 }224 };225 scheduleCallback(NormalPriority, work);226 expect(Scheduler).toFlushAndYield([227 'A',228 'B',229 'Schedule high pri',230 // Even though there's time left in the frame, the low pri callback231 // should yield to the high pri callback232 'Yield!',233 'High pri',234 // Continue low pri work235 'C',236 'D',237 ]);238 },239 );240 it('cancelling a continuation', () => {241 const task = scheduleCallback(NormalPriority, () => {242 Scheduler.unstable_yieldValue('Yield');243 return () => {244 Scheduler.unstable_yieldValue('Continuation');245 };246 });247 expect(Scheduler).toFlushAndYieldThrough(['Yield']);248 cancelCallback(task);249 expect(Scheduler).toFlushWithoutYielding();250 });251 it('top-level immediate callbacks fire in a subsequent task', () => {252 scheduleCallback(ImmediatePriority, () =>253 Scheduler.unstable_yieldValue('A'),254 );255 scheduleCallback(ImmediatePriority, () =>256 Scheduler.unstable_yieldValue('B'),257 );258 scheduleCallback(ImmediatePriority, () =>259 Scheduler.unstable_yieldValue('C'),260 );261 scheduleCallback(ImmediatePriority, () =>262 Scheduler.unstable_yieldValue('D'),263 );264 // Immediate callback hasn't fired, yet.265 expect(Scheduler).toHaveYielded([]);266 // They all flush immediately within the subsequent task.267 expect(Scheduler).toFlushExpired(['A', 'B', 'C', 'D']);268 });269 it('nested immediate callbacks are added to the queue of immediate callbacks', () => {270 scheduleCallback(ImmediatePriority, () =>271 Scheduler.unstable_yieldValue('A'),272 );273 scheduleCallback(ImmediatePriority, () => {274 Scheduler.unstable_yieldValue('B');275 // This callback should go to the end of the queue276 scheduleCallback(ImmediatePriority, () =>277 Scheduler.unstable_yieldValue('C'),278 );279 });280 scheduleCallback(ImmediatePriority, () =>281 Scheduler.unstable_yieldValue('D'),282 );283 expect(Scheduler).toHaveYielded([]);284 // C should flush at the end285 expect(Scheduler).toFlushExpired(['A', 'B', 'D', 'C']);286 });287 it('wrapped callbacks have same signature as original callback', () => {288 const wrappedCallback = wrapCallback((...args) => ({args}));289 expect(wrappedCallback('a', 'b')).toEqual({args: ['a', 'b']});290 });291 it('wrapped callbacks inherit the current priority', () => {292 const wrappedCallback = runWithPriority(NormalPriority, () =>293 wrapCallback(() => {294 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());295 }),296 );297 const wrappedUserBlockingCallback = runWithPriority(298 UserBlockingPriority,299 () =>300 wrapCallback(() => {301 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());302 }),303 );304 wrappedCallback();305 expect(Scheduler).toHaveYielded([NormalPriority]);306 wrappedUserBlockingCallback();307 expect(Scheduler).toHaveYielded([UserBlockingPriority]);308 });309 it('wrapped callbacks inherit the current priority even when nested', () => {310 let wrappedCallback;311 let wrappedUserBlockingCallback;312 runWithPriority(NormalPriority, () => {313 wrappedCallback = wrapCallback(() => {314 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());315 });316 wrappedUserBlockingCallback = runWithPriority(UserBlockingPriority, () =>317 wrapCallback(() => {318 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());319 }),320 );321 });322 wrappedCallback();323 expect(Scheduler).toHaveYielded([NormalPriority]);324 wrappedUserBlockingCallback();325 expect(Scheduler).toHaveYielded([UserBlockingPriority]);326 });327 it("immediate callbacks fire even if there's an error", () => {328 scheduleCallback(ImmediatePriority, () => {329 Scheduler.unstable_yieldValue('A');330 throw new Error('Oops A');331 });332 scheduleCallback(ImmediatePriority, () => {333 Scheduler.unstable_yieldValue('B');334 });335 scheduleCallback(ImmediatePriority, () => {336 Scheduler.unstable_yieldValue('C');337 throw new Error('Oops C');338 });339 expect(() => expect(Scheduler).toFlushExpired()).toThrow('Oops A');340 expect(Scheduler).toHaveYielded(['A']);341 // B and C flush in a subsequent event. That way, the second error is not342 // swallowed.343 expect(() => expect(Scheduler).toFlushExpired()).toThrow('Oops C');344 expect(Scheduler).toHaveYielded(['B', 'C']);345 });346 it('multiple immediate callbacks can throw and there will be an error for each one', () => {347 scheduleCallback(ImmediatePriority, () => {348 throw new Error('First error');349 });350 scheduleCallback(ImmediatePriority, () => {351 throw new Error('Second error');352 });353 expect(() => Scheduler.unstable_flushAll()).toThrow('First error');354 // The next error is thrown in the subsequent event355 expect(() => Scheduler.unstable_flushAll()).toThrow('Second error');356 });357 it('exposes the current priority level', () => {358 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());359 runWithPriority(ImmediatePriority, () => {360 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());361 runWithPriority(NormalPriority, () => {362 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());363 runWithPriority(UserBlockingPriority, () => {364 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());365 });366 });367 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());368 });369 expect(Scheduler).toHaveYielded([370 NormalPriority,371 ImmediatePriority,372 NormalPriority,373 UserBlockingPriority,374 ImmediatePriority,375 ]);376 });377 if (__DEV__) {378 // Function names are minified in prod, though you could still infer the379 // priority if you have sourcemaps.380 // TODO: Feature temporarily disabled while we investigate a bug in one of381 // our minifiers.382 it.skip('adds extra function to the JS stack whose name includes the priority level', () => {383 function inferPriorityFromCallstack() {384 try {385 throw Error();386 } catch (e) {387 const stack = e.stack;388 const lines = stack.split('\n');389 for (let i = lines.length - 1; i >= 0; i--) {390 const line = lines[i];391 const found = line.match(392 /scheduler_flushTaskAtPriority_([A-Za-z]+)/,393 );394 if (found !== null) {395 const priorityStr = found[1];396 switch (priorityStr) {397 case 'Immediate':398 return ImmediatePriority;399 case 'UserBlocking':400 return UserBlockingPriority;401 case 'Normal':402 return NormalPriority;403 case 'Low':404 return LowPriority;405 case 'Idle':406 return IdlePriority;407 }408 }409 }410 return null;411 }412 }413 scheduleCallback(ImmediatePriority, () =>414 Scheduler.unstable_yieldValue(415 'Immediate: ' + inferPriorityFromCallstack(),416 ),417 );418 scheduleCallback(UserBlockingPriority, () =>419 Scheduler.unstable_yieldValue(420 'UserBlocking: ' + inferPriorityFromCallstack(),421 ),422 );423 scheduleCallback(NormalPriority, () =>424 Scheduler.unstable_yieldValue(425 'Normal: ' + inferPriorityFromCallstack(),426 ),427 );428 scheduleCallback(LowPriority, () =>429 Scheduler.unstable_yieldValue('Low: ' + inferPriorityFromCallstack()),430 );431 scheduleCallback(IdlePriority, () =>432 Scheduler.unstable_yieldValue('Idle: ' + inferPriorityFromCallstack()),433 );434 expect(Scheduler).toFlushAndYield([435 'Immediate: ' + ImmediatePriority,436 'UserBlocking: ' + UserBlockingPriority,437 'Normal: ' + NormalPriority,438 'Low: ' + LowPriority,439 'Idle: ' + IdlePriority,440 ]);441 });442 }443 describe('delayed tasks', () => {444 it('schedules a delayed task', () => {445 scheduleCallback(446 NormalPriority,447 () => Scheduler.unstable_yieldValue('A'),448 {449 delay: 1000,450 },451 );452 // Should flush nothing, because delay hasn't elapsed453 expect(Scheduler).toFlushAndYield([]);454 // Advance time until right before the threshold455 Scheduler.unstable_advanceTime(999);456 // Still nothing457 expect(Scheduler).toFlushAndYield([]);458 // Advance time past the threshold459 Scheduler.unstable_advanceTime(1);460 // Now it should flush like normal461 expect(Scheduler).toFlushAndYield(['A']);462 });463 it('schedules multiple delayed tasks', () => {464 scheduleCallback(465 NormalPriority,466 () => Scheduler.unstable_yieldValue('C'),467 {468 delay: 300,469 },470 );471 scheduleCallback(472 NormalPriority,473 () => Scheduler.unstable_yieldValue('B'),474 {475 delay: 200,476 },477 );478 scheduleCallback(479 NormalPriority,480 () => Scheduler.unstable_yieldValue('D'),481 {482 delay: 400,483 },484 );485 scheduleCallback(486 NormalPriority,487 () => Scheduler.unstable_yieldValue('A'),488 {489 delay: 100,490 },491 );492 // Should flush nothing, because delay hasn't elapsed493 expect(Scheduler).toFlushAndYield([]);494 // Advance some time.495 Scheduler.unstable_advanceTime(200);496 // Both A and B are no longer delayed. They can now flush incrementally.497 expect(Scheduler).toFlushAndYieldThrough(['A']);498 expect(Scheduler).toFlushAndYield(['B']);499 // Advance the rest500 Scheduler.unstable_advanceTime(200);501 expect(Scheduler).toFlushAndYield(['C', 'D']);502 });503 it('interleaves normal tasks and delayed tasks', () => {504 // Schedule some high priority callbacks with a delay. When their delay505 // elapses, they will be the most important callback in the queue.506 scheduleCallback(507 UserBlockingPriority,508 () => Scheduler.unstable_yieldValue('Timer 2'),509 {delay: 300},510 );511 scheduleCallback(512 UserBlockingPriority,513 () => Scheduler.unstable_yieldValue('Timer 1'),514 {delay: 100},515 );516 // Schedule some tasks at default priority.517 scheduleCallback(NormalPriority, () => {518 Scheduler.unstable_yieldValue('A');519 Scheduler.unstable_advanceTime(100);520 });521 scheduleCallback(NormalPriority, () => {522 Scheduler.unstable_yieldValue('B');523 Scheduler.unstable_advanceTime(100);524 });525 scheduleCallback(NormalPriority, () => {526 Scheduler.unstable_yieldValue('C');527 Scheduler.unstable_advanceTime(100);528 });529 scheduleCallback(NormalPriority, () => {530 Scheduler.unstable_yieldValue('D');531 Scheduler.unstable_advanceTime(100);532 });533 // Flush all the work. The timers should be interleaved with the534 // other tasks.535 expect(Scheduler).toFlushAndYield([536 'A',537 'Timer 1',538 'B',539 'C',540 'Timer 2',541 'D',542 ]);543 });544 it('interleaves delayed tasks with time-sliced tasks', () => {545 // Schedule some high priority callbacks with a delay. When their delay546 // elapses, they will be the most important callback in the queue.547 scheduleCallback(548 UserBlockingPriority,549 () => Scheduler.unstable_yieldValue('Timer 2'),550 {delay: 300},551 );552 scheduleCallback(553 UserBlockingPriority,554 () => Scheduler.unstable_yieldValue('Timer 1'),555 {delay: 100},556 );557 // Schedule a time-sliced task at default priority.558 const tasks = [['A', 100], ['B', 100], ['C', 100], ['D', 100]];559 const work = () => {560 while (tasks.length > 0) {561 const task = tasks.shift();562 const [label, ms] = task;563 Scheduler.unstable_advanceTime(ms);564 Scheduler.unstable_yieldValue(label);565 if (tasks.length > 0 && shouldYield()) {566 return work;567 }568 }569 };570 scheduleCallback(NormalPriority, work);571 // Flush all the work. The timers should be interleaved with the572 // other tasks.573 expect(Scheduler).toFlushAndYield([574 'A',575 'Timer 1',576 'B',577 'C',578 'Timer 2',579 'D',580 ]);581 });582 it('schedules callback with both delay and timeout', () => {583 scheduleCallback(584 NormalPriority,585 () => {586 Scheduler.unstable_yieldValue('A');587 Scheduler.unstable_advanceTime(100);588 },589 {delay: 100, timeout: 900},590 );591 Scheduler.unstable_advanceTime(99);592 // Does not flush because delay has not elapsed593 expect(Scheduler).toFlushAndYield([]);594 // Delay has elapsed but task has not expired595 Scheduler.unstable_advanceTime(1);596 expect(Scheduler).toFlushExpired([]);597 // Still not expired598 Scheduler.unstable_advanceTime(899);599 expect(Scheduler).toFlushExpired([]);600 // Now it expires601 Scheduler.unstable_advanceTime(1);602 expect(Scheduler).toHaveYielded(['A']);603 });604 it('cancels a delayed task', () => {605 // Schedule several tasks with the same delay606 const options = {delay: 100};607 scheduleCallback(608 NormalPriority,609 () => Scheduler.unstable_yieldValue('A'),610 options,611 );612 const taskB = scheduleCallback(613 NormalPriority,614 () => Scheduler.unstable_yieldValue('B'),615 options,616 );617 const taskC = scheduleCallback(618 NormalPriority,619 () => Scheduler.unstable_yieldValue('C'),620 options,621 );622 // Cancel B before its delay has elapsed623 expect(Scheduler).toFlushAndYield([]);624 cancelCallback(taskB);625 // Cancel C after its delay has elapsed626 Scheduler.unstable_advanceTime(500);627 cancelCallback(taskC);628 // Only A should flush629 expect(Scheduler).toFlushAndYield(['A']);630 });631 });...
SchedulerMock-test.js
Source:SchedulerMock-test.js
...36 getCurrentPriorityLevel = Scheduler.unstable_getCurrentPriorityLevel;37 shouldYield = Scheduler.unstable_shouldYield;38 });39 it('flushes work incrementally', () => {40 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('A'));41 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('B'));42 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('C'));43 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('D'));44 expect(Scheduler).toFlushAndYieldThrough(['A', 'B']);45 expect(Scheduler).toFlushAndYieldThrough(['C']);46 expect(Scheduler).toFlushAndYield(['D']);47 });48 it('cancels work', () => {49 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('A'));50 const callbackHandleB = scheduleCallback(NormalPriority, () =>51 Scheduler.unstable_yieldValue('B'),52 );53 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('C'));54 cancelCallback(callbackHandleB);55 expect(Scheduler).toFlushAndYield([56 'A',57 // B should have been cancelled58 'C',59 ]);60 });61 it('executes the highest priority callbacks first', () => {62 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('A'));63 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('B'));64 // Yield before B is flushed65 expect(Scheduler).toFlushAndYieldThrough(['A']);66 scheduleCallback(UserBlockingPriority, () =>67 Scheduler.unstable_yieldValue('C'),68 );69 scheduleCallback(UserBlockingPriority, () =>70 Scheduler.unstable_yieldValue('D'),71 );72 // C and D should come first, because they are higher priority73 expect(Scheduler).toFlushAndYield(['C', 'D', 'B']);74 });75 it('expires work', () => {76 scheduleCallback(NormalPriority, didTimeout => {77 Scheduler.unstable_advanceTime(100);78 Scheduler.unstable_yieldValue(`A (did timeout: ${didTimeout})`);79 });80 scheduleCallback(UserBlockingPriority, didTimeout => {81 Scheduler.unstable_advanceTime(100);82 Scheduler.unstable_yieldValue(`B (did timeout: ${didTimeout})`);83 });84 scheduleCallback(UserBlockingPriority, didTimeout => {85 Scheduler.unstable_advanceTime(100);86 Scheduler.unstable_yieldValue(`C (did timeout: ${didTimeout})`);87 });88 // Advance time, but not by enough to expire any work89 Scheduler.unstable_advanceTime(249);90 expect(Scheduler).toHaveYielded([]);91 // Schedule a few more callbacks92 scheduleCallback(NormalPriority, didTimeout => {93 Scheduler.unstable_advanceTime(100);94 Scheduler.unstable_yieldValue(`D (did timeout: ${didTimeout})`);95 });96 scheduleCallback(NormalPriority, didTimeout => {97 Scheduler.unstable_advanceTime(100);98 Scheduler.unstable_yieldValue(`E (did timeout: ${didTimeout})`);99 });100 // Advance by just a bit more to expire the user blocking callbacks101 Scheduler.unstable_advanceTime(1);102 expect(Scheduler).toFlushAndYieldThrough([103 'B (did timeout: true)',104 'C (did timeout: true)',105 ]);106 // Expire A107 Scheduler.unstable_advanceTime(4600);108 expect(Scheduler).toFlushAndYieldThrough(['A (did timeout: true)']);109 // Flush the rest without expiring110 expect(Scheduler).toFlushAndYield([111 'D (did timeout: false)',112 'E (did timeout: true)',113 ]);114 });115 it('has a default expiration of ~5 seconds', () => {116 scheduleCallback(NormalPriority, () => Scheduler.unstable_yieldValue('A'));117 Scheduler.unstable_advanceTime(4999);118 expect(Scheduler).toHaveYielded([]);119 Scheduler.unstable_advanceTime(1);120 expect(Scheduler).toFlushExpired(['A']);121 });122 it('continues working on same task after yielding', () => {123 scheduleCallback(NormalPriority, () => {124 Scheduler.unstable_advanceTime(100);125 Scheduler.unstable_yieldValue('A');126 });127 scheduleCallback(NormalPriority, () => {128 Scheduler.unstable_advanceTime(100);129 Scheduler.unstable_yieldValue('B');130 });131 let didYield = false;132 const tasks = [133 ['C1', 100],134 ['C2', 100],135 ['C3', 100],136 ];137 const C = () => {138 while (tasks.length > 0) {139 const [label, ms] = tasks.shift();140 Scheduler.unstable_advanceTime(ms);141 Scheduler.unstable_yieldValue(label);142 if (shouldYield()) {143 didYield = true;144 return C;145 }146 }147 };148 scheduleCallback(NormalPriority, C);149 scheduleCallback(NormalPriority, () => {150 Scheduler.unstable_advanceTime(100);151 Scheduler.unstable_yieldValue('D');152 });153 scheduleCallback(NormalPriority, () => {154 Scheduler.unstable_advanceTime(100);155 Scheduler.unstable_yieldValue('E');156 });157 // Flush, then yield while in the middle of C.158 expect(didYield).toBe(false);159 expect(Scheduler).toFlushAndYieldThrough(['A', 'B', 'C1']);160 expect(didYield).toBe(true);161 // When we resume, we should continue working on C.162 expect(Scheduler).toFlushAndYield(['C2', 'C3', 'D', 'E']);163 });164 it('continuation callbacks inherit the expiration of the previous callback', () => {165 const tasks = [166 ['A', 125],167 ['B', 124],168 ['C', 100],169 ['D', 100],170 ];171 const work = () => {172 while (tasks.length > 0) {173 const [label, ms] = tasks.shift();174 Scheduler.unstable_advanceTime(ms);175 Scheduler.unstable_yieldValue(label);176 if (shouldYield()) {177 return work;178 }179 }180 };181 // Schedule a high priority callback182 scheduleCallback(UserBlockingPriority, work);183 // Flush until just before the expiration time184 expect(Scheduler).toFlushAndYieldThrough(['A', 'B']);185 // Advance time by just a bit more. This should expire all the remaining work.186 Scheduler.unstable_advanceTime(1);187 expect(Scheduler).toFlushExpired(['C', 'D']);188 });189 it('continuations are interrupted by higher priority work', () => {190 const tasks = [191 ['A', 100],192 ['B', 100],193 ['C', 100],194 ['D', 100],195 ];196 const work = () => {197 while (tasks.length > 0) {198 const [label, ms] = tasks.shift();199 Scheduler.unstable_advanceTime(ms);200 Scheduler.unstable_yieldValue(label);201 if (tasks.length > 0 && shouldYield()) {202 return work;203 }204 }205 };206 scheduleCallback(NormalPriority, work);207 expect(Scheduler).toFlushAndYieldThrough(['A']);208 scheduleCallback(UserBlockingPriority, () => {209 Scheduler.unstable_advanceTime(100);210 Scheduler.unstable_yieldValue('High pri');211 });212 expect(Scheduler).toFlushAndYield(['High pri', 'B', 'C', 'D']);213 });214 it(215 'continuations do not block higher priority work scheduled ' +216 'inside an executing callback',217 () => {218 const tasks = [219 ['A', 100],220 ['B', 100],221 ['C', 100],222 ['D', 100],223 ];224 const work = () => {225 while (tasks.length > 0) {226 const task = tasks.shift();227 const [label, ms] = task;228 Scheduler.unstable_advanceTime(ms);229 Scheduler.unstable_yieldValue(label);230 if (label === 'B') {231 // Schedule high pri work from inside another callback232 Scheduler.unstable_yieldValue('Schedule high pri');233 scheduleCallback(UserBlockingPriority, () => {234 Scheduler.unstable_advanceTime(100);235 Scheduler.unstable_yieldValue('High pri');236 });237 }238 if (tasks.length > 0) {239 // Return a continuation240 return work;241 }242 }243 };244 scheduleCallback(NormalPriority, work);245 expect(Scheduler).toFlushAndYield([246 'A',247 'B',248 'Schedule high pri',249 // The high pri callback should fire before the continuation of the250 // lower pri work251 'High pri',252 // Continue low pri work253 'C',254 'D',255 ]);256 },257 );258 it('cancelling a continuation', () => {259 const task = scheduleCallback(NormalPriority, () => {260 Scheduler.unstable_yieldValue('Yield');261 return () => {262 Scheduler.unstable_yieldValue('Continuation');263 };264 });265 expect(Scheduler).toFlushAndYieldThrough(['Yield']);266 cancelCallback(task);267 expect(Scheduler).toFlushWithoutYielding();268 });269 it('top-level immediate callbacks fire in a subsequent task', () => {270 scheduleCallback(ImmediatePriority, () =>271 Scheduler.unstable_yieldValue('A'),272 );273 scheduleCallback(ImmediatePriority, () =>274 Scheduler.unstable_yieldValue('B'),275 );276 scheduleCallback(ImmediatePriority, () =>277 Scheduler.unstable_yieldValue('C'),278 );279 scheduleCallback(ImmediatePriority, () =>280 Scheduler.unstable_yieldValue('D'),281 );282 // Immediate callback hasn't fired, yet.283 expect(Scheduler).toHaveYielded([]);284 // They all flush immediately within the subsequent task.285 expect(Scheduler).toFlushExpired(['A', 'B', 'C', 'D']);286 });287 it('nested immediate callbacks are added to the queue of immediate callbacks', () => {288 scheduleCallback(ImmediatePriority, () =>289 Scheduler.unstable_yieldValue('A'),290 );291 scheduleCallback(ImmediatePriority, () => {292 Scheduler.unstable_yieldValue('B');293 // This callback should go to the end of the queue294 scheduleCallback(ImmediatePriority, () =>295 Scheduler.unstable_yieldValue('C'),296 );297 });298 scheduleCallback(ImmediatePriority, () =>299 Scheduler.unstable_yieldValue('D'),300 );301 expect(Scheduler).toHaveYielded([]);302 // C should flush at the end303 expect(Scheduler).toFlushExpired(['A', 'B', 'D', 'C']);304 });305 it('wrapped callbacks have same signature as original callback', () => {306 const wrappedCallback = wrapCallback((...args) => ({args}));307 expect(wrappedCallback('a', 'b')).toEqual({args: ['a', 'b']});308 });309 it('wrapped callbacks inherit the current priority', () => {310 const wrappedCallback = runWithPriority(NormalPriority, () =>311 wrapCallback(() => {312 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());313 }),314 );315 const wrappedUserBlockingCallback = runWithPriority(316 UserBlockingPriority,317 () =>318 wrapCallback(() => {319 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());320 }),321 );322 wrappedCallback();323 expect(Scheduler).toHaveYielded([NormalPriority]);324 wrappedUserBlockingCallback();325 expect(Scheduler).toHaveYielded([UserBlockingPriority]);326 });327 it('wrapped callbacks inherit the current priority even when nested', () => {328 let wrappedCallback;329 let wrappedUserBlockingCallback;330 runWithPriority(NormalPriority, () => {331 wrappedCallback = wrapCallback(() => {332 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());333 });334 wrappedUserBlockingCallback = runWithPriority(UserBlockingPriority, () =>335 wrapCallback(() => {336 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());337 }),338 );339 });340 wrappedCallback();341 expect(Scheduler).toHaveYielded([NormalPriority]);342 wrappedUserBlockingCallback();343 expect(Scheduler).toHaveYielded([UserBlockingPriority]);344 });345 it("immediate callbacks fire even if there's an error", () => {346 scheduleCallback(ImmediatePriority, () => {347 Scheduler.unstable_yieldValue('A');348 throw new Error('Oops A');349 });350 scheduleCallback(ImmediatePriority, () => {351 Scheduler.unstable_yieldValue('B');352 });353 scheduleCallback(ImmediatePriority, () => {354 Scheduler.unstable_yieldValue('C');355 throw new Error('Oops C');356 });357 expect(() => expect(Scheduler).toFlushExpired()).toThrow('Oops A');358 expect(Scheduler).toHaveYielded(['A']);359 // B and C flush in a subsequent event. That way, the second error is not360 // swallowed.361 expect(() => expect(Scheduler).toFlushExpired()).toThrow('Oops C');362 expect(Scheduler).toHaveYielded(['B', 'C']);363 });364 it('multiple immediate callbacks can throw and there will be an error for each one', () => {365 scheduleCallback(ImmediatePriority, () => {366 throw new Error('First error');367 });368 scheduleCallback(ImmediatePriority, () => {369 throw new Error('Second error');370 });371 expect(() => Scheduler.unstable_flushAll()).toThrow('First error');372 // The next error is thrown in the subsequent event373 expect(() => Scheduler.unstable_flushAll()).toThrow('Second error');374 });375 it('exposes the current priority level', () => {376 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());377 runWithPriority(ImmediatePriority, () => {378 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());379 runWithPriority(NormalPriority, () => {380 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());381 runWithPriority(UserBlockingPriority, () => {382 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());383 });384 });385 Scheduler.unstable_yieldValue(getCurrentPriorityLevel());386 });387 expect(Scheduler).toHaveYielded([388 NormalPriority,389 ImmediatePriority,390 NormalPriority,391 UserBlockingPriority,392 ImmediatePriority,393 ]);394 });395 if (__DEV__) {396 // Function names are minified in prod, though you could still infer the397 // priority if you have sourcemaps.398 // TODO: Feature temporarily disabled while we investigate a bug in one of399 // our minifiers.400 it.skip('adds extra function to the JS stack whose name includes the priority level', () => {401 function inferPriorityFromCallstack() {402 try {403 throw Error();404 } catch (e) {405 const stack = e.stack;406 const lines = stack.split('\n');407 for (let i = lines.length - 1; i >= 0; i--) {408 const line = lines[i];409 const found = line.match(410 /scheduler_flushTaskAtPriority_([A-Za-z]+)/,411 );412 if (found !== null) {413 const priorityStr = found[1];414 switch (priorityStr) {415 case 'Immediate':416 return ImmediatePriority;417 case 'UserBlocking':418 return UserBlockingPriority;419 case 'Normal':420 return NormalPriority;421 case 'Low':422 return LowPriority;423 case 'Idle':424 return IdlePriority;425 }426 }427 }428 return null;429 }430 }431 scheduleCallback(ImmediatePriority, () =>432 Scheduler.unstable_yieldValue(433 'Immediate: ' + inferPriorityFromCallstack(),434 ),435 );436 scheduleCallback(UserBlockingPriority, () =>437 Scheduler.unstable_yieldValue(438 'UserBlocking: ' + inferPriorityFromCallstack(),439 ),440 );441 scheduleCallback(NormalPriority, () =>442 Scheduler.unstable_yieldValue(443 'Normal: ' + inferPriorityFromCallstack(),444 ),445 );446 scheduleCallback(LowPriority, () =>447 Scheduler.unstable_yieldValue('Low: ' + inferPriorityFromCallstack()),448 );449 scheduleCallback(IdlePriority, () =>450 Scheduler.unstable_yieldValue('Idle: ' + inferPriorityFromCallstack()),451 );452 expect(Scheduler).toFlushAndYield([453 'Immediate: ' + ImmediatePriority,454 'UserBlocking: ' + UserBlockingPriority,455 'Normal: ' + NormalPriority,456 'Low: ' + LowPriority,457 'Idle: ' + IdlePriority,458 ]);459 });460 }461 describe('delayed tasks', () => {462 it('schedules a delayed task', () => {463 scheduleCallback(464 NormalPriority,465 () => Scheduler.unstable_yieldValue('A'),466 {467 delay: 1000,468 },469 );470 // Should flush nothing, because delay hasn't elapsed471 expect(Scheduler).toFlushAndYield([]);472 // Advance time until right before the threshold473 Scheduler.unstable_advanceTime(999);474 // Still nothing475 expect(Scheduler).toFlushAndYield([]);476 // Advance time past the threshold477 Scheduler.unstable_advanceTime(1);478 // Now it should flush like normal479 expect(Scheduler).toFlushAndYield(['A']);480 });481 it('schedules multiple delayed tasks', () => {482 scheduleCallback(483 NormalPriority,484 () => Scheduler.unstable_yieldValue('C'),485 {486 delay: 300,487 },488 );489 scheduleCallback(490 NormalPriority,491 () => Scheduler.unstable_yieldValue('B'),492 {493 delay: 200,494 },495 );496 scheduleCallback(497 NormalPriority,498 () => Scheduler.unstable_yieldValue('D'),499 {500 delay: 400,501 },502 );503 scheduleCallback(504 NormalPriority,505 () => Scheduler.unstable_yieldValue('A'),506 {507 delay: 100,508 },509 );510 // Should flush nothing, because delay hasn't elapsed511 expect(Scheduler).toFlushAndYield([]);512 // Advance some time.513 Scheduler.unstable_advanceTime(200);514 // Both A and B are no longer delayed. They can now flush incrementally.515 expect(Scheduler).toFlushAndYieldThrough(['A']);516 expect(Scheduler).toFlushAndYield(['B']);517 // Advance the rest518 Scheduler.unstable_advanceTime(200);519 expect(Scheduler).toFlushAndYield(['C', 'D']);520 });521 it('interleaves normal tasks and delayed tasks', () => {522 // Schedule some high priority callbacks with a delay. When their delay523 // elapses, they will be the most important callback in the queue.524 scheduleCallback(525 UserBlockingPriority,526 () => Scheduler.unstable_yieldValue('Timer 2'),527 {delay: 300},528 );529 scheduleCallback(530 UserBlockingPriority,531 () => Scheduler.unstable_yieldValue('Timer 1'),532 {delay: 100},533 );534 // Schedule some tasks at default priority.535 scheduleCallback(NormalPriority, () => {536 Scheduler.unstable_yieldValue('A');537 Scheduler.unstable_advanceTime(100);538 });539 scheduleCallback(NormalPriority, () => {540 Scheduler.unstable_yieldValue('B');541 Scheduler.unstable_advanceTime(100);542 });543 scheduleCallback(NormalPriority, () => {544 Scheduler.unstable_yieldValue('C');545 Scheduler.unstable_advanceTime(100);546 });547 scheduleCallback(NormalPriority, () => {548 Scheduler.unstable_yieldValue('D');549 Scheduler.unstable_advanceTime(100);550 });551 // Flush all the work. The timers should be interleaved with the552 // other tasks.553 expect(Scheduler).toFlushAndYield([554 'A',555 'Timer 1',556 'B',557 'C',558 'Timer 2',559 'D',560 ]);561 });562 it('interleaves delayed tasks with time-sliced tasks', () => {563 // Schedule some high priority callbacks with a delay. When their delay564 // elapses, they will be the most important callback in the queue.565 scheduleCallback(566 UserBlockingPriority,567 () => Scheduler.unstable_yieldValue('Timer 2'),568 {delay: 300},569 );570 scheduleCallback(571 UserBlockingPriority,572 () => Scheduler.unstable_yieldValue('Timer 1'),573 {delay: 100},574 );575 // Schedule a time-sliced task at default priority.576 const tasks = [577 ['A', 100],578 ['B', 100],579 ['C', 100],580 ['D', 100],581 ];582 const work = () => {583 while (tasks.length > 0) {584 const task = tasks.shift();585 const [label, ms] = task;586 Scheduler.unstable_advanceTime(ms);587 Scheduler.unstable_yieldValue(label);588 if (tasks.length > 0) {589 return work;590 }591 }592 };593 scheduleCallback(NormalPriority, work);594 // Flush all the work. The timers should be interleaved with the595 // other tasks.596 expect(Scheduler).toFlushAndYield([597 'A',598 'Timer 1',599 'B',600 'C',601 'Timer 2',602 'D',603 ]);604 });605 it('cancels a delayed task', () => {606 // Schedule several tasks with the same delay607 const options = {delay: 100};608 scheduleCallback(609 NormalPriority,610 () => Scheduler.unstable_yieldValue('A'),611 options,612 );613 const taskB = scheduleCallback(614 NormalPriority,615 () => Scheduler.unstable_yieldValue('B'),616 options,617 );618 const taskC = scheduleCallback(619 NormalPriority,620 () => Scheduler.unstable_yieldValue('C'),621 options,622 );623 // Cancel B before its delay has elapsed624 expect(Scheduler).toFlushAndYield([]);625 cancelCallback(taskB);626 // Cancel C after its delay has elapsed627 Scheduler.unstable_advanceTime(500);628 cancelCallback(taskC);629 // Only A should flush630 expect(Scheduler).toFlushAndYield(['A']);631 });632 it('gracefully handles scheduled tasks that are not a function', () => {633 scheduleCallback(ImmediatePriority, null);634 expect(Scheduler).toFlushWithoutYielding();635 scheduleCallback(ImmediatePriority, undefined);636 expect(Scheduler).toFlushWithoutYielding();637 scheduleCallback(ImmediatePriority, {});638 expect(Scheduler).toFlushWithoutYielding();639 scheduleCallback(ImmediatePriority, 42);640 expect(Scheduler).toFlushWithoutYielding();641 });642 });...
Scheduler-test.internal.js
Source:Scheduler-test.internal.js
...130 wrapCallback = Schedule.unstable_wrapCallback;131 getCurrentPriorityLevel = Schedule.unstable_getCurrentPriorityLevel;132 });133 it('flushes work incrementally', () => {134 scheduleCallback(() => doWork('A', 100));135 scheduleCallback(() => doWork('B', 200));136 scheduleCallback(() => doWork('C', 300));137 scheduleCallback(() => doWork('D', 400));138 expect(flushWork(300)).toEqual(['A', 'B']);139 expect(flushWork(300)).toEqual(['C']);140 expect(flushWork(400)).toEqual(['D']);141 });142 it('flushes work until framesize reached', () => {143 scheduleCallback(() => doWork('A1_100', 100));144 scheduleCallback(() => doWork('A2_200', 200));145 scheduleCallback(() => doWork('B1_100', 100));146 scheduleCallback(() => doWork('B2_200', 200));147 scheduleCallback(() => doWork('C1_300', 300));148 scheduleCallback(() => doWork('C2_300', 300));149 scheduleCallback(() => doWork('D_3000', 3000));150 scheduleCallback(() => doWork('E1_300', 300));151 scheduleCallback(() => doWork('E2_200', 200));152 scheduleCallback(() => doWork('F1_200', 200));153 scheduleCallback(() => doWork('F2_200', 200));154 scheduleCallback(() => doWork('F3_300', 300));155 scheduleCallback(() => doWork('F4_500', 500));156 scheduleCallback(() => doWork('F5_200', 200));157 scheduleCallback(() => doWork('F6_20', 20));158 expect(Date.now()).toEqual(0);159 // No time left after A1_100 and A2_200 are run160 expect(flushWork(300)).toEqual(['A1_100', 'A2_200']);161 expect(Date.now()).toEqual(300);162 // B2_200 is started as there is still time left after B1_100163 expect(flushWork(101)).toEqual(['B1_100', 'B2_200']);164 expect(Date.now()).toEqual(600);165 // C1_300 is started as there is even a little frame time166 expect(flushWork(1)).toEqual(['C1_300']);167 expect(Date.now()).toEqual(900);168 // C2_300 is started even though there is no frame time169 expect(flushWork(0)).toEqual(['C2_300']);170 expect(Date.now()).toEqual(1200);171 // D_3000 is very slow, but won't affect next flushes (if no172 // timeouts happen)173 expect(flushWork(100)).toEqual(['D_3000']);174 expect(Date.now()).toEqual(4200);175 expect(flushWork(400)).toEqual(['E1_300', 'E2_200']);176 expect(Date.now()).toEqual(4700);177 // Default timeout is 5000, so during F2_200, work will timeout and are done178 // in reverse, including F2_200179 expect(flushWork(1000)).toEqual([180 'F1_200',181 'F2_200',182 'F3_300',183 'F4_500',184 'F5_200',185 'F6_20',186 ]);187 expect(Date.now()).toEqual(6120);188 });189 it('cancels work', () => {190 scheduleCallback(() => doWork('A', 100));191 const callbackHandleB = scheduleCallback(() => doWork('B', 200));192 scheduleCallback(() => doWork('C', 300));193 cancelCallback(callbackHandleB);194 expect(flushWork()).toEqual([195 'A',196 // B should have been cancelled197 'C',198 ]);199 });200 it('executes the highest priority callbacks first', () => {201 scheduleCallback(() => doWork('A', 100));202 scheduleCallback(() => doWork('B', 100));203 // Yield before B is flushed204 expect(flushWork(100)).toEqual(['A']);205 runWithPriority(UserBlockingPriority, () => {206 scheduleCallback(() => doWork('C', 100));207 scheduleCallback(() => doWork('D', 100));208 });209 // C and D should come first, because they are higher priority210 expect(flushWork()).toEqual(['C', 'D', 'B']);211 });212 it('expires work', () => {213 scheduleCallback(() => doWork('A', 100));214 runWithPriority(UserBlockingPriority, () => {215 scheduleCallback(() => doWork('B', 100));216 });217 scheduleCallback(() => doWork('C', 100));218 runWithPriority(UserBlockingPriority, () => {219 scheduleCallback(() => doWork('D', 100));220 });221 // Advance time, but not by enough to expire any work222 advanceTime(249);223 expect(clearYieldedValues()).toEqual([]);224 // Advance by just a bit more to expire the high pri callbacks225 advanceTime(1);226 expect(clearYieldedValues()).toEqual(['B', 'D']);227 // Expire the rest228 advanceTime(10000);229 expect(clearYieldedValues()).toEqual(['A', 'C']);230 });231 it('has a default expiration of ~5 seconds', () => {232 scheduleCallback(() => doWork('A', 100));233 advanceTime(4999);234 expect(clearYieldedValues()).toEqual([]);235 advanceTime(1);236 expect(clearYieldedValues()).toEqual(['A']);237 });238 it('continues working on same task after yielding', () => {239 scheduleCallback(() => doWork('A', 100));240 scheduleCallback(() => doWork('B', 100));241 const tasks = [['C1', 100], ['C2', 100], ['C3', 100]];242 const C = deadline => {243 while (tasks.length > 0) {244 doWork(...tasks.shift());245 if (246 tasks.length > 0 &&247 !deadline.didTimeout &&248 deadline.timeRemaining() <= 0249 ) {250 yieldValue('Yield!');251 return C;252 }253 }254 };255 scheduleCallback(C);256 scheduleCallback(() => doWork('D', 100));257 scheduleCallback(() => doWork('E', 100));258 expect(flushWork(300)).toEqual(['A', 'B', 'C1', 'Yield!']);259 expect(flushWork()).toEqual(['C2', 'C3', 'D', 'E']);260 });261 it('continuation callbacks inherit the expiration of the previous callback', () => {262 const tasks = [['A', 125], ['B', 124], ['C', 100], ['D', 100]];263 const work = deadline => {264 while (tasks.length > 0) {265 doWork(...tasks.shift());266 if (267 tasks.length > 0 &&268 !deadline.didTimeout &&269 deadline.timeRemaining() <= 0270 ) {271 yieldValue('Yield!');272 return work;273 }274 }275 };276 // Schedule a high priority callback277 runWithPriority(UserBlockingPriority, () => scheduleCallback(work));278 // Flush until just before the expiration time279 expect(flushWork(249)).toEqual(['A', 'B', 'Yield!']);280 // Advance time by just a bit more. This should expire all the remaining work.281 advanceTime(1);282 expect(clearYieldedValues()).toEqual(['C', 'D']);283 });284 it('nested callbacks inherit the priority of the currently executing callback', () => {285 runWithPriority(UserBlockingPriority, () => {286 scheduleCallback(() => {287 doWork('Parent callback', 100);288 scheduleCallback(() => {289 doWork('Nested callback', 100);290 });291 });292 });293 expect(flushWork(100)).toEqual(['Parent callback']);294 // The nested callback has user-blocking priority, so it should295 // expire quickly.296 advanceTime(250 + 100);297 expect(clearYieldedValues()).toEqual(['Nested callback']);298 });299 it('continuations are interrupted by higher priority work', () => {300 const tasks = [['A', 100], ['B', 100], ['C', 100], ['D', 100]];301 const work = deadline => {302 while (tasks.length > 0) {303 doWork(...tasks.shift());304 if (305 tasks.length > 0 &&306 !deadline.didTimeout &&307 deadline.timeRemaining() <= 0308 ) {309 yieldValue('Yield!');310 return work;311 }312 }313 };314 scheduleCallback(work);315 expect(flushWork(100)).toEqual(['A', 'Yield!']);316 runWithPriority(UserBlockingPriority, () => {317 scheduleCallback(() => doWork('High pri', 100));318 });319 expect(flushWork()).toEqual(['High pri', 'B', 'C', 'D']);320 });321 it(322 'continutations are interrupted by higher priority work scheduled ' +323 'inside an executing callback',324 () => {325 const tasks = [['A', 100], ['B', 100], ['C', 100], ['D', 100]];326 const work = deadline => {327 while (tasks.length > 0) {328 const task = tasks.shift();329 doWork(...task);330 if (task[0] === 'B') {331 // Schedule high pri work from inside another callback332 yieldValue('Schedule high pri');333 runWithPriority(UserBlockingPriority, () =>334 scheduleCallback(() => doWork('High pri', 100)),335 );336 }337 if (338 tasks.length > 0 &&339 !deadline.didTimeout &&340 deadline.timeRemaining() <= 0341 ) {342 yieldValue('Yield!');343 return work;344 }345 }346 };347 scheduleCallback(work);348 expect(flushWork()).toEqual([349 'A',350 'B',351 'Schedule high pri',352 // Even though there's time left in the frame, the low pri callback353 // should yield to the high pri callback354 'Yield!',355 'High pri',356 // Continue low pri work357 'C',358 'D',359 ]);360 },361 );362 it('immediate callbacks fire at the end of outermost event', () => {363 runWithPriority(ImmediatePriority, () => {364 scheduleCallback(() => yieldValue('A'));365 scheduleCallback(() => yieldValue('B'));366 // Nested event367 runWithPriority(ImmediatePriority, () => {368 scheduleCallback(() => yieldValue('C'));369 // Nothing should have fired yet370 expect(clearYieldedValues()).toEqual([]);371 });372 // Nothing should have fired yet373 expect(clearYieldedValues()).toEqual([]);374 });375 // The callbacks were called at the end of the outer event376 expect(clearYieldedValues()).toEqual(['A', 'B', 'C']);377 });378 it('wrapped callbacks have same signature as original callback', () => {379 const wrappedCallback = wrapCallback((...args) => ({args}));380 expect(wrappedCallback('a', 'b')).toEqual({args: ['a', 'b']});381 });382 it('wrapped callbacks inherit the current priority', () => {383 const wrappedCallback = wrapCallback(() => {384 scheduleCallback(() => {385 doWork('Normal', 100);386 });387 });388 const wrappedInteractiveCallback = runWithPriority(389 UserBlockingPriority,390 () =>391 wrapCallback(() => {392 scheduleCallback(() => {393 doWork('User-blocking', 100);394 });395 }),396 );397 // This should schedule a normal callback398 wrappedCallback();399 // This should schedule an user-blocking callback400 wrappedInteractiveCallback();401 advanceTime(249);402 expect(clearYieldedValues()).toEqual([]);403 advanceTime(1);404 expect(clearYieldedValues()).toEqual(['User-blocking']);405 advanceTime(10000);406 expect(clearYieldedValues()).toEqual(['Normal']);407 });408 it('wrapped callbacks inherit the current priority even when nested', () => {409 const wrappedCallback = wrapCallback(() => {410 scheduleCallback(() => {411 doWork('Normal', 100);412 });413 });414 const wrappedInteractiveCallback = runWithPriority(415 UserBlockingPriority,416 () =>417 wrapCallback(() => {418 scheduleCallback(() => {419 doWork('User-blocking', 100);420 });421 }),422 );423 runWithPriority(UserBlockingPriority, () => {424 // This should schedule a normal callback425 wrappedCallback();426 // This should schedule an user-blocking callback427 wrappedInteractiveCallback();428 });429 advanceTime(249);430 expect(clearYieldedValues()).toEqual([]);431 advanceTime(1);432 expect(clearYieldedValues()).toEqual(['User-blocking']);433 advanceTime(10000);434 expect(clearYieldedValues()).toEqual(['Normal']);435 });436 it('immediate callbacks fire at the end of callback', () => {437 const immediateCallback = runWithPriority(ImmediatePriority, () =>438 wrapCallback(() => {439 scheduleCallback(() => yieldValue('callback'));440 }),441 );442 immediateCallback();443 // The callback was called at the end of the outer event444 expect(clearYieldedValues()).toEqual(['callback']);445 });446 it("immediate callbacks fire even if there's an error", () => {447 expect(() => {448 runWithPriority(ImmediatePriority, () => {449 scheduleCallback(() => {450 yieldValue('A');451 throw new Error('Oops A');452 });453 scheduleCallback(() => {454 yieldValue('B');455 });456 scheduleCallback(() => {457 yieldValue('C');458 throw new Error('Oops C');459 });460 });461 }).toThrow('Oops A');462 expect(clearYieldedValues()).toEqual(['A']);463 // B and C flush in a subsequent event. That way, the second error is not464 // swallowed.465 expect(() => flushWork(0)).toThrow('Oops C');466 expect(clearYieldedValues()).toEqual(['B', 'C']);467 });468 it('exposes the current priority level', () => {469 yieldValue(getCurrentPriorityLevel());470 runWithPriority(ImmediatePriority, () => {...
SchedulerNoDOM-test.js
Source:SchedulerNoDOM-test.js
...27 UserBlockingPriority = Scheduler.unstable_UserBlockingPriority;28 });29 it('runAllTimers flushes all scheduled callbacks', () => {30 let log = [];31 scheduleCallback(() => {32 log.push('A');33 });34 scheduleCallback(() => {35 log.push('B');36 });37 scheduleCallback(() => {38 log.push('C');39 });40 expect(log).toEqual([]);41 jest.runAllTimers();42 expect(log).toEqual(['A', 'B', 'C']);43 });44 it('executes callbacks in order of priority', () => {45 let log = [];46 scheduleCallback(() => {47 log.push('A');48 });49 scheduleCallback(() => {50 log.push('B');51 });52 runWithPriority(UserBlockingPriority, () => {53 scheduleCallback(() => {54 log.push('C');55 });56 scheduleCallback(() => {57 log.push('D');58 });59 });60 expect(log).toEqual([]);61 jest.runAllTimers();62 expect(log).toEqual(['C', 'D', 'A', 'B']);63 });64 it('advanceTimersByTime expires callbacks incrementally', () => {65 let log = [];66 scheduleCallback(() => {67 log.push('A');68 });69 scheduleCallback(() => {70 log.push('B');71 });72 runWithPriority(UserBlockingPriority, () => {73 scheduleCallback(() => {74 log.push('C');75 });76 scheduleCallback(() => {77 log.push('D');78 });79 });80 expect(log).toEqual([]);81 jest.advanceTimersByTime(249);82 expect(log).toEqual([]);83 jest.advanceTimersByTime(1);84 expect(log).toEqual(['C', 'D']);85 log = [];86 jest.runAllTimers();87 expect(log).toEqual(['A', 'B']);88 });89 it('calls immediate callbacks immediately', () => {90 let log = [];91 runWithPriority(ImmediatePriority, () => {92 scheduleCallback(() => {93 log.push('A');94 scheduleCallback(() => {95 log.push('B');96 });97 });98 });99 expect(log).toEqual(['A', 'B']);100 });101 it('handles errors', () => {102 let log = [];103 expect(() => {104 runWithPriority(ImmediatePriority, () => {105 scheduleCallback(() => {106 log.push('A');107 throw new Error('Oops A');108 });109 scheduleCallback(() => {110 log.push('B');111 });112 scheduleCallback(() => {113 log.push('C');114 throw new Error('Oops C');115 });116 });117 }).toThrow('Oops A');118 expect(log).toEqual(['A']);119 log = [];120 // B and C flush in a subsequent event. That way, the second error is not121 // swallowed.122 expect(() => jest.runAllTimers()).toThrow('Oops C');123 expect(log).toEqual(['B', 'C']);124 });...
SchedulerNoDOM-test.internal.js
Source:SchedulerNoDOM-test.internal.js
...27 UserBlockingPriority = Scheduler.unstable_UserBlockingPriority;28 });29 it('runAllTimers flushes all scheduled callbacks', () => {30 let log = [];31 scheduleCallback(() => {32 log.push('A');33 });34 scheduleCallback(() => {35 log.push('B');36 });37 scheduleCallback(() => {38 log.push('C');39 });40 expect(log).toEqual([]);41 jest.runAllTimers();42 expect(log).toEqual(['A', 'B', 'C']);43 });44 it('executes callbacks in order of priority', () => {45 let log = [];46 scheduleCallback(() => {47 log.push('A');48 });49 scheduleCallback(() => {50 log.push('B');51 });52 runWithPriority(UserBlockingPriority, () => {53 scheduleCallback(() => {54 log.push('C');55 });56 scheduleCallback(() => {57 log.push('D');58 });59 });60 expect(log).toEqual([]);61 jest.runAllTimers();62 expect(log).toEqual(['C', 'D', 'A', 'B']);63 });64 it('advanceTimersByTime expires callbacks incrementally', () => {65 let log = [];66 scheduleCallback(() => {67 log.push('A');68 });69 scheduleCallback(() => {70 log.push('B');71 });72 runWithPriority(UserBlockingPriority, () => {73 scheduleCallback(() => {74 log.push('C');75 });76 scheduleCallback(() => {77 log.push('D');78 });79 });80 expect(log).toEqual([]);81 jest.advanceTimersByTime(249);82 expect(log).toEqual([]);83 jest.advanceTimersByTime(1);84 expect(log).toEqual(['C', 'D']);85 log = [];86 jest.runAllTimers();87 expect(log).toEqual(['A', 'B']);88 });89 it('calls immediate callbacks immediately', () => {90 let log = [];91 runWithPriority(ImmediatePriority, () => {92 scheduleCallback(() => {93 log.push('A');94 scheduleCallback(() => {95 log.push('B');96 });97 });98 });99 expect(log).toEqual(['A', 'B']);100 });101 it('handles errors', () => {102 let log = [];103 expect(() => {104 runWithPriority(ImmediatePriority, () => {105 scheduleCallback(() => {106 log.push('A');107 throw new Error('Oops A');108 });109 scheduleCallback(() => {110 log.push('B');111 });112 scheduleCallback(() => {113 log.push('C');114 throw new Error('Oops C');115 });116 });117 }).toThrow('Oops A');118 expect(log).toEqual(['A']);119 log = [];120 // B and C flush in a subsequent event. That way, the second error is not121 // swallowed.122 expect(() => jest.runAllTimers()).toThrow('Oops C');123 expect(log).toEqual(['B', 'C']);124 });...
Using AI Code Generation
1const playwright = require('playwright');2(async () => {3 const browser = await playwright.chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.evaluate(() => {7 window.playwright.scheduleCallback(async () => {8 console.log('I am running in the background');9 });10 });11 await page.screenshot({ path: 'example.png' });12 await browser.close();13})();14const playwright = require('playwright');15(async () => {16 const browser = await playwright.chromium.launch();17 const context = await browser.newContext();18 const page = await context.newPage();19 await page.evaluate(() => {20 window.playwright.scheduleCallback(async () => {21 console.log('I am running in the background');22 }, 1000);23 });24 await page.screenshot({ path: 'example.png' });25 await browser.close();26})();27const playwright = require('playwright');28(async () => {29 const browser = await playwright.chromium.launch();30 const context = await browser.newContext();31 const page = await context.newPage();32 await page.evaluate(() => {33 window.playwright.scheduleCallback(async () => {34 console.log('I am running in the background');35 }, 1000);36 });37 await page.screenshot({ path: 'example.png' });38 await browser.close();39})();40const playwright = require('playwright');41(async () => {
Using AI Code Generation
1const playwright = require('playwright');2const path = require('path');3(async () => {4 const browser = await playwright.chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 await page.evaluate(() => {8 const { scheduleCallback } = window.playwrightInternals;9 scheduleCallback('myCallback', 1000);10 });11 await page.exposeFunction('myCallback', () => {12 console.log('myCallback called');13 });14 await page.waitForTimeout(5000);15 await browser.close();16})();
Using AI Code Generation
1const playwright = require('playwright');2const { scheduleCallback } = require('playwright/lib/internal/inspectorInstrumentation');3(async () => {4 const browser = await playwright.chromium.launch({ headless: false });5 const context = await browser.newContext();6 const page = await context.newPage();7 await page.screenshot({ path: 'google.png' });8 await browser.close();9})();10const { helper } = require('./helper');11const { assert } = require('./helper');12const { TimeoutError } = require('../utils/errors');13const { debugError } = require('../utils/debug');14const kMaxTimerDuration = 2147483647 / 1000;15class Timer {16 * @param {!Page} page17 * @param {function()|string} script18 * @param {number} timeout19 * @param {!Object=} options20 static async create(page, script, timeout, options = {}) {21 const timer = new Timer(page, script, timeout, options);22 await timer.init();23 return timer;24 }25 * @param {!Page} page26 * @param {function()|string} script27 * @param {number} timeout28 * @param {!Object=} options29 constructor(page, script, timeout, options = {}) {30 this._page = page;31 this._timeout = timeout;32 this._polling = 'polling' in options ? options.polling : 'raf';33 this._runOnlyOnce = !!options.runOnlyOnce;34 this._terminationPromiseCallback = null;35 this._terminationPromise = new Promise(f => this._terminationPromiseCallback = f);36 this._terminated = false;37 this._promiseCallback = null;38 this._promise = new Promise(f => this._promiseCallback = f);39 this._resolveCallback = null;40 this._rejectCallback = null;41 this._promise = new Promise((f, r) => {42 this._resolveCallback = f;43 this._rejectCallback = r;44 });45 this._timeoutTimer = null;46 this._repeatTimer = null;47 this._repeatEvery = options.repeatEvery;48 if (
Using AI Code Generation
1const { chromium } = require('playwright');2const { scheduleCallback } = require('playwright/lib/internal/inspectorInstrumentation');3(async () => {4 const browser = await chromium.launch({ headless: false });5 const page = await browser.newPage();6 await page.click('text=Get started');7 await page.click('text=API');8 await page.click('text=Page');9 await page.click('text=page.click');10 await page.click('text=Examples');11 await page.click('text=Demo');12 await page.click('text=Docs');13 await page.fill('input[placeholder="Search"]', 'Click');14 await page.click('text=Click');15 await page.waitForSelector('text=Page.click', { state: 'attached' });16 await page.click('text=Examples');17 await page.click('text=Demo');18 await page.click('text=Docs');19 await page.fill('input[placeholder="Search"]', 'Click');20 await page.click('text=Click');21 await page.waitForSelector('text=Page.click', { state: 'attached' });22 await page.click('text=Examples');23 await page.click('text=Demo');24 await page.click('text=Docs');25 await page.fill('input[placeholder="Search"]', 'Click');26 await page.click('text=Click');27 await page.waitForSelector('text=Page.click', { state: 'attached' });28 await page.click('text=Examples');29 await page.click('text=Demo');30 await page.click('text=Docs');31 await page.fill('input[placeholder="Search"]', 'Click');32 await page.click('text=Click');33 await page.waitForSelector('text=Page.click', { state: 'attached' });34 await page.click('text=Examples');35 await page.click('text=Demo');36 await page.click('text=Docs');37 await page.fill('input[placeholder="Search"]', 'Click');38 await page.click('text=Click');39 await page.waitForSelector('text=Page.click', { state: 'attached' });40 await page.click('text=Examples');41 await page.click('text=Demo');42 await page.click('text=Docs');43 await page.fill('input[placeholder="Search"]', 'Click');44 await page.click('text=
Using AI Code Generation
1const playwright = require('playwright');2const { scheduleCallback } = require('playwright/lib/internal/recorder/recorderActions');3(async () => {4 const browser = await playwright.chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 await page.screenshot({ path: `example.png` });8 await scheduleCallback(async () => {9 await page.click('text=Google apps');10 });11 await page.screenshot({ path: `example.png` });12 await browser.close();13})();14const playwright = require('playwright');15const { scheduleCallback } = require('playwright/lib/internal/recorder/recorderActions');16(async () => {17 const browser = await playwright.chromium.launch();18 const context = await browser.newContext();19 const page = await context.newPage();20 await page.screenshot({ path: `example.png` });21 await scheduleCallback(async () => {22 await page.click('text=Google apps');23 });24 await page.screenshot({ path: `example.png` });25 await browser.close();26})();27const playwright = require('playwright');28const { scheduleCallback } = require('playwright/lib/internal/recorder/recorderActions');29(async () => {30 const browser = await playwright.chromium.launch();31 const context = await browser.newContext();32 const page = await context.newPage();33 await page.screenshot({ path: `example.png` });34 await scheduleCallback(async () => {35 await page.click('text=Google apps');36 });37 await page.screenshot({ path: `example.png` });38 await browser.close();39})();40const playwright = require('playwright');41const { scheduleCallback } = require('playwright/lib/internal/recorder/recorderActions');42(async () => {43 const browser = await playwright.chromium.launch();44 const context = await browser.newContext();45 const page = await context.newPage();46 await page.screenshot({ path:
Using AI Code Generation
1const { scheduleCallback } = require('playwright-core/lib/server/supplements/recorder/recorderSupplement');2const { Page } = require('playwright-core/lib/server/page');3const { Frame } = require('playwright-core/lib/server/frames');4const { ElementHandle } = require('playwright-core/lib/server/dom');5const { JSHandle } = require('playwright-core/lib/server/jsHandle');6const { ChannelOwner } = require('playwright-core/lib/server/channelOwner');7const { context } = require('./context');8const page = await context.newPage();9const frame = await page.mainFrame().childFrames()[0];10const elementHandle = await frame.$('selector');11const jsHandle = await frame.evaluateHandle(() => document);12const channelOwner = await frame._page._delegate._owner._channel;13scheduleCallback(page, 'Page', 'load', []);14scheduleCallback(frame, 'Frame', 'load', []);15scheduleCallback(elementHandle, 'ElementHandle', 'click', []);16scheduleCallback(jsHandle, 'JSHandle', 'click', []);17scheduleCallback(channelOwner, 'ChannelOwner', 'click', []);18await page._delegate._owner._channel.saveRecording();19await page.close();20await browser.close();21await context.close();22await server.close();23await browserServer.close();24await browserContext.close();25await browserType.close();26await browser.close();27await deviceDescriptor.close();28await browserContext.close();29await browserType.close();30await browser.close();31await deviceDescriptor.close();32await browserContext.close();33await browserType.close();34await browser.close();
Using AI Code Generation
1const playwright = require('playwright');2const { scheduleCallback } = require('playwright/lib/internal/inspector');3const { chromium } = require('playwright');4const browser = await chromium.launch();5const context = await browser.newContext();6const page = await context.newPage();7await page.screenshot({ path: `google.png` });8await scheduleCallback('console.log', 'Hello from playwright');9await browser.close();10const playwright = require('playwright');11const { scheduleCallback } = require('playwright/lib/internal/inspector');12const { chromium } = require('playwright');13const browser = await chromium.launch();14const context = await browser.newContext();15const page = await context.newPage();16await page.screenshot({ path: `google.png` });17await scheduleCallback('console.log', 'Hello from playwright');18await browser.close();19const playwright = require('playwright');20const { scheduleCallback } = require('playwright/lib/internal/inspector');21const { chromium } = require('playwright');22const browser = await chromium.launch();23const context = await browser.newContext();24const page = await context.newPage();25await page.screenshot({ path: `google.png` });26await scheduleCallback('console.log', 'Hello from playwright');27await browser.close();28const playwright = require('playwright');29const { scheduleCallback } = require('playwright/lib/internal/inspector');30const { chromium } = require('playwright');31const browser = await chromium.launch();32const context = await browser.newContext();33const page = await context.newPage();34await page.screenshot({ path: `google.png` });35await scheduleCallback('console.log', 'Hello from playwright');36await browser.close();37const playwright = require('playwright');38const { scheduleCallback } = require('playwright/lib/internal/inspector');39const { chromium } = require('playwright');
Using AI Code Generation
1const { scheduleCallback } = require('playwright/lib/internal/inspectorInstrumentation');2scheduleCallback('test', () => {3 console.log('test');4});5Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /node_modules/playwright/lib/internal/inspectorInstrumentation.js6Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /node_modules/playwright/lib/internal/inspectorInstrumentation.cjs7Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /node_modules/playwright/lib/internal/inspectorInstrumentation.js
Using AI Code Generation
1const { scheduleCallback } = require('playwright/lib/server/supplements/recorder/recorderSupplement');2scheduleCallback(async (page, callback) => {3});4const { scheduleCallback } = require('playwright/lib/server/supplements/recorder/recorderSupplement');5scheduleCallback(async (page, callback) => {6});7const { scheduleCallback } = require('playwright/lib/server/supplements/recorder/recorderSupplement');8scheduleCallback(async (page, callback) => {9});10const { scheduleCallback } = require('playwright/lib/server/supplements/recorder/recorderSupplement');11scheduleCallback(async (page, callback) => {12});13const { scheduleCallback } = require('playwright/lib/server/supplements/recorder/recorderSupplement');14scheduleCallback(async (page, callback) => {15});16const { scheduleCallback } = require('playwright/lib/server/supplements/recorder/recorderSupplement');17scheduleCallback(async (page, callback) => {18});19const { scheduleCallback } = require('playwright/lib/server/supplements/recorder/recorderSupplement');20scheduleCallback(async (page, callback) => {21});22const { scheduleCallback } = require('playwright/lib/server/supplements/recorder/recorderSupplement');23scheduleCallback(async (page, callback) => {24});25const { scheduleCallback } = require('playwright/lib/server/supplements/recorder/recorderSupplement');26scheduleCallback(async (page, callback) => {27});28const { scheduleCallback } = require('playwright/lib/server/supplements/recorder/recorderSupplement');29scheduleCallback(async (page, callback) => {30});
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!