Skip to content

Commit 78873b6

Browse files
committed
test: refactor tests to use nodejs test runner
1 parent baec01a commit 78873b6

19 files changed

+787
-617
lines changed

.eslintrc

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
"eslint:recommended",
1717
"plugin:@typescript-eslint/eslint-recommended",
1818
"plugin:@typescript-eslint/recommended",
19-
"plugin:mocha/recommended",
2019
"prettier"
2120
],
2221
"rules": {

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@
7777
"eslint-config-prettier": "^9.1.0",
7878
"eslint-plugin-header": "^3.1.1",
7979
"eslint-plugin-jest-formatting": "^3.1.0",
80-
"eslint-plugin-mocha": "^10.2.0",
8180
"eslint-plugin-prettier": "^5.0.1",
8281
"eslint-plugin-unicorn": "^49.0.0",
8382
"mocha": "^10.2.0",

register.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { register } from 'node:module';
2+
import { pathToFileURL } from 'node:url';
3+
4+
register('ts-node/esm', pathToFileURL('./'));

src/data/gateway-data-source.test.ts

+54-53
Original file line numberDiff line numberDiff line change
@@ -15,82 +15,83 @@
1515
* You should have received a copy of the GNU Affero General Public License
1616
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1717
*/
18+
import { strict as assert } from 'node:assert';
19+
import { afterEach, before, beforeEach, describe, it, mock } from 'node:test';
1820
import axios from 'axios';
19-
import chai, { expect } from 'chai';
20-
import sinon, { SinonSandbox } from 'sinon';
21-
import sinonChai from 'sinon-chai';
2221
import * as winston from 'winston';
2322
import { GatewayDataSource } from './gateway-data-source.js';
2423

25-
chai.use(sinonChai);
24+
let log: winston.Logger;
25+
let dataSource: GatewayDataSource;
26+
let mockedAxiosInstance: any;
2627

27-
describe('GatewayDataSource', function () {
28-
let log: winston.Logger;
29-
let sandbox: SinonSandbox;
30-
let dataSource: GatewayDataSource;
31-
let mockedAxiosInstance: any;
32-
33-
before(function () {
34-
log = winston.createLogger({ silent: true });
35-
});
36-
37-
beforeEach(function () {
38-
sandbox = sinon.createSandbox();
28+
before(async () => {
29+
log = winston.createLogger({ silent: true });
30+
});
3931

40-
mockedAxiosInstance = {
41-
request: sandbox.stub().resolves({
42-
status: 200,
43-
data: 'mocked stream',
44-
headers: {
45-
'content-length': '123',
46-
'content-type': 'application/json',
47-
},
48-
}),
49-
defaults: {
50-
baseURL: 'https://gateway.domain', // Ensure this matches what you expect
32+
beforeEach(async () => {
33+
mockedAxiosInstance = {
34+
request: async () => ({
35+
status: 200,
36+
data: 'mocked stream',
37+
headers: {
38+
'content-length': '123',
39+
'content-type': 'application/json',
5140
},
52-
};
53-
sandbox.stub(axios, 'create').returns(mockedAxiosInstance as any);
41+
}),
42+
defaults: {
43+
baseURL: 'https://gateway.domain',
44+
},
45+
};
5446

55-
dataSource = new GatewayDataSource({
56-
log,
57-
trustedGatewayUrl: 'https://gateway.domain',
58-
});
59-
});
47+
mock.method(axios, 'create', () => mockedAxiosInstance);
6048

61-
afterEach(function () {
62-
sandbox.restore();
49+
dataSource = new GatewayDataSource({
50+
log,
51+
trustedGatewayUrl: 'https://gateway.domain',
6352
});
53+
});
6454

65-
describe('getData', function () {
66-
it('should fetch data successfully from the gateway', async function () {
55+
afterEach(async () => {
56+
mock.restoreAll();
57+
});
58+
59+
describe('GatewayDataSource', () => {
60+
describe('getData', () => {
61+
it('should fetch data successfully from the gateway', async () => {
6762
const data = await dataSource.getData('some-id');
6863

69-
expect(data).to.have.property('stream', 'mocked stream');
70-
expect(data).to.have.property('size', 123);
71-
expect(data).to.have.property('sourceContentType', 'application/json');
72-
expect(data).to.have.property('verified', false);
73-
expect(data).to.have.property('cached', false);
64+
assert.deepEqual(data, {
65+
stream: 'mocked stream',
66+
size: 123,
67+
sourceContentType: 'application/json',
68+
verified: false,
69+
cached: false,
70+
});
7471
});
7572

76-
it('should throw an error for unexpected status code', async function () {
77-
mockedAxiosInstance.request.resolves({ status: 404 });
73+
it('should throw an error for unexpected status code', async () => {
74+
mockedAxiosInstance.request = async () => ({ status: 404 });
7875

7976
try {
8077
await dataSource.getData('bad-id');
78+
assert.fail('Expected an error to be thrown');
8179
} catch (error: any) {
82-
expect(error.message).to.equal(
83-
'Unexpected status code from gateway: 404',
84-
);
80+
assert.equal(error.message, 'Unexpected status code from gateway: 404');
8581
}
8682
});
8783

88-
it('should handle network or Axios errors gracefully', async function () {
89-
mockedAxiosInstance.request.rejects(new Error('Network Error'));
84+
it('should handle network or Axios errors gracefully', async () => {
85+
mockedAxiosInstance.request = async () => {
86+
throw new Error('Network Error');
87+
};
9088

91-
await expect(dataSource.getData('bad-id')).to.be.rejectedWith(
92-
'Network Error',
93-
);
89+
try {
90+
await dataSource.getData('bad-id');
91+
assert.fail('Expected an error to be thrown');
92+
} catch (error: any) {
93+
assert.equal(error.message, 'Network Error');
94+
}
9495
});
9596
});
9697
});

src/data/read-through-chunk-data-cache.test.ts

+57-56
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@
1515
* You should have received a copy of the GNU Affero General Public License
1616
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1717
*/
18-
import chai, { expect } from 'chai';
1918
import fs from 'node:fs';
20-
import sinon, { SinonSandbox } from 'sinon';
21-
import sinonChai from 'sinon-chai';
19+
import { strict as assert } from 'node:assert';
20+
import { afterEach, before, describe, it, mock } from 'node:test';
2221
import * as winston from 'winston';
2322

2423
import { ArweaveChunkSourceStub } from '../../test/stubs.js';
@@ -27,43 +26,32 @@ import { FsChunkDataStore } from '../store/fs-chunk-data-store.js';
2726
import { Chunk, ChunkData, ChunkDataStore } from '../types.js';
2827
import { ReadThroughChunkDataCache } from './read-through-chunk-data-cache.js';
2928

30-
chai.use(sinonChai);
3129
const B64_DATA_ROOT = 'wRq6f05oRupfTW_M5dcYBtwK5P8rSNYu20vC6D_o-M4';
3230
const TX_SIZE = 256000;
3331
const ABSOLUTE_OFFSET = 51530681327863;
3432
const RELATIVE_OFFSET = 0;
3533

36-
describe('ReadThroughChunkDataCache', () => {
37-
let log: winston.Logger;
38-
let chunkSource: ArweaveChunkSourceStub;
39-
let chunkDataStore: ChunkDataStore;
40-
let chunkCache: ReadThroughChunkDataCache;
41-
let sandbox: SinonSandbox;
34+
let log: winston.Logger;
35+
let chunkSource: ArweaveChunkSourceStub;
36+
let chunkDataStore: ChunkDataStore;
37+
let chunkCache: ReadThroughChunkDataCache;
4238

43-
before(() => {
44-
log = winston.createLogger({ silent: true });
45-
chunkSource = new ArweaveChunkSourceStub();
46-
chunkDataStore = new FsChunkDataStore({
47-
log,
48-
baseDir: 'data/chunks',
49-
});
50-
chunkCache = new ReadThroughChunkDataCache({
51-
log,
52-
chunkSource,
53-
chunkDataStore,
54-
});
39+
before(() => {
40+
log = winston.createLogger({ silent: true });
41+
chunkSource = new ArweaveChunkSourceStub();
42+
chunkDataStore = new FsChunkDataStore({
43+
log,
44+
baseDir: 'data/chunks',
5545
});
56-
57-
beforeEach(() => {
58-
sandbox = sinon.createSandbox();
59-
});
60-
61-
afterEach(() => {
62-
sandbox.restore();
46+
chunkCache = new ReadThroughChunkDataCache({
47+
log,
48+
chunkSource,
49+
chunkDataStore,
6350
});
51+
});
6452

53+
describe('ReadThroughChunkDataCache', () => {
6554
// TODO remove mocks from tests
66-
6755
describe('getChunkDataByAny', () => {
6856
let mockedChunk: Chunk;
6957
let mockedChunkData: ChunkData;
@@ -76,9 +64,9 @@ describe('ReadThroughChunkDataCache', () => {
7664
),
7765
);
7866
const txPath = fromB64Url(jsonChunk.tx_path);
79-
const dataRootBuffer = txPath.slice(-64, -32);
67+
const dataRootBuffer = txPath.subarray(-64, -32);
8068
const dataPath = fromB64Url(jsonChunk.data_path);
81-
const hash = dataPath.slice(-64, -32);
69+
const hash = dataPath.subarray(-64, -32);
8270
mockedChunk = {
8371
tx_path: txPath,
8472
data_root: dataRootBuffer,
@@ -97,55 +85,68 @@ describe('ReadThroughChunkDataCache', () => {
9785
};
9886
});
9987

88+
afterEach(() => {
89+
mock.restoreAll();
90+
});
91+
10092
it('should fetch chunk data from cache when available', async () => {
101-
// mock the file exists
102-
const storeGetSpy = sandbox
103-
.stub(chunkDataStore, 'get')
104-
.resolves(mockedChunkData);
105-
const networkSpy = sandbox.spy(chunkSource, 'getChunkByAny');
93+
mock.method(chunkDataStore, 'get', async () => mockedChunkData);
94+
mock.method(chunkSource, 'getChunkByAny');
95+
10696
await chunkCache.getChunkDataByAny(
10797
TX_SIZE,
10898
ABSOLUTE_OFFSET,
10999
B64_DATA_ROOT,
110100
0,
111101
);
112-
expect(networkSpy).not.to.have.been.called;
113-
expect(storeGetSpy).to.have.been.called;
102+
103+
assert.deepEqual((chunkSource.getChunkByAny as any).mock.callCount(), 0);
104+
assert.deepEqual((chunkDataStore.get as any).mock.callCount(), 1);
114105
});
115106

116107
it('should fetch chunk data from network when not in local cache', async () => {
117-
// mock file does not exist
118-
const storeHasSpy = sandbox.stub(chunkDataStore, 'has').resolves(false);
119-
const storeGetSpy = sandbox.spy(chunkDataStore, 'get');
120-
const networkSpy = sandbox
121-
.stub(chunkSource, 'getChunkByAny')
122-
.resolves(mockedChunk);
108+
const chuunkDataStoreHasSpy = mock.method(
109+
chunkDataStore,
110+
'has',
111+
async () => false,
112+
);
113+
const chunkDataStoreGetSpy = mock.method(chunkDataStore, 'get');
114+
const networkSpy = mock.method(
115+
chunkSource,
116+
'getChunkByAny',
117+
async () => mockedChunk,
118+
);
123119
await chunkCache.getChunkDataByAny(
124120
TX_SIZE,
125121
ABSOLUTE_OFFSET,
126122
B64_DATA_ROOT,
127123
0,
128124
);
129-
expect(storeGetSpy).to.have.been.called;
130-
expect(storeHasSpy).to.have.been.called;
131-
expect(networkSpy).to.have.been.called;
125+
assert.deepEqual(chunkDataStoreGetSpy.mock.callCount(), 1);
126+
assert.deepEqual(chuunkDataStoreHasSpy.mock.callCount(), 1);
127+
assert.deepEqual(networkSpy.mock.callCount(), 1);
132128
});
133129

134130
it('should fetch chunk data from network when an error occurs fetching from local cache', async () => {
135-
const storeHasSpy = sandbox.stub(chunkDataStore, 'has').rejects();
136-
const storeGetSpy = sandbox.spy(chunkDataStore, 'get');
137-
const networkSpy = sandbox
138-
.stub(chunkSource, 'getChunkByAny')
139-
.resolves(mockedChunk);
131+
const storeHasSpy = mock.method(chunkDataStore, 'has', async () => {
132+
throw new Error('Error');
133+
});
134+
const storeGetSpy = mock.method(chunkDataStore, 'get');
135+
const networkSpy = mock.method(
136+
chunkSource,
137+
'getChunkByAny',
138+
async () => mockedChunk,
139+
);
140140
await chunkCache.getChunkDataByAny(
141141
TX_SIZE,
142142
ABSOLUTE_OFFSET,
143143
B64_DATA_ROOT,
144144
0,
145145
);
146-
expect(storeGetSpy).to.have.been.called;
147-
expect(storeHasSpy).to.have.been.called;
148-
expect(networkSpy).to.have.been.called;
146+
147+
assert.deepEqual(storeGetSpy.mock.callCount(), 1);
148+
assert.deepEqual(storeHasSpy.mock.callCount(), 1);
149+
assert.deepEqual(networkSpy.mock.callCount(), 1);
149150
});
150151
});
151152
});

0 commit comments

Comments
 (0)