Sinon: κ°€μ§œ 타이머λ₯Ό μ‚¬μš©ν•  λ•Œ λ„€μ΄ν‹°λΈŒ ES6 약속을 해결해도 콜백이 νŠΈλ¦¬κ±°λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

에 λ§Œλ“  2015λ…„ 04μ›” 23일  Β·  30μ½”λ©˜νŠΈ  Β·  좜처: sinonjs/sinon

λ‹€μŒ ν…ŒμŠ€νŠΈμ—μ„œλŠ” ν™•μΈλœ 약속에 λŒ€ν•œ 콜백이 ν…ŒμŠ€νŠΈ λ‚΄μ—μ„œ 호좜될 κ²ƒμœΌλ‘œ μ˜ˆμƒν–ˆμŠ΅λ‹ˆλ‹€. λΆ„λͺ…νžˆ λ„€μ΄ν‹°λΈŒ PromiseλŠ” μ½œλ°±μ„ λ™κΈ°μ μœΌλ‘œ ν˜ΈμΆœν•˜μ§€ μ•Šμ§€λ§Œ setTimeout(callback, 0) 와 μœ μ‚¬ν•œ λ°©μ‹μœΌλ‘œ ν˜ΈμΆœλ˜λ„λ‘ μ˜ˆμ•½ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ μ‹€μ œλ‘œ setTimeout을 μ‚¬μš©ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ sinon의 κ°€μ§œ 타이머 κ΅¬ν˜„μ€ tick() λ₯Ό ν˜ΈμΆœν•  λ•Œ μ½œλ°±μ„ νŠΈλ¦¬κ±°ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

describe 'Promise', ->
  beforeEach ->
    <strong i="8">@clock</strong> = sinon.useFakeTimers()
  afterEach ->
    @clock.restore()
    console.log 'teardown'

  it "should invoke callback", ->
    p = new Promise (resolve, reject) ->
      console.log 'resolving'
      resolve(42)
      console.log 'resolved'
    p.then ->
      console.log 'callback'
    @clock.tick()
    console.log "test finished"

λ‚˜λŠ” 이 좜λ ₯을 κΈ°λŒ€ν•œλ‹€:

resolved
callback
test finished
teardown

λŒ€μ‹  λ‚˜λŠ” 이것을 μ–»λŠ”λ‹€ :

resolved
test finished
teardown
callback

μ½œλ°±μ€ ν…ŒμŠ€νŠΈκ°€ μ™„λ£Œλœ 후에 ν˜ΈμΆœλ˜λ―€λ‘œ 콜백 λ‚΄λΆ€μ—μ„œ λ°œμƒν•˜λŠ” 일에 κΈ°λ°˜ν•œ μ–΄μ„€μ…˜μ€ μ‹€νŒ¨ν•©λ‹ˆλ‹€.

then() λ₯Ό ν˜ΈμΆœν•˜κΈ° μ „μ΄λ‚˜ 후에 ν”„λΌλ―ΈμŠ€κ°€ ν•΄κ²°λ˜μ—ˆλŠ”μ§€ μ—¬λΆ€λŠ” 차이가 μ—†μŠ΅λ‹ˆλ‹€.

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

당신이 ν•„μš”λ‘œ ν•˜λŠ” μœ μΌν•œ 것은 약속 λ§ˆμ΄ν¬λ‘œνƒœμŠ€ν¬κ°€ 싀행될 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦¬λŠ” κ²ƒμž…λ‹ˆλ‹€.
λ”°λΌμ„œ λ‹€μŒ μ ‘κ·Ό 방식이 μ™„λ²½ν•˜κ²Œ μž‘λ™ν•©λ‹ˆλ‹€.

const tick = async (ms) => {
  clock.tick(ms);
};

it("imitates promise fulfill when called once", async () => {
    new Promise(resolve => setTimeout(resolve, 400)).then(callback);
    expect(callback.callCount).to.eql(0);

    await tick(200);
    expect(callback.callCount).to.eql(0);

    await tick(200);
    expect(callback.callCount).to.eql(1);
  });

λͺ¨λ“  30 λŒ“κΈ€

λ‚˜λŠ” λ˜ν•œμ΄ λ¬Έμ œμ— λΆ€λ”ͺμ³€λ‹€.

Promise 사양이 setTimeout λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³  ν˜„μž¬ μž‘μ—… 직후에 μˆ˜ν–‰λ  μƒˆ μž‘μ—…μ„ μ˜ˆμ•½ν•˜κΈ° λ•Œλ¬Έμ— 이것이 해결될 수 μ—†λ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

ν…ŒμŠ€νŠΈμ—μ„œ 약속을 λ°˜ν™˜ν•˜λ €κ³  ν–ˆμŠ΅λ‹ˆκΉŒ? λŒ€λΆ€λΆ„μ˜ ν…ŒμŠ€νŠΈ λΌμ΄λΈŒλŸ¬λ¦¬λŠ” ν˜„μž¬ Promiseλ₯Ό μ§€μ›ν•˜λ©° it() ν•¨μˆ˜κ°€ Promiseλ₯Ό λ°˜ν™˜ν•˜λ©΄ ν…ŒμŠ€νŠΈ μ‹€ν–‰μžλŠ” ν…ŒμŠ€νŠΈκ°€ μ™„λ£Œλ˜μ—ˆμŒμ„ μ•Œλ¦¬κΈ° 전에 Promiseκ°€ ν•΄κ²°λ˜κ±°λ‚˜ 거뢀될 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦½λ‹ˆλ‹€.

