You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
6.8 KiB
TypeScript

import { expect } from 'chai';
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import { toString } from 'ramda';
import { arraySum, getArrayFromZeroOfLengthN, sleep, TimeUnit } from 'swiss-army-knifey';
import { combineReturns, composeWithPromise, simpleCombineReturns } from '../../src/utils/ramda';
chai.use(chaiAsPromised);
describe(`ramda style`, function() {
describe(`composeWithPromise(few functions)`, function() {
it('should await and return a composed result', async function() {
const paramToProp = (param: string) => ({ param });
const sleepingSentence = (s: number) => async ({ param }: { param: string }) => {
const d1 = new Date();
await sleep(s, TimeUnit.second);
const d2 = new Date();
return `a_[${param}], slept for: ${d2.getTime() - d1.getTime()}`;
};
const toUp = async (param: string) => param.toUpperCase();
const removeStart = async (param: string) => param.slice(1);
const composed = composeWithPromise(
removeStart,
sleepingSentence(1),
paramToProp,
toUp,
sleepingSentence(2),
paramToProp
);
return expect(composed('hey')).to.eventually.match(/_\[A_\[HEY\], SLEPT FOR: \d{4}\], slept for: \d{3,4}$/g);
});
it('should be able to compose non async functions', async function() {
const paramToProp = (param: string) => ({ param });
const toUp = (param: string) => param.toUpperCase();
const removeFirst = ({ param }: { param: string }) => param.slice(1);
const composed = composeWithPromise(
removeFirst,
paramToProp,
toUp,
toString
);
return expect(composed(3.14159)).to.equal('.14159');
});
it('should handle arrays of promises', async function() {
// [1, 2, 3] -> [Promise 1, Promise 4, Promise 9]
const asyncSquare = (ns: number[]) => {
return ns.map(async n => {
await sleep(1, TimeUnit.second);
return n * n;
})
};
// [1, 4, 9] -> [0, 6, 45]
const asyncSum = (ns: number[]) => {
return ns
// [1, 4, 9]
.map(getArrayFromZeroOfLengthN)
// [[0], [0, 1, 2, 3], [0, 1, 2, 3, 4, 5, 6, 7, 8]]
.map(async (arr: number[]) => {
await sleep(1, TimeUnit.second);
return arraySum(arr);
});
// [0, 6, 36]
};
const composed = composeWithPromise(
asyncSum,
asyncSquare,
);
return expect(composed([1, 2, 3])).to.eventually.deep.equal([0, 6, 36]);
});
it('should handle rejections', async function() {
// [1, 2, 3] -> [Promise 1, Promise 4, Promise 9]
const asyncSquare = (ns: number[]) => {
return ns.map(async n => {
await sleep(1, TimeUnit.second);
return n * n;
})
};
// [1, 4, 9] -> [0, 6, 45]
const asyncSum = (ns: number[]) => {
return ns
// [1, 4, 9]
.map(getArrayFromZeroOfLengthN)
// [[0], [0, 1, 2, 3], [0, 1, 2, 3, 4, 5, 6, 7, 8]]
.map(async (arr: number[]) => {
await sleep(1, TimeUnit.second);
throw new Error('Woho rejected promise');
});
// [0, 6, 36]
};
const composed = composeWithPromise(
asyncSum,
asyncSquare,
);
return expect(composed([1, 2, 3])).to.eventually.be.rejectedWith('Woho rejected promise');
});
});
describe('simpleCombineReturns', () => {
it('should combine results of promise-returning functions with sleep delay', async () => {
const fn1 = async (num: number) => {
await sleep(1, TimeUnit.second);
return { value1: num + 1 };
};
const fn2 = async (num: number) => {
await sleep(1, TimeUnit.second);
return { value2: num * 2 };
};
const startTime = Date.now();
const result = await simpleCombineReturns([fn1, fn2], 10);
const endTime = Date.now();
expect(result).to.deep.equal({ value1: 11, value2: 20 });
expect(endTime - startTime).to.be.greaterThan(1000); // Check that at least 1 second has passed
});
it('should combine results of functions taking string inputs', async () => {
const fn1 = async (str: string) => {
await sleep(1, TimeUnit.second);
return { upper: str.toUpperCase() };
};
const fn2 = async (str: string) => {
await sleep(1, TimeUnit.second);
return { length: str.length };
};
const result = await simpleCombineReturns([fn1, fn2], "test");
expect(result).to.deep.equal({ upper: "TEST", length: 4 });
});
it('should combine results of functions returning different types', async () => {
const fn1 = async (value: number) => {
await sleep(1, TimeUnit.second);
return { boolValue: value > 10 };
};
const fn2 = async (value: number) => {
await sleep(1, TimeUnit.second);
return { stringValue: `Value is ${value}` };
};
const result = await simpleCombineReturns([fn1, fn2], 15);
expect(result).to.deep.equal({ boolValue: true, stringValue: "Value is 15" });
});
});
describe('combineReturns', () => {
it('should combine results of curried promise-returning functions with sleep delay', async () => {
const fn1 = async (num: number) => {
await sleep(1, TimeUnit.second);
return { value1: num + 1 };
};
const fn2 = async (num: number) => {
await sleep(1, TimeUnit.second);
return { value2: num * 2 };
};
const combined = combineReturns([fn1, fn2]);
const startTime = Date.now();
const result = await combined(10);
const endTime = Date.now();
expect(result).to.deep.equal({ value1: 11, value2: 20 });
expect(endTime - startTime).to.be.greaterThan(1000); // Check that at least 1 second has passed
});
it('should combine results of curried functions taking string inputs', async () => {
const fn1 = async (str: string) => {
await sleep(1, TimeUnit.second);
return { upper: str.toUpperCase() };
};
const fn2 = async (str: string) => {
await sleep(1, TimeUnit.second);
return { length: str.length };
};
const combined = combineReturns([fn1, fn2]);
const result = await combined("test");
expect(result).to.deep.equal({ upper: "TEST", length: 4 });
});
it('should combine results of curried functions returning different types', async () => {
const fn1 = async (value: number) => {
await sleep(1, TimeUnit.second);
return { boolValue: value > 10 };
};
const fn2 = async (value: number) => {
await sleep(1, TimeUnit.second);
return { stringValue: `Value is ${value}` };
};
const combined = combineReturns([fn1, fn2]);
const result = await combined(15);
expect(result).to.deep.equal({ boolValue: true, stringValue: "Value is 15" });
});
});
});