Upgrade dependencies and fix ESLint issues.

This commit is contained in:
Oleksii Trekhleb
2020-07-26 13:06:15 +02:00
parent 4d8baf87db
commit 63f5a27152
36 changed files with 4442 additions and 1630 deletions

5961
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -35,15 +35,15 @@
"devDependencies": { "devDependencies": {
"@babel/cli": "^7.10.5", "@babel/cli": "^7.10.5",
"@babel/preset-env": "^7.10.4", "@babel/preset-env": "^7.10.4",
"@types/jest": "^24.9.1", "@types/jest": "^26.0.7",
"eslint": "^6.8.0", "eslint": "^7.5.0",
"eslint-config-airbnb": "^17.1.1", "eslint-config-airbnb": "^18.2.0",
"eslint-plugin-import": "^2.22.0", "eslint-plugin-import": "^2.22.0",
"eslint-plugin-jest": "^22.21.0", "eslint-plugin-jest": "^23.18.2",
"eslint-plugin-jsx-a11y": "^6.3.1", "eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-react": "^7.20.3", "eslint-plugin-react": "^7.20.3",
"husky": "^2.7.0", "husky": "^4.2.5",
"jest": "^24.9.0" "jest": "^26.1.0"
}, },
"dependencies": {} "dependencies": {}
} }

View File