예, ν…ŒμŠ€νŠΈμ—μ„œ 약속을 λ°˜ν™˜ν•˜λ©΄ μ•„λ§ˆλ„ μž‘λ™ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ κ°€μ§œ 타이머λ₯Ό μ‚¬μš©ν•  λ•Œ ν…ŒμŠ€νŠΈ κΈ°λŠ₯μ—μ„œ λŒμ•„μ˜€κΈ° 전에 ν…ŒμŠ€νŠΈλ₯Ό μˆ˜ν–‰ν•  수 μžˆμ„ κ²ƒμœΌλ‘œ κΈ°λŒ€ν•©λ‹ˆλ‹€. 그것은 μΌμ’…μ˜ μš”μ μž…λ‹ˆλ‹€.

Date 객체가 κ΅μ²΄λ˜λŠ” κ²ƒμ²˜λŸΌ Promise 객체λ₯Ό κ΅μ²΄ν•˜λ©΄ 이것이 κ°€λŠ₯ν•˜λ‹€κ³  ν™•μ‹ ν•©λ‹ˆλ‹€. κ·Έλ ‡κ²Œ ν•˜λ €λ©΄ κΈ°λ³Έ κ΅¬ν˜„μ— μ˜μ‘΄ν•  수 μ—†κΈ° λ•Œλ¬Έμ— 약속 μ‚¬μ–‘μ˜ 경쟁 κ΅¬ν˜„μ΄ ν•„μš”ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” λ„ˆν¬λ“€μ΄ μ—¬κΈ°μ„œ μ§€μ ν•œ 문제λ₯Ό λ³Έλ‹€. κ·ΈλŸ¬λ‚˜ 약속 사양과 sinon λ¬Έμ„œλ₯Ό 기반으둜 ν•˜μ—¬ 이것이 "μž‘λ™ν•΄μ•Ό"ν•˜λŠ” κ²ƒμ²˜λŸΌ λ³΄μ˜€λ˜ νŠΉμ • 상황을 μ–ΈκΈ‰ν•˜κ³  μ‹Άμ—ˆμŠ΅λ‹ˆλ‹€. 이 경우 ν…ŒμŠ€νŠΈμ— 약속을 λ°˜ν™˜ν•˜μ§€λ§Œ κ°€μ§œ 타이머λ₯Ό μ‚¬μš©ν•˜λ©΄ 약속이 ν•΄κ²°λ˜μ§€ μ•ŠλŠ” κ²ƒμ²˜λŸΌ λ³΄μž…λ‹ˆλ‹€.

이 두 가지 ν…ŒμŠ€νŠΈκ°€ λͺ¨λ‘ μž‘λ™ν•΄μ•Ό ν•˜λŠ” 것 κ°™μ•˜μ§€λ§Œ 첫 번째 ν…ŒμŠ€νŠΈλŠ” ν†΅κ³Όν•˜κ³  두 번째 ν…ŒμŠ€νŠΈλŠ” μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€. λ‚˜λŠ” mocha와 ν•¨κ»˜ chai-as-promised ν”ŒλŸ¬κ·ΈμΈκ³Ό ν•¨κ»˜ chaiλ₯Ό μ‚¬μš©ν•˜κ³  μžˆλŠ”λ° "timeout of 2000msκ°€ μ΄ˆκ³Όλ˜μ—ˆμŠ΅λ‹ˆλ‹€. 이 ν…ŒμŠ€νŠΈμ—μ„œ done() 콜백이 호좜되고 μžˆλŠ”μ§€ ν™•μΈν•˜μ‹­μ‹œμ˜€."λΌλŠ” 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€.

describe('chai as promised', function() {

    it('should resolve a promise', function() {
        var promise = new Promise(function( resolve ) {
            setTimeout( resolve, 1000 );
        });
        return expect( promise ).to.have.been.fulfilled;
    });

});

describe('sinon.useFakeTimers()', function() {

    before(function() {
        this.clock = sinon.useFakeTimers();
    });

    after(function() {
        this.clock.restore();
    });

    it('should resolve a promise after ticking', function() {

        var promise = new Promise(function( resolve ) {
            setTimeout( resolve, 1000 );
        });

        this.clock.tick( 1001 );

        return expect( promise ).to.have.been.fulfilled;
    });

});

λΉ λ₯Έ ν…ŒμŠ€νŠΈ ν”„λ‘œμ νŠΈλ₯Ό μ€€λΉ„ν–ˆμŠ΅λ‹ˆλ‹€: https://github.com/JustinLivi/sinon-promises-test

ν…ŒμŠ€νŠΈκ°€ μ™„λ£Œλ˜κΈ° 전에 λ³΅μ›ν•˜λŠ” 것이 μ‹€ν–‰ κ°€λŠ₯ν•œ ν•΄κ²° 방법인 것 κ°™μŠ΅λ‹ˆλ‹€.

