How to use scheduleCallback method in Playwright Internal

Best JavaScript code snippet using playwright-internal

SchedulerDOM-test.js

Source:SchedulerDOM-test.js Github

copy

Full Screen

...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...

Full Screen

Full Screen

Scheduler-test.js

Source:Scheduler-test.js Github

copy

Full Screen

...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 });...

Full Screen

Full Screen

SchedulerMock-test.js

Source:SchedulerMock-test.js Github

copy

Full Screen

...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 });...

Full Screen

Full Screen

Scheduler-test.internal.js

Source:Scheduler-test.internal.js Github

copy

Full Screen

...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, () => {...

Full Screen

Full Screen

SchedulerNoDOM-test.js

Source:SchedulerNoDOM-test.js Github

copy

Full Screen

...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 });...

Full Screen

Full Screen

SchedulerNoDOM-test.internal.js

Source:SchedulerNoDOM-test.internal.js Github

copy

Full Screen

...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 });...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

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 () => {

Full Screen

Using AI Code Generation

copy

Full Screen

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})();

Full Screen

Using AI Code Generation

copy

Full Screen

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 (

Full Screen

Using AI Code Generation

copy

Full Screen

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=

Full Screen

Using AI Code Generation

copy

Full Screen

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:

Full Screen

Using AI Code Generation

copy

Full Screen

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();

Full Screen

Using AI Code Generation

copy

Full Screen

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');

Full Screen

Using AI Code Generation

copy

Full Screen

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

Full Screen

Using AI Code Generation

copy

Full Screen

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});

Full Screen

Playwright tutorial

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.

Chapters:

  1. What is Playwright : Playwright is comparatively new but has gained good popularity. Get to know some history of the Playwright with some interesting facts connected with it.
  2. How To Install Playwright : Learn in detail about what basic configuration and dependencies are required for installing Playwright and run a test. Get a step-by-step direction for installing the Playwright automation framework.
  3. Playwright Futuristic Features: Launched in 2020, Playwright gained huge popularity quickly because of some obliging features such as Playwright Test Generator and Inspector, Playwright Reporter, Playwright auto-waiting mechanism and etc. Read up on those features to master Playwright testing.
  4. What is Component Testing: Component testing in Playwright is a unique feature that allows a tester to test a single component of a web application without integrating them with other elements. Learn how to perform Component testing on the Playwright automation framework.
  5. Inputs And Buttons In Playwright: Every website has Input boxes and buttons; learn about testing inputs and buttons with different scenarios and examples.
  6. Functions and Selectors in Playwright: Learn how to launch the Chromium browser with Playwright. Also, gain a better understanding of some important functions like “BrowserContext,” which allows you to run multiple browser sessions, and “newPage” which interacts with a page.
  7. Handling Alerts and Dropdowns in Playwright : Playwright interact with different types of alerts and pop-ups, such as simple, confirmation, and prompt, and different types of dropdowns, such as single selector and multi-selector get your hands-on with handling alerts and dropdown in Playright testing.
  8. Playwright vs Puppeteer: Get to know about the difference between two testing frameworks and how they are different than one another, which browsers they support, and what features they provide.
  9. Run Playwright Tests on LambdaTest: Playwright testing with LambdaTest leverages test performance to the utmost. You can run multiple Playwright tests in Parallel with the LammbdaTest test cloud. Get a step-by-step guide to run your Playwright test on the LambdaTest platform.
  10. Playwright Python Tutorial: Playwright automation framework support all major languages such as Python, JavaScript, TypeScript, .NET and etc. However, there are various advantages to Python end-to-end testing with Playwright because of its versatile utility. Get the hang of Playwright python testing with this chapter.
  11. Playwright End To End Testing Tutorial: Get your hands on with Playwright end-to-end testing and learn to use some exciting features such as TraceViewer, Debugging, Networking, Component testing, Visual testing, and many more.
  12. Playwright Video Tutorial: Watch the video tutorials on Playwright testing from experts and get a consecutive in-depth explanation of Playwright automation testing.

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful