Skip to content

Anti Features

Mason edited this page Jan 23, 2020 · 2 revisions

these are examples of feature ideas that will not be added, and the reasons why (including recommended alternatives)

Multiple Declaration Modes

The main reason for not wanting this is "Worse is Better". all these can be done using the features of your test framework of choice, so why should givens do it?

generally, the difficulty with having options for the given function is that when this function is called again for the same key, it is unclear if the same options object must be passed or not.

Particular examples of different types of declaration modes, and their correct versions:

NoCache

A variant of given(key, callback) which tells givens to use a resolution strategy which always reruns the topmost callback instead of using the cached value

There are two possible alternatives. The first is to not use givens at all. Instead just use a function and call it every time you need a value. The second (if you need overriding behavior) is to use the given function with a return type of function, and call that function when you want the non cached value.

// non-example, with noCache syntax borrowed from the given2 library
given('@nonCached', () => math.Random();

it('is random', () => {
    expect(given.nonCached).not.toEqual(given.nonCached);
});

// first
const nonCached = () => math.Random();

it('is random', () => {
    expect(nonCached()).not.toEqual(nonCached());
});

// second
given('nonCached', () => () => math.Random());

it('is random', () => {
    expect(given.nonCached()).not.toEqual(given.nonCached());
});

Immediate Evaluation

A variant of given(key, callback) which executes the callback before the test calls given.key. There are two options for when to execute the callback, both of which have flaws. the first is to do it immediately when the given function is called. This is a bad idea, because you shouldn't ever need to access the variable before the test (especially since beforeEach works perfectly fine to access givens before a test). The second option for when to execute is to create a beforeEach hook for evaluating and caching it. This is reasonable, but by the "worse is better" principle givens leaves the writing of this beforeEach function to the writer of the tests.

// non-example, with immediate syntax borrowed from the given2 library
let counter = 1;
given('!immediate', () => counter += 1);

it('should be 2', () => {
    expect(counter).toBe(2);
});

// how you should go about this if you need the value of the function
given('myObject', () => new myObject());
beforeEach(() => { const _ = given.myObject; };

it('can still be accessed', () => {
    const a = given.myObject;
});

// if you don't need the value of the function
beforeEach(() => new myObject());

it('cannot be accessed, but has run', () => {
    // you could check that mocked functions have been called by the constructor, for example.
});

Calling given() from inside a test

while this seems like it might be nice, this actually breaks predictability in some situations, for example:

given('a', () => 2);
given('b', () => 3 + given.a);

it('does weird stuff', () => {
    expect(given.b).toEqual(5);
    given('a', () => 4);
    expect(given.b).toEqual(/* 5 or 7? */);
});

when you update the value of a, the cached values become out of date, and therefore ambiguous as to whether or not the cache for all values dependent on b should cleared or not.

Clone this wiki locally