describe('sinon.useFakeTimers()', function() {

    before(function() {
        this.clock = sinon.useFakeTimers();
    });

    it('should resolve a promise after ticking', function() {

        var promise = new Promise(function( resolve ) {
            setTimeout( resolve, 1000 );
        });

        this.clock.tick( 1001 );
        this.clock.restore();

        return expect( promise ).to.have.been.fulfilled;
    });

});

μš°λ¦¬κ°€ μ‚¬μš©ν•˜λŠ” ν•΄κ²° 방법은 ν…ŒμŠ€νŠΈλ₯Ό μ‹€ν–‰ν•  λ•Œ κΈ°λ³Έ 약속 κ΅¬ν˜„μ„ setTimeout에 μ˜μ‘΄ν•˜λŠ” κ°„λ‹¨ν•œ κ²ƒμœΌλ‘œ λ°”κΎΈλŠ” κ²ƒμž…λ‹ˆλ‹€.

window.Promise = require('promise-polyfill')

Sinon.JSλŠ” useFakeTimersλ₯Ό ν˜ΈμΆœν•  λ•Œ κ°„λ‹¨νžˆ λ™μΌν•œ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

@JustinLivi κ°€ μ™„λ£Œλ˜κΈ° 전에 λ³΅μ›ν–ˆμŠ΅λ‹ˆλ‹€. +1:

κ·Έλž˜μ„œ, μ–΄λ–€ ν•΄κ²°μ±…μ΄λ‚˜ ν•΄κ²° 방법이 μžˆμŠ΅λ‹ˆκΉŒ?
λ‚΄ ν…ŒμŠ€νŠΈμ—μ„œ κ·Έλ ‡κ²Œ λ§ν–ˆκΈ° λ•Œλ¬Έμ— λ‚΄ 앱을 μˆ˜μ •ν•˜κ³  ES6 약속 μ‚¬μš©μ„ 쀑지할 수 μ—†μŠ΅λ‹ˆλ‹€. :)

κΈ°λ³Έ 약속이 μ•„λ‹ˆλΌ es6-promise 폴리필에 λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.
@JustinLivi 의 clock.restore() μ†”λ£¨μ…˜μ΄ 문제λ₯Ό ν•΄κ²°ν•©λ‹ˆλ‹€.

이 λ¬Έμ œκ°€ μ™œ μ—¬κΈ°μ—μ„œ μ˜€λž«λ™μ•ˆ 남아 μžˆλŠ”μ§€ λͺ¨λ₯΄κ² μ§€λ§Œ 이것은 Sinon의 λ¬Έμ œκ°€ μ•„λ‹™λ‹ˆλ‹€. Promiseλ₯Ό μ‚¬μš©ν•˜λŠ” 것은 본질적으둜 비동기 λ‘œμ§μ„ β€‹β€‹μˆ˜ν–‰ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. κ·Έλž˜λ„ μ—¬κΈ°μ˜ λͺ¨λ“  ν…ŒμŠ€νŠΈλŠ” 동기 논리λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€(OPκ°€ μ‹€μ œλ‘œ μ–ΈκΈ‰ν•œ λŒ€λ‘œ). λ”°λΌμ„œ μ‹œκ°„μ„ 속이더라도 μ—¬μ „νžˆ ν•¨μˆ˜κ°€ μ™„λ£Œλœ ν›„ μ‹€ν–‰ν•˜κΈ° μœ„ν•΄ Promise에 μ˜μ‘΄ν•˜κ³  μžˆμœΌλ―€λ‘œ ν…ŒμŠ€νŠΈλ₯Ό μ•½κ°„ λ³€κ²½ν•΄μ•Ό ν•©λ‹ˆλ‹€. 이것은 일반적으둜 λŒ€λΆ€λΆ„μ˜ ν…ŒμŠ€νŠΈ ν”„λ ˆμž„μ›Œν¬ λ¬Έμ„œμ—μ„œ λ‹€λ£¨μ§€λ§Œ( μ—¬κΈ°μ—λŠ” Mochaμ—μ„œ κ°€μ Έμ˜¨ κ²ƒμž…λ‹ˆλ‹€), λ‹€κ°€μ˜€λŠ” μƒˆ μ‚¬μ΄νŠΈμ—μ„œ ν…ŒμŠ€νŠΈ λ ˆμ‹œν”Όκ°€ ν¬ν•¨λœ 일뢀 기사λ₯Ό 톡해 이 문제λ₯Ό λ‹€λ£° κ²ƒμž…λ‹ˆλ‹€.

λ”°λΌμ„œ @JustinLivi 의 예제λ₯Ό μ•½κ°„ λ³€κ²½ν•˜λ©΄ λ‹€μŒ ν…ŒμŠ€νŠΈλ‘œ λλ‚©λ‹ˆλ‹€.

var sinon = require('sinon');

describe('sinon.useFakeTimers()', function() {

    before(function() {
        this.clock = sinon.useFakeTimers();
    });

    it('should resolve a promise after ticking', function(done) {

        var promise = new Promise(function( resolve ) {
            setTimeout( resolve, 10000 );
        });

        this.clock.tick( 10001 );

        promise
            .then(done) // call done when the promise completes
            .catch(done); // catch any accidental errors
    });

});

