feat(tracker): safety wrap for angular, new performance/lag display system

* feat(tracker): make message commits low priority (possibly improve browser lags display), add safe polyfill for env methods hijacked by angular

* feat(tracker): add bun.sh support

* feat(tracker): add bun.sh support to actions

* feat(tracker): add bun.sh support to actions

* feat(tracker): add bun.sh support to actions

* fix(tracker): fix e2e test workflow file

* fix(tracker): fix e2e test workflow file

* fix(tracker): fix test workflow file

* fix(tracker): fix requestIdleCallback check, add test cov for new utilities

* fix(tracker): fix eslint complains

* fix(ui): fix yarn bug

* fix(ui): fix yarn bug

* fix(ui): fix yarn bug

* fix(ui): fix ci test

* fix(ui): fix ci test

* fix(ui): fix ci test

* fix(ui): fix ci test

* fix(ui): fix ci test

* fix(ui): fix ci test

* fix(ui): fix ci test

* fix(ui): debug logs

* fix(ui): debug logs

* fix(ui): debug logs

* fix(ui): debug logs

* fix(ui): remove logs

* fix(ui): fix waiting for ui

* fix(ui): fix?

* fix(ui): fix?

* fix(ui): fix?

* fix(ui): fix?

* fix(ui): fix!

* fix(ui): fix!

* fix(ui): finally
This commit is contained in:
Delirium 2023-10-25 12:29:42 +02:00 committed by GitHub
parent e6957d631c
commit e3893b92ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 435 additions and 116 deletions

View file

@ -17,8 +17,11 @@ jobs:
name: Build and test Tracker
strategy:
matrix:
node-version: [ 16.x ]
node-version: [ 18.x ]
steps:
- uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
@ -28,7 +31,7 @@ jobs:
uses: actions/cache@v3
with:
path: tracker/tracker/node_modules
key: ${{ runner.OS }}-test_tracker_build-${{ hashFiles('**/yarn.lock') }}
key: ${{ runner.OS }}-test_tracker_build-${{ hashFiles('**/bun.lockb') }}
restore-keys: |
test_tracker_build{{ runner.OS }}-build-
test_tracker_build{{ runner.OS }}-
@ -36,27 +39,34 @@ jobs:
uses: actions/cache@v3
with:
path: tracker/tracker-assist/node_modules
key: ${{ runner.OS }}-test_tracker_build-${{ hashFiles('**/yarn.lock') }}
key: ${{ runner.OS }}-test_tracker_build-${{ hashFiles('**/bun.lockb') }}
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
bun install
- name: (TA) Setup Testing packages
run: |
cd tracker/tracker-assist
yarn
bun install
- name: Jest tests
run: |
cd tracker/tracker
yarn test:ci
- name: Jest tests
bun run test:ci
- name: Building test
run: |
cd tracker/tracker
bun run build
- name: (TA) Jest tests
run: |
cd tracker/tracker-assist
yarn test:ci
bun run test:ci
- name: (TA) Building test
run: |
cd tracker/tracker-assist
bun run build
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
with:

View file

