change(tracker): unit tests for tracker

* chore(tracker):exclude test files from compilation

* feat(tracker): webworker unit tests

* fix(tracker): no empty tests

* change(tracker): add jest test to workflow

* change(tracker): fix jest run

---------

Co-authored-by: nick-delirium <nikita@openreplay.com>
This commit is contained in:
Alex K 2023-02-06 12:42:18 +01:00 committed by GitHub
parent e8d2379943
commit 17008a694d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 169 additions and 4 deletions

View file

@ -47,8 +47,10 @@ jobs:
cd tracker/tracker
npm i -g yarn
yarn
# - name: Jest tests
# run: yarn test
- name: Jest tests
run: |
cd tracker/tracker
yarn test
- name: Build tracker inst
run: |
cd tracker/tracker

1
.gitignore vendored
View file

@ -3,5 +3,6 @@ public
node_modules
*DS_Store
*.env
*.log
**/*.envrc
.idea

View file

@ -6,3 +6,6 @@ build
.cache
.eslintrc.cjs
*.gen.ts
**/*.test.ts
src/main/plugin.ts

View file

@ -3,7 +3,7 @@ module.exports = {
root: true,
parser: '@typescript-eslint/parser',
parserOptions: {
project: ['./tsconfig-base.json', './src/main/tsconfig-cjs.json'],
project: ['./tsconfig-base.json', './src/main/tsconfig-cjs.json'], // ??TODO: use correct project
tsconfigRootDir: __dirname,
},
plugins: ['prettier', '@typescript-eslint'],

View file

@ -0,0 +1,63 @@
import { describe, expect, test, jest, beforeEach, afterEach } from '@jest/globals'
import PrimitiveEncoder from './PrimitiveEncoder.js'
describe('PrimitiveEncoder', () => {
test('initial state', () => {
const enc = new PrimitiveEncoder(10)
expect(enc.getCurrentOffset()).toBe(0)
expect(enc.isEmpty).toBe(true)
expect(enc.flush().length).toBe(0)
})
test('skip()', () => {
const enc = new PrimitiveEncoder(10)
enc.skip(5)
expect(enc.getCurrentOffset()).toBe(5)
expect(enc.isEmpty).toBe(false)
})
test('checkpoint()', () => {
const enc = new PrimitiveEncoder(10)
enc.skip(5)
enc.checkpoint()
expect(enc.flush().length).toBe(5)
})
test('boolean(true)', () => {
const enc = new PrimitiveEncoder(10)
enc.boolean(true)
enc.checkpoint()
const bytes = enc.flush()
expect(bytes.length).toBe(1)
expect(bytes[0]).toBe(1)
})
test('boolean(false)', () => {
const enc = new PrimitiveEncoder(10)
enc.boolean(false)
enc.checkpoint()
const bytes = enc.flush()
expect(bytes.length).toBe(1)
expect(bytes[0]).toBe(0)
})
// TODO: test correct enc/dec on a top level(?) with player(PrimitiveReader.ts)/tracker(PrimitiveEncoder.ts)
test('buffer oveflow with string()', () => {
const N = 10
const enc = new PrimitiveEncoder(N)
const wasWritten = enc.string('long string'.repeat(N))
expect(wasWritten).toBe(false)
})
test('buffer oveflow with uint()', () => {
const enc = new PrimitiveEncoder(1)
const wasWritten = enc.uint(Number.MAX_SAFE_INTEGER)
expect(wasWritten).toBe(false)
})
test('buffer oveflow with boolean()', () => {
const enc = new PrimitiveEncoder(1)
let wasWritten = enc.boolean(true)
expect(wasWritten).toBe(true)
wasWritten = enc.boolean(true)
expect(wasWritten).toBe(false)
})
})

View file

@ -0,0 +1,95 @@
import { describe, expect, test, jest, beforeEach, afterEach } from '@jest/globals'
import QueueSender from './QueueSender.js'
global.fetch = () => Promise.resolve(new Response()) // jsdom does not have it
function mockFetch(status: number) {
return jest
.spyOn(global, 'fetch')
.mockImplementation(() => Promise.resolve({ status } as Response))
}
const baseURL = 'MYBASEURL'
const sampleArray = new Uint8Array(1)
const randomToken = 'abc'
function defaultQueueSender({
url = baseURL,
onUnauthorised = () => {},
onFailed = () => {},
} = {}) {
return new QueueSender(baseURL, onUnauthorised, onFailed)
}
describe('QueueSender', () => {
afterEach(() => {
jest.restoreAllMocks()
})
// Test fetch first parameter + authorization header to be present
// authorise() / push()
test('Does not call fetch if not authorised', () => {
const queueSender = defaultQueueSender()
const fetchMock = mockFetch(200)
queueSender.push(sampleArray)
expect(fetchMock).not.toBeCalled()
})
test('Calls fetch on push() if authorised', () => {
const queueSender = defaultQueueSender()
const fetchMock = mockFetch(200)
queueSender.authorise(randomToken)
expect(fetchMock).toBeCalledTimes(0)
queueSender.push(sampleArray)
expect(fetchMock).toBeCalledTimes(1)
})
test('Calls fetch on authorisation if there was a push() call before', () => {
const queueSender = defaultQueueSender()
const fetchMock = mockFetch(200)
queueSender.push(sampleArray)
queueSender.authorise(randomToken)
expect(fetchMock).toBeCalledTimes(1)
})
// .clean()
test("Doesn't call fetch on push() after clean()", () => {
const queueSender = defaultQueueSender()
const fetchMock = mockFetch(200)
queueSender.authorise(randomToken)
queueSender.clean()
queueSender.push(sampleArray)
expect(fetchMock).not.toBeCalled()
})
test("Doesn't call fetch on authorisation if there was push() & clean() calls before", () => {
const queueSender = defaultQueueSender()
const fetchMock = mockFetch(200)
queueSender.push(sampleArray)
queueSender.clean()
queueSender.authorise(randomToken)
expect(fetchMock).not.toBeCalled()
})
//Test N sequential ToBeCalledTimes(N)
//Test N sequential pushes with different timeouts to be sequential
// onUnauthorised
test('Calls onUnauthorized callback on 401', (done) => {
const onUnauthorised = jest.fn()
const queueSender = defaultQueueSender({
onUnauthorised,
})
const fetchMock = mockFetch(401)
queueSender.authorise(randomToken)
queueSender.push(sampleArray)
setTimeout(() => {
// how to make test simpler and more explicit?
expect(onUnauthorised).toBeCalled()
done()
}, 100)
})
//Test onFailure
//Test attempts timeout/ attempts count (toBeCalledTimes on one batch)
})

View file

@ -10,5 +10,6 @@
"target": "es6",
"module": "es6",
"moduleResolution": "nodenext"
}
},
"exclude": ["**/*.test.ts"]
}