context
Version:
Lightweight context propagation for JavaScript and TypeScript. Create a scoped storage object, run code inside it, and read the active value anywhere down the call stack - without depending on React.
105 lines (90 loc) • 3 kB
text/typescript
import { describe, it, expect, beforeEach } from 'vitest';
import { createContext, CtxApi } from '../context';
describe('Context', () => {
let ctx: CtxApi<any>;
beforeEach(() => {
ctx = createContext();
});
describe('Exposed Methods', () => {
it('should have a use method', () => {
expect(ctx.use).toBeInstanceOf(Function);
});
it('should have a run method', () => {
expect(ctx.run).toBeInstanceOf(Function);
});
});
describe('use', () => {
describe('When not inside of an active context', () => {
describe('When a default value was not provided', () => {
it('should return undefined', () => {
expect(ctx.use()).toBeUndefined();
});
});
describe('When a default value was provided', () => {
beforeEach(() => {
ctx = createContext('i am the default value!');
});
it('should return the default value', () => {
expect(ctx.use()).toBe('i am the default value!');
});
});
});
});
describe('useX', () => {
describe('When not inside of an active context', () => {
it('Should throw an error', () => {
expect(() => {
ctx.useX();
}).toThrow('Not inside of a running context.');
});
it('Should throw an error with a custom message when passed', () => {
expect(() => {
ctx.useX('i am the error message!');
}).toThrow('i am the error message!');
});
describe('When a default value was provided', () => {
beforeEach(() => {
ctx = createContext('i am the default value!');
});
it('Should disregard default value', () => {
expect(() => {
ctx.useX();
}).toThrow('Not inside of a running context.');
});
});
});
});
describe('run', () => {
describe('It should set the current context value to the passed value', () => {
it('should set the current context value to the passed value', () => {
const value = { some: 'object' };
ctx.run(value, () => {
expect(ctx.use()).toBe(value);
});
});
});
describe('When nesting run calls', () => {
it("sets each layer's context with its respective value", () => {
const value_a = { some: 'object' };
ctx.run(value_a, () => {
expect(ctx.use()).toBe(value_a);
const value_b = { another: 'obj' };
ctx.run(value_b, () => {
expect(ctx.use()).toBe(value_b);
});
});
});
it('Restores the previous context value when exiting a context layer', () => {
const value_a = { some: 'object' };
ctx.run(value_a, () => {
const value_b = { another: 'obj' };
ctx.run(value_b, () => {
expect(ctx.use()).toBe(value_b);
});
expect(ctx.use()).toBe(value_a);
});
expect(ctx.use()).toBeUndefined();
});
});
});
});