Jest: рд╡рд╛рджрд╛ рд╕рдорд╛рдзрд╛рди рдХрддрд╛рд░ рдХреЛ рдлреНрд▓рд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдПрдкреАрдЖрдИ рдкреНрд░рджрд╛рди рдХрд░реЗрдВ

рдХреЛ рдирд┐рд░реНрдорд┐рдд 23 рдирд╡ре░ 2016  ┬╖  46рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: facebook/jest

рдХреНрдпрд╛ рдЖрдк рдХрд┐рд╕реА рд╕реБрд╡рд┐рдзрд╛ рдХрд╛ рдЕрдиреБрд░реЛрдз рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рдмрдЧ рдХреА рд░рд┐рдкреЛрд░реНрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ?

_Feature_, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди Promise s рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдХреЛрдб рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рддреЗ рд╕рдордп рдПрдХ рдмрд╣реБрдд рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред

рд╡рд░реНрддрдорд╛рди рд╡реНрдпрд╡рд╣рд╛рд░ рдХреНрдпрд╛ рд╣реИ?

рдореЗрд░реЗ рдкрд╛рд╕ рдПрдХ рдШрдЯрдХ рд╣реИ рдЬреЛ Promise рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдмрд╛рд╣рд░реА рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХреЗ рд▓рд┐рдП рдЕрдиреБрд╡рд░реНрддреА рдХрд╛рд░реНрд░рд╡рд╛рдИ рдореЗрдВ рдЖрдВрддрд░рд┐рдХ рд░реВрдк рд╕реЗ рд░реИрдкрд┐рдВрдЧ рдФрд░ рдЪреЗрдирд┐рдВрдЧ рдХрд░рддрд╛ рд╣реИред рдореИрдВ async рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХрд╛ рдореЙрдХ рдкреНрд░рджрд╛рди рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдореЗрд░реЗ рдкрд░реАрдХреНрд╖рдг рдореЗрдВ рджрд┐рдП рдЧрдП рд╡рд╛рджреЗ рдХреЛ рд╣рд▓ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред

рдШрдЯрдХ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рд╣реИ:

class Component extends React.Component {
  // ...
  load() {
    Promise.resolve(this.props.load())
      .then(
        result => result
          ? result
          : Promise.reject(/* ... */)
        () => Promise.reject(/* ... */)
      )
      .then(result => this.props.afterLoad(result));
  }
}

рдФрд░ рдкрд░реАрдХреНрд╖рдг рдХреЛрдб рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:

const load = jest.fn(() => new Promise(succeed => load.succeed = succeed));
const afterLoad = jest.fn();
const result = 'mock result';
mount(<Component load={load} afterLoad={afterLoad} />);
// ... some interaction that requires the `load`
load.succeed(result);
expect(afterLoad).toHaveBeenCalledWith(result);

рдкрд░реАрдХреНрд╖рдг рд╡рд┐рдлрд▓ рд░рд╣рддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ expect() рдХрд╛ рдореВрд▓реНрдпрд╛рдВрдХрди рдЬрдВрдЬреАрд░ рд╡рд╛рджрд╛ рд╣реИрдВрдбрд▓рд░ рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдореБрдЭреЗ рдЬреЛ рдЪрд╛рд╣рд┐рдП рд╡рд╣ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдкрд░реАрдХреНрд╖рдг рдореЗрдВ рдЖрдВрддрд░рд┐рдХ рд╡рд╛рджрд╛ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдХреА рд▓рдВрдмрд╛рдИ рдХреЛ рджреЛрд╣рд░рд╛рдирд╛ рд╣реЛрдЧрд╛, рдЬреИрд╕реЗ:

return Promise.resolve(load.succeed(result))
  // length of the `.then()` chain needs to be at least as long as in the tested code
  .then(() => {})
  .then(() => expect(result).toHaveBeenCalledWith(result));

рдЕрдкреЗрдХреНрд╖рд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рдХреНрдпрд╛ рд╣реИ?

рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдЬреЗрд╕реНрдЯ рд╕рднреА рд▓рдВрдмрд┐рдд рд╡рд╛рджреЗ рд╕рдВрдЪрд╛рд▓рдХреЛрдВ рдХреЛ рдлреНрд▓рд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рдХрд╛ рдПрдкреАрдЖрдИ рдкреНрд░рджрд╛рди рдХрд░реЗрдЧрд╛, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП:

load.succeed(result);
jest.flushAllPromises();
expect(result).toHaveBeenCalledWith(result);

рдореИрдВрдиреЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рдкреНрд░рднрд╛рд╡ рдХреЗ runAllTicks рдФрд░ runAllTimers рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд╣реИред


_рд╡реИрдХрд▓реНрдкрд┐рдХ рд░реВрдк рд╕реЗ, рдЕрдЧрд░ рдореБрдЭреЗ рдХреБрдЫ рдкрд╣рд▓реЗ рд╕реЗ рдореМрдЬреВрдж рд╕реБрд╡рд┐рдзрд╛ рдпрд╛ рдкреИрдЯрд░реНрди рдпрд╛рдж рдЖ рд░рд╣рд╛ рд╣реИ, рддреЛ рдореИрдВ рдЙрдореНрдореАрдж рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдХрд┐ рдпрд╣рд╛рдВ рдХреЛрдИ рдореБрдЭреЗ рд╕рд╣реА рджрд┐рд╢рд╛ рдореЗрдВ рдЗрдВрдЧрд┐рдд рдХрд░реЗ :)_

Enhancement New API proposal

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдПрдХ рд╕рд╣рд╛рдпрдХ рдХрд╛рд░реНрдп рдЗрд╕реЗ рдПрдХ рд╡рд╛рджреЗ рдореЗрдВ рдмрджрд▓ рд╕рдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЖрдкрдХреЛ рдХрд┐рдП рдЧрдП рдХреЙрд▓рдмреИрдХ рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдпрд╣ рдХрд╛рдлреА рдЫреЛрдЯрд╛ рд╣реИ, рдпрд╣ рдпреВрдЬрд░рд▓реИрдВрдб рдореЗрдВ рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рдлреА рд╣рд╛рдирд┐рдХрд╛рд░рдХ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдЗрд╕реЗ рдЬреЗрд╕реНрдЯ рдСрдмреНрдЬреЗрдХреНрдЯ рдкрд░ рд░рдЦрд╛ рдЬрд╛рддрд╛ рд╣реИ рддреЛ рдореИрдВ рд╢рд┐рдХрд╛рдпрдд рдирд╣реАрдВ рдХрд░рддрд╛ред рдореЗрд░реА рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдореЗрдВ рдРрд╕рд╛ рдХреБрдЫ рдмрд╣реБрдд рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

function flushPromises() {
  return new Promise(resolve => setImmediate(resolve));
}