@ -20,7 +20,7 @@ export default class PolynomialHash {
* @return {number} * @return {number}
*/ */
hash(word) { hash(word) {
const charCodes = Array.from(word).map(char => this.charToNumber(char)); const charCodes = Array.from(word).map((char) => this.charToNumber(char));
let hash = 0; let hash = 0;
for (let charIndex = 0; charIndex < charCodes.length; charIndex += 1) { for (let charIndex = 0; charIndex < charCodes.length; charIndex += 1) {

View File

@ -66,7 +66,7 @@ export default function articulationPoints(graph) {
// Get minimum low discovery time from all neighbors. // Get minimum low discovery time from all neighbors.
/** @param {GraphVertex} neighbor */ /** @param {GraphVertex} neighbor */
visitedSet[currentVertex.getKey()].lowDiscoveryTime = currentVertex.getNeighbors() visitedSet[currentVertex.getKey()].lowDiscoveryTime = currentVertex.getNeighbors()
.filter(earlyNeighbor => earlyNeighbor.getKey() !== previousVertex.getKey()) .filter((earlyNeighbor) => earlyNeighbor.getKey() !== previousVertex.getKey())
/** /**
* @param {number} lowestDiscoveryTime * @param {number} lowestDiscoveryTime
* @param {GraphVertex} neighbor * @param {GraphVertex} neighbor

View File

@ -53,7 +53,7 @@ export default function graphBridges(graph) {
// Check if current node is connected to any early node other then previous one. // Check if current node is connected to any early node other then previous one.
visitedSet[currentVertex.getKey()].lowDiscoveryTime = currentVertex.getNeighbors() visitedSet[currentVertex.getKey()].lowDiscoveryTime = currentVertex.getNeighbors()
.filter(earlyNeighbor => earlyNeighbor.getKey() !== previousVertex.getKey()) .filter((earlyNeighbor) => earlyNeighbor.getKey() !== previousVertex.getKey())
.reduce( .reduce(
/** /**
* @param {number} lowestDiscoveryTime * @param {number} lowestDiscoveryTime

View File

@ -8,9 +8,9 @@ import DisjointSet from '../../../data-structures/disjoint-set/DisjointSet';
export default function detectUndirectedCycleUsingDisjointSet(graph) { export default function detectUndirectedCycleUsingDisjointSet(graph) {
// Create initial singleton disjoint sets for each graph vertex. // Create initial singleton disjoint sets for each graph vertex.
/** @param {GraphVertex} graphVertex */ /** @param {GraphVertex} graphVertex */
const keyExtractor = graphVertex => graphVertex.getKey(); const keyExtractor = (graphVertex) => graphVertex.getKey();
const disjointSet = new DisjointSet(keyExtractor); const disjointSet = new DisjointSet(keyExtractor);
graph.getAllVertices().forEach(graphVertex => disjointSet.makeSet(graphVertex)); graph.getAllVertices().forEach((graphVertex) => disjointSet.makeSet(graphVertex));
// Go trough all graph edges one by one and check if edge vertices are from the // Go trough all graph edges one by one and check if edge vertices are from the
// different sets. In this case joint those sets together. Do this until you find // different sets. In this case joint those sets together. Do this until you find

View File

@ -75,7 +75,7 @@ export default function eulerianPath(graph) {
[edgeToDelete] = currentEdges; [edgeToDelete] = currentEdges;
} else { } else {
// If there are many edges left then we need to peek any of those except bridges. // If there are many edges left then we need to peek any of those except bridges.
[edgeToDelete] = currentEdges.filter(edge => !bridges[edge.getKey()]); [edgeToDelete] = currentEdges.filter((edge) => !bridges[edge.getKey()]);
} }
// Detect next current vertex. // Detect next current vertex.

View File

@ -20,7 +20,7 @@ function isSafe(adjacencyMatrix, verticesIndices, cycle, vertexCandidate) {
} }
// Check if vertexCandidate is being added to the path for the first time. // Check if vertexCandidate is being added to the path for the first time.
const candidateDuplicate = cycle.find(vertex => vertex.getKey() === vertexCandidate.getKey()); const candidateDuplicate = cycle.find((vertex) => vertex.getKey() === vertexCandidate.getKey());
return !candidateDuplicate; return !candidateDuplicate;
} }
@ -61,7 +61,7 @@ function hamiltonianCycleRecursive({
cycle, cycle,
}) { }) {
// Clone cycle in order to prevent it from modification by other DFS branches. // Clone cycle in order to prevent it from modification by other DFS branches.
const currentCycle = [...cycle].map(vertex => new GraphVertex(vertex.value)); const currentCycle = [...cycle].map((vertex) => new GraphVertex(vertex.value));
if (vertices.length === currentCycle.length) { if (vertices.length === currentCycle.length) {
// Hamiltonian path is found. // Hamiltonian path is found.

View File

@ -33,7 +33,7 @@ export default function kruskal(graph) {
const sortedEdges = new QuickSort(sortingCallbacks).sort(graph.getAllEdges()); const sortedEdges = new QuickSort(sortingCallbacks).sort(graph.getAllEdges());
// Create disjoint sets for all graph vertices. // Create disjoint sets for all graph vertices.
const keyCallback = graphVertex => graphVertex.getKey(); const keyCallback = (graphVertex) => graphVertex.getKey();
const disjointSet = new DisjointSet(keyCallback); const disjointSet = new DisjointSet(keyCallback);
graph.getAllVertices().forEach((graphVertex) => { graph.getAllVertices().forEach((graphVertex) => {

View File

@ -21,7 +21,6 @@ describe('reverseTraversal', () => {
}); });
}); });
// it('should reverse traversal the linked list with callback', () => { // it('should reverse traversal the linked list with callback', () => {
// const linkedList = new LinkedList(); // const linkedList = new LinkedList();
// //

View File

@ -244,7 +244,7 @@ export default class FourierTester {
const { input, output: expectedOutput } = testCase; const { input, output: expectedOutput } = testCase;
// Try to split input signal into sequence of pure sinusoids. // Try to split input signal into sequence of pure sinusoids.
const formattedInput = input.map(sample => sample.amplitude); const formattedInput = input.map((sample) => sample.amplitude);
const currentOutput = fourierTransform(formattedInput); const currentOutput = fourierTransform(formattedInput);
// Check the signal has been split into proper amount of sub-signals. // Check the signal has been split into proper amount of sub-signals.

View File

@ -46,8 +46,8 @@ export default function fastFourierTransform(inputData, inverse = false) {
for (let blockLength = 2; blockLength <= N; blockLength *= 2) { for (let blockLength = 2; blockLength <= N; blockLength *= 2) {
const imaginarySign = inverse ? -1 : 1; const imaginarySign = inverse ? -1 : 1;
const phaseStep = new ComplexNumber({ const phaseStep = new ComplexNumber({
re: Math.cos(2 * Math.PI / blockLength), re: Math.cos((2 * Math.PI) / blockLength),
im: imaginarySign * Math.sin(2 * Math.PI / blockLength), im: imaginarySign * Math.sin((2 * Math.PI) / blockLength),
}); });
for (let blockStart = 0; blockStart < N; blockStart += blockLength) { for (let blockStart = 0; blockStart < N; blockStart += blockLength) {

View File

@ -9,7 +9,7 @@ export default function pascalTriangle(lineNumber) {
for (let numIndex = 1; numIndex < currentLineSize; numIndex += 1) { for (let numIndex = 1; numIndex < currentLineSize; numIndex += 1) {
// See explanation of this formula in README. // See explanation of this formula in README.
currentLine[numIndex] = currentLine[numIndex - 1] * (lineNumber - numIndex + 1) / numIndex; currentLine[numIndex] = (currentLine[numIndex - 1] * (lineNumber - numIndex + 1)) / numIndex;
} }
return currentLine; return currentLine;

View File

@ -6,7 +6,7 @@ describe('degreeToRadian', () => {
expect(degreeToRadian(45)).toBe(Math.PI / 4); expect(degreeToRadian(45)).toBe(Math.PI / 4);
expect(degreeToRadian(90)).toBe(Math.PI / 2); expect(degreeToRadian(90)).toBe(Math.PI / 2);
expect(degreeToRadian(180)).toBe(Math.PI); expect(degreeToRadian(180)).toBe(Math.PI);
expect(degreeToRadian(270)).toBe(3 * Math.PI / 2); expect(degreeToRadian(270)).toBe((3 * Math.PI) / 2);
expect(degreeToRadian(360)).toBe(2 * Math.PI); expect(degreeToRadian(360)).toBe(2 * Math.PI);
}); });
}); });

View File

@ -6,7 +6,7 @@ describe('radianToDegree', () => {
expect(radianToDegree(Math.PI / 4)).toBe(45); expect(radianToDegree(Math.PI / 4)).toBe(45);
expect(radianToDegree(Math.PI / 2)).toBe(90); expect(radianToDegree(Math.PI / 2)).toBe(90);
expect(radianToDegree(Math.PI)).toBe(180); expect(radianToDegree(Math.PI)).toBe(180);
expect(radianToDegree(3 * Math.PI / 2)).toBe(270); expect(radianToDegree((3 * Math.PI) / 2)).toBe(270);
expect(radianToDegree(2 * Math.PI)).toBe(360); expect(radianToDegree(2 * Math.PI)).toBe(360);
}); });
}); });