μ‹€μ œλ‘œ Mochaλ₯Ό μ‚¬μš©ν•˜λŠ” 경우 Promisesλ₯Ό μ‚¬μš©ν•  λ•Œ μœ„μ™€ λ™μΌν•œ μ½”λ“œμ˜ "λ°”λ‘œ κ°€κΈ°" 버전이 μžˆμŠ΅λ‹ˆλ‹€. Promiseλ₯Ό ν…ŒμŠ€νŠΈ ν”„λ ˆμž„μ›Œν¬μ— 직접 λ°˜ν™˜ν•˜κΈ°λ§Œ ν•˜λ©΄ λ©λ‹ˆλ‹€.

it('should resolve a promise after ticking', function() {
    var promise = new Promise(function( resolve ) {
        setTimeout( resolve, 10000 );
    });

    this.clock.tick( 10001 );

    return promise;
});

이것은

  1. Promise μƒμ„±μžμ— λ§€κ°œλ³€μˆ˜λ‘œ μ „μ†‘λœ executor ν•¨μˆ˜λ₯Ό λ™κΈ°μ μœΌλ‘œ μ‹€ν–‰ ν•˜μ—¬(ES2015 사양 μ°Έμ‘°) μƒˆ μ‹œκ°„ 초과λ₯Ό 효과적으둜 μ„€μ •ν•©λ‹ˆλ‹€.
  2. μƒμ„±λœ 약속을 λ°˜ν™˜ν•©λ‹ˆλ‹€.
  3. μ‹œκ°„μ„ μ²΄ν¬ν•˜μ„Έμš”.
  4. 약속이 ν•΄κ²°λœ κ²ƒμœΌλ‘œ ν‘œμ‹œν•˜μ—¬ μ‹œκ°„ 초과 κΈ°λŠ₯을 νŠΈλ¦¬κ±°ν•©λ‹ˆλ‹€.
  5. process (λ˜λŠ” λΈŒλΌμš°μ €)λŠ” μƒˆ "ν‹±"을 μŠ€νƒν•˜μ—¬ 약속을 ν•΄κ²°ν•˜κ³  λ‚˜λ¨Έμ§€ Thenables λ₯Ό ν˜ΈμΆœν•©λ‹ˆλ‹€.

버그가 μ•„λ‹Œ κ²ƒμœΌλ‘œ μ’…λ£Œν•©λ‹ˆλ‹€.

@fatso83 μ„€λͺ…ν•˜μ‹  λ°©μ‹μœΌλ‘œ ν…ŒμŠ€νŠΈλ₯Ό ν†΅κ³Όν•˜λŠ” 방법을 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€. ν…ŒμŠ€νŠΈ μ €μž₯μ†Œμ— 예제 ν…ŒμŠ€νŠΈλ₯Ό μΆ”κ°€ν–ˆλŠ”λ° μ—¬μ „νžˆ timeout of 2000ms exceeded. Ensure the done() callback is being called in this test. κ°€ ν‘œμ‹œλ©λ‹ˆλ‹€.

μ—¬κΈ°λ₯Ό μ°Έμ‘°ν•˜μ‹­μ‹œμ˜€: https://github.com/JustinLivi/sinon-promises-test/blob/master/test.js#L60
λ˜ν•œ λ‚΄κ°€ 말할 μˆ˜μžˆλŠ” ν•œμ΄ ν…ŒμŠ€νŠΈλŠ” μ—¬μ „νžˆ μ‹€νŒ¨ν•©λ‹ˆλ‹€. https://github.com/JustinLivi/Sinon.JS/commit/de106e6db2f5cc076b7e3a78635bd9ae2b6be1c2

νŽΈμ§‘: @fpirsch 의 μ˜κ²¬μ— λ”°λ₯΄λ©΄ es6 promise polyfill을 μ‚¬μš©ν•  λ•ŒμΈ 것 κ°™μŠ΅λ‹ˆλ‹€. λΈ”λ£¨λ²„λ“œμ™€ 같은 λŒ€μ²΄ 라이브러리λ₯Ό μ‚¬μš©ν•΄ λ³Έ μ‚¬λžŒμ΄ μžˆμŠ΅λ‹ˆκΉŒ?

@fatso83 이것은 return promise λ¬Έμ œκ°€ μ•„λ‹™λ‹ˆλ‹€.
제 κ²½μš°μ—λŠ” Phantom(ꡬ식, 약속 μ—†μŒ) + es6-promises polyfill + sinon.js λ¬Έμ œμž…λ‹ˆλ‹€. μ΅œμ‹  λΈŒλΌμš°μ €μ—μ„œλŠ” 약속이 ν•΄κ²°λ˜κ³  ν…ŒμŠ€νŠΈκ°€ 잘 μ‹€ν–‰λ˜μ§€λ§Œ 약속 폴리필을 μ‚¬μš©ν•˜λ©΄ 타이머가 κ°€μ§œμΌ λ•Œ 약속이 ν•΄κ²°λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

