core-native
Version:
A lightweight framework based on React Native + Redux + Redux Saga, in strict TypeScript.
157 lines (137 loc) • 5.64 kB
text/typescript
import {all, call, race} from "../src/typed-saga";
import {call as rawCall, delay, Effect} from "redux-saga/effects";
describe("typed-saga (functional test)", () => {
interface APIResponse {
foo: number;
}
async function fetchAPI(value: number): Promise<APIResponse> {
return {foo: value * 2};
}
test("typed saga call", () => {
function* saga() {
const apiResult = yield* call(fetchAPI, 50);
yield apiResult;
}
const sagaGenerator = saga();
const firstYield = sagaGenerator.next();
const callEffect = rawCall(fetchAPI, 50);
expect(firstYield.done).toBe(false);
expect(firstYield.value).toEqual(callEffect);
/**
* Must pass parameter to next() to mock the whole saga workflow
* Ref: https://redux-saga.js.org/docs/advanced/Testing.html
*/
const secondYield = sagaGenerator.next({foo: 100});
expect(secondYield.done).toBe(false);
expect(secondYield.value).toEqual({foo: 100});
const thirdYield = sagaGenerator.next();
expect(thirdYield.done).toBe(true);
expect(thirdYield.value).toBeUndefined();
});
});
describe("typed-saga (type test)", () => {
describe("race", () => {
test("should accept an object as parameter", () => {
race({});
race({d1: delay(1), d2: delay(2)});
function* testTyping() {
const {a, b, c, d, e} = yield* race({
a: call(async (_: number): Promise<number> => _, 1),
b: call(async (_: string): Promise<string> => _, "s"),
c: call(async (_: {foo: number; bar: string}): Promise<{baz: boolean}> => ({baz: true}), {foo: 0, bar: ""}),
d: delay(10),
e: Promise.resolve("a"),
});
const [_a, _b, _c, _d, _e]: [
// prettier-reserve
number | undefined,
string | undefined,
{baz: boolean} | undefined,
Effect | undefined,
string | undefined,
] = [a, b, c, d, e];
}
});
test("should accept an array as parameter", () => {
race([]);
race([delay(1), delay(2)]);
function* testTyping() {
const [a, b, c, d, e] = yield* race([
// prettier-reserve
call(async (_: number): Promise<number> => _, 1),
call(async (_: string): Promise<string> => _, "s"),
call(async (_: {foo: number; bar: string}): Promise<{baz: boolean}> => ({baz: true}), {foo: 0, bar: ""}),
delay(10),
Promise.resolve("a"),
]);
const [_a, _b, _c, _d, _e]: [
// prettier-reserve
number | undefined,
string | undefined,
{baz: boolean} | undefined,
Effect | undefined,
string | undefined,
] = [a, b, c, d, e];
}
});
test("should not accept any primitive values as parameter", () => {
// @ts-expect-error
race(undefined);
// @ts-expect-error
race(null);
// @ts-expect-error
race(1);
// @ts-expect-error
race(true);
// @ts-expect-error
race("string");
// @ts-expect-error
race(Symbol.for("symbol"));
});
});
describe("all", () => {
test("should accept an object as parameter", () => {
all({});
all({d1: delay(1), d2: delay(2)});
function* testTyping() {
const {a, b, c, d, e} = yield* all({
a: call(async (_: number): Promise<number> => _, 1),
b: call(async (_: string): Promise<string> => _, "s"),
c: call(async (_: {foo: number; bar: string}): Promise<{baz: boolean}> => ({baz: true}), {foo: 0, bar: ""}),
d: delay(10),
e: Promise.resolve("a"),
});
const [_a, _b, _c, _d, _e]: [number, string, {baz: boolean}, Effect, string] = [a, b, c, d, e];
}
});
test("should accept an array as parameter", () => {
all([]);
all([delay(1), delay(2)]);
function* testTyping() {
const [a, b, c, d, e] = yield* all([
// prettier-reserve
call(async (_: number): Promise<number> => _, 1),
call(async (_: string): Promise<string> => _, "s"),
call(async (_: {foo: number; bar: string}): Promise<{baz: boolean}> => ({baz: true}), {foo: 0, bar: ""}),
delay(10),
Promise.resolve("a"),
]);
const [_a, _b, _c, _d, _e]: [number, string, {baz: boolean}, Effect, string] = [a, b, c, d, e];
}
});
test("should not accept any primitive values as parameter", () => {
// @ts-expect-error
all(undefined);
// @ts-expect-error
all(null);
// @ts-expect-error
all(1);
// @ts-expect-error
all(true);
// @ts-expect-error
all("string");
// @ts-expect-error
all(Symbol.for("symbol"));
});
});
});