@ -27,8 +27,11 @@ jobs:
name: Build and test Tracker plus Replayer
strategy:
matrix:
node-version: [ 16.x ]
node-version: [ 18.x ]
steps:
- uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
@ -38,18 +41,18 @@ jobs:
uses: actions/cache@v3
with:
path: tracker/tracker/node_modules
key: ${{ runner.OS }}-test_tracker_build-${{ hashFiles('tracker/tracker/yarn.lock') }}
key: ${{ runner.OS }}-test_tracker_build-${{ hashFiles('tracker/tracker/bun.lockb') }}
restore-keys: |
test_tracker_build-{{ runner.OS }}-build-
test_tracker_build-{{ runner.OS }}-
- name: Setup Testing packages
run: |
cd tracker/tracker
yarn
bun install
- name: Build tracker inst
run: |
cd tracker/tracker
yarn build
bun run build
- name: Setup Testing UI Env
run: |
cd tracker/tracker-testing-playground
@ -67,10 +70,6 @@ jobs:
run: |
cd tracker/tracker-testing-playground
yarn
- name: Run testing frontend
run: |
cd tracker/tracker-testing-playground
yarn start &> ui.log &
- name: Cache node modules
uses: actions/cache@v3
with:
@ -96,39 +95,50 @@ jobs:
echo "MINIO_USE_SSL = ''" >> .env
echo "MINIO_ACCESS_KEY = ''" >> .env
echo "MINIO_SECRET_KEY = ''" >> .env
echo "VERSION = '1.9.0'" >> .env
echo "TRACKER_VERSION = '4.0.0'" >> .env
echo "VERSION = '1.15.0'" >> .env
echo "TRACKER_VERSION = '10.0.0'" >> .env
echo "COMMIT_HASH = 'dev'" >> .env
echo "{ \"account\": \"$CY_ACC\", \"password\": \"$CY_PASS\" }" >> cypress.env.json
- name: Setup packages
run: |
cd frontend
yarn
npm install --legacy-peer-deps
- name: Run unit tests
run: |
cd frontend
yarn test
npm run test:ci
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: ui
name: ui
- name: Wait for Testing Frontend
- name: Run testing frontend
run: |
cd tracker/tracker-testing-playground
yarn start &> testing.log &
echo "Started"
npm i -g wait-on
echo "Got wait on"
sleep 30
cat testing.log
npx wait-on http://localhost:3000
echo "Done"
timeout-minutes: 4
- name: Run Frontend
run: |
cd frontend
yarn start &> frontend.log &
- name: Wait for frontend
run: |
cd frontend
bun start &> frontend.log &
echo "Started"
sleep 30
cat frontend.log
npx wait-on http://0.0.0.0:3333
echo "Done"
timeout-minutes: 4
- name: (Chrome) Run visual tests
run: |
cd frontend
yarn cy:test
npm run cy:test
# firefox have different viewport somehow
# - name: (Firefox) Run visual tests
# run: yarn cy:test-firefox

View file