@JustinLivi 및 @fpirsch : 이 버그 λ³΄κ³ μ„œλŠ” _native_ Promise μ‚¬μš©μ— κ΄€ν•œ κ²ƒμž…λ‹ˆλ‹€. es6-promise λ₯Ό μ‚¬μš©ν•˜λŠ” @JustinLivi 의 ν…ŒμŠ€νŠΈ ν”„λ‘œμ νŠΈλ₯Ό λ³΄μ•˜μœΌλ―€λ‘œ 보증할 수 μ—†μŠ΅λ‹ˆλ‹€. λ‹€λ₯Έ 폴리필도 λ§ˆμ°¬κ°€μ§€μž…λ‹ˆλ‹€. 그건 또 λ‹€λ₯Έ λ¬Έμ œμž…λ‹ˆλ‹€. κΈ°λ³Έ 약속을 μ§€μ›ν•˜λŠ” λ…Έλ“œ 5 및 6으둜 이것을 ν…ŒμŠ€νŠΈν–ˆμŠ΅λ‹ˆλ‹€.

이전 κ²Œμ‹œλ¬Όμ˜ 예제 μ½”λ“œλ₯Ό λ³΅μ‚¬ν•˜μ—¬ λΆ™μ—¬λ„£κ³  μ‹€ν–‰(Mocha 및 Sinon 사전 μ„€μΉ˜):

$ pbpaste > test.js

$ mocha test.js

  sinon.useFakeTimers()
    βœ“ should resolve a promise after ticking

  1 passing (12ms)

@fpirsch : return promise 문제라고 λ§ν•œ 적이 μ—†μŠ΅λ‹ˆλ‹€. λ‚˜λŠ” κ·Έκ°€ ν…ŒμŠ€νŠΈλ₯Ό 더 짧은 ν˜•μ‹μœΌλ‘œ λ‹€μ‹œ μž‘μ„±ν•  수 μžˆλ‹€κ³  μ–ΈκΈ‰ν–ˆμŠ΅λ‹ˆλ‹€. μˆ˜μ •μ΄ μ•„λ‹ˆλΌ νŒμž…λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λͺ‡ 가지 κ·€μ€‘ν•œ 정보λ₯Ό μ œκ³΅ν–ˆμŠ΅λ‹ˆλ‹€. κΈ°λ³Έ λΈŒλΌμš°μ €μ—μ„œλŠ” μž‘λ™ν•˜μ§€λ§Œ 약속 ν΄λ¦¬ν•„μ—μ„œλŠ” μ‹€νŒ¨ν•©λ‹ˆλ‹€. 그것은 Sinon이 μ•„λ‹ˆλΌ λ‹Ήμ‹ μ˜ promise lib의 잘λͺ»μž…λ‹ˆλ‹€. κ·€ν•˜μ˜ 약속 λΌμ΄λΈŒλŸ¬λ¦¬λŠ” μ•„λ§ˆλ„ setTimeout 및 친ꡬλ₯Ό μΊμ‹œν•˜μ§€ μ•Šκ³  κΈ°λŠ₯에 μ˜μ‘΄ν•˜λ―€λ‘œ μ€‘λ‹¨λ©λ‹ˆλ‹€. pinkyswear libμ—μ„œ μ •ν™•νžˆ 이 문제λ₯Ό μˆ˜μ •ν•œ 적이 μžˆμœΌλ―€λ‘œ λ‹Ήμ—°ν•©λ‹ˆλ‹€.

es6-promise 의 μ†ŒμŠ€λ₯Ό ν™•μΈν–ˆκ³  setTimeout 에 λŒ€ν•œ μ°Έμ‘°λ₯Ό μΊμ‹œν•˜μ§€ μ•ŠμœΌλ―€λ‘œ sinon이 ν•˜λŠ” λͺ¨λ“  κ²ƒμ˜ 영ν–₯을 λ°›μŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λ‚˜λŠ” κ·Έ μŠ€μΌ€μ€„λŸ¬κ°€ μ—¬κΈ°μ—μ„œ μ–΄λ–»κ²Œ 관련이 μžˆλŠ”μ§€ μ•Œμ§€ λͺ»ν•©λ‹ˆλ‹€ ... λ˜ν•œ 폴리필이 νƒ€μž„μ•„μ›ƒ μŠ€μΌ€μ€„λŸ¬λ‘œ λŒμ•„κ°€κΈ° 전에 μ‹œλ„ν•  λ‹€λ₯Έ μ˜΅μ…˜μ˜ κ±°λŒ€ν•œ λͺ©λ‘μ΄ μžˆμŠ΅λ‹ˆλ‹€ . κ·Έ λŒ€μ²΄μ— μ°©λ₯™ν•˜λŠ” λͺ¨λ“  λΈŒλΌμš°μ €λŠ” κ³ λŒ€μ—¬μ•Ό ν•©λ‹ˆλ‹€. :)

κ·ΈλŸ¬λ‚˜ μ–΄μ¨Œλ“  @fpirsch 와 @JustinLivi κ°€ μ–ΈκΈ‰ν•œ 것은 Sinonκ³Ό 폴리필 κ°„μ˜ μƒν˜Έ μš΄μš©μ„±μ— κ΄€ν•œ λ¬Έμ œμž…λ‹ˆλ‹€. 그리고 그것은 또 λ‹€λ₯Έ λ¬Έμ œμž…λ‹ˆλ‹€. Sinon이 ATM에 λŒ€ν•΄ λ§Žμ€ 것을 ν•  수 μžˆλŠ” 방법을 μ•Œμ§€ λͺ»ν•˜μ§€λ§Œ(λͺ¨λ“  PR은 es6-polyfill 둜 끝날 κ°€λŠ₯성이 더 λ†’μŒ), 이것이 Sinon 문제인 경우 자유둭게 μƒˆ 문제λ₯Ό μ—¬μ‹­μ‹œμ˜€.

