fix(tracker): fix dead tests (tabid prop)
This commit is contained in:
parent
0dc3dd2210
commit
c07b03cc34
9 changed files with 452 additions and 15 deletions
65
.github/workflows/tracker-tests.yaml
vendored
Normal file
65
.github/workflows/tracker-tests.yaml
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# Checking unit tests for tracker and assist
|
||||
name: Tracker tests
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
paths:
|
||||
- tracker/**
|
||||
pull_request:
|
||||
branches: [ "dev", "main" ]
|
||||
paths:
|
||||
- frontend/**
|
||||
- tracker/**
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: macos-latest
|
||||
name: Build and test Tracker
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [ 16.x ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Cache tracker modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: tracker/tracker/node_modules
|
||||
key: ${{ runner.OS }}-test_tracker_build-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
test_tracker_build{{ runner.OS }}-build-
|
||||
test_tracker_build{{ runner.OS }}-
|
||||
- name: Cache tracker-assist modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: tracker/tracker-assist/node_modules
|
||||
key: ${{ runner.OS }}-test_tracker_build-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
test_tracker_build{{ runner.OS }}-build-
|
||||
test_tracker_build{{ runner.OS }}-
|
||||
- name: Setup Testing packages
|
||||
run: |
|
||||
cd tracker/tracker
|
||||
npm i -g yarn
|
||||
yarn
|
||||
- name: Setup Testing packages
|
||||
run: |
|
||||
cd tracker/tracker-assist
|
||||
yarn
|
||||
- name: Jest tests
|
||||
run: |
|
||||
cd tracker/tracker
|
||||
yarn test:
|
||||
- name: Jest tests
|
||||
run: |
|
||||
cd tracker/tracker-assist
|
||||
yarn test:ci
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
flags: tracker
|
||||
name: tracker
|
||||
10
.github/workflows/ui-tests.js.yml
vendored
10
.github/workflows/ui-tests.js.yml
vendored
|
|
@ -47,16 +47,6 @@ jobs:
|
|||
cd tracker/tracker
|
||||
npm i -g yarn
|
||||
yarn
|
||||
- name: Jest tests
|
||||
run: |
|
||||
cd tracker/tracker
|
||||
yarn test:ci
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
flags: tracker
|
||||
name: tracker
|
||||
- name: Build tracker inst
|
||||
run: |
|
||||
cd tracker/tracker
|
||||
|
|
|
|||
1
tracker/tracker-assist/.gitignore
vendored
1
tracker/tracker-assist/.gitignore
vendored
|
|
@ -6,3 +6,4 @@ cjs
|
|||
.cache
|
||||
*.cache
|
||||
*.DS_Store
|
||||
coverage
|
||||
13
tracker/tracker-assist/jest.config.js
Normal file
13
tracker/tracker-assist/jest.config.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
const config = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'jsdom',
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: ['src/**/*.ts', '!src/**/*.d.ts',],
|
||||
// .js file extension fix
|
||||
moduleNameMapper: {
|
||||
'(.+)\\.js': '$1',
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
||||
|
|
@ -23,7 +23,9 @@
|
|||
"replace-req-version": "replace-in-files lib/* cjs/* --string='REQUIRED_TRACKER_VERSION' --replacement='3.5.14'",
|
||||
"prepublishOnly": "npm run build",
|
||||
"prepare": "cd ../../ && husky install tracker/.husky/",
|
||||
"lint-front": "lint-staged"
|
||||
"lint-front": "lint-staged",
|
||||
"test": "jest --coverage=false",
|
||||
"test:ci": "jest --coverage=true"
|
||||
},
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.10",
|
||||
|
|
@ -44,7 +46,10 @@
|
|||
"lint-staged": "^13.0.3",
|
||||
"prettier": "^2.7.1",
|
||||
"replace-in-files-cli": "^1.0.0",
|
||||
"typescript": "^4.6.0-dev.20211126"
|
||||
"typescript": "^4.6.0-dev.20211126",
|
||||
"jest": "^29.3.1",
|
||||
"jest-environment-jsdom": "^29.3.1",
|
||||
"ts-jest": "^29.0.3"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
|
|
|
|||
|
|
@ -513,6 +513,11 @@ export default class Assist {
|
|||
})
|
||||
|
||||
call.answer(lStreams[call.peer].stream)
|
||||
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
initiateCallEnd()
|
||||
})
|
||||
|
||||
this.setCallingState(CallingState.True)
|
||||
if (!callEndCallback) { callEndCallback = this.options.onCallStart?.() }
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ if (nativeInputValueDescriptor && nativeInputValueDescriptor.set) {
|
|||
|
||||
|
||||
export default class RemoteControl {
|
||||
private mouse: Mouse | null
|
||||
status: RCStatus = RCStatus.Disabled
|
||||
private mouse: Mouse | null = null
|
||||
public status: RCStatus = RCStatus.Disabled
|
||||
private agentID: string | null = null
|
||||
|
||||
constructor(
|
||||
|
|
@ -114,7 +114,9 @@ export default class RemoteControl {
|
|||
input = (id, value: string) => {
|
||||
if (id !== this.agentID || !this.mouse || !this.focused) { return }
|
||||
if (this.focused instanceof HTMLTextAreaElement
|
||||
|| this.focused instanceof HTMLInputElement) {
|
||||
|| this.focused instanceof HTMLInputElement
|
||||
|| this.focused.tagName === 'INPUT'
|
||||
|| this.focused.tagName === 'TEXTAREA') {
|
||||
setInputValue.call(this.focused, value)
|
||||
const ev = new Event('input', { bubbles: true,})
|
||||
this.focused.dispatchEvent(ev)
|
||||
|
|
|
|||
148
tracker/tracker-assist/tests/AnnotationCanvas.test.ts
Normal file
148
tracker/tracker-assist/tests/AnnotationCanvas.test.ts
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
import AnnotationCanvas from '../src/AnnotationCanvas'
|
||||
import { describe, expect, test, it, jest, beforeEach, afterEach, } from '@jest/globals'
|
||||
|
||||
|
||||
describe('AnnotationCanvas', () => {
|
||||
let annotationCanvas
|
||||
let documentBody
|
||||
let canvasMock
|
||||
let contextMock
|
||||
|
||||
beforeEach(() => {
|
||||
canvasMock = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
style: {},
|
||||
getContext: jest.fn(() => contextMock as unknown as HTMLCanvasElement),
|
||||
parentNode: document,
|
||||
}
|
||||
|
||||
contextMock = {
|
||||
globalAlpha: 1.0,
|
||||
beginPath: jest.fn(),
|
||||
moveTo: jest.fn(),
|
||||
lineTo: jest.fn(),
|
||||
lineWidth: 8,
|
||||
lineCap: 'round',
|
||||
lineJoin: 'round',
|
||||
strokeStyle: 'red',
|
||||
stroke: jest.fn(),
|
||||
globalCompositeOperation: '',
|
||||
fillStyle: '',
|
||||
fillRect: jest.fn(),
|
||||
clearRect: jest.fn(),
|
||||
}
|
||||
|
||||
documentBody = document.body
|
||||
// @ts-ignore
|
||||
document['removeChild'] = (el) => jest.fn(el)
|
||||
// @ts-ignore
|
||||
document['createElement'] = () => canvasMock
|
||||
|
||||
jest.spyOn(documentBody, 'appendChild').mockImplementation(jest.fn())
|
||||
jest.spyOn(documentBody, 'removeChild').mockImplementation(jest.fn())
|
||||
jest.spyOn(window, 'addEventListener').mockImplementation(jest.fn())
|
||||
jest.spyOn(window, 'removeEventListener').mockImplementation(jest.fn())
|
||||
annotationCanvas = new AnnotationCanvas()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks()
|
||||
})
|
||||
|
||||
it('should create a canvas element with correct styles when initialized', () => {
|
||||
const createElSpy = jest.spyOn(document, 'createElement')
|
||||
annotationCanvas = new AnnotationCanvas()
|
||||
expect(createElSpy).toHaveBeenCalledWith('canvas')
|
||||
expect(canvasMock.style.position).toBe('fixed')
|
||||
expect(canvasMock.style.left).toBe(0)
|
||||
expect(canvasMock.style.top).toBe(0)
|
||||
expect(canvasMock.style.pointerEvents).toBe('none')
|
||||
expect(canvasMock.style.zIndex).toBe(2147483647 - 2)
|
||||
})
|
||||
|
||||
it('should resize the canvas when calling resizeCanvas method', () => {
|
||||
annotationCanvas.resizeCanvas()
|
||||
|
||||
expect(canvasMock.width).toBe(window.innerWidth)
|
||||
expect(canvasMock.height).toBe(window.innerHeight)
|
||||
})
|
||||
|
||||
it('should start painting and set the last position when calling start method', () => {
|
||||
const position = [10, 20,]
|
||||
|
||||
annotationCanvas.start(position)
|
||||
|
||||
expect(annotationCanvas.painting).toBe(true)
|
||||
expect(annotationCanvas.clrTmID).toBeNull()
|
||||
expect(annotationCanvas.lastPosition).toEqual(position)
|
||||
})
|
||||
|
||||
it('should stop painting and call fadeOut method when calling stop method', () => {
|
||||
annotationCanvas.painting = true
|
||||
const fadeOutSpy = jest.spyOn(annotationCanvas, 'fadeOut')
|
||||
|
||||
annotationCanvas.stop()
|
||||
|
||||
expect(annotationCanvas.painting).toBe(false)
|
||||
expect(fadeOutSpy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not stop painting or call fadeOut method when calling stop method while not painting', () => {
|
||||
annotationCanvas.painting = false
|
||||
const fadeOutSpy = jest.spyOn(annotationCanvas, 'fadeOut')
|
||||
annotationCanvas.stop()
|
||||
|
||||
expect(fadeOutSpy).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should draw a line on the canvas when calling move method', () => {
|
||||
annotationCanvas.painting = true
|
||||
annotationCanvas.ctx = contextMock
|
||||
const initialLastPosition = [0, 0,]
|
||||
const position = [10, 20,]
|
||||
|
||||
annotationCanvas.move(position)
|
||||
|
||||
expect(contextMock.globalAlpha).toBe(1.0)
|
||||
expect(contextMock.beginPath).toHaveBeenCalled()
|
||||
expect(contextMock.moveTo).toHaveBeenCalledWith(initialLastPosition[0], initialLastPosition[1])
|
||||
expect(contextMock.lineTo).toHaveBeenCalledWith(position[0], position[1])
|
||||
expect(contextMock.stroke).toHaveBeenCalled()
|
||||
expect(annotationCanvas.lastPosition).toEqual(position)
|
||||
})
|
||||
|
||||
it('should not draw a line on the canvas when calling move method while not painting', () => {
|
||||
annotationCanvas.painting = false
|
||||
annotationCanvas.ctx = contextMock
|
||||
const position = [10, 20,]
|
||||
|
||||
annotationCanvas.move(position)
|
||||
|
||||
expect(contextMock.beginPath).not.toHaveBeenCalled()
|
||||
expect(contextMock.stroke).not.toHaveBeenCalled()
|
||||
expect(annotationCanvas.lastPosition).toEqual([0, 0,])
|
||||
})
|
||||
|
||||
it('should fade out the canvas when calling fadeOut method', () => {
|
||||
annotationCanvas.ctx = contextMock
|
||||
jest.useFakeTimers()
|
||||
const timerSpy = jest.spyOn(window, 'setTimeout')
|
||||
annotationCanvas.fadeOut()
|
||||
|
||||
expect(timerSpy).toHaveBeenCalledTimes(2)
|
||||
expect(contextMock.globalCompositeOperation).toBe('source-over')
|
||||
expect(contextMock.fillStyle).toBe('rgba(255, 255, 255, 0.1)')
|
||||
expect(contextMock.fillRect).toHaveBeenCalledWith(0, 0, canvasMock.width, canvasMock.height)
|
||||
jest.runOnlyPendingTimers()
|
||||
expect(contextMock.clearRect).toHaveBeenCalledWith(0, 0, canvasMock.width, canvasMock.height)
|
||||
})
|
||||
|
||||
it('should remove the canvas element when calling remove method', () => {
|
||||
const spyOnRemove = jest.spyOn(document, 'removeChild')
|
||||
annotationCanvas.remove()
|
||||
|
||||
expect(spyOnRemove).toHaveBeenCalledWith(canvasMock)
|
||||
expect(window.removeEventListener).toHaveBeenCalledWith('resize', annotationCanvas.resizeCanvas)
|
||||
})
|
||||
})
|
||||
208
tracker/tracker-assist/tests/RemoteControl.test.ts
Normal file
208
tracker/tracker-assist/tests/RemoteControl.test.ts
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
import RemoteControl, { RCStatus, } from '../src/RemoteControl'
|
||||
import ConfirmWindow from '../src/ConfirmWindow/ConfirmWindow'
|
||||
import { describe, expect, test, jest, beforeEach, afterEach, } from '@jest/globals'
|
||||
|
||||
describe('RemoteControl', () => {
|
||||
let remoteControl
|
||||
let options
|
||||
let onGrand
|
||||
let onRelease
|
||||
let confirmWindowMountMock
|
||||
let confirmWindowRemoveMock
|
||||
|
||||
beforeEach(() => {
|
||||
options = {
|
||||
/* mock options */
|
||||
}
|
||||
onGrand = jest.fn()
|
||||
onRelease = jest.fn()
|
||||
confirmWindowMountMock = jest.fn(() => Promise.resolve(true))
|
||||
confirmWindowRemoveMock = jest.fn()
|
||||
|
||||
jest.spyOn(window, 'HTMLInputElement').mockImplementation((): any => ({
|
||||
value: '',
|
||||
dispatchEvent: jest.fn(),
|
||||
}))
|
||||
|
||||
jest.spyOn(window, 'HTMLTextAreaElement').mockImplementation((): any => ({
|
||||
value: '',
|
||||
dispatchEvent: jest.fn(),
|
||||
}))
|
||||
|
||||
jest
|
||||
.spyOn(ConfirmWindow.prototype, 'mount')
|
||||
.mockImplementation(confirmWindowMountMock)
|
||||
jest
|
||||
.spyOn(ConfirmWindow.prototype, 'remove')
|
||||
.mockImplementation(confirmWindowRemoveMock)
|
||||
|
||||
remoteControl = new RemoteControl(options, onGrand, onRelease)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks()
|
||||
})
|
||||
|
||||
test('should initialize with disabled status', () => {
|
||||
expect(remoteControl.status).toBe(RCStatus.Disabled)
|
||||
expect(remoteControl.agentID).toBeNull()
|
||||
expect(remoteControl.confirm).toBeNull()
|
||||
expect(remoteControl.mouse).toBeNull()
|
||||
})
|
||||
|
||||
test('should request control when calling requestControl method', () => {
|
||||
const id = 'agent123'
|
||||
remoteControl.requestControl(id)
|
||||
|
||||
expect(remoteControl.agentID).toBe(id)
|
||||
expect(remoteControl.status).toBe(RCStatus.Requesting)
|
||||
expect(confirmWindowMountMock).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('should grant control when calling grantControl method', () => {
|
||||
const id = 'agent123'
|
||||
remoteControl.grantControl(id)
|
||||
|
||||
expect(remoteControl.agentID).toBe(id)
|
||||
expect(remoteControl.status).toBe(RCStatus.Enabled)
|
||||
expect(onGrand).toHaveBeenCalledWith(id)
|
||||
expect(remoteControl.mouse).toBeDefined()
|
||||
})
|
||||
|
||||
test('should release control when calling releaseControl method', () => {
|
||||
const isDenied = true
|
||||
remoteControl['confirm'] = { remove: jest.fn(), } as unknown as ConfirmWindow
|
||||
const confirmSpy = jest.spyOn(remoteControl['confirm'], 'remove')
|
||||
|
||||
remoteControl.releaseControl(isDenied)
|
||||
expect(remoteControl.agentID).toBeNull()
|
||||
expect(remoteControl.status).toBe(RCStatus.Disabled)
|
||||
expect(onRelease).toHaveBeenCalledWith(null, isDenied)
|
||||
expect(confirmSpy).toHaveBeenCalled()
|
||||
expect(remoteControl.mouse).toBeNull()
|
||||
})
|
||||
|
||||
test('should reset mouse when calling resetMouse method', () => {
|
||||
remoteControl.resetMouse()
|
||||
|
||||
expect(remoteControl.mouse).toBeNull()
|
||||
})
|
||||
|
||||
test('should call mouse.scroll when calling scroll method with correct agentID', () => {
|
||||
const id = 'agent123'
|
||||
const d = 10
|
||||
remoteControl.agentID = id
|
||||
remoteControl.mouse = {
|
||||
scroll: jest.fn(),
|
||||
}
|
||||
|
||||
remoteControl.scroll(id, d)
|
||||
|
||||
expect(remoteControl.mouse.scroll).toHaveBeenCalledWith(d)
|
||||
})
|
||||
|
||||
test('should not call mouse.scroll when calling scroll method with incorrect agentID', () => {
|
||||
const id = 'agent123'
|
||||
const d = 10
|
||||
remoteControl.agentID = 'anotherAgent'
|
||||
remoteControl.mouse = {
|
||||
scroll: jest.fn(),
|
||||
}
|
||||
|
||||
remoteControl.scroll(id, d)
|
||||
|
||||
expect(remoteControl.mouse.scroll).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('should call mouse.move when calling move method with correct agentID', () => {
|
||||
const id = 'agent123'
|
||||
const xy = { x: 10, y: 20, }
|
||||
remoteControl.agentID = id
|
||||
remoteControl.mouse = {
|
||||
move: jest.fn(),
|
||||
}
|
||||
|
||||
remoteControl.move(id, xy)
|
||||
|
||||
expect(remoteControl.mouse.move).toHaveBeenCalledWith(xy)
|
||||
})
|
||||
|
||||
test('should not call mouse.move when calling move method with incorrect agentID', () => {
|
||||
const id = 'agent123'
|
||||
const xy = { x: 10, y: 20, }
|
||||
remoteControl.agentID = 'anotherAgent'
|
||||
remoteControl.mouse = {
|
||||
move: jest.fn(),
|
||||
}
|
||||
|
||||
remoteControl.move(id, xy)
|
||||
|
||||
expect(remoteControl.mouse.move).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('should call mouse.click when calling click method with correct agentID', () => {
|
||||
const id = 'agent123'
|
||||
const xy = { x: 10, y: 20, }
|
||||
remoteControl.agentID = id
|
||||
remoteControl.mouse = {
|
||||
click: jest.fn(),
|
||||
}
|
||||
|
||||
remoteControl.click(id, xy)
|
||||
|
||||
expect(remoteControl.mouse.click).toHaveBeenCalledWith(xy)
|
||||
})
|
||||
|
||||
test('should not call mouse.click when calling click method with incorrect agentID', () => {
|
||||
const id = 'agent123'
|
||||
const xy = { x: 10, y: 20, }
|
||||
remoteControl.agentID = 'anotherAgent'
|
||||
remoteControl.mouse = {
|
||||
click: jest.fn(),
|
||||
}
|
||||
|
||||
remoteControl.click(id, xy)
|
||||
|
||||
expect(remoteControl.mouse.click).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('should set the focused element when calling focus method', () => {
|
||||
const id = 'agent123'
|
||||
const element = document.createElement('div')
|
||||
|
||||
remoteControl.focus(id, element)
|
||||
|
||||
expect(remoteControl.focused).toBe(element)
|
||||
})
|
||||
|
||||
test('should call setInputValue and dispatch input event when calling input method with HTMLInputElement', () => {
|
||||
const id = 'agent1234'
|
||||
const value = 'test_test'
|
||||
const element = document.createElement('input')
|
||||
const dispatchSpy = jest.spyOn(element, 'dispatchEvent')
|
||||
remoteControl.agentID = id
|
||||
remoteControl.mouse = true
|
||||
remoteControl.focused = element
|
||||
|
||||
remoteControl.input(id, value)
|
||||
|
||||
expect(element.value).toBe(value)
|
||||
expect(dispatchSpy).toHaveBeenCalledWith(
|
||||
new Event('input', { bubbles: true, })
|
||||
)
|
||||
})
|
||||
|
||||
test('should update innerText when calling input method with content editable element', () => {
|
||||
const id = 'agent123'
|
||||
const value = 'test'
|
||||
const element = document.createElement('div')
|
||||
// @ts-ignore
|
||||
element['isContentEditable'] = true
|
||||
remoteControl.agentID = id
|
||||
remoteControl.mouse = true
|
||||
remoteControl.focused = element
|
||||
|
||||
remoteControl.input(id, value)
|
||||
expect(element.innerText).toBe(value)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Reference in a new issue