@ -38,7 +38,7 @@ type Entries<T> = {
[K in keyof T]: [K, T[K]];
}[keyof T][];
export default class LSCache<G extends Record<string, boolean | number | string> {
export default class LSCache<G extends Record<string, boolean | number | string>> {
constructor(private state: SimpleState<G>, private keyMap: Record<keyof Partial<G>, string>) {
}
update(newState: Partial<G>) {

View file

@ -1,44 +0,0 @@
describe('Testing general stability', {
viewportHeight: 900,
viewportWidth: 1400,
}, () => {
it('Checking if app will crash', () => {
cy.clearCookies()
cy.clearAllSessionStorage()
cy.clearAllCookies()
cy.clearAllLocalStorage()
cy.intercept('**/api/account').as('getAccount');
cy.visit('/')
cy.get('[data-test-id=login]').type(Cypress.env('account').replaceAll('"', ''));
cy.get('[data-test-id=password]').type(Cypress.env('password').replaceAll('"', ''));
cy.get('[data-test-id=log-button]').click();
cy.wait('@getAccount')
Cypress.on('uncaught:exception', (err, runnable) => {
return false
})
cy.get(':nth-child(1) > .ant-menu-item-group-title > .ant-typography').should('be.visible')
cy.visit('/5/dashboard')
cy.wait(500)
cy.get('input[name="dashboardsSearch"]').should('be.visible')
cy.visit('/client/account')
cy.get(':nth-child(2) > .profileSettings-module__left--D4pCi > .profileSettings-module__info--DhVpL').should('be.visible')
cy.get('.ant-menu-item-group-list > :nth-child(2)').click()
cy.wait(250)
cy.get('.text-2xl > div').should('be.visible')
cy.get('.ant-menu-item-group-list > :nth-child(3)').click()
cy.get('.ant-menu-item-group-list > :nth-child(4)').click()
cy.get('.text-base').should('be.visible')
cy.get('.ant-menu-item-group-title').should('be.visible')
// if test has not failed, we assume that app is not crashed (so far)
})
})

View file

@ -146,6 +146,16 @@ __metadata:
languageName: node
linkType: hard
"@babel/code-frame@npm:^7.22.13":
version: 7.22.13
resolution: "@babel/code-frame@npm:7.22.13"
dependencies:
"@babel/highlight": ^7.22.13
chalk: ^2.4.2
checksum: f4cc8ae1000265677daf4845083b72f88d00d311adb1a93c94eb4b07bf0ed6828a81ae4ac43ee7d476775000b93a28a9cddec18fbdc5796212d8dcccd5de72bd
languageName: node
linkType: hard
"@babel/compat-data@npm:^7.17.7, @babel/compat-data@npm:^7.20.1, @babel/compat-data@npm:^7.20.5":
version: 7.20.10
resolution: "@babel/compat-data@npm:7.20.10"
@ -220,6 +230,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-annotate-as-pure@npm:^7.22.5":
version: 7.22.5
resolution: "@babel/helper-annotate-as-pure@npm:7.22.5"
dependencies:
"@babel/types": ^7.22.5
checksum: 5a80dc364ddda26b334bbbc0f6426cab647381555ef7d0cd32eb284e35b867c012ce6ce7d52a64672ed71383099c99d32765b3d260626527bb0e3470b0f58e45
languageName: node
linkType: hard
"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.18.6":
version: 7.18.9
resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.18.9"
@ -263,6 +282,25 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-create-class-features-plugin@npm:^7.21.0":
version: 7.22.15
resolution: "@babel/helper-create-class-features-plugin@npm:7.22.15"
dependencies:
"@babel/helper-annotate-as-pure": ^7.22.5
"@babel/helper-environment-visitor": ^7.22.5
"@babel/helper-function-name": ^7.22.5
"@babel/helper-member-expression-to-functions": ^7.22.15
"@babel/helper-optimise-call-expression": ^7.22.5
"@babel/helper-replace-supers": ^7.22.9
"@babel/helper-skip-transparent-expression-wrappers": ^7.22.5
"@babel/helper-split-export-declaration": ^7.22.6
semver: ^6.3.1
peerDependencies:
"@babel/core": ^7.0.0
checksum: 2ae5759fe8845fda99b34f2ba6cd0794fc860213d14c93a87aa9180960252bce621157a79c373b7fbb423b25a55fb0e20eae0d5f8e4ad5ef22dc70e7c2af3805
languageName: node
linkType: hard
"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.20.5":
version: 7.20.5
resolution: "@babel/helper-create-regexp-features-plugin@npm:7.20.5"
@ -316,6 +354,13 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-environment-visitor@npm:^7.22.20, @babel/helper-environment-visitor@npm:^7.22.5":
version: 7.22.20
resolution: "@babel/helper-environment-visitor@npm:7.22.20"
checksum: e762c2d8f5d423af89bd7ae9abe35bd4836d2eb401af868a63bbb63220c513c783e25ef001019418560b3fdc6d9a6fb67e6c0b650bcdeb3a2ac44b5c3d2bdd94
languageName: node
linkType: hard
"@babel/helper-explode-assignable-expression@npm:^7.18.6":
version: 7.18.6
resolution: "@babel/helper-explode-assignable-expression@npm:7.18.6"
@ -335,6 +380,16 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-function-name@npm:^7.22.5":
version: 7.23.0
resolution: "@babel/helper-function-name@npm:7.23.0"
dependencies:
"@babel/template": ^7.22.15
"@babel/types": ^7.23.0
checksum: d771dd1f3222b120518176733c52b7cadac1c256ff49b1889dbbe5e3fed81db855b8cc4e40d949c9d3eae0e795e8229c1c8c24c0e83f27cfa6ee3766696c6428
languageName: node
linkType: hard
"@babel/helper-hoist-variables@npm:^7.18.6":
version: 7.18.6
resolution: "@babel/helper-hoist-variables@npm:7.18.6"
@ -353,6 +408,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-member-expression-to-functions@npm:^7.22.15":
version: 7.23.0
resolution: "@babel/helper-member-expression-to-functions@npm:7.23.0"
dependencies:
"@babel/types": ^7.23.0
checksum: b810daddf093ffd0802f1429052349ed9ea08ef7d0c56da34ffbcdecbdafac86f95bdea2fe30e0e0e629febc7dd41b56cb5eacc10d1a44336d37b755dac31fa4
languageName: node
linkType: hard
"@babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.12.13, @babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.18.6":
version: 7.18.6
resolution: "@babel/helper-module-imports@npm:7.18.6"
@ -387,6 +451,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-optimise-call-expression@npm:^7.22.5":
version: 7.22.5
resolution: "@babel/helper-optimise-call-expression@npm:7.22.5"
dependencies:
"@babel/types": ^7.22.5
checksum: 31b41a764fc3c585196cf5b776b70cf4705c132e4ce9723f39871f215f2ddbfb2e28a62f9917610f67c8216c1080482b9b05f65dd195dae2a52cef461f2ac7b8
languageName: node
linkType: hard
"@babel/helper-plugin-utils@npm:7.10.4":
version: 7.10.4
resolution: "@babel/helper-plugin-utils@npm:7.10.4"
@ -429,6 +502,19 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-replace-supers@npm:^7.22.9":
version: 7.22.20
resolution: "@babel/helper-replace-supers@npm:7.22.20"
dependencies:
"@babel/helper-environment-visitor": ^7.22.20
"@babel/helper-member-expression-to-functions": ^7.22.15
"@babel/helper-optimise-call-expression": ^7.22.5
peerDependencies:
"@babel/core": ^7.0.0
checksum: 6b0858811ad46873817c90c805015d63300e003c5a85c147a17d9845fa2558a02047c3cc1f07767af59014b2dd0fa75b503e5bc36e917f360e9b67bb6f1e79f4
languageName: node
linkType: hard
"@babel/helper-simple-access@npm:^7.20.2":
version: 7.20.2
resolution: "@babel/helper-simple-access@npm:7.20.2"
@ -447,6 +533,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-skip-transparent-expression-wrappers@npm:^7.22.5":
version: 7.22.5
resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.22.5"
dependencies:
"@babel/types": ^7.22.5
checksum: ab7fa2aa709ab49bb8cd86515a1e715a3108c4bb9a616965ba76b43dc346dee66d1004ccf4d222b596b6224e43e04cbc5c3a34459501b388451f8c589fbc3691
languageName: node
linkType: hard
"@babel/helper-split-export-declaration@npm:^7.18.6":
version: 7.18.6
resolution: "@babel/helper-split-export-declaration@npm:7.18.6"
@ -456,6 +551,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-split-export-declaration@npm:^7.22.6":
version: 7.22.6
resolution: "@babel/helper-split-export-declaration@npm:7.22.6"
dependencies:
"@babel/types": ^7.22.5
checksum: d83e4b623eaa9622c267d3c83583b72f3aac567dc393dda18e559d79187961cb29ae9c57b2664137fc3d19508370b12ec6a81d28af73a50e0846819cb21c6e44
languageName: node
linkType: hard
"@babel/helper-string-parser@npm:^7.19.4":
version: 7.19.4
resolution: "@babel/helper-string-parser@npm:7.19.4"
@ -463,6 +567,13 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-string-parser@npm:^7.22.5":
version: 7.22.5
resolution: "@babel/helper-string-parser@npm:7.22.5"
checksum: 6b0ff8af724377ec41e5587fffa7605198da74cb8e7d8d48a36826df0c0ba210eb9fedb3d9bef4d541156e0bd11040f021945a6cbb731ccec4aefb4affa17aa4
languageName: node
linkType: hard
"@babel/helper-validator-identifier@npm:^7.18.6, @babel/helper-validator-identifier@npm:^7.19.1":
version: 7.19.1
resolution: "@babel/helper-validator-identifier@npm:7.19.1"
@ -470,6 +581,13 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-validator-identifier@npm:^7.22.20":
version: 7.22.20
resolution: "@babel/helper-validator-identifier@npm:7.22.20"
checksum: dcad63db345fb110e032de46c3688384b0008a42a4845180ce7cd62b1a9c0507a1bed727c4d1060ed1a03ae57b4d918570259f81724aaac1a5b776056f37504e
languageName: node
linkType: hard
"@babel/helper-validator-option@npm:^7.18.6":
version: 7.18.6
resolution: "@babel/helper-validator-option@npm:7.18.6"
@ -511,6 +629,17 @@ __metadata:
languageName: node
linkType: hard
"@babel/highlight@npm:^7.22.13":
version: 7.22.20
resolution: "@babel/highlight@npm:7.22.20"
dependencies:
"@babel/helper-validator-identifier": ^7.22.20
chalk: ^2.4.2
js-tokens: ^4.0.0
checksum: f3c3a193afad23434297d88e81d1d6c0c2cf02423de2139ada7ce0a7fc62d8559abf4cc996533c1a9beca7fc990010eb8d544097f75e818ac113bf39ed810aa2
languageName: node
linkType: hard
"@babel/node@npm:^7.16.8":
version: 7.20.7
resolution: "@babel/node@npm:7.20.7"
@ -538,6 +667,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/parser@npm:^7.22.15":
version: 7.23.0
resolution: "@babel/parser@npm:7.23.0"
bin:
parser: ./bin/babel-parser.js
checksum: ab4ea9360ed4ba3c728c5a9bf33035103ebde20a7e943c4ae1d42becb02a313d731d12a93c795c5a19777031e4022e64b92a52262eda902522a1a18649826283
languageName: node
linkType: hard
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.18.6":
version: 7.18.6
resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.18.6"
@ -779,6 +917,20 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-proposal-private-property-in-object@npm:^7.21.11":
version: 7.21.11
resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.11"
dependencies:
"@babel/helper-annotate-as-pure": ^7.18.6
"@babel/helper-create-class-features-plugin": ^7.21.0
"@babel/helper-plugin-utils": ^7.20.2
"@babel/plugin-syntax-private-property-in-object": ^7.14.5
peerDependencies:
"@babel/core": ^7.0.0-0
checksum: 3c8c9ea175101b1cbb2b0e8fee20fcbdd03eb0700d3581aa826ac3573c9b002f39b1512c2af9fd1903ff921bcc864da95ad3cdeba53c9fbcfb3dc23916eacf47
languageName: node
linkType: hard
"@babel/plugin-proposal-unicode-property-regex@npm:^7.18.6, @babel/plugin-proposal-unicode-property-regex@npm:^7.4.4":
version: 7.18.6
resolution: "@babel/plugin-proposal-unicode-property-regex@npm:7.18.6"
@ -1737,6 +1889,17 @@ __metadata:
languageName: node
linkType: hard
"@babel/template@npm:^7.22.15":
version: 7.22.15
resolution: "@babel/template@npm:7.22.15"
dependencies:
"@babel/code-frame": ^7.22.13
"@babel/parser": ^7.22.15
"@babel/types": ^7.22.15
checksum: 9312edd37cf1311d738907003f2aa321a88a42ba223c69209abe4d7111db019d321805504f606c7fd75f21c6cf9d24d0a8223104cd21ebd207e241b6c551f454
languageName: node
linkType: hard
"@babel/traverse@npm:^7.1.0, @babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.12.11, @babel/traverse@npm:^7.12.9, @babel/traverse@npm:^7.13.0, @babel/traverse@npm:^7.20.10, @babel/traverse@npm:^7.20.12, @babel/traverse@npm:^7.20.5, @babel/traverse@npm:^7.20.7, @babel/traverse@npm:^7.7.2":
version: 7.20.12
resolution: "@babel/traverse@npm:7.20.12"
@ -1766,6 +1929,17 @@ __metadata:
languageName: node
linkType: hard
"@babel/types@npm:^7.22.15, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0":
version: 7.23.0
resolution: "@babel/types@npm:7.23.0"
dependencies:
"@babel/helper-string-parser": ^7.22.5
"@babel/helper-validator-identifier": ^7.22.20
to-fast-properties: ^2.0.0
checksum: 70e4db41acb6793d0eb8d81a2fa88f19ee661219b84bd5f703dbdb54eb3a4d3c0dfc55e69034c945b479df9f43fd4b1376480aaccfc19797ce5af1c5d2576b36
languageName: node
linkType: hard
"@base2/pretty-print-object@npm:1.0.1":
version: 1.0.1
resolution: "@base2/pretty-print-object@npm:1.0.1"
@ -8044,7 +8218,7 @@ __metadata:
languageName: node
linkType: hard
"chalk@npm:^2.0.0, chalk@npm:^2.0.1, chalk@npm:^2.4.1":
"chalk@npm:^2.0.0, chalk@npm:^2.0.1, chalk@npm:^2.4.1, chalk@npm:^2.4.2":
version: 2.4.2
resolution: "chalk@npm:2.4.2"
dependencies:
@ -17558,6 +17732,7 @@ __metadata:
"@babel/plugin-proposal-class-properties": ^7.17.12
"@babel/plugin-proposal-decorators": ^7.17.12
"@babel/plugin-proposal-private-methods": ^7.10.4
"@babel/plugin-proposal-private-property-in-object": ^7.21.11
"@babel/plugin-syntax-bigint": ^7.8.3
"@babel/plugin-transform-runtime": ^7.17.12
"@babel/preset-env": ^7.17.12
@ -21852,6 +22027,15 @@ __metadata:
languageName: node
linkType: hard
"semver@npm:^6.3.1":
version: 6.3.1
resolution: "semver@npm:6.3.1"
bin:
semver: bin/semver.js
checksum: e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d
languageName: node
linkType: hard
"semver@npm:^7.5.3":
version: 7.5.4
resolution: "semver@npm:7.5.4"

View file

@ -7,7 +7,7 @@ then
pwd
cd tracker/tracker
npm run lint-front
bun run lint-front
cd ../../
fi
@ -17,7 +17,7 @@ then
echo "tracker-assist"
cd tracker/tracker-assist
npm run lint-front
bun run lint-front
cd ../../
fi

BIN
tracker/tracker-assist/bun.lockb Executable file

Binary file not shown.

View file

@ -22,7 +22,7 @@
"zustand": "^4.1.1"
},
"scripts": {
"start": "HOST=0.0.0.0 react-scripts start",
"start": "HOST=0.0.0.0 react-scripts --openssl-legacy-provider start",
"build": "NODE_OPTIONS=--openssl-legacy-provider react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"

View file

@ -2,6 +2,10 @@
The main package of the [OpenReplay](https://openreplay.com/) tracker.
## Development & Contribution
Please use [bun](https://bun.sh/) to install and build this library. Any submitted pull request must pass **all tests** and should have positive test coverage diff %.
## Documentation
For launch options and available public methods, [refer to the documentation](https://docs.openreplay.com/installation/javascript-sdk#options)

BIN
tracker/tracker/bun.lockb Executable file

Binary file not shown.

View file

@ -1,7 +1,7 @@
{
"name": "@openreplay/tracker",
"description": "The OpenReplay tracker main package",
"version": "10.0.0",
"version": "10.0.1-1",
"keywords": [
"logging",
"replay"
@ -19,13 +19,13 @@
"tscRun": "tsc -b src/main && tsc -b src/webworker && tsc --project src/main/tsconfig-cjs.json",
"rollup": "rollup --config rollup.config.js",
"compile": "node --experimental-modules --experimental-json-modules scripts/compile.cjs",
"build": "npm run clean && npm run tscRun && npm run rollup && npm run compile",
"build": "bun run clean && bun run tscRun && bun run rollup && bun run compile",
"prepare": "cd ../../ && husky install tracker/.husky/",
"lint-front": "lint-staged",
"test": "jest --coverage=false",
"test:ci": "jest --coverage=true",
"postversion": "npm run build",
"prepublishOnly": "npm run build"
"postversion": "bun run build",
"prepublishOnly": "bun run build"
},
"devDependencies": {
"@babel/core": "^7.10.2",

View file

@ -1,6 +1,14 @@
import type Message from './messages.gen.js'
import { Timestamp, Metadata, UserID, Type as MType, TabChange, TabData } from './messages.gen.js'
import { now, adjustTimeOrigin, deprecationWarn, inIframe } from '../utils.js'
import {
now,
adjustTimeOrigin,
deprecationWarn,
inIframe,
createEventListener,
deleteEventListener,
requestIdleCb,
} from '../utils.js'
import Nodes from './nodes.js'
import Observer from './observer/top_observer.js'
import Sanitizer from './sanitizer.js'
@ -338,12 +346,15 @@ export default class App {
}
private commit(): void {
if (this.worker && this.messages.length) {
if (this.worker !== undefined && this.messages.length) {
requestIdleCb(() => {
this.messages.unshift(TabData(this.session.getTabId()))
this.messages.unshift(Timestamp(this.timestamp()))
this.worker.postMessage(this.messages)
// ? why I need to do this?
this.worker!.postMessage(this.messages)
this.commitCallbacks.forEach((cb) => cb(this.messages))
this.messages.length = 0
})
}
}
@ -397,8 +408,14 @@ export default class App {
if (useSafe) {
listener = this.safe(listener)
}
this.attachStartCallback(() => target?.addEventListener(type, listener, useCapture), useSafe)
this.attachStopCallback(() => target?.removeEventListener(type, listener, useCapture), useSafe)
this.attachStartCallback(
() => (target ? createEventListener(target, type, listener, useCapture) : null),
useSafe,
)
this.attachStopCallback(
() => (target ? deleteEventListener(target, type, listener, useCapture) : null),
useSafe,
)
}
// TODO: full correct semantic

View file

@ -5,7 +5,7 @@ export const LogLevel = {
Errors: 2,
Silent: 0,
} as const
type LogLevel = typeof LogLevel[keyof typeof LogLevel]
type LogLevel = (typeof LogLevel)[keyof typeof LogLevel]
type CustomLevel = {
error: boolean

View file

@ -1,3 +1,5 @@
import { createEventListener, deleteEventListener } from '../utils.js'
type NodeCallback = (node: Node, isStart: boolean) => void
type ElementListener = [string, EventListener, boolean]
@ -19,7 +21,7 @@ export default class Nodes {
if (id === undefined) {
return
}
node.addEventListener(type, listener, useCapture)
createEventListener(node, type, listener, useCapture)
let listeners = this.elementListeners.get(id)
if (listeners === undefined) {
listeners = []
@ -49,7 +51,7 @@ export default class Nodes {
if (listeners !== undefined) {
this.elementListeners.delete(id)
listeners.forEach((listener) =>
node.removeEventListener(listener[0], listener[1], listener[2]),
deleteEventListener(node, listener[0], listener[1], listener[2]),
)
}
this.totalNodeAmount--

View file

@ -1,3 +1,4 @@
import { createMutationObserver, ngSafeBrowserMethod } from '../../utils.js'
import {
RemoveNodeAttribute,
SetNodeAttributeURLBased,
@ -66,8 +67,11 @@ export default abstract class Observer {
private readonly indexes: Array<number> = []
private readonly attributesMap: Map<number, Set<string>> = new Map()
private readonly textSet: Set<number> = new Set()
constructor(protected readonly app: App, protected readonly isTopContext = false) {
this.observer = new MutationObserver(
constructor(
protected readonly app: App,
protected readonly isTopContext = false,
) {
this.observer = createMutationObserver(
this.app.safe((mutations) => {
for (const mutation of mutations) {
// mutations order is sequential
@ -114,7 +118,7 @@ export default abstract class Observer {
}
}
this.commitNodes()
}),
}) as MutationCallback,
)
}
private clear(): void {

View file

@ -24,7 +24,10 @@ export default class Sanitizer {
private readonly hidden: Set<number> = new Set()
private readonly options: Options
constructor(private readonly app: App, options: Partial<Options>) {
constructor(
private readonly app: App,
options: Partial<Options>,
) {
this.options = Object.assign(
{
obscureTextEmails: true,

View file

@ -35,7 +35,10 @@ export default class Session {
private tabId: string
public userInfo: UserInfo
constructor(private readonly app: App, private readonly options: Options) {
constructor(
private readonly app: App,
private readonly options: Options,
) {
this.createTabId()
}

View file

@ -18,7 +18,10 @@ export class StringDictionary {
export default class AttributeSender {
private dict = new StringDictionary()
constructor(private readonly app: App, private readonly isDictDisabled: boolean) {}
constructor(
private readonly app: App,
private readonly isDictDisabled: boolean,
) {}
public sendSetAttribute(id: number, name: string, value: string) {
if (this.isDictDisabled) {

View file

@ -1,5 +1,5 @@
import type App from '../app/index.js'
import { isURL, IS_FIREFOX, MAX_STR_LEN } from '../utils.js'
import { isURL, IS_FIREFOX, MAX_STR_LEN, createMutationObserver } from '../utils.js'
import { ResourceTiming, SetNodeAttributeURLBased } from '../app/messages.gen.js'
import { hasTag } from '../app/guards.js'
@ -81,8 +81,8 @@ export default function (app: App): void {
sendSrcset(id, img)
}
})
const observer = new MutationObserver((mutations) => {
const observer = createMutationObserver(
app.safe((mutations) => {
for (const mutation of mutations) {
if (mutation.type === 'attributes') {
const target = mutation.target as HTMLImageElement
@ -98,7 +98,8 @@ export default function (app: App): void {
}
}
}
})
}) as MutationCallback,
)
app.attachStopCallback(() => {
observer.disconnect()

View file

@ -113,3 +113,67 @@ export function inIframe() {
return true
}
}
/**
* Because angular devs decided that its a good idea to override a browser apis
* we need to use this to achieve safe behavior
* */
export function ngSafeBrowserMethod(method: string): string {
// @ts-ignore
return window.Zone && '__symbol__' in window.Zone
? // @ts-ignore
window['Zone']['__symbol__'](method)
: method
}
export function createMutationObserver(cb: MutationCallback) {
const mObserver = ngSafeBrowserMethod('MutationObserver') as 'MutationObserver'
return new window[mObserver](cb)
}
export function createEventListener(
target: EventTarget,
event: string,
cb: EventListenerOrEventListenerObject,
capture?: boolean,
) {
const safeAddEventListener = ngSafeBrowserMethod('addEventListener') as 'addEventListener'
target[safeAddEventListener](event, cb, capture)
}
export function deleteEventListener(
target: EventTarget,
event: string,
cb: EventListenerOrEventListenerObject,
capture?: boolean,
) {
const safeRemoveEventListener = ngSafeBrowserMethod(
'removeEventListener',
) as 'removeEventListener'
target[safeRemoveEventListener](event, cb, capture)
}
/**
* This is a brief polyfill that suits our needs
* I took inspiration from Microsoft Clarity polyfill on this one
* then adapted it a little bit
*
* I'm very grateful for their bright idea
* */
export function requestIdleCb(callback: () => void) {
const taskTimeout = 3000
if (window.requestIdleCallback) {
return window.requestIdleCallback(callback, { timeout: taskTimeout })
} else {
const channel = new MessageChannel()
const incoming = channel.port1
const outgoing = channel.port2
incoming.onmessage = (): void => {
callback()
}
requestAnimationFrame((): void => {
outgoing.postMessage(1)
})
}
}

View file

@ -11,6 +11,8 @@ import {
hasOpenreplayAttribute,
canAccessIframe,
generateRandomId,
ngSafeBrowserMethod,
requestIdleCb,
} from '../main/utils.js'
describe('adjustTimeOrigin', () => {
@ -184,3 +186,59 @@ describe('generateRandomId', () => {
expect(/^[0-9a-f]+$/.test(id)).toBe(true)
})
})
describe('ngSafeBrowserMethod', () => {
test('returns the method as-is if Zone and __symbol__ are not in window.Zone', () => {
//@ts-ignore
window.Zone = undefined // Ensure Zone is not in the window object
expect(ngSafeBrowserMethod('someMethod')).toBe('someMethod')
})
test('returns the __symbol__ of the method if Zone and __symbol__ are in window.Zone', () => {
//@ts-ignore
window.Zone = {
__symbol__: (method: string) => `__${method}__`,
}
expect(ngSafeBrowserMethod('someMethod')).toBe('__someMethod__')
})
})
describe('requestIdleCb', () => {
test('uses window.requestIdleCallback when available', () => {
const callback = jest.fn()
// @ts-ignore
window.requestIdleCallback = callback
requestIdleCb(callback)
expect(callback).toBeCalled()
})
test('falls back to using a MessageChannel if requestIdleCallback is not available', () => {
const callback = jest.fn()
class MessageChannelMock {
port1 = {
// @ts-ignore
postMessage: (v: any) => this.port2.onmessage(v),
onmessage: null,
}
port2 = {
onmessage: null,
// @ts-ignore
postMessage: (v: any) => this.port1.onmessage(v),
}
}
// @ts-ignore
globalThis.MessageChannel = MessageChannelMock
// @ts-ignore
globalThis.requestAnimationFrame = (cb: () => void) => cb()
// @ts-ignore
window.requestIdleCallback = undefined
requestIdleCb(callback)
// You can assert that the callback was called using the MessageChannel approach.
// This is more challenging to test, so it's recommended to mock MessageChannel.
expect(callback).toBeCalled()
})
})