μΆ”μ‹ : @ropez 의 νŒμ€ promise-polyfill λ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμ΄μ—ˆμœΌλ©° μ΄λŠ” μ‹€μ œλ‘œ μ΅œμ†Œ 폴리필에 λŒ€ν•œ ꢌμž₯ 사항이기도 ν•˜μ§€λ§Œ 제곡된 것과 λ°˜λŒ€μ˜ μ΄μœ μž…λ‹ˆλ‹€. @mroderick 은 setTimeout 에 λŒ€ν•œ μ°Έμ‘°λ₯Ό μΊμ‹œν•˜κΈ° μœ„ν•΄ 1월에 ν•΄λ‹Ή ν”„λ‘œμ νŠΈλ₯Ό νŒ¨μΉ˜ν–ˆμŠ΅λ‹ˆλ‹€( @ropez 주석 ν›„ λͺ‡ κ°œμ›”). 그러면 약속이 _sinon이 무엇을 ν•˜κ³  μžˆλ“ _ κΈ€λ‘œλ²Œ setTimeout 참쑰둜 ν•΄κ²°λ©λ‹ˆλ‹€. μžμ„Έν•œ λ‚΄μš©μ€ taylorhakes/promise-polyfill#15λ₯Ό μ°Έμ‘°ν•˜μ„Έμš”.

