JSlang.dev

JavaScript Deep Dives with Wolfram. Since 2015
Inclusive, Test-Driven, Spec-Focused, Collaborative.

January 19, 2023
TestsSource
try-finally (without catch)

Source Code

The source code we wrote during the event.

import {strict as assert} from 'assert';

describe('Use try+finally without catch?', () => {
  it('using try+finally without catch is valid syntax', () => {
    assert.doesNotThrow(function() {
      eval(`
        try {}
        finally {}
      `);
    });
  });
  it('using try without catch+finally is invalid syntax', () => {
    assert.throws(function() {
      eval(`try{}`);
    }, SyntaxError);
  });
});

describe('execution order of try+finally', () => {
  it('try block is executed before finally block, if there is no exception thrown', () => {
    const executedBlocks = [];
    try {
      executedBlocks.push('try');
    } finally {
      executedBlocks.push('finally');
    }
    assert.deepEqual(executedBlocks, ['try', 'finally']);
  });
  it('finally block is also executed after the try block, when it throws', () => {
    const executedBlocks = []
    assert.throws(() => {
      try {
        executedBlocks.push('try');
        throw Error('an error');
      } finally {
        executedBlocks.push('finally');
      }
    })
    assert.deepEqual(executedBlocks, ['try', 'finally']);
  });
});

describe('What happens when a block returns?', () => {
  it('returns from inside a finally block, also when there is a return inside try block', () => {
    function functionThatReturnsFromTryAndFinally() {
      try {
        return 'returned from try';
      } finally {
        return 'returned from finally';
      }
    }
    assert.equal(functionThatReturnsFromTryAndFinally(), 'returned from finally');
  });
  it('returns from inside the try block, when there is no return inside the finally block', () => {
    function returnFromTry() {
      try {
        return 'from try';
      } finally {
        // do not return
      }
    }
    assert.equal(returnFromTry(), 'from try');
  });
  it('returns from inside the finally block, even when undefined is returned by it', () => {
    function returnsHopefully() {
      try {
        return 'from try';
      } finally {
        return undefined;
      }
    }
    assert.equal(returnsHopefully(), undefined);
  });
  it('returns throwing in the try block and returning in the finally block', () => {
    function fn() {
      try {
        throw 'in try';
      } finally {
        return 'from finally'
      }
    }
    assert.equal(fn(), 'from finally');
  });
});

describe('What happens when a block throws?', () => {
  it('throws even when there is a finally block that does not return or throw', () => {
    function fn() {
      try {
        throw 'in try';
      } finally {
        // do nothing
      }
    }
    assert.throws(fn);
  });
  it('throwing inside finally is what is returned, even when try throws', () => {
    class TryError extends Error {};
    class FinallyError extends Error {};
    function fn() {
      try {
        throw new TryError();
      } finally {
        throw new FinallyError();
      }
    }
    assert.throws(fn, FinallyError);
  });
});