View File

@ -31,7 +31,7 @@ export default function interpolationSearch(sortedArray, seekElement) {
} }
// Do interpolation of the middle index. // Do interpolation of the middle index.
const middleIndex = leftIndex + Math.floor(valueDelta * indexDelta / rangeDelta); const middleIndex = leftIndex + Math.floor((valueDelta * indexDelta) / rangeDelta);
// If we've found the element just return its position. // If we've found the element just return its position.
if (sortedArray[middleIndex] === seekElement) { if (sortedArray[middleIndex] === seekElement) {

View File

@ -7,7 +7,7 @@ export default function combineWithRepetitions(comboOptions, comboLength) {
// If the length of the combination is 1 then each element of the original array // If the length of the combination is 1 then each element of the original array
// is a combination itself. // is a combination itself.
if (comboLength === 1) { if (comboLength === 1) {
return comboOptions.map(comboOption => [comboOption]); return comboOptions.map((comboOption) => [comboOption]);
} }
// Init combinations array. // Init combinations array.

View File

@ -7,7 +7,7 @@ export default function combineWithoutRepetitions(comboOptions, comboLength) {
// If the length of the combination is 1 then each element of the original array // If the length of the combination is 1 then each element of the original array
// is a combination itself. // is a combination itself.
if (comboLength === 1) { if (comboLength === 1) {
return comboOptions.map(comboOption => [comboOption]); return comboOptions.map((comboOption) => [comboOption]);
} }
// Init combinations array. // Init combinations array.

View File

@ -150,7 +150,6 @@ export default class Knapsack {
} }
} }
// Solve unbounded knapsack problem. // Solve unbounded knapsack problem.
// Greedy approach. // Greedy approach.
solveUnboundedKnapsackProblem() { solveUnboundedKnapsackProblem() {

View File

@ -8,7 +8,7 @@ export default function permutateWithRepetitions(
permutationLength = permutationOptions.length, permutationLength = permutationOptions.length,
) { ) {
if (permutationLength === 1) { if (permutationLength === 1) {
return permutationOptions.map(permutationOption => [permutationOption]); return permutationOptions.map((permutationOption) => [permutationOption]);
} }
// Init permutations array. // Init permutations array.

View File

@ -81,7 +81,6 @@ function nQueensRecursive(solutions, previousQueensPositions, queensCount, rowIn
return false; return false;
} }
/** /**
* @param {number} queensCount * @param {number} queensCount
* @return {QueenPosition[][]} * @return {QueenPosition[][]}

View File

@ -16,7 +16,7 @@ export default class BloomFilter {
const hashValues = this.getHashValues(item); const hashValues = this.getHashValues(item);
// Set each hashValue index to true. // Set each hashValue index to true.
hashValues.forEach(val => this.storage.setValue(val)); hashValues.forEach((val) => this.storage.setValue(val));
} }
/** /**

View File

@ -51,7 +51,7 @@ describe('BloomFilter', () => {
}); });
it('should insert strings correctly and return true when checking for inserted values', () => { it('should insert strings correctly and return true when checking for inserted values', () => {
people.forEach(person => bloomFilter.insert(person)); people.forEach((person) => bloomFilter.insert(person));
expect(bloomFilter.mayContain('Bruce Wayne')).toBe(true); expect(bloomFilter.mayContain('Bruce Wayne')).toBe(true);
expect(bloomFilter.mayContain('Clark Kent')).toBe(true); expect(bloomFilter.mayContain('Clark Kent')).toBe(true);

View File

@ -94,7 +94,7 @@ describe('DisjointSet', () => {
}); });
it('should do basic manipulations on disjoint set with custom key extractor', () => { it('should do basic manipulations on disjoint set with custom key extractor', () => {
const keyExtractor = value => value.key; const keyExtractor = (value) => value.key;
const disjointSet = new DisjointSet(keyExtractor); const disjointSet = new DisjointSet(keyExtractor);

View File

@ -218,7 +218,7 @@ export default class DoublyLinkedList {
* @return {DoublyLinkedList} * @return {DoublyLinkedList}
*/ */
fromArray(values) { fromArray(values) {
values.forEach(value => this.append(value)); values.forEach((value) => this.append(value));
return this; return this;
} }
@ -228,7 +228,7 @@ export default class DoublyLinkedList {
* @return {string} * @return {string}
*/ */
toString(callback) { toString(callback) {
return this.toArray().map(node => node.toString(callback)).toString(); return this.toArray().map((node) => node.toString(callback)).toString();
} }
/** /**

View File

@ -164,7 +164,7 @@ describe('DoublyLinkedList', () => {
.append(nodeValue1) .append(nodeValue1)
.prepend(nodeValue2); .prepend(nodeValue2);
const nodeStringifier = value => `${value.key}:${value.value}`; const nodeStringifier = (value) => `${value.key}:${value.value}`;
expect(linkedList.toString(nodeStringifier)).toBe('key2:2,key1:1'); expect(linkedList.toString(nodeStringifier)).toBe('key2:2,key1:1');
}); });
@ -195,12 +195,12 @@ describe('DoublyLinkedList', () => {
.append({ value: 2, key: 'test2' }) .append({ value: 2, key: 'test2' })
.append({ value: 3, key: 'test3' }); .append({ value: 3, key: 'test3' });
const node = linkedList.find({ callback: value => value.key === 'test2' }); const node = linkedList.find({ callback: (value) => value.key === 'test2' });
expect(node).toBeDefined(); expect(node).toBeDefined();
expect(node.value.value).toBe(2); expect(node.value.value).toBe(2);
expect(node.value.key).toBe('test2'); expect(node.value.key).toBe('test2');
expect(linkedList.find({ callback: value => value.key === 'test5' })).toBeNull(); expect(linkedList.find({ callback: (value) => value.key === 'test5' })).toBeNull();
}); });
it('should find node by means of custom compare function', () => { it('should find node by means of custom compare function', () => {

View File

@ -48,7 +48,7 @@ describe('DoublyLinkedListNode', () => {
it('should convert node to string with custom stringifier', () => { it('should convert node to string with custom stringifier', () => {
const nodeValue = { value: 1, key: 'test' }; const nodeValue = { value: 1, key: 'test' };
const node = new DoublyLinkedListNode(nodeValue); const node = new DoublyLinkedListNode(nodeValue);
const toStringCallback = value => `value: ${value.value}, key: ${value.key}`; const toStringCallback = (value) => `value: ${value.value}, key: ${value.key}`;
expect(node.toString(toStringCallback)).toBe('value: 1, key: test'); expect(node.toString(toStringCallback)).toBe('value: 1, key: test');
}); });

View File

@ -64,7 +64,7 @@ export default class GraphVertex {
* @return {GraphEdge[]} * @return {GraphEdge[]}
*/ */
getEdges() { getEdges() {
return this.edges.toArray().map(linkedListNode => linkedListNode.value); return this.edges.toArray().map((linkedListNode) => linkedListNode.value);
} }
/** /**
@ -80,7 +80,7 @@ export default class GraphVertex {
*/ */
hasEdge(requiredEdge) { hasEdge(requiredEdge) {
const edgeNode = this.edges.find({ const edgeNode = this.edges.find({
callback: edge => edge === requiredEdge, callback: (edge) => edge === requiredEdge,
}); });
return !!edgeNode; return !!edgeNode;
@ -92,7 +92,7 @@ export default class GraphVertex {
*/ */
hasNeighbor(vertex) { hasNeighbor(vertex) {
const vertexNode = this.edges.find({ const vertexNode = this.edges.find({
callback: edge => edge.startVertex === vertex || edge.endVertex === vertex, callback: (edge) => edge.startVertex === vertex || edge.endVertex === vertex,
}); });
return !!vertexNode; return !!vertexNode;
@ -123,7 +123,7 @@ export default class GraphVertex {
* @return {GraphVertex} * @return {GraphVertex}
*/ */
deleteAllEdges() { deleteAllEdges() {
this.getEdges().forEach(edge => this.deleteEdge(edge)); this.getEdges().forEach((edge) => this.deleteEdge(edge));
return this; return this;
} }

View File

@ -52,7 +52,7 @@ export default class HashTable {
const keyHash = this.hash(key); const keyHash = this.hash(key);
this.keys[key] = keyHash; this.keys[key] = keyHash;
const bucketLinkedList = this.buckets[keyHash]; const bucketLinkedList = this.buckets[keyHash];
const node = bucketLinkedList.find({ callback: nodeValue => nodeValue.key === key }); const node = bucketLinkedList.find({ callback: (nodeValue) => nodeValue.key === key });
if (!node) { if (!node) {
// Insert new node. // Insert new node.
@ -71,7 +71,7 @@ export default class HashTable {
const keyHash = this.hash(key); const keyHash = this.hash(key);
delete this.keys[key]; delete this.keys[key];
const bucketLinkedList = this.buckets[keyHash]; const bucketLinkedList = this.buckets[keyHash];
const node = bucketLinkedList.find({ callback: nodeValue => nodeValue.key === key }); const node = bucketLinkedList.find({ callback: (nodeValue) => nodeValue.key === key });
if (node) { if (node) {
return bucketLinkedList.delete(node.value); return bucketLinkedList.delete(node.value);
@ -86,7 +86,7 @@ export default class HashTable {
*/ */
get(key) { get(key) {
const bucketLinkedList = this.buckets[this.hash(key)]; const bucketLinkedList = this.buckets[this.hash(key)];
const node = bucketLinkedList.find({ callback: nodeValue => nodeValue.key === key }); const node = bucketLinkedList.find({ callback: (nodeValue) => nodeValue.key === key });
return node ? node.value.value : undefined; return node ? node.value.value : undefined;
} }

View File

@ -35,7 +35,7 @@ describe('HashTable', () => {
expect(hashTable.has('b')).toBe(true); expect(hashTable.has('b')).toBe(true);
expect(hashTable.has('c')).toBe(true); expect(hashTable.has('c')).toBe(true);
const stringifier = value => `${value.key}:${value.value}`; const stringifier = (value) => `${value.key}:${value.value}`;
expect(hashTable.buckets[0].toString(stringifier)).toBe('c:earth'); expect(hashTable.buckets[0].toString(stringifier)).toBe('c:earth');
expect(hashTable.buckets[1].toString(stringifier)).toBe('a:sky,d:ocean'); expect(hashTable.buckets[1].toString(stringifier)).toBe('a:sky,d:ocean');

View File

@ -180,7 +180,7 @@ export default class LinkedList {
* @return {LinkedList} * @return {LinkedList}
*/ */
fromArray(values) { fromArray(values) {
values.forEach(value => this.append(value)); values.forEach((value) => this.append(value));
return this; return this;
} }
@ -205,7 +205,7 @@ export default class LinkedList {
* @return {string} * @return {string}
*/ */
toString(callback) { toString(callback) {
return this.toArray().map(node => node.toString(callback)).toString(); return this.toArray().map((node) => node.toString(callback)).toString();
} }
/** /**

View File

@ -146,7 +146,7 @@ describe('LinkedList', () => {
.append(nodeValue1) .append(nodeValue1)
.prepend(nodeValue2); .prepend(nodeValue2);
const nodeStringifier = value => `${value.key}:${value.value}`; const nodeStringifier = (value) => `${value.key}:${value.value}`;
expect(linkedList.toString(nodeStringifier)).toBe('key2:2,key1:1'); expect(linkedList.toString(nodeStringifier)).toBe('key2:2,key1:1');
}); });
@ -177,12 +177,12 @@ describe('LinkedList', () => {
.append({ value: 2, key: 'test2' }) .append({ value: 2, key: 'test2' })
.append({ value: 3, key: 'test3' }); .append({ value: 3, key: 'test3' });
const node = linkedList.find({ callback: value => value.key === 'test2' }); const node = linkedList.find({ callback: (value) => value.key === 'test2' });
expect(node).toBeDefined(); expect(node).toBeDefined();
expect(node.value.value).toBe(2); expect(node.value.value).toBe(2);
expect(node.value.key).toBe('test2'); expect(node.value.key).toBe('test2');
expect(linkedList.find({ callback: value => value.key === 'test5' })).toBeNull(); expect(linkedList.find({ callback: (value) => value.key === 'test5' })).toBeNull();
}); });
it('should create linked list from array', () => { it('should create linked list from array', () => {

View File

@ -39,7 +39,7 @@ describe('LinkedListNode', () => {
it('should convert node to string with custom stringifier', () => { it('should convert node to string with custom stringifier', () => {
const nodeValue = { value: 1, key: 'test' }; const nodeValue = { value: 1, key: 'test' };
const node = new LinkedListNode(nodeValue); const node = new LinkedListNode(nodeValue);
const toStringCallback = value => `value: ${value.value}, key: ${value.key}`; const toStringCallback = (value) => `value: ${value.value}, key: ${value.key}`;
expect(node.toString(toStringCallback)).toBe('value: 1, key: test'); expect(node.toString(toStringCallback)).toBe('value: 1, key: test');
}); });

View File

@ -22,7 +22,7 @@ describe('Queue', () => {
queue.enqueue({ value: 'test1', key: 'key1' }); queue.enqueue({ value: 'test1', key: 'key1' });
queue.enqueue({ value: 'test2', key: 'key2' }); queue.enqueue({ value: 'test2', key: 'key2' });
const stringifier = value => `${value.key}:${value.value}`; const stringifier = (value) => `${value.key}:${value.value}`;
expect(queue.toString(stringifier)).toBe('key1:test1,key2:test2'); expect(queue.toString(stringifier)).toBe('key1:test1,key2:test2');
expect(queue.dequeue().value).toBe('test1'); expect(queue.dequeue().value).toBe('test1');

View File

@ -54,7 +54,7 @@ export default class Stack {
toArray() { toArray() {
return this.linkedList return this.linkedList
.toArray() .toArray()
.map(linkedListNode => linkedListNode.value); .map((linkedListNode) => linkedListNode.value);
} }
/** /**

View File

@ -56,7 +56,7 @@ describe('Stack', () => {
stack.push({ value: 'test1', key: 'key1' }); stack.push({ value: 'test1', key: 'key1' });
stack.push({ value: 'test2', key: 'key2' }); stack.push({ value: 'test2', key: 'key2' });
const stringifier = value => `${value.key}:${value.value}`; const stringifier = (value) => `${value.key}:${value.value}`;
expect(stack.toString(stringifier)).toBe('key2:test2,key1:test1'); expect(stack.toString(stringifier)).toBe('key2:test2,key1:test1');
expect(stack.pop().value).toBe('test2'); expect(stack.pop().value).toBe('test2');