Testing Graph Data Structure Operations in javascript-algorithms
This comprehensive test suite validates the Graph data structure implementation, covering both directed and undirected graph operations. The tests verify vertex and edge management, graph traversal, and matrix representations while ensuring proper handling of edge cases and graph modifications.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
trekhleb/javascript-algorithms
src/data-structures/graph/__test__/Graph.test.js
import Graph from '../Graph';
import GraphVertex from '../GraphVertex';
import GraphEdge from '../GraphEdge';
describe('Graph', () => {
it('should add vertices to graph', () => {
const graph = new Graph();
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
graph
.addVertex(vertexA)
.addVertex(vertexB);
expect(graph.toString()).toBe('A,B');
expect(graph.getVertexByKey(vertexA.getKey())).toEqual(vertexA);
expect(graph.getVertexByKey(vertexB.getKey())).toEqual(vertexB);
});
it('should add edges to undirected graph', () => {
const graph = new Graph();
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const edgeAB = new GraphEdge(vertexA, vertexB);
graph.addEdge(edgeAB);
expect(graph.getAllVertices().length).toBe(2);
expect(graph.getAllVertices()[0]).toEqual(vertexA);
expect(graph.getAllVertices()[1]).toEqual(vertexB);
const graphVertexA = graph.getVertexByKey(vertexA.getKey());
const graphVertexB = graph.getVertexByKey(vertexB.getKey());
expect(graph.toString()).toBe('A,B');
expect(graphVertexA).toBeDefined();
expect(graphVertexB).toBeDefined();
expect(graph.getVertexByKey('not existing')).toBeUndefined();
expect(graphVertexA.getNeighbors().length).toBe(1);
expect(graphVertexA.getNeighbors()[0]).toEqual(vertexB);
expect(graphVertexA.getNeighbors()[0]).toEqual(graphVertexB);
expect(graphVertexB.getNeighbors().length).toBe(1);
expect(graphVertexB.getNeighbors()[0]).toEqual(vertexA);
expect(graphVertexB.getNeighbors()[0]).toEqual(graphVertexA);
});
it('should add edges to directed graph', () => {
const graph = new Graph(true);
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const edgeAB = new GraphEdge(vertexA, vertexB);
graph.addEdge(edgeAB);
const graphVertexA = graph.getVertexByKey(vertexA.getKey());
const graphVertexB = graph.getVertexByKey(vertexB.getKey());
expect(graph.toString()).toBe('A,B');
expect(graphVertexA).toBeDefined();
expect(graphVertexB).toBeDefined();
expect(graphVertexA.getNeighbors().length).toBe(1);
expect(graphVertexA.getNeighbors()[0]).toEqual(vertexB);
expect(graphVertexA.getNeighbors()[0]).toEqual(graphVertexB);
expect(graphVertexB.getNeighbors().length).toBe(0);
});
it('should find edge by vertices in undirected graph', () => {
const graph = new Graph();
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const vertexC = new GraphVertex('C');
const edgeAB = new GraphEdge(vertexA, vertexB, 10);
graph.addEdge(edgeAB);
const graphEdgeAB = graph.findEdge(vertexA, vertexB);
const graphEdgeBA = graph.findEdge(vertexB, vertexA);
const graphEdgeAC = graph.findEdge(vertexA, vertexC);
const graphEdgeCA = graph.findEdge(vertexC, vertexA);
expect(graphEdgeAC).toBeNull();
expect(graphEdgeCA).toBeNull();
expect(graphEdgeAB).toEqual(edgeAB);
expect(graphEdgeBA).toEqual(edgeAB);
expect(graphEdgeAB.weight).toBe(10);
});
it('should find edge by vertices in directed graph', () => {
const graph = new Graph(true);
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const vertexC = new GraphVertex('C');
const edgeAB = new GraphEdge(vertexA, vertexB, 10);
graph.addEdge(edgeAB);
const graphEdgeAB = graph.findEdge(vertexA, vertexB);
const graphEdgeBA = graph.findEdge(vertexB, vertexA);
const graphEdgeAC = graph.findEdge(vertexA, vertexC);
const graphEdgeCA = graph.findEdge(vertexC, vertexA);
expect(graphEdgeAC).toBeNull();
expect(graphEdgeCA).toBeNull();
expect(graphEdgeBA).toBeNull();
expect(graphEdgeAB).toEqual(edgeAB);
expect(graphEdgeAB.weight).toBe(10);
});
it('should return vertex neighbors', () => {
const graph = new Graph(true);
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const vertexC = new GraphVertex('C');
const edgeAB = new GraphEdge(vertexA, vertexB);
const edgeAC = new GraphEdge(vertexA, vertexC);
graph
.addEdge(edgeAB)
.addEdge(edgeAC);
const neighbors = graph.getNeighbors(vertexA);
expect(neighbors.length).toBe(2);
expect(neighbors[0]).toEqual(vertexB);
expect(neighbors[1]).toEqual(vertexC);
});
it('should throw an error when trying to add edge twice', () => {
function addSameEdgeTwice() {
const graph = new Graph(true);
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const edgeAB = new GraphEdge(vertexA, vertexB);
graph
.addEdge(edgeAB)
.addEdge(edgeAB);
}
expect(addSameEdgeTwice).toThrow();
});
it('should return the list of all added edges', () => {
const graph = new Graph(true);
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const vertexC = new GraphVertex('C');
const edgeAB = new GraphEdge(vertexA, vertexB);
const edgeBC = new GraphEdge(vertexB, vertexC);
graph
.addEdge(edgeAB)
.addEdge(edgeBC);
const edges = graph.getAllEdges();
expect(edges.length).toBe(2);
expect(edges[0]).toEqual(edgeAB);
expect(edges[1]).toEqual(edgeBC);
});
it('should calculate total graph weight for default graph', () => {
const graph = new Graph();
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const vertexC = new GraphVertex('C');
const vertexD = new GraphVertex('D');
const edgeAB = new GraphEdge(vertexA, vertexB);
const edgeBC = new GraphEdge(vertexB, vertexC);
const edgeCD = new GraphEdge(vertexC, vertexD);
const edgeAD = new GraphEdge(vertexA, vertexD);
graph
.addEdge(edgeAB)
.addEdge(edgeBC)
.addEdge(edgeCD)
.addEdge(edgeAD);
expect(graph.getWeight()).toBe(0);
});
it('should calculate total graph weight for weighted graph', () => {
const graph = new Graph();
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const vertexC = new GraphVertex('C');
const vertexD = new GraphVertex('D');
const edgeAB = new GraphEdge(vertexA, vertexB, 1);
const edgeBC = new GraphEdge(vertexB, vertexC, 2);
const edgeCD = new GraphEdge(vertexC, vertexD, 3);
const edgeAD = new GraphEdge(vertexA, vertexD, 4);
graph
.addEdge(edgeAB)
.addEdge(edgeBC)
.addEdge(edgeCD)
.addEdge(edgeAD);
expect(graph.getWeight()).toBe(10);
});
it('should be possible to delete edges from graph', () => {
const graph = new Graph();
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const vertexC = new GraphVertex('C');
const edgeAB = new GraphEdge(vertexA, vertexB);
const edgeBC = new GraphEdge(vertexB, vertexC);
const edgeAC = new GraphEdge(vertexA, vertexC);
graph
.addEdge(edgeAB)
.addEdge(edgeBC)
.addEdge(edgeAC);
expect(graph.getAllEdges().length).toBe(3);
graph.deleteEdge(edgeAB);
expect(graph.getAllEdges().length).toBe(2);
expect(graph.getAllEdges()[0].getKey()).toBe(edgeBC.getKey());
expect(graph.getAllEdges()[1].getKey()).toBe(edgeAC.getKey());
});
it('should should throw an error when trying to delete not existing edge', () => {
function deleteNotExistingEdge() {
const graph = new Graph();
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const vertexC = new GraphVertex('C');
const edgeAB = new GraphEdge(vertexA, vertexB);
const edgeBC = new GraphEdge(vertexB, vertexC);
graph.addEdge(edgeAB);
graph.deleteEdge(edgeBC);
}
expect(deleteNotExistingEdge).toThrowError();
});
it('should be possible to reverse graph', () => {
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const vertexC = new GraphVertex('C');
const vertexD = new GraphVertex('D');
const edgeAB = new GraphEdge(vertexA, vertexB);
const edgeAC = new GraphEdge(vertexA, vertexC);
const edgeCD = new GraphEdge(vertexC, vertexD);
const graph = new Graph(true);
graph
.addEdge(edgeAB)
.addEdge(edgeAC)
.addEdge(edgeCD);
expect(graph.toString()).toBe('A,B,C,D');
expect(graph.getAllEdges().length).toBe(3);
expect(graph.getNeighbors(vertexA).length).toBe(2);
expect(graph.getNeighbors(vertexA)[0].getKey()).toBe(vertexB.getKey());
expect(graph.getNeighbors(vertexA)[1].getKey()).toBe(vertexC.getKey());
expect(graph.getNeighbors(vertexB).length).toBe(0);
expect(graph.getNeighbors(vertexC).length).toBe(1);
expect(graph.getNeighbors(vertexC)[0].getKey()).toBe(vertexD.getKey());
expect(graph.getNeighbors(vertexD).length).toBe(0);
graph.reverse();
expect(graph.toString()).toBe('A,B,C,D');
expect(graph.getAllEdges().length).toBe(3);
expect(graph.getNeighbors(vertexA).length).toBe(0);
expect(graph.getNeighbors(vertexB).length).toBe(1);
expect(graph.getNeighbors(vertexB)[0].getKey()).toBe(vertexA.getKey());
expect(graph.getNeighbors(vertexC).length).toBe(1);
expect(graph.getNeighbors(vertexC)[0].getKey()).toBe(vertexA.getKey());
expect(graph.getNeighbors(vertexD).length).toBe(1);
expect(graph.getNeighbors(vertexD)[0].getKey()).toBe(vertexC.getKey());
});
it('should return vertices indices', () => {
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const vertexC = new GraphVertex('C');
const vertexD = new GraphVertex('D');
const edgeAB = new GraphEdge(vertexA, vertexB);
const edgeBC = new GraphEdge(vertexB, vertexC);
const edgeCD = new GraphEdge(vertexC, vertexD);
const edgeBD = new GraphEdge(vertexB, vertexD);
const graph = new Graph();
graph
.addEdge(edgeAB)
.addEdge(edgeBC)
.addEdge(edgeCD)
.addEdge(edgeBD);
const verticesIndices = graph.getVerticesIndices();
expect(verticesIndices).toEqual({
A: 0,
B: 1,
C: 2,
D: 3,
});
});
it('should generate adjacency matrix for undirected graph', () => {
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const vertexC = new GraphVertex('C');
const vertexD = new GraphVertex('D');
const edgeAB = new GraphEdge(vertexA, vertexB);
const edgeBC = new GraphEdge(vertexB, vertexC);
const edgeCD = new GraphEdge(vertexC, vertexD);
const edgeBD = new GraphEdge(vertexB, vertexD);
const graph = new Graph();
graph
.addEdge(edgeAB)
.addEdge(edgeBC)
.addEdge(edgeCD)
.addEdge(edgeBD);
const adjacencyMatrix = graph.getAdjacencyMatrix();
expect(adjacencyMatrix).toEqual([
[Infinity, 0, Infinity, Infinity],
[0, Infinity, 0, 0],
[Infinity, 0, Infinity, 0],
[Infinity, 0, 0, Infinity],
]);
});
it('should generate adjacency matrix for directed graph', () => {
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const vertexC = new GraphVertex('C');
const vertexD = new GraphVertex('D');
const edgeAB = new GraphEdge(vertexA, vertexB, 2);
const edgeBC = new GraphEdge(vertexB, vertexC, 1);
const edgeCD = new GraphEdge(vertexC, vertexD, 5);
const edgeBD = new GraphEdge(vertexB, vertexD, 7);
const graph = new Graph(true);
graph
.addEdge(edgeAB)
.addEdge(edgeBC)
.addEdge(edgeCD)
.addEdge(edgeBD);
const adjacencyMatrix = graph.getAdjacencyMatrix();
expect(adjacencyMatrix).toEqual([
[Infinity, 2, Infinity, Infinity],
[Infinity, Infinity, 1, 7],
[Infinity, Infinity, Infinity, 5],
[Infinity, Infinity, Infinity, Infinity],
]);
});
});