import replaceStateWithRollback from 'bitbucket/internal/bbui/utils/replace-state-with-rollback';

const state = [1, 2, 3];
const forward = sinon.spy(() => [11, 2, 3]);
const back = sinon.spy(() => [1, 12, 3]);
const commit = sinon.spy(() => [1, 2, 13]);

QUnit.module('utils-replace-state-with-rollback', {
    beforeEach: function() {
        forward.reset();
        back.reset();
        commit.reset();
    },
});

QUnit.test('it optimistically applies an action', function(assert) {
    const action = {
        type: 'ACTION',
        meta: {
            isPending: true,
        },
    };

    const newState = replaceStateWithRollback(state, action, {
        forward,
        back,
        commit,
    });

    assert.deepEqual(newState, [11, 2, 3]);
    sinon.assert.calledOnce(forward);
    sinon.assert.notCalled(back);
    sinon.assert.notCalled(commit);
});

QUnit.test('it rolls back on error', function(assert) {
    const action = {
        type: 'ACTION',
        payload: {
            error: [],
        },
        meta: {
            isPending: false,
        },
    };

    const newState = replaceStateWithRollback(state, action, {
        forward,
        back,
        commit,
    });

    assert.deepEqual(newState, [1, 12, 3]);
    sinon.assert.notCalled(forward);
    sinon.assert.calledOnce(back);
    sinon.assert.calledWith(back, sinon.match([1, 2, 3]));
    sinon.assert.notCalled(commit);
});

QUnit.test('it commits on success', function(assert) {
    const action = {
        type: 'ACTION',
        payload: {
            something: true,
        },
        meta: {
            isPending: false,
        },
    };

    const newState = replaceStateWithRollback(state, action, {
        forward,
        back,
        commit,
    });

    assert.deepEqual(newState, [1, 2, 13]);
    sinon.assert.notCalled(forward);
    sinon.assert.notCalled(back);
    sinon.assert.calledOnce(commit);
});

QUnit.test('it ignores an inappropriate action', function(assert) {
    const action = {
        type: 'ACTION',
        payload: {
            something: true,
        },
    };

    const result = replaceStateWithRollback(state, action, {
        forward,
        back,
        commit,
    });

    assert.deepEqual(result, state);
    sinon.assert.notCalled(forward);
    sinon.assert.notCalled(back);
    sinon.assert.notCalled(commit);
});
