add MockedD3.ts

This commit is contained in:
Ashley Engelund (weedySeaDragon @ github)
2022-10-15 19:14:56 -07:00
parent a26673c59a
commit d106d3d1b1

View File

@@ -0,0 +1,119 @@
/**
* This is a mocked/stubbed version of the d3 Selection type. Each of the main functions are all
* mocked (via vi.fn()) so you can track if they have been called, etc.
*/
export class MockedD3 {
public attribs = new Map<string, string | null>();
public id: string | undefined = '';
_children: MockedD3[] = [];
constructor(givenId = 'mock-id') {
this.id = givenId;
}
/** Helpful utility during development/debugging. This is not a real d3 function */
public listChildren(): string {
return this._children
.map((child) => {
return child.id;
})
.join(', ');
}
select = vi.fn().mockImplementation(({ select_str = '' }): MockedD3 => {
// Get the id from an argument string. if it is of the form [id='some-id'], strip off the
// surrounding id[..]
const stripSurroundRegexp = /\[id='(.*)'\]/;
const matchedSurrounds = select_str.match(stripSurroundRegexp);
const cleanId = matchedSurrounds ? matchedSurrounds[1] : select_str;
return new MockedD3(cleanId);
});
append = vi
.fn()
.mockImplementation(function (this: MockedD3, type: string, id = '' + '-appended'): MockedD3 {
const newMock = new MockedD3(id);
newMock.attribs.set('type', type);
this._children.push(newMock);
return newMock;
});
// NOTE: The d3 implementation allows for a selector ('beforeSelector' arg below).
// With this mocked implementation, we assume it will always refer to an node id
// and will always be of the form "#[id of the node to insert before]".
// To keep this simple, any leading '#' is removed and the resulting string is the node id searched.
insert = (type: string, beforeSelector?: string, id = this.id + '-inserted'): MockedD3 => {
const newMock = new MockedD3(id);
newMock.attribs.set('type', type);
if (beforeSelector === undefined) {
this._children.push(newMock);
} else {
const idOnly = beforeSelector[0] == '#' ? beforeSelector.substring(1) : beforeSelector;
const foundIndex = this._children.findIndex((child) => child.id === idOnly);
if (foundIndex < 0) this._children.push(newMock);
else this._children.splice(foundIndex, 0, newMock);
}
return newMock;
};
attr(attrName: string): null | undefined | string | number;
// attr(attrName: string, attrValue: string): MockedD3;
attr(attrName: string, attrValue?: string): null | undefined | string | number | MockedD3 {
if (arguments.length === 1) {
return this.attribs.get(attrName);
} else {
if (attrName === 'id') this.id = attrValue; // also set the id explicitly
if (attrValue !== undefined) this.attribs.set(attrName, attrValue);
return this;
}
}
public lower(attrValue = '') {
this.attribs.set('lower', attrValue);
return this;
}
public style(attrValue = '') {
this.attribs.set('style', attrValue);
return this;
}
public text(attrValue = '') {
this.attribs.set('text', attrValue);
return this;
}
// NOTE: Arbitrarily returns an empty object. The return value could be something different with a mockReturnValue() or mockImplementation()
public node = vi.fn().mockReturnValue({});
nodes = vi.fn().mockImplementation(function (this: MockedD3): MockedD3[] {
return this._children;
});
// This will try to use attrs that have been set.
getBBox = () => {
const x = this.attribs.has('x') ? this.attribs.get('x') : 20;
const y = this.attribs.has('y') ? this.attribs.get('y') : 30;
const width = this.attribs.has('width') ? this.attribs.get('width') : 140;
const height = this.attribs.has('height') ? this.attribs.get('height') : 250;
return {
x: x,
y: y,
width: width,
height: height,
};
};
// --------------------------------------------------------------------------------
// The following functions are here for completeness. They simply return a vi.fn()
insertBefore = vi.fn();
curveBasis = vi.fn();
curveBasisClosed = vi.fn();
curveBasisOpen = vi.fn();
curveLinear = vi.fn();
curveLinearClosed = vi.fn();
curveMonotoneX = vi.fn();
curveMonotoneY = vi.fn();
curveNatural = vi.fn();
curveStep = vi.fn();
curveStepAfter = vi.fn();
curveStepBefore = vi.fn();
}