test('', () => {
  somethingThatKicksOffPromiseChain();
  return flushPromises().then(() => {
    expect(...
  });
})

Async рдХреЗ рд╕рд╛рде рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдВ рдпрд╣ рд▓рдЧрднрдЧ рд╕реБрдВрджрд░ рд╣реИ:

test('', async () => {
  somethingThatKicksOffPromiseChain();
  await flushPromises();
  expect(...
})

рд╕рднреА 46 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдЬрдмрдХрд┐ async рдкрд░реАрдХреНрд╖рдг рд╡рд╛рджрд╛ рдХрд░рддрд╛ рд╣реИ, рдпрд╣ рдпрд╛рдж рд░рдЦрдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реИ рдХрд┐ рдЖрдк рдПрдХ рдкрд░реАрдХреНрд╖рдг рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдПрдХ рд╡рд╛рджреЗ рдХреЗ рд░реВрдк рдореЗрдВ рд╡рд╛рдкрд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдРрд╕рд╛ рдХреБрдЫ рдХрд╛рдо рдХрд░реЗрдЧрд╛:

test('my promise test', () => { //a test function returning a Promise
  return Promise.resolve(load.succeed(result))
    .then(() => {})
    .then(() => expect(result).toHaveBeenCalledWith(result));
})

рдкрд░реАрдХреНрд╖рдг рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рдПрдХ рд╡рд╛рджрд╛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рд╕реЗ рдЬреЗрд╕реНрдЯ рдХреЛ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдПрд╕рд┐рдВрдХ рдкрд░реАрдХреНрд╖рдг рд╣реИ рдФрд░ рдЗрд╕реЗ рд╣рд▓ рд╣реЛрдиреЗ рдпрд╛ рд╕рдордп рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рддрдХ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдирд╛ рд╣реИред

@thymikee рдмреЗрд╢рдХ рдореИрдВ рдЬреЗрд╕реНрдЯ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореВрд▓реНрдп рд╡рд╛рдкрд╕ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ - рдпрд╣ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдмрд┐рдВрджреБ рд╕реЗ рдмрд╛рд╣рд░ рд╣реИред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЖрдкрдиреЗ рдЕрдкрдиреЗ рдХреЛрдб рдореЗрдВ .then(() => {}) рд▓рд╛рдЗрди рдХреЛ рдХреИрд╕реЗ рдЫреЛрдбрд╝рд╛ред рдореИрдВ рдпрд╣ рдирд╣реАрдВ рджреЗрдЦрддрд╛ рдХрд┐ рдореИрдВ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдЕрдзрд┐рдХ рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ рд╡рд░реНрдгрди рдХреИрд╕реЗ рдХрд░ рд╕рдХрддрд╛ рд╣реВрдБ рдЬрд┐рддрдирд╛ рдореИрдВрдиреЗ рдкрд╣рд▓реЗ рдкреЛрд╕реНрдЯ рдореЗрдВ рдХрд┐рдпрд╛ рдерд╛ред рдХреГрдкрдпрд╛ рдЗрд╕реЗ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдкрдврд╝реЗрдВ рдФрд░ рдпрд╛ рддреЛ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рдлрд┐рд░ рд╕реЗ рдЦреЛрд▓реЗрдВ рдпрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВ рдХрд┐ рдЗрд╕реЗ рдХреИрд╕реЗ рд╣рд▓ рдХрд┐рдпрд╛ рдЬрд╛рдПред

_рдореИрдВрдиреЗ рднреНрд░рдо рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП OP рдореЗрдВ рдХреЛрдб рдореЗрдВ return рдЬреЛрдбрд╝рд╛ рд╣реИред_

рдЗрд╕реА рддрд░рд╣ рдХреА рд╕рдорд╕реНрдпрд╛ рдореЗрдВ рднрд╛рдЧ рдЧрдпрд╛, рдФрд░ рдЗрд╕реЗ рдпрд╣рд╛рдБ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛: https://github.com/pekala/test-problem-example

рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ: рдореИрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░реИрдХреНрд╢рди (рдПрдВрдЬрд╛рдЗрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдирдХрд▓реА) рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк Redux рд╕реНрдЯреЛрд░ рдкрд░ рднреЗрдЬреЗ рдЧрдП рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдЕрдиреБрдХреНрд░рдо рдкрд░ рдЬреЛрд░ рджреЗрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред рд╡рд╛рджреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рднреЗрдЬреЗ рдЧрдП рд╕рд┐рдВрдХ рдФрд░ рдПрд╕рд┐рдВрдХреНрд╕ рдХреЗ рд░реВрдк рдореЗрдВ рдХреНрд░рд┐рдпрд╛рдПрдВ (рддреБрд░рдВрдд рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдордЬрд╛рдХ рдЙрдбрд╝рд╛рдпрд╛ рдЧрдпрд╛)ред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╡рд╛рджрд╛ рд╢реНрд░реГрдВрдЦрд▓рд╛ рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рджрд╛рд╡рд╛ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИ, рдЕрдЧрд░ рдЖрдкрдХреЗ рдкрд╛рд╕ рд╡рд╛рджрд╛ рд╢реНрд░реГрдВрдЦрд▓рд╛ рддрдХ рд╕реАрдзреА рдкрд╣реБрдВрдЪ рдирд╣реАрдВ рд╣реИред setTimeout(..., 0) рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рд╣реИрдХреА рд▓рдЧрддрд╛ рд╣реИ рдФрд░ рдпрджрд┐ setTimeout рдХреЗ рдХреЙрд▓рдмреИрдХ рдореЗрдВ рджрд╛рд╡рд╛ рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЬреЗрд╕реНрдЯ рдЯрд╛рдЗрдордЖрдЙрдЯ рддреНрд░реБрдЯрд┐ (рдЕрднрд┐рдХрдерди рддреНрд░реБрдЯрд┐ рдХреЗ рдмрдЬрд╛рдп) рдХреЗ рд╕рд╛рде рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред

flushAllPromises рдХрд╛ рд╡рд┐рдЪрд╛рд░ рдПрдХ рд╕рдорд╛рдзрд╛рди рдХреА рддрд░рд╣ рд▓рдЧрддрд╛ рд╣реИ, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ runAllTicks рдХреЛ рдпрд╣реА рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП?

рдлреЙрд▓реЛ-рдЕрдк рдХреЗ рд░реВрдк рдореЗрдВ: рдореИрдВрдиреЗ setTimeout(..., 0) рдХреЛ setImmediate setTimeout(..., 0) рд╕рд╛рде рдмрджрд▓рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рдФрд░ рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╡рд╛рджрд╛ рдХреЙрд▓рдмреИрдХ рдорд╛рдЗрдХреНрд░реЛрдЯрд╛рд╕реНрдХ рдХрддрд╛рд░ рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рджреЛрдиреЛрдВ рджрд╛рд╡реЗ рдЪрд▓рд╛рддреЗ рд╣реИрдВ рдФрд░ рдЬреЗрд╕реНрдЯ рдХреЛ рджрд╛рд╡рд╛ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдкрд░ рд╕рдордп рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рд╕реЗ рд░реЛрдХрддрд╛ рд╣реИред рддреЛ, рдпрд╣ рдареАрдХ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдореЗрд░реЗ рдЙрдкрдпреЛрдЧрдХреЗрд╕ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реНрд╡реАрдХрд╛рд░реНрдп рд╕рдорд╛рдзрд╛рди рд╣реИ:

test('changing the reddit downloads posts', done => {
    setImmediate(() => {
        // assertions...
        done()
    })
})

рдПрдХ рд╕рд╣рд╛рдпрдХ рдХрд╛рд░реНрдп рдЗрд╕реЗ рдПрдХ рд╡рд╛рджреЗ рдореЗрдВ рдмрджрд▓ рд╕рдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЖрдкрдХреЛ рдХрд┐рдП рдЧрдП рдХреЙрд▓рдмреИрдХ рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдпрд╣ рдХрд╛рдлреА рдЫреЛрдЯрд╛ рд╣реИ, рдпрд╣ рдпреВрдЬрд░рд▓реИрдВрдб рдореЗрдВ рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рдлреА рд╣рд╛рдирд┐рдХрд╛рд░рдХ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдЗрд╕реЗ рдЬреЗрд╕реНрдЯ рдСрдмреНрдЬреЗрдХреНрдЯ рдкрд░ рд░рдЦрд╛ рдЬрд╛рддрд╛ рд╣реИ рддреЛ рдореИрдВ рд╢рд┐рдХрд╛рдпрдд рдирд╣реАрдВ рдХрд░рддрд╛ред рдореЗрд░реА рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдореЗрдВ рдРрд╕рд╛ рдХреБрдЫ рдмрд╣реБрдд рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

function flushPromises() {
  return new Promise(resolve => setImmediate(resolve));
}

test('', () => {
  somethingThatKicksOffPromiseChain();
  return flushPromises().then(() => {
    expect(...
  });
})

Async рдХреЗ рд╕рд╛рде рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдВ рдпрд╣ рд▓рдЧрднрдЧ рд╕реБрдВрджрд░ рд╣реИ:

test('', async () => {
  somethingThatKicksOffPromiseChain();
  await flushPromises();
  expect(...
})

@jwbay рд╡рд╣реАрдВ рдХреБрдЫ рдЕрдЪреНрдЫреА рдЪреАрдиреА рд╣реИ !

рдпрд╣ рд╕рдЪ рд╣реИ рдХрд┐ рдпрд╣ flushPromises рдПрдХ-рд▓рд╛рдЗрдирд░ рдирд┐рдХрд▓рд╛, рд▓реЗрдХрд┐рди рдпрд╣ рдмрд┐рд▓реНрдХреБрд▓ рднреА рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЙрд╕ рдПрдХ рдкрдВрдХреНрддрд┐ рддрдХ рдХреИрд╕реЗ рдкрд╣реБрдВрдЪрд╛ рдЬрд╛рдПред рдЗрд╕рд▓рд┐рдП рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЬреЗрд╕реНрдЯ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЗрд╕реЗ рдПрдХ рдЙрдкрдпреЛрдЧ рд╕рдорд╛рд░реЛрд╣ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрд▓рдмреНрдз рдХрд░рд╛рдирд╛ рдПрдХ рд▓рд╛рдн рд╣реЛрдЧрд╛ред

@pekala рд╡рди рд▓рд╛рдЗрдирд░ IMO рдЖрд╡рд╢реНрдпрдХ рд╡реНрдпрд╡рд╣рд╛рд░ рдкреНрд░рджрд╛рди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд▓рдВрдмрд┐рдд рд╡рд╛рджреЗ рдХреЗ рд╣рд▓ рд╣реЛрдиреЗ рддрдХ рдкреНрд░рддреАрдХреНрд╖рд╛ рдирд╣реАрдВ рдХрд░реЗрдЧрд╛:

function foo() {  
  return new Promise((res) => {
    setTimeout(() => {
      res()
    }, 2000);
  });
}

рд╕реНрд╡рд┐рдЬрд╝рд▓рд┐рдВрдЧ рдкреНрд░реЙрдорд┐рд╕ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛ рд╣реИ рдФрд░ рдЬрдм рдПрдХ рдирдпрд╛ рдкреНрд░реЙрдорд┐рд╕ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддреЛ рдЙрд╕реЗ рдХреБрдЫ рдРрд░реЗ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ, рдлрд┐рд░ рд╕рднреА рд╡рд╛рджреЛрдВ рдХреЛ рдкреНрд░реЙрдорд┐рд╕ рдкрд░ рдлреНрд▓рд╢ рдХрд░реЗрдВред рдЗрд╕ рдРрд░реЗ рдореЗрдВ рд╕рднреА рд╡рд╛рджреЗ?

@talkol рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рддрдм рддрдХ рд╣реЛрдЧрд╛, рдЬрдм рддрдХ рдЖрдк рд╣рдореЗрдВ рдирдХрд▓реА рдЯрд╛рдЗрдорд░ рднреА рджреЗрдВрдЧреЗред рдореИрдВрдиреЗ рд╣рд╛рд▓рд╛рдВрдХрд┐ рдЗрд╕рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИред

@pekala рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╕рд╛рде рдирдХрд▓реА рдЯрд╛рдЗрдорд░ рдХреА рдХреЛрдИ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рд╡рд╛рджрд╛ рд╕рдордп рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рд╣реА рд╣рд▓ рд╣реЛрдЧрд╛
рдореБрдЭреЗ рдмрд╕ рдЗрд╕ рдмрд╛рдд рдХреА рдЪрд┐рдВрддрд╛ рд╣реИ рдХрд┐ рд╕реНрд╡рд┐рдЬрд╝рд▓рд┐рдВрдЧ рдкреНрд░реЙрдорд┐рд╕ рдордЬрд╝рд╛рдХ рдХреЗ рдЕрдВрджрд░реВрдиреА рдХрд╛рдордХрд╛рдЬ рдХреЗ рд╕рд╛рде рдЦрд┐рд▓рд╡рд╛рдбрд╝ рдХрд░реЗрдЧрд╛, рдпрд╣ рдереЛрдбрд╝рд╛ рдХрдард┐рди рд╣реИ

рдпрджрд┐ рдЖрдк рдирдХрд▓реА рдЯрд╛рдЗрдорд░ рдирд╣реАрдВ рдмрдирд╛рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЗ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЛ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдореЗрдВ рд╡рд╛рд╕реНрддрд╡рд┐рдХ 2s+ рд▓рдЧреЗрдВрдЧреЗред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХреА рджреЗрд░реА рдХреЛ рджреВрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рдЕрднреНрдпрд╛рд╕ рд╣реЛрдЧрд╛, рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ @jwbay рджреНрд╡рд╛рд░рд╛ рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд flushPromises рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред

рд╕рдм рдХреБрдЫ рдЗрд╕ рдмрд╛рдд рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЖрдк рдХреНрдпрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣реЗ рд╣реИрдВ :) рдореИрдВ рдХреЗрд╡рд▓ рдЗрддрдирд╛ рдХрд╣ рд░рд╣рд╛ рд╣реВрдВ рдХрд┐ рдЯрд╛рдЗрдорд░ рд╡рд╛рджреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрд╕рдВрдмрдВрдзрд┐рдд рдЪрд┐рдВрддрд╛ рд╣реИ

рд╣рдо рд╡рд╛рджреЗ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ рдХреЛ рд╣рд▓ рдирд╣реАрдВ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдЬреЛ рд╕реЗрдЯрдЯрд╛рдЗрдордЖрдЙрдЯ рдХреЙрд▓ рдХреЗ рд╕рд╛рде рдорд┐рд╢реНрд░рд┐рдд рд╣реИрдВред рдЬреЗрд╕реНрдЯ v19.0.2 рдореЗрдВ рд╣рдореЗрдВ рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдЬреЗрд╕реНрдЯ v20.0.0 рдореЗрдВ рд╡рд╛рджреЗ рдХрднреА рднреА рд╕рдВрдХрд▓реНрдк / рдЕрд╕реНрд╡реАрдХрд╛рд░ рдХрд╛рд░реНрдпреЛрдВ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕рд▓рд┐рдП рдкрд░реАрдХреНрд╖рдг рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВред рд╣рдорд╛рд░рд╛ рдореБрджреНрджрд╛ рдЗрд╕ рдореБрджреНрджреЗ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ рдХрд┐ рдкреНрд░реЙрдорд┐рд╕ рд░реЗрдЬреЛрд▓реНрдпреВрд╢рди рдХрддрд╛рд░_ тАЛтАЛрдХреЛ рдлреНрд▓рд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП _an рдПрдкреАрдЖрдИ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдореБрджреНрджрд╛ рдЬреЗрд╕реНрдЯ v20.0.0 рд╕реЗ рдкрд╣рд▓реЗ рдХрд╛ рд▓рдЧрддрд╛ рд╣реИ, рдЬрд╣рд╛рдВ рд╣рдордиреЗ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рджреЗрдЦрдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛, рдЗрд╕рд▓рд┐рдП рдореБрдЭреЗ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИред

рдпрд╣ рдПрдХрдорд╛рддреНрд░ рд╕рдорд╛рдзрд╛рди рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдЕрдкрдиреЗ рдХреБрдЫ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рд╕рд╛рде рд▓рд╛рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреЛрдб рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ setTimeout s рдФрд░ Promise s рдХреА рдПрдХ рд╢реНрд░реГрдВрдЦрд▓рд╛ рд╣реИ рдЬреЛ рдЕрдВрддрддрдГ рдХреЙрд▓ рдХрд░рддреА рд╣реИ onUpdateFailed рдХреЙрд▓рдмреИрдХред

  ReactTestUtils.Simulate.submit(form);
  return Promise.resolve()
    .then(() => { jest.runOnlyPendingTimers(); })
    .then(() => { jest.runOnlyPendingTimers(); })
    .then(() => { jest.runOnlyPendingTimers(); })
    .then(() => {
      expect(onUpdateFailed).toHaveBeenCalledTimes(1);
      expect(getErrorMessage(page)).toEqual('Input is invalid.');
    });

рдЗрддрдирд╛ рд╕реБрдВрджрд░ рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрд╣рд╛рдВ рдХрд┐рд╕реА рднреА рд╕рд▓рд╛рд╣ рдХреА рдмрд╣реБрдд рд╕рд░рд╛рд╣рдирд╛ рдХреА рдЬрд╛рддреА рд╣реИред

рдПрдХ рдФрд░ рдЙрджрд╛рд╣рд░рдг рдЬрд╣рд╛рдВ рдЖрдк рдкрд░реАрдХреНрд╖рдг рд╕реЗ рд╡рд╛рджрд╛ рд╡рд╛рдкрд╕ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ:

describe('stream from promise', () => {
  it('should wait till promise resolves', () => {
    const stream = Observable.fromPromise(Promise.resolve('foo'));
    const results = [];
    stream.subscribe(data => { results.push(data); });
    jest.runAllTimers();
    expect(results).toEqual(['foo']);
  });
});

рдпрд╣ рдкрд░реАрдХреНрд╖рдг рдЬреЗрд╕реНрдЯ 20.0.4 рдХреЗ рд╕рд╛рде рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред

@philwhln рдХрд╛ рд╕рдорд╛рдзрд╛рди рднреА async/рдкреНрд░рддреАрдХреНрд╖рд╛ рдХреЗ рд╕рд╛рде рд▓рд┐рдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ

ReactTestUtils.Simulate.submit(form);

await jest.runOnlyPendingTimers();
await jest.runOnlyPendingTimers();
await jest.runOnlyPendingTimers();

expect(onUpdateFailed).toHaveBeenCalledTimes(1);
expect(getErrorMessage(page)).toEqual('Input is invalid.');

рдореБрдЭреЗ рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдлрд╝рдВрдХреНрд╢рди рдкрд╕рдВрдж рдЖрдПрдЧрд╛ рдЬреЛ рд╡рд╛рджрд╛ рдХрддрд╛рд░ рдХреЛ рдлрд╝реНрд▓рд╢ рдХрд░рддрд╛ рд╣реИ

рдореБрдЭреЗ рдПрдХ рдРрд╕рд╛ рдлрд╝рдВрдХреНрд╢рди рдкрд╕рдВрдж рдЖрдПрдЧрд╛ рдЬреЛ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рдмреАрдЪ рд╡рд╛рджрд╛ рдХрддрд╛рд░реЛрдВ рдХреЛ рднреА рдлреНрд▓рд╢ рдХрд░рддрд╛ рд╣реИред

рдореИрдВ рдХреЛрдб рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдЬреЛ рдХрдИ рд╡рд╛рджреЛрдВ рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП Promise.all рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред рдЬрдм рдЙрди рд▓рд┐рдкрдЯреЗ рд╡рд╛рджреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ (рдХреНрдпреЛрдВрдХрд┐ рдореИрдВ рдпрд╣реА рдкрд░реАрдХреНрд╖рдг рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ) рд╡рд╛рджрд╛ рддреБрд░рдВрдд рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рддрд╛ рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдХрднреА-рдХрднреА рдЕрдиреНрдп рд╡рд╛рджреЗ (рджреМрдбрд╝ рдХреА рд╕реНрдерд┐рддрд┐, рдЧреИрд░ рдирд┐рдпрддрд╛рддреНрдордХ) рд╡рд╛рдкрд╕реА рд╣реЛрддреА рд╣реИ рдЬрдмрдХрд┐ рдЕрдЧрд▓рд╛ рдкрд░реАрдХреНрд╖рдг рдЪрд▓ рд░рд╣рд╛ рд╣реЛрддрд╛ рд╣реИред

рдпрд╣ рдореЗрд░реЗ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рд╕рд╛рде рдЧреИрд░-рдЕрдиреБрдорд╛рдирд┐рдд/рджреЛрд╣рд░рд╛рдП рдЬрд╛рдиреЗ рдпреЛрдЧреНрдп рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЗ рд╕рд╛рде рд╕рднреА рдкреНрд░рдХрд╛рд░ рдХреЗ рдХрд╣рд░ рдХрд╛ рдХрд╛рд░рдг рдмрдирддрд╛ рд╣реИред

рдЗрд╕реЗ рдареАрдХ рд╕реЗ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ Promise рдХрд╛ рдЙрдкрд╣рд╛рд╕ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рддрд╛рдХрд┐ рд╣рдо рдЕрдВрддрддрдГ рд╕рднреА рд╕рдВрд▓рдЧреНрди рд╕реВрдХреНрд╖реНрдо рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд╕рдордХрд╛рд▓рд┐рдХ рд░реВрдк рд╕реЗ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рджреЗрдЦ рд╕рдХреЗрдВред рд╡рд╛рджреЗ-рдордЬрд╛рдХ рдХреНрдпрд╛ рдХрд░ рд░рд╣рд╛ рд╣реИ рдХреЗ рд░рд╛рд╕реНрддреЗ рдореЗрдВ рдХреБрдЫред

process.nextTick рд╕рд╛рде рд╕рдВрд▓рдЧреНрди рд╕реВрдХреНрд╖реНрдо рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдлреНрд▓рд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдПрдХ рдПрдкреАрдЖрдИ рд╣реИ рдФрд░ рдЙрд╕ рдПрдкреАрдЖрдИ рдХреЛ рд╢рд╛рдпрдж рд╡рд╛рджреЗ ( jest.runAllTicks ) рдХреЗ рд╕рд╛рде рднреА рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдореЗрд░реЗ рдкрд╛рд╕ рдЪрдореЗрд▓реА рдХреЗ рд╕рд╛рде рдПрдХ рд╕рдорд╛рдзрд╛рди рдерд╛ рдЬреЛ рдпрд╛рдХреВ рдХреЗ рдЕрдЧрд▓реЗ рдЯрд┐рдХ, рдПрдХ рд╡рд╛рджрд╛ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдореЗрдВ рдЬреБрдбрд╝рд╛ рд╣реБрдЖ рдерд╛ рдФрд░ рдЕрдЧрд▓реА рдЯрд┐рдХ рдХреЙрд▓реЛрдВ рдХреЛ рдкрдХрдбрд╝рд╛ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдЬрд▓реНрджреА рдЦреЗрд▓рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреАред
рд╣рд╛рд▓рд╛рдБрдХрд┐, рдордЬрд╝рд╛рдХ рд╕реНрд╡рдпрдВ рд╡рд╛рджреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рдиреЗ рдЗрд╕реЗ рд╕рдорд╕реНрдпрд╛рдЧреНрд░рд╕реНрдд рдмрдирд╛ рджрд┐рдпрд╛ред
рдЕрдВрдд рдореЗрдВ рдореИрдВрдиреЗ рдпрд╛рдХреВ рдХреЛ рд▓реЗ рд▓рд┐рдпрд╛ рдФрд░ рдЙрд╕реЗ рд╣реИрдХ рдХрд░ рд▓рд┐рдпрд╛ рддрд╛рдХрд┐ рдПрдХ рдлреНрд▓рд╢ рд╡рд┐рдзрд┐ рд╣реЛ рдЬреЛ рдЙрд╕рдХреА рдХрддрд╛рд░ рдХреЛ рд╣рдЯрд╛ рджреЗред рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдпрд╣ рд╕рд╛рдорд╛рдиреНрдп рд░реВрдк рд╕реЗ рдЕрдЧрд▓реА рдЯрд┐рдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрджрд┐ рдЖрдк рдлреНрд▓рд╢ рдХреЛ рдХреЙрд▓ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рд╕рднреА рд▓рдВрдмрд┐рдд рд╡рд╛рджреЗ рд╣реИрдВрдбрд▓рд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рд╣реЛрддреЗ рд╣реИрдВред
рд╕реНрд░реЛрдд рдпрд╣рд╛рдБ рд╣реИ:
https://github.com/lukeapage/yaku-mock
рдпрд╣ рд╕рд╛рдл рдХрд░рдиреЗ, ysmood рд╕реЗ рд╕рдВрдкрд░реНрдХ рдХрд░рдХреЗ рдпрд╣ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рд╡реЗ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛ рд╕реЛрдЪрддреЗ рд╣реИрдВ рдФрд░ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рдмрд╣реБрдд рдХреБрдЫ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдЖрдк рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдФрд░ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рд╡рд╛рджреЛрдВ рдХреЛ рд╕рд┐рдВрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд░рд▓ рд╕рдорд╛рдзрд╛рди рдХреЗ рд░реВрдк рдореЗрдВ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд┐рдпрд╛ред

рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╛рдзрд╛рд░рдг рд╕рдорд╛рдзрд╛рди рдХреЗ рд░реВрдк рдореЗрдВ рдореБрдЭреЗ @jwbay рдХрд╛ рд╕рдорд╛рдзрд╛рди рдкрд╕рдВрдж рд╣реИред

рд╣рдо jest рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд╕рдорд╛рди рдХреБрдЫ рдХреИрд╕реЗ рдЬреЛрдбрд╝реЗрдВрдЧреЗ?

await jest.nextTick();

рдХреЗ рд░реВрдк рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЧрдпрд╛

const nextTick = () => new Promise(res => process.nextTick(res));

cc @cpojer @SimenB @rogeliog

рдореИрдВ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдШрдЯрдХреЛрдВ рдХреЛ рдорд╛рдЙрдВрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдВрдЬрд╛рдЗрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред

рдореЗрд░реЗ рдкрд╛рд╕ рднреА рдРрд╕реЗ рдХрд╛рд░реНрдп рд╣реИрдВ рдЬреЛ рд╡рд╛рджреЗ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдкреЗрдХреНрд╖рд╛ рдХрд░рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЙрдкрд░реНрдпреБрдХреНрдд рд╕реБрдзрд╛рд░реЛрдВ рдореЗрдВ рд╕реЗ рдХреЛрдИ рднреА рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдореИрдВ рдЙрдиреНрд╣реЗрдВ рдЕрдкрдиреЗ рдкрд░реАрдХреНрд╖рдг рдореЗрдВ рд╕рдордХрд╛рд▓рд┐рдХ рд░реВрдк рд╕реЗ рд╕рдВрднрд╛рд▓рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдЧрд╛ - рдЕрдЧрд░ - рдХрд╛рд░реНрдпреЛрдВ рдиреЗ рд╡рд╛рджрд╛ рд╡рд╕реНрддреБрдУрдВ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░ рджрд┐рдпрд╛, await рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рд▓реЗрдХрд┐рди рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ рдлрд╝рдВрдХреНрд╢рди рд╡рд╛рджрд╛ рд╡рд╕реНрддреБрдУрдВ рдХреЛ рд╡рд╛рдкрд╕ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВред

рдпрд╣ рд╡рд╣ рд╕рдорд╛рдзрд╛рди рд╣реИ рдЬрд┐рд╕реЗ рдореИрдВрдиреЗ рд╡реИрд╢реНрд╡рд┐рдХ рдкреНрд░реЙрдорд┐рд╕ рдлрд╝рдВрдХреНрд╢рди рдкрд░ рдПрдХ рдЬрд╛рд╕реВрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рдорд╛рдкреНрдд рдХрд┐рдпрд╛ред

global.Promise = require.requireActual('promise');

it('my test', async () => {
    const spy = sinon.spy(global, 'Promise');

    wrapper.props().dispatch(functionWithPromiseCalls());

    for (let i = 0; i < spy.callCount; i += 1) {
      const promise = spy.getCall(i);
      await promise.returnValue;
    }

    expect(...)
});

рдореБрдЭреЗ рдЗрд╕рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХреЗ рдорд╛рдорд▓реЗ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝рд╛ (рднрдпрд╛рдирдХ рддрдХрдиреАрдХ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж @jwbay )

рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЖрдк рдЬрд╛рдВрдЪрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдХрд┐ рдЖрдкрдХреЗ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЯрд╛рдЗрдордЖрдЙрдЯ рд╣реИ, рдФрд░ рдпрд╣ рдХрд┐ рдЯрд╛рдЗрдордЖрдЙрдЯ рдареАрдХ рд╕реЗ рд▓рд╛рдЧреВ рд╣реИ:

      jest.useFakeTimers();
      const EXPECTED_DEFAULT_TIMEOUT_MS = 10000;

      const catchHandler = jest.fn().mockImplementationOnce(err => {
        expect(err).not.toBeNull();
        expect(err.message).toContain('timeout');
      });

      // launch the async func returning a promise
      fetchStuffWithTimeout().catch(catchHandler);

      expect(catchHandler).not.toHaveBeenCalled(); // not yet

      jest.advanceTimersByTime(EXPECTED_DEFAULT_TIMEOUT_MS - 1);
      await flushPromises();

      expect(catchHandler).not.toHaveBeenCalled(); // not yet

      jest.advanceTimersByTime(1);
      await flushPromises();

      expect(catchHandler).toHaveBeenCalledTimes(1); // ok, rejected precisely

рдПрдХ рд╡рд╛рджрд╛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рд╕реЗ рд╕рдВрдХрд▓реНрдк/рдЕрд╕реНрд╡реАрдХреГрддрд┐ рдХреЗ рд╕рдЯреАрдХ рд╕рдордп рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рдорд┐рд▓рддреА рд╣реИред

рд╡рд╣рд╛рдВ рдПрдХ рд╡рд╛рджрд╛ рдлреНрд▓рд╢рд┐рдВрдЧ рдХреА рдЬрд░реВрд░рдд рд╣реИред рдЗрд╕рдХреЗ рдмрд┐рдирд╛, рдЕрдкреЗрдХреНрд╖рд╛ рдХреЛ рдмрд╣реБрдд рдЬрд▓реНрджреА рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред

рдЖрд╢рд╛ рд╣реИ рдХрд┐ рдЗрд╕рд╕реЗ рд╕рдорд╕реНрдпрд╛ рдХреЛ рдХрдо рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдорд┐рд▓реЗрдЧреАред

рд╕рд╛рде рдЪрд▓рдиреЗ рд╡рд╛рд▓реЗ рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП, рдпрд╣рд╛рдВ рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдЦреБрд▓рд╛ рдкреАрдЖрд░ рд╣реИ: #6876

https://github.com/airbnb/enzyme/issues/1587 . рд╕реЗ рдХреНрд░реЙрд╕ рдкреЛрд╕реНрдЯрд┐рдВрдЧ

рдореБрдЭреЗ рдЖрд╢реНрдЪрд░реНрдп рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреИрдЯрд░реНрди рдкрд░реНрдпрд╛рдкреНрдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдФрд░ рдпрджрд┐ рдореИрдВ рдХреБрдЫ рдРрд╕рд╛ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдЬрд┐рд╕реЗ рдмреБрд░рд╛ рдЕрднреНрдпрд╛рд╕ рдорд╛рдирд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдореБрдЭреЗ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред

рд▓реЛрдЧ рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛ рд╕реЛрдЪрддреЗ рд╣реИрдВ?

export class MyComponent extends React.Component {
  constructor (props) {
    super(props)

    this.hasFinishedAsync = new Promise((resolve, reject) => {
      this.finishedAsyncResolve = resolve
    })
  }

  componentDidMount () {
    this.doSomethingAsync()
  }

  async doSomethingAsync () {
    try {
      actuallyDoAsync()
      this.props.callback()
      this.finishedAsyncResolve('success')
    } catch (error) {
      this.props.callback()
      this.finishedAsyncResolve('error')
    }
  }

  // the rest of the component
}

рдФрд░ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ:

it(`should properly await for async code to finish`, () => {
  const mockCallback = jest.fn()
  const wrapper = shallow(<MyComponent callback={mockCallback}/>)

  expect(mockCallback.mock.calls.length).toBe(0)

  await wrapper.instance().hasFinishedAsync

  expect(mockCallback.mock.calls.length).toBe(1)
})

рдореБрдЭреЗ рдПрдХ рд╕рдорд╕реНрдпрд╛ рдереА рдЬрдм рдПрд╕рд┐рдВрдХ рдХреЙрд▓ рд╕реАрдзреЗ рдХрдВрдкреЛрдиреЗрдВрдЯрдбрд┐рдбрдорд╛рдЙрдВрдЯ рдореЗрдВ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рд▓реЗрдХрд┐рди рдпрд╣ рдПрдХ рдПрд╕рд┐рдВрдХреНрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░ рд░рд╣рд╛ рдерд╛, рдЬреЛ рдПрдХ рдФрд░ рдПрд╕рд┐рдВрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░ рд░рд╣рд╛ рдерд╛ рдФрд░ рдЗрд╕реА рддрд░рд╣ред рдЕрдЧрд░ рдореИрдВрдиреЗ рд╕рднреА рдПрд╕рд┐рдВрдХ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдореЗрдВ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдПрд╕рд┐рдВрдХ рдЪрд░рдг рдЬреЛрдбрд╝рд╛ рд╣реИ, рддреЛ рдореБрдЭреЗ рдЕрддрд┐рд░рд┐рдХреНрдд .then() рдпрд╛ рдЕрддрд┐рд░рд┐рдХреНрдд await рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛, рд▓реЗрдХрд┐рди рдпрд╣ рдареАрдХ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИред

рдХреНрдпрд╛ рдХреЛрдИ рдХрд╛рд░рдг рд╣реИ рдХрд┐ рдореБрдЭреЗ рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдпрд╛ рдХреНрдпрд╛ рдпрд╣ рд▓реЛрдЧреЛрдВ рдХреЛ рдЕрдЪреНрдЫрд╛ рд▓рдЧрддрд╛ рд╣реИ?

рдореИрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рд▓реИрдВрдб рдореЗрдВ рдРрд╕рд╛ рдХрд░рдиреЗ рдореЗрдВ рдПрдХ рд╕рд╛рд╣рд╕рд┐рдХ рдХрд╛рд░реНрдп рдкрд░ рдЧрдпрд╛ рдФрд░ рдкрд╛рдпрд╛ рдХрд┐ рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдФрд░ рдЗрддрдирд╛ рдмреБрд░рд╛ рдирд╣реАрдВ рд╣реИ (рд╣рд╛рд▓рд╛рдВрдХрд┐ рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдирдХреНрд╢рд╛ рдирд╣реАрдВ рд╣реИ рддреЛ рдЗрд╕рдореЗрдВ рдХреБрдЫ рдиреБрдХрд╕рд╛рди рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ)ред рдпрд╣рд╛рдВ рдПрдХ рдЕрдиреБрднрд╡ рд░рд┐рдкреЛрд░реНрдЯ рд╣реИ рдЬреЛ (рдЙрдореНрдореАрдж рд╣реИ) рд╕реАрдзреЗ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╡рд┐рд╕реНрддреГрдд рд╣реИ ; рдПрдХ TLDR async / await рдХреЛ рд╡рд╛рджреЛрдВ рдХреЗ рдиреАрдЪреЗ рдЯреНрд░рд╛рдВрд╕рдкрд╛рдЗрд▓ рдХрд░рдирд╛ рд╣реИ, рдФрд░ рд▓реЛрд▓реЗрдХреНрд╕ рдХреЗ рд▓рд┐рдП рдмреНрд▓реВрдмрд░реНрдб рдФрд░ рджреЗрд╢реА рдЯрд╛рдЗрдорд░ рдХреЗ рд▓рд┐рдП рдореВрд▓ рд╡рд╛рджреЛрдВ рдХреЛ рд╕реНрд╡реИрдк рдХрд░рдирд╛ рд╣реИ; node_modules/ рд╕рд╣рд┐рдд рд╕рдм рдХреБрдЫ рдкрд╛рд░рджрд░реНрд╢реА рдХрд░реЗрдВ; queueMicrotask рд╡рд╛рджреЛрдВ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдЖрд╡рд╢реНрдпрдХ рдЖрджрд┐рдо рд╣реИ, рд▓реЗрдХрд┐рди рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рд▓реЛрд▓реЗрдХреНрд╕ рдЗрд╕реЗ рдкреНрд░рджрд╛рди рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ рдХреНрдпреЛрдВрдХрд┐ JSDOM рдЗрд╕реЗ рдкреНрд░рджрд╛рди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред

рдореИрдВ jest.mockAllTimers() рдФрд░ рд░рд┐рдПрдХреНрдЯ рдШрдЯрдХреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рд╣реА рдореБрджреНрджреЗ рдореЗрдВ рднрд╛рдЧ рдЧрдпрд╛ рдЬреЛ Promise рдореЗрдВ componentDidMount() ред

#issuecomment-279171856 рд╕реЗ рд╕рдорд╛рдзрд╛рди рдиреЗ рд╕рдорд╕реНрдпрд╛ рдХреЛ рдПрдХ рд╕реБрдВрджрд░ рддрд░реАрдХреЗ рд╕реЗ рд╣рд▓ рдХрд┐рдпрд╛ред

рд╣рдореЗрдВ рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рдЬреЗрд╕реНрдЯ рдПрдкреАрдЖрдИ рдореЗрдВ рдХреБрдЫ рдРрд╕рд╛ рд╣реА рдЪрд╛рд╣рд┐рдП!

рдореИрдВ рд╣рд╛рд▓ рд╣реА рдореЗрдВ рд╕рд╛рдорд╛рдиреЛрдВ рдХреЗ рдПрдХ рд╕рдореВрд╣ рдХреЛ рдЕрдкрдЧреНрд░реЗрдб рдХрд░рддреЗ рд╕рдордп рдПрдХ рд╕рдорд╕реНрдпрд╛ рдореЗрдВ рднрд╛рдЧ рдЧрдпрд╛, рдЗрд╕рдиреЗ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рдПрдХ рд╕рдореВрд╣ рдореЗрдВ рдПрдХ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдЦреБрд▓рд╛рд╕рд╛ рдХрд┐рдпрд╛ рдЬрд╣рд╛рдВ рд╣рдо рд╣рдореЗрд╢рд╛ рд╡рд╛рджреЗ рдЦрддреНрдо рд╣реЛрдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдирд╣реАрдВ рдХрд░ рд░рд╣реЗ рдереЗред рдФрд░ рдЬрдмрдХрд┐ await new Promise(resolve => setImmediate(resolve)); рдЬреИрд╕реА рд╡рд┐рдзрд┐рдпреЛрдВ рдиреЗ рд╕рд╛рдзрд╛рд░рдг рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдХрд╛рдо рдХрд┐рдпрд╛, рдореИрдВрдиреЗ рдЕрдкрдиреЗ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рдкрд╛рдпрд╛, рдореБрдЭреЗ рдкрд╛рдЗрдк рдХреЛ рд╕рд╛рдлрд╝ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕реЗ рдХреБрдЫ рдмрд╛рд░ рдЪрд▓рд╛рдирд╛ рд╣реЛрдЧрд╛ред рдЬрд┐рд╕рдХрд╛ рдЙрд▓реНрд▓реЗрдЦ @quasicomputational рдиреЗ рдЕрдкрдиреЗ рдЕрдиреНрд╡реЗрд╖рдг рдореЗрдВ рдпрд╣рд╛рдБ рдХрд┐рдпрд╛ рд╣реИ ред рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдореБрдЭреЗ рдирд╣реАрдВ рд▓рдЧрддрд╛ рдХрд┐ рдпрд╣ рдЬрд╛рдирдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рд╣реИ рдХрд┐ рдЬрдм рд╡рд╣ рдкрд╛рдЗрдк рд╡рд╛рджреЛрдВ рдХреЛ рдмрдирд╛рдП рдЬрд╛рдиреЗ рдХреЗ рджреМрд░рд╛рди рдЙрдиреНрд╣реЗрдВ рдмрд╛рдзрд┐рдд рдХрд┐рдП рдмрд┐рдирд╛ рд╕реНрдкрд╖реНрдЯ рд╣реЛрддрд╛ рд╣реИред рддреЛ рдореИрдВрдиреЗ рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЫреЛрдЯреА рд╕реА рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдмрдирд╛рдИ... рд╡рд╛рджрд╛-рдЬрд╛рд╕реВрд╕ ред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдореЗрд░реЗ рдкрд╛рд╕ рдПрдХ рдкрд░реАрдХреНрд╖рдг рдерд╛ рдЬреЛ рдирдХрд▓реА рдЯрд╛рдЗрдорд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рдерд╛ рдФрд░ рдпрд╣ рдЙрд╕рдХреЗ рд╕рд╛рде рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рдерд╛ ... рдЗрд╕рд▓рд┐рдП рдпрд╣ рдЕрднреА рддрдХ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рд╣реИред

рд╣рд╛рд▓рд╛рдВрдХрд┐ рдореИрдВ рдпрд╣ рднреА рдХрд▓реНрдкрдирд╛ рдХрд░рддрд╛ рд╣реВрдВ рдХрд┐ рд╡реЗ рдЖрдкрдХреЗ рдХреЛрдб рдореЗрдВ рдХреЗрд╡рд▓ async / await рд╕рд╛рде рдХрд╛рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрджрд┐ рд╡реЗ рд╡рд╛рджреЛрдВ рдХреЗ рд▓рд┐рдП рдкрд╛рд░рджрд░реНрд╢реА рд╣реИрдВред рдпрджрд┐ рдЙрдиреНрд╣реЗрдВ рд╡рд╛рджреЛрдВ рдкрд░ рдирд╣реАрдВ рдкрд╣реБрдБрдЪрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЙрдирдореЗрдВ рд╢рд╛рдорд┐рд▓ рдирд╣реАрдВ рд╣реЛ рдкрд╛рдПрдЧрд╛ рдФрд░ рдЙрдирдХреЗ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдирд╣реАрдВ рдХрд░ рдкрд╛рдПрдЧрд╛ред

рдореИрдВрдиреЗ рдЦреБрдж рдХреЛ рдпрд╣реА рдореБрджреНрджрд╛ рдкрд╛рдпрд╛ рдФрд░ рдореБрдЭреЗ рдПрд╣рд╕рд╛рд╕ рд╣реБрдЖ:
рд╣рдореЗрдВ рд▓рдВрдмрд┐рдд рд╡рд╛рджреЛрдВ рдХреЛ рдкреВрд░рд╛ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рдмрд▓реНрдХрд┐ рд▓рдВрдмрд┐рдд рд╡рд╛рджреЛрдВ рдХреЗ рд╣реЛрдиреЗ рдкрд░ рд╣рдореЗрдВ рдкреВрд░реА рдкрд░реАрдХреНрд╖рд╛ рд╡рд┐рдлрд▓ рдХрд░ рджреЗрдиреА рдЪрд╛рд╣рд┐рдПред
рдЗрд╕ рддрд░рд╣ рд╣рдо рдирд┐рд░рд╕реНрдд рдирд┐рдпрдВрддреНрд░рдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдП рдЧрдП рдХреЛрдб рдХреЗ рдЕрдВрджрд░ рд▓рдВрдмрд┐рдд рд╡рд╛рджреЛрдВ рдХреЛ рдирд┐рд░рд╕реНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рд╣реЛрдВрдЧреЗ:
https://developers.google.com/web/updates/2017/09/abortable-fetch
рдЬрд╕реНрдЯ рдлреНрд▓рд╢рд┐рдВрдЧ рд╡рд╛рджреЛрдВ рдХреЛ рдХрд╣рдиреЗ рдХреЗ рдмрд░рд╛рдмрд░ рд╣реИ "Concurrency рдХрдард┐рди рд╣реИ рддреЛ рдЪрд▓рд┐рдП рдЗрд╕рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ"ред рд╣рдХреАрдХрдд рдореЗрдВ рдпрд╣ рдмрд┐рд▓реНрдХреБрд▓ рд╡рд┐рдкрд░реАрдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред
рдЪреВрдВрдХрд┐ рд╕рдореЗрдХрди рдХрдард┐рди рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдЗрд╕рдХрд╛ рдФрд░ рднреА рдЕрдзрд┐рдХ рдкрд░реАрдХреНрд╖рдг рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рд▓рдВрдмрд┐рдд рд╡рд╛рджреЛрдВ рдХреЗ рд╕рд╛рде рдХрд┐рд╕реА рднреА рдкрд░реАрдХреНрд╖рд╛ рдХреЛ рдкрд╛рд╕ рдирд╣реАрдВ рд╣реЛрдиреЗ рджреЗрдирд╛ рдЪрд╛рд╣рд┐рдПред

рдЗрд╕ рд╕реНрдЯреИрдХ рдУрд╡рд░рдлреНрд▓реЛ рдкреНрд░рд╢реНрди рдкрд░ рд╡рд╛рджреЛрдВ рдХреЛ рд░рджреНрдж рдХрд░рдиреЗ рдХреА рдЧрдбрд╝рдмрдбрд╝реА рдХреЛ рджреЗрдЦрддреЗ рд╣реБрдП рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИ (YET) рдПрдХ рдЖрд╕рд╛рди рдХрд╛рдо рд╣реИ:
https://stackoverflow.com/a/53933849/373542
рдореИрдВ рдЕрдкрдиреЗ рдлрд╝реЗрдЪ рд╡рд╛рджреЛрдВ рдХреЛ рдирд┐рд░рд╕реНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ KISS рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд▓рд┐рдЦрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реВрдБ рдФрд░ рдпрд╣рд╛рдБ рдкрд░рд┐рдгрд╛рдо рдкреЛрд╕реНрдЯ рдХрд░реВрдБрдЧрд╛ред

@ giorgio-zamparelli: _ "Concurrency рдХрдард┐рди рд╣реИ рддреЛ рдЪрд▓рд┐рдП рдЗрд╕рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ"_ рдореВрд▓ рд░рд┐рдкреЛрд░реНрдЯ рдХреЗ рдмрд┐рдВрджреБ рдХреЗ рдмрд┐рд▓реНрдХреБрд▓ рдмрдЧрд▓ рдореЗрдВ рд╣реИред рдореБрджреНрджрд╛ _рд▓рдВрдмрд┐рдд_ рд╡рд╛рджреЛрдВ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдирд╣реАрдВ рд╣реИ, рдмрд▓реНрдХрд┐ рдЗрд╕ рддрдереНрдп рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реИ рдХрд┐ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ async рдХреЛрдб рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╡рд╛рджреЗ _resolution_ рдХреЗ рдкреНрд░рдЪрд╛рд░ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдирд╛ рдЕрдирд╛рд╡рд╢реНрдпрдХ рд░реВрдк рд╕реЗ рдХрдард┐рди рд╣реИред

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдлреНрд▓рд╢рд┐рдВрдЧ рд╡рд╛рджреЗ рдмреАрдорд╛рд░реА рдХреЗ рдмрдЬрд╛рдп рд▓рдХреНрд╖рдгреЛрдВ рдХреЛ рдареАрдХ рдХрд░ рджреЗрдВрдЧреЗред

рд╡рд╛рджреЛрдВ рдХреЛ рдмрд┐рдирд╛ рдлреНрд▓рд╢ рдХрд┐рдП рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рд╕рд╛рдорд╛рдиреНрдп рд░реВрдк рд╕реЗ рд╣рд▓ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдпрджрд┐ рдЖрдкрдХреЗ рдкрд░реАрдХреНрд╖рдг рдореЗрдВ рдХреЛрдИ рд▓рдВрдмрд┐рдд рд╡рд╛рджрд╛ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдпрд╛ рддреЛ рдЗрд╕рдХреЗ рд╕рдорд╛рдзрд╛рди рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреА рдЪрд╛рд╣рд┐рдП рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП wait рд╕реЗ @testing-library/react рдпрд╛ рдпрджрд┐ рд▓рдВрдмрд┐рдд рд╡рд╛рджрд╛ рдкрд░реАрдХреНрд╖рдг рдХреЗ рджрд╛рдпрд░реЗ рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рдирд╣реАрдВ рд╣реИ рддреЛ рдЖрдкрдХреЛ рдпрд╛ рддреЛ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдЗрд╕реЗ рд╢реБрд░реВ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдХреЛрдб рдХрд╛ рдордЬрд╛рдХ рдЙрдбрд╝рд╛рдПрдВ рдпрд╛ рдЖрдкрдХреЛ AbortController рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд░рд┐рдПрдХреНрдЯ рд╡рд┐рд▓рдЕрдирдорд╛рдЙрдВрдЯ рдЬреАрд╡рдирдЪрдХреНрд░ рдШрдЯрдирд╛ рдХреА рддрд░рд╣ рдХрд╣реАрдВ рднреА рд▓рдВрдмрд┐рдд рд╡рд╛рджреЗ рдХреЛ рд░рджреНрдж рдХрд░ рджреЗрдирд╛ рдЪрд╛рд╣рд┐рдП

рдПрдмреЙрд░реНрдЯрдХрдВрдЯреНрд░реЛрд▓рд░ рдПрдХ рдирдпрд╛ рдПрдкреАрдЖрдИ рд╣реИ рдЬрд┐рд╕рдХрд╛ рд▓рдЧрднрдЧ рдХреЛрдИ рднреА рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реИ рдФрд░ рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рдЕрдзрд┐рдХрд╛рдВрд╢ рд▓рдЯрдХреЗ рд╣реБрдП рд╡рд╛рджреЛрдВ рдХреЗ рд▓рд┐рдП рдпрд╣ рдареАрдХ рд╣реИред

рдореБрдЭреЗ рдЧрд▓рдд рд╕рд╛рдмрд┐рдд рдХрд░реЗрдВ:
рдореИрдВ рдЖрд╕рд╛рдиреА рд╕реЗ рдЧрд▓рдд рд╕рд╛рдмрд┐рдд рд╣реЛ рд╕рдХрддрд╛ рд╣реВрдВ рдЕрдЧрд░ рдХрд┐рд╕реА рдиреЗ рдЗрд╕ рдореБрджреНрджреЗ рдореЗрдВ рд▓рдВрдмрд┐рдд рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛ рд╣реЛрдиреЗ рдХреА рд╕реВрдЪрдирд╛ рджреА рд╣реИ рддреЛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА AbortController рдФрд░ jest.mock рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд┐рдпрд╛ рд╣реИ рдФрд░ рдпрд╣ рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рдерд╛ред

@ рдЬрд┐рдпреЛрд░реНрдЬрд┐рдпреЛ-рдЬрд╝рдореНрдкрд░реЗрд▓реА: рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдЧрд▓рддрдлрд╣рдореА рдореЗрд░реЗ рд╡рд╛рдХреНрдпрд╛рдВрд╢ _ "рдлреНрд▓рд╢ рд╕рднреА рд▓рдВрдмрд┐рдд рд╡рд╛рджреЗ рд╣реИрдВрдбрд▓рд░" рдХреЗ рдЙрдкрдпреЛрдЧ рд╕реЗ рдЙрддреНрдкрдиреНрди рд╣реЛрддреА рд╣реИ (рдФрд░ рдпрджрд┐ рдРрд╕рд╛ рд╣реЛрддрд╛ рд╣реИ, рддреЛ рдореБрдЭреЗ рдЦреЗрдж рд╣реИ)ред рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдЙрдореНрдореАрдж рд╕реЗ рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ рдХреНрдпрд╛ рдЖрдкрдиреЗ рд╕рдорд╕реНрдпрд╛ рд╡рд┐рд╡рд░рдг рдХреЛ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдкрдврд╝рд╛ рд╣реИ, рдореЗрд░рд╛ рдорддрд▓рдм рд╣реИ "рд╡рд╛рджреЛрдВ рдХреЗ рд▓рдВрдмрд┐рдд рд╣реИрдВрдбрд▓рд░"ред

рдЗрд╕рд▓рд┐рдП, рджреЛрд╣рд░рд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдпрд╣рд╛рдВ (рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕реЗ) _рд▓рдВрдмрд┐рдд_ рд╡рд╛рджреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдирд╣реАрдВ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдмрд▓реНрдХрд┐ рдиреНрдпреВрдирддрдо рдкрд░реЗрд╢рд╛рдиреА рдХреЗ рд╕рд╛рде рд╡рд╛рджрд╛ рд╕рдорд╛рдзрд╛рди рдХреЛ рдлреНрд▓рд╢ рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░ рд░рд╣реЗ рд╣реИрдВред рдпрд╛, рджреВрд╕рд░реЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ, рдЙрд╕ рдмрд┐рдВрджреБ рд╕реЗ рдкрд╛рд░рджрд░реНрд╢реА рдФрд░ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╣рд╛рдВ рдПрдХ рд╡рд╛рджрд╛ рдЙрд╕ рдмрд┐рдВрджреБ рддрдХ рд╣рд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ рдЬрд╣рд╛рдВ рдЙрд╕рдХреЗ рдмрд╛рдж рдХреЗ рд╕рднреА рдкреНрд░рднрд╛рд╡ рд▓рд╛рдЧреВ рд╣реЛрддреЗ рд╣реИрдВ (рддрд╛рдХрд┐ рд╣рдо рдЗрд╕рдХреЗ рдкрд░рд┐рдгрд╛рдо рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░ рд╕рдХреЗрдВ)ред

рдореИрдВрдиреЗ рд╣рд╛рд▓ рд╣реА рдореЗрдВ рдЗрд╕ рдЙрджреНрджреЗрд╢реНрдп рдХреЗ рд▓рд┐рдП flush-microtasks рдЬрд╛рд░реА рдХрд┐рдпрд╛ рд╣реИред рдпрд╣ рдЙрдзрд╛рд░ рд▓реЗрддрд╛ рд╣реИ рдЗрд╕рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕реЗ рд╣реИ, рдЬреЛ @jwbay рд╕реЗ рдЖрд╢реНрдЪрд░реНрдпрдЬрдирдХ рд░реВрдк рд╕реЗ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рд╣реИ рдХреЗ рд╕рдорд╛рдзрд╛рди рдпрд╣рд╛рдБ рдпрд╛ @thymikee рдХреЗ рд╕рдорд╛рдзрд╛рди рдпрд╣рд╛рдБ ред рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЬрдЯрд┐рд▓рддрд╛ рдХреЛрдИ рд╕рд╛рд░реНрдердХ рдЕрдВрддрд░ рдмрдирд╛рддреА рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдЗрд╕ рдзрд╛рдЧреЗ рдореЗрдВ рдЕрдиреНрдп рд╕рдорд╛рдзрд╛рдиреЛрдВ рджреНрд╡рд╛рд░рд╛ рд╡рд┐рдЪрд╛рд░ рдирд╣реАрдВ рдХрд┐рдП рдЧрдП рдХрд┐рдирд╛рд░реЗ рдХреЗ рдорд╛рдорд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИред рдореИрдВрдиреЗ рдХреЗрд╡рд▓ рдЙрд╕ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдХреНрдпреЛрдВрдХрд┐ react-testing-library рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ (рджреЗрдЦреЗрдВ рдпрд╣рд╛рдВ ), рд▓реЗрдХрд┐рди рдЗрд╕рдХрд╛ рдЦреБрд▓рд╛рд╕рд╛ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред

import { flushMicroTasks } from 'flush-microtasks'

await flushMicroTasks()

@aleclarson рдлреНрд▓рд╢-рдорд╛рдЗрдХреНрд░реЛрдЯрд╛рд╕реНрдХ рдФрд░ рдлреНрд▓рд╢-рд╡рд╛рджреЛрдВ рдХреЗ рдмреАрдЪ рдХреЛрдИ рдЕрдВрддрд░ рд╣реИ

@ramusus рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ flush-promises @jwbay рдХреЗ рд╕рдорд╛рдзрд╛рди рдХреЗ рд╕рдорд╛рди рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред

https://github.com/kentor/flush-promises/blob/46f58770b14fb74ce1ff27da00837c7e722b9d06/index.js

рдЖрд░рдЯреАрдПрд▓ рдиреЗ рд░рд┐рдПрдХреНрдЯ рдХрд╛ рдХреЛрдб рднреА рдХреЙрдкреА рдХрд┐рдпрд╛ рд╣реИ: https://github.com/testing-library/react-testing-library/blob/8db62fee6303d16e0d5c933ec1fab5841dd2109b/src/flush-microtasks.js

рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ: рд╣рд╛, рдкрд╣рд▓реЗ рд╣реА рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ: рдореБрд╕реНрдХреБрд░рд╛рддреЗ рд╣реБрдП:

рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЬрдм рд▓реЛрдЧ рдЗрд╕рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рддреЛ рд╣рдореЗрдВ рдЗрд╕реЗ рдЬреЗрд╕реНрдЯ рдореЗрдВ рдмрдирд╛рдиреЗ рдХреА рдЬрд╝рд░реВрд░рдд рд╣реИ? рд╢рд╛рдпрдж рд╣рдо рдЗрд╕реЗ рдбреЙрдХреНрд╕ рдореЗрдВ рд▓рд┐рдВрдХ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ? рдпрд╣ рдореБрджреНрджрд╛ рдЙрдиреНрд╣реЗрдВ рд╕рдордХрд╛рд▓рд┐рдХ рд░реВрдк рд╕реЗ рдлреНрд▓рд╢ рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИ, рдЬреЛ рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╣рдо рдЬреЛ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдЙрд╕рд╕реЗ рдкрд░реЗ рд╣реИ (рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ async-await рд╕рд╛рде рдЕрд╕рдВрднрд╡ рд╣реИ)

flushPromises рд╕рдорд╛рдзрд╛рди рдХреЗрд╡рд▓ рдЙрди рд╡рд╛рджреЛрдВ рдкрд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬреЛ рддреБрд░рдВрдд рд╣рд▓ рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВ рд▓реЗрдХрд┐рди рдЙрди рдкрд░ рдирд╣реАрдВ рдЬреЛ рдЕрднреА рднреА рд▓рдВрдмрд┐рдд рд╣реИрдВред

рд╣рдореНрдо, рдЕрдЪреНрдЫрд╛ рдмрд┐рдВрджреБред рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ рдХрд┐рд╕реА рддрд░рд╣ pending рд╡рд╛рджреЛрдВ рдХреЛ рдЯреНрд░реИрдХ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ рдпрд╛ рдирд╣реАрдВред async_hooks рд╕рд╛рде рдХреБрдЫ рдЪрддреБрд░ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдирд┐рд╢реНрдЪрд┐рдд рдирд╣реАрдВ рд╣реИред рд╕рдВрднрд╡рдд: рдпреВрдЬрд░рд▓реИрдВрдб рдХреЛрдб рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдП рдЧрдП рд╡рд╛рджреЛрдВ рдФрд░ рдЬреЗрд╕реНрдЯ рдФрд░ рдЙрд╕рдХреА рдирд┐рд░реНрднрд░рддрд╛ рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдП рдЧрдП рд╡рд╛рджреЛрдВ рдХреЗ рдмреАрдЪ рдЕрдВрддрд░ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рдирд╛ рджрд░реНрджрдирд╛рдХ рд╣реЛрдЧрд╛

рдореИрдВрдиреЗ рдХрд╛рдЙрдВрдЯрд░ рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП Promise рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рд▓рдкреЗрдЯрдиреЗ/рдирдХрд▓реА рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд┐рдпрд╛ рд╣реИ рд▓реЗрдХрд┐рди рдпрд╣ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ:

const _promise = window.Promise;
window.Promise = function(promiseFunction){
    // counter
    return new _promise(promiseFunction);
}

рдореБрдЦреНрдп рдореБрджреНрджрд╛ async рдлрд╝рдВрдХреНрд╢рдВрд╕ рд╣реИ рдЬреЛ рд╡реИрд╢реНрд╡рд┐рдХ Promise рдмрд┐рд▓реНрдХреБрд▓ рднреА рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ

рдареАрдХ рд╣реИ, рдореБрдЭреЗ рдЗрд╕ рддрд░рд╣ рдХрд╛ рдПрдХ рдмрд╣реБрдд рд╣реА рдЖрд╕рд╛рди рддрд░реАрдХрд╛ рдорд┐рд▓ рдЧрдпрд╛ рд╣реИред

  1. рд╕реВрдЪреА рдХреЗ рд╕рд╛рде рдПрдХ рдирдпрд╛ рдореЙрдбреНрдпреВрд▓ рдмрдирд╛рдПрдВред
  2. рдЙрд╕ рд╕реВрдЪреА рдореЗрдВ рдЕрдкрдиреЗ рд╡рд╛рджреЗ рдЬреЛрдбрд╝реЗрдВред
  3. рдЕрдкрдиреЗ рдкрд░реАрдХреНрд╖рдг рдореЗрдВ рд╡рд╛рджреЛрдВ рдХреЛ рд╣рд▓ рдХрд░реЗрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ рд╕реВрдЪреА рд╕реЗ рд╣рдЯрд╛ рджреЗрдВред
  4. рдореЗрд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдореИрдВ рдПрдВрдЬрд╛рдЗрдо рд╕реЗ wrapper.update() рдЪрд▓рд╛рддрд╛ рд╣реВрдВред рдЬрд░реВрд░рдд рдкрдбрд╝рдиреЗ рдкрд░ рдпрд╣рд╛рдВ рднреА рдХреБрдЫ рдРрд╕рд╛ рд╣реА рдХрд░реЗрдВред
  5. рдЪрд░рдг 3 рдФрд░ 4 рдХреЛ рддрдм рддрдХ рджреЛрд╣рд░рд╛рдПрдВ рдЬрдм рддрдХ рд╕реВрдЪреА рдЦрд╛рд▓реА рди рд╣реЛ рдЬрд╛рдПред

рдореБрдЭреЗ рдкрддрд╛ рд╣реИ, рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рдХреЛрдб рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд░рдирд╛ рдПрдХ рдЕрдЪреНрдЫрд╛ рдЕрднреНрдпрд╛рд╕ рдирд╣реАрдВ рд╣реИ рд▓реЗрдХрд┐рди рдореИрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╕рд░реНрд╡рд░ рд╕рд╛рдЗрдб рдкреНрд░рддрд┐рдкрд╛рджрди рдкрд░ рдЗрд╕ рддрд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВред рд▓реЗрдХрд┐рди рдЕрдВрдд рдореЗрдВ рдмрд╕ рдЗрдВрддрдЬрд╛рд░ рд╣реИред \_(уГД)_/┬п

рдЬреЗрд╕реНрдЯ 26 рдореЗрдВ рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рдЕрдкрдбреЗрдЯ рд╣реИ, рдЬрд╣рд╛рдВ рдирдХрд▓реА рдЯрд╛рдЗрдорд░ рдЕрдм @sinon/рдирдХрд▓реА-рдЯрд╛рдЗрдорд░ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИрдВ (рдпрджрд┐ jest.useFakeTimers('modern') рд╕рд╛рде рд╕рдХреНрд╖рдо рд╣реИ)ред

рдореИрдВрдиреЗ рдЕрдкрдиреЗ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рд╕рд╛рде рдЖрдзреБрдирд┐рдХ рдирдХрд▓реА рдЯрд╛рдЗрдорд░ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА, рдФрд░ рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ рдпрд╣ await new Promise(resolve => setImmediate(resolve)); рд╣реИрдХ рдХреЛ рдЕрдирд┐рд╢реНрдЪрд┐рдд рдХрд╛рд▓ рддрдХ рд▓рдЯрдХрд╛ рджреЗрддрд╛ рд╣реИред рд╕реМрднрд╛рдЧреНрдп рд╕реЗ, @sinon/fake-timers рдореЗрдВ рдХрдИ *Async() рд╡рд┐рдзрд┐рдпрд╛рдВ рд╢рд╛рдорд┐рд▓ рд╣реИрдВ рдЬреЛ "рдЗрд╡реЗрдВрдЯ рд▓реВрдк рдХреЛ рднреА рддреЛрдбрд╝ рджреЗрдВрдЧреА, рдЬрд┐рд╕рд╕реЗ рдХрд┐рд╕реА рднреА рдЕрдиреБрд╕реВрдЪрд┐рдд рд╡рд╛рджрд╛ рдХреЙрд▓рдмреИрдХ рдХреЛ рдЯрд╛рдЗрдорд░ рдЪрд▓рд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ _before_ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреА рдЗрдЬрд╛рдЬрдд рдорд┐рд▓рддреА рд╣реИред"ред рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдореБрдЭреЗ рдЬреЗрд╕реНрдЯ рдПрдкреАрдЖрдИ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ clock рдСрдмреНрдЬреЗрдХреНрдЯ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдирд╣реАрдВ рджрд┐рдЦ рд░рд╣рд╛ рд╣реИред

рдХрд┐рд╕реА рдХреЛ рдкрддрд╛ рд╣реИ рдХрд┐ рдЬреЗрд╕реНрдЯ рдХреЛ рд╣рдореЗрдВ рд╡рд╣ clock рд╡рд╕реНрддреБ рдХреИрд╕реЗ рджреА рдЬрд╛рдП?

рджреВрд╕рд░реЛрдВ рдХреА рддрд░рд╣, await new Promise(setImmediate); рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореЗрд░реА рдкреНрд░реЗрд░рдгрд╛ рд╕рдорд╛рдзрд╛рди рдпреЛрдЧреНрдп рд╡рд╛рджреЛрдВ рдХреЛ рдкреВрд░рд╛ рдХрд░рдирд╛ рд╣реИ, рддрд╛рдХрд┐ рдореИрдВ рд╕рд┐рд╕реНрдЯрдо рдкрд░ рдЙрдирдХреЗ рдкреНрд░рднрд╛рд╡ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░ рд╕рдХреВрдВред

рдРрд╕рд╛ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ рдХрд┐ "рдЖрдзреБрдирд┐рдХ" рдирдХрд▓реА рдЯрд╛рдЗрдорд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕рдордп-рд╕рдордп рдкрд░ рдирд┐рд░рд░реНрдердХ рд░реВрдк рд╕реЗ рджреВрд╕рд░реЛрдВ рдХреЛ рдХрдорддрд░ рдЖрдВрдХрддреЗ рд╣реИрдВред

рдЗрд╕рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╣рд╛рдВ рдХреБрдЫ рдпреВрдирд┐рдЯ рдкрд░реАрдХреНрд╖рдг рджрд┐рдП рдЧрдП рд╣реИрдВ:

describe('flushing of js-queues using different timers', () => {
  beforeAll(() => {
    // It would take the failing test 5 long seconds to time out.
    jest.setTimeout(100);
  });

  it.each([
    [
      'given real timers',
      () => {
        jest.useRealTimers();
      },
    ],
    ['given no timers', () => {}],
    [
      'given "legacy" fake timers',
      () => {
        jest.useFakeTimers('legacy');
      },
    ],
    [
      // This is the the failing scenario, not working like the other timers.
      'given "modern" fake timers',
      () => {
        jest.useFakeTimers('modern');
      },
    ],
  ])(
    '%s, when using setImmediate to flush, flushes a promise without timing out',
    async (_, initializeScenarioSpecificTimers) => {
      initializeScenarioSpecificTimers();

      let promiseIsFlushed = false;

      Promise.resolve().then(() => {
        promiseIsFlushed = true;
      });

      // Flush promises
      await new Promise(setImmediate);

      expect(promiseIsFlushed).toBe(true);
    },
  );
});

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдкрд┐рдЫрд▓рд╛ рдкрд░реАрдХреНрд╖рдг рд╡рд┐рдлрд▓ рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдЬреИрд╕рд╛ рдХрд┐ рд╣реЛрддрд╛ рд╣реИред

рдореЗрд░реЗ рд▓рд┐рдП рд╡рд░реНрдХрдЕрд░рд╛рдЙрдВрдб рд╡реИрд╢реНрд╡рд┐рдХ "рд╕реЗрдЯрдЗрдореАрдбрд┐рдПрдЯ" рдХреЗ рдмрдЬрд╛рдп рдкреИрдХреЗрдЬ "рдЯрд╛рдЗрдорд░" рд╕реЗ рдиреЛрдб-рджреЗрд╢реА "рд╕реЗрдЯрдЗрдореАрдбрд┐рдПрдЯ" рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╡рд╛рджреЛрдВ рдХреЛ рдлреНрд▓рд╢ рдХрд░рдирд╛ рдерд╛ред рдЗрд╕рдХреЗ рд╣реЛрдиреЗ рд╕реЗ, рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЧреБрдЬрд░рддрд╛ рд╣реИ:

import { setImmediate as flushMicroTasks } from 'timers';

it('given "modern" fake timers, when using native timers to flush, flushes a promise without timing out', async () => {
  jest.useFakeTimers('modern');

  let promiseIsFlushed = false;

  Promise.resolve().then(() => {
    promiseIsFlushed = true;
  });

  // Flush micro and macro -tasks
  await new Promise(flushMicroTasks);

  expect(promiseIsFlushed).toBe(true);
});

рдзрдиреНрдпрд╡рд╛рдж @aleclarsonред

рдпрд╣рд╛рдБ рдЗрд╕ рдореБрджреНрджреЗ рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░рд╛ рд╕рдорд╛рдзрд╛рди рд╣реИ:

https://github.com/team-igniter-from-houston-inc/async-fn
https://medium.com/houston-io/how-to-unit-test-asynchronous-code-for-javascript-in-2020-41c124be2552

рдЯреЗрд╕реНрдЯ рдХреЛрдб рдЗрд╕ рддрд░рд╣ рд▓рд┐рдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:

// Note: asyncFn(), extends jest.fn() with a way to control resolving/rejecting of a promise
const load = asyncFn();

const afterLoad = jest.fn();
const result = 'mock result';

mount(<Component load={load} afterLoad={afterLoad} />);

// ... some interaction that requires the `load`

// Note: New way to controlling when promise resolves
await load.resolve(result);

expect(afterLoad).toHaveBeenCalledWith(result);

рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдХреИрд╕реЗ рдЖрдкрдХреЛ рд╡рд╛рджреЛрдВ рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдпрд╛ рдЯрд╛рдЗрдорд░ рдЪрд▓рд╛рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рднреА рдЬрд╛рдирдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред

@ рдЬрдирд╕рд╡ рдЕрдЪреНрдЫрд╛/+1ред Fwiw рдореИрдВрдиреЗ рдЙрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЛ рджреЗрдЦрд╛ рд╣реИ рдЬрд┐рд╕реЗ рдЖрд╕реНрдердЧрд┐рдд рдкреИрдЯрд░реНрди рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдЕрдЪреНрдЫреЗ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рд▓рд┐рдП рдмрдирд╛рддрд╛ рд╣реИред

рдореБрдЭреЗ рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдирдХрд▓реА рдЯрд╛рдЗрдорд░ рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛ рдпрд╣ рд╣реИ рдХрд┐ рдпрд╣ рдкреНрд░рд╛рдХреГрддрд┐рдХ рд░рди-рд▓реВрдк рдХреЛ рддреЛрдбрд╝рддрд╛ рд╣реИ рдХрд┐ рдЯрд╛рдЗрдорд░ рдХреЛ рдХреИрд╕реЗ рдХрд╛рд░реНрдп рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рдореБрдЭреЗ рдЖрд╢реНрдЪрд░реНрдп рд╣реИ рдХрд┐ рд╣рдо рдХреЗрд╡рд▓ рдЬреЗрд╕реНрдЯ рдЯрд╛рдЗрдорд░ рд░рди рдлрд╝рдВрдХреНрд╢рди рдПрд╕рд┐рдВрдХреНрд╕ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ? рд╕рдордХрд╛рд▓рд┐рдХ рд░реВрдк рд╕реЗ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯрд╛рдЗрдорд░ рдмрджрд▓рдирд╛ рдкрд░реАрдХреНрд╖рдг рдХреЛрдб рдХреЛ рд╕рд╛рдл-рд╕реБрдерд░рд╛ рдмрдирд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдЗрд╕ рдмрдбрд╝реЗ рджреБрд╖реНрдкреНрд░рднрд╛рд╡ рдХрд╛ рдХрд╛рд░рдг рдмрдирддрд╛ рд╣реИред

рдореЗрд░рд╛ рдЙрдкрдпреЛрдЧрдХреЗрд╕:

public static resolvingPromise<T>(result: T, delay: number = 5): Promise<T> {
    return new Promise((resolve) => {
        setTimeout(
            () => {
                resolve(result);
            },
            delay
        );
    });
}

рдкрд░реАрдХреНрд╖рдг рдлрд╝рд╛рдЗрд▓:

it("accepts delay as second parameter", async () => {
    const spy = jest.fn();
    MockMiddleware.resolvingPromise({ mock: true }, 50).then(spy);
    jest.advanceTimersByTime(49);
    expect(spy).not.toHaveBeenCalled();
    jest.advanceTimersByTime(1);
    await Promise.resolve(); // without this line, this test won't pass
    expect(spy).toHaveBeenCalled();
});
рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

Antho2407 picture Antho2407  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

stephenlautier picture stephenlautier  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

paularmstrong picture paularmstrong  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

jardakotesovec picture jardakotesovec  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

rosiakr picture rosiakr  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