Skip to content

Commit

Permalink
chore: context
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexey Zorkaltsev committed Oct 20, 2023
1 parent 5b6fdef commit 309a716
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 7 deletions.
64 changes: 61 additions & 3 deletions src/__tests__/unit/utils/context.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,65 @@
import {Context, NOT_A_CONTEXT, setContextNewIdGenerator} from "../../../utils/context";

describe('utils.context', () => {
it('general', async () => {});
it('general', async () => {
const ctx1 = new Context();
expect(ctx1.id).toBeUndefined();
expect(ctx1.toString()).toBe('');

let n = 0;
setContextNewIdGenerator(() => n++);
setContextNewIdGenerator(() => ''); // 2nd assignment should be ignored
const ctx2 = new Context();
console.info(100, ctx2)
expect(ctx2.id).toBe(0);
const ctx3 = new Context();
expect(ctx3.id).toBe(1);

ctx3.do(() => {
const ctx = ctx3.findContextByClass<Context>(Context);
expect(ctx3).toBe(ctx);
});

const ctx4 = new Context(ctx3);
expect(ctx4.id).toBe(1);
expect(ctx4.toString()).toBe('1: ');
});

it('context-chain look up', async () => {
class A extends Context {}
class B extends Context {}
class C extends Context {}

const a = new A();

const b = new B(a);

expect(b.findContextByClass(A)).toBe(a);
expect(b.findContextByClass(B)).toBe(b);
expect(b.findContextByClass(C)).toBe(NOT_A_CONTEXT);
});

it('new id generator', async () => {});
it('done is invoked at the end of do()', async () => {
class A extends Context {
done = jest.fn();
}
const a = new A();
expect(await a.do(() => 123)).toBe(123);
expect(a.done.mock.calls).toEqual([[undefined]]);
const error = new Error('test');
await expect(a.do(() => {
throw error})).rejects.toThrow(error);
expect(a.done.mock.calls).toEqual([[undefined], [error]]);

it('context-chain look up', async () => {});
a.done.mockReset();
class B extends Context {
// without done
}
const b = new B(a);
expect(await b.do(() => 123)).toBe(123);
expect(a.done.mock.calls).toEqual([[undefined]]);
expect(b.do(() => {
throw error})).rejects.toThrow(error);
expect(a.done.mock.calls).toEqual([[undefined], [error]]);
});
});
13 changes: 9 additions & 4 deletions src/utils/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,27 @@ export class Context {
readonly id?: any;
readonly parent?: Context;

protected done?: (error?: Error) => void;
/**
* A non-required method that is called after the function, and allows you to collect the method
* run time and close spans for tracing.
*/
protected done?: (error?: any) => void;

constructor(parent?: Context) {
if (parent && parent !== NOT_A_CONTEXT) {
if (parent.id) {
if (parent.id !== undefined) {
this.id = parent.id;
}
this.parent = parent;
} else {
const id = newId();
if (id) {
if (id !== undefined) {
this.id = id;
}
}
}

async do<T>(func: () => T): T {
async do<T>(func: () => T): Promise<T> {
const prevContext = _context;
let error: any;
try {
Expand Down Expand Up @@ -79,6 +83,7 @@ export class Context {
* This is an object that does not contain any context, but allows to execute context.do().
*/
export const NOT_A_CONTEXT = Object.create(Context.prototype);
NOT_A_CONTEXT.id = 'NOT_A_CONTEXT';

/**
* The current context so that it can be retrieved via getConext().
Expand Down

0 comments on commit 309a716

Please sign in to comment.