network proxy: move tests from tracker
This commit is contained in:
parent
ba1fba3a85
commit
4996210959
5 changed files with 122 additions and 206 deletions
|
|
@ -9,11 +9,14 @@
|
|||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc"
|
||||
"build": "tsc",
|
||||
"test": "vitest"
|
||||
},
|
||||
"author": "Nikita <nikita@openreplay.com>",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"jsdom": "^25.0.1",
|
||||
"vitest": "^2.1.1",
|
||||
"typescript": "^5.6.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,77 +8,80 @@ import {
|
|||
isIterable,
|
||||
formatByteSize,
|
||||
getURL,
|
||||
} from '../main/modules/Network/utils.js'
|
||||
import { describe, it, expect, jest } from '@jest/globals'
|
||||
} from '../src/utils.js';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
describe('Network utility function tests', () => {
|
||||
it('genResponseByType should handle response types correctly', () => {
|
||||
expect(genResponseByType('json', '{"key":"value"}')).toEqual({ key: 'value' })
|
||||
expect(genResponseByType('blob', new Blob())).toBe('[object Blob]')
|
||||
})
|
||||
expect(genResponseByType('json', '{"key":"value"}')).toEqual({ key: 'value' });
|
||||
expect(genResponseByType('blob', new Blob())).toBe('[object Blob]');
|
||||
});
|
||||
|
||||
it('getStringResponseByType should handle response types correctly', () => {
|
||||
expect(getStringResponseByType('json', '{"key":"value"}')).toBe('{"key":"value"}')
|
||||
expect(getStringResponseByType('json', { key: 'value' })).toBe('{"key":"value"}')
|
||||
expect(getStringResponseByType('blob', new Blob())).toBe('[object Blob]')
|
||||
})
|
||||
expect(getStringResponseByType('json', '{"key":"value"}')).toBe('{"key":"value"}');
|
||||
expect(getStringResponseByType('json', { key: 'value' })).toBe('{"key":"value"}');
|
||||
expect(getStringResponseByType('blob', new Blob())).toBe('[object Blob]');
|
||||
});
|
||||
|
||||
it('genStringBody should handle body types correctly', () => {
|
||||
expect(genStringBody('{"key":"value"}')).toBe('{"key":"value"}')
|
||||
expect(genStringBody(new URLSearchParams('key=value'))).toBe('key=value')
|
||||
expect(genStringBody('{"key":"value"}')).toBe('{"key":"value"}');
|
||||
expect(genStringBody(new URLSearchParams('key=value'))).toBe('key=value');
|
||||
// Add more cases as needed
|
||||
})
|
||||
});
|
||||
|
||||
it('genGetDataByUrl should get data from URL', () => {
|
||||
expect(genGetDataByUrl('http://localhost/?key=value')).toEqual({ key: 'value' })
|
||||
expect(genGetDataByUrl('http://localhost/?key=value')).toEqual({ key: 'value' });
|
||||
// Add more cases as needed
|
||||
})
|
||||
});
|
||||
|
||||
it('genGetDataByUrl handles wrong format', () => {
|
||||
// @ts-ignore
|
||||
expect(genGetDataByUrl('http://localhost/?key=value', '')).toEqual({ key: 'value' })
|
||||
})
|
||||
expect(genGetDataByUrl('http://localhost/?key=value', '')).toEqual({ key: 'value' });
|
||||
});
|
||||
|
||||
it('genFormattedBody should format body correctly', () => {
|
||||
const param = new URLSearchParams('key=value&other=test')
|
||||
const blob = new Blob([param.toString()], { type: 'text/plain' })
|
||||
const uArr = new Uint8Array([1, 2, 3])
|
||||
const dataView = new DataView(uArr.buffer)
|
||||
expect(genFormattedBody('{"key":"value"}')).toEqual({ key: 'value' })
|
||||
expect(genFormattedBody('key=value&other=test')).toEqual({ key: 'value', other: 'test' })
|
||||
expect(genFormattedBody(param)).toEqual({ key: 'value', other: 'test' })
|
||||
expect(genFormattedBody(blob)).toEqual('[byte data]')
|
||||
expect(genFormattedBody(dataView)).toEqual('[byte data]')
|
||||
expect(genFormattedBody(uArr)).toEqual('[byte data]')
|
||||
})
|
||||
const param = new URLSearchParams('key=value&other=test');
|
||||
const blob = new Blob([param.toString()], { type: 'text/plain' });
|
||||
const uArr = new Uint8Array([1, 2, 3]);
|
||||
const dataView = new DataView(uArr.buffer);
|
||||
expect(genFormattedBody('{"key":"value"}')).toEqual({ key: 'value' });
|
||||
expect(genFormattedBody('key=value&other=test')).toEqual({ key: 'value', other: 'test' });
|
||||
expect(genFormattedBody(param)).toEqual({ key: 'value', other: 'test' });
|
||||
expect(genFormattedBody(blob)).toEqual('[byte data]');
|
||||
expect(genFormattedBody(dataView)).toEqual('[byte data]');
|
||||
expect(genFormattedBody(uArr)).toEqual('[byte data]');
|
||||
});
|
||||
|
||||
it('isPureObject should return true for objects', () => {
|
||||
expect(isPureObject({})).toBe(true)
|
||||
expect(isPureObject([])).toBe(true)
|
||||
expect(isPureObject(null)).toBe(false)
|
||||
expect(isPureObject(undefined)).toBe(false)
|
||||
})
|
||||
expect(isPureObject({})).toBe(true);
|
||||
expect(isPureObject([])).toBe(true);
|
||||
expect(isPureObject(null)).toBe(false);
|
||||
expect(isPureObject(undefined)).toBe(false);
|
||||
});
|
||||
|
||||
it('isIterable should return true for iterables', () => {
|
||||
expect(isIterable([])).toBe(true)
|
||||
expect(isIterable(new Map())).toBe(true)
|
||||
expect(isIterable('string')).toBe(true)
|
||||
expect(isIterable(undefined)).toBe(false)
|
||||
})
|
||||
expect(isIterable([])).toBe(true);
|
||||
expect(isIterable(new Map())).toBe(true);
|
||||
expect(isIterable('string')).toBe(true);
|
||||
expect(isIterable(undefined)).toBe(false);
|
||||
});
|
||||
|
||||
it('formatByteSize should format byte sizes correctly', () => {
|
||||
expect(formatByteSize(500)).toBe('500B')
|
||||
expect(formatByteSize(1500)).toBe('1.5 KB')
|
||||
expect(formatByteSize(1500000)).toBe('1.5 MB')
|
||||
expect(formatByteSize(-1)).toBe('')
|
||||
})
|
||||
expect(formatByteSize(500)).toBe('500B');
|
||||
expect(formatByteSize(1500)).toBe('1.5 KB');
|
||||
expect(formatByteSize(1500000)).toBe('1.5 MB');
|
||||
expect(formatByteSize(-1)).toBe('');
|
||||
});
|
||||
|
||||
it('getURL should get a URL', () => {
|
||||
// @ts-ignore
|
||||
delete window.location
|
||||
// @ts-ignore
|
||||
window.location = new URL('https://www.example.com')
|
||||
expect(getURL('https://example.com').toString()).toBe('https://example.com/')
|
||||
expect(getURL('//example.com').toString()).toBe('https://example.com/')
|
||||
expect(getURL('/path').toString()).toBe('https://www.example.com/path')
|
||||
})
|
||||
})
|
||||
const originalLocation = window.location;
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: new URL('https://www.example.com'),
|
||||
writable: true,
|
||||
});
|
||||
expect(getURL('https://example.com').toString()).toBe('https://example.com/');
|
||||
expect(getURL('//example.com').toString()).toBe('https://example.com/');
|
||||
expect(getURL('/path').toString()).toBe('https://www.example.com/path');
|
||||
window.location = originalLocation;
|
||||
});
|
||||
});
|
||||
|
|
@ -1,29 +1,27 @@
|
|||
import NetworkMessage, { RequestState, httpMethod } from '../main/modules/Network/networkMessage.js'
|
||||
import { NetworkRequest } from '../main/app/messages.gen.js'
|
||||
import { describe, it, expect, beforeEach, jest } from '@jest/globals'
|
||||
import NetworkMessage from '../src/networkMessage.js';
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
|
||||
describe('NetworkMessage', () => {
|
||||
const ignoredHeaders = ['cookie']
|
||||
const setSessionTokenHeader = jest.fn()
|
||||
const sanitize = jest.fn()
|
||||
const ignoredHeaders = ['cookie'];
|
||||
const setSessionTokenHeader = vi.fn();
|
||||
const sanitize = vi.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('getMessage', () => {
|
||||
it('should properly construct and return a NetworkRequest', () => {
|
||||
// @ts-ignore
|
||||
const networkMessage = new NetworkMessage(ignoredHeaders, setSessionTokenHeader, sanitize)
|
||||
const networkMessage = new NetworkMessage(ignoredHeaders, setSessionTokenHeader, sanitize);
|
||||
|
||||
// Set some basic properties
|
||||
networkMessage.method = 'GET'
|
||||
networkMessage.url = 'https://example.com'
|
||||
networkMessage.status = 200
|
||||
networkMessage.requestType = 'xhr'
|
||||
networkMessage.startTime = 0
|
||||
networkMessage.duration = 500
|
||||
networkMessage.getData = { key: 'value' }
|
||||
networkMessage.method = 'GET';
|
||||
networkMessage.url = 'https://example.com';
|
||||
networkMessage.status = 200;
|
||||
networkMessage.requestType = 'xhr';
|
||||
networkMessage.startTime = 0;
|
||||
networkMessage.duration = 500;
|
||||
networkMessage.getData = { key: 'value' };
|
||||
|
||||
// Expect sanitized message
|
||||
sanitize.mockReturnValueOnce({
|
||||
|
|
@ -32,60 +30,61 @@ describe('NetworkMessage', () => {
|
|||
status: 200,
|
||||
request: {},
|
||||
response: {},
|
||||
})
|
||||
});
|
||||
|
||||
const result = networkMessage.getMessage()
|
||||
const result = networkMessage.getMessage();
|
||||
|
||||
const expected = NetworkRequest(
|
||||
'xhr',
|
||||
'GET',
|
||||
'https://example.com',
|
||||
JSON.stringify({}),
|
||||
JSON.stringify({}),
|
||||
200,
|
||||
// yeah
|
||||
result[7],
|
||||
500,
|
||||
0,
|
||||
)
|
||||
expect(result).toBeDefined()
|
||||
expect(result).toEqual(expected)
|
||||
expect(sanitize).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
const expected = {
|
||||
requestType: 'xhr',
|
||||
method: 'GET',
|
||||
url: 'https://example.com',
|
||||
request: JSON.stringify({}),
|
||||
response: JSON.stringify({}),
|
||||
status: 200,
|
||||
startTime: result!.startTime,
|
||||
duration: 500,
|
||||
responseSize: 0
|
||||
};
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result).toEqual(expected);
|
||||
expect(sanitize).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('writeHeaders', () => {
|
||||
it('should properly write request and response headers', () => {
|
||||
// @ts-ignore
|
||||
const networkMessage = new NetworkMessage(ignoredHeaders, setSessionTokenHeader, sanitize)
|
||||
const networkMessage = new NetworkMessage(ignoredHeaders, setSessionTokenHeader, sanitize);
|
||||
|
||||
networkMessage.requestHeader = { 'Content-Type': 'application/json', cookie: 'test' }
|
||||
networkMessage.header = { 'Content-Type': 'application/json', cookie: 'test' }
|
||||
networkMessage.requestHeader = { 'Content-Type': 'application/json', cookie: 'test' };
|
||||
networkMessage.header = { 'Content-Type': 'application/json', cookie: 'test' };
|
||||
|
||||
const result = networkMessage.writeHeaders()
|
||||
const result = networkMessage.writeHeaders();
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result.reqHs).toEqual({ 'Content-Type': 'application/json' })
|
||||
expect(result.resHs).toEqual({ 'Content-Type': 'application/json' })
|
||||
expect(setSessionTokenHeader).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
expect(result).toBeDefined();
|
||||
expect(result.reqHs).toEqual({ 'Content-Type': 'application/json' });
|
||||
expect(result.resHs).toEqual({ 'Content-Type': 'application/json' });
|
||||
expect(setSessionTokenHeader).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isHeaderIgnored', () => {
|
||||
it('should properly identify ignored headers', () => {
|
||||
// @ts-ignore
|
||||
const networkMessage = new NetworkMessage(ignoredHeaders, setSessionTokenHeader, sanitize)
|
||||
const networkMessage = new NetworkMessage(ignoredHeaders, setSessionTokenHeader, sanitize);
|
||||
|
||||
expect(networkMessage.isHeaderIgnored('cookie')).toBe(true);
|
||||
expect(networkMessage.isHeaderIgnored('Content-Type')).toBe(false);
|
||||
});
|
||||
|
||||
expect(networkMessage.isHeaderIgnored('cookie')).toBe(true)
|
||||
expect(networkMessage.isHeaderIgnored('Content-Type')).toBe(false)
|
||||
})
|
||||
it('if ignoreHeaders is true should ignore all headers', () => {
|
||||
// @ts-ignore
|
||||
const networkMessage = new NetworkMessage(true, setSessionTokenHeader, sanitize)
|
||||
const networkMessage = new NetworkMessage(true, setSessionTokenHeader, sanitize);
|
||||
|
||||
expect(networkMessage.isHeaderIgnored('cookie')).toBe(true)
|
||||
expect(networkMessage.isHeaderIgnored('Content-Type')).toBe(true)
|
||||
expect(networkMessage.isHeaderIgnored('Random-Header')).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
expect(networkMessage.isHeaderIgnored('cookie')).toBe(true);
|
||||
expect(networkMessage.isHeaderIgnored('Content-Type')).toBe(true);
|
||||
expect(networkMessage.isHeaderIgnored('Random-Header')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
8
networkProxy/vitest.config.ts
Normal file
8
networkProxy/vitest.config.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { defineConfig } from 'vitest/config'
|
||||
|
||||
export default defineConfig(({ mode }) => ({
|
||||
define: { global: 'window' },
|
||||
test: {
|
||||
environment: "jsdom"
|
||||
}
|
||||
}));
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
// @ts-nocheck
|
||||
import { describe, test, expect, beforeEach, jest } from '@jest/globals'
|
||||
import setProxy from '../main/modules/Network/index.js'
|
||||
import FetchProxy from '../main/modules/Network/fetchProxy.js'
|
||||
import XHRProxy from '../main/modules/Network/xhrProxy.js'
|
||||
import BeaconProxy from '../main/modules/Network/beaconProxy.js'
|
||||
|
||||
globalThis.fetch = jest.fn()
|
||||
|
||||
jest.mock('../main/modules/Network/fetchProxy.js')
|
||||
jest.mock('../main/modules/Network/xhrProxy.js')
|
||||
jest.mock('../main/modules/Network/beaconProxy.js')
|
||||
|
||||
describe('Network Proxy', () => {
|
||||
let context
|
||||
const ignoredHeaders = []
|
||||
const setSessionTokenHeader = jest.fn()
|
||||
const sanitize = jest.fn()
|
||||
const sendMessage = jest.fn()
|
||||
const isServiceUrl = jest.fn()
|
||||
const tokenUrlMatcher = jest.fn()
|
||||
|
||||
beforeEach(() => {
|
||||
context = {
|
||||
fetch: jest.fn(),
|
||||
XMLHttpRequest: jest.fn(),
|
||||
navigator: {
|
||||
sendBeacon: jest.fn(),
|
||||
},
|
||||
}
|
||||
FetchProxy.create.mockReturnValue(jest.fn())
|
||||
XHRProxy.create.mockReturnValue(jest.fn())
|
||||
BeaconProxy.create.mockReturnValue(jest.fn())
|
||||
})
|
||||
test('should not replace fetch if not present', () => {
|
||||
context = {
|
||||
XMLHttpRequest: jest.fn(),
|
||||
navigator: {
|
||||
sendBeacon: jest.fn(),
|
||||
},
|
||||
}
|
||||
setProxy(
|
||||
context,
|
||||
ignoredHeaders,
|
||||
setSessionTokenHeader,
|
||||
sanitize,
|
||||
sendMessage,
|
||||
isServiceUrl,
|
||||
tokenUrlMatcher,
|
||||
)
|
||||
expect(context.fetch).toBeUndefined()
|
||||
expect(FetchProxy.create).toHaveBeenCalledTimes(0)
|
||||
expect(XHRProxy.create).toHaveBeenCalled()
|
||||
expect(BeaconProxy.create).toHaveBeenCalled()
|
||||
})
|
||||
test('should replace XMLHttpRequest if present', () => {
|
||||
setProxy(
|
||||
context,
|
||||
ignoredHeaders,
|
||||
setSessionTokenHeader,
|
||||
sanitize,
|
||||
sendMessage,
|
||||
isServiceUrl,
|
||||
tokenUrlMatcher,
|
||||
)
|
||||
expect(context.XMLHttpRequest).toEqual(expect.any(Function))
|
||||
expect(XHRProxy.create).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('should replace fetch if present', () => {
|
||||
setProxy(
|
||||
context,
|
||||
ignoredHeaders,
|
||||
setSessionTokenHeader,
|
||||
sanitize,
|
||||
sendMessage,
|
||||
isServiceUrl,
|
||||
tokenUrlMatcher,
|
||||
)
|
||||
expect(context.fetch).toEqual(expect.any(Function))
|
||||
expect(FetchProxy.create).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('should replace navigator.sendBeacon if present', () => {
|
||||
setProxy(
|
||||
context,
|
||||
ignoredHeaders,
|
||||
setSessionTokenHeader,
|
||||
sanitize,
|
||||
sendMessage,
|
||||
isServiceUrl,
|
||||
tokenUrlMatcher,
|
||||
)
|
||||
expect(context.navigator.sendBeacon).toEqual(expect.any(Function))
|
||||
expect(BeaconProxy.create).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Reference in a new issue