@fatso83 정보 κ°μ‚¬ν•©λ‹ˆλ‹€. λΆˆν–‰νžˆλ„ @mroderick 이 promise-polyfill 에 λŒ€ν•΄ ν–ˆλ˜ κ²ƒμ²˜λŸΌ setTimeout 에 λŒ€ν•œ μ°Έμ‘°λ₯Ό μ €μž₯ν•˜λŠ” 것은 제 κ²½μš°μ—λŠ” μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. es6-promise λ₯Ό promise-polyfill 둜 바꾸지 μ•ŠμŠ΅λ‹ˆλ‹€. :-(
νŽΈμ§‘: λ‹¨μˆœν•œ νŒ¬ν…€+λͺ¨μΉ΄ μŠ€νƒμ—μ„œλŠ” μˆ˜ν–‰λ˜μ§€λ§Œ μΉ΄λ₯΄λ§ˆκ°€ μžˆλŠ” 전체 μŠ€νƒμ—μ„œλŠ” μˆ˜ν–‰λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ„ˆλ¬΄ ν”Όκ³€ν•©λ‹ˆλ‹€.

@fatso83 여기에 예λ₯Ό λ“€κ² μŠ΅λ‹ˆλ‹€: faketimers
κ²°κ΅­ Karma에 λ¬Έμ œκ°€ μžˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€. 이 λ¬Έμ œμ— λŒ€ν•΄ 더 깊이 νŒŒκ³ λ“€λ„λ‘ λ…Έλ ₯ν•˜κ² μŠ΅λ‹ˆλ‹€.

@fpirsch : λ­”κ°€ ν•˜κ³  μžˆλŠ” 것 κ°™μ•„μš”. λ‹Ήμ‹ κ³Ό @JustinLivi λͺ¨λ‘ μΉ΄λ₯΄λ§ˆλ₯Ό ν…ŒμŠ€νŠΈ λŸ¬λ„ˆλ‘œ μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 그듀은 맀우 λΉ„μŠ·ν•΄ λ³΄μž…λ‹ˆλ‹€. μΆ”μ‹ : Justin이 문제λ₯Ό λ³΄μ—¬μ£ΌλŠ” ν…ŒμŠ€νŠΈ 사둀λ₯Ό 이미 μ œκ³΅ν–ˆκΈ° λ•Œλ¬Έμ— μ™„μ „νžˆ λΆˆν•„μš”ν•˜λ‹€κ³  μƒκ°ν•˜μ—¬ λ‚΄ μ˜κ²¬μ„ μ‚­μ œν–ˆμ§€λ§Œ κ·€ν•˜μ˜ 예제 ν”„λ‘œμ νŠΈλŠ” 이것이 Karma μΌμ΄λΌλŠ” 가섀을 κ°•ν™”ν•©λ‹ˆλ‹€. κ°μ‚¬ν•©λ‹ˆλ‹€!

이것은 관련이 μžˆμ„ 수 μžˆμ§€λ§Œ ν™•μ‹€ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ•„λž˜μ˜ μ„Έ 번째 ν…ŒμŠ€νŠΈκ°€ μ‹€νŒ¨ν•˜λŠ” μ΄μœ λŠ” λ¬΄μ—‡μž…λ‹ˆκΉŒ? νŠΉμ • μ‹€νŒ¨λŠ” 일반적인 ν…ŒμŠ€νŠΈ μ‹œκ°„ μ΄ˆκ³Όμž…λ‹ˆλ‹€.

     Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.
describe.only('working', () => {
  let clock;
  beforeEach(() => { clock = Sinon.useFakeTimers(); })
  afterEach(() => { clock.restore() })

  const delay = (ms) => (
    new Promise((resolve/* , reject */) => {
      setTimeout(resolve, ms)
    })
  );

  it('1 OK', () => {
    const promise = new Promise((resolve) => {
      setTimeout(resolve, 100)
    })
    clock.tick(200)
    return promise
  })

  it('2 OK', () => {
    const promise = delay(100)
    clock.tick(200)
    return promise
  })

  it('3 FAIL', () => {
    const promise = delay(50).then(() => delay(50))
    clock.tick(200)
    return promise
  })
})

@jasonkuhrt μ„Έ 번째 ν…ŒμŠ€νŠΈλŠ” clock.tick 이 μ‹€ν–‰κΈ°λ₯Ό λ™κΈ°μ μœΌλ‘œ μ²˜λ¦¬ν•˜λ―€λ‘œ 비동기 νŠΉμ„± 으둜 인해 .then(...) κ°€ μ‹€ν–‰λ˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μ‹€νŒ¨ν•©λ‹ˆλ‹€.

onFulfilled λ˜λŠ” onRejectedλŠ” μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ μŠ€νƒμ— ν”Œλž«νΌ μ½”λ“œλ§Œ 포함될 λ•ŒκΉŒμ§€ ν˜ΈμΆœλ˜μ§€ μ•Šμ•„μ•Ό ν•©λ‹ˆλ‹€.

@fatso83 타이머 λ₯Ό μΆ”κ°€ν•˜λŠ” 체인 ν”„λΌλ―ΈμŠ€μ— λŒ€ν•œ λ‘€λ ‰μŠ€ 개발자의 μž…μž₯을 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€. ν˜„μž¬ μ œν•œ 사항은 μ΅œμ†Œν•œ λ¬Έμ„œμ— μžμ„Ένžˆ λ‚˜μ™€ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€.

이것이 μ§€μ›λ˜μ–΄μ•Ό ν•˜λŠ”μ§€ 여뢀에 따라 이 λ¬Έμ œλŠ” λ‹€μ‹œ 열릴 수 있고(λ˜λŠ” μƒˆ λ¬Έμ œκ°€ 열릴 수 있음) lolex 의 μƒˆ λ¬Έμ œμ— 쒅속될 수 μžˆμŠ΅λ‹ˆλ‹€.
λ˜ν•œ 이 μ‚¬μš© 사둀(타이머λ₯Ό μΆ”κ°€ν•˜λŠ” μ—°κ²° 약속)λ₯Ό κ³ λ €ν•΄μ•Ό ν•˜λŠ” 경우, 이둜 인해 lolex API μˆ˜μ •μ΄ 쀑단될 수 μžˆμŠ΅λ‹ˆλ‹€(AFAIK clock.tick 은 비동기식이어야 함).

@gautaz μ•„ 이제 이해가 λ©λ‹ˆλ‹€. μ„€λͺ…ν•΄μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€!

lolex λŠ” 동기화 라이브러리이고 @jasonkuhrt 의 문제λ₯Ό μ–΄λ–»κ²Œ ν•΄κ²°ν•΄μ•Ό 할지 μ™„μ „νžˆ λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€. 자유둭게 PR을 μ œκ³΅ν•  수 μžˆμ§€λ§Œ clock.tick λ₯Ό μˆ˜μ •ν•˜λŠ” 것은 그닀지 맀λ ₯적이지 μ•ŠμŠ΅λ‹ˆλ‹€. 차라리 μΆ”κ°€ 비동기 방법을보고 μ‹ΆμŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” 약속과 μ‹œκ³„ λ˜‘λ”±κ³Ό κ΄€λ ¨ν•˜μ—¬ λ§Žμ€ λ¬Έμ œκ°€ μ—†μ—ˆμ§€λ§Œ μ•„λ§ˆλ„ 그것이 동기식이고 κ·Έ 사이에 μΆ”κ°€ μ‹œκ³„ 틱을 μΆ”κ°€ν•œ 것을 λ³΄μ•˜κΈ° λ•Œλ¬ΈμΌ κ²ƒμž…λ‹ˆλ‹€.

@fatso83 λ§žμŠ΅λ‹ˆλ‹€ . 비동기 tick λ₯Ό μΆ”κ°€ν•˜λ©΄ 덜 λ°©ν•΄κ°€ λ©λ‹ˆλ‹€(사싀 μ „ν˜€ λ°©ν•΄κ°€ λ˜μ§€ μ•ŠμŒ).
λ”°λΌμ„œ asyncTick 와 같은 것이 적합할 수 μžˆμŠ΅λ‹ˆλ‹€. μ‹œκ°„μ΄ 되면 μ‘°μ‚¬ν•˜κ² μŠ΅λ‹ˆλ‹€.

@gautaz lolex 에 패치λ₯Ό μ œκ³΅ν•  κΈ°νšŒκ°€ μžˆμ—ˆλŠ”μ§€ κΆκΈˆν•©λ‹ˆλ‹€.

@fatso83 μ•ˆλ…•ν•˜μ„Έμš”, μ €λŠ” μž‘λ…„μ— 제 μ˜†μ—μ„œ 지점을 μ‹œμž‘ν–ˆμ§€λ§Œ μ§€κΈˆμ€ κ·Έ 일을 끝낼 μ‹œκ°„μ΄ μ—†μŠ΅λ‹ˆλ‹€.
λ‚˜μ—κ²Œλ„ 같은 문제둜 κ±Έλ € λ„˜μ–΄μ§„ λ™λ£Œκ°€ μžˆμœΌλ―€λ‘œ λ¬Έμ œκ°€ λ‚˜μ—κ²Œ μΆ”κ°€ μ‹œκ°„μ„ μ œκ³΅ν•  만큼 μΆ©λΆ„νžˆ 컀지기λ₯Ό λ°”λž„ λΏμž…λ‹ˆλ‹€.

κ·Έ λ™μ•ˆ 이 νŠΉμ • μ§€μ μ—μ„œ lolex API와 κ΄€λ ¨ν•˜μ—¬ λ³€κ²½ 사항이 μžˆμŠ΅λ‹ˆκΉŒ?

그것은 μ—†μ–΄μ•Όν•©λ‹ˆλ‹€. μ§€λ‚œ λ°˜λ…„ λ™μ•ˆ μ½”λ“œλ² μ΄μŠ€μ— 거의 λ³€ν™”κ°€ μ—†μ—ˆμŠ΅λ‹ˆλ‹€. κ½€ μ•ˆμ •μ μž…λ‹ˆλ‹€.

여기에 κ°„λ‹¨ν•œ ν•΄κ²° 방법이 μžˆμŠ΅λ‹ˆκΉŒ? 같은 λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€. 두 가지 약속이 있으며 setTimeout으둜 ν•΄κ²°λ©λ‹ˆλ‹€. ν•΄κ²° μ „, 두 번째 ν•΄κ²° μ „, 첫 번째 ν•΄κ²° ν›„, λͺ¨λ“  ν•΄κ²° ν›„ ν•­λͺ©μ„ 확인해야 ν•©λ‹ˆλ‹€.

당신이 ν•„μš”λ‘œ ν•˜λŠ” μœ μΌν•œ 것은 약속 λ§ˆμ΄ν¬λ‘œνƒœμŠ€ν¬κ°€ 싀행될 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦¬λŠ” κ²ƒμž…λ‹ˆλ‹€.
λ”°λΌμ„œ λ‹€μŒ μ ‘κ·Ό 방식이 μ™„λ²½ν•˜κ²Œ μž‘λ™ν•©λ‹ˆλ‹€.

const tick = async (ms) => {
  clock.tick(ms);
};

it("imitates promise fulfill when called once", async () => {
    new Promise(resolve => setTimeout(resolve, 400)).then(callback);
    expect(callback.callCount).to.eql(0);

    await tick(200);
    expect(callback.callCount).to.eql(0);

    await tick(200);
    expect(callback.callCount).to.eql(1);
  });

@jakwuh 의 νŠΈλ¦­μ€ then 콜백이 틱에 μ˜ν•΄ μ—°κΈ°λ˜μ—ˆλ‹€λŠ” 점을 μ œμ™Έν•˜κ³  μ €μ—κ²Œ νš¨κ³Όμ μ΄μ—ˆμŠ΅λ‹ˆλ‹€(λ…Έλ“œ 8, 트랜슀파일 μ—†μŒ, κΈ°λ³Έ 약속).

μ—…λ°μ΄νŠΈλœ 의견 : λ‚΄ μ›λž˜ 의견(μ•„λž˜)의 μ†”λ£¨μ…˜μ— λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€. λ•Œλ‘œλŠ” μ‹€μ œλ‘œ λͺ¨λ“  것을 ν”ŒλŸ¬μ‹œν•˜κΈ° μœ„ν•΄ μ—¬λŸ¬ 개의 연속적인 await Promise.resolve() 호좜이 ν•„μš”ν–ˆμŠ΅λ‹ˆλ‹€. λ‹€μŒμ€ 쑰금 더 잘 μž‘λ™ν•˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

beforeEach(function() {
    const originalSetImmediate = setImmediate;
    this.clock = sinon.useFakeTimers();
    this.tickAsync = async ms => {
        this.clock.tick(ms);
        await new Promise(resolve => originalSetImmediate(resolve));
    }
});

afterEach(function() {
    this.clock.restore();
});

μ›λž˜ 주석 [κ²½κ³ : μœ„μ˜ μ½”λ“œμ²˜λŸΌ μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.]

tick λ„μš°λ―Έμ— 비동기 간격을 μΆ”κ°€ν•˜λ©΄ λ¬Έμ œκ°€ ν•΄κ²°λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

```js
const ν‹± = 비동기(ms) => {
clock.tick(ms);
Promise.resolve()λ₯Ό κΈ°λ‹€λ¦½λ‹ˆλ‹€.
};

이 μ˜μ—­μ—μ„œ Sinon을 κ°œμ„ ν•˜λŠ” μž‘μ—…(μ‹€μ œλ‘œλŠ” ν˜•μ œ ν”„λ‘œμ νŠΈ lolex )에 관심이 μžˆλŠ” μ‚¬λžŒλ“€μ€ μ—¬κΈ°μ—μ„œ 토둠을 ν™•μΈν•˜μ‹­μ‹œμ˜€.

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