From 7f09a2ef87edcc4ceb920bc0e10b08baf165d3dd Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 19 Aug 2024 13:32:04 +0200 Subject: [PATCH 01/53] add jest-config dev package --- dev-packages/jest-config/README.md | 3 + dev-packages/jest-config/package.json | 26 + dev-packages/jest-config/src/jest.config.js | 29 + package.json | 5 +- packages/core/jest.config.js | 2 +- packages/core/package.json | 4 + yarn.lock | 791 ++++++++++++++++++-- 7 files changed, 791 insertions(+), 69 deletions(-) create mode 100644 dev-packages/jest-config/README.md create mode 100644 dev-packages/jest-config/package.json create mode 100644 dev-packages/jest-config/src/jest.config.js diff --git a/dev-packages/jest-config/README.md b/dev-packages/jest-config/README.md new file mode 100644 index 000000000000..c49c95215373 --- /dev/null +++ b/dev-packages/jest-config/README.md @@ -0,0 +1,3 @@ +# `@sentry-internal/jest-config` + +A package containing the base Jest config for the sentry-javascript SDK repo diff --git a/dev-packages/jest-config/package.json b/dev-packages/jest-config/package.json new file mode 100644 index 000000000000..f34ca76332ce --- /dev/null +++ b/dev-packages/jest-config/package.json @@ -0,0 +1,26 @@ +{ + "private": true, + "version": "8.26.0", + "name": "@sentry-internal/jest-config", + "author": "Sentry", + "license": "MIT", + "main": "./src/jest.config.js", + "files": [ + "src" + ], + "exports": { + "./package.json": "./package.json", + ".": { + "require": { + "default": "./src/jest.config.js" + } + } + }, + "sideEffects": false, + "engines": { + "node": ">=14.18" + }, + "volta": { + "extends": "../../package.json" + } +} diff --git a/dev-packages/jest-config/src/jest.config.js b/dev-packages/jest-config/src/jest.config.js new file mode 100644 index 000000000000..6bb8d30df35e --- /dev/null +++ b/dev-packages/jest-config/src/jest.config.js @@ -0,0 +1,29 @@ +module.exports = { + // this is the package root, even when tests are being run at the repo level + rootDir: process.cwd(), + collectCoverage: true, + transform: { + '^.+\\.ts$': 'ts-jest', + '^.+\\.tsx$': 'ts-jest', + }, + coverageDirectory: '/coverage', + moduleFileExtensions: ['js', 'ts', 'tsx'], + testMatch: ['/**/*.test.ts', '/**/*.test.tsx'], + moduleNameMapper: { + '^axios$': require.resolve('axios'), + }, + globals: { + 'ts-jest': { + tsconfig: '/tsconfig.test.json', + }, + __DEBUG_BUILD__: true, + }, + testPathIgnorePatterns: ['/build/', '/node_modules/'], + + // On CI, we do not need the pretty CLI output, as it makes logs harder to parse + ...(process.env.CI + ? { + coverageReporters: ['json', 'lcov', 'clover'], + } + : {}), +}; diff --git a/package.json b/package.json index beba7d79d284..188d842f2968 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,8 @@ "dev-packages/test-utils", "dev-packages/size-limit-gh-action", "dev-packages/external-contributor-gh-action", - "dev-packages/rollup-utils" + "dev-packages/rollup-utils", + "dev-packages/jest-config" ], "devDependencies": { "@biomejs/biome": "^1.4.0", @@ -108,6 +109,8 @@ "@size-limit/file": "~11.1.0", "@size-limit/webpack": "~11.1.0", "@strictsoftware/typedoc-plugin-monorepo": "^0.3.1", + "@stryker-mutator/core": "^8.5.0", + "@stryker-mutator/jest-runner": "^8.5.0", "@types/jest": "^27.4.1", "@types/jsdom": "^21.1.6", "@types/node": "^14.18.0", diff --git a/packages/core/jest.config.js b/packages/core/jest.config.js index 24f49ab59a4c..8cdf86519208 100644 --- a/packages/core/jest.config.js +++ b/packages/core/jest.config.js @@ -1 +1 @@ -module.exports = require('../../jest/jest.config.js'); +module.exports = require('@sentry-internal/jest-config'); diff --git a/packages/core/package.json b/packages/core/package.json index 8f140bfbb09c..3a603c63c561 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -42,6 +42,9 @@ "@sentry/types": "8.26.0", "@sentry/utils": "8.26.0" }, + "devDependencies": { + "@sentry-internal/jest-config": "8.26.0" + }, "scripts": { "build": "run-p build:transpile build:types", "build:dev": "yarn build", @@ -60,6 +63,7 @@ "lint": "eslint . --format stylish", "test": "jest", "test:watch": "jest --watch", + "test:mutation": "stryker run", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/yarn.lock b/yarn.lock index 481175f8db61..34dc60261848 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1141,6 +1141,11 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.7.tgz#d23bbea508c3883ba8251fb4164982c36ea577ed" integrity sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw== +"@babel/compat-data@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.2.tgz#e41928bd33475305c586f6acbbb7e3ade7a6f7f5" + integrity sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ== + "@babel/core@7.18.10": version "7.18.10" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.10.tgz#39ad504991d77f1f3da91be0b8b949a5bc466fb8" @@ -1288,6 +1293,27 @@ json5 "^2.2.3" semver "^6.3.1" +"@babel/core@~7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77" + integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.0" + "@babel/helper-compilation-targets" "^7.25.2" + "@babel/helper-module-transforms" "^7.25.2" + "@babel/helpers" "^7.25.0" + "@babel/parser" "^7.25.0" + "@babel/template" "^7.25.0" + "@babel/traverse" "^7.25.2" + "@babel/types" "^7.25.2" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + "@babel/generator@7.18.12": version "7.18.12" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.12.tgz#fa58daa303757bd6f5e4bbca91b342040463d9f4" @@ -1356,6 +1382,16 @@ "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" +"@babel/generator@^7.25.0", "@babel/generator@~7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.0.tgz#f858ddfa984350bc3d3b7f125073c9af6988f18e" + integrity sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw== + dependencies: + "@babel/types" "^7.25.0" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^2.5.1" + "@babel/helper-annotate-as-pure@7.18.6", "@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" @@ -1446,6 +1482,17 @@ lru-cache "^5.1.1" semver "^6.3.1" +"@babel/helper-compilation-targets@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c" + integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw== + dependencies: + "@babel/compat-data" "^7.25.2" + "@babel/helper-validator-option" "^7.24.8" + browserslist "^4.23.1" + lru-cache "^5.1.1" + semver "^6.3.1" + "@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.19.0", "@babel/helper-create-class-features-plugin@^7.5.5": version "7.19.0" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz#bfd6904620df4e46470bae4850d66be1054c404b" @@ -1489,6 +1536,19 @@ "@babel/helper-split-export-declaration" "^7.24.7" semver "^6.3.1" +"@babel/helper-create-class-features-plugin@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.0.tgz#a109bf9c3d58dfed83aaf42e85633c89f43a6253" + integrity sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-member-expression-to-functions" "^7.24.8" + "@babel/helper-optimise-call-expression" "^7.24.7" + "@babel/helper-replace-supers" "^7.25.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" + "@babel/traverse" "^7.25.0" + semver "^6.3.1" + "@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.19.0": version "7.19.0" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz#7976aca61c0984202baca73d84e2337a5424a41b" @@ -1634,6 +1694,14 @@ "@babel/traverse" "^7.24.7" "@babel/types" "^7.24.7" +"@babel/helper-member-expression-to-functions@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz#6155e079c913357d24a4c20480db7c712a5c3fb6" + integrity sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA== + dependencies: + "@babel/traverse" "^7.24.8" + "@babel/types" "^7.24.8" + "@babel/helper-module-imports@7.18.6", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" @@ -1710,6 +1778,16 @@ "@babel/helper-split-export-declaration" "^7.24.7" "@babel/helper-validator-identifier" "^7.24.7" +"@babel/helper-module-transforms@^7.24.8", "@babel/helper-module-transforms@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6" + integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ== + dependencies: + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-simple-access" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" + "@babel/traverse" "^7.25.2" + "@babel/helper-optimise-call-expression@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" @@ -1756,6 +1834,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz#98c84fe6fe3d0d3ae7bfc3a5e166a46844feb2a0" integrity sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg== +"@babel/helper-plugin-utils@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878" + integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg== + "@babel/helper-remap-async-to-generator@^7.18.6", "@babel/helper-remap-async-to-generator@^7.18.9": version "7.18.9" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" @@ -1804,6 +1887,15 @@ "@babel/helper-member-expression-to-functions" "^7.24.7" "@babel/helper-optimise-call-expression" "^7.24.7" +"@babel/helper-replace-supers@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz#ff44deac1c9f619523fe2ca1fd650773792000a9" + integrity sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.24.8" + "@babel/helper-optimise-call-expression" "^7.24.7" + "@babel/traverse" "^7.25.0" + "@babel/helper-simple-access@^7.19.4", "@babel/helper-simple-access@^7.20.2": version "7.20.2" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz#0ab452687fe0c2cfb1e2b9e0015de07fc2d62dd9" @@ -1894,6 +1986,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz#4d2d0f14820ede3b9807ea5fc36dfc8cd7da07f2" integrity sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg== +"@babel/helper-string-parser@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" + integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== + "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": version "7.19.1" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" @@ -1929,6 +2026,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz#24c3bb77c7a425d1742eec8fb433b5a1b38e62f6" integrity sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw== +"@babel/helper-validator-option@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" + integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== + "@babel/helper-wrap-function@^7.18.9": version "7.19.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz#89f18335cff1152373222f76a4b37799636ae8b1" @@ -2001,6 +2103,14 @@ "@babel/template" "^7.24.7" "@babel/types" "^7.24.7" +"@babel/helpers@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.0.tgz#e69beb7841cb93a6505531ede34f34e6a073650a" + integrity sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw== + dependencies: + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.0" + "@babel/highlight@^7.10.4", "@babel/highlight@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" @@ -2103,6 +2213,13 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88" integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== +"@babel/parser@^7.25.0", "@babel/parser@^7.25.3", "@babel/parser@~7.25.0": + version "7.25.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.3.tgz#91fb126768d944966263f0657ab222a642b82065" + integrity sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw== + dependencies: + "@babel/types" "^7.25.2" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.24.4": version "7.24.4" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz#6125f0158543fb4edf1c22f322f3db67f21cb3e1" @@ -2218,7 +2335,7 @@ "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-decorators" "^7.24.1" -"@babel/plugin-proposal-decorators@^7.23.0": +"@babel/plugin-proposal-decorators@^7.23.0", "@babel/plugin-proposal-decorators@~7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.7.tgz#7e2dcfeda4a42596b57c4c9de1f5176bbfc532e3" integrity sha512-RL9GR0pUG5Kc8BUWLNDm2T5OpYwSX15r98I0IkgmRQTXuELq/OynH8xtMTMvTJFjXbMWFVTKtYkTaYQsuAwQlQ== @@ -2235,6 +2352,14 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-dynamic-import" "^7.8.3" +"@babel/plugin-proposal-explicit-resource-management@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-explicit-resource-management/-/plugin-proposal-explicit-resource-management-7.24.7.tgz#9b4bbf1cac69dccdab3fb1833efb38bf96fd8748" + integrity sha512-sYvUjHrKctxFiNe/YFyzNyXoblzP4YaZrWSk0js7QU3Lw2lYjLAxnzV8l/4+7PB5+NDFKGblPUq2YbdTxs3Ppg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/plugin-syntax-explicit-resource-management" "^7.24.7" + "@babel/plugin-proposal-export-namespace-from@^7.18.9": version "7.18.9" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz#5f7313ab348cdb19d590145f9247540e94761203" @@ -2411,6 +2536,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-explicit-resource-management@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-explicit-resource-management/-/plugin-syntax-explicit-resource-management-7.24.7.tgz#967236d403d9c6f9ded538abb6ca757136dd468a" + integrity sha512-gEl7s4tkyWl3EcfUCLVcJJRSogDQju6qX2hdJmZVO0wdpVGzss5bJU8wySoZ7JQw1jBjztEY1a/eYstgv+AQkA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/plugin-syntax-export-namespace-from@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" @@ -2460,7 +2592,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.18.6", "@babel/plugin-syntax-jsx@^7.23.3": +"@babel/plugin-syntax-jsx@^7.18.6", "@babel/plugin-syntax-jsx@^7.23.3", "@babel/plugin-syntax-jsx@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz#39a1fa4a7e3d3d7f34e2acc6be585b718d30e02d" integrity sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ== @@ -2884,6 +3016,15 @@ "@babel/helper-plugin-utils" "^7.24.0" "@babel/helper-simple-access" "^7.22.5" +"@babel/plugin-transform-modules-commonjs@^7.24.7": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz#ab6421e564b717cb475d6fff70ae7f103536ea3c" + integrity sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA== + dependencies: + "@babel/helper-module-transforms" "^7.24.8" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-simple-access" "^7.24.7" + "@babel/plugin-transform-modules-systemjs@^7.18.9", "@babel/plugin-transform-modules-systemjs@^7.24.1": version "7.24.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz#2b9625a3d4e445babac9788daec39094e6b11e3e" @@ -3228,6 +3369,17 @@ "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-typescript" "^7.24.7" +"@babel/plugin-transform-typescript@^7.24.7": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.2.tgz#237c5d10de6d493be31637c6b9fa30b6c5461add" + integrity sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-create-class-features-plugin" "^7.25.0" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" + "@babel/plugin-syntax-typescript" "^7.24.7" + "@babel/plugin-transform-typescript@~7.4.0": version "7.4.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.4.5.tgz#ab3351ba35307b79981993536c93ff8be050ba28" @@ -3577,6 +3729,17 @@ "@babel/helper-validator-option" "^7.16.7" "@babel/plugin-transform-typescript" "^7.16.7" +"@babel/preset-typescript@~7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz#66cd86ea8f8c014855671d5ea9a737139cbbfef1" + integrity sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-validator-option" "^7.24.7" + "@babel/plugin-syntax-jsx" "^7.24.7" + "@babel/plugin-transform-modules-commonjs" "^7.24.7" + "@babel/plugin-transform-typescript" "^7.24.7" + "@babel/regjsgen@^0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" @@ -3651,6 +3814,15 @@ "@babel/parser" "^7.24.0" "@babel/types" "^7.24.0" +"@babel/template@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" + integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/parser" "^7.25.0" + "@babel/types" "^7.25.0" + "@babel/traverse@^7.13.0", "@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1", "@babel/traverse@^7.22.10", "@babel/traverse@^7.23.0", "@babel/traverse@^7.4.5", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" @@ -3715,6 +3887,19 @@ debug "^4.3.1" globals "^11.1.0" +"@babel/traverse@^7.24.8", "@babel/traverse@^7.25.0", "@babel/traverse@^7.25.2": + version "7.25.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.3.tgz#f1b901951c83eda2f3e29450ce92743783373490" + integrity sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.0" + "@babel/parser" "^7.25.3" + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.2" + debug "^4.3.1" + globals "^11.1.0" + "@babel/types@7.20.7", "@babel/types@^7.20.7": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.7.tgz#54ec75e252318423fc07fb644dc6a58a64c09b7f" @@ -3778,6 +3963,15 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@babel/types@^7.24.8", "@babel/types@^7.25.0", "@babel/types@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.2.tgz#55fb231f7dc958cd69ea141a4c2997e819646125" + integrity sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q== + dependencies: + "@babel/helper-string-parser" "^7.24.8" + "@babel/helper-validator-identifier" "^7.24.7" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -5682,6 +5876,145 @@ resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== +"@inquirer/checkbox@^2.4.7": + version "2.4.7" + resolved "https://registry.yarnpkg.com/@inquirer/checkbox/-/checkbox-2.4.7.tgz#0a2867a3a8c5853c79e43e99634e80c1721934ca" + integrity sha512-5YwCySyV1UEgqzz34gNsC38eKxRBtlRDpJLlKcRtTjlYA/yDKuc1rfw+hjw+2WJxbAZtaDPsRl5Zk7J14SBoBw== + dependencies: + "@inquirer/core" "^9.0.10" + "@inquirer/figures" "^1.0.5" + "@inquirer/type" "^1.5.2" + ansi-escapes "^4.3.2" + yoctocolors-cjs "^2.1.2" + +"@inquirer/confirm@^3.1.22": + version "3.1.22" + resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-3.1.22.tgz#23990624c11f60c6f7a5b0558c7505c35076a037" + integrity sha512-gsAKIOWBm2Q87CDfs9fEo7wJT3fwWIJfnDGMn9Qy74gBnNFOACDNfhUzovubbJjWnKLGBln7/NcSmZwj5DuEXg== + dependencies: + "@inquirer/core" "^9.0.10" + "@inquirer/type" "^1.5.2" + +"@inquirer/core@^9.0.10": + version "9.0.10" + resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-9.0.10.tgz#4270191e2ad3bea6223530a093dd9479bcbc7dd0" + integrity sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA== + dependencies: + "@inquirer/figures" "^1.0.5" + "@inquirer/type" "^1.5.2" + "@types/mute-stream" "^0.0.4" + "@types/node" "^22.1.0" + "@types/wrap-ansi" "^3.0.0" + ansi-escapes "^4.3.2" + cli-spinners "^2.9.2" + cli-width "^4.1.0" + mute-stream "^1.0.0" + signal-exit "^4.1.0" + strip-ansi "^6.0.1" + wrap-ansi "^6.2.0" + yoctocolors-cjs "^2.1.2" + +"@inquirer/editor@^2.1.22": + version "2.1.22" + resolved "https://registry.yarnpkg.com/@inquirer/editor/-/editor-2.1.22.tgz#f97eda20954da1dab47df9f4c3ae11604d56360c" + integrity sha512-K1QwTu7GCK+nKOVRBp5HY9jt3DXOfPGPr6WRDrPImkcJRelG9UTx2cAtK1liXmibRrzJlTWOwqgWT3k2XnS62w== + dependencies: + "@inquirer/core" "^9.0.10" + "@inquirer/type" "^1.5.2" + external-editor "^3.1.0" + +"@inquirer/expand@^2.1.22": + version "2.1.22" + resolved "https://registry.yarnpkg.com/@inquirer/expand/-/expand-2.1.22.tgz#7593e93a516a49434629c41f3738479c8234d2df" + integrity sha512-wTZOBkzH+ItPuZ3ZPa9lynBsdMp6kQ9zbjVPYEtSBG7UulGjg2kQiAnUjgyG4SlntpTce5bOmXAPvE4sguXjpA== + dependencies: + "@inquirer/core" "^9.0.10" + "@inquirer/type" "^1.5.2" + yoctocolors-cjs "^2.1.2" + +"@inquirer/figures@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.5.tgz#57f9a996d64d3e3345d2a3ca04d36912e94f8790" + integrity sha512-79hP/VWdZ2UVc9bFGJnoQ/lQMpL74mGgzSYX1xUqCVk7/v73vJCMw1VuyWN1jGkZ9B3z7THAbySqGbCNefcjfA== + +"@inquirer/input@^2.2.9": + version "2.2.9" + resolved "https://registry.yarnpkg.com/@inquirer/input/-/input-2.2.9.tgz#08fdf9a48e4f6fc64c2d508b9d10afac843f9bd8" + integrity sha512-7Z6N+uzkWM7+xsE+3rJdhdG/+mQgejOVqspoW+w0AbSZnL6nq5tGMEVASaYVWbkoSzecABWwmludO2evU3d31g== + dependencies: + "@inquirer/core" "^9.0.10" + "@inquirer/type" "^1.5.2" + +"@inquirer/number@^1.0.10": + version "1.0.10" + resolved "https://registry.yarnpkg.com/@inquirer/number/-/number-1.0.10.tgz#ac2b440ca57b5de5a231e4898c12d4453683c055" + integrity sha512-kWTxRF8zHjQOn2TJs+XttLioBih6bdc5CcosXIzZsrTY383PXI35DuhIllZKu7CdXFi2rz2BWPN9l0dPsvrQOA== + dependencies: + "@inquirer/core" "^9.0.10" + "@inquirer/type" "^1.5.2" + +"@inquirer/password@^2.1.22": + version "2.1.22" + resolved "https://registry.yarnpkg.com/@inquirer/password/-/password-2.1.22.tgz#ec7ee5709923cf285b3e0ae53eed4fdc3c05b422" + integrity sha512-5Fxt1L9vh3rAKqjYwqsjU4DZsEvY/2Gll+QkqR4yEpy6wvzLxdSgFhUcxfDAOtO4BEoTreWoznC0phagwLU5Kw== + dependencies: + "@inquirer/core" "^9.0.10" + "@inquirer/type" "^1.5.2" + ansi-escapes "^4.3.2" + +"@inquirer/prompts@^5.3.6": + version "5.3.8" + resolved "https://registry.yarnpkg.com/@inquirer/prompts/-/prompts-5.3.8.tgz#f394050d95076c2f1b046be324f06f619b257c3e" + integrity sha512-b2BudQY/Si4Y2a0PdZZL6BeJtl8llgeZa7U2j47aaJSCeAl1e4UI7y8a9bSkO3o/ZbZrgT5muy/34JbsjfIWxA== + dependencies: + "@inquirer/checkbox" "^2.4.7" + "@inquirer/confirm" "^3.1.22" + "@inquirer/editor" "^2.1.22" + "@inquirer/expand" "^2.1.22" + "@inquirer/input" "^2.2.9" + "@inquirer/number" "^1.0.10" + "@inquirer/password" "^2.1.22" + "@inquirer/rawlist" "^2.2.4" + "@inquirer/search" "^1.0.7" + "@inquirer/select" "^2.4.7" + +"@inquirer/rawlist@^2.2.4": + version "2.2.4" + resolved "https://registry.yarnpkg.com/@inquirer/rawlist/-/rawlist-2.2.4.tgz#73d5d4fafa2ca012e6cfb9eb1d8ddf33bab2dde0" + integrity sha512-pb6w9pWrm7EfnYDgQObOurh2d2YH07+eDo3xQBsNAM2GRhliz6wFXGi1thKQ4bN6B0xDd6C3tBsjdr3obsCl3Q== + dependencies: + "@inquirer/core" "^9.0.10" + "@inquirer/type" "^1.5.2" + yoctocolors-cjs "^2.1.2" + +"@inquirer/search@^1.0.7": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@inquirer/search/-/search-1.0.7.tgz#72ab9ccfb57f05dd81a8b2df26214588e048be18" + integrity sha512-p1wpV+3gd1eST/o5N3yQpYEdFNCzSP0Klrl+5bfD3cTTz8BGG6nf4Z07aBW0xjlKIj1Rp0y3x/X4cZYi6TfcLw== + dependencies: + "@inquirer/core" "^9.0.10" + "@inquirer/figures" "^1.0.5" + "@inquirer/type" "^1.5.2" + yoctocolors-cjs "^2.1.2" + +"@inquirer/select@^2.4.7": + version "2.4.7" + resolved "https://registry.yarnpkg.com/@inquirer/select/-/select-2.4.7.tgz#6a23742b4f76d228186dfd42571d973def378ffa" + integrity sha512-JH7XqPEkBpNWp3gPCqWqY8ECbyMoFcCZANlL6pV9hf59qK6dGmkOlx1ydyhY+KZ0c5X74+W6Mtp+nm2QX0/MAQ== + dependencies: + "@inquirer/core" "^9.0.10" + "@inquirer/figures" "^1.0.5" + "@inquirer/type" "^1.5.2" + ansi-escapes "^4.3.2" + yoctocolors-cjs "^2.1.2" + +"@inquirer/type@^1.5.2": + version "1.5.2" + resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-1.5.2.tgz#15f5e4a4dae02c4203650cb07c8a000cdd423939" + integrity sha512-w9qFkumYDCNyDZmNQjf/n6qQuvQ4dMC3BJesY4oF+yr0CxR5vxujflAVeIcS6U336uzi9GM0kAfZlLrZ9UTkpA== + dependencies: + mute-stream "^1.0.0" + "@ioredis/commands@^1.1.1": version "1.2.0" resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" @@ -8108,6 +8441,11 @@ "@angular-devkit/schematics" "14.2.13" jsonc-parser "3.1.0" +"@sec-ant/readable-stream@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz#60de891bb126abfdc5410fdc6166aca065f10a0c" + integrity sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg== + "@sentry-internal/rrdom@2.11.0": version "2.11.0" resolved "https://registry.yarnpkg.com/@sentry-internal/rrdom/-/rrdom-2.11.0.tgz#f7c8f54705ad84ece0e97e53f12e87c687749b32" @@ -8496,6 +8834,11 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz#719df7fb41766bc143369eaa0dd56d8dc87c9958" integrity sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg== +"@sindresorhus/merge-streams@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz#abb11d99aeb6d27f1b563c38147a72d50058e339" + integrity sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ== + "@sinonjs/commons@^1.7.0": version "1.8.2" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.2.tgz#858f5c4b48d80778fde4b9d541f27edc0d56488b" @@ -9072,6 +9415,81 @@ dependencies: highlight.js "^9.15.6" +"@stryker-mutator/api@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@stryker-mutator/api/-/api-8.5.0.tgz#b58b0c15c4c525541a9a6bb78cf1ec469de4beb2" + integrity sha512-dhz6BAbNr6LW96UjJFyxVnGOvJqo+7GdIBJl3Cckg3/Bakn0jL61xZ0ca9pcrbVHivy9vlzMs+dCv2pr9QV9rg== + dependencies: + mutation-testing-metrics "3.2.0" + mutation-testing-report-schema "3.1.1" + tslib "~2.6.3" + typed-inject "~4.0.0" + +"@stryker-mutator/core@^8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@stryker-mutator/core/-/core-8.5.0.tgz#6b6173716e15d99bcbd900063c5917afcbe9a065" + integrity sha512-1bmX0+BImAWK+w9kPl83VchsYgYBMXHngD5i8Se2AEFMP5jj4J4uPOya45fAEVJcY4ooIIuwY3zkFwX6T1Crsw== + dependencies: + "@inquirer/prompts" "^5.3.6" + "@stryker-mutator/api" "8.5.0" + "@stryker-mutator/instrumenter" "8.5.0" + "@stryker-mutator/util" "8.5.0" + ajv "~8.17.1" + chalk "~5.3.0" + commander "~12.1.0" + diff-match-patch "1.0.5" + emoji-regex "~10.3.0" + execa "~9.3.0" + file-url "~4.0.0" + get-port "~7.1.0" + lodash.groupby "~4.6.0" + log4js "~6.9.1" + minimatch "~9.0.5" + mutation-testing-elements "3.2.0" + mutation-testing-metrics "3.2.0" + mutation-testing-report-schema "3.1.1" + npm-run-path "~5.3.0" + progress "~2.0.3" + rxjs "~7.8.1" + semver "^7.6.3" + source-map "~0.7.4" + tree-kill "~1.2.2" + tslib "2.6.3" + typed-inject "~4.0.0" + typed-rest-client "~2.0.2" + +"@stryker-mutator/instrumenter@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@stryker-mutator/instrumenter/-/instrumenter-8.5.0.tgz#868b3aa9ad452d1cf8e63aaa7c14dd60f5ac3a10" + integrity sha512-sA+jXiGxeFuWJjAAJm8XvwpI1z2lxh2+CzpLyTR2d089fnEUoiqFsVHy2NsYxR9xZ5uqDu5FlnBlafXgLui1bw== + dependencies: + "@babel/core" "~7.25.2" + "@babel/generator" "~7.25.0" + "@babel/parser" "~7.25.0" + "@babel/plugin-proposal-decorators" "~7.24.7" + "@babel/plugin-proposal-explicit-resource-management" "^7.24.7" + "@babel/preset-typescript" "~7.24.7" + "@stryker-mutator/api" "8.5.0" + "@stryker-mutator/util" "8.5.0" + angular-html-parser "~6.0.2" + semver "~7.6.3" + weapon-regex "~1.3.2" + +"@stryker-mutator/jest-runner@^8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@stryker-mutator/jest-runner/-/jest-runner-8.5.0.tgz#3464105e4d92aec7b3346b8fdc0fd300a5614ade" + integrity sha512-6UmieXl/6NJ6YtQHWY97O9jdtcQ2OHw4JLE0VMgPPSrrSyXHhU4V1CPYK2gHGPdu87YRGYg3A4BpIDny00fUlg== + dependencies: + "@stryker-mutator/api" "8.5.0" + "@stryker-mutator/util" "8.5.0" + semver "~7.6.3" + tslib "~2.6.3" + +"@stryker-mutator/util@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@stryker-mutator/util/-/util-8.5.0.tgz#66bccae7aedebb96bde6738aac55cce8e81c7f09" + integrity sha512-T1ElpGUDqESKcwuRnfEuroE7N2pEMLTqieWRLIJZsP2ubEfnoHp4aGVL6IjPRdiZr4jetZOLfjlTzddrqrbsvg== + "@sveltejs/kit@^2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@sveltejs/kit/-/kit-2.0.2.tgz#bd02523fe570ddaf89148bffb1eb2233c458054b" @@ -9756,17 +10174,8 @@ dependencies: "@types/unist" "*" -"@types/history-4@npm:@types/history@4.7.8": - version "4.7.8" - resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" - integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== - -"@types/history-5@npm:@types/history@4.7.8": - version "4.7.8" - resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" - integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== - -"@types/history@*": +"@types/history-4@npm:@types/history@4.7.8", "@types/history-5@npm:@types/history@4.7.8", "@types/history@*": + name "@types/history-4" version "4.7.8" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== @@ -9921,6 +10330,13 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.32.tgz#f6cd08939ae3ad886fcc92ef7f0109dacddf61ab" integrity sha512-xPSg0jm4mqgEkNhowKgZFBNtwoEwF6gJ4Dhww+GFpm3IgtNseHQZ5IqdNwnquZEoANxyDAKDRAdVo4Z72VvD/g== +"@types/mute-stream@^0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@types/mute-stream/-/mute-stream-0.0.4.tgz#77208e56a08767af6c5e1237be8888e2f255c478" + integrity sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow== + dependencies: + "@types/node" "*" + "@types/mysql@2.15.22", "@types/mysql@^2.15.21": version "2.15.22" resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.22.tgz#8705edb9872bf4aa9dbc004cd494e00334e5cdb4" @@ -9997,6 +10413,13 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.2.tgz#c076ed1d7b6095078ad3cf21dfeea951842778b1" integrity sha512-1uEQxww3DaghA0RxqHx0O0ppVlo43pJhepY51OxuQIKHpjbnYLA7vcdwioNPzIqmC2u3I/dmylcqjlh0e7AyUA== +"@types/node@^22.1.0": + version "22.4.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.4.1.tgz#9b595d292c65b94c20923159e2ce947731b6fdce" + integrity sha512-1tbpb9325+gPnKK0dMm+/LMriX0vKxf6RnB0SZUqfyVkQ4fMgUSySqhxE/y8Jvs4NyF1yHzTfG9KlnkIODxPKg== + dependencies: + undici-types "~6.19.2" + "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" @@ -10087,15 +10510,7 @@ "@types/history" "^3" "@types/react" "*" -"@types/react-router-4@npm:@types/react-router@5.1.14": - version "5.1.14" - resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.14.tgz#e0442f4eb4c446541ad7435d44a97f8fe6df40da" - integrity sha512-LAJpqYUaCTMT2anZheoidiIymt8MuX286zoVFPM3DVb23aQBH0mAkFvzpd4LKqiolV8bBtZWT5Qp7hClCNDENw== - dependencies: - "@types/history" "*" - "@types/react" "*" - -"@types/react-router-5@npm:@types/react-router@5.1.14": +"@types/react-router-4@npm:@types/react-router@5.1.14", "@types/react-router-5@npm:@types/react-router@5.1.14": version "5.1.14" resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.14.tgz#e0442f4eb4c446541ad7435d44a97f8fe6df40da" integrity sha512-LAJpqYUaCTMT2anZheoidiIymt8MuX286zoVFPM3DVb23aQBH0mAkFvzpd4LKqiolV8bBtZWT5Qp7hClCNDENw== @@ -10265,6 +10680,11 @@ resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz#f066abfcd1cbe66267cdbbf0de010d8a41b41597" integrity sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow== +"@types/wrap-ansi@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd" + integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g== + "@types/ws@^8.5.1": version "8.5.10" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.10.tgz#4acfb517970853fa6574a3a6886791d04a396787" @@ -11614,6 +12034,16 @@ ajv@^8.10.0: require-from-string "^2.0.2" uri-js "^4.2.2" +ajv@~8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + amd-name-resolver@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-1.3.1.tgz#ffe71c683c6e7191fc4ae1bb3aaed15abea135d9" @@ -11627,6 +12057,13 @@ amdefine@>=0.0.4: resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= +angular-html-parser@~6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/angular-html-parser/-/angular-html-parser-6.0.2.tgz#998ea2aeee7d11f737ba433cba81f9f8fd4b211e" + integrity sha512-8+sH1TwYxv8XsQes1psxTHMtWRBbJFA/jY0ThqpT4AgCiRdhTtRxru0vlBfyRJpL9CHd3G06k871bR2vyqaM6A== + dependencies: + tslib "^2.6.2" + ansi-align@^3.0.0, ansi-align@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" @@ -11649,7 +12086,7 @@ ansi-escapes@^3.2.0: resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== -ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0, ansi-escapes@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== @@ -14057,7 +14494,7 @@ chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^5.0.0, chalk@^5.2.0, chalk@^5.3.0: +chalk@^5.0.0, chalk@^5.2.0, chalk@^5.3.0, chalk@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== @@ -14294,6 +14731,11 @@ cli-spinners@^2.9.0: resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.1.tgz#9c0b9dad69a6d47cbb4333c14319b060ed395a35" integrity sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ== +cli-spinners@^2.9.2: + version "2.9.2" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" + integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== + cli-table3@^0.6.0: version "0.6.3" resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2" @@ -14320,6 +14762,11 @@ cli-width@^3.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== +cli-width@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" + integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== + client-only@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" @@ -14544,6 +14991,11 @@ commander@^9.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== +commander@~12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + comment-parser@^0.7.6: version "0.7.6" resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-0.7.6.tgz#0e743a53c8e646c899a1323db31f6cd337b10f12" @@ -15391,6 +15843,11 @@ date-fns@^3.6.0: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-3.6.0.tgz#f20ca4fe94f8b754951b24240676e8618c0206bf" integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww== +date-format@^4.0.14: + version "4.0.14" + resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.14.tgz#7a8e584434fb169a521c8b7aa481f355810d9400" + integrity sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg== + dateformat@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" @@ -15714,6 +16171,14 @@ dequal@^2.0.0, dequal@^2.0.3: resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== +des.js@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da" + integrity sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + destr@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.3.tgz#7f9e97cb3d16dbdca7be52aca1644ce402cfe449" @@ -15846,6 +16311,11 @@ devlop@^1.0.0: dependencies: dequal "^2.0.0" +diff-match-patch@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37" + integrity sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw== + diff-sequences@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" @@ -16905,7 +17375,7 @@ emittery@^0.8.1: resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== -emoji-regex@^10.2.1: +emoji-regex@^10.2.1, emoji-regex@~10.3.0: version "10.3.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.3.0.tgz#76998b9268409eb3dae3de989254d456e70cfe23" integrity sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw== @@ -18195,6 +18665,24 @@ execa@^8.0.1: signal-exit "^4.1.0" strip-final-newline "^3.0.0" +execa@~9.3.0: + version "9.3.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-9.3.1.tgz#09c86ab4dc2ef3de6d34f6568f4bad76ded4fded" + integrity sha512-gdhefCCNy/8tpH/2+ajP9IQc14vXchNdd0weyzSJEFURhRMGncQ+zKFxwjAufIewPEJm9BPOaJnvg2UtlH2gPQ== + dependencies: + "@sindresorhus/merge-streams" "^4.0.0" + cross-spawn "^7.0.3" + figures "^6.1.0" + get-stream "^9.0.0" + human-signals "^8.0.0" + is-plain-obj "^4.1.0" + is-stream "^4.0.1" + npm-run-path "^5.2.0" + pretty-ms "^9.0.0" + signal-exit "^4.1.0" + strip-final-newline "^4.0.0" + yoctocolors "^2.0.0" + exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.1.0.tgz#318d545213d2b2a31499e92c35f74c94196a22f7" @@ -18307,7 +18795,7 @@ extend@^3.0.0, extend@^3.0.2: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -external-editor@^3.0.3: +external-editor@^3.0.3, external-editor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== @@ -18475,6 +18963,11 @@ fast-text-encoding@^1.0.0, fast-text-encoding@^1.0.3: resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz#ec02ac8e01ab8a319af182dae2681213cfe9ce53" integrity sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig== +fast-uri@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" + integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== + fast-xml-parser@4.2.5: version "4.2.5" resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz#a6747a09296a6cb34f2ae634019bf1738f3b421f" @@ -18547,6 +19040,13 @@ figures@^2.0.0: dependencies: escape-string-regexp "^1.0.5" +figures@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-6.1.0.tgz#935479f51865fa7479f6fa94fc6fc7ac14e62c4a" + integrity sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg== + dependencies: + is-unicode-supported "^2.0.0" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -18559,6 +19059,11 @@ file-uri-to-path@1.0.0: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== +file-url@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/file-url/-/file-url-4.0.0.tgz#6fe05262d3187da70bc69889091932b6bc7df270" + integrity sha512-vRCdScQ6j3Ku6Kd7W1kZk9c++5SqD6Xz5Jotrjr/nkY714M14RFHy/AAVA2WQvpsqVAVgTbDrYyBpU205F0cLw== + filelist@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" @@ -18807,7 +19312,7 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== -flatted@^3.3.1: +flatted@^3.2.7, flatted@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== @@ -19244,6 +19749,11 @@ get-port@5.1.1, get-port@^5.1.1: resolved "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== +get-port@~7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-7.1.0.tgz#d5a500ebfc7aa705294ec2b83cc38c5d0e364fec" + integrity sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw== + get-source@^2.0.12: version "2.0.12" resolved "https://registry.yarnpkg.com/get-source/-/get-source-2.0.12.tgz#0b47d57ea1e53ce0d3a69f4f3d277eb8047da944" @@ -19301,6 +19811,14 @@ get-stream@^8.0.1: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== +get-stream@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-9.0.1.tgz#95157d21df8eb90d1647102b63039b1df60ebd27" + integrity sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA== + dependencies: + "@sec-ant/readable-stream" "^0.4.1" + is-stream "^4.0.1" + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -20649,6 +21167,11 @@ human-signals@^5.0.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== +human-signals@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-8.0.0.tgz#2d3d63481c7c2319f0373428b01ffe30da6df852" + integrity sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA== + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -21410,7 +21933,7 @@ is-plain-obj@^3.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== -is-plain-obj@^4.0.0: +is-plain-obj@^4.0.0, is-plain-obj@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== @@ -21523,6 +22046,11 @@ is-stream@^3.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== +is-stream@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-4.0.1.tgz#375cf891e16d2e4baec250b85926cffc14720d9b" + integrity sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A== + is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" @@ -21577,6 +22105,11 @@ is-unicode-supported@^1.1.0, is-unicode-supported@^1.3.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz#d824984b616c292a2e198207d4a609983842f714" integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ== +is-unicode-supported@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz#fdf32df9ae98ff6ab2cedc155a5a6e895701c451" + integrity sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q== + is-url-superb@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-url-superb/-/is-url-superb-4.0.0.tgz#b54d1d2499bb16792748ac967aa3ecb41a33a8c2" @@ -22299,6 +22832,11 @@ js-cleanup@^1.2.0: perf-regexes "^1.0.1" skip-regex "^1.0.2" +js-md4@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/js-md4/-/js-md4-0.3.2.tgz#cd3b3dc045b0c404556c81ddb5756c23e59d7cf5" + integrity sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA== + js-string-escape@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" @@ -23208,6 +23746,11 @@ lodash.get@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== +lodash.groupby@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz#0b08a1dcf68397c397855c3239783832df7403d1" + integrity sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw== + lodash.isarguments@^3.0.0, lodash.isarguments@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" @@ -23330,6 +23873,17 @@ log-symbols@^5.1.0: chalk "^5.0.0" is-unicode-supported "^1.1.0" +log4js@~6.9.1: + version "6.9.1" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.9.1.tgz#aba5a3ff4e7872ae34f8b4c533706753709e38b6" + integrity sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g== + dependencies: + date-format "^4.0.14" + debug "^4.3.4" + flatted "^3.2.7" + rfdc "^1.3.0" + streamroller "^3.1.5" + loglevel@^1.6.8: version "1.8.0" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.0.tgz#e7ec73a57e1e7b419cb6c6ac06bf050b67356114" @@ -24508,6 +25062,13 @@ minimatch@~3.0.4: dependencies: brace-expansion "^1.1.7" +minimatch@~9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -24959,6 +25520,23 @@ mustache@^4.2.0: resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64" integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ== +mutation-testing-elements@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/mutation-testing-elements/-/mutation-testing-elements-3.2.0.tgz#61870f83f52f77d8d89d15d96bb8214583313746" + integrity sha512-zOwr/DGzEv9WW03Sj5IROgsGpOGbKz1ktx0tbCtJArE0VKhPXDtYKi/uKUv8AIUjHHXWGkGvU5WMfyZ/ckRglw== + +mutation-testing-metrics@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/mutation-testing-metrics/-/mutation-testing-metrics-3.2.0.tgz#b89feed6257eee5e8e36b00a56a16736902fa74d" + integrity sha512-PheogUIwu8g4jN6uF9PM5sskBWcZlTSYnANxxYBFvZi3n+2lcd3hLOj+JdHqNEAY1uTsgkmR9Vkh4RtVp8QwSw== + dependencies: + mutation-testing-report-schema "3.1.1" + +mutation-testing-report-schema@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/mutation-testing-report-schema/-/mutation-testing-report-schema-3.1.1.tgz#3695a4932955f7eb4e05a00342bd94c3b445143b" + integrity sha512-lWIbgUEnMEdsY2yymC7SZRBO+6dbZa5tY/Bmw+xjXYPdBxTVlnd2mjKRPZ6FUxgHJ9vMQmQnktMNAKCWZp1H0A== + mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -24969,7 +25547,7 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -mute-stream@~1.0.0: +mute-stream@^1.0.0, mute-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== @@ -25894,6 +26472,13 @@ npm-run-path@^5.1.0: dependencies: path-key "^4.0.0" +npm-run-path@^5.2.0, npm-run-path@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" + integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== + dependencies: + path-key "^4.0.0" + npmlog@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" @@ -26094,6 +26679,11 @@ object-inspect@^1.12.2, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + object-is@^1.0.1: version "1.1.5" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" @@ -26788,6 +27378,11 @@ parse-ms@^2.1.0: resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-2.1.0.tgz#348565a753d4391fa524029956b172cb7753097d" integrity sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA== +parse-ms@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-4.0.0.tgz#c0c058edd47c2a590151a718990533fd62803df4" + integrity sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw== + parse-node-version@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" @@ -28145,6 +28740,13 @@ pretty-ms@^7.0.1: dependencies: parse-ms "^2.1.0" +pretty-ms@^9.0.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-9.1.0.tgz#0ad44de6086454f48a168e5abb3c26f8db1b3253" + integrity sha512-o1piW0n3tgKIKCwk2vpM/vOV13zjJzvP37Ioze54YlTHE06m4tjEbzg9WsKkvTuyYln2DHjo5pY4qrZGI0otpw== + dependencies: + parse-ms "^4.0.0" + printable-characters@^1.0.42: version "1.0.42" resolved "https://registry.yarnpkg.com/printable-characters/-/printable-characters-1.0.42.tgz#3f18e977a9bd8eb37fcc4ff5659d7be90868b3d8" @@ -28206,7 +28808,7 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= -progress@^2.0.0, progress@^2.0.3: +progress@^2.0.0, progress@^2.0.3, progress@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== @@ -28392,6 +28994,13 @@ qs@6.11.0, qs@^6.4.0: dependencies: side-channel "^1.0.4" +qs@^6.10.3: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== + dependencies: + side-channel "^1.0.6" + query-string@^4.2.2: version "4.3.4" resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" @@ -28604,7 +29213,8 @@ react-is@^18.0.0: dependencies: "@remix-run/router" "1.0.2" -"react-router-6@npm:react-router@6.3.0": +"react-router-6@npm:react-router@6.3.0", react-router@6.3.0: + name react-router-6 version "6.3.0" resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.3.0.tgz#3970cc64b4cb4eae0c1ea5203a80334fdd175557" integrity sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ== @@ -28619,13 +29229,6 @@ react-router-dom@^6.2.2: history "^5.2.0" react-router "6.3.0" -react-router@6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.3.0.tgz#3970cc64b4cb4eae0c1ea5203a80334fdd175557" - integrity sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ== - dependencies: - history "^5.2.0" - react@^18.0.0: version "18.0.0" resolved "https://registry.yarnpkg.com/react/-/react-18.0.0.tgz#b468736d1f4a5891f38585ba8e8fb29f91c3cb96" @@ -29509,7 +30112,7 @@ rfdc@^1.2.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== -rfdc@^1.4.1: +rfdc@^1.3.0, rfdc@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== @@ -29775,7 +30378,7 @@ rxjs@6.6.7, rxjs@^6.4.0, rxjs@^6.6.0: dependencies: tslib "^1.9.0" -rxjs@7.8.1, rxjs@^7.8.1: +rxjs@7.8.1, rxjs@^7.8.1, rxjs@~7.8.1: version "7.8.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== @@ -30045,6 +30648,11 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0, semve resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== +semver@^7.6.3, semver@~7.6.3: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + send@0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" @@ -30302,6 +30910,16 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + sift@13.5.2: version "13.5.2" resolved "https://registry.yarnpkg.com/sift/-/sift-13.5.2.tgz#24a715e13c617b086166cd04917d204a591c9da6" @@ -30738,7 +31356,7 @@ source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, sourc resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@0.7.4, source-map@^0.7.4, source-map@~0.7.2: +source-map@0.7.4, source-map@^0.7.4, source-map@~0.7.2, source-map@~0.7.4: version "0.7.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== @@ -31068,6 +31686,15 @@ stream-to-array@^2.3.0: dependencies: any-promise "^1.1.0" +streamroller@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.5.tgz#1263182329a45def1ffaef58d31b15d13d2ee7ff" + integrity sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw== + dependencies: + date-format "^4.0.14" + debug "^4.3.4" + fs-extra "^8.1.0" + streamsearch@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" @@ -31104,16 +31731,7 @@ string-template@~0.2.1: resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0= -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@4.2.3, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@4.2.3, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -31225,14 +31843,7 @@ stringify-object@^3.2.1: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -31297,6 +31908,11 @@ strip-final-newline@^3.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== +strip-final-newline@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-4.0.0.tgz#35a369ec2ac43df356e3edd5dcebb6429aa1fa5c" + integrity sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw== + strip-indent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" @@ -32095,7 +32711,7 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== -tree-kill@1.2.2: +tree-kill@1.2.2, tree-kill@~1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== @@ -32233,7 +32849,7 @@ tslib@2.6.2, tslib@^2.6.2: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== -tslib@2.6.3, tslib@^2.2.0: +tslib@2.6.3, tslib@^2.2.0, tslib@~2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== @@ -32280,7 +32896,7 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" -tunnel@^0.0.6: +tunnel@0.0.6, tunnel@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== @@ -32372,6 +32988,22 @@ typed-assert@^1.0.8: resolved "https://registry.yarnpkg.com/typed-assert/-/typed-assert-1.0.9.tgz#8af9d4f93432c4970ec717e3006f33f135b06213" integrity sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg== +typed-inject@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/typed-inject/-/typed-inject-4.0.0.tgz#133c00ad7ed9d129aeedf4e102fd07cc530d26cb" + integrity sha512-OuBL3G8CJlS/kjbGV/cN8Ni32+ktyyi6ADDZpKvksbX0fYBV5WcukhRCYa7WqLce7dY/Br2dwtmJ9diiadLFpg== + +typed-rest-client@~2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/typed-rest-client/-/typed-rest-client-2.0.2.tgz#82d451b9a219bf8fa688b698b2581327be4b920d" + integrity sha512-rmAQM2gZw/PQpK5+5aSs+I6ZBv4PFC2BT1o+0ADS1SgSejA+14EmbI2Lt8uXwkX7oeOMkwFmg0pHKwe8D9IT5A== + dependencies: + des.js "^1.1.0" + js-md4 "^0.3.2" + qs "^6.10.3" + tunnel "0.0.6" + underscore "^1.12.1" + typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -32561,6 +33193,16 @@ underscore@>=1.8.3: resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e" integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw== +underscore@^1.12.1: + version "1.13.7" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.7.tgz#970e33963af9a7dda228f17ebe8399e5fbe63a10" + integrity sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g== + +undici-types@~6.19.2: + version "6.19.6" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.6.tgz#e218c3df0987f4c0e0008ca00d6b6472d9b89b36" + integrity sha512-e/vggGopEfTKSvj4ihnOLTsqhrKRN3LeO6qSN/GxohhuRv8qH9bNQ4B8W7e/vFL+0XTnmHPB4/kegunZGA4Org== + undici@^5.25.4: version "5.28.3" resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.3.tgz#a731e0eff2c3fcfd41c1169a869062be222d1e5b" @@ -33719,6 +34361,11 @@ wcwidth@^1.0.0, wcwidth@^1.0.1: dependencies: defaults "^1.0.3" +weapon-regex@~1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/weapon-regex/-/weapon-regex-1.3.2.tgz#53bef6d51254e53708d14c86de11496af2e8ad83" + integrity sha512-jtFTAr0F3gmiX10J6+BYgPrZ/yjXhpcxK/j/Lm1fWRLATxfecPgnkd3DqSUkD0AC2wVVyAkMtsgeuiIuELlW3w== + web-encoding@1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/web-encoding/-/web-encoding-1.1.5.tgz#fc810cf7667364a6335c939913f5051d3e0c4864" @@ -34232,7 +34879,7 @@ wrangler@^3.67.1: optionalDependencies: fsevents "~2.3.2" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@7.0.0, wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -34241,10 +34888,10 @@ wrangler@^3.67.1: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@7.0.0, wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== dependencies: ansi-styles "^4.0.0" string-width "^4.1.0" @@ -34534,6 +35181,16 @@ yocto-queue@^1.0.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== +yoctocolors-cjs@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz#f4b905a840a37506813a7acaa28febe97767a242" + integrity sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA== + +yoctocolors@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/yoctocolors/-/yoctocolors-2.1.1.tgz#e0167474e9fbb9e8b3ecca738deaa61dd12e56fc" + integrity sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ== + youch@^3.2.2: version "3.3.3" resolved "https://registry.yarnpkg.com/youch/-/youch-3.3.3.tgz#50cfdf5bc395ce664a5073e31b712ff4a859d928" From 49c8673b2d575539b557ab918f770c491b9c5b74 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 19 Aug 2024 13:33:11 +0200 Subject: [PATCH 02/53] add stryke config file --- packages/core/stryker.config.mjs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 packages/core/stryker.config.mjs diff --git a/packages/core/stryker.config.mjs b/packages/core/stryker.config.mjs new file mode 100644 index 000000000000..bf43e1870724 --- /dev/null +++ b/packages/core/stryker.config.mjs @@ -0,0 +1,10 @@ +/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ +const config = { + packageManager: 'yarn', + reporters: ['html', 'clear-text', 'progress', 'json'], + testRunner: 'jest', + coverageAnalysis: 'perTest', + ignoreStatic: true, +}; + +export default config; From 53fb7f5b4ceeafb3cdd6d80d3c0621ce4c75580e Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 19 Aug 2024 13:34:10 +0200 Subject: [PATCH 03/53] add `/reports` to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3cc2319ea8a9..48f630e1b11e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ build/ # various integration test builds dist/ coverage/ +reports/ scratch/ *.js.map *.pyc From 9d66abe8be030384f9e519c77ab9540de8d2e0c3 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 19 Aug 2024 16:06:25 +0200 Subject: [PATCH 04/53] add stryker to browser and node --- .gitignore | 2 ++ dev-packages/jest-config/src/jest.config.js | 2 +- dev-packages/vitest-config/README.md | 3 ++ dev-packages/vitest-config/package.json | 33 +++++++++++++++++++ dev-packages/vitest-config/src/vite.config.js | 21 ++++++++++++ package.json | 4 ++- packages/browser/package.json | 4 ++- packages/browser/stryker.config.mjs | 10 ++++++ packages/browser/vite.config.ts | 6 ++-- .../core/test/lib/transports/offline.test.ts | 2 +- packages/node/jest.config.js | 2 +- packages/node/package.json | 4 ++- packages/node/stryker.config.mjs | 10 ++++++ .../node/test/helpers/clear-global-scope.ts | 7 ++++ packages/node/test/integration/scope.test.ts | 2 +- .../test/integrations/contextlines.test.ts | 4 ++- yarn.lock | 9 +++++ 17 files changed, 115 insertions(+), 10 deletions(-) create mode 100644 dev-packages/vitest-config/README.md create mode 100644 dev-packages/vitest-config/package.json create mode 100644 dev-packages/vitest-config/src/vite.config.js create mode 100644 packages/browser/stryker.config.mjs create mode 100644 packages/node/stryker.config.mjs create mode 100644 packages/node/test/helpers/clear-global-scope.ts diff --git a/.gitignore b/.gitignore index 48f630e1b11e..e079be5f90ee 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,8 @@ local.log .rpt2_cache +.stryker-tmp + lint-results.json # legacy diff --git a/dev-packages/jest-config/src/jest.config.js b/dev-packages/jest-config/src/jest.config.js index 6bb8d30df35e..c7a8db440462 100644 --- a/dev-packages/jest-config/src/jest.config.js +++ b/dev-packages/jest-config/src/jest.config.js @@ -18,7 +18,7 @@ module.exports = { }, __DEBUG_BUILD__: true, }, - testPathIgnorePatterns: ['/build/', '/node_modules/'], + testPathIgnorePatterns: ['/build/', '/node_modules/', '/.stryker-tmp/'], // On CI, we do not need the pretty CLI output, as it makes logs harder to parse ...(process.env.CI diff --git a/dev-packages/vitest-config/README.md b/dev-packages/vitest-config/README.md new file mode 100644 index 000000000000..7f3c5c824f54 --- /dev/null +++ b/dev-packages/vitest-config/README.md @@ -0,0 +1,3 @@ +# `@sentry-internal/vitest-config` + +A package containing the base Vitest config for the sentry-javascript SDK repo diff --git a/dev-packages/vitest-config/package.json b/dev-packages/vitest-config/package.json new file mode 100644 index 000000000000..6de0a94d8c6d --- /dev/null +++ b/dev-packages/vitest-config/package.json @@ -0,0 +1,33 @@ +{ + "private": true, + "version": "8.26.0", + "name": "@sentry-internal/vitest-config", + "author": "Sentry", + "license": "MIT", + "main": "./src/vite.config.ts", + "module": "./src/vite.config.ts", + "files": [ + "src" + ], + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "default": "./src/vite.config.js" + }, + "require": { + "default": "./src/vite.config.js" + } + } + }, + "dependencies": { + "vitest": "^1.6.0" + }, + "sideEffects": false, + "engines": { + "node": ">=14.18" + }, + "volta": { + "extends": "../../package.json" + } +} diff --git a/dev-packages/vitest-config/src/vite.config.js b/dev-packages/vitest-config/src/vite.config.js new file mode 100644 index 000000000000..4ed1e90f361a --- /dev/null +++ b/dev-packages/vitest-config/src/vite.config.js @@ -0,0 +1,21 @@ +const { defineConfig } = require('vitest/config'); +const path = require('path'); + +/** + * @type {import('vitest').VitestConfig} + */ +module.exports = defineConfig({ + define: { + __DEBUG_BUILD__: true, + }, + test: { + globals: true, + coverage: { + enabled: true, + reportsDirectory: './coverage', + }, + typecheck: { + tsconfig: path.join(process.cwd(), 'tsconfig.test.json'), + }, + }, +}); diff --git a/package.json b/package.json index 188d842f2968..e1a0eb03ee01 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,8 @@ "dev-packages/size-limit-gh-action", "dev-packages/external-contributor-gh-action", "dev-packages/rollup-utils", - "dev-packages/jest-config" + "dev-packages/jest-config", + "dev-packages/vitest-config" ], "devDependencies": { "@biomejs/biome": "^1.4.0", @@ -111,6 +112,7 @@ "@strictsoftware/typedoc-plugin-monorepo": "^0.3.1", "@stryker-mutator/core": "^8.5.0", "@stryker-mutator/jest-runner": "^8.5.0", + "@stryker-mutator/vitest-runner": "^8.5.0", "@types/jest": "^27.4.1", "@types/jsdom": "^21.1.6", "@types/node": "^14.18.0", diff --git a/packages/browser/package.json b/packages/browser/package.json index 07322e621598..ae61c88770d4 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -49,7 +49,8 @@ }, "devDependencies": { "@sentry-internal/integration-shims": "8.26.0", - "fake-indexeddb": "^4.0.1" + "@sentry-internal/vitest-config": "8.26.0", + "fake-indexeddb": "^4.0.1", }, "scripts": { "build": "run-p build:transpile build:bundle build:types", @@ -72,6 +73,7 @@ "size:check": "cat build/bundles/bundle.min.js | gzip -9 | wc -c | awk '{$1=$1/1024; print \"ES2017: \",$1,\"kB\";}'", "test": "vitest run", "test:watch": "vitest --watch", + "test:mutation": "stryker run", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/browser/stryker.config.mjs b/packages/browser/stryker.config.mjs new file mode 100644 index 000000000000..98f92c75dd9c --- /dev/null +++ b/packages/browser/stryker.config.mjs @@ -0,0 +1,10 @@ +/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ +const config = { + packageManager: 'yarn', + reporters: ['html', 'clear-text', 'progress', 'json'], + testRunner: 'vitest', + coverageAnalysis: 'perTest', + ignoreStatic: true, +}; + +export default config; diff --git a/packages/browser/vite.config.ts b/packages/browser/vite.config.ts index a5523c61f601..e7a48bfa6d90 100644 --- a/packages/browser/vite.config.ts +++ b/packages/browser/vite.config.ts @@ -1,10 +1,12 @@ +import baseConfig from '@sentry-internal/vitest-config'; import { defineConfig } from 'vitest/config'; -import baseConfig from '../../vite/vite.config'; - export default defineConfig({ ...baseConfig, test: { ...baseConfig.test, + typecheck: { + tsconfig: './tsconfig.test.json', + }, }, }); diff --git a/packages/core/test/lib/transports/offline.test.ts b/packages/core/test/lib/transports/offline.test.ts index ea3fa13ffd69..8ad6da4111f3 100644 --- a/packages/core/test/lib/transports/offline.test.ts +++ b/packages/core/test/lib/transports/offline.test.ts @@ -160,7 +160,7 @@ function waitUntil(fn: () => boolean, timeout: number): Promise { }); } -describe('makeOfflineTransport', () => { +describe.skip('makeOfflineTransport', () => { it('Sends envelope and checks the store for further envelopes', async () => { const { getCalls, store } = createTestStore(); const { getSendCount, baseTransport } = createTestTransport({ statusCode: 200 }); diff --git a/packages/node/jest.config.js b/packages/node/jest.config.js index 24f49ab59a4c..8cdf86519208 100644 --- a/packages/node/jest.config.js +++ b/packages/node/jest.config.js @@ -1 +1 @@ -module.exports = require('../../jest/jest.config.js'); +module.exports = require('@sentry-internal/jest-config'); diff --git a/packages/node/package.json b/packages/node/package.json index fa8fa1a797c7..79dbde038948 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -96,7 +96,8 @@ "import-in-the-middle": "^1.11.0" }, "devDependencies": { - "@types/node": "^14.18.0" + "@types/node": "^14.18.0", + "@sentry-internal/jest-config": "8.26.0" }, "optionalDependencies": { "opentelemetry-instrumentation-fetch-node": "1.2.3" @@ -120,6 +121,7 @@ "test": "yarn test:jest", "test:jest": "jest", "test:watch": "jest --watch", + "test:mutation": "stryker run", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/node/stryker.config.mjs b/packages/node/stryker.config.mjs new file mode 100644 index 000000000000..bf43e1870724 --- /dev/null +++ b/packages/node/stryker.config.mjs @@ -0,0 +1,10 @@ +/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ +const config = { + packageManager: 'yarn', + reporters: ['html', 'clear-text', 'progress', 'json'], + testRunner: 'jest', + coverageAnalysis: 'perTest', + ignoreStatic: true, +}; + +export default config; diff --git a/packages/node/test/helpers/clear-global-scope.ts b/packages/node/test/helpers/clear-global-scope.ts new file mode 100644 index 000000000000..3aa49a31716f --- /dev/null +++ b/packages/node/test/helpers/clear-global-scope.ts @@ -0,0 +1,7 @@ +import { getMainCarrier } from '@sentry/core'; + +export function clearGlobalScope() { + const carrier = getMainCarrier(); + // @ts-expect-error - just messing around + carrier.globalScope = undefined; +} diff --git a/packages/node/test/integration/scope.test.ts b/packages/node/test/integration/scope.test.ts index 1a7a899ab423..c5f7dde6c1ad 100644 --- a/packages/node/test/integration/scope.test.ts +++ b/packages/node/test/integration/scope.test.ts @@ -1,6 +1,6 @@ import { getCapturedScopesOnSpan, getCurrentScope } from '@sentry/core'; import { getClient } from '@sentry/opentelemetry'; -import { clearGlobalScope } from '../../../core/test/lib/clear-global-scope'; +import { clearGlobalScope } from './../helpers/clear-global-scope'; import * as Sentry from '../../src/'; import type { NodeClient } from '../../src/sdk/client'; diff --git a/packages/node/test/integrations/contextlines.test.ts b/packages/node/test/integrations/contextlines.test.ts index 56af4a3e58e8..39209294e147 100644 --- a/packages/node/test/integrations/contextlines.test.ts +++ b/packages/node/test/integrations/contextlines.test.ts @@ -164,7 +164,9 @@ describe('ContextLines', () => { } expect(errorFrame.context_line).toBe(" return new Error('mock error');"); - expect(errorFrame.pre_context).toHaveLength(2); + // We expect 2 lines of context before the error line however, when running the tests with stryker (for mutation + // testing) the test files are modified which adds two additional pre context lines. + expect(errorFrame.pre_context?.length).toBeGreaterThanOrEqual(2); expect(errorFrame.post_context).toHaveLength(1); }); diff --git a/yarn.lock b/yarn.lock index 34dc60261848..09341f972f21 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9490,6 +9490,15 @@ resolved "https://registry.yarnpkg.com/@stryker-mutator/util/-/util-8.5.0.tgz#66bccae7aedebb96bde6738aac55cce8e81c7f09" integrity sha512-T1ElpGUDqESKcwuRnfEuroE7N2pEMLTqieWRLIJZsP2ubEfnoHp4aGVL6IjPRdiZr4jetZOLfjlTzddrqrbsvg== +"@stryker-mutator/vitest-runner@^8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@stryker-mutator/vitest-runner/-/vitest-runner-8.5.0.tgz#e6606013f2468fb5d6f11d8cbd7d0258d30957ce" + integrity sha512-zOF/UWlHav7z5qU8IfJpWMz3t5I8y8QqMXrs91ArmtCn9vIf20MXby0wRv+HM4+GaRVHhyZdWK1s/xjgeQu5zg== + dependencies: + "@stryker-mutator/api" "8.5.0" + "@stryker-mutator/util" "8.5.0" + tslib "~2.6.3" + "@sveltejs/kit@^2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@sveltejs/kit/-/kit-2.0.2.tgz#bd02523fe570ddaf89148bffb1eb2233c458054b" From 2229b635a94f4b2a321477ef23abb4faa30f2e22 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 19 Aug 2024 16:12:17 +0200 Subject: [PATCH 05/53] add top-level script --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index e1a0eb03ee01..b2d17d68cf0b 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "test:ci:browser": "UNIT_TEST_ENV=browser ts-node ./scripts/ci-unit-tests.ts", "test:ci:node": "UNIT_TEST_ENV=node ts-node ./scripts/ci-unit-tests.ts", "test:ci:bun": "lerna run test --scope @sentry/bun", + "test:mutation": "lerna run test:mutation", "yalc:publish": "lerna run yalc:publish" }, "volta": { From b7c567269bbfd6f43635339af62144c0ed0a3b36 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 19 Aug 2024 16:16:11 +0200 Subject: [PATCH 06/53] clean stryker dirs --- packages/browser/package.json | 2 +- packages/core/package.json | 2 +- packages/node/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/browser/package.json b/packages/browser/package.json index ae61c88770d4..3b6d547e8d61 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -67,7 +67,7 @@ "build:types:watch": "tsc -p tsconfig.types.json --watch", "build:tarball": "npm pack", "circularDepCheck": "madge --circular src/index.ts", - "clean": "rimraf build coverage .rpt2_cache sentry-browser-*.tgz", + "clean": "rimraf build coverage .rpt2_cache sentry-browser-*.tgz .stryker-tmp", "fix": "eslint . --format stylish --fix", "lint": "eslint . --format stylish", "size:check": "cat build/bundles/bundle.min.js | gzip -9 | wc -c | awk '{$1=$1/1024; print \"ES2017: \",$1,\"kB\";}'", diff --git a/packages/core/package.json b/packages/core/package.json index 3a603c63c561..923e18315d13 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -58,7 +58,7 @@ "build:types:watch": "tsc -p tsconfig.types.json --watch", "build:tarball": "npm pack", "circularDepCheck": "madge --circular src/index.ts", - "clean": "rimraf build coverage sentry-core-*.tgz", + "clean": "rimraf build coverage sentry-core-*.tgz .stryker-tmp", "fix": "eslint . --format stylish --fix", "lint": "eslint . --format stylish", "test": "jest", diff --git a/packages/node/package.json b/packages/node/package.json index 79dbde038948..0fd52c5fbe2e 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -115,7 +115,7 @@ "build:types:watch": "tsc -p tsconfig.types.json --watch", "build:tarball": "npm pack", "circularDepCheck": "madge --circular src/index.ts", - "clean": "rimraf build coverage sentry-node-*.tgz", + "clean": "rimraf build coverage sentry-node-*.tgz .stryker-tmp", "fix": "eslint . --format stylish --fix", "lint": "eslint . --format stylish", "test": "yarn test:jest", From e967907d39a89a05bfad4565bf7a1dc54e92a63f Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 20 Aug 2024 09:43:44 +0200 Subject: [PATCH 07/53] test(core): Switch to vitest 5x speed improvement! --- packages/core/jest.config.js | 1 - packages/core/package.json | 6 +- packages/core/stryker.config.mjs | 2 +- packages/core/test/lib/api.test.ts | 1 + packages/core/test/lib/attachments.test.ts | 3 +- packages/core/test/lib/base.test.ts | 277 +++++++++--------- packages/core/test/lib/carrier.test.ts | 1 + packages/core/test/lib/checkin.test.ts | 1 + packages/core/test/lib/envelope.test.ts | 6 +- packages/core/test/lib/feedback.test.ts | 17 +- packages/core/test/lib/hint.test.ts | 6 +- packages/core/test/lib/integration.test.ts | 59 ++-- .../lib/integrations/captureconsole.test.ts | 47 +-- .../core/test/lib/integrations/debug.test.ts | 5 +- .../core/test/lib/integrations/dedupe.test.ts | 1 + .../lib/integrations/extraerrordata.test.ts | 1 + .../lib/integrations/functiontostring.test.ts | 1 + .../lib/integrations/inboundfilters.test.ts | 1 + .../test/lib/integrations/metadata.test.ts | 3 +- .../test/lib/integrations/requestdata.test.ts | 5 +- .../lib/integrations/rewriteframes.test.ts | 1 + .../lib/integrations/sessiontiming.test.ts | 1 + .../third-party-errors-filter.test.ts | 2 + .../test/lib/integrations/zoderrrors.test.ts | 1 + packages/core/test/lib/metadata.test.ts | 1 + .../core/test/lib/metrics/aggregator.test.ts | 17 +- .../lib/metrics/browser-aggregator.test.ts | 1 + packages/core/test/lib/metrics/timing.test.ts | 11 +- packages/core/test/lib/metrics/utils.test.ts | 3 +- packages/core/test/lib/prepareEvent.test.ts | 15 +- packages/core/test/lib/scope.test.ts | 91 +++--- packages/core/test/lib/sdk.test.ts | 22 +- .../core/test/lib/serverruntimeclient.test.ts | 5 +- packages/core/test/lib/session.test.ts | 2 + packages/core/test/lib/sessionflusher.test.ts | 31 +- .../tracing/dynamicSamplingContext.test.ts | 3 +- packages/core/test/lib/tracing/errors.test.ts | 9 +- .../core/test/lib/tracing/idleSpan.test.ts | 111 +++---- .../tracing/sentryNonRecordingSpan.test.ts | 1 + .../core/test/lib/tracing/sentrySpan.test.ts | 13 +- .../core/test/lib/tracing/spanstatus.test.ts | 1 + packages/core/test/lib/tracing/trace.test.ts | 24 +- .../core/test/lib/transports/base.test.ts | 17 +- .../test/lib/transports/multiplexed.test.ts | 6 +- .../core/test/lib/transports/offline.test.ts | 4 +- .../lib/utils/applyScopeDataToEvent.test.ts | 2 + .../lib/utils/handleCallbackErrors.test.ts | 41 +-- .../test/lib/utils/hasTracingEnabled.test.ts | 1 + .../test/lib/utils/isSentryRequestUrl.test.ts | 1 + packages/core/test/lib/utils/meta.test.ts | 7 +- .../core/test/lib/utils/parameterize.test.ts | 1 + .../test/lib/utils/parseSampleRate.test.ts | 1 + .../core/test/lib/utils/spanUtils.test.ts | 2 + .../core/test/lib/utils/traceData.test.ts | 31 +- packages/core/tsconfig.test.json | 4 +- packages/core/vite.config.ts | 12 + 56 files changed, 507 insertions(+), 433 deletions(-) delete mode 100644 packages/core/jest.config.js create mode 100644 packages/core/vite.config.ts diff --git a/packages/core/jest.config.js b/packages/core/jest.config.js deleted file mode 100644 index 8cdf86519208..000000000000 --- a/packages/core/jest.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('@sentry-internal/jest-config'); diff --git a/packages/core/package.json b/packages/core/package.json index 923e18315d13..3cc9a530cd5f 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -43,7 +43,7 @@ "@sentry/utils": "8.26.0" }, "devDependencies": { - "@sentry-internal/jest-config": "8.26.0" + "@sentry-internal/vite-config": "8.26.0" }, "scripts": { "build": "run-p build:transpile build:types", @@ -61,8 +61,8 @@ "clean": "rimraf build coverage sentry-core-*.tgz .stryker-tmp", "fix": "eslint . --format stylish --fix", "lint": "eslint . --format stylish", - "test": "jest", - "test:watch": "jest --watch", + "test": "vitest run", + "test:watch": "vitest --watch", "test:mutation": "stryker run", "yalc:publish": "yalc publish --push --sig" }, diff --git a/packages/core/stryker.config.mjs b/packages/core/stryker.config.mjs index bf43e1870724..98f92c75dd9c 100644 --- a/packages/core/stryker.config.mjs +++ b/packages/core/stryker.config.mjs @@ -2,7 +2,7 @@ const config = { packageManager: 'yarn', reporters: ['html', 'clear-text', 'progress', 'json'], - testRunner: 'jest', + testRunner: 'vitest', coverageAnalysis: 'perTest', ignoreStatic: true, }; diff --git a/packages/core/test/lib/api.test.ts b/packages/core/test/lib/api.test.ts index d2e500776228..38530771890a 100644 --- a/packages/core/test/lib/api.test.ts +++ b/packages/core/test/lib/api.test.ts @@ -1,6 +1,7 @@ import type { DsnComponents, SdkInfo } from '@sentry/types'; import { makeDsn } from '@sentry/utils'; +import { describe, expect, it, test } from 'vitest'; import { getEnvelopeEndpointWithUrlEncodedAuth, getReportDialogEndpoint } from '../../src/api'; const ingestDsn = 'https://abc@xxxx.ingest.sentry.io:1234/subpath/123'; diff --git a/packages/core/test/lib/attachments.test.ts b/packages/core/test/lib/attachments.test.ts index 4f43f86a6451..2afe4e40fc31 100644 --- a/packages/core/test/lib/attachments.test.ts +++ b/packages/core/test/lib/attachments.test.ts @@ -1,5 +1,6 @@ import { parseEnvelope } from '@sentry/utils'; +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; import { createTransport } from '../../src/transports/base'; import { TestClient, getDefaultTestClientOptions } from '../mocks/client'; @@ -10,7 +11,7 @@ describe('Attachments', () => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); test('actually end up in envelope', async () => { diff --git a/packages/core/test/lib/base.test.ts b/packages/core/test/lib/base.test.ts index 026b2b3479bc..31c5254809e0 100644 --- a/packages/core/test/lib/base.test.ts +++ b/packages/core/test/lib/base.test.ts @@ -1,5 +1,6 @@ import type { Client, Envelope, ErrorEvent, Event, TransactionEvent } from '@sentry/types'; import { SentryError, SyncPromise, dsnToString, logger } from '@sentry/utils'; +import { afterEach, beforeEach, describe, expect, it, test, vi } from 'vitest'; import { Scope, @@ -20,11 +21,11 @@ const PUBLIC_DSN = 'https://username@domain/123'; // eslint-disable-next-line no-var declare var global: any; -const clientEventFromException = jest.spyOn(TestClient.prototype, 'eventFromException'); -const clientProcess = jest.spyOn(TestClient.prototype as any, '_process'); +const clientEventFromException = vi.spyOn(TestClient.prototype, 'eventFromException'); +const clientProcess = vi.spyOn(TestClient.prototype as any, '_process'); -jest.mock('@sentry/utils', () => { - const original = jest.requireActual('@sentry/utils'); +vi.mock('@sentry/utils', async () => { + const original = await vi.importActual('@sentry/utils'); return { ...original, @@ -67,7 +68,7 @@ describe('BaseClient', () => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); describe('constructor() / getDsn()', () => { @@ -89,7 +90,7 @@ describe('BaseClient', () => { test('handles being passed an invalid Dsn', () => { // Hide warning logs in the test - jest.spyOn(console, 'error').mockImplementation(() => {}); + vi.spyOn(console, 'error').mockImplementation(() => {}); const options = getDefaultTestClientOptions({ dsn: 'abc' }); const client = new TestClient(options); @@ -174,7 +175,7 @@ describe('BaseClient', () => { }); test('calls `beforeBreadcrumb` and adds the breadcrumb without any changes', () => { - const beforeBreadcrumb = jest.fn(breadcrumb => breadcrumb); + const beforeBreadcrumb = vi.fn(breadcrumb => breadcrumb); const options = getDefaultTestClientOptions({ beforeBreadcrumb }); const client = new TestClient(options); setCurrentClient(client); @@ -187,7 +188,7 @@ describe('BaseClient', () => { }); test('calls `beforeBreadcrumb` and uses the new one', () => { - const beforeBreadcrumb = jest.fn(() => ({ message: 'changed' })); + const beforeBreadcrumb = vi.fn(() => ({ message: 'changed' })); const options = getDefaultTestClientOptions({ beforeBreadcrumb }); const client = new TestClient(options); setCurrentClient(client); @@ -200,7 +201,7 @@ describe('BaseClient', () => { }); test('calls `beforeBreadcrumb` and discards the breadcrumb when returned `null`', () => { - const beforeBreadcrumb = jest.fn(() => null); + const beforeBreadcrumb = vi.fn(() => null); const options = getDefaultTestClientOptions({ beforeBreadcrumb }); const client = new TestClient(options); setCurrentClient(client); @@ -213,7 +214,7 @@ describe('BaseClient', () => { }); test('`beforeBreadcrumb` gets an access to a hint as a second argument', () => { - const beforeBreadcrumb = jest.fn((breadcrumb, hint) => ({ ...breadcrumb, data: hint.data })); + const beforeBreadcrumb = vi.fn((breadcrumb, hint) => ({ ...breadcrumb, data: hint.data })); const options = getDefaultTestClientOptions({ beforeBreadcrumb }); const client = new TestClient(options); setCurrentClient(client); @@ -369,7 +370,7 @@ describe('BaseClient', () => { test('should call `eventFromException` if input to `captureMessage` is not a primitive', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN }); const client = new TestClient(options); - const spy = jest.spyOn(TestClient.instance!, 'eventFromException'); + const spy = vi.spyOn(TestClient.instance!, 'eventFromException'); client.captureMessage('foo'); client.captureMessage(null as any); @@ -955,7 +956,7 @@ describe('BaseClient', () => { test('calls `beforeSend` and uses original event without any changes', () => { expect.assertions(2); - const beforeSend = jest.fn(event => event); + const beforeSend = vi.fn(event => event); const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, beforeSend }); const client = new TestClient(options); @@ -968,7 +969,7 @@ describe('BaseClient', () => { test('calls `beforeSendTransaction` and uses original event without any changes', () => { expect.assertions(2); - const beforeSendTransaction = jest.fn(event => event); + const beforeSendTransaction = vi.fn(event => event); const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, beforeSendTransaction }); const client = new TestClient(options); @@ -981,7 +982,7 @@ describe('BaseClient', () => { test('calls `beforeSendSpan` and uses original spans without any changes', () => { expect.assertions(2); - const beforeSendSpan = jest.fn(span => span); + const beforeSendSpan = vi.fn(span => span); const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, beforeSendSpan }); const client = new TestClient(options); @@ -1013,7 +1014,7 @@ describe('BaseClient', () => { test('calls `beforeSend` and uses the modified event', () => { expect.assertions(2); - const beforeSend = jest.fn(event => { + const beforeSend = vi.fn(event => { event.message = 'changed1'; return event; }); @@ -1029,7 +1030,7 @@ describe('BaseClient', () => { test('calls `beforeSendTransaction` and uses the modified event', () => { expect.assertions(2); - const beforeSendTransaction = jest.fn(event => { + const beforeSendTransaction = vi.fn(event => { event.transaction = '/adopt/dont/shop'; return event; }); @@ -1043,7 +1044,7 @@ describe('BaseClient', () => { }); test('calls `beforeSendTransaction` and drops spans', () => { - const beforeSendTransaction = jest.fn(event => { + const beforeSendTransaction = vi.fn(event => { event.spans = [{ span_id: 'span5', trace_id: 'trace1', start_timestamp: 1234 }]; return event; }); @@ -1069,7 +1070,7 @@ describe('BaseClient', () => { test('calls `beforeSendSpan` and uses the modified spans', () => { expect.assertions(3); - const beforeSendSpan = jest.fn(span => { + const beforeSendSpan = vi.fn(span => { span.data = { version: 'bravo' }; return span; }); @@ -1108,11 +1109,11 @@ describe('BaseClient', () => { test('calls `beforeSend` and discards the event', () => { expect.assertions(4); - const beforeSend = jest.fn(() => null); + const beforeSend = vi.fn(() => null); const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, beforeSend }); const client = new TestClient(options); - const captureExceptionSpy = jest.spyOn(client, 'captureException'); - const loggerWarnSpy = jest.spyOn(logger, 'log'); + const captureExceptionSpy = vi.spyOn(client, 'captureException'); + const loggerWarnSpy = vi.spyOn(logger, 'log'); client.captureEvent({ message: 'hello' }); @@ -1127,11 +1128,11 @@ describe('BaseClient', () => { test('calls `beforeSendTransaction` and discards the event', () => { expect.assertions(4); - const beforeSendTransaction = jest.fn(() => null); + const beforeSendTransaction = vi.fn(() => null); const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, beforeSendTransaction }); const client = new TestClient(options); - const captureExceptionSpy = jest.spyOn(client, 'captureException'); - const loggerWarnSpy = jest.spyOn(logger, 'log'); + const captureExceptionSpy = vi.spyOn(client, 'captureException'); + const loggerWarnSpy = vi.spyOn(logger, 'log'); client.captureEvent({ transaction: '/dogs/are/great', type: 'transaction' }); @@ -1144,7 +1145,7 @@ describe('BaseClient', () => { }); test('calls `beforeSendSpan` and discards the span', () => { - const beforeSendSpan = jest.fn(() => null); + const beforeSendSpan = vi.fn(() => null); const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, beforeSendSpan }); const client = new TestClient(options); @@ -1179,11 +1180,11 @@ describe('BaseClient', () => { expect.assertions(invalidValues.length * 3); for (const val of invalidValues) { - const beforeSend = jest.fn(() => val); + const beforeSend = vi.fn(() => val); // @ts-expect-error we need to test regular-js behavior const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, beforeSend }); const client = new TestClient(options); - const loggerWarnSpy = jest.spyOn(logger, 'warn'); + const loggerWarnSpy = vi.spyOn(logger, 'warn'); client.captureEvent({ message: 'hello' }); @@ -1200,11 +1201,11 @@ describe('BaseClient', () => { expect.assertions(invalidValues.length * 3); for (const val of invalidValues) { - const beforeSendTransaction = jest.fn(() => val); + const beforeSendTransaction = vi.fn(() => val); // @ts-expect-error we need to test regular-js behavior const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, beforeSendTransaction }); const client = new TestClient(options); - const loggerWarnSpy = jest.spyOn(logger, 'warn'); + const loggerWarnSpy = vi.spyOn(logger, 'warn'); client.captureEvent({ transaction: '/dogs/are/great', type: 'transaction' }); @@ -1216,11 +1217,10 @@ describe('BaseClient', () => { } }); - test('calls async `beforeSend` and uses original event without any changes', done => { - jest.useFakeTimers(); - expect.assertions(2); + test('calls async `beforeSend` and uses original event without any changes', async () => { + vi.useFakeTimers(); - const beforeSend = jest.fn( + const beforeSend = vi.fn( async event => new Promise(resolve => { setTimeout(() => { @@ -1232,25 +1232,26 @@ describe('BaseClient', () => { const client = new TestClient(options); client.captureEvent({ message: 'hello' }); - jest.runOnlyPendingTimers(); + vi.runOnlyPendingTimers(); - TestClient.sendEventCalled = (event: Event) => { - expect(beforeSend).toHaveBeenCalled(); - expect(event.message).toEqual('hello'); - }; + expect(beforeSend).toHaveBeenCalled(); + + const event = await new Promise(resolve => { + TestClient.sendEventCalled = (event: Event) => { + expect(event.message).toEqual('hello'); + resolve(event); + }; + }); - setTimeout(() => { - done(); - }, 5); + expect(event.message).toEqual('hello'); - jest.runOnlyPendingTimers(); + vi.runOnlyPendingTimers(); }); - test('calls async `beforeSendTransaction` and uses original event without any changes', done => { - jest.useFakeTimers(); - expect.assertions(2); + test('calls async `beforeSendTransaction` and uses original event without any changes', async () => { + vi.useFakeTimers(); - const beforeSendTransaction = jest.fn( + const beforeSendTransaction = vi.fn( async event => new Promise(resolve => { setTimeout(() => { @@ -1261,26 +1262,33 @@ describe('BaseClient', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, beforeSendTransaction }); const client = new TestClient(options); + vi.runOnlyPendingTimers(); + client.captureEvent({ transaction: '/dogs/are/great', type: 'transaction' }); - jest.runOnlyPendingTimers(); - TestClient.sendEventCalled = (event: Event) => { - expect(beforeSendTransaction).toHaveBeenCalled(); - expect(event.transaction).toBe('/dogs/are/great'); - }; + vi.runOnlyPendingTimers(); - setTimeout(() => { - done(); - }, 5); + expect(beforeSendTransaction).toHaveBeenCalledWith( + expect.objectContaining({ type: 'transaction', transaction: '/dogs/are/great' }), + expect.any(Object), + ); + + vi.runOnlyPendingTimers(); + + const event = await new Promise(resolve => { + TestClient.sendEventCalled = (event: Event) => { + resolve(event); + }; + }); - jest.runOnlyPendingTimers(); + expect(event.transaction).toBe('/dogs/are/great'); }); - test('calls async `beforeSend` and uses the modified event', done => { - jest.useFakeTimers(); + test('calls async `beforeSend` and uses the modified event', async () => { + vi.useFakeTimers(); expect.assertions(2); - const beforeSend = jest.fn(async event => { + const beforeSend = vi.fn(async event => { event.message = 'changed2'; return new Promise(resolve => { setTimeout(() => { @@ -1292,25 +1300,23 @@ describe('BaseClient', () => { const client = new TestClient(options); client.captureEvent({ message: 'hello' }); - jest.runOnlyPendingTimers(); + vi.runOnlyPendingTimers(); - TestClient.sendEventCalled = (event: Event) => { - expect(beforeSend).toHaveBeenCalled(); - expect(event.message).toEqual('changed2'); - }; + expect(beforeSend).toHaveBeenCalledTimes(1); - setTimeout(() => { - done(); - }, 5); + const event = await new Promise(resolve => { + TestClient.sendEventCalled = (event: Event) => { + resolve(event); + }; + }); - jest.runOnlyPendingTimers(); + expect(event.message).toEqual('changed2'); }); - test('calls async `beforeSendTransaction` and uses the modified event', done => { - jest.useFakeTimers(); - expect.assertions(2); + test('calls async `beforeSendTransaction` and uses the modified event', async () => { + vi.useFakeTimers(); - const beforeSendTransaction = jest.fn(async event => { + const beforeSendTransaction = vi.fn(async event => { event.transaction = '/adopt/dont/shop'; return new Promise(resolve => { setTimeout(() => { @@ -1322,25 +1328,24 @@ describe('BaseClient', () => { const client = new TestClient(options); client.captureEvent({ transaction: '/dogs/are/great', type: 'transaction' }); - jest.runOnlyPendingTimers(); + vi.runOnlyPendingTimers(); - TestClient.sendEventCalled = (event: Event) => { - expect(beforeSendTransaction).toHaveBeenCalled(); - expect(event.transaction).toBe('/adopt/dont/shop'); - }; + expect(beforeSendTransaction).toHaveBeenCalledTimes(1); - setTimeout(() => { - done(); - }, 5); + const event = await new Promise(resolve => { + TestClient.sendEventCalled = (event: Event) => { + resolve(event); + }; + }); - jest.runOnlyPendingTimers(); + expect(event.transaction).toBe('/adopt/dont/shop'); }); test('calls async `beforeSend` and discards the event', () => { - jest.useFakeTimers(); + vi.useFakeTimers(); expect.assertions(2); - const beforeSend = jest.fn( + const beforeSend = vi.fn( async () => new Promise(resolve => { setTimeout(() => { @@ -1352,17 +1357,17 @@ describe('BaseClient', () => { const client = new TestClient(options); client.captureEvent({ message: 'hello' }); - jest.runAllTimers(); + vi.runAllTimers(); expect(beforeSend).toHaveBeenCalled(); expect(TestClient.instance!.event).toBeUndefined(); }); test('calls async `beforeSendTransaction` and discards the event', () => { - jest.useFakeTimers(); + vi.useFakeTimers(); expect.assertions(2); - const beforeSendTransaction = jest.fn( + const beforeSendTransaction = vi.fn( async () => new Promise(resolve => { setTimeout(() => { @@ -1374,7 +1379,7 @@ describe('BaseClient', () => { const client = new TestClient(options); client.captureEvent({ transaction: '/dogs/are/great', type: 'transaction' }); - jest.runAllTimers(); + vi.runAllTimers(); expect(beforeSendTransaction).toHaveBeenCalled(); expect(TestClient.instance!.event).toBeUndefined(); @@ -1383,7 +1388,7 @@ describe('BaseClient', () => { test('`beforeSend` gets access to a hint as a second argument', () => { expect.assertions(3); - const beforeSend = jest.fn((event, hint) => ({ ...event, data: hint.data })); + const beforeSend = vi.fn((event, hint) => ({ ...event, data: hint.data })); const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, beforeSend }); const client = new TestClient(options); @@ -1397,7 +1402,7 @@ describe('BaseClient', () => { test('`beforeSendTransaction` gets access to a hint as a second argument', () => { expect.assertions(3); - const beforeSendTransaction = jest.fn((event, hint) => ({ ...event, data: hint.data })); + const beforeSendTransaction = vi.fn((event, hint) => ({ ...event, data: hint.data })); const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, beforeSendTransaction }); const client = new TestClient(options); @@ -1417,7 +1422,7 @@ describe('BaseClient', () => { test('`beforeSend` records dropped events', () => { expect.assertions(2); - const beforeSend = jest.fn(() => null); + const beforeSend = vi.fn(() => null); const client = new TestClient( getDefaultTestClientOptions({ dsn: PUBLIC_DSN, @@ -1425,7 +1430,7 @@ describe('BaseClient', () => { }), ); - const recordLostEventSpy = jest.spyOn(client, 'recordDroppedEvent'); + const recordLostEventSpy = vi.spyOn(client, 'recordDroppedEvent'); client.captureEvent({ message: 'hello' }, {}); @@ -1438,7 +1443,7 @@ describe('BaseClient', () => { test('`beforeSendTransaction` records dropped events', () => { expect.assertions(2); - const beforeSendTransaction = jest.fn(() => null); + const beforeSendTransaction = vi.fn(() => null); const client = new TestClient( getDefaultTestClientOptions({ @@ -1447,7 +1452,7 @@ describe('BaseClient', () => { }), ); - const recordLostEventSpy = jest.spyOn(client, 'recordDroppedEvent'); + const recordLostEventSpy = vi.spyOn(client, 'recordDroppedEvent'); client.captureEvent({ transaction: '/dogs/are/great', type: 'transaction' }); @@ -1462,8 +1467,8 @@ describe('BaseClient', () => { expect.assertions(3); const client = new TestClient(getDefaultTestClientOptions({ dsn: PUBLIC_DSN })); - const captureExceptionSpy = jest.spyOn(client, 'captureException'); - const loggerLogSpy = jest.spyOn(logger, 'log'); + const captureExceptionSpy = vi.spyOn(client, 'captureException'); + const loggerLogSpy = vi.spyOn(logger, 'log'); const scope = new Scope(); scope.addEventProcessor(() => null); @@ -1480,8 +1485,8 @@ describe('BaseClient', () => { expect.assertions(3); const client = new TestClient(getDefaultTestClientOptions({ dsn: PUBLIC_DSN })); - const captureExceptionSpy = jest.spyOn(client, 'captureException'); - const loggerLogSpy = jest.spyOn(logger, 'log'); + const captureExceptionSpy = vi.spyOn(client, 'captureException'); + const loggerLogSpy = vi.spyOn(logger, 'log'); const scope = new Scope(); scope.addEventProcessor(() => null); @@ -1500,7 +1505,7 @@ describe('BaseClient', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN }); const client = new TestClient(options); - const recordLostEventSpy = jest.spyOn(client, 'recordDroppedEvent'); + const recordLostEventSpy = vi.spyOn(client, 'recordDroppedEvent'); const scope = new Scope(); scope.addEventProcessor(() => null); @@ -1518,7 +1523,7 @@ describe('BaseClient', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN }); const client = new TestClient(options); - const recordLostEventSpy = jest.spyOn(client, 'recordDroppedEvent'); + const recordLostEventSpy = vi.spyOn(client, 'recordDroppedEvent'); const scope = new Scope(); scope.addEventProcessor(() => null); @@ -1557,7 +1562,7 @@ describe('BaseClient', () => { }); test('mutating transaction name with `beforeSendTransaction` sets transaction-name-change metadata', () => { - const beforeSendTransaction = jest.fn(event => { + const beforeSendTransaction = vi.fn(event => { event.transaction = '/adopt/dont/shop'; return event; }); @@ -1584,8 +1589,8 @@ describe('BaseClient', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN }); const client = new TestClient(options); - const captureExceptionSpy = jest.spyOn(client, 'captureException'); - const loggerWarnSpy = jest.spyOn(logger, 'warn'); + const captureExceptionSpy = vi.spyOn(client, 'captureException'); + const loggerWarnSpy = vi.spyOn(logger, 'warn'); const scope = new Scope(); const exception = new Error('sorry'); scope.addEventProcessor(() => { @@ -1614,7 +1619,7 @@ describe('BaseClient', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, sampleRate: 0 }); const client = new TestClient(options); - const recordLostEventSpy = jest.spyOn(client, 'recordDroppedEvent'); + const recordLostEventSpy = vi.spyOn(client, 'recordDroppedEvent'); client.captureEvent({ message: 'hello' }, {}); expect(recordLostEventSpy).toHaveBeenCalledWith('sample_rate', 'error', { @@ -1669,7 +1674,7 @@ describe('BaseClient', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] }); const client = new TestClient(options); // note: not the `Client` method `setupIntegrations`, but the free-standing function which that method calls - const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations'); + const setupIntegrationsHelper = vi.spyOn(integrationModule, 'setupIntegrations'); // it should install the first time, because integrations aren't yet installed... client.init(); @@ -1690,7 +1695,7 @@ describe('BaseClient', () => { describe('flush/close', () => { test('flush', async () => { - jest.useRealTimers(); + vi.useRealTimers(); expect.assertions(4); const { makeTransport, getSendCalled, getSentCount, delay } = makeFakeTransport(1); @@ -1715,7 +1720,7 @@ describe('BaseClient', () => { }); test('flush with some events being processed async', async () => { - jest.useRealTimers(); + vi.useRealTimers(); expect.assertions(4); const { makeTransport, getSendCalled, getSentCount, delay } = makeFakeTransport(300); @@ -1728,7 +1733,7 @@ describe('BaseClient', () => { }), ); - const spy = jest.spyOn(TestClient.instance!, 'eventFromMessage'); + const spy = vi.spyOn(TestClient.instance!, 'eventFromMessage'); spy.mockImplementationOnce( (message, level) => new SyncPromise(resolve => { @@ -1750,7 +1755,7 @@ describe('BaseClient', () => { }); test('close', async () => { - jest.useRealTimers(); + vi.useRealTimers(); expect.assertions(4); const { makeTransport, delay, getSentCount } = makeFakeTransport(300); @@ -1774,7 +1779,7 @@ describe('BaseClient', () => { }); test('multiple concurrent flush calls should just work', async () => { - jest.useRealTimers(); + vi.useRealTimers(); expect.assertions(3); const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN }); @@ -1796,11 +1801,11 @@ describe('BaseClient', () => { describe('sendEvent', () => { beforeEach(() => { - jest.useFakeTimers(); + vi.useFakeTimers(); }); afterEach(() => { - jest.useRealTimers(); + vi.useRealTimers(); }); it('emits `afterSendEvent` when sending an error', async () => { @@ -1812,15 +1817,15 @@ describe('BaseClient', () => { ); // @ts-expect-error Accessing private transport API - const mockSend = jest.spyOn(client._transport, 'send'); + const mockSend = vi.spyOn(client._transport, 'send'); const errorEvent: Event = { message: 'error' }; - const callback = jest.fn(); + const callback = vi.fn(); client.on('afterSendEvent', callback); client.sendEvent(errorEvent); - jest.runAllTimers(); + vi.runAllTimers(); // Wait for two ticks // note that for whatever reason, await new Promise(resolve => setTimeout(resolve, 0)) causes the test to hang await undefined; @@ -1840,15 +1845,15 @@ describe('BaseClient', () => { ); // @ts-expect-error Accessing private transport API - const mockSend = jest.spyOn(client._transport, 'send'); + const mockSend = vi.spyOn(client._transport, 'send'); const transactionEvent: Event = { type: 'transaction', event_id: 'tr1' }; - const callback = jest.fn(); + const callback = vi.fn(); client.on('afterSendEvent', callback); client.sendEvent(transactionEvent); - jest.runAllTimers(); + vi.runAllTimers(); // Wait for two ticks // note that for whatever reason, await new Promise(resolve => setTimeout(resolve, 0)) causes the test to hang await undefined; @@ -1870,21 +1875,17 @@ describe('BaseClient', () => { ); // @ts-expect-error Accessing private transport API - const mockSend = jest.spyOn(client._transport, 'send').mockImplementation(() => { + const mockSend = vi.spyOn(client._transport, 'send').mockImplementation(() => { return Promise.reject('send error'); }); const errorEvent: Event = { message: 'error' }; - const callback = jest.fn(); + const callback = vi.fn(); client.on('afterSendEvent', callback); client.sendEvent(errorEvent); - jest.runAllTimers(); - // Wait for two ticks - // note that for whatever reason, await new Promise(resolve => setTimeout(resolve, 0)) causes the test to hang - await undefined; - await undefined; + await vi.runAllTimersAsync(); expect(mockSend).toBeCalledTimes(1); expect(callback).toBeCalledTimes(1); @@ -1902,24 +1903,20 @@ describe('BaseClient', () => { ); // @ts-expect-error Accessing private transport API - const mockSend = jest.spyOn(client._transport, 'send').mockImplementation(() => { + const mockSend = vi.spyOn(client._transport, 'send').mockImplementation(() => { return Promise.resolve({ statusCode: 200 }); }); const errorEvent: Event = { message: 'error' }; - const callback = jest.fn(); + const callback = vi.fn(); client.on('afterSendEvent', callback); client.sendEvent(errorEvent); - jest.runAllTimers(); - // Wait for two ticks - // note that for whatever reason, await new Promise(resolve => setTimeout(resolve, 0)) causes the test to hang - await undefined; - await undefined; + await vi.runAllTimersAsync(); expect(mockSend).toBeCalledTimes(1); - expect(callback).toBeCalledTimes(1); + expect(callback).toHaveBeenCalledTimes(1); expect(callback).toBeCalledWith(errorEvent, { statusCode: 200 }); }); }); @@ -2040,7 +2037,7 @@ describe('BaseClient', () => { describe('hook removal with `on`', () => { it('should return a cleanup function that, when executed, unregisters a hook', async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); expect.assertions(8); const client = new TestClient( @@ -2050,23 +2047,19 @@ describe('BaseClient', () => { }), ); - const mockSend = jest.spyOn(client.getTransport()!, 'send').mockImplementation(() => { + const mockSend = vi.spyOn(client.getTransport()!, 'send').mockImplementation(() => { return Promise.resolve({ statusCode: 200 }); }); const errorEvent: Event = { message: 'error' }; - const callback = jest.fn(); + const callback = vi.fn(); const removeAfterSendEventListenerFn = client.on('afterSendEvent', callback); expect(client['_hooks']['afterSendEvent']).toEqual([callback]); client.sendEvent(errorEvent); - jest.runAllTimers(); - // Wait for two ticks - // note that for whatever reason, await new Promise(resolve => setTimeout(resolve, 0)) causes the test to hang - await undefined; - await undefined; + await vi.runAllTimersAsync(); expect(mockSend).toBeCalledTimes(1); expect(callback).toBeCalledTimes(1); @@ -2077,11 +2070,7 @@ describe('BaseClient', () => { expect(client['_hooks']['afterSendEvent']).toEqual([]); client.sendEvent(errorEvent); - jest.runAllTimers(); - // Wait for two ticks - // note that for whatever reason, await new Promise(resolve => setTimeout(resolve, 0)) causes the test to hang - await undefined; - await undefined; + await vi.runAllTimersAsync(); expect(mockSend).toBeCalledTimes(2); // Note that the `callback` has still been called only once and not twice, diff --git a/packages/core/test/lib/carrier.test.ts b/packages/core/test/lib/carrier.test.ts index 3c94c96b98c1..721874a7e17e 100644 --- a/packages/core/test/lib/carrier.test.ts +++ b/packages/core/test/lib/carrier.test.ts @@ -1,4 +1,5 @@ import { SDK_VERSION } from '@sentry/utils'; +import { describe, expect, it } from 'vitest'; import { getSentryCarrier } from '../../src/carrier'; describe('getSentryCarrier', () => { diff --git a/packages/core/test/lib/checkin.test.ts b/packages/core/test/lib/checkin.test.ts index 5ae6bac6b5f3..203207b95222 100644 --- a/packages/core/test/lib/checkin.test.ts +++ b/packages/core/test/lib/checkin.test.ts @@ -1,5 +1,6 @@ import type { SerializedCheckIn } from '@sentry/types'; +import { describe, expect, test } from 'vitest'; import { createCheckInEnvelope } from '../../src/checkin'; describe('createCheckInEnvelope', () => { diff --git a/packages/core/test/lib/envelope.test.ts b/packages/core/test/lib/envelope.test.ts index 74e764c1d938..bd9a6d8c3a13 100644 --- a/packages/core/test/lib/envelope.test.ts +++ b/packages/core/test/lib/envelope.test.ts @@ -11,6 +11,8 @@ import { import { createEventEnvelope, createSpanEnvelope } from '../../src/envelope'; import { TestClient, getDefaultTestClientOptions } from '../mocks/client'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + const testDsn: DsnComponents = { protocol: 'https', projectId: 'abc', host: 'testry.io', publicKey: 'pubKey123' }; describe('createEventEnvelope', () => { @@ -185,7 +187,7 @@ describe('createSpanEnvelope', () => { }); it('calls `beforeSendSpan` and uses original span without any changes', () => { - const beforeSendSpan = jest.fn(span => span); + const beforeSendSpan = vi.fn(span => span); const options = getDefaultTestClientOptions({ dsn: 'https://domain/123', beforeSendSpan }); const client = new TestClient(options); @@ -217,7 +219,7 @@ describe('createSpanEnvelope', () => { }); it('calls `beforeSendSpan` and uses the modified span', () => { - const beforeSendSpan = jest.fn(span => { + const beforeSendSpan = vi.fn(span => { span.description = `mutated description: ${span.description}`; return span; }); diff --git a/packages/core/test/lib/feedback.test.ts b/packages/core/test/lib/feedback.test.ts index cd9e99e43bdb..4d49b7541bcb 100644 --- a/packages/core/test/lib/feedback.test.ts +++ b/packages/core/test/lib/feedback.test.ts @@ -1,4 +1,5 @@ import type { Span } from '@sentry/types'; +import { beforeEach, describe, expect, it, test, vi } from 'vitest'; import { Scope, addBreadcrumb, @@ -35,7 +36,7 @@ describe('captureFeedback', () => { setCurrentClient(client); client.init(); - const mockTransport = jest.spyOn(client.getTransport()!, 'send'); + const mockTransport = vi.spyOn(client.getTransport()!, 'send'); const eventId = captureFeedback({ message: 'test', @@ -90,7 +91,7 @@ describe('captureFeedback', () => { setCurrentClient(client); client.init(); - const mockTransport = jest.spyOn(client.getTransport()!, 'send'); + const mockTransport = vi.spyOn(client.getTransport()!, 'send'); const eventId = captureFeedback({ name: 'doe', @@ -155,7 +156,7 @@ describe('captureFeedback', () => { setCurrentClient(client); client.init(); - const mockTransport = jest.spyOn(client.getTransport()!, 'send'); + const mockTransport = vi.spyOn(client.getTransport()!, 'send'); const attachment1 = new Uint8Array([1, 2, 3, 4, 5]); const attachment2 = new Uint8Array([6, 7, 8, 9]); @@ -248,7 +249,7 @@ describe('captureFeedback', () => { setCurrentClient(client); client.init(); - const mockTransport = jest.spyOn(client.getTransport()!, 'send'); + const mockTransport = vi.spyOn(client.getTransport()!, 'send'); const traceId = '4C79F60C11214EB38604F4AE0781BFB2'; const spanId = 'FA90FDEAD5F74052'; @@ -322,7 +323,7 @@ describe('captureFeedback', () => { setCurrentClient(client); client.init(); - const mockTransport = jest.spyOn(client.getTransport()!, 'send'); + const mockTransport = vi.spyOn(client.getTransport()!, 'send'); let span: Span | undefined; const eventId = startSpan({ name: 'test-span' }, _span => { @@ -392,7 +393,7 @@ describe('captureFeedback', () => { setCurrentClient(client); client.init(); - const mockTransport = jest.spyOn(client.getTransport()!, 'send'); + const mockTransport = vi.spyOn(client.getTransport()!, 'send'); withIsolationScope(isolationScope => { isolationScope.setTag('test-1', 'tag'); @@ -478,8 +479,8 @@ describe('captureFeedback', () => { const scope = new Scope(); scope.setClient(client2); - const mockTransport = jest.spyOn(client.getTransport()!, 'send'); - const mockTransport2 = jest.spyOn(client2.getTransport()!, 'send'); + const mockTransport = vi.spyOn(client.getTransport()!, 'send'); + const mockTransport2 = vi.spyOn(client2.getTransport()!, 'send'); const eventId = captureFeedback( { diff --git a/packages/core/test/lib/hint.test.ts b/packages/core/test/lib/hint.test.ts index c5a31a944663..96ff73dc302b 100644 --- a/packages/core/test/lib/hint.test.ts +++ b/packages/core/test/lib/hint.test.ts @@ -5,8 +5,10 @@ import { initAndBind } from '../../src/sdk'; import { TestClient, getDefaultTestClientOptions } from '../mocks/client'; import { AddAttachmentTestIntegration } from '../mocks/integration'; +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; + const PUBLIC_DSN = 'https://username@domain/123'; -const sendEvent = jest.spyOn(TestClient.prototype, 'sendEvent'); +const sendEvent = vi.spyOn(TestClient.prototype, 'sendEvent'); describe('Hint', () => { beforeEach(() => { @@ -15,7 +17,7 @@ describe('Hint', () => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); // @ts-expect-error for testing delete GLOBAL_OBJ.__SENTRY__; }); diff --git a/packages/core/test/lib/integration.test.ts b/packages/core/test/lib/integration.test.ts index 18b9d1791bc8..d7ba64481f28 100644 --- a/packages/core/test/lib/integration.test.ts +++ b/packages/core/test/lib/integration.test.ts @@ -2,6 +2,7 @@ import type { Integration, Options } from '@sentry/types'; import { logger } from '@sentry/utils'; import { getCurrentScope } from '../../src/currentScopes'; +import { afterEach, beforeEach, describe, expect, it, test, vi } from 'vitest'; import { addIntegration, getIntegrationsToSetup, installedIntegrations, setupIntegration } from '../../src/integration'; import { setCurrentClient } from '../../src/sdk'; import { TestClient, getDefaultTestClientOptions } from '../mocks/client'; @@ -339,7 +340,7 @@ describe('setupIntegration', () => { it('works with a minimal integration', () => { class CustomIntegration implements Integration { name = 'test'; - setupOnce = jest.fn(); + setupOnce = vi.fn(); } const client = getTestClient(); @@ -355,7 +356,7 @@ describe('setupIntegration', () => { it('only calls setupOnce a single time', () => { class CustomIntegration implements Integration { name = 'test'; - setupOnce = jest.fn(); + setupOnce = vi.fn(); } const client1 = getTestClient(); @@ -382,8 +383,8 @@ describe('setupIntegration', () => { it('calls setup for each client', () => { class CustomIntegration implements Integration { name = 'test'; - setupOnce = jest.fn(); - setup = jest.fn(); + setupOnce = vi.fn(); + setup = vi.fn(); } const client1 = getTestClient(); @@ -420,8 +421,8 @@ describe('setupIntegration', () => { it('binds preprocessEvent for each client', () => { class CustomIntegration implements Integration { name = 'test'; - setupOnce = jest.fn(); - preprocessEvent = jest.fn(); + setupOnce = vi.fn(); + preprocessEvent = vi.fn(); } const client1 = getTestClient(); @@ -472,8 +473,8 @@ describe('setupIntegration', () => { it('allows to mutate events in preprocessEvent', async () => { class CustomIntegration implements Integration { name = 'test'; - setupOnce = jest.fn(); - preprocessEvent = jest.fn(event => { + setupOnce = vi.fn(); + preprocessEvent = vi.fn(event => { event.event_id = 'mutated'; }); } @@ -485,7 +486,7 @@ describe('setupIntegration', () => { setupIntegration(client, integration, integrationIndex); - const sendEvent = jest.fn(); + const sendEvent = vi.fn(); client.sendEvent = sendEvent; client.captureEvent({ event_id: '1a' }); @@ -500,8 +501,8 @@ describe('setupIntegration', () => { it('binds processEvent for each client', () => { class CustomIntegration implements Integration { name = 'test'; - setupOnce = jest.fn(); - processEvent = jest.fn(event => { + setupOnce = vi.fn(); + processEvent = vi.fn(event => { return event; }); } @@ -554,8 +555,8 @@ describe('setupIntegration', () => { it('allows to mutate events in processEvent', async () => { class CustomIntegration implements Integration { name = 'test'; - setupOnce = jest.fn(); - processEvent = jest.fn(_event => { + setupOnce = vi.fn(); + processEvent = vi.fn(_event => { return { event_id: 'mutated' }; }); } @@ -567,7 +568,7 @@ describe('setupIntegration', () => { setupIntegration(client, integration, integrationIndex); - const sendEvent = jest.fn(); + const sendEvent = vi.fn(); client.sendEvent = sendEvent; client.captureEvent({ event_id: '1a' }); @@ -582,8 +583,8 @@ describe('setupIntegration', () => { it('allows to drop events in processEvent', async () => { class CustomIntegration implements Integration { name = 'test'; - setupOnce = jest.fn(); - processEvent = jest.fn(_event => { + setupOnce = vi.fn(); + processEvent = vi.fn(_event => { return null; }); } @@ -595,7 +596,7 @@ describe('setupIntegration', () => { setupIntegration(client, integration, integrationIndex); - const sendEvent = jest.fn(); + const sendEvent = vi.fn(); client.sendEvent = sendEvent; client.captureEvent({ event_id: '1a' }); @@ -612,15 +613,15 @@ describe('addIntegration', () => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('works with a client setup', () => { - const warnings = jest.spyOn(logger, 'warn'); + const warnings = vi.spyOn(logger, 'warn'); class CustomIntegration implements Integration { name = 'test'; - setupOnce = jest.fn(); + setupOnce = vi.fn(); } const client = getTestClient(); @@ -634,10 +635,10 @@ describe('addIntegration', () => { }); it('works without a client setup', () => { - const warnings = jest.spyOn(logger, 'warn'); + const warnings = vi.spyOn(logger, 'warn'); class CustomIntegration implements Integration { name = 'test'; - setupOnce = jest.fn(); + setupOnce = vi.fn(); } getCurrentScope().setClient(undefined); @@ -651,9 +652,9 @@ describe('addIntegration', () => { }); it('triggers all hooks', () => { - const setup = jest.fn(); - const setupOnce = jest.fn(); - const setupAfterAll = jest.fn(); + const setup = vi.fn(); + const setupOnce = vi.fn(); + const setupAfterAll = vi.fn(); class CustomIntegration implements Integration { name = 'test'; @@ -675,13 +676,13 @@ describe('addIntegration', () => { }); it('does not trigger hooks if already installed', () => { - const logs = jest.spyOn(logger, 'log'); + const logs = vi.spyOn(logger, 'log'); class CustomIntegration implements Integration { name = 'test'; - setupOnce = jest.fn(); - setup = jest.fn(); - afterAllSetup = jest.fn(); + setupOnce = vi.fn(); + setup = vi.fn(); + afterAllSetup = vi.fn(); } const client = getTestClient(); diff --git a/packages/core/test/lib/integrations/captureconsole.test.ts b/packages/core/test/lib/integrations/captureconsole.test.ts index ce913642b123..23d400ad0025 100644 --- a/packages/core/test/lib/integrations/captureconsole.test.ts +++ b/packages/core/test/lib/integrations/captureconsole.test.ts @@ -13,14 +13,17 @@ import * as SentryCore from '../../../src/exports'; import { captureConsoleIntegration } from '../../../src/integrations/captureconsole'; -const mockConsole: { [key in ConsoleLevel]: jest.Mock } = { - debug: jest.fn(), - log: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - assert: jest.fn(), - info: jest.fn(), - trace: jest.fn(), +import type { Mock } from 'vitest'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +const mockConsole: { [key in ConsoleLevel]: Mock } = { + debug: vi.fn(), + log: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + assert: vi.fn(), + info: vi.fn(), + trace: vi.fn(), }; describe('CaptureConsole setup', () => { @@ -31,23 +34,23 @@ describe('CaptureConsole setup', () => { let mockClient: Client; const mockScope = { - setExtra: jest.fn(), - addEventProcessor: jest.fn(), + setExtra: vi.fn(), + addEventProcessor: vi.fn(), }; - const captureMessage = jest.fn(); - const captureException = jest.fn(); - const withScope = jest.fn(callback => { + const captureMessage = vi.fn(); + const captureException = vi.fn(); + const withScope = vi.fn(callback => { return callback(mockScope); }); beforeEach(() => { mockClient = {} as Client; - jest.spyOn(SentryCore, 'captureMessage').mockImplementation(captureMessage); - jest.spyOn(SentryCore, 'captureException').mockImplementation(captureException); - jest.spyOn(CurrentScopes, 'getClient').mockImplementation(() => mockClient); - jest.spyOn(CurrentScopes, 'withScope').mockImplementation(withScope); + vi.spyOn(SentryCore, 'captureMessage').mockImplementation(captureMessage); + vi.spyOn(SentryCore, 'captureException').mockImplementation(captureException); + vi.spyOn(CurrentScopes, 'getClient').mockImplementation(() => mockClient); + vi.spyOn(CurrentScopes, 'withScope').mockImplementation(withScope); CONSOLE_LEVELS.forEach(key => { originalConsoleMethods[key] = mockConsole[key]; @@ -55,7 +58,7 @@ describe('CaptureConsole setup', () => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); CONSOLE_LEVELS.forEach(key => { originalConsoleMethods[key] = _originalConsoleMethods[key]; @@ -135,7 +138,7 @@ describe('CaptureConsole setup', () => { expect(mockScope.addEventProcessor).toHaveBeenCalledTimes(1); - const addedEventProcessor = (mockScope.addEventProcessor as jest.Mock).mock.calls[0][0]; + const addedEventProcessor = (mockScope.addEventProcessor as Mock).mock.calls[0][0]; const someEvent: Event = {}; addedEventProcessor(someEvent); @@ -264,7 +267,7 @@ describe('CaptureConsole setup', () => { it('should call the original console function when console members are called', () => { // Mock console log to test if it was called const originalConsoleLog = GLOBAL_OBJ.console.log; - const mockConsoleLog = jest.fn(); + const mockConsoleLog = vi.fn(); GLOBAL_OBJ.console.log = mockConsoleLog; const captureConsole = captureConsoleIntegration({ levels: ['log'] }); @@ -309,7 +312,7 @@ describe('CaptureConsole setup', () => { }); it("marks captured exception's mechanism as unhandled", () => { - // const addExceptionMechanismSpy = jest.spyOn(utils, 'addExceptionMechanism'); + // const addExceptionMechanismSpy = vi.spyOn(utils, 'addExceptionMechanism'); const captureConsole = captureConsoleIntegration({ levels: ['error'] }); captureConsole.setup?.(mockClient); @@ -317,7 +320,7 @@ describe('CaptureConsole setup', () => { const someError = new Error('some error'); GLOBAL_OBJ.console.error(someError); - const addedEventProcessor = (mockScope.addEventProcessor as jest.Mock).mock.calls[0][0]; + const addedEventProcessor = (mockScope.addEventProcessor as Mock).mock.calls[0][0]; const someEvent: Event = { exception: { values: [{}], diff --git a/packages/core/test/lib/integrations/debug.test.ts b/packages/core/test/lib/integrations/debug.test.ts index c391d3057f0e..a403eceab51d 100644 --- a/packages/core/test/lib/integrations/debug.test.ts +++ b/packages/core/test/lib/integrations/debug.test.ts @@ -1,5 +1,6 @@ import type { Client, Event, EventHint } from '@sentry/types'; +import { afterAll, afterEach, describe, expect, it, vi } from 'vitest'; import { debugIntegration } from '../../../src/integrations/debug'; function testEventLogged( @@ -26,7 +27,7 @@ function testEventLogged( } // Replace console log with a mock so we can check for invocations -const mockConsoleLog = jest.fn(); +const mockConsoleLog = vi.fn(); // eslint-disable-next-line @typescript-eslint/unbound-method const originalConsoleLog = global.console.log; global.console.log = mockConsoleLog; @@ -38,7 +39,7 @@ describe('Debug integration setup should register an event processor that', () = }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('logs an event', () => { diff --git a/packages/core/test/lib/integrations/dedupe.test.ts b/packages/core/test/lib/integrations/dedupe.test.ts index 9478f41a6492..aeb02cba1bb1 100644 --- a/packages/core/test/lib/integrations/dedupe.test.ts +++ b/packages/core/test/lib/integrations/dedupe.test.ts @@ -1,5 +1,6 @@ import type { Event as SentryEvent, Exception, StackFrame, Stacktrace } from '@sentry/types'; +import { describe, expect, it } from 'vitest'; import { _shouldDropEvent, dedupeIntegration } from '../../../src/integrations/dedupe'; type EventWithException = SentryEvent & { diff --git a/packages/core/test/lib/integrations/extraerrordata.test.ts b/packages/core/test/lib/integrations/extraerrordata.test.ts index d38f8fff25ee..66ee8376b3c3 100644 --- a/packages/core/test/lib/integrations/extraerrordata.test.ts +++ b/packages/core/test/lib/integrations/extraerrordata.test.ts @@ -2,6 +2,7 @@ import type { Event as SentryEvent, ExtendedError } from '@sentry/types'; import { extraErrorDataIntegration } from '../../../src/integrations/extraerrordata'; +import { beforeEach, describe, expect, it } from 'vitest'; import { TestClient, getDefaultTestClientOptions } from '../../mocks/client'; const extraErrorData = extraErrorDataIntegration(); diff --git a/packages/core/test/lib/integrations/functiontostring.test.ts b/packages/core/test/lib/integrations/functiontostring.test.ts index 87a85744c7ce..fb875564fdbb 100644 --- a/packages/core/test/lib/integrations/functiontostring.test.ts +++ b/packages/core/test/lib/integrations/functiontostring.test.ts @@ -1,4 +1,5 @@ import { fill } from '@sentry/utils'; +import { afterAll, beforeEach, describe, expect, it } from 'vitest'; import { getClient, getCurrentScope, setCurrentClient } from '../../../src'; import { functionToStringIntegration } from '../../../src/integrations/functiontostring'; import { TestClient, getDefaultTestClientOptions } from '../../mocks/client'; diff --git a/packages/core/test/lib/integrations/inboundfilters.test.ts b/packages/core/test/lib/integrations/inboundfilters.test.ts index eb68c8c14d3b..a91330eee382 100644 --- a/packages/core/test/lib/integrations/inboundfilters.test.ts +++ b/packages/core/test/lib/integrations/inboundfilters.test.ts @@ -1,5 +1,6 @@ import type { Event, EventProcessor } from '@sentry/types'; +import { describe, expect, it } from 'vitest'; import type { InboundFiltersOptions } from '../../../src/integrations/inboundfilters'; import { inboundFiltersIntegration } from '../../../src/integrations/inboundfilters'; import { TestClient, getDefaultTestClientOptions } from '../../mocks/client'; diff --git a/packages/core/test/lib/integrations/metadata.test.ts b/packages/core/test/lib/integrations/metadata.test.ts index 2fb06bd6081d..a2fe55b645c0 100644 --- a/packages/core/test/lib/integrations/metadata.test.ts +++ b/packages/core/test/lib/integrations/metadata.test.ts @@ -1,6 +1,7 @@ import type { Event } from '@sentry/types'; import { GLOBAL_OBJ, createStackParser, nodeStackLineParser, parseEnvelope } from '@sentry/utils'; +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; import { captureException, createTransport, moduleMetadataIntegration, setCurrentClient } from '../../../src'; import { TestClient, getDefaultTestClientOptions } from '../../mocks/client'; @@ -18,7 +19,7 @@ describe('ModuleMetadata integration', () => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); test('Adds and removes metadata from stack frames', done => { diff --git a/packages/core/test/lib/integrations/requestdata.test.ts b/packages/core/test/lib/integrations/requestdata.test.ts index 648d47e4faf5..b21ff8023167 100644 --- a/packages/core/test/lib/integrations/requestdata.test.ts +++ b/packages/core/test/lib/integrations/requestdata.test.ts @@ -4,9 +4,10 @@ import * as sentryUtils from '@sentry/utils'; import type { RequestDataIntegrationOptions } from '../../../src'; import { requestDataIntegration, setCurrentClient } from '../../../src'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { TestClient, getDefaultTestClientOptions } from '../../mocks/client'; -const addRequestDataToEventSpy = jest.spyOn(sentryUtils, 'addRequestDataToEvent'); +const addRequestDataToEventSpy = vi.spyOn(sentryUtils, 'addRequestDataToEvent'); const headers = { ears: 'furry', nose: 'wet', tongue: 'spotted', cookie: 'favorite=zukes' }; const method = 'wagging'; @@ -53,7 +54,7 @@ describe('`RequestData` integration', () => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); describe('option conversion', () => { diff --git a/packages/core/test/lib/integrations/rewriteframes.test.ts b/packages/core/test/lib/integrations/rewriteframes.test.ts index f3ea865b459d..d14cdd2ee58b 100644 --- a/packages/core/test/lib/integrations/rewriteframes.test.ts +++ b/packages/core/test/lib/integrations/rewriteframes.test.ts @@ -1,5 +1,6 @@ import type { Event, StackFrame } from '@sentry/types'; +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest'; import { generateIteratee, rewriteFramesIntegration } from '../../../src/integrations/rewriteframes'; let rewriteFrames: ReturnType; diff --git a/packages/core/test/lib/integrations/sessiontiming.test.ts b/packages/core/test/lib/integrations/sessiontiming.test.ts index 6213d7cae9c1..4f14febb41ec 100644 --- a/packages/core/test/lib/integrations/sessiontiming.test.ts +++ b/packages/core/test/lib/integrations/sessiontiming.test.ts @@ -1,4 +1,5 @@ import type { Event } from '@sentry/types'; +import { describe, expect, it } from 'vitest'; import { sessionTimingIntegration } from '../../../src/integrations/sessiontiming'; const sessionTiming = sessionTimingIntegration(); diff --git a/packages/core/test/lib/integrations/third-party-errors-filter.test.ts b/packages/core/test/lib/integrations/third-party-errors-filter.test.ts index b11b93498b02..b1440de17195 100644 --- a/packages/core/test/lib/integrations/third-party-errors-filter.test.ts +++ b/packages/core/test/lib/integrations/third-party-errors-filter.test.ts @@ -3,6 +3,8 @@ import { GLOBAL_OBJ, createStackParser, nodeStackLineParser } from '@sentry/util import { thirdPartyErrorFilterIntegration } from '../../../src/integrations/third-party-errors-filter'; import { addMetadataToStackFrames } from '../../../src/metadata'; +import { beforeEach, describe, expect, it } from 'vitest'; + function clone(data: T): T { return JSON.parse(JSON.stringify(data)); } diff --git a/packages/core/test/lib/integrations/zoderrrors.test.ts b/packages/core/test/lib/integrations/zoderrrors.test.ts index 33dc2609ac09..9523c8806c52 100644 --- a/packages/core/test/lib/integrations/zoderrrors.test.ts +++ b/packages/core/test/lib/integrations/zoderrrors.test.ts @@ -1,5 +1,6 @@ import type { Event, EventHint } from '@sentry/types'; +import { describe, expect, test } from 'vitest'; import { applyZodErrorsToEvent } from '../../../src/integrations/zoderrors'; // Simplified type definition diff --git a/packages/core/test/lib/metadata.test.ts b/packages/core/test/lib/metadata.test.ts index 378bb51e6562..9fe22a238a5a 100644 --- a/packages/core/test/lib/metadata.test.ts +++ b/packages/core/test/lib/metadata.test.ts @@ -1,6 +1,7 @@ import type { Event } from '@sentry/types'; import { GLOBAL_OBJ, createStackParser, nodeStackLineParser } from '@sentry/utils'; +import { beforeEach, describe, expect, it } from 'vitest'; import { addMetadataToStackFrames, getMetadataForUrl, stripMetadataFromStackFrames } from '../../src/metadata'; const parser = createStackParser(nodeStackLineParser()); diff --git a/packages/core/test/lib/metrics/aggregator.test.ts b/packages/core/test/lib/metrics/aggregator.test.ts index 2a471d12bb04..1dfa93c7eedb 100644 --- a/packages/core/test/lib/metrics/aggregator.test.ts +++ b/packages/core/test/lib/metrics/aggregator.test.ts @@ -1,3 +1,4 @@ +import { beforeEach, describe, expect, it, test, vi } from 'vitest'; import { MetricsAggregator } from '../../../src/metrics/aggregator'; import { MAX_WEIGHT } from '../../../src/metrics/constants'; import { CounterMetric } from '../../../src/metrics/instance'; @@ -10,7 +11,7 @@ describe('MetricsAggregator', () => { const options = getDefaultTestClientOptions({ tracesSampleRate: 0.0 }); beforeEach(() => { - jest.useFakeTimers('legacy'); + vi.useFakeTimers(); testClient = new TestClient(options); }); @@ -81,12 +82,13 @@ describe('MetricsAggregator', () => { describe('close', () => { test('should flush immediately', () => { - const capture = jest.spyOn(testClient, 'sendEnvelope'); + const clearIntervalSpy = vi.spyOn(global, 'clearInterval'); + const capture = vi.spyOn(testClient, 'sendEnvelope'); const aggregator = new MetricsAggregator(testClient); aggregator.add('c', 'requests', 1); aggregator.close(); // It should clear the interval. - expect(clearInterval).toHaveBeenCalled(); + expect(clearIntervalSpy).toHaveBeenCalledTimes(1); expect(capture).toBeCalled(); expect(capture).toBeCalledTimes(1); }); @@ -94,7 +96,8 @@ describe('MetricsAggregator', () => { describe('flush', () => { test('should flush immediately', () => { - const capture = jest.spyOn(testClient, 'sendEnvelope'); + const clearIntervalSpy = vi.spyOn(global, 'clearInterval'); + const capture = vi.spyOn(testClient, 'sendEnvelope'); const aggregator = new MetricsAggregator(testClient); aggregator.add('c', 'requests', 1); aggregator.flush(); @@ -104,14 +107,14 @@ describe('MetricsAggregator', () => { capture.mockReset(); aggregator.close(); // It should clear the interval. - expect(clearInterval).toHaveBeenCalled(); + expect(clearIntervalSpy).toHaveBeenCalledTimes(1); // It shouldn't be called since it's been already flushed. expect(capture).toBeCalledTimes(0); }); test('should not capture if empty', () => { - const capture = jest.spyOn(testClient, 'sendEnvelope'); + const capture = vi.spyOn(testClient, 'sendEnvelope'); const aggregator = new MetricsAggregator(testClient); aggregator.add('c', 'requests', 1); aggregator.flush(); @@ -124,7 +127,7 @@ describe('MetricsAggregator', () => { describe('add', () => { test('it should respect the max weight and flush if exceeded', () => { - const capture = jest.spyOn(testClient, 'sendEnvelope'); + const capture = vi.spyOn(testClient, 'sendEnvelope'); const aggregator = new MetricsAggregator(testClient); for (let i = 0; i < MAX_WEIGHT; i++) { diff --git a/packages/core/test/lib/metrics/browser-aggregator.test.ts b/packages/core/test/lib/metrics/browser-aggregator.test.ts index 669959a03e05..de0668f6021c 100644 --- a/packages/core/test/lib/metrics/browser-aggregator.test.ts +++ b/packages/core/test/lib/metrics/browser-aggregator.test.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import { BrowserMetricsAggregator } from '../../../src/metrics/browser-aggregator'; import { CounterMetric } from '../../../src/metrics/instance'; import { serializeMetricBuckets } from '../../../src/metrics/utils'; diff --git a/packages/core/test/lib/metrics/timing.test.ts b/packages/core/test/lib/metrics/timing.test.ts index fa7c9f88da77..066d06790e91 100644 --- a/packages/core/test/lib/metrics/timing.test.ts +++ b/packages/core/test/lib/metrics/timing.test.ts @@ -1,3 +1,4 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { getCurrentScope, getIsolationScope, setCurrentClient } from '../../../src'; import { MetricsAggregator } from '../../../src/metrics/aggregator'; import { metrics as metricsCore } from '../../../src/metrics/exports'; @@ -28,7 +29,7 @@ describe('metrics.timing', () => { const res = metricsDefault.timing('t1', 10); expect(res).toStrictEqual(undefined); - const sendSpy = jest.spyOn(testClient.getTransport()!, 'send'); + const sendSpy = vi.spyOn(testClient.getTransport()!, 'send'); metricsCore.getMetricsAggregatorForClient(testClient, MetricsAggregator)!.flush(); @@ -43,7 +44,7 @@ describe('metrics.timing', () => { const res = metricsDefault.timing('t1', 10, 'hour'); expect(res).toStrictEqual(undefined); - const sendSpy = jest.spyOn(testClient.getTransport()!, 'send'); + const sendSpy = vi.spyOn(testClient.getTransport()!, 'send'); metricsCore.getMetricsAggregatorForClient(testClient, MetricsAggregator)!.flush(); @@ -60,7 +61,7 @@ describe('metrics.timing', () => { }); expect(res).toStrictEqual(undefined); - const sendSpy = jest.spyOn(testClient.getTransport()!, 'send'); + const sendSpy = vi.spyOn(testClient.getTransport()!, 'send'); metricsCore.getMetricsAggregatorForClient(testClient, MetricsAggregator)!.flush(); @@ -83,7 +84,7 @@ describe('metrics.timing', () => { }); expect(res).toStrictEqual('oho'); - const sendSpy = jest.spyOn(testClient.getTransport()!, 'send'); + const sendSpy = vi.spyOn(testClient.getTransport()!, 'send'); metricsCore.getMetricsAggregatorForClient(testClient, MetricsAggregator)!.flush(); @@ -102,7 +103,7 @@ describe('metrics.timing', () => { expect(res).toBeInstanceOf(Promise); expect(await res).toStrictEqual('oho'); - const sendSpy = jest.spyOn(testClient.getTransport()!, 'send'); + const sendSpy = vi.spyOn(testClient.getTransport()!, 'send'); metricsCore.getMetricsAggregatorForClient(testClient, MetricsAggregator)!.flush(); diff --git a/packages/core/test/lib/metrics/utils.test.ts b/packages/core/test/lib/metrics/utils.test.ts index e25014715748..7885f828080b 100644 --- a/packages/core/test/lib/metrics/utils.test.ts +++ b/packages/core/test/lib/metrics/utils.test.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import { COUNTER_METRIC_TYPE, DISTRIBUTION_METRIC_TYPE, @@ -15,7 +16,7 @@ describe('getBucketKey', () => { [DISTRIBUTION_METRIC_TYPE, 'lcp', 'second', { a: '1', b: '2', c: '3' }, 'dlcpseconda,1,b,2,c,3'], [DISTRIBUTION_METRIC_TYPE, 'lcp', 'second', { numericKey: '2' }, 'dlcpsecondnumericKey,2'], [SET_METRIC_TYPE, 'important_org_ids', 'none', { numericKey: '2' }, 'simportant_org_idsnonenumericKey,2'], - ])('should return', (metricType, name, unit, tags, expected) => { + ])('should return (%s, %s, %s, %s) -> %s', (metricType, name, unit, tags, expected) => { expect(getBucketKey(metricType, name, unit, tags)).toEqual(expected); }); diff --git a/packages/core/test/lib/prepareEvent.test.ts b/packages/core/test/lib/prepareEvent.test.ts index 0698aa15e447..0da220b07dcb 100644 --- a/packages/core/test/lib/prepareEvent.test.ts +++ b/packages/core/test/lib/prepareEvent.test.ts @@ -11,6 +11,7 @@ import type { import { GLOBAL_OBJ, createStackParser } from '@sentry/utils'; import { getGlobalScope, getIsolationScope } from '../../src'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { Scope } from '../../src/scope'; import { applyDebugIds, @@ -197,7 +198,7 @@ describe('prepareEvent', () => { }); it('works without any scope data', async () => { - const eventProcessor = jest.fn((a: unknown) => a) as EventProcessor; + const eventProcessor = vi.fn((a: unknown) => a) as EventProcessor; const scope = new Scope(); @@ -242,9 +243,9 @@ describe('prepareEvent', () => { const breadcrumb3 = { message: '3', timestamp: 123 } as Breadcrumb; const breadcrumb4 = { message: '4', timestamp: 123 } as Breadcrumb; - const eventProcessor1 = jest.fn((a: unknown) => a) as EventProcessor; - const eventProcessor2 = jest.fn((b: unknown) => b) as EventProcessor; - const eventProcessor3 = jest.fn((b: unknown) => b) as EventProcessor; + const eventProcessor1 = vi.fn((a: unknown) => a) as EventProcessor; + const eventProcessor2 = vi.fn((b: unknown) => b) as EventProcessor; + const eventProcessor3 = vi.fn((b: unknown) => b) as EventProcessor; const attachment1 = { filename: '1' } as Attachment; const attachment2 = { filename: '2' } as Attachment; @@ -326,8 +327,8 @@ describe('prepareEvent', () => { const breadcrumb2 = { message: '2', timestamp: 222 } as Breadcrumb; const breadcrumb3 = { message: '3', timestamp: 333 } as Breadcrumb; - const eventProcessor1 = jest.fn((a: unknown) => a) as EventProcessor; - const eventProcessor2 = jest.fn((a: unknown) => a) as EventProcessor; + const eventProcessor1 = vi.fn((a: unknown) => a) as EventProcessor; + const eventProcessor2 = vi.fn((a: unknown) => a) as EventProcessor; const attachmentGlobal = { filename: 'global scope attachment' } as Attachment; const attachmentIsolation = { filename: 'isolation scope attachment' } as Attachment; @@ -490,7 +491,7 @@ describe('prepareEvent', () => { const captureContextScope = new Scope(); captureContextScope.setTags({ foo: 'bar' }); - const captureContext = jest.fn(passedScope => { + const captureContext = vi.fn(passedScope => { expect(passedScope).toEqual(scope); return captureContextScope; }); diff --git a/packages/core/test/lib/scope.test.ts b/packages/core/test/lib/scope.test.ts index 33c89a2e9eb5..0836546664bd 100644 --- a/packages/core/test/lib/scope.test.ts +++ b/packages/core/test/lib/scope.test.ts @@ -8,6 +8,7 @@ import { withScope, } from '../../src'; +import { beforeEach, describe, expect, it, test, vi } from 'vitest'; import { Scope } from '../../src/scope'; import { TestClient, getDefaultTestClientOptions } from '../mocks/client'; import { clearGlobalScope } from './clear-global-scope'; @@ -347,7 +348,7 @@ describe('Scope', () => { }); test('given callback function, pass it the scope and returns original or modified scope', () => { - const cb = jest + const cb = vi .fn() .mockImplementationOnce(v => v) .mockImplementationOnce(v => { @@ -365,7 +366,7 @@ describe('Scope', () => { }); test('given callback function, when it doesnt return instanceof Scope, ignore it and return original scope', () => { - const cb = jest.fn().mockImplementationOnce(_v => 'wat'); + const cb = vi.fn().mockImplementationOnce(_v => 'wat'); const updatedScope = scope.update(cb); expect(cb).toHaveBeenCalledWith(scope); expect(updatedScope).toEqual(scope); @@ -571,7 +572,7 @@ describe('Scope', () => { describe('.captureException()', () => { it('should call captureException() on client with newly generated event ID if not explicitly passed in', () => { - const fakeCaptureException = jest.fn(() => 'mock-event-id'); + const fakeCaptureException = vi.fn(() => 'mock-event-id'); const fakeClient = { captureException: fakeCaptureException, } as unknown as Client; @@ -600,7 +601,7 @@ describe('Scope', () => { }); it('should pass exception to captureException() on client', () => { - const fakeCaptureException = jest.fn(() => 'mock-event-id'); + const fakeCaptureException = vi.fn(() => 'mock-event-id'); const fakeClient = { captureException: fakeCaptureException, } as unknown as Client; @@ -615,7 +616,7 @@ describe('Scope', () => { }); it('should call captureException() on client with a synthetic exception', () => { - const fakeCaptureException = jest.fn(() => 'mock-event-id'); + const fakeCaptureException = vi.fn(() => 'mock-event-id'); const fakeClient = { captureException: fakeCaptureException, } as unknown as Client; @@ -632,7 +633,7 @@ describe('Scope', () => { }); it('should pass the original exception to captureException() on client', () => { - const fakeCaptureException = jest.fn(() => 'mock-event-id'); + const fakeCaptureException = vi.fn(() => 'mock-event-id'); const fakeClient = { captureException: fakeCaptureException, } as unknown as Client; @@ -650,7 +651,7 @@ describe('Scope', () => { }); it('should forward hint to captureException() on client', () => { - const fakeCaptureException = jest.fn(() => 'mock-event-id'); + const fakeCaptureException = vi.fn(() => 'mock-event-id'); const fakeClient = { captureException: fakeCaptureException, } as unknown as Client; @@ -669,7 +670,7 @@ describe('Scope', () => { describe('.captureMessage()', () => { it('should call captureMessage() on client with newly generated event ID if not explicitly passed in', () => { - const fakeCaptureMessage = jest.fn(() => 'mock-event-id'); + const fakeCaptureMessage = vi.fn(() => 'mock-event-id'); const fakeClient = { captureMessage: fakeCaptureMessage, } as unknown as Client; @@ -695,7 +696,7 @@ describe('Scope', () => { }); it('should pass exception to captureMessage() on client', () => { - const fakeCaptureMessage = jest.fn(() => 'mock-event-id'); + const fakeCaptureMessage = vi.fn(() => 'mock-event-id'); const fakeClient = { captureMessage: fakeCaptureMessage, } as unknown as Client; @@ -708,7 +709,7 @@ describe('Scope', () => { }); it('should call captureMessage() on client with a synthetic exception', () => { - const fakeCaptureMessage = jest.fn(() => 'mock-event-id'); + const fakeCaptureMessage = vi.fn(() => 'mock-event-id'); const fakeClient = { captureMessage: fakeCaptureMessage, } as unknown as Client; @@ -726,7 +727,7 @@ describe('Scope', () => { }); it('should pass the original exception to captureMessage() on client', () => { - const fakeCaptureMessage = jest.fn(() => 'mock-event-id'); + const fakeCaptureMessage = vi.fn(() => 'mock-event-id'); const fakeClient = { captureMessage: fakeCaptureMessage, } as unknown as Client; @@ -744,7 +745,7 @@ describe('Scope', () => { }); it('should forward level and hint to captureMessage() on client', () => { - const fakeCaptureMessage = jest.fn(() => 'mock-event-id'); + const fakeCaptureMessage = vi.fn(() => 'mock-event-id'); const fakeClient = { captureMessage: fakeCaptureMessage, } as unknown as Client; @@ -764,7 +765,7 @@ describe('Scope', () => { describe('.captureEvent()', () => { it('should call captureEvent() on client with newly generated event ID if not explicitly passed in', () => { - const fakeCaptureEvent = jest.fn(() => 'mock-event-id'); + const fakeCaptureEvent = vi.fn(() => 'mock-event-id'); const fakeClient = { captureEvent: fakeCaptureEvent, } as unknown as Client; @@ -789,7 +790,7 @@ describe('Scope', () => { }); it('should pass event to captureEvent() on client', () => { - const fakeCaptureEvent = jest.fn(() => 'mock-event-id'); + const fakeCaptureEvent = vi.fn(() => 'mock-event-id'); const fakeClient = { captureEvent: fakeCaptureEvent, } as unknown as Client; @@ -804,7 +805,7 @@ describe('Scope', () => { }); it('should forward hint to captureEvent() on client', () => { - const fakeCaptureEvent = jest.fn(() => 'mock-event-id'); + const fakeCaptureEvent = vi.fn(() => 'mock-event-id'); const fakeClient = { captureEvent: fakeCaptureEvent, } as unknown as Client; @@ -861,30 +862,35 @@ describe('withScope()', () => { getGlobalScope().clear(); }); - it('will make the passed scope the active scope within the callback', done => { + it('makes the passed scope the active scope within the callback', () => { + expect.assertions(1); + withScope(scope => { expect(getCurrentScope()).toBe(scope); - done(); }); }); - it('will pass a scope that is different from the current active isolation scope', done => { + it('passes a scope that is different from the current active isolation scope', () => { + expect.assertions(1); + withScope(scope => { expect(getIsolationScope()).not.toBe(scope); - done(); }); }); - it('will always make the inner most passed scope the current isolation scope when nesting calls', done => { + it('always makes the inner most passed scope the current isolation scope when nesting calls', () => { + expect.assertions(1); + withIsolationScope(_scope1 => { withIsolationScope(scope2 => { expect(getIsolationScope()).toBe(scope2); - done(); }); }); }); - it('forks the scope when not passing any scope', done => { + it('forks the scope when not passing any scope', () => { + expect.assertions(3); + const initialScope = getCurrentScope(); initialScope.setTag('aa', 'aa'); @@ -893,11 +899,12 @@ describe('withScope()', () => { scope.setTag('bb', 'bb'); expect(scope).not.toBe(initialScope); expect(scope.getScopeData().tags).toEqual({ aa: 'aa', bb: 'bb' }); - done(); }); }); - it('forks the scope when passing undefined', done => { + it('forks the scope when passing undefined', () => { + expect.assertions(3); + const initialScope = getCurrentScope(); initialScope.setTag('aa', 'aa'); @@ -906,11 +913,12 @@ describe('withScope()', () => { scope.setTag('bb', 'bb'); expect(scope).not.toBe(initialScope); expect(scope.getScopeData().tags).toEqual({ aa: 'aa', bb: 'bb' }); - done(); }); }); - it('sets the passed in scope as active scope', done => { + it('sets the passed in scope as active scope', () => { + expect.assertions(2); + const initialScope = getCurrentScope(); initialScope.setTag('aa', 'aa'); @@ -919,7 +927,6 @@ describe('withScope()', () => { withScope(customScope, scope => { expect(getCurrentScope()).toBe(customScope); expect(scope).toBe(customScope); - done(); }); }); }); @@ -931,58 +938,64 @@ describe('withIsolationScope()', () => { getGlobalScope().clear(); }); - it('will make the passed isolation scope the active isolation scope within the callback', done => { + it('makes the passed isolation scope the active isolation scope within the callback', () => { + expect.assertions(1); + withIsolationScope(scope => { expect(getIsolationScope()).toBe(scope); - done(); }); }); - it('will pass an isolation scope that is different from the current active scope', done => { + it('passes an isolation scope that is different from the current active scope', () => { + expect.assertions(1); + withIsolationScope(scope => { expect(getCurrentScope()).not.toBe(scope); - done(); }); }); - it('will always make the inner most passed scope the current scope when nesting calls', done => { + it('always makes the inner most passed scope the current scope when nesting calls', () => { + expect.assertions(1); + withIsolationScope(_scope1 => { withIsolationScope(scope2 => { expect(getIsolationScope()).toBe(scope2); - done(); }); }); }); // Note: This is expected! In browser, we do not actually fork this - it('does not fork isolation scope when not passing any isolation scope', done => { + it('does not fork the isolation scope when not passing any isolation scope', () => { + expect.assertions(2); + const isolationScope = getIsolationScope(); withIsolationScope(scope => { expect(getIsolationScope()).toBe(scope); expect(scope).toBe(isolationScope); - done(); }); }); - it('does not fork isolation scope when passing undefined', done => { + it('does not fork isolation scope when passing undefined', () => { + expect.assertions(2); + const isolationScope = getIsolationScope(); withIsolationScope(undefined, scope => { expect(getIsolationScope()).toBe(scope); expect(scope).toBe(isolationScope); - done(); }); }); - it('ignores passed in isolation scope', done => { + it('ignores passed in isolation scope', () => { + expect.assertions(2); + const isolationScope = getIsolationScope(); const customIsolationScope = new Scope(); withIsolationScope(customIsolationScope, scope => { expect(getIsolationScope()).toBe(isolationScope); expect(scope).toBe(isolationScope); - done(); }); }); diff --git a/packages/core/test/lib/sdk.test.ts b/packages/core/test/lib/sdk.test.ts index 74213cd8d99f..6a486397405e 100644 --- a/packages/core/test/lib/sdk.test.ts +++ b/packages/core/test/lib/sdk.test.ts @@ -1,6 +1,8 @@ import type { Client, Integration } from '@sentry/types'; import { captureCheckIn, getCurrentScope, setCurrentClient } from '../../src'; +import type { Mock } from 'vitest'; +import { beforeEach, describe, expect, it, test, vi } from 'vitest'; import { installedIntegrations } from '../../src/integration'; import { initAndBind } from '../../src/sdk'; import { TestClient, getDefaultTestClientOptions } from '../mocks/client'; @@ -12,7 +14,7 @@ const PUBLIC_DSN = 'https://username@domain/123'; export class MockIntegration implements Integration { public name: string; - public setupOnce: () => void = jest.fn(); + public setupOnce: () => void = vi.fn(); public constructor(name: string) { this.name = name; } @@ -32,8 +34,8 @@ describe('SDK', () => { ]; const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations }); initAndBind(TestClient, options); - expect((integrations[0]?.setupOnce as jest.Mock).mock.calls.length).toBe(1); - expect((integrations[1]?.setupOnce as jest.Mock).mock.calls.length).toBe(1); + expect((integrations[0]?.setupOnce as Mock).mock.calls.length).toBe(1); + expect((integrations[1]?.setupOnce as Mock).mock.calls.length).toBe(1); }); test('calls hooks in the correct order', () => { @@ -41,21 +43,21 @@ describe('SDK', () => { const integration1 = { name: 'integration1', - setupOnce: jest.fn(() => list.push('setupOnce1')), - afterAllSetup: jest.fn(() => list.push('afterAllSetup1')), + setupOnce: vi.fn(() => list.push('setupOnce1')), + afterAllSetup: vi.fn(() => list.push('afterAllSetup1')), } satisfies Integration; const integration2 = { name: 'integration2', - setupOnce: jest.fn(() => list.push('setupOnce2')), - setup: jest.fn(() => list.push('setup2')), - afterAllSetup: jest.fn(() => list.push('afterAllSetup2')), + setupOnce: vi.fn(() => list.push('setupOnce2')), + setup: vi.fn(() => list.push('setup2')), + afterAllSetup: vi.fn(() => list.push('afterAllSetup2')), } satisfies Integration; const integration3 = { name: 'integration3', - setupOnce: jest.fn(() => list.push('setupOnce3')), - setup: jest.fn(() => list.push('setup3')), + setupOnce: vi.fn(() => list.push('setupOnce3')), + setup: vi.fn(() => list.push('setup3')), } satisfies Integration; const integrations: Integration[] = [integration1, integration2, integration3]; diff --git a/packages/core/test/lib/serverruntimeclient.test.ts b/packages/core/test/lib/serverruntimeclient.test.ts index 8b149f7f2aaa..a73d9fe8bc08 100644 --- a/packages/core/test/lib/serverruntimeclient.test.ts +++ b/packages/core/test/lib/serverruntimeclient.test.ts @@ -1,5 +1,6 @@ import type { Event, EventHint } from '@sentry/types'; +import { describe, expect, it, test, vi } from 'vitest'; import { createTransport } from '../../src'; import type { ServerRuntimeClientOptions } from '../../src/server-runtime-client'; import { ServerRuntimeClient } from '../../src/server-runtime-client'; @@ -77,7 +78,7 @@ describe('ServerRuntimeClient', () => { }); client = new ServerRuntimeClient(options); - const sendEnvelopeSpy = jest.spyOn(client, 'sendEnvelope'); + const sendEnvelopeSpy = vi.spyOn(client, 'sendEnvelope'); const id = client.captureCheckIn( { monitorSlug: 'foo', status: 'in_progress' }, @@ -147,7 +148,7 @@ describe('ServerRuntimeClient', () => { const options = getDefaultClientOptions({ dsn: PUBLIC_DSN, serverName: 'bar', enabled: false }); client = new ServerRuntimeClient(options); - const sendEnvelopeSpy = jest.spyOn(client, 'sendEnvelope'); + const sendEnvelopeSpy = vi.spyOn(client, 'sendEnvelope'); client.captureCheckIn({ monitorSlug: 'foo', status: 'in_progress' }); diff --git a/packages/core/test/lib/session.test.ts b/packages/core/test/lib/session.test.ts index 41eb0c234d13..09b07bf047b9 100644 --- a/packages/core/test/lib/session.test.ts +++ b/packages/core/test/lib/session.test.ts @@ -3,6 +3,8 @@ import { timestampInSeconds } from '@sentry/utils'; import { closeSession, makeSession, updateSession } from '../../src/session'; +import { describe, expect, it, test } from 'vitest'; + describe('Session', () => { it('initializes with the proper defaults', () => { const newSession = makeSession(); diff --git a/packages/core/test/lib/sessionflusher.test.ts b/packages/core/test/lib/sessionflusher.test.ts index 808ba6308069..13bf1ef7a628 100644 --- a/packages/core/test/lib/sessionflusher.test.ts +++ b/packages/core/test/lib/sessionflusher.test.ts @@ -2,20 +2,23 @@ import type { Client } from '@sentry/types'; import { SessionFlusher } from '../../src/sessionflusher'; +import type { Mock } from 'vitest'; +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; + describe('Session Flusher', () => { - let sendSession: jest.Mock; + let sendSession: Mock; let mockClient: Client; beforeEach(() => { - jest.useFakeTimers(); - sendSession = jest.fn(() => Promise.resolve({ status: 'success' })); + vi.useFakeTimers(); + sendSession = vi.fn(() => Promise.resolve({ status: 'success' })); mockClient = { sendSession, } as unknown as Client; }); afterEach(() => { - jest.restoreAllMocks(); + vi.restoreAllMocks(); }); test('test incrementSessionStatusCount updates the internal SessionFlusher state', () => { @@ -56,27 +59,27 @@ describe('Session Flusher', () => { test('flush is called every 60 seconds after initialisation of an instance of SessionFlusher', () => { const flusher = new SessionFlusher(mockClient, { release: '1.0.0', environment: 'dev' }); - const flusherFlushFunc = jest.spyOn(flusher, 'flush'); - jest.advanceTimersByTime(59000); + const flusherFlushFunc = vi.spyOn(flusher, 'flush'); + vi.advanceTimersByTime(59000); expect(flusherFlushFunc).toHaveBeenCalledTimes(0); - jest.advanceTimersByTime(2000); + vi.advanceTimersByTime(2000); expect(flusherFlushFunc).toHaveBeenCalledTimes(1); - jest.advanceTimersByTime(58000); + vi.advanceTimersByTime(58000); expect(flusherFlushFunc).toHaveBeenCalledTimes(1); - jest.advanceTimersByTime(2000); + vi.advanceTimersByTime(2000); expect(flusherFlushFunc).toHaveBeenCalledTimes(2); }); test('sendSessions is called on flush if sessions were captured', () => { const flusher = new SessionFlusher(mockClient, { release: '1.0.0', environment: 'dev' }); - const flusherFlushFunc = jest.spyOn(flusher, 'flush'); + const flusherFlushFunc = vi.spyOn(flusher, 'flush'); const date = new Date('2021-04-08T12:18:23.043Z'); (flusher as any)._incrementSessionStatusCount('ok', date); (flusher as any)._incrementSessionStatusCount('ok', date); expect(sendSession).toHaveBeenCalledTimes(0); - jest.advanceTimersByTime(61000); + vi.advanceTimersByTime(61000); expect(flusherFlushFunc).toHaveBeenCalledTimes(1); expect(sendSession).toHaveBeenCalledWith( @@ -89,10 +92,10 @@ describe('Session Flusher', () => { test('sendSessions is not called on flush if no sessions were captured', () => { const flusher = new SessionFlusher(mockClient, { release: '1.0.0', environment: 'dev' }); - const flusherFlushFunc = jest.spyOn(flusher, 'flush'); + const flusherFlushFunc = vi.spyOn(flusher, 'flush'); expect(sendSession).toHaveBeenCalledTimes(0); - jest.advanceTimersByTime(61000); + vi.advanceTimersByTime(61000); expect(flusherFlushFunc).toHaveBeenCalledTimes(1); expect(sendSession).toHaveBeenCalledTimes(0); }); @@ -105,7 +108,7 @@ describe('Session Flusher', () => { test('calling close on SessionFlusher will force call flush', () => { const flusher = new SessionFlusher(mockClient, { release: '1.0.x' }); - const flusherFlushFunc = jest.spyOn(flusher, 'flush'); + const flusherFlushFunc = vi.spyOn(flusher, 'flush'); const date = new Date('2021-04-08T12:18:23.043Z'); (flusher as any)._incrementSessionStatusCount('ok', date); (flusher as any)._incrementSessionStatusCount('ok', date); diff --git a/packages/core/test/lib/tracing/dynamicSamplingContext.test.ts b/packages/core/test/lib/tracing/dynamicSamplingContext.test.ts index 095416d929df..4ec61a45d50d 100644 --- a/packages/core/test/lib/tracing/dynamicSamplingContext.test.ts +++ b/packages/core/test/lib/tracing/dynamicSamplingContext.test.ts @@ -1,4 +1,5 @@ import type { Span, SpanContextData, TransactionSource } from '@sentry/types'; +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; import { SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, @@ -17,7 +18,7 @@ describe('getDynamicSamplingContextFromSpan', () => { }); afterEach(() => { - jest.resetAllMocks(); + vi.resetAllMocks(); }); test('uses frozen DSC from span', () => { diff --git a/packages/core/test/lib/tracing/errors.test.ts b/packages/core/test/lib/tracing/errors.test.ts index 3e3f85ef73b7..005968413412 100644 --- a/packages/core/test/lib/tracing/errors.test.ts +++ b/packages/core/test/lib/tracing/errors.test.ts @@ -1,16 +1,17 @@ import type { HandlerDataError, HandlerDataUnhandledRejection } from '@sentry/types'; import { setCurrentClient, spanToJSON, startInactiveSpan, startSpan } from '../../../src'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { _resetErrorsInstrumented, registerSpanErrorInstrumentation } from '../../../src/tracing/errors'; import { TestClient, getDefaultTestClientOptions } from '../../mocks/client'; -const mockAddGlobalErrorInstrumentationHandler = jest.fn(); -const mockAddGlobalUnhandledRejectionInstrumentationHandler = jest.fn(); +const mockAddGlobalErrorInstrumentationHandler = vi.fn(); +const mockAddGlobalUnhandledRejectionInstrumentationHandler = vi.fn(); let mockErrorCallback: (data: HandlerDataError) => void = () => {}; let mockUnhandledRejectionCallback: (data: HandlerDataUnhandledRejection) => void = () => {}; -jest.mock('@sentry/utils', () => { - const actual = jest.requireActual('@sentry/utils'); +vi.mock('@sentry/utils', async () => { + const actual = await vi.importActual('@sentry/utils'); return { ...actual, addGlobalErrorInstrumentationHandler: (callback: () => void) => { diff --git a/packages/core/test/lib/tracing/idleSpan.test.ts b/packages/core/test/lib/tracing/idleSpan.test.ts index ff45938646a1..c3044916df96 100644 --- a/packages/core/test/lib/tracing/idleSpan.test.ts +++ b/packages/core/test/lib/tracing/idleSpan.test.ts @@ -1,3 +1,4 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { TestClient, getDefaultTestClientOptions } from '../../mocks/client'; import type { Event, Span } from '@sentry/types'; @@ -22,7 +23,7 @@ const dsn = 'https://123@sentry.io/42'; describe('startIdleSpan', () => { beforeEach(() => { - jest.useFakeTimers(); + vi.useFakeTimers(); getCurrentScope().clear(); getIsolationScope().clear(); @@ -35,7 +36,7 @@ describe('startIdleSpan', () => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('sets & unsets the idle span on the scope', () => { @@ -46,7 +47,7 @@ describe('startIdleSpan', () => { expect(getActiveSpan()).toBe(idleSpan); idleSpan!.end(); - jest.runAllTimers(); + vi.runAllTimers(); expect(getActiveSpan()).toBe(undefined); }); @@ -73,13 +74,13 @@ describe('startIdleSpan', () => { const childSpan = startInactiveSpan({ name: 'inner2' }); span.end(); - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout + 1); + vi.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout + 1); // Idle span is still recording expect(idleSpan.isRecording()).toBe(true); childSpan.end(); - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout + 1); + vi.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout + 1); // Now it is finished! expect(idleSpan.isRecording()).toBe(false); @@ -87,7 +88,7 @@ describe('startIdleSpan', () => { }); it('calls beforeSpanEnd callback before finishing', () => { - const beforeSpanEnd = jest.fn(); + const beforeSpanEnd = vi.fn(); const idleSpan = startIdleSpan({ name: 'foo' }, { beforeSpanEnd }); expect(idleSpan).toBeDefined(); @@ -95,14 +96,14 @@ describe('startIdleSpan', () => { startSpan({ name: 'inner' }, () => {}); - jest.runOnlyPendingTimers(); + vi.runOnlyPendingTimers(); expect(beforeSpanEnd).toHaveBeenCalledTimes(1); expect(beforeSpanEnd).toHaveBeenLastCalledWith(idleSpan); }); it('allows to mutate idle span in beforeSpanEnd before it is sent', () => { const transactions: Event[] = []; - const beforeSendTransaction = jest.fn(event => { + const beforeSendTransaction = vi.fn(event => { transactions.push(event); return null; }); @@ -118,7 +119,7 @@ describe('startIdleSpan', () => { // We want to accomodate a bit of drift there, so we ensure this starts earlier... const baseTimeInSeconds = Math.floor(Date.now() / 1000) - 9999; - const beforeSpanEnd = jest.fn((span: Span) => { + const beforeSpanEnd = vi.fn((span: Span) => { span.setAttribute('foo', 'bar'); // Try adding a child here - we do this in browser tracing... const inner = startInactiveSpan({ name: 'from beforeSpanEnd', startTime: baseTimeInSeconds }); @@ -129,8 +130,8 @@ describe('startIdleSpan', () => { expect(beforeSpanEnd).not.toHaveBeenCalled(); - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout + 1); - jest.runOnlyPendingTimers(); + vi.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout + 1); + vi.runOnlyPendingTimers(); expect(spanToJSON(idleSpan!).data).toEqual( expect.objectContaining({ @@ -156,7 +157,7 @@ describe('startIdleSpan', () => { it('filters spans on end', () => { const transactions: Event[] = []; - const beforeSendTransaction = jest.fn(event => { + const beforeSendTransaction = vi.fn(event => { transactions.push(event); return null; }); @@ -196,8 +197,8 @@ describe('startIdleSpan', () => { regularSpan.end(baseTimeInSeconds + 4); idleSpan.end(baseTimeInSeconds + 10); - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout + 1); - jest.runOnlyPendingTimers(); + vi.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout + 1); + vi.runOnlyPendingTimers(); expect(regularSpan.isRecording()).toBe(false); expect(idleSpan.isRecording()).toBe(false); @@ -236,7 +237,7 @@ describe('startIdleSpan', () => { it('Ensures idle span cannot exceed finalTimeout', () => { const transactions: Event[] = []; - const beforeSendTransaction = jest.fn(event => { + const beforeSendTransaction = vi.fn(event => { transactions.push(event); return null; }); @@ -273,7 +274,7 @@ describe('startIdleSpan', () => { startTime: baseTimeInSeconds + 4, }); - jest.runOnlyPendingTimers(); + vi.runOnlyPendingTimers(); expect(regularSpan.isRecording()).toBe(false); expect(idleSpan.isRecording()).toBe(false); @@ -325,7 +326,7 @@ describe('startIdleSpan', () => { expect(hookSpans).toEqual([{ span: idleSpan, hook: 'spanStart' }]); - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); + vi.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); expect(spanToJSON(idleSpan).timestamp).toBeDefined(); expect(hookSpans).toEqual([ @@ -343,7 +344,7 @@ describe('startIdleSpan', () => { setCurrentClient(client); client.init(); - const recordDroppedEventSpy = jest.spyOn(client, 'recordDroppedEvent'); + const recordDroppedEventSpy = vi.spyOn(client, 'recordDroppedEvent'); const idleSpan = startIdleSpan({ name: 'idle span' }); expect(idleSpan).toBeDefined(); @@ -355,7 +356,7 @@ describe('startIdleSpan', () => { it('sets finish reason when span is ended manually', () => { let transaction: Event | undefined; - const beforeSendTransaction = jest.fn(event => { + const beforeSendTransaction = vi.fn(event => { transaction = event; return null; }); @@ -366,7 +367,7 @@ describe('startIdleSpan', () => { const span = startIdleSpan({ name: 'foo' }); span.end(); - jest.runOnlyPendingTimers(); + vi.runOnlyPendingTimers(); expect(beforeSendTransaction).toHaveBeenCalledTimes(1); expect(transaction?.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON]).toEqual( @@ -376,7 +377,7 @@ describe('startIdleSpan', () => { it('sets finish reason when span ends', () => { let transaction: Event | undefined; - const beforeSendTransaction = jest.fn(event => { + const beforeSendTransaction = vi.fn(event => { transaction = event; return null; }); @@ -387,7 +388,7 @@ describe('startIdleSpan', () => { startIdleSpan({ name: 'foo' }); startSpan({ name: 'inner' }, () => {}); - jest.runOnlyPendingTimers(); + vi.runOnlyPendingTimers(); expect(beforeSendTransaction).toHaveBeenCalledTimes(1); expect(transaction?.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON]).toEqual( @@ -397,7 +398,7 @@ describe('startIdleSpan', () => { it('sets finish reason when span ends via expired heartbeat timeout', () => { let transaction: Event | undefined; - const beforeSendTransaction = jest.fn(event => { + const beforeSendTransaction = vi.fn(event => { transaction = event; return null; }); @@ -408,7 +409,7 @@ describe('startIdleSpan', () => { startIdleSpan({ name: 'foo' }); startSpanManual({ name: 'inner' }, () => {}); - jest.runOnlyPendingTimers(); + vi.runOnlyPendingTimers(); expect(beforeSendTransaction).toHaveBeenCalledTimes(1); expect(transaction?.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON]).toEqual( @@ -418,7 +419,7 @@ describe('startIdleSpan', () => { it('sets finish reason when span ends via final timeout', () => { let transaction: Event | undefined; - const beforeSendTransaction = jest.fn(event => { + const beforeSendTransaction = vi.fn(event => { transaction = event; return null; }); @@ -430,15 +431,15 @@ describe('startIdleSpan', () => { startIdleSpan({ name: 'foo' }, { finalTimeout: TRACING_DEFAULTS.childSpanTimeout * 2 }); const span1 = startInactiveSpan({ name: 'inner' }); - jest.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout - 1); + vi.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout - 1); span1.end(); const span2 = startInactiveSpan({ name: 'inner2' }); - jest.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout - 1); + vi.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout - 1); span2.end(); startInactiveSpan({ name: 'inner3' }); - jest.runOnlyPendingTimers(); + vi.runOnlyPendingTimers(); expect(beforeSendTransaction).toHaveBeenCalledTimes(1); expect(transaction?.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON]).toEqual( @@ -448,7 +449,7 @@ describe('startIdleSpan', () => { it('uses finish reason set outside when span ends', () => { let transaction: Event | undefined; - const beforeSendTransaction = jest.fn(event => { + const beforeSendTransaction = vi.fn(event => { transaction = event; return null; }); @@ -460,7 +461,7 @@ describe('startIdleSpan', () => { const span = startIdleSpan({ name: 'foo' }); span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON, 'custom reason'); startSpan({ name: 'inner' }, () => {}); - jest.runOnlyPendingTimers(); + vi.runOnlyPendingTimers(); expect(beforeSendTransaction).toHaveBeenCalledTimes(1); expect(transaction?.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON]).toEqual( @@ -473,7 +474,7 @@ describe('startIdleSpan', () => { const idleSpan = startIdleSpan({ name: 'idle span' }); expect(idleSpan).toBeDefined(); - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); + vi.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); expect(spanToJSON(idleSpan).timestamp).toBeDefined(); }); @@ -483,7 +484,7 @@ describe('startIdleSpan', () => { startInactiveSpan({ name: 'span' }); - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); + vi.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); }); @@ -494,11 +495,11 @@ describe('startIdleSpan', () => { startSpan({ name: 'span1' }, () => {}); - jest.advanceTimersByTime(2); + vi.advanceTimersByTime(2); startSpan({ name: 'span2' }, () => {}); - jest.advanceTimersByTime(8); + vi.advanceTimersByTime(8); expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); }); @@ -510,11 +511,11 @@ describe('startIdleSpan', () => { startSpan({ name: 'span1' }, () => {}); - jest.advanceTimersByTime(2); + vi.advanceTimersByTime(2); startSpan({ name: 'span2' }, () => {}); - jest.advanceTimersByTime(10); + vi.advanceTimersByTime(10); expect(spanToJSON(idleSpan).timestamp).toBeDefined(); }); @@ -532,12 +533,12 @@ describe('startIdleSpan', () => { expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); // Wait some time - jest.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout - 1000); + vi.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout - 1000); expect(spanToJSON(idleSpan).status).not.toEqual('deadline_exceeded'); expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); // Wait for timeout to exceed - jest.advanceTimersByTime(1000); + vi.advanceTimersByTime(1000); expect(spanToJSON(idleSpan).status).not.toEqual('deadline_exceeded'); expect(spanToJSON(idleSpan).timestamp).toBeDefined(); }); @@ -553,26 +554,26 @@ describe('startIdleSpan', () => { expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); // Wait some time - jest.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout - 1000); + vi.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout - 1000); expect(spanToJSON(idleSpan).status).not.toEqual('deadline_exceeded'); expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); // New span resets the timeout startInactiveSpan({ name: 'span' }); - jest.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout - 1000); + vi.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout - 1000); expect(spanToJSON(idleSpan).status).not.toEqual('deadline_exceeded'); expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); // New span resets the timeout startInactiveSpan({ name: 'span' }); - jest.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout - 1000); + vi.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout - 1000); expect(spanToJSON(idleSpan).status).not.toEqual('deadline_exceeded'); expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); // Wait for timeout to exceed - jest.advanceTimersByTime(1000); + vi.advanceTimersByTime(1000); expect(spanToJSON(idleSpan).status).not.toEqual('deadline_exceeded'); expect(spanToJSON(idleSpan).timestamp).toBeDefined(); }); @@ -583,16 +584,16 @@ describe('startIdleSpan', () => { const idleSpan = startIdleSpan({ name: 'idle span' }, { disableAutoFinish: true }); expect(idleSpan).toBeDefined(); - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); + vi.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); + vi.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); // Now emit a signal getClient()!.emit('idleSpanEnableAutoFinish', idleSpan); - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); + vi.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); expect(spanToJSON(idleSpan).timestamp).toBeDefined(); }); @@ -602,16 +603,16 @@ describe('startIdleSpan', () => { startInactiveSpan({ name: 'inner' }); - jest.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout); + vi.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout); expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); - jest.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout); + vi.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout); expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); // Now emit a signal getClient()!.emit('idleSpanEnableAutoFinish', idleSpan); - jest.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout); + vi.advanceTimersByTime(TRACING_DEFAULTS.childSpanTimeout); expect(spanToJSON(idleSpan).timestamp).toBeDefined(); }); @@ -619,7 +620,7 @@ describe('startIdleSpan', () => { const idleSpan = startIdleSpan({ name: 'idle span' }, { disableAutoFinish: true }); expect(idleSpan).toBeDefined(); - jest.advanceTimersByTime(TRACING_DEFAULTS.finalTimeout); + vi.advanceTimersByTime(TRACING_DEFAULTS.finalTimeout); expect(spanToJSON(idleSpan).timestamp).toBeDefined(); }); @@ -628,17 +629,17 @@ describe('startIdleSpan', () => { const idleSpan = startIdleSpan({ name: 'idle span' }, { disableAutoFinish: true }); expect(idleSpan).toBeDefined(); - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); + vi.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); + vi.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); // Now emit a signal, but with a different span getClient()!.emit('idleSpanEnableAutoFinish', span); // This doesn't affect us! - jest.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); + vi.advanceTimersByTime(TRACING_DEFAULTS.idleTimeout); expect(spanToJSON(idleSpan).timestamp).toBeUndefined(); }); }); @@ -659,7 +660,7 @@ describe('startIdleSpan', () => { expect(getActiveSpan()).toBe(idleSpan); - jest.runAllTimers(); + vi.runAllTimers(); expect(spanToJSON(idleSpan!).timestamp).toBe(1100); }); @@ -679,7 +680,7 @@ describe('startIdleSpan', () => { expect(getActiveSpan()).toBe(idleSpan); - jest.runAllTimers(); + vi.runAllTimers(); expect(spanToJSON(idleSpan!).timestamp).toBe(1030); }); @@ -699,7 +700,7 @@ describe('startIdleSpan', () => { expect(getActiveSpan()).toBe(idleSpan); - jest.runAllTimers(); + vi.runAllTimers(); expect(spanToJSON(idleSpan!).timestamp).toBeLessThan(999_999_999); expect(spanToJSON(idleSpan!).timestamp).toBeGreaterThan(1060); diff --git a/packages/core/test/lib/tracing/sentryNonRecordingSpan.test.ts b/packages/core/test/lib/tracing/sentryNonRecordingSpan.test.ts index d5643c3d3651..dc10b7567e6b 100644 --- a/packages/core/test/lib/tracing/sentryNonRecordingSpan.test.ts +++ b/packages/core/test/lib/tracing/sentryNonRecordingSpan.test.ts @@ -1,4 +1,5 @@ import type { Span } from '@sentry/types'; +import { describe, expect, it } from 'vitest'; import { SPAN_STATUS_ERROR } from '../../../src/tracing'; import { SentryNonRecordingSpan } from '../../../src/tracing/sentryNonRecordingSpan'; import { TRACE_FLAG_NONE, spanIsSampled, spanToJSON } from '../../../src/utils/spanUtils'; diff --git a/packages/core/test/lib/tracing/sentrySpan.test.ts b/packages/core/test/lib/tracing/sentrySpan.test.ts index 9698ab5e3398..48cd8dc7ed48 100644 --- a/packages/core/test/lib/tracing/sentrySpan.test.ts +++ b/packages/core/test/lib/tracing/sentrySpan.test.ts @@ -1,4 +1,5 @@ import { timestampInSeconds } from '@sentry/utils'; +import { describe, expect, it, test, vi } from 'vitest'; import { setCurrentClient } from '../../../src'; import { SentrySpan } from '../../../src/tracing/sentrySpan'; import { SPAN_STATUS_ERROR } from '../../../src/tracing/spanstatus'; @@ -101,7 +102,7 @@ describe('SentrySpan', () => { setCurrentClient(client); // @ts-expect-error Accessing private transport API - const mockSend = jest.spyOn(client._transport, 'send'); + const mockSend = vi.spyOn(client._transport, 'send'); const notSampledSpan = new SentrySpan({ name: 'not-sampled', @@ -125,7 +126,7 @@ describe('SentrySpan', () => { }); test('sends the span if `beforeSendSpan` does not modify the span ', () => { - const beforeSendSpan = jest.fn(span => span); + const beforeSendSpan = vi.fn(span => span); const client = new TestClient( getDefaultTestClientOptions({ dsn: 'https://username@domain/123', @@ -136,7 +137,7 @@ describe('SentrySpan', () => { setCurrentClient(client); // @ts-expect-error Accessing private transport API - const mockSend = jest.spyOn(client._transport, 'send'); + const mockSend = vi.spyOn(client._transport, 'send'); const span = new SentrySpan({ name: 'test', isStandalone: true, @@ -149,7 +150,7 @@ describe('SentrySpan', () => { }); test('does not send the span if `beforeSendSpan` drops the span', () => { - const beforeSendSpan = jest.fn(() => null); + const beforeSendSpan = vi.fn(() => null); const client = new TestClient( getDefaultTestClientOptions({ dsn: 'https://username@domain/123', @@ -159,9 +160,9 @@ describe('SentrySpan', () => { ); setCurrentClient(client); - const recordDroppedEventSpy = jest.spyOn(client, 'recordDroppedEvent'); + const recordDroppedEventSpy = vi.spyOn(client, 'recordDroppedEvent'); // @ts-expect-error Accessing private transport API - const mockSend = jest.spyOn(client._transport, 'send'); + const mockSend = vi.spyOn(client._transport, 'send'); const span = new SentrySpan({ name: 'test', isStandalone: true, diff --git a/packages/core/test/lib/tracing/spanstatus.test.ts b/packages/core/test/lib/tracing/spanstatus.test.ts index 2ed356b1d73e..ee6bfd59443f 100644 --- a/packages/core/test/lib/tracing/spanstatus.test.ts +++ b/packages/core/test/lib/tracing/spanstatus.test.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import { SentrySpan, setHttpStatus, spanToJSON } from '../../../src/index'; describe('setHttpStatus', () => { diff --git a/packages/core/test/lib/tracing/trace.test.ts b/packages/core/test/lib/tracing/trace.test.ts index fe58ce6f9f7d..82dac553bf7d 100644 --- a/packages/core/test/lib/tracing/trace.test.ts +++ b/packages/core/test/lib/tracing/trace.test.ts @@ -1,4 +1,5 @@ import type { Event, Span, StartSpanOptions } from '@sentry/types'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, @@ -12,6 +13,7 @@ import { spanToJSON, withScope, } from '../../../src'; + import { getAsyncContextStrategy } from '../../../src/asyncContext'; import { SentrySpan, @@ -53,7 +55,7 @@ describe('startSpan', () => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); describe.each([ @@ -476,7 +478,7 @@ describe('startSpan', () => { }); it('samples with a tracesSampler', () => { - const tracesSampler = jest.fn(() => { + const tracesSampler = vi.fn(() => { return true; }); @@ -503,7 +505,7 @@ describe('startSpan', () => { }); it('includes the scope at the time the span was started when finished', async () => { - const beforeSendTransaction = jest.fn(event => event); + const beforeSendTransaction = vi.fn(event => event); const client = new TestClient( getDefaultTestClientOptions({ @@ -553,7 +555,7 @@ describe('startSpan', () => { const carrier = getMainCarrier(); - const customFn = jest.fn((_options: StartSpanOptions, callback: (span: Span) => string) => { + const customFn = vi.fn((_options: StartSpanOptions, callback: (span: Span) => string) => { callback(staticSpan); return 'aha'; }) as typeof startSpan; @@ -929,7 +931,7 @@ describe('startSpanManual', () => { const carrier = getMainCarrier(); - const customFn = jest.fn((_options: StartSpanOptions, callback: (span: Span) => string) => { + const customFn = vi.fn((_options: StartSpanOptions, callback: (span: Span) => string) => { callback(staticSpan); return 'aha'; }) as unknown as typeof startSpanManual; @@ -1238,7 +1240,7 @@ describe('startInactiveSpan', () => { }); it('includes the scope at the time the span was started when finished', async () => { - const beforeSendTransaction = jest.fn(event => event); + const beforeSendTransaction = vi.fn(event => event); const client = new TestClient( getDefaultTestClientOptions({ @@ -1295,7 +1297,7 @@ describe('startInactiveSpan', () => { const carrier = getMainCarrier(); - const customFn = jest.fn((_options: StartSpanOptions) => { + const customFn = vi.fn((_options: StartSpanOptions) => { return staticSpan; }) as unknown as typeof startInactiveSpan; @@ -1458,7 +1460,7 @@ describe('getActiveSpan', () => { const carrier = getMainCarrier(); - const customFn = jest.fn(() => { + const customFn = vi.fn(() => { return staticSpan; }) as typeof getActiveSpan; @@ -1525,7 +1527,7 @@ describe('withActiveSpan()', () => { const carrier = getMainCarrier(); - const customFn = jest.fn((_span: Span | null, callback: (scope: Scope) => string) => { + const customFn = vi.fn((_span: Span | null, callback: (scope: Scope) => string) => { callback(staticScope); return 'aha'; }) as typeof withActiveSpan; @@ -1557,7 +1559,7 @@ describe('span hooks', () => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('correctly emits span hooks', () => { @@ -1608,7 +1610,7 @@ describe('suppressTracing', () => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('works for a root span', () => { diff --git a/packages/core/test/lib/transports/base.test.ts b/packages/core/test/lib/transports/base.test.ts index a8198ce38b3d..4fb3773d8249 100644 --- a/packages/core/test/lib/transports/base.test.ts +++ b/packages/core/test/lib/transports/base.test.ts @@ -1,6 +1,7 @@ import type { AttachmentItem, EventEnvelope, EventItem, TransportMakeRequestResponse } from '@sentry/types'; import type { PromiseBuffer } from '@sentry/utils'; import { createEnvelope, resolvedSyncPromise, serializeEnvelope } from '@sentry/utils'; +import { describe, expect, it, vi } from 'vitest'; import { createTransport } from '../../../src/transports/base'; @@ -37,8 +38,8 @@ describe('createTransport', () => { it('flushes the buffer', async () => { const mockBuffer: PromiseBuffer = { $: [], - add: jest.fn(), - drain: jest.fn(), + add: vi.fn(), + drain: vi.fn(), }; const transport = createTransport(transportOptions, _ => resolvedSyncPromise({}), mockBuffer); /* eslint-disable @typescript-eslint/unbound-method */ @@ -93,11 +94,11 @@ describe('createTransport', () => { transportResponse = res; } - const mockRequestExecutor = jest.fn(_ => { + const mockRequestExecutor = vi.fn(_ => { return resolvedSyncPromise(transportResponse); }); - const mockRecordDroppedEventCallback = jest.fn(); + const mockRecordDroppedEventCallback = vi.fn(); const transport = createTransport({ recordDroppedEvent: mockRecordDroppedEventCallback }, mockRequestExecutor); @@ -108,7 +109,7 @@ describe('createTransport', () => { const { retryAfterSeconds, beforeLimit, withinLimit, afterLimit } = setRateLimitTimes(); const [transport, setTransportResponse, requestExecutor, recordDroppedEventCallback] = createTestTransport({}); - const dateNowSpy = jest.spyOn(Date, 'now').mockImplementation(() => beforeLimit); + const dateNowSpy = vi.spyOn(Date, 'now').mockImplementation(() => beforeLimit); await transport.send(ERROR_ENVELOPE); expect(requestExecutor).toHaveBeenCalledTimes(1); @@ -157,7 +158,7 @@ describe('createTransport', () => { }, }); - const dateNowSpy = jest.spyOn(Date, 'now').mockImplementation(() => beforeLimit); + const dateNowSpy = vi.spyOn(Date, 'now').mockImplementation(() => beforeLimit); await transport.send(ERROR_ENVELOPE); expect(requestExecutor).toHaveBeenCalledTimes(1); @@ -207,7 +208,7 @@ describe('createTransport', () => { }, }); - const dateNowSpy = jest.spyOn(Date, 'now').mockImplementation(() => beforeLimit); + const dateNowSpy = vi.spyOn(Date, 'now').mockImplementation(() => beforeLimit); await transport.send(ERROR_ENVELOPE); expect(requestExecutor).toHaveBeenCalledTimes(1); @@ -271,7 +272,7 @@ describe('createTransport', () => { }, }); - const dateNowSpy = jest.spyOn(Date, 'now').mockImplementation(() => beforeLimit); + const dateNowSpy = vi.spyOn(Date, 'now').mockImplementation(() => beforeLimit); await transport.send(ERROR_ENVELOPE); expect(requestExecutor).toHaveBeenCalledTimes(1); diff --git a/packages/core/test/lib/transports/multiplexed.test.ts b/packages/core/test/lib/transports/multiplexed.test.ts index 4ddde08437f2..0323f2ee3e49 100644 --- a/packages/core/test/lib/transports/multiplexed.test.ts +++ b/packages/core/test/lib/transports/multiplexed.test.ts @@ -12,6 +12,8 @@ import { createClientReportEnvelope, createEnvelope, dsnFromString, parseEnvelop import { createTransport, getEnvelopeEndpointWithUrlEncodedAuth, makeMultiplexedTransport } from '../../../src'; import { eventFromEnvelope } from '../../../src/transports/multiplexed'; +import { describe, expect, it, vi } from 'vitest'; + const DSN1 = 'https://1234@5678.ingest.sentry.io/4321'; const DSN1_URL = getEnvelopeEndpointWithUrlEncodedAuth(dsnFromString(DSN1)!); @@ -88,7 +90,7 @@ describe('makeMultiplexedTransport', () => { it('Falls back to options DSN when a matched DSN is invalid', async () => { // Hide warning logs in the test - jest.spyOn(console, 'error').mockImplementation(() => {}); + vi.spyOn(console, 'error').mockImplementation(() => {}); expect.assertions(1); @@ -102,7 +104,7 @@ describe('makeMultiplexedTransport', () => { const transport = makeTransport({ url: DSN1_URL, ...transportOptions }); await transport.send(ERROR_ENVELOPE); - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('DSN can be overridden via match callback', async () => { diff --git a/packages/core/test/lib/transports/offline.test.ts b/packages/core/test/lib/transports/offline.test.ts index 8ad6da4111f3..736002a95d7e 100644 --- a/packages/core/test/lib/transports/offline.test.ts +++ b/packages/core/test/lib/transports/offline.test.ts @@ -17,6 +17,7 @@ import { parseEnvelope, } from '@sentry/utils'; +import { describe, expect, it } from 'vitest'; import { createTransport } from '../../../src'; import type { CreateOfflineStore, OfflineTransportOptions } from '../../../src/transports/offline'; import { START_DELAY, makeOfflineTransport } from '../../../src/transports/offline'; @@ -160,7 +161,7 @@ function waitUntil(fn: () => boolean, timeout: number): Promise { }); } -describe.skip('makeOfflineTransport', () => { +describe('makeOfflineTransport', () => { it('Sends envelope and checks the store for further envelopes', async () => { const { getCalls, store } = createTestStore(); const { getSendCount, baseTransport } = createTestTransport({ statusCode: 200 }); @@ -410,7 +411,6 @@ describe.skip('makeOfflineTransport', () => { START_DELAY + 2_000, ); - // eslint-disable-next-line jest/no-disabled-tests it.skip( 'Follows the Retry-After header', async () => { diff --git a/packages/core/test/lib/utils/applyScopeDataToEvent.test.ts b/packages/core/test/lib/utils/applyScopeDataToEvent.test.ts index e6370931f4cf..5bd797255ec0 100644 --- a/packages/core/test/lib/utils/applyScopeDataToEvent.test.ts +++ b/packages/core/test/lib/utils/applyScopeDataToEvent.test.ts @@ -7,6 +7,8 @@ import { mergeScopeData, } from '../../../src/utils/applyScopeDataToEvent'; +import { describe, expect, it } from 'vitest'; + describe('mergeArray', () => { it.each([ [[], [], undefined], diff --git a/packages/core/test/lib/utils/handleCallbackErrors.test.ts b/packages/core/test/lib/utils/handleCallbackErrors.test.ts index 3c6bb1e19302..efa632d62a4a 100644 --- a/packages/core/test/lib/utils/handleCallbackErrors.test.ts +++ b/packages/core/test/lib/utils/handleCallbackErrors.test.ts @@ -1,10 +1,11 @@ +import { describe, expect, it, vi } from 'vitest'; import { handleCallbackErrors } from '../../../src/utils/handleCallbackErrors'; describe('handleCallbackErrors', () => { it('works with a simple callback', () => { - const onError = jest.fn(); + const onError = vi.fn(); - const fn = jest.fn(() => 'aa'); + const fn = vi.fn(() => 'aa'); const res = handleCallbackErrors(fn, onError); @@ -16,9 +17,9 @@ describe('handleCallbackErrors', () => { it('triggers onError when callback has sync error', () => { const error = new Error('test error'); - const onError = jest.fn(); + const onError = vi.fn(); - const fn = jest.fn(() => { + const fn = vi.fn(() => { throw error; }); @@ -30,9 +31,9 @@ describe('handleCallbackErrors', () => { }); it('works with an async callback', async () => { - const onError = jest.fn(); + const onError = vi.fn(); - const fn = jest.fn(async () => 'aa'); + const fn = vi.fn(async () => 'aa'); const res = handleCallbackErrors(fn, onError); @@ -46,11 +47,11 @@ describe('handleCallbackErrors', () => { }); it('triggers onError when callback returns promise that rejects', async () => { - const onError = jest.fn(); + const onError = vi.fn(); const error = new Error('test error'); - const fn = jest.fn(async () => { + const fn = vi.fn(async () => { await new Promise(resolve => setTimeout(resolve, 10)); throw error; }); @@ -70,10 +71,10 @@ describe('handleCallbackErrors', () => { describe('onFinally', () => { it('triggers after successfuly sync callback', () => { - const onError = jest.fn(); - const onFinally = jest.fn(); + const onError = vi.fn(); + const onFinally = vi.fn(); - const fn = jest.fn(() => 'aa'); + const fn = vi.fn(() => 'aa'); const res = handleCallbackErrors(fn, onError, onFinally); @@ -86,10 +87,10 @@ describe('handleCallbackErrors', () => { it('triggers after error in sync callback', () => { const error = new Error('test error'); - const onError = jest.fn(); - const onFinally = jest.fn(); + const onError = vi.fn(); + const onFinally = vi.fn(); - const fn = jest.fn(() => { + const fn = vi.fn(() => { throw error; }); @@ -102,10 +103,10 @@ describe('handleCallbackErrors', () => { }); it('triggers after successful async callback', async () => { - const onError = jest.fn(); - const onFinally = jest.fn(); + const onError = vi.fn(); + const onFinally = vi.fn(); - const fn = jest.fn(async () => 'aa'); + const fn = vi.fn(async () => 'aa'); const res = handleCallbackErrors(fn, onError, onFinally); @@ -122,12 +123,12 @@ describe('handleCallbackErrors', () => { }); it('triggers after error in async callback', async () => { - const onError = jest.fn(); - const onFinally = jest.fn(); + const onError = vi.fn(); + const onFinally = vi.fn(); const error = new Error('test error'); - const fn = jest.fn(async () => { + const fn = vi.fn(async () => { await new Promise(resolve => setTimeout(resolve, 10)); throw error; }); diff --git a/packages/core/test/lib/utils/hasTracingEnabled.test.ts b/packages/core/test/lib/utils/hasTracingEnabled.test.ts index a03ff25c9be9..bfec89fc74af 100644 --- a/packages/core/test/lib/utils/hasTracingEnabled.test.ts +++ b/packages/core/test/lib/utils/hasTracingEnabled.test.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import { hasTracingEnabled } from '../../../src'; describe('hasTracingEnabled', () => { diff --git a/packages/core/test/lib/utils/isSentryRequestUrl.test.ts b/packages/core/test/lib/utils/isSentryRequestUrl.test.ts index b223f856b95e..1c4c059beead 100644 --- a/packages/core/test/lib/utils/isSentryRequestUrl.test.ts +++ b/packages/core/test/lib/utils/isSentryRequestUrl.test.ts @@ -1,5 +1,6 @@ import type { Client } from '@sentry/types'; +import { describe, expect, it } from 'vitest'; import { isSentryRequestUrl } from '../../../src'; describe('isSentryRequestUrl', () => { diff --git a/packages/core/test/lib/utils/meta.test.ts b/packages/core/test/lib/utils/meta.test.ts index 3d78247b8951..28d21eeb54b1 100644 --- a/packages/core/test/lib/utils/meta.test.ts +++ b/packages/core/test/lib/utils/meta.test.ts @@ -1,9 +1,10 @@ +import { describe, expect, it, vi } from 'vitest'; import { getTraceMetaTags } from '../../../src/utils/meta'; import * as TraceDataModule from '../../../src/utils/traceData'; describe('getTraceMetaTags', () => { it('renders baggage and sentry-trace values to stringified Html meta tags', () => { - jest.spyOn(TraceDataModule, 'getTraceData').mockReturnValueOnce({ + vi.spyOn(TraceDataModule, 'getTraceData').mockReturnValueOnce({ 'sentry-trace': '12345678901234567890123456789012-1234567890123456-1', baggage: 'sentry-environment=production', }); @@ -13,7 +14,7 @@ describe('getTraceMetaTags', () => { }); it('renders just sentry-trace values to stringified Html meta tags', () => { - jest.spyOn(TraceDataModule, 'getTraceData').mockReturnValueOnce({ + vi.spyOn(TraceDataModule, 'getTraceData').mockReturnValueOnce({ 'sentry-trace': '12345678901234567890123456789012-1234567890123456-1', }); @@ -23,7 +24,7 @@ describe('getTraceMetaTags', () => { }); it('returns an empty string if neither sentry-trace nor baggage values are available', () => { - jest.spyOn(TraceDataModule, 'getTraceData').mockReturnValueOnce({}); + vi.spyOn(TraceDataModule, 'getTraceData').mockReturnValueOnce({}); expect(getTraceMetaTags()).toBe(''); }); diff --git a/packages/core/test/lib/utils/parameterize.test.ts b/packages/core/test/lib/utils/parameterize.test.ts index 413ba8043c49..4c5538f1854a 100644 --- a/packages/core/test/lib/utils/parameterize.test.ts +++ b/packages/core/test/lib/utils/parameterize.test.ts @@ -1,5 +1,6 @@ import type { ParameterizedString } from '@sentry/types'; +import { describe, expect, test } from 'vitest'; import { parameterize } from '../../../src/utils/parameterize'; describe('parameterize()', () => { diff --git a/packages/core/test/lib/utils/parseSampleRate.test.ts b/packages/core/test/lib/utils/parseSampleRate.test.ts index 9c0d91b1810e..fae94a6cc354 100644 --- a/packages/core/test/lib/utils/parseSampleRate.test.ts +++ b/packages/core/test/lib/utils/parseSampleRate.test.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import { parseSampleRate } from '../../../src/utils/parseSampleRate'; describe('parseSampleRate', () => { diff --git a/packages/core/test/lib/utils/spanUtils.test.ts b/packages/core/test/lib/utils/spanUtils.test.ts index 2a4850947e80..ec03d4cb5e88 100644 --- a/packages/core/test/lib/utils/spanUtils.test.ts +++ b/packages/core/test/lib/utils/spanUtils.test.ts @@ -16,6 +16,8 @@ import type { OpenTelemetrySdkTraceBaseSpan } from '../../../src/utils/spanUtils import { getRootSpan, spanIsSampled, spanTimeInputToSeconds, spanToJSON } from '../../../src/utils/spanUtils'; import { TestClient, getDefaultTestClientOptions } from '../../mocks/client'; +import { beforeEach, describe, expect, it, test } from 'vitest'; + describe('spanToTraceHeader', () => { test('simple', () => { const span = new SentrySpan(); diff --git a/packages/core/test/lib/utils/traceData.test.ts b/packages/core/test/lib/utils/traceData.test.ts index a6fb3c57814e..0f16fc881a40 100644 --- a/packages/core/test/lib/utils/traceData.test.ts +++ b/packages/core/test/lib/utils/traceData.test.ts @@ -3,6 +3,7 @@ import * as SentryCoreCurrentScopes from '../../../src/currentScopes'; import * as SentryCoreTracing from '../../../src/tracing'; import * as SentryCoreSpanUtils from '../../../src/utils/spanUtils'; +import { describe, expect, it, vi } from 'vitest'; import { isValidBaggageString } from '../../../src/utils/traceData'; const TRACE_FLAG_SAMPLED = 1; @@ -24,11 +25,11 @@ const mockedScope = { describe('getTraceData', () => { it('returns the tracing data from the span, if a span is available', () => { { - jest.spyOn(SentryCoreTracing, 'getDynamicSamplingContextFromSpan').mockReturnValueOnce({ + vi.spyOn(SentryCoreTracing, 'getDynamicSamplingContextFromSpan').mockReturnValueOnce({ environment: 'production', }); - jest.spyOn(SentryCoreSpanUtils, 'getActiveSpan').mockImplementationOnce(() => mockedSpan); - jest.spyOn(SentryCoreCurrentScopes, 'getCurrentScope').mockImplementationOnce(() => mockedScope); + vi.spyOn(SentryCoreSpanUtils, 'getActiveSpan').mockImplementationOnce(() => mockedSpan); + vi.spyOn(SentryCoreCurrentScopes, 'getCurrentScope').mockImplementationOnce(() => mockedScope); const data = getTraceData(); @@ -40,8 +41,8 @@ describe('getTraceData', () => { }); it('returns propagationContext DSC data if no span is available', () => { - jest.spyOn(SentryCoreSpanUtils, 'getActiveSpan').mockImplementationOnce(() => undefined); - jest.spyOn(SentryCoreCurrentScopes, 'getCurrentScope').mockImplementationOnce( + vi.spyOn(SentryCoreSpanUtils, 'getActiveSpan').mockImplementationOnce(() => undefined); + vi.spyOn(SentryCoreCurrentScopes, 'getCurrentScope').mockImplementationOnce( () => ({ getPropagationContext: () => ({ @@ -56,7 +57,7 @@ describe('getTraceData', () => { }), }) as any, ); - jest.spyOn(SentryCoreCurrentScopes, 'getClient').mockImplementationOnce(() => mockedClient); + vi.spyOn(SentryCoreCurrentScopes, 'getClient').mockImplementationOnce(() => mockedClient); const traceData = getTraceData(); @@ -67,13 +68,13 @@ describe('getTraceData', () => { }); it('returns only the `sentry-trace` value if no DSC is available', () => { - jest.spyOn(SentryCoreTracing, 'getDynamicSamplingContextFromClient').mockReturnValueOnce({ + vi.spyOn(SentryCoreTracing, 'getDynamicSamplingContextFromClient').mockReturnValueOnce({ trace_id: '', public_key: undefined, }); // @ts-expect-error - we don't need to provide all the properties - jest.spyOn(SentryCoreSpanUtils, 'getActiveSpan').mockImplementationOnce(() => ({ + vi.spyOn(SentryCoreSpanUtils, 'getActiveSpan').mockImplementationOnce(() => ({ isRecording: () => true, spanContext: () => { return { @@ -84,8 +85,8 @@ describe('getTraceData', () => { }, })); - jest.spyOn(SentryCoreCurrentScopes, 'getCurrentScope').mockImplementationOnce(() => mockedScope); - jest.spyOn(SentryCoreCurrentScopes, 'getClient').mockImplementationOnce(() => mockedClient); + vi.spyOn(SentryCoreCurrentScopes, 'getCurrentScope').mockImplementationOnce(() => mockedScope); + vi.spyOn(SentryCoreCurrentScopes, 'getClient').mockImplementationOnce(() => mockedClient); const traceData = getTraceData(); @@ -95,13 +96,13 @@ describe('getTraceData', () => { }); it('returns only the `sentry-trace` tag if no DSC is available without a client', () => { - jest.spyOn(SentryCoreTracing, 'getDynamicSamplingContextFromClient').mockReturnValueOnce({ + vi.spyOn(SentryCoreTracing, 'getDynamicSamplingContextFromClient').mockReturnValueOnce({ trace_id: '', public_key: undefined, }); // @ts-expect-error - we don't need to provide all the properties - jest.spyOn(SentryCoreSpanUtils, 'getActiveSpan').mockImplementationOnce(() => ({ + vi.spyOn(SentryCoreSpanUtils, 'getActiveSpan').mockImplementationOnce(() => ({ isRecording: () => true, spanContext: () => { return { @@ -111,8 +112,8 @@ describe('getTraceData', () => { }; }, })); - jest.spyOn(SentryCoreCurrentScopes, 'getCurrentScope').mockImplementationOnce(() => mockedScope); - jest.spyOn(SentryCoreCurrentScopes, 'getClient').mockImplementationOnce(() => undefined); + vi.spyOn(SentryCoreCurrentScopes, 'getCurrentScope').mockImplementationOnce(() => mockedScope); + vi.spyOn(SentryCoreCurrentScopes, 'getClient').mockImplementationOnce(() => undefined); const traceData = getTraceData(); @@ -124,7 +125,7 @@ describe('getTraceData', () => { it('returns an empty object if the `sentry-trace` value is invalid', () => { // @ts-expect-error - we don't need to provide all the properties - jest.spyOn(SentryCoreSpanUtils, 'getActiveSpan').mockImplementationOnce(() => ({ + vi.spyOn(SentryCoreSpanUtils, 'getActiveSpan').mockImplementationOnce(() => ({ isRecording: () => true, spanContext: () => { return { diff --git a/packages/core/tsconfig.test.json b/packages/core/tsconfig.test.json index 6fde53bec436..dddd57894b34 100644 --- a/packages/core/tsconfig.test.json +++ b/packages/core/tsconfig.test.json @@ -6,8 +6,6 @@ "compilerOptions": { "lib": ["DOM", "ES2018"], // should include all types from `./tsconfig.json` plus types for all test frameworks used - "types": ["node", "jest"] - - // other package-specific, test-specific options + "types": ["node"] } } diff --git a/packages/core/vite.config.ts b/packages/core/vite.config.ts new file mode 100644 index 000000000000..e7a48bfa6d90 --- /dev/null +++ b/packages/core/vite.config.ts @@ -0,0 +1,12 @@ +import baseConfig from '@sentry-internal/vitest-config'; +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + ...baseConfig, + test: { + ...baseConfig.test, + typecheck: { + tsconfig: './tsconfig.test.json', + }, + }, +}); From 8d97a052fa71374a12baaca4bbbb0d94d32e1d6e Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 20 Aug 2024 10:24:24 +0200 Subject: [PATCH 08/53] test(core): Improve offline transport test performance switch to fake timers --- packages/core/test/lib/transports/offline.test.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/core/test/lib/transports/offline.test.ts b/packages/core/test/lib/transports/offline.test.ts index 736002a95d7e..28969eed5474 100644 --- a/packages/core/test/lib/transports/offline.test.ts +++ b/packages/core/test/lib/transports/offline.test.ts @@ -17,7 +17,7 @@ import { parseEnvelope, } from '@sentry/utils'; -import { describe, expect, it } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { createTransport } from '../../../src'; import type { CreateOfflineStore, OfflineTransportOptions } from '../../../src/transports/offline'; import { START_DELAY, makeOfflineTransport } from '../../../src/transports/offline'; @@ -162,7 +162,9 @@ function waitUntil(fn: () => boolean, timeout: number): Promise { } describe('makeOfflineTransport', () => { - it('Sends envelope and checks the store for further envelopes', async () => { + vi.useFakeTimers(); + + it('sends envelope and checks the store for further envelopes', async () => { const { getCalls, store } = createTestStore(); const { getSendCount, baseTransport } = createTestTransport({ statusCode: 200 }); let queuedCount = 0; @@ -174,6 +176,9 @@ describe('makeOfflineTransport', () => { return true; }, }); + + vi.runAllTimersAsync(); + const result = await transport.send(ERROR_ENVELOPE); expect(result).toEqual({ statusCode: 200 }); @@ -411,7 +416,7 @@ describe('makeOfflineTransport', () => { START_DELAY + 2_000, ); - it.skip( + it( 'Follows the Retry-After header', async () => { const { getCalls, store } = createTestStore(ERROR_ENVELOPE); From e27d70c0ce6c828860c42dcc0c755e6023a3cdc4 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 20 Aug 2024 13:56:44 +0200 Subject: [PATCH 09/53] add summary script --- package.json | 2 +- packages/browser/package.json | 2 +- scripts/stryker-results.ts | 93 +++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 scripts/stryker-results.ts diff --git a/package.json b/package.json index b2d17d68cf0b..ea5d915d9fea 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "test:ci:browser": "UNIT_TEST_ENV=browser ts-node ./scripts/ci-unit-tests.ts", "test:ci:node": "UNIT_TEST_ENV=node ts-node ./scripts/ci-unit-tests.ts", "test:ci:bun": "lerna run test --scope @sentry/bun", - "test:mutation": "lerna run test:mutation", + "test:mutation": "lerna run --stream --concurrency=auto test:mutation && ts-node ./scripts/stryker-results.ts", "yalc:publish": "lerna run yalc:publish" }, "volta": { diff --git a/packages/browser/package.json b/packages/browser/package.json index 3b6d547e8d61..f7b1e12df9bf 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -50,7 +50,7 @@ "devDependencies": { "@sentry-internal/integration-shims": "8.26.0", "@sentry-internal/vitest-config": "8.26.0", - "fake-indexeddb": "^4.0.1", + "fake-indexeddb": "^4.0.1" }, "scripts": { "build": "run-p build:transpile build:bundle build:types", diff --git a/scripts/stryker-results.ts b/scripts/stryker-results.ts new file mode 100644 index 000000000000..14f8c8beacb0 --- /dev/null +++ b/scripts/stryker-results.ts @@ -0,0 +1,93 @@ +/* eslint-disable no-console */ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +import type { schema } from '@stryker-mutator/api/core'; + +interface MutationTestResultAggregation { + package: string; + killed: number; + timeout: number; + survived: number; + noCoverage: number; + ignored: number; + error: number; + detected: number; + undetected: number; + total: number; + score: number; + scoreCovered: number; +} + +function main(): void { + const mutationResults: schema.MutationTestResult[] = getMutationTestResults(); + console.table(mutationResults.map(getMutationTestResultAggregation)); +} + +function getMutationTestResults(): schema.MutationTestResult[] { + const packagesDir = path.resolve(path.join(process.cwd(), 'packages')); + + const packages = fs + .readdirSync(packagesDir) + .map(packageDir => path.resolve(path.join(packagesDir, packageDir))) + .filter(dir => fs.statSync(dir).isDirectory()) + .filter(dir => fs.existsSync(path.join(dir, 'reports'))); + + const strykerReportJsonFiles = packages + .map(dir => path.join(dir, 'reports', 'mutation', 'mutation.json')) + .filter(fs.existsSync); + + const mutationResults: schema.MutationTestResult[] = strykerReportJsonFiles.map( + file => JSON.parse(fs.readFileSync(file, 'utf-8')) as schema.MutationTestResult, + ); + return mutationResults; +} + +function getMutationTestResultAggregation(mutationResults: schema.MutationTestResult): MutationTestResultAggregation { + const total = Object.values(mutationResults.files).reduce((acc, file) => acc + file.mutants.length, 0); + const allMutants = Object.values(mutationResults.files).reduce( + (acc, file) => [...acc, ...file.mutants], + [] as schema.MutantResult[], + ); + + const noCoverage = allMutants.filter(mutant => mutant.status === 'NoCoverage').length; + const killed = allMutants.filter(mutant => mutant.status === 'Killed').length; + const survived = allMutants.filter(mutant => mutant.status === 'Survived').length; + const error = allMutants.filter( + mutant => mutant.status === 'RuntimeError' || mutant.status === 'CompileError', + ).length; + const ignored = allMutants.filter(mutant => mutant.status === 'Ignored').length; + const timeout = allMutants.filter(mutant => mutant.status === 'Timeout').length; + + const detected = killed + timeout; + + return { + package: getPackageName(mutationResults), + killed, + survived, + noCoverage, + ignored, + error, + timeout, + total, + detected, + undetected: survived + noCoverage, + score: Math.fround(detected / (total - ignored)), + scoreCovered: Math.fround(detected / (total - ignored - noCoverage)), + }; +} + +function getPackageName(mutationResults: schema.MutationTestResult): string { + try { + return ( + JSON.parse(fs.readFileSync(path.join(mutationResults.projectRoot ?? '', 'package.json')).toString()) as { + name: string; + } + ).name; + } catch { + return mutationResults.projectRoot || 'unknown'; + } +} + +main(); From ad9a65b3d608051879396450936f3100da4dcb69 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 20 Aug 2024 13:57:11 +0200 Subject: [PATCH 10/53] add dashboard upload --- packages/browser/stryker.config.mjs | 7 ++++++- packages/core/stryker.config.mjs | 7 ++++++- packages/node/stryker.config.mjs | 5 +++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/browser/stryker.config.mjs b/packages/browser/stryker.config.mjs index 98f92c75dd9c..f0fb65ade8b3 100644 --- a/packages/browser/stryker.config.mjs +++ b/packages/browser/stryker.config.mjs @@ -1,10 +1,15 @@ /** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ const config = { packageManager: 'yarn', - reporters: ['html', 'clear-text', 'progress', 'json'], + reporters: ['html', 'clear-text', 'progress', 'json', 'dashboard'], testRunner: 'vitest', coverageAnalysis: 'perTest', ignoreStatic: true, + dashboard: { + project: 'github.com/Lms24/sentry-javascript-test-fork', + module: '@sentry/browser', + version: 'develop', + }, }; export default config; diff --git a/packages/core/stryker.config.mjs b/packages/core/stryker.config.mjs index 98f92c75dd9c..7283a49aac7b 100644 --- a/packages/core/stryker.config.mjs +++ b/packages/core/stryker.config.mjs @@ -1,10 +1,15 @@ /** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ const config = { packageManager: 'yarn', - reporters: ['html', 'clear-text', 'progress', 'json'], + reporters: ['html', 'clear-text', 'progress', 'json', 'dashboard', 'dashboard'], testRunner: 'vitest', coverageAnalysis: 'perTest', ignoreStatic: true, + dashboard: { + project: 'github.com/Lms24/sentry-javascript-test-fork', + module: '@sentry/core', + version: 'develop', + }, }; export default config; diff --git a/packages/node/stryker.config.mjs b/packages/node/stryker.config.mjs index bf43e1870724..67320e9523fd 100644 --- a/packages/node/stryker.config.mjs +++ b/packages/node/stryker.config.mjs @@ -5,6 +5,11 @@ const config = { testRunner: 'jest', coverageAnalysis: 'perTest', ignoreStatic: true, + dashboard: { + project: 'github.com/Lms24/sentry-javascript-test-fork', + module: '@sentry/node', + version: 'develop', + }, }; export default config; From d77d9e3c0a5184ad290f52f797199f14d7d27b9b Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 20 Aug 2024 15:30:53 +0200 Subject: [PATCH 11/53] add svelte, sveltekit, unify config --- dev-packages/stryker-config/README.md | 3 +++ dev-packages/stryker-config/package.json | 25 +++++++++++++++++++ .../stryker-config/src/stryker.config.mjs | 25 +++++++++++++++++++ nx.json | 7 +++++- package.json | 5 ++-- packages/browser/package.json | 1 + packages/browser/stryker.config.mjs | 11 +++----- packages/core/package.json | 2 +- packages/core/stryker.config.mjs | 11 +++----- packages/node/stryker.config.mjs | 10 +++----- packages/svelte/package.json | 1 + packages/svelte/stryker.config.mjs | 12 +++++++++ packages/svelte/vite.config.ts | 11 +++++--- packages/sveltekit/package.json | 1 + packages/sveltekit/stryker.config.mjs | 12 +++++++++ packages/sveltekit/vite.config.ts | 6 ++++- scripts/stryker-results.ts | 11 ++++---- 17 files changed, 121 insertions(+), 33 deletions(-) create mode 100644 dev-packages/stryker-config/README.md create mode 100644 dev-packages/stryker-config/package.json create mode 100644 dev-packages/stryker-config/src/stryker.config.mjs create mode 100644 packages/svelte/stryker.config.mjs create mode 100644 packages/sveltekit/stryker.config.mjs diff --git a/dev-packages/stryker-config/README.md b/dev-packages/stryker-config/README.md new file mode 100644 index 000000000000..de77ceae12cc --- /dev/null +++ b/dev-packages/stryker-config/README.md @@ -0,0 +1,3 @@ +# `@sentry-internal/stryker-config` + +A package containing the base Stryker config for the sentry-javascript SDK repo diff --git a/dev-packages/stryker-config/package.json b/dev-packages/stryker-config/package.json new file mode 100644 index 000000000000..969390183e2d --- /dev/null +++ b/dev-packages/stryker-config/package.json @@ -0,0 +1,25 @@ +{ + "private": true, + "version": "8.26.0", + "name": "@sentry-internal/stryker-config", + "author": "Sentry", + "license": "MIT", + "files": [ + "src" + ], + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "default": "./src/stryker.config.mjs" + } + } + }, + "sideEffects": false, + "engines": { + "node": ">=14.18" + }, + "volta": { + "extends": "../../package.json" + } +} diff --git a/dev-packages/stryker-config/src/stryker.config.mjs b/dev-packages/stryker-config/src/stryker.config.mjs new file mode 100644 index 000000000000..cc6ee1e42794 --- /dev/null +++ b/dev-packages/stryker-config/src/stryker.config.mjs @@ -0,0 +1,25 @@ +import child_process from 'child_process'; + +// STRYKER_DASHBOARD_API_KEY env variable needs to be set to upload to dashboard + +/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ +const config = { + packageManager: 'yarn', + reporters: ['html', 'clear-text', 'progress', 'json', 'dashboard'], + testRunner: 'vitest', + coverageAnalysis: 'perTest', + ignoreStatic: true, + dashboard: { + // TODO: change to getsentry/sentry-javascript if we ship this into production + project: 'github.com/Lms24/sentry-javascript-test-fork', + version: child_process.execSync('git rev-parse HEAD').toString().trim(), + }, + clearTextReporter: { + logTests: false, + reportMutants: false, + reportScoreTable: true, + skipFull: false, + }, +}; + +export default config; diff --git a/nx.json b/nx.json index d4a90a3a6777..ae9751e774ef 100644 --- a/nx.json +++ b/nx.json @@ -3,7 +3,7 @@ "default": { "runner": "nx/tasks-runners/default", "options": { - "cacheableOperations": ["build:bundle", "build:transpile", "build:types", "lint", "test:unit", "build:tarball"], + "cacheableOperations": ["build:bundle", "build:transpile", "build:types", "lint", "test:unit", "build:tarball", "test:mutation"], "cacheDirectory": ".nxcache" } } @@ -58,6 +58,11 @@ "dependsOn": ["build:types", "^build:types", "build:transpile", "^build:transpile"], "inputs": ["default"], "outputs": ["{projectRoot}/coverage"] + }, + "test:mutation": { + "dependsOn:": ["build:types", "^build:types", "build:transpile", "^build:transpile"], + "inputs": ["default"], + "outputs": ["{projectRoot}/reports"] } }, "$schema": "./node_modules/nx/schemas/nx-schema.json" diff --git a/package.json b/package.json index ea5d915d9fea..0637bb147ab2 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "test:ci:browser": "UNIT_TEST_ENV=browser ts-node ./scripts/ci-unit-tests.ts", "test:ci:node": "UNIT_TEST_ENV=node ts-node ./scripts/ci-unit-tests.ts", "test:ci:bun": "lerna run test --scope @sentry/bun", - "test:mutation": "lerna run --stream --concurrency=auto test:mutation && ts-node ./scripts/stryker-results.ts", + "test:mutation": "lerna run --stream --concurrency=2 test:mutation && ts-node ./scripts/stryker-results.ts", "yalc:publish": "lerna run yalc:publish" }, "volta": { @@ -95,7 +95,8 @@ "dev-packages/external-contributor-gh-action", "dev-packages/rollup-utils", "dev-packages/jest-config", - "dev-packages/vitest-config" + "dev-packages/vitest-config", + "dev-packages/stryker-config" ], "devDependencies": { "@biomejs/biome": "^1.4.0", diff --git a/packages/browser/package.json b/packages/browser/package.json index f7b1e12df9bf..34e70d02dee9 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -50,6 +50,7 @@ "devDependencies": { "@sentry-internal/integration-shims": "8.26.0", "@sentry-internal/vitest-config": "8.26.0", + "@sentry-internal/stryker-config": "8.26.0", "fake-indexeddb": "^4.0.1" }, "scripts": { diff --git a/packages/browser/stryker.config.mjs b/packages/browser/stryker.config.mjs index f0fb65ade8b3..2f7a7587770e 100644 --- a/packages/browser/stryker.config.mjs +++ b/packages/browser/stryker.config.mjs @@ -1,14 +1,11 @@ +import baseConfig from '@sentry-internal/stryker-config'; + /** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ const config = { - packageManager: 'yarn', - reporters: ['html', 'clear-text', 'progress', 'json', 'dashboard'], - testRunner: 'vitest', - coverageAnalysis: 'perTest', - ignoreStatic: true, + ...baseConfig, dashboard: { - project: 'github.com/Lms24/sentry-javascript-test-fork', + ...baseConfig.dashboard, module: '@sentry/browser', - version: 'develop', }, }; diff --git a/packages/core/package.json b/packages/core/package.json index 3cc9a530cd5f..76679948efe4 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -43,7 +43,7 @@ "@sentry/utils": "8.26.0" }, "devDependencies": { - "@sentry-internal/vite-config": "8.26.0" + "@sentry-internal/vitest-config": "8.26.0" }, "scripts": { "build": "run-p build:transpile build:types", diff --git a/packages/core/stryker.config.mjs b/packages/core/stryker.config.mjs index 7283a49aac7b..cf879a99a484 100644 --- a/packages/core/stryker.config.mjs +++ b/packages/core/stryker.config.mjs @@ -1,14 +1,11 @@ +import baseConfig from '@sentry-internal/stryker-config'; + /** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ const config = { - packageManager: 'yarn', - reporters: ['html', 'clear-text', 'progress', 'json', 'dashboard', 'dashboard'], - testRunner: 'vitest', - coverageAnalysis: 'perTest', - ignoreStatic: true, + ...baseConfig, dashboard: { - project: 'github.com/Lms24/sentry-javascript-test-fork', + ...baseConfig.dashboard, module: '@sentry/core', - version: 'develop', }, }; diff --git a/packages/node/stryker.config.mjs b/packages/node/stryker.config.mjs index 67320e9523fd..1afd0140bcc7 100644 --- a/packages/node/stryker.config.mjs +++ b/packages/node/stryker.config.mjs @@ -1,14 +1,12 @@ +import baseConfig from '@sentry-internal/stryker-config'; + /** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ const config = { - packageManager: 'yarn', - reporters: ['html', 'clear-text', 'progress', 'json'], + ...baseConfig, testRunner: 'jest', - coverageAnalysis: 'perTest', - ignoreStatic: true, dashboard: { - project: 'github.com/Lms24/sentry-javascript-test-fork', + ...baseConfig.dashboard, module: '@sentry/node', - version: 'develop', }, }; diff --git a/packages/svelte/package.json b/packages/svelte/package.json index cd01ba37e5bc..88e7d1e175b6 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -71,6 +71,7 @@ "lint": "eslint . --format stylish", "test": "vitest run", "test:watch": "vitest --watch", + "test:mutation": "stryker run", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/svelte/stryker.config.mjs b/packages/svelte/stryker.config.mjs new file mode 100644 index 000000000000..a99493ec7423 --- /dev/null +++ b/packages/svelte/stryker.config.mjs @@ -0,0 +1,12 @@ +import baseConfig from '@sentry-internal/stryker-config'; + +/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ +const config = { + ...baseConfig, + dashboard: { + ...baseConfig.dashboard, + module: '@sentry/svelte', + }, +}; + +export default config; diff --git a/packages/svelte/vite.config.ts b/packages/svelte/vite.config.ts index e0fcc1fd3dd3..43338dd49743 100644 --- a/packages/svelte/vite.config.ts +++ b/packages/svelte/vite.config.ts @@ -1,11 +1,16 @@ +import baseConfig from '@sentry-internal/vitest-config'; import { svelte } from '@sveltejs/vite-plugin-svelte'; -import baseConfig from '../../vite/vite.config'; +import { defineConfig } from 'vitest/config'; -export default { +export default defineConfig({ ...baseConfig, plugins: [svelte({ hot: !process.env.VITEST })], test: { ...baseConfig.test, alias: [{ find: /^svelte$/, replacement: 'svelte/internal' }], + coverage: { + ...baseConfig.test!.coverage, + exclude: ['build', '.eslintrc.js', 'vite.config.ts', 'rollup.*'], + }, }, -}; +}); diff --git a/packages/sveltekit/package.json b/packages/sveltekit/package.json index a3df07e38eff..7a5420c7451b 100644 --- a/packages/sveltekit/package.json +++ b/packages/sveltekit/package.json @@ -74,6 +74,7 @@ "test": "yarn test:unit", "test:unit": "vitest run", "test:watch": "vitest --watch", + "test:mutation": "stryker run", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/sveltekit/stryker.config.mjs b/packages/sveltekit/stryker.config.mjs new file mode 100644 index 000000000000..92cc1ed94b5b --- /dev/null +++ b/packages/sveltekit/stryker.config.mjs @@ -0,0 +1,12 @@ +import baseConfig from '@sentry-internal/stryker-config'; + +/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ +const config = { + ...baseConfig, + dashboard: { + ...baseConfig.dashboard, + module: '@sentry/sveltekit', + }, +}; + +export default config; diff --git a/packages/sveltekit/vite.config.ts b/packages/sveltekit/vite.config.ts index 4f8ead0177f9..80732a692f3b 100644 --- a/packages/sveltekit/vite.config.ts +++ b/packages/sveltekit/vite.config.ts @@ -1,7 +1,7 @@ import { dirname, resolve } from 'path'; import { fileURLToPath } from 'url'; -import baseConfig from '../../vite/vite.config'; +import baseConfig from '@sentry-internal/vitest-config'; export default { ...baseConfig, @@ -14,5 +14,9 @@ export default { replacement: resolve(fileURLToPath(dirname(import.meta.url)), '/.empty.js'), }, ], + coverage: { + ...baseConfig.test.coverage, + exclude: ['build', '.eslintrc.js', 'vite.config.ts', 'rollup.*', 'stryker*', 'test/*'], + }, }, }; diff --git a/scripts/stryker-results.ts b/scripts/stryker-results.ts index 14f8c8beacb0..94392a84f9a4 100644 --- a/scripts/stryker-results.ts +++ b/scripts/stryker-results.ts @@ -22,7 +22,8 @@ interface MutationTestResultAggregation { function main(): void { const mutationResults: schema.MutationTestResult[] = getMutationTestResults(); - console.table(mutationResults.map(getMutationTestResultAggregation)); + const results = mutationResults.map(getMutationTestResultAggregation).sort((a, b) => b.score - a.score); + console.table(results); } function getMutationTestResults(): schema.MutationTestResult[] { @@ -64,6 +65,10 @@ function getMutationTestResultAggregation(mutationResults: schema.MutationTestRe return { package: getPackageName(mutationResults), + score: Math.round((detected / (total - ignored) + Number.EPSILON) * 100) / 100, + scoreCovered: Math.round((detected / (total - ignored - noCoverage) + Number.EPSILON) * 100) / 100, + detected, + undetected: survived + noCoverage, killed, survived, noCoverage, @@ -71,10 +76,6 @@ function getMutationTestResultAggregation(mutationResults: schema.MutationTestRe error, timeout, total, - detected, - undetected: survived + noCoverage, - score: Math.fround(detected / (total - ignored)), - scoreCovered: Math.fround(detected / (total - ignored - noCoverage)), }; } From 13a918ef410389a0fca37e12428fec76efabb494 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 20 Aug 2024 16:09:56 +0200 Subject: [PATCH 12/53] add github workflow --- .github/workflows/mutation.yml | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/workflows/mutation.yml diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml new file mode 100644 index 000000000000..d12149221955 --- /dev/null +++ b/.github/workflows/mutation.yml @@ -0,0 +1,54 @@ +name: 'Mutation Testing' +on: + push: + branches: + - lms/test-hackweek-mutation-testing + workflow_dispatch: + inputs: + commit: + description: If the commit you want to test isn't the head of a branch, provide its SHA here + required: false + schedule: + # Run every sunday at 00:00 UTC + - cron: '0 0 * * 0' + + +env: + HEAD_COMMIT: ${{ github.event.inputs.commit || github.sha }} + +jobs: + job_build: + name: Build & Test + runs-on: ubuntu-20.04 + timeout-minutes: 15 + steps: + - name: 'Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }})' + uses: actions/checkout@v4 + with: + ref: ${{ env.HEAD_COMMIT }} + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version-file: 'package.json' + + - name: Install Dependencies + uses: ./.github/actions/install-dependencies + id: install_dependencies + + - name: Build packages + # Set the CODECOV_TOKEN for Bundle Analysis + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + run: yarn build + + - name: Run Mutation Testing + run: yarn test:mutation + + - name: Upload Results + uses: actions/upload-artifact@v4 + with: + name: ${{ github.sha }} + path: | + ${{ github.workspace }}/packages/**/mutation.json + ${{ github.workspace }}/packages/**/mutation.html From 02aaa7e94af87d9e1a05780a894012cb67b17005 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 20 Aug 2024 16:11:46 +0200 Subject: [PATCH 13/53] simplify install deps --- .github/workflows/mutation.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index d12149221955..e0e670ee46c9 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -33,8 +33,7 @@ jobs: node-version-file: 'package.json' - name: Install Dependencies - uses: ./.github/actions/install-dependencies - id: install_dependencies + run: yarn install --frozen-lockfile - name: Build packages # Set the CODECOV_TOKEN for Bundle Analysis From a9542c18886a8414ad303beb18f7d4a8afb442e0 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 20 Aug 2024 16:28:05 +0200 Subject: [PATCH 14/53] increase timeout --- .github/workflows/mutation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index e0e670ee46c9..c168e98a46f6 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -20,7 +20,7 @@ jobs: job_build: name: Build & Test runs-on: ubuntu-20.04 - timeout-minutes: 15 + timeout-minutes: 300 steps: - name: 'Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }})' uses: actions/checkout@v4 From 7281739b5870f2c363ba3e2f6da38ac782c38054 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 14:54:15 +0200 Subject: [PATCH 15/53] sentry runner, adjust ci --- .github/workflows/mutation.yml | 144 ++++++++++++++++++++-- dev-packages/stryker-config/package.json | 5 +- dev-packages/stryker-runner/README.md | 3 + dev-packages/stryker-runner/package.json | 35 ++++++ dev-packages/stryker-runner/src/run.ts | 105 ++++++++++++++++ dev-packages/stryker-runner/tsconfig.json | 10 ++ package.json | 3 +- packages/browser/package.json | 3 +- packages/browser/stryker.config.mjs | 2 +- packages/core/package.json | 3 +- packages/core/stryker.config.mjs | 2 +- packages/node/package.json | 5 +- packages/node/stryker.config.mjs | 2 +- packages/svelte/package.json | 3 +- packages/svelte/stryker.config.mjs | 2 +- packages/sveltekit/package.json | 3 +- packages/sveltekit/stryker.config.mjs | 2 +- packages/utils/package.json | 2 + scripts/stryker-results.ts | 44 ++++++- scripts/stryker-start-trace.ts | 16 +++ yarn.lock | 2 +- 21 files changed, 370 insertions(+), 26 deletions(-) create mode 100644 dev-packages/stryker-runner/README.md create mode 100644 dev-packages/stryker-runner/package.json create mode 100644 dev-packages/stryker-runner/src/run.ts create mode 100644 dev-packages/stryker-runner/tsconfig.json create mode 100644 scripts/stryker-start-trace.ts diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index c168e98a46f6..2714a3c54149 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -9,18 +9,90 @@ on: description: If the commit you want to test isn't the head of a branch, provide its SHA here required: false schedule: - # Run every sunday at 00:00 UTC + # run every sunday at midnight: - cron: '0 0 * * 0' +# Cancel in progress workflows on pull_requests. +# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-a-fallback-value +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true env: HEAD_COMMIT: ${{ github.event.inputs.commit || github.sha }} + # WARNING: this disables cross os caching as ~ and + # github.workspace evaluate to differents paths + CACHED_DEPENDENCY_PATHS: | + ${{ github.workspace }}/node_modules + ${{ github.workspace }}/packages/*/node_modules + ${{ github.workspace }}/dev-packages/*/node_modules + ~/.cache/mongodb-binaries/ + + # DEPENDENCY_CACHE_KEY: can't be set here because we don't have access to yarn.lock + + # WARNING: this disables cross os caching as ~ and + # github.workspace evaluate to differents paths + # packages/utils/cjs and packages/utils/esm: Symlinks to the folders inside of `build`, needed for tests + CACHED_BUILD_PATHS: | + ${{ github.workspace }}/dev-packages/*/build + ${{ github.workspace }}/packages/*/build + ${{ github.workspace }}/packages/ember/*.d.ts + ${{ github.workspace }}/packages/gatsby/*.d.ts + ${{ github.workspace }}/packages/core/src/version.ts + ${{ github.workspace }}/packages/utils/cjs + ${{ github.workspace }}/packages/utils/esm + + BUILD_CACHE_KEY: build-cache-${{ github.event.inputs.commit || github.sha }} + BUILD_CACHE_TARBALL_KEY: tarball-${{ github.event.inputs.commit || github.sha }} + + # GH will use the first restore-key it finds that matches + # So it will start by looking for one from the same branch, else take the newest one it can find elsewhere + # We want to prefer the cache from the current develop branch, if we don't find any on the current branch + NX_CACHE_RESTORE_KEYS: | + nx-Linux-${{ github.ref }}-${{ github.event.inputs.commit || github.sha }} + nx-Linux-${{ github.ref }} + nx-Linux + jobs: + job_get_metadata: + name: Get Metadata + runs-on: ubuntu-20.04 + permissions: + pull-requests: read + steps: + - name: Check out current commit + uses: actions/checkout@v4 + with: + ref: ${{ env.HEAD_COMMIT }} + # We need to check out not only the fake merge commit between the PR and the base branch which GH creates, but + # also its parents, so that we can pull the commit message from the head commit of the PR + fetch-depth: 2 + + - name: Get metadata + id: get_metadata + # We need to try a number of different options for finding the head commit, because each kind of trigger event + # stores it in a different location + run: | + COMMIT_SHA=$(git rev-parse --short ${{ github.event.head_commit.id || env.HEAD_COMMIT }}) + echo "COMMIT_SHA=$COMMIT_SHA" >> $GITHUB_ENV + echo "COMMIT_MESSAGE=$(git log -n 1 --pretty=format:%s $COMMIT_SHA)" >> $GITHUB_ENV + + - name: Generate Sentry Trace + id: sentry_trace + run: | + yarn ts-node ./scripts/stryker-start-trace.ts + + outputs: + commit_label: '${{ env.COMMIT_SHA }}: ${{ env.COMMIT_MESSAGE }}' + sentry_trace: '${{ env.SENTRY_MUT_SENTRY_TRACE }}' + baggage: '${{ env.SENTRY_MUT_BAGGAGE }}' + job_build: - name: Build & Test + name: Build + needs: job_get_metadata runs-on: ubuntu-20.04 - timeout-minutes: 300 + timeout-minutes: 15 steps: - name: 'Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }})' uses: actions/checkout@v4 @@ -33,21 +105,73 @@ jobs: node-version-file: 'package.json' - name: Install Dependencies - run: yarn install --frozen-lockfile + uses: ./.github/actions/install-dependencies + id: install_dependencies + + - name: Check build cache + uses: actions/cache@v4 + id: cache_built_packages + with: + path: ${{ env.CACHED_BUILD_PATHS }} + key: ${{ env.BUILD_CACHE_KEY }} + + - name: NX cache + uses: actions/cache@v4 + with: + path: .nxcache + key: nx-Linux-${{ github.ref }}-${{ env.HEAD_COMMIT || github.sha }} + restore-keys: + ${{ env.NX_CACHE_RESTORE_KEYS || 'nx-never-restore'}} - name: Build packages - # Set the CODECOV_TOKEN for Bundle Analysis - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} run: yarn build - - name: Run Mutation Testing - run: yarn test:mutation + outputs: + dependency_cache_key: ${{ steps.install_dependencies.outputs.cache_key }} + + job_mutation_test: + name: Run (${{ matrix.package }}) Mutation Testing + needs: [job_get_metadata, job_build] + timeout-minutes: 180 + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + package: [ + '@sentry/core', + '@sentry/browser', + '@sentry/node', + '@sentry/svelte', + '@sentry/sveltekit', + ] + steps: + - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) + uses: actions/checkout@v4 + with: + ref: ${{ env.HEAD_COMMIT }} + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version-file: 'package.json' + - name: Restore caches + uses: ./.github/actions/restore-cache + env: + DEPENDENCY_CACHE_KEY: ${{ needs.job_build.outputs.dependency_cache_key }} + + - name: Set trace propagation data + run: | + echo "SENTRY_MUT_SENTRY_TRACE=${{ needs.job_get_metadata.outputs.sentry_trace }}" >> $GITHUB_ENV + echo "SENTRY_MUT_BAGGAGE=${{ needs.job_get_metadata.outputs.baggage }}" >> $GITHUB_ENV + + - name: Run mutation test + run: yarn nx run ${{ matrix.package }}:mutation-test + env: + NODE_VERSION: ${{ matrix.node }} - name: Upload Results uses: actions/upload-artifact@v4 with: - name: ${{ github.sha }} + name: ${{ matrix.package }} reports path: | ${{ github.workspace }}/packages/**/mutation.json ${{ github.workspace }}/packages/**/mutation.html diff --git a/dev-packages/stryker-config/package.json b/dev-packages/stryker-config/package.json index 969390183e2d..ad6ba2628cfe 100644 --- a/dev-packages/stryker-config/package.json +++ b/dev-packages/stryker-config/package.json @@ -9,7 +9,7 @@ ], "exports": { "./package.json": "./package.json", - ".": { + "./config": { "import": { "default": "./src/stryker.config.mjs" } @@ -21,5 +21,6 @@ }, "volta": { "extends": "../../package.json" - } + }, + "type": "module" } diff --git a/dev-packages/stryker-runner/README.md b/dev-packages/stryker-runner/README.md new file mode 100644 index 000000000000..d6ccd577e0fd --- /dev/null +++ b/dev-packages/stryker-runner/README.md @@ -0,0 +1,3 @@ +# `@sentry-internal/stryker-runner` + +A runner to run stryker with Sentry instrumentation to catch errors during test runs, as well as performance data diff --git a/dev-packages/stryker-runner/package.json b/dev-packages/stryker-runner/package.json new file mode 100644 index 000000000000..97a38bd09c3d --- /dev/null +++ b/dev-packages/stryker-runner/package.json @@ -0,0 +1,35 @@ +{ + "private": true, + "version": "8.26.0", + "name": "@sentry-internal/stryker-runner", + "author": "Sentry", + "license": "MIT", + "files": [ + "src" + ], + "exports": { + "./package.json": "./package.json" + }, + "sideEffects": false, + "engines": { + "node": ">=14.18" + }, + "volta": { + "extends": "../../package.json" + }, + "dependencies": { + "@sentry/node": "^8.26.0", + "@stryker-mutator/core": "^8.5.0", + "typescript": "^4.9.5" + }, + "devDependencies": { + "@stryker-mutator/api": "^8.5.0" + }, + "scripts": { + "build": "tsc", + "build:watch": "tsc --watch", + "start": "node ./dist/run.js" + }, + "type": "module", + "bin": "./build/run.js" +} diff --git a/dev-packages/stryker-runner/src/run.ts b/dev-packages/stryker-runner/src/run.ts new file mode 100644 index 000000000000..151452ac05c1 --- /dev/null +++ b/dev-packages/stryker-runner/src/run.ts @@ -0,0 +1,105 @@ +#!/usr/bin/env node + +import * as child_process from 'node:child_process'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +import * as Sentry from '@sentry/node'; + +import type { schema } from '@stryker-mutator/api/core'; +/* eslint-disable no-console */ +import type { StrykerCli } from '@stryker-mutator/core'; +import { Stryker } from '@stryker-mutator/core'; + +interface PackageJson { + name: string; +} + +interface MutationTestResultAggregation { + killed: number; + timeout: number; + survived: number; + noCoverage: number; + ignored: number; + error: number; + detected: number; + undetected: number; + total: number; + score: number; + scoreCovered: number; +} + +Sentry.init({ + dsn: 'https://cdae3f96df86224530838d318d268f62@o447951.ingest.us.sentry.io/4507814527303680', + tracesSampleRate: 1.0, + defaultIntegrations: false, + + environment: process.env.CI ? 'ci' : 'local', + release: child_process.execSync('git rev-parse HEAD').toString().trim(), +}); + +const configFile = path.join(process.cwd(), '/stryker.config.mjs'); +const pkgJson = path.join(process.cwd(), 'package.json'); + +const packageName = (JSON.parse(fs.readFileSync(pkgJson).toString()) as PackageJson).name; + +async function main(): Promise { + await Sentry.continueTrace( + { + sentryTrace: process.env.SENTRY_MUT_SENTRY_TRACE || undefined, + baggage: process.env.SENTRY_MUT_BAGGAGE || undefined, + }, + () => + Sentry.startSpan({ name: packageName, op: 'mutation' }, async () => { + const config = await Sentry.startSpan({ name: 'import stryker config', op: 'import' }, async () => { + const mod = (await import(configFile)) as { default: Partial }; + return mod.default; + }); + + // Runs Stryker, will not assume to be allowed to exit the process. + const stryker = new Stryker(config); + const mutantResults = await Sentry.startSpan({ name: 'run mutation test', op: 'stryker' }, async () => + stryker.runMutationTest(), + ); + + Sentry.startSpan({ name: 'report results', op: 'sentry' }, () => { + const aggregatedResult = getMutationTestResultAggregation(mutantResults); + Sentry.setTag('mutation.score', aggregatedResult.score); + Sentry.setTag('mutation.package', packageName); + Sentry.setMeasurement('mutation.score', aggregatedResult.score, 'ratio'); + Sentry.setMeasurement('mutation.score_covered', aggregatedResult.scoreCovered, 'ratio'); + }); + }), + ); +} + +main().catch(console.error); + +function getMutationTestResultAggregation(mutantResults: schema.MutantResult[]): MutationTestResultAggregation { + const total = mutantResults.length; + + const noCoverage = mutantResults.filter(mutant => mutant.status === 'NoCoverage').length; + const killed = mutantResults.filter(mutant => mutant.status === 'Killed').length; + const survived = mutantResults.filter(mutant => mutant.status === 'Survived').length; + const error = mutantResults.filter( + mutant => mutant.status === 'RuntimeError' || mutant.status === 'CompileError', + ).length; + const ignored = mutantResults.filter(mutant => mutant.status === 'Ignored').length; + const timeout = mutantResults.filter(mutant => mutant.status === 'Timeout').length; + + const detected = killed + timeout; + + return { + score: Math.round((detected / (total - ignored) + Number.EPSILON) * 100) / 100, + scoreCovered: Math.round((detected / (total - ignored - noCoverage) + Number.EPSILON) * 100) / 100, + detected, + undetected: survived + noCoverage, + killed, + survived, + noCoverage, + ignored, + error, + timeout, + total, + }; +} diff --git a/dev-packages/stryker-runner/tsconfig.json b/dev-packages/stryker-runner/tsconfig.json new file mode 100644 index 000000000000..a9a30600a64b --- /dev/null +++ b/dev-packages/stryker-runner/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "moduleResolution": "NodeNext", + "target": "ES2022", + "module": "NodeNext", + "outDir": "build" + }, + "include": ["src/**/*.ts"] +} diff --git a/package.json b/package.json index 0637bb147ab2..32066979c1a7 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,8 @@ "dev-packages/rollup-utils", "dev-packages/jest-config", "dev-packages/vitest-config", - "dev-packages/stryker-config" + "dev-packages/stryker-config", + "dev-packages/stryker-runner" ], "devDependencies": { "@biomejs/biome": "^1.4.0", diff --git a/packages/browser/package.json b/packages/browser/package.json index 34e70d02dee9..548ffe65ffb1 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -51,6 +51,7 @@ "@sentry-internal/integration-shims": "8.26.0", "@sentry-internal/vitest-config": "8.26.0", "@sentry-internal/stryker-config": "8.26.0", + "@sentry-internal/stryker-runner": "8.26.0", "fake-indexeddb": "^4.0.1" }, "scripts": { @@ -74,7 +75,7 @@ "size:check": "cat build/bundles/bundle.min.js | gzip -9 | wc -c | awk '{$1=$1/1024; print \"ES2017: \",$1,\"kB\";}'", "test": "vitest run", "test:watch": "vitest --watch", - "test:mutation": "stryker run", + "test:mutation": "stryker-runner", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/browser/stryker.config.mjs b/packages/browser/stryker.config.mjs index 2f7a7587770e..e432f08e109b 100644 --- a/packages/browser/stryker.config.mjs +++ b/packages/browser/stryker.config.mjs @@ -1,4 +1,4 @@ -import baseConfig from '@sentry-internal/stryker-config'; +import baseConfig from '@sentry-internal/stryker-config/config'; /** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ const config = { diff --git a/packages/core/package.json b/packages/core/package.json index 76679948efe4..5cfefa457bf7 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -43,6 +43,7 @@ "@sentry/utils": "8.26.0" }, "devDependencies": { + "@sentry-internal/stryker-runner": "8.26.0", "@sentry-internal/vitest-config": "8.26.0" }, "scripts": { @@ -63,7 +64,7 @@ "lint": "eslint . --format stylish", "test": "vitest run", "test:watch": "vitest --watch", - "test:mutation": "stryker run", + "test:mutation": "stryker-runner", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/core/stryker.config.mjs b/packages/core/stryker.config.mjs index cf879a99a484..c28cd37bf8c0 100644 --- a/packages/core/stryker.config.mjs +++ b/packages/core/stryker.config.mjs @@ -1,4 +1,4 @@ -import baseConfig from '@sentry-internal/stryker-config'; +import baseConfig from '@sentry-internal/stryker-config/config'; /** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ const config = { diff --git a/packages/node/package.json b/packages/node/package.json index 0fd52c5fbe2e..8ad9859b832e 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -97,7 +97,8 @@ }, "devDependencies": { "@types/node": "^14.18.0", - "@sentry-internal/jest-config": "8.26.0" + "@sentry-internal/jest-config": "8.26.0", + "@sentry-internal/stryker-runner": "8.26.0" }, "optionalDependencies": { "opentelemetry-instrumentation-fetch-node": "1.2.3" @@ -121,7 +122,7 @@ "test": "yarn test:jest", "test:jest": "jest", "test:watch": "jest --watch", - "test:mutation": "stryker run", + "test:mutation": "stryker-runner", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/node/stryker.config.mjs b/packages/node/stryker.config.mjs index 1afd0140bcc7..172b2ba11ae4 100644 --- a/packages/node/stryker.config.mjs +++ b/packages/node/stryker.config.mjs @@ -1,4 +1,4 @@ -import baseConfig from '@sentry-internal/stryker-config'; +import baseConfig from '@sentry-internal/stryker-config/config'; /** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ const config = { diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 88e7d1e175b6..6f6eb35de415 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -50,6 +50,7 @@ }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "1.4.0", + "@sentry-internal/stryker-runner": "8.26.0", "@testing-library/svelte": "^3.2.1", "svelte": "3.49.0" }, @@ -71,7 +72,7 @@ "lint": "eslint . --format stylish", "test": "vitest run", "test:watch": "vitest --watch", - "test:mutation": "stryker run", + "test:mutation": "stryker-runner", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/svelte/stryker.config.mjs b/packages/svelte/stryker.config.mjs index a99493ec7423..2445945d495a 100644 --- a/packages/svelte/stryker.config.mjs +++ b/packages/svelte/stryker.config.mjs @@ -1,4 +1,4 @@ -import baseConfig from '@sentry-internal/stryker-config'; +import baseConfig from '@sentry-internal/stryker-config/config'; /** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ const config = { diff --git a/packages/sveltekit/package.json b/packages/sveltekit/package.json index 7a5420c7451b..550d28612d57 100644 --- a/packages/sveltekit/package.json +++ b/packages/sveltekit/package.json @@ -53,6 +53,7 @@ }, "devDependencies": { "@babel/types": "7.20.7", + "@sentry-internal/stryker-runner": "8.26.0", "@sveltejs/kit": "^2.0.2", "svelte": "^4.2.8", "vite": "^5.0.10" @@ -74,7 +75,7 @@ "test": "yarn test:unit", "test:unit": "vitest run", "test:watch": "vitest --watch", - "test:mutation": "stryker run", + "test:mutation": "stryker-runner", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/sveltekit/stryker.config.mjs b/packages/sveltekit/stryker.config.mjs index 92cc1ed94b5b..372443b6d222 100644 --- a/packages/sveltekit/stryker.config.mjs +++ b/packages/sveltekit/stryker.config.mjs @@ -1,4 +1,4 @@ -import baseConfig from '@sentry-internal/stryker-config'; +import baseConfig from '@sentry-internal/stryker-config/config'; /** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ const config = { diff --git a/packages/utils/package.json b/packages/utils/package.json index f9aaffaeaf56..e51f17267af0 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -42,6 +42,7 @@ "@sentry/types": "8.26.0" }, "devDependencies": { + "@sentry-internal/stryker-runner": "8.26.0", "@types/array.prototype.flat": "^1.2.1", "array.prototype.flat": "^1.3.0" }, @@ -63,6 +64,7 @@ "lint": "eslint . --format stylish", "test": "jest", "test:watch": "jest --watch", + "test:mutation": "stryker-runner", "version": "node ../../scripts/versionbump.js src/version.ts", "yalc:publish": "yalc publish --push --sig" }, diff --git a/scripts/stryker-results.ts b/scripts/stryker-results.ts index 94392a84f9a4..dd27b987096c 100644 --- a/scripts/stryker-results.ts +++ b/scripts/stryker-results.ts @@ -1,10 +1,27 @@ /* eslint-disable no-console */ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ + +import * as child_process from 'node:child_process'; import * as fs from 'node:fs'; import * as path from 'node:path'; import type { schema } from '@stryker-mutator/api/core'; +import * as Sentry from '@sentry/node'; + +Sentry.init({ + dsn: 'https://cdae3f96df86224530838d318d268f62@o447951.ingest.us.sentry.io/4507814527303680', + tracesSampleRate: 1.0, + defaultIntegrations: false, + + environment: process.env.CI ? 'ci' : 'local', + release: child_process.execSync('git rev-parse HEAD').toString().trim(), + + beforeSendTransaction(transaction) { + console.log('Sending transaction to Sentry:', transaction); + return transaction; + }, +}); + interface MutationTestResultAggregation { package: string; killed: number; @@ -24,6 +41,7 @@ function main(): void { const mutationResults: schema.MutationTestResult[] = getMutationTestResults(); const results = mutationResults.map(getMutationTestResultAggregation).sort((a, b) => b.score - a.score); console.table(results); + sendResultsToSentry(results); } function getMutationTestResults(): schema.MutationTestResult[] { @@ -79,6 +97,30 @@ function getMutationTestResultAggregation(mutationResults: schema.MutationTestRe }; } +// sentry-trace header: uuid{32}-uuid{16}-bool{1}: +// 8e6b2b4a9e9a4b7b9e9b9e9a9e9b9e9a-8e6b2b4a9e9a4b7b-1 + +function sendResultsToSentry(mutationResults: MutationTestResultAggregation[]): void { + Sentry.continueTrace( + { + sentryTrace: '8e6b2b4a9e9a4b7b9e9b9e9a9e9b9e9a-8e6b2b4a9e9a4b7b-1', + baggage: 'sentry-trace_id=8e6b2b4a9e9a4b7b9e9b9e9a9e9b9e9a', + }, + () => { + mutationResults.forEach(res => { + Sentry.withScope(scope => { + Sentry.startSpanManual({ name: res.package, op: 'test' }, rootSpan => { + scope.setTag('mutation.score', res.score); + scope.setTag('mutation.package', res.package); + Sentry.setMeasurement('mutation.score', res.score, 'ratio'); + rootSpan.end(); + }); + }); + }); + }, + ); +} + function getPackageName(mutationResults: schema.MutationTestResult): string { try { return ( diff --git a/scripts/stryker-start-trace.ts b/scripts/stryker-start-trace.ts new file mode 100644 index 000000000000..cd32fcac5e7d --- /dev/null +++ b/scripts/stryker-start-trace.ts @@ -0,0 +1,16 @@ +// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access +import { randomUUID } from 'node:crypto'; + +const traceId = randomUUID().replace(/-/g, ''); +const spanId = randomUUID().replace(/-/g, '').slice(0, 16); + +const sentryTrace = `${traceId}-${spanId}-1`; +const baggage = `sentry-trace_id=${sentryTrace}`; + +process.env.SENTRY_MUT_SENTRY_TRACE = sentryTrace; +process.env.SENTRY_MUT_BAGGAGE = baggage; + +export default { + sentryTrace, + baggage, +}; diff --git a/yarn.lock b/yarn.lock index 09341f972f21..bd0d7dd20324 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9415,7 +9415,7 @@ dependencies: highlight.js "^9.15.6" -"@stryker-mutator/api@8.5.0": +"@stryker-mutator/api@8.5.0", "@stryker-mutator/api@^8.5.0": version "8.5.0" resolved "https://registry.yarnpkg.com/@stryker-mutator/api/-/api-8.5.0.tgz#b58b0c15c4c525541a9a6bb78cf1ec469de4beb2" integrity sha512-dhz6BAbNr6LW96UjJFyxVnGOvJqo+7GdIBJl3Cckg3/Bakn0jL61xZ0ca9pcrbVHivy9vlzMs+dCv2pr9QV9rg== From 25f82d607c6911a77ad8e571774a90afd1cb3d92 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 14:55:45 +0200 Subject: [PATCH 16/53] start trace later --- .github/workflows/mutation.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 2714a3c54149..1114582a9db1 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -78,15 +78,8 @@ jobs: echo "COMMIT_SHA=$COMMIT_SHA" >> $GITHUB_ENV echo "COMMIT_MESSAGE=$(git log -n 1 --pretty=format:%s $COMMIT_SHA)" >> $GITHUB_ENV - - name: Generate Sentry Trace - id: sentry_trace - run: | - yarn ts-node ./scripts/stryker-start-trace.ts - outputs: commit_label: '${{ env.COMMIT_SHA }}: ${{ env.COMMIT_MESSAGE }}' - sentry_trace: '${{ env.SENTRY_MUT_SENTRY_TRACE }}' - baggage: '${{ env.SENTRY_MUT_BAGGAGE }}' job_build: name: Build @@ -126,8 +119,15 @@ jobs: - name: Build packages run: yarn build + - name: Generate Sentry Trace + id: sentry_trace + run: | + yarn ts-node ./scripts/stryker-start-trace.ts + outputs: dependency_cache_key: ${{ steps.install_dependencies.outputs.cache_key }} + sentry_trace: '${{ env.SENTRY_MUT_SENTRY_TRACE }}' + baggage: '${{ env.SENTRY_MUT_BAGGAGE }}' job_mutation_test: name: Run (${{ matrix.package }}) Mutation Testing @@ -160,8 +160,8 @@ jobs: - name: Set trace propagation data run: | - echo "SENTRY_MUT_SENTRY_TRACE=${{ needs.job_get_metadata.outputs.sentry_trace }}" >> $GITHUB_ENV - echo "SENTRY_MUT_BAGGAGE=${{ needs.job_get_metadata.outputs.baggage }}" >> $GITHUB_ENV + echo "SENTRY_MUT_SENTRY_TRACE=${{ needs.job_build.outputs.sentry_trace }}" >> $GITHUB_ENV + echo "SENTRY_MUT_BAGGAGE=${{ needs.job_build.outputs.baggage }}" >> $GITHUB_ENV - name: Run mutation test run: yarn nx run ${{ matrix.package }}:mutation-test From 13e28680f76e83554136c2b153de139cad3a8e02 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 15:03:38 +0200 Subject: [PATCH 17/53] rm nx cache --- .github/workflows/mutation.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 1114582a9db1..c15842657839 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -46,14 +46,6 @@ env: BUILD_CACHE_KEY: build-cache-${{ github.event.inputs.commit || github.sha }} BUILD_CACHE_TARBALL_KEY: tarball-${{ github.event.inputs.commit || github.sha }} - # GH will use the first restore-key it finds that matches - # So it will start by looking for one from the same branch, else take the newest one it can find elsewhere - # We want to prefer the cache from the current develop branch, if we don't find any on the current branch - NX_CACHE_RESTORE_KEYS: | - nx-Linux-${{ github.ref }}-${{ github.event.inputs.commit || github.sha }} - nx-Linux-${{ github.ref }} - nx-Linux - jobs: job_get_metadata: name: Get Metadata @@ -108,14 +100,6 @@ jobs: path: ${{ env.CACHED_BUILD_PATHS }} key: ${{ env.BUILD_CACHE_KEY }} - - name: NX cache - uses: actions/cache@v4 - with: - path: .nxcache - key: nx-Linux-${{ github.ref }}-${{ env.HEAD_COMMIT || github.sha }} - restore-keys: - ${{ env.NX_CACHE_RESTORE_KEYS || 'nx-never-restore'}} - - name: Build packages run: yarn build From 8078e66955886eca66e8d96706af818066ba979e Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 15:28:42 +0200 Subject: [PATCH 18/53] fix dependency tree --- dev-packages/stryker-runner/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-packages/stryker-runner/package.json b/dev-packages/stryker-runner/package.json index 97a38bd09c3d..1091f42705e6 100644 --- a/dev-packages/stryker-runner/package.json +++ b/dev-packages/stryker-runner/package.json @@ -18,7 +18,6 @@ "extends": "../../package.json" }, "dependencies": { - "@sentry/node": "^8.26.0", "@stryker-mutator/core": "^8.5.0", "typescript": "^4.9.5" }, @@ -27,6 +26,7 @@ }, "scripts": { "build": "tsc", + "build:transpile": "tsc", "build:watch": "tsc --watch", "start": "node ./dist/run.js" }, From 360e87d49b309ee2bd91b98ba7ca9e9d3b7e050c Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 15:28:54 +0200 Subject: [PATCH 19/53] Revert "rm nx cache" This reverts commit 13e28680f76e83554136c2b153de139cad3a8e02. --- .github/workflows/mutation.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index c15842657839..1114582a9db1 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -46,6 +46,14 @@ env: BUILD_CACHE_KEY: build-cache-${{ github.event.inputs.commit || github.sha }} BUILD_CACHE_TARBALL_KEY: tarball-${{ github.event.inputs.commit || github.sha }} + # GH will use the first restore-key it finds that matches + # So it will start by looking for one from the same branch, else take the newest one it can find elsewhere + # We want to prefer the cache from the current develop branch, if we don't find any on the current branch + NX_CACHE_RESTORE_KEYS: | + nx-Linux-${{ github.ref }}-${{ github.event.inputs.commit || github.sha }} + nx-Linux-${{ github.ref }} + nx-Linux + jobs: job_get_metadata: name: Get Metadata @@ -100,6 +108,14 @@ jobs: path: ${{ env.CACHED_BUILD_PATHS }} key: ${{ env.BUILD_CACHE_KEY }} + - name: NX cache + uses: actions/cache@v4 + with: + path: .nxcache + key: nx-Linux-${{ github.ref }}-${{ env.HEAD_COMMIT || github.sha }} + restore-keys: + ${{ env.NX_CACHE_RESTORE_KEYS || 'nx-never-restore'}} + - name: Build packages run: yarn build From 721d72f490cb7a6b1f0b8b8b5905d8d276f2cc7b Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 15:55:30 +0200 Subject: [PATCH 20/53] maybe pls fix dep error --- dev-packages/stryker-runner/package.json | 2 +- dev-packages/stryker-runner/src/run.ts | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/dev-packages/stryker-runner/package.json b/dev-packages/stryker-runner/package.json index 1091f42705e6..71572c96de21 100644 --- a/dev-packages/stryker-runner/package.json +++ b/dev-packages/stryker-runner/package.json @@ -28,7 +28,7 @@ "build": "tsc", "build:transpile": "tsc", "build:watch": "tsc --watch", - "start": "node ./dist/run.js" + "start": "node ./build/run.js" }, "type": "module", "bin": "./build/run.js" diff --git a/dev-packages/stryker-runner/src/run.ts b/dev-packages/stryker-runner/src/run.ts index 151452ac05c1..ae11f8b92cc5 100644 --- a/dev-packages/stryker-runner/src/run.ts +++ b/dev-packages/stryker-runner/src/run.ts @@ -4,8 +4,6 @@ import * as child_process from 'node:child_process'; import * as fs from 'node:fs'; import * as path from 'node:path'; -import * as Sentry from '@sentry/node'; - import type { schema } from '@stryker-mutator/api/core'; /* eslint-disable no-console */ import type { StrykerCli } from '@stryker-mutator/core'; @@ -29,21 +27,23 @@ interface MutationTestResultAggregation { scoreCovered: number; } -Sentry.init({ - dsn: 'https://cdae3f96df86224530838d318d268f62@o447951.ingest.us.sentry.io/4507814527303680', - tracesSampleRate: 1.0, - defaultIntegrations: false, - - environment: process.env.CI ? 'ci' : 'local', - release: child_process.execSync('git rev-parse HEAD').toString().trim(), -}); - const configFile = path.join(process.cwd(), '/stryker.config.mjs'); const pkgJson = path.join(process.cwd(), 'package.json'); const packageName = (JSON.parse(fs.readFileSync(pkgJson).toString()) as PackageJson).name; async function main(): Promise { + // @ts-expect-error - ugly but this creates a type error b/c i can't register the package as dep + const Sentry = await import('@sentry/node'); + Sentry.init({ + dsn: 'https://cdae3f96df86224530838d318d268f62@o447951.ingest.us.sentry.io/4507814527303680', + tracesSampleRate: 1.0, + defaultIntegrations: false, + + environment: process.env.CI ? 'ci' : 'local', + release: child_process.execSync('git rev-parse HEAD').toString().trim(), + }); + await Sentry.continueTrace( { sentryTrace: process.env.SENTRY_MUT_SENTRY_TRACE || undefined, From feaa498e761ef0cc95d2d7cece7d7bbd504d606d Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 16:09:33 +0200 Subject: [PATCH 21/53] fix test command in ci --- .github/workflows/mutation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 1114582a9db1..b727844409bb 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -164,7 +164,7 @@ jobs: echo "SENTRY_MUT_BAGGAGE=${{ needs.job_build.outputs.baggage }}" >> $GITHUB_ENV - name: Run mutation test - run: yarn nx run ${{ matrix.package }}:mutation-test + run: yarn nx run ${{ matrix.package }}:test:mutation env: NODE_VERSION: ${{ matrix.node }} From 12e776eb62eec86dd20f8253e9835177cec1ef96 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 16:20:06 +0200 Subject: [PATCH 22/53] maybe fix missing runner issue --- .github/workflows/mutation.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index b727844409bb..beabca671bda 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -158,6 +158,9 @@ jobs: env: DEPENDENCY_CACHE_KEY: ${{ needs.job_build.outputs.dependency_cache_key }} + - name: Run yarn again + run: yarn + - name: Set trace propagation data run: | echo "SENTRY_MUT_SENTRY_TRACE=${{ needs.job_build.outputs.sentry_trace }}" >> $GITHUB_ENV From 40e167fccc58e44dc4a88ed0dab1219fee2424ae Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 16:25:27 +0200 Subject: [PATCH 23/53] . --- packages/core/package.json | 2 +- packages/svelte/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/package.json b/packages/core/package.json index 5cfefa457bf7..20822aa00dc8 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -64,7 +64,7 @@ "lint": "eslint . --format stylish", "test": "vitest run", "test:watch": "vitest --watch", - "test:mutation": "stryker-runner", + "test:mutation": "npx stryker-runner", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 6f6eb35de415..60e804368497 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -72,7 +72,7 @@ "lint": "eslint . --format stylish", "test": "vitest run", "test:watch": "vitest --watch", - "test:mutation": "stryker-runner", + "test:mutation": "yarn stryker-runner", "yalc:publish": "yalc publish --push --sig" }, "volta": { From d829ec448991a55a0c14eaa90609f408ff67cce8 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 19:39:14 +0200 Subject: [PATCH 24/53] check dir content --- .github/workflows/mutation.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index beabca671bda..76a72708eb2c 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -124,6 +124,11 @@ jobs: run: | yarn ts-node ./scripts/stryker-start-trace.ts + + - name: Test 1 + run: | + ls -la node_modules/.bin + ls -la ../../node_modules/.bin outputs: dependency_cache_key: ${{ steps.install_dependencies.outputs.cache_key }} sentry_trace: '${{ env.SENTRY_MUT_SENTRY_TRACE }}' @@ -166,6 +171,11 @@ jobs: echo "SENTRY_MUT_SENTRY_TRACE=${{ needs.job_build.outputs.sentry_trace }}" >> $GITHUB_ENV echo "SENTRY_MUT_BAGGAGE=${{ needs.job_build.outputs.baggage }}" >> $GITHUB_ENV + - name: Test 2 + run: | + ls -la node_modules/.bin + ls -la ../../node_modules/.bin + - name: Run mutation test run: yarn nx run ${{ matrix.package }}:test:mutation env: From 4c1934e232af9ebd6e58a56e94a1d0aa1b7532ab Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 19:44:35 +0200 Subject: [PATCH 25/53] . --- .github/workflows/mutation.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 76a72708eb2c..e194cd9eef96 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -128,7 +128,10 @@ jobs: - name: Test 1 run: | ls -la node_modules/.bin - ls -la ../../node_modules/.bin + ls -la packages/core/node_modules/.bin + ls -la packages/svelte/node_modules/.bin + ls -la packages/browser/node_modules/.bin + outputs: dependency_cache_key: ${{ steps.install_dependencies.outputs.cache_key }} sentry_trace: '${{ env.SENTRY_MUT_SENTRY_TRACE }}' @@ -174,7 +177,9 @@ jobs: - name: Test 2 run: | ls -la node_modules/.bin - ls -la ../../node_modules/.bin + ls -la packages/core/node_modules/.bin + ls -la packages/svelte/node_modules/.bin + ls -la packages/browser/node_modules/.bin - name: Run mutation test run: yarn nx run ${{ matrix.package }}:test:mutation From 17e56cc8ced063f2dacb305c730499d24a3dfe72 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 19:49:34 +0200 Subject: [PATCH 26/53] .. --- .github/workflows/mutation.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index e194cd9eef96..1456207ec12e 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -49,10 +49,10 @@ env: # GH will use the first restore-key it finds that matches # So it will start by looking for one from the same branch, else take the newest one it can find elsewhere # We want to prefer the cache from the current develop branch, if we don't find any on the current branch - NX_CACHE_RESTORE_KEYS: | - nx-Linux-${{ github.ref }}-${{ github.event.inputs.commit || github.sha }} - nx-Linux-${{ github.ref }} - nx-Linux + # NX_CACHE_RESTORE_KEYS: | + # nx-Linux-${{ github.ref }}-${{ github.event.inputs.commit || github.sha }} + # nx-Linux-${{ github.ref }} + # nx-Linux jobs: job_get_metadata: @@ -108,13 +108,13 @@ jobs: path: ${{ env.CACHED_BUILD_PATHS }} key: ${{ env.BUILD_CACHE_KEY }} - - name: NX cache - uses: actions/cache@v4 - with: - path: .nxcache - key: nx-Linux-${{ github.ref }}-${{ env.HEAD_COMMIT || github.sha }} - restore-keys: - ${{ env.NX_CACHE_RESTORE_KEYS || 'nx-never-restore'}} + # - name: NX cache + # uses: actions/cache@v4 + # with: + # path: .nxcache + # key: nx-Linux-${{ github.ref }}-${{ env.HEAD_COMMIT || github.sha }} + # restore-keys: + # ${{ env.NX_CACHE_RESTORE_KEYS || 'nx-never-restore'}} - name: Build packages run: yarn build From 5593843636427d23f73e9a5b34bc35877874c8c9 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 19:57:21 +0200 Subject: [PATCH 27/53] esm --- .github/workflows/mutation.yml | 22 +++++++++++----------- dev-packages/stryker-runner/package.json | 4 ++-- dev-packages/stryker-runner/tsconfig.json | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 1456207ec12e..e194cd9eef96 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -49,10 +49,10 @@ env: # GH will use the first restore-key it finds that matches # So it will start by looking for one from the same branch, else take the newest one it can find elsewhere # We want to prefer the cache from the current develop branch, if we don't find any on the current branch - # NX_CACHE_RESTORE_KEYS: | - # nx-Linux-${{ github.ref }}-${{ github.event.inputs.commit || github.sha }} - # nx-Linux-${{ github.ref }} - # nx-Linux + NX_CACHE_RESTORE_KEYS: | + nx-Linux-${{ github.ref }}-${{ github.event.inputs.commit || github.sha }} + nx-Linux-${{ github.ref }} + nx-Linux jobs: job_get_metadata: @@ -108,13 +108,13 @@ jobs: path: ${{ env.CACHED_BUILD_PATHS }} key: ${{ env.BUILD_CACHE_KEY }} - # - name: NX cache - # uses: actions/cache@v4 - # with: - # path: .nxcache - # key: nx-Linux-${{ github.ref }}-${{ env.HEAD_COMMIT || github.sha }} - # restore-keys: - # ${{ env.NX_CACHE_RESTORE_KEYS || 'nx-never-restore'}} + - name: NX cache + uses: actions/cache@v4 + with: + path: .nxcache + key: nx-Linux-${{ github.ref }}-${{ env.HEAD_COMMIT || github.sha }} + restore-keys: + ${{ env.NX_CACHE_RESTORE_KEYS || 'nx-never-restore'}} - name: Build packages run: yarn build diff --git a/dev-packages/stryker-runner/package.json b/dev-packages/stryker-runner/package.json index 71572c96de21..75ab6cedb05d 100644 --- a/dev-packages/stryker-runner/package.json +++ b/dev-packages/stryker-runner/package.json @@ -28,8 +28,8 @@ "build": "tsc", "build:transpile": "tsc", "build:watch": "tsc --watch", - "start": "node ./build/run.js" + "start": "node ./build/esm/run.js" }, "type": "module", - "bin": "./build/run.js" + "bin": "./build/esm/run.js" } diff --git a/dev-packages/stryker-runner/tsconfig.json b/dev-packages/stryker-runner/tsconfig.json index a9a30600a64b..391eac9eaf93 100644 --- a/dev-packages/stryker-runner/tsconfig.json +++ b/dev-packages/stryker-runner/tsconfig.json @@ -4,7 +4,7 @@ "moduleResolution": "NodeNext", "target": "ES2022", "module": "NodeNext", - "outDir": "build" + "outDir": "build/esm" }, "include": ["src/**/*.ts"] } From 8f4cc7ab99df144b86bd780b97720209be744b67 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 20:11:22 +0200 Subject: [PATCH 28/53] ... --- .github/workflows/mutation.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index e194cd9eef96..18c20e839ee8 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -166,6 +166,14 @@ jobs: env: DEPENDENCY_CACHE_KEY: ${{ needs.job_build.outputs.dependency_cache_key }} + - name: NX cache + uses: actions/cache@v4 + with: + path: .nxcache + key: nx-Linux-${{ github.ref }}-${{ env.HEAD_COMMIT || github.sha }} + restore-keys: + ${{ env.NX_CACHE_RESTORE_KEYS || 'nx-never-restore'}} + - name: Run yarn again run: yarn From 80d069c142402acf413435f776311328758a1b69 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 21 Aug 2024 22:00:12 +0200 Subject: [PATCH 29/53] maybe now? --- dev-packages/stryker-runner/package.json | 3 +-- packages/core/package.json | 2 +- packages/svelte/package.json | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dev-packages/stryker-runner/package.json b/dev-packages/stryker-runner/package.json index 75ab6cedb05d..dc620f0f32c6 100644 --- a/dev-packages/stryker-runner/package.json +++ b/dev-packages/stryker-runner/package.json @@ -5,12 +5,11 @@ "author": "Sentry", "license": "MIT", "files": [ - "src" + "build" ], "exports": { "./package.json": "./package.json" }, - "sideEffects": false, "engines": { "node": ">=14.18" }, diff --git a/packages/core/package.json b/packages/core/package.json index 20822aa00dc8..5cfefa457bf7 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -64,7 +64,7 @@ "lint": "eslint . --format stylish", "test": "vitest run", "test:watch": "vitest --watch", - "test:mutation": "npx stryker-runner", + "test:mutation": "stryker-runner", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 60e804368497..6f6eb35de415 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -72,7 +72,7 @@ "lint": "eslint . --format stylish", "test": "vitest run", "test:watch": "vitest --watch", - "test:mutation": "yarn stryker-runner", + "test:mutation": "stryker-runner", "yalc:publish": "yalc publish --push --sig" }, "volta": { From 43089e64b41fade4c25ed0ad0138cb65ab977899 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 10:11:55 +0200 Subject: [PATCH 30/53] use script instead of package --- .github/workflows/mutation.yml | 2 +- .../stryker-runner/src/runMutation.ts | 103 ++++++++++++++++++ nx.json | 2 +- package.json | 2 +- packages/browser/package.json | 2 +- packages/core/package.json | 2 +- packages/node/package.json | 2 +- packages/svelte/package.json | 2 +- packages/sveltekit/package.json | 2 +- packages/utils/package.json | 2 +- ...-results.ts => stryker-collect-results.ts} | 0 scripts/stryker/package.json | 3 + scripts/stryker/run-with-sentry.mjs | 83 ++++++++++++++ .../start-trace.mjs} | 0 14 files changed, 198 insertions(+), 9 deletions(-) create mode 100644 dev-packages/stryker-runner/src/runMutation.ts rename scripts/{stryker-results.ts => stryker-collect-results.ts} (100%) create mode 100644 scripts/stryker/package.json create mode 100644 scripts/stryker/run-with-sentry.mjs rename scripts/{stryker-start-trace.ts => stryker/start-trace.mjs} (100%) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 18c20e839ee8..df4a19d4300b 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -122,7 +122,7 @@ jobs: - name: Generate Sentry Trace id: sentry_trace run: | - yarn ts-node ./scripts/stryker-start-trace.ts + yarn ts-node ./scripts/stryker/start-trace.ts - name: Test 1 diff --git a/dev-packages/stryker-runner/src/runMutation.ts b/dev-packages/stryker-runner/src/runMutation.ts new file mode 100644 index 000000000000..7824596455ec --- /dev/null +++ b/dev-packages/stryker-runner/src/runMutation.ts @@ -0,0 +1,103 @@ +#!/usr/bin/env node + +import * as child_process from 'node:child_process'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +import type { schema } from '@stryker-mutator/api/core'; +/* eslint-disable no-console */ +import type { StrykerCli } from '@stryker-mutator/core'; +import { Stryker } from '@stryker-mutator/core'; + +interface PackageJson { + name: string; +} + +interface MutationTestResultAggregation { + killed: number; + timeout: number; + survived: number; + noCoverage: number; + ignored: number; + error: number; + detected: number; + undetected: number; + total: number; + score: number; + scoreCovered: number; +} + +const configFile = path.join(process.cwd(), '/stryker.config.mjs'); +const pkgJson = path.join(process.cwd(), 'package.json'); + +const packageName = (JSON.parse(fs.readFileSync(pkgJson).toString()) as PackageJson).name; +const Sentry = await import('@sentry/node'); + +main().catch(console.error); + +function getMutationTestResultAggregation(mutantResults: schema.MutantResult[]): MutationTestResultAggregation { + const total = mutantResults.length; + + const noCoverage = mutantResults.filter(mutant => mutant.status === 'NoCoverage').length; + const killed = mutantResults.filter(mutant => mutant.status === 'Killed').length; + const survived = mutantResults.filter(mutant => mutant.status === 'Survived').length; + const error = mutantResults.filter( + mutant => mutant.status === 'RuntimeError' || mutant.status === 'CompileError', + ).length; + const ignored = mutantResults.filter(mutant => mutant.status === 'Ignored').length; + const timeout = mutantResults.filter(mutant => mutant.status === 'Timeout').length; + + const detected = killed + timeout; + + return { + score: Math.round((detected / (total - ignored) + Number.EPSILON) * 100) / 100, + scoreCovered: Math.round((detected / (total - ignored - noCoverage) + Number.EPSILON) * 100) / 100, + detected, + undetected: survived + noCoverage, + killed, + survived, + noCoverage, + ignored, + error, + timeout, + total, + }; +} + +async function main(): Promise { + Sentry.init({ + dsn: process.env.SENTRY_DSN, + tracesSampleRate: 1.0, + defaultIntegrations: false, + environment: process.env.CI ? 'ci' : 'local', + release: child_process.execSync('git rev-parse HEAD').toString().trim(), + }); + + await Sentry.continueTrace( + { + sentryTrace: process.env.SENTRY_MUT_SENTRY_TRACE || undefined, + baggage: process.env.SENTRY_MUT_BAGGAGE || undefined, + }, + async () => { + await Sentry.startSpan({ name: packageName, op: 'mutation' }, async () => { + const config = await Sentry.startSpan({ name: 'import stryker config', op: 'import' }, async () => { + const mod = (await import(configFile)) as { default: Partial }; + return mod.default; + }); + + const stryker = new Stryker(config); + const mutantResults = await Sentry.startSpan({ name: 'run mutation test', op: 'stryker' }, async () => + stryker.runMutationTest(), + ); + + Sentry.startSpan({ name: 'report results', op: 'sentry' }, () => { + const aggregatedResult = getMutationTestResultAggregation(mutantResults); + Sentry.setTag('mutation.score', aggregatedResult.score); + Sentry.setTag('mutation.package', packageName); + Sentry.setMeasurement('mutation.score', aggregatedResult.score, 'ratio'); + Sentry.setMeasurement('mutation.score_covered', aggregatedResult.scoreCovered, 'ratio'); + }); + }); + }, + ); +} diff --git a/nx.json b/nx.json index ae9751e774ef..34531904cd47 100644 --- a/nx.json +++ b/nx.json @@ -3,7 +3,7 @@ "default": { "runner": "nx/tasks-runners/default", "options": { - "cacheableOperations": ["build:bundle", "build:transpile", "build:types", "lint", "test:unit", "build:tarball", "test:mutation"], + "cacheableOperations": ["build:bundle", "build:transpile", "build:types", "lint", "test:unit", "build:tarball"], "cacheDirectory": ".nxcache" } } diff --git a/package.json b/package.json index 32066979c1a7..3e5744c306b5 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "test:ci:browser": "UNIT_TEST_ENV=browser ts-node ./scripts/ci-unit-tests.ts", "test:ci:node": "UNIT_TEST_ENV=node ts-node ./scripts/ci-unit-tests.ts", "test:ci:bun": "lerna run test --scope @sentry/bun", - "test:mutation": "lerna run --stream --concurrency=2 test:mutation && ts-node ./scripts/stryker-results.ts", + "test:mutation": "lerna run --stream --concurrency=auto test:mutation && ts-node ./scripts/stryker-collect-results.ts", "yalc:publish": "lerna run yalc:publish" }, "volta": { diff --git a/packages/browser/package.json b/packages/browser/package.json index 548ffe65ffb1..b5edfdef75af 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -75,7 +75,7 @@ "size:check": "cat build/bundles/bundle.min.js | gzip -9 | wc -c | awk '{$1=$1/1024; print \"ES2017: \",$1,\"kB\";}'", "test": "vitest run", "test:watch": "vitest --watch", - "test:mutation": "stryker-runner", + "test:mutation": "node ./../../scripts/stryker/run-with-sentry.mjs", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/core/package.json b/packages/core/package.json index 5cfefa457bf7..d5c2a424c5d5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -64,7 +64,7 @@ "lint": "eslint . --format stylish", "test": "vitest run", "test:watch": "vitest --watch", - "test:mutation": "stryker-runner", + "test:mutation": "node ./../../scripts/stryker/run-with-sentry.mjs", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/node/package.json b/packages/node/package.json index 8ad9859b832e..c8a61ca9c1da 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -122,7 +122,7 @@ "test": "yarn test:jest", "test:jest": "jest", "test:watch": "jest --watch", - "test:mutation": "stryker-runner", + "test:mutation": "node ./../../scripts/stryker/run-with-sentry.mjs", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 6f6eb35de415..69f3ccf386e9 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -72,7 +72,7 @@ "lint": "eslint . --format stylish", "test": "vitest run", "test:watch": "vitest --watch", - "test:mutation": "stryker-runner", + "test:mutation": "node ./../../scripts/stryker/run-with-sentry.mjs", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/sveltekit/package.json b/packages/sveltekit/package.json index 550d28612d57..66feca997f3e 100644 --- a/packages/sveltekit/package.json +++ b/packages/sveltekit/package.json @@ -75,7 +75,7 @@ "test": "yarn test:unit", "test:unit": "vitest run", "test:watch": "vitest --watch", - "test:mutation": "stryker-runner", + "test:mutation": "node ./../../scripts/stryker/run-with-sentry.mjs", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/utils/package.json b/packages/utils/package.json index e51f17267af0..03a1a01b43b5 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -64,7 +64,7 @@ "lint": "eslint . --format stylish", "test": "jest", "test:watch": "jest --watch", - "test:mutation": "stryker-runner", + "test:mutation": "node ./../../scripts/stryker/run-with-sentry.mjs", "version": "node ../../scripts/versionbump.js src/version.ts", "yalc:publish": "yalc publish --push --sig" }, diff --git a/scripts/stryker-results.ts b/scripts/stryker-collect-results.ts similarity index 100% rename from scripts/stryker-results.ts rename to scripts/stryker-collect-results.ts diff --git a/scripts/stryker/package.json b/scripts/stryker/package.json new file mode 100644 index 000000000000..3dbc1ca591c0 --- /dev/null +++ b/scripts/stryker/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/scripts/stryker/run-with-sentry.mjs b/scripts/stryker/run-with-sentry.mjs new file mode 100644 index 000000000000..e0ea65da9d4e --- /dev/null +++ b/scripts/stryker/run-with-sentry.mjs @@ -0,0 +1,83 @@ +import * as child_process from 'node:child_process'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +import * as Sentry from '@sentry/node'; +import { Stryker } from '@stryker-mutator/core'; + +const configFile = path.join(process.cwd(), '/stryker.config.mjs'); +const pkgJson = path.join(process.cwd(), 'package.json'); + +const packageName = JSON.parse(fs.readFileSync(pkgJson).toString()).name; + +Sentry.init({ + dsn: 'https://cdae3f96df86224530838d318d268f62@o447951.ingest.us.sentry.io/4507814527303680', + tracesSampleRate: 1.0, + defaultIntegrations: false, + + environment: process.env.CI ? 'ci' : 'local', + release: child_process.execSync('git rev-parse HEAD').toString().trim(), + + debug: true, +}); + +async function main() { + await Sentry.continueTrace( + { + sentryTrace: process.env.SENTRY_MUT_SENTRY_TRACE || undefined, + baggage: process.env.SENTRY_MUT_BAGGAGE || undefined, + }, + () => + Sentry.startSpan({ name: packageName, op: 'mutation' }, async () => { + const config = await Sentry.startSpan({ name: 'import stryker config', op: 'import' }, async () => { + const mod = await import(configFile); + return mod.default; + }); + + // Runs Stryker, will not assume to be allowed to exit the process. + const stryker = new Stryker(config); + const mutantResults = await Sentry.startSpan({ name: 'run mutation test', op: 'stryker' }, async () => + stryker.runMutationTest(), + ); + + Sentry.startSpan({ name: 'report results', op: 'sentry' }, () => { + const aggregatedResult = getMutationTestResultAggregation(mutantResults); + Sentry.setTag('mutation.score', aggregatedResult.score); + Sentry.setTag('mutation.package', packageName); + Sentry.setMeasurement('mutation.score', aggregatedResult.score, 'ratio'); + Sentry.setMeasurement('mutation.score_covered', aggregatedResult.scoreCovered, 'ratio'); + }); + }), + ); +} + +main().catch(console.error); + +function getMutationTestResultAggregation(mutantResults) { + const total = mutantResults.length; + + const noCoverage = mutantResults.filter(mutant => mutant.status === 'NoCoverage').length; + const killed = mutantResults.filter(mutant => mutant.status === 'Killed').length; + const survived = mutantResults.filter(mutant => mutant.status === 'Survived').length; + const error = mutantResults.filter( + mutant => mutant.status === 'RuntimeError' || mutant.status === 'CompileError', + ).length; + const ignored = mutantResults.filter(mutant => mutant.status === 'Ignored').length; + const timeout = mutantResults.filter(mutant => mutant.status === 'Timeout').length; + + const detected = killed + timeout; + + return { + score: Math.round((detected / (total - ignored) + Number.EPSILON) * 100) / 100, + scoreCovered: Math.round((detected / (total - ignored - noCoverage) + Number.EPSILON) * 100) / 100, + detected, + undetected: survived + noCoverage, + killed, + survived, + noCoverage, + ignored, + error, + timeout, + total, + }; +} diff --git a/scripts/stryker-start-trace.ts b/scripts/stryker/start-trace.mjs similarity index 100% rename from scripts/stryker-start-trace.ts rename to scripts/stryker/start-trace.mjs From f1a5fd3c55be5116c80e30781af190037b45d269 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 10:23:46 +0200 Subject: [PATCH 31/53] fix scripts --- .github/workflows/mutation.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index df4a19d4300b..99a8f12ac787 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -122,7 +122,7 @@ jobs: - name: Generate Sentry Trace id: sentry_trace run: | - yarn ts-node ./scripts/stryker/start-trace.ts + node ./scripts/stryker/start-trace.mjs - name: Test 1 @@ -138,7 +138,7 @@ jobs: baggage: '${{ env.SENTRY_MUT_BAGGAGE }}' job_mutation_test: - name: Run (${{ matrix.package }}) Mutation Testing + name: Mutation Test (${{ matrix.package }}) needs: [job_get_metadata, job_build] timeout-minutes: 180 runs-on: ubuntu-20.04 From 470807cfbfebad7e841743e65a4186f27bbaf1d0 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 10:34:18 +0200 Subject: [PATCH 32/53] remove runner from ci --- dev-packages/stryker-runner/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/dev-packages/stryker-runner/package.json b/dev-packages/stryker-runner/package.json index dc620f0f32c6..229f8f801677 100644 --- a/dev-packages/stryker-runner/package.json +++ b/dev-packages/stryker-runner/package.json @@ -25,7 +25,6 @@ }, "scripts": { "build": "tsc", - "build:transpile": "tsc", "build:watch": "tsc --watch", "start": "node ./build/esm/run.js" }, From 079780c8a696f80dc984eccf4070e9844a6f46af Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 11:02:33 +0200 Subject: [PATCH 33/53] debug missing traceid --- .github/workflows/mutation.yml | 15 ++++----------- scripts/stryker/run-with-sentry.mjs | 13 +++++++++++++ scripts/stryker/start-trace.mjs | 4 ++++ 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 99a8f12ac787..372c5786bb93 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -123,14 +123,8 @@ jobs: id: sentry_trace run: | node ./scripts/stryker/start-trace.mjs - - - - name: Test 1 - run: | - ls -la node_modules/.bin - ls -la packages/core/node_modules/.bin - ls -la packages/svelte/node_modules/.bin - ls -la packages/browser/node_modules/.bin + echo '${{ env.SENTRY_MUT_SENTRY_TRACE }}' + echo '${{ env.SENTRY_MUT_BAGGAGE }}' outputs: dependency_cache_key: ${{ steps.install_dependencies.outputs.cache_key }} @@ -157,10 +151,12 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ env.HEAD_COMMIT }} + - name: Set up Node uses: actions/setup-node@v4 with: node-version-file: 'package.json' + - name: Restore caches uses: ./.github/actions/restore-cache env: @@ -174,9 +170,6 @@ jobs: restore-keys: ${{ env.NX_CACHE_RESTORE_KEYS || 'nx-never-restore'}} - - name: Run yarn again - run: yarn - - name: Set trace propagation data run: | echo "SENTRY_MUT_SENTRY_TRACE=${{ needs.job_build.outputs.sentry_trace }}" >> $GITHUB_ENV diff --git a/scripts/stryker/run-with-sentry.mjs b/scripts/stryker/run-with-sentry.mjs index e0ea65da9d4e..f860f96bfc20 100644 --- a/scripts/stryker/run-with-sentry.mjs +++ b/scripts/stryker/run-with-sentry.mjs @@ -22,6 +22,10 @@ Sentry.init({ }); async function main() { + console.log('Continuing Trace from env variables:'); + console.log(`- sentry-trace: ${process.env.SENTRY_MUT_SENTRY_TRACE}`); + console.log(`- baggage: ${process.env.SENTRY_MUT_BAGGAGE}`); + await Sentry.continueTrace( { sentryTrace: process.env.SENTRY_MUT_SENTRY_TRACE || undefined, @@ -46,6 +50,15 @@ async function main() { Sentry.setTag('mutation.package', packageName); Sentry.setMeasurement('mutation.score', aggregatedResult.score, 'ratio'); Sentry.setMeasurement('mutation.score_covered', aggregatedResult.scoreCovered, 'ratio'); + Sentry.setMeasurement('mutation.total', aggregatedResult.total, 'number'); + Sentry.setMeasurement('mutation.detected', aggregatedResult.detected, 'number'); + Sentry.setMeasurement('mutation.undetected', aggregatedResult.undetected, 'number'); + Sentry.setMeasurement('mutation.killed', aggregatedResult.killed, 'number'); + Sentry.setMeasurement('mutation.survived', aggregatedResult.survived, 'number'); + Sentry.setMeasurement('mutation.no_coverage', aggregatedResult.noCoverage, 'number'); + Sentry.setMeasurement('mutation.ignored', aggregatedResult.ignored, 'number'); + Sentry.setMeasurement('mutation.error', aggregatedResult.error, 'number'); + Sentry.setMeasurement('mutation.timeout', aggregatedResult.timeout, 'number'); }); }), ); diff --git a/scripts/stryker/start-trace.mjs b/scripts/stryker/start-trace.mjs index cd32fcac5e7d..3c209d49b802 100644 --- a/scripts/stryker/start-trace.mjs +++ b/scripts/stryker/start-trace.mjs @@ -10,6 +10,10 @@ const baggage = `sentry-trace_id=${sentryTrace}`; process.env.SENTRY_MUT_SENTRY_TRACE = sentryTrace; process.env.SENTRY_MUT_BAGGAGE = baggage; +console.log('Starting Trace with:'); +console.log(`- sentry-trace: ${sentryTrace}`); +console.log(`- baggage: ${baggage}`); + export default { sentryTrace, baggage, From 1b0ef5db5233a70a7d59e7c922ba04f090d9b86a Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 11:06:52 +0200 Subject: [PATCH 34/53] fix baggage --- scripts/stryker/start-trace.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/stryker/start-trace.mjs b/scripts/stryker/start-trace.mjs index 3c209d49b802..12cb1ed7ec99 100644 --- a/scripts/stryker/start-trace.mjs +++ b/scripts/stryker/start-trace.mjs @@ -5,7 +5,7 @@ const traceId = randomUUID().replace(/-/g, ''); const spanId = randomUUID().replace(/-/g, '').slice(0, 16); const sentryTrace = `${traceId}-${spanId}-1`; -const baggage = `sentry-trace_id=${sentryTrace}`; +const baggage = `sentry-trace_id=${trace_id}`; process.env.SENTRY_MUT_SENTRY_TRACE = sentryTrace; process.env.SENTRY_MUT_BAGGAGE = baggage; From 40008fb7ac9fde9ff30be72548b9c95c76f0f135 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 11:15:13 +0200 Subject: [PATCH 35/53] fix job outputs for sentry_trace and baggage --- .github/workflows/mutation.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 372c5786bb93..ae7611593d4e 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -120,16 +120,16 @@ jobs: run: yarn build - name: Generate Sentry Trace - id: sentry_trace + id: step_sentry_trace run: | node ./scripts/stryker/start-trace.mjs - echo '${{ env.SENTRY_MUT_SENTRY_TRACE }}' - echo '${{ env.SENTRY_MUT_BAGGAGE }}' + echo 'sentry_trace=${{ env.SENTRY_MUT_SENTRY_TRACE }}' >> $GITHUB_OUTPUT + echo 'baggage=${{ env.SENTRY_MUT_BAGGAGE }}' >> $GITHUB_OUTPUT outputs: dependency_cache_key: ${{ steps.install_dependencies.outputs.cache_key }} - sentry_trace: '${{ env.SENTRY_MUT_SENTRY_TRACE }}' - baggage: '${{ env.SENTRY_MUT_BAGGAGE }}' + sentry_trace: ${{ steps.step_sentry_trace.outputs.sentry_trace }} + baggage: ${{ steps.step_sentry_trace.outputs.baggage }} job_mutation_test: name: Mutation Test (${{ matrix.package }}) From 30eed17df38ac90ea63c36e3a69f649ba682d928 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 11:19:43 +0200 Subject: [PATCH 36/53] dumb mistake --- scripts/stryker/start-trace.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/stryker/start-trace.mjs b/scripts/stryker/start-trace.mjs index 12cb1ed7ec99..2152ae9dc36f 100644 --- a/scripts/stryker/start-trace.mjs +++ b/scripts/stryker/start-trace.mjs @@ -5,7 +5,7 @@ const traceId = randomUUID().replace(/-/g, ''); const spanId = randomUUID().replace(/-/g, '').slice(0, 16); const sentryTrace = `${traceId}-${spanId}-1`; -const baggage = `sentry-trace_id=${trace_id}`; +const baggage = `sentry-trace_id=${traceId}`; process.env.SENTRY_MUT_SENTRY_TRACE = sentryTrace; process.env.SENTRY_MUT_BAGGAGE = baggage; From 4fd16951035f675048e2e49c1f9022f4226f85db Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 11:35:01 +0200 Subject: [PATCH 37/53] y u no work :( --- .github/workflows/mutation.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index ae7611593d4e..5a244524b851 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -123,6 +123,8 @@ jobs: id: step_sentry_trace run: | node ./scripts/stryker/start-trace.mjs + echo 'sentry_trace=${{ env.SENTRY_MUT_SENTRY_TRACE }}' + echo 'baggage=${{ env.SENTRY_MUT_BAGGAGE }}' echo 'sentry_trace=${{ env.SENTRY_MUT_SENTRY_TRACE }}' >> $GITHUB_OUTPUT echo 'baggage=${{ env.SENTRY_MUT_BAGGAGE }}' >> $GITHUB_OUTPUT From b6ed71467558c9d7779df7fed9551a72f11eacc0 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 11:50:19 +0200 Subject: [PATCH 38/53] write to github output in node script --- .github/workflows/mutation.yml | 5 +---- scripts/stryker/start-trace.mjs | 3 +++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 5a244524b851..ec44fbfad1ac 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -123,10 +123,7 @@ jobs: id: step_sentry_trace run: | node ./scripts/stryker/start-trace.mjs - echo 'sentry_trace=${{ env.SENTRY_MUT_SENTRY_TRACE }}' - echo 'baggage=${{ env.SENTRY_MUT_BAGGAGE }}' - echo 'sentry_trace=${{ env.SENTRY_MUT_SENTRY_TRACE }}' >> $GITHUB_OUTPUT - echo 'baggage=${{ env.SENTRY_MUT_BAGGAGE }}' >> $GITHUB_OUTPUT + echo output=${{ env.GITHUB_OUTPUT }} outputs: dependency_cache_key: ${{ steps.install_dependencies.outputs.cache_key }} diff --git a/scripts/stryker/start-trace.mjs b/scripts/stryker/start-trace.mjs index 2152ae9dc36f..1ca197f522bf 100644 --- a/scripts/stryker/start-trace.mjs +++ b/scripts/stryker/start-trace.mjs @@ -10,6 +10,9 @@ const baggage = `sentry-trace_id=${traceId}`; process.env.SENTRY_MUT_SENTRY_TRACE = sentryTrace; process.env.SENTRY_MUT_BAGGAGE = baggage; +fs.appendFileSync(process.env.GITHUB_OUTPUT, `sentry_trace=${sentryTrace}\n`); +fs.appendFileSync(process.env.GITHUB_OUTPUT, `baggage=${baggage}\n`); + console.log('Starting Trace with:'); console.log(`- sentry-trace: ${sentryTrace}`); console.log(`- baggage: ${baggage}`); From fe21686b2de9baefc09845d491fe24820425892d Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 11:55:13 +0200 Subject: [PATCH 39/53] fs import --- scripts/stryker/start-trace.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/stryker/start-trace.mjs b/scripts/stryker/start-trace.mjs index 1ca197f522bf..1fde0161db54 100644 --- a/scripts/stryker/start-trace.mjs +++ b/scripts/stryker/start-trace.mjs @@ -1,5 +1,6 @@ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access import { randomUUID } from 'node:crypto'; +import * as fs from 'node:fs'; const traceId = randomUUID().replace(/-/g, ''); const spanId = randomUUID().replace(/-/g, '').slice(0, 16); From 22a0ea98f439b3e5ea0c82769c1bc064a09d7a56 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 12:08:23 +0200 Subject: [PATCH 40/53] units and flush --- scripts/stryker/run-with-sentry.mjs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/scripts/stryker/run-with-sentry.mjs b/scripts/stryker/run-with-sentry.mjs index f860f96bfc20..91122e365d1d 100644 --- a/scripts/stryker/run-with-sentry.mjs +++ b/scripts/stryker/run-with-sentry.mjs @@ -50,18 +50,20 @@ async function main() { Sentry.setTag('mutation.package', packageName); Sentry.setMeasurement('mutation.score', aggregatedResult.score, 'ratio'); Sentry.setMeasurement('mutation.score_covered', aggregatedResult.scoreCovered, 'ratio'); - Sentry.setMeasurement('mutation.total', aggregatedResult.total, 'number'); - Sentry.setMeasurement('mutation.detected', aggregatedResult.detected, 'number'); - Sentry.setMeasurement('mutation.undetected', aggregatedResult.undetected, 'number'); - Sentry.setMeasurement('mutation.killed', aggregatedResult.killed, 'number'); - Sentry.setMeasurement('mutation.survived', aggregatedResult.survived, 'number'); - Sentry.setMeasurement('mutation.no_coverage', aggregatedResult.noCoverage, 'number'); - Sentry.setMeasurement('mutation.ignored', aggregatedResult.ignored, 'number'); - Sentry.setMeasurement('mutation.error', aggregatedResult.error, 'number'); - Sentry.setMeasurement('mutation.timeout', aggregatedResult.timeout, 'number'); + Sentry.setMeasurement('mutation.total', aggregatedResult.total, 'none'); + Sentry.setMeasurement('mutation.detected', aggregatedResult.detected, 'none'); + Sentry.setMeasurement('mutation.undetected', aggregatedResult.undetected, 'none'); + Sentry.setMeasurement('mutation.killed', aggregatedResult.killed, 'none'); + Sentry.setMeasurement('mutation.survived', aggregatedResult.survived, 'none'); + Sentry.setMeasurement('mutation.no_coverage', aggregatedResult.noCoverage, 'none'); + Sentry.setMeasurement('mutation.ignored', aggregatedResult.ignored, 'none'); + Sentry.setMeasurement('mutation.error', aggregatedResult.error, 'none'); + Sentry.setMeasurement('mutation.timeout', aggregatedResult.timeout, 'none'); }); }), ); + + await Sentry.flush(5000); } main().catch(console.error); From b7935c693f752c18aa0bd4926371049fbf44c6bc Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 12:16:35 +0200 Subject: [PATCH 41/53] disable dashboard for now --- dev-packages/stryker-config/src/stryker.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-packages/stryker-config/src/stryker.config.mjs b/dev-packages/stryker-config/src/stryker.config.mjs index cc6ee1e42794..86f4241afa4c 100644 --- a/dev-packages/stryker-config/src/stryker.config.mjs +++ b/dev-packages/stryker-config/src/stryker.config.mjs @@ -5,7 +5,7 @@ import child_process from 'child_process'; /** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ const config = { packageManager: 'yarn', - reporters: ['html', 'clear-text', 'progress', 'json', 'dashboard'], + reporters: ['html', 'clear-text', 'progress', 'json'], testRunner: 'vitest', coverageAnalysis: 'perTest', ignoreStatic: true, From c942f0bfa15c1ee3b7b0b4784be9e63c11e37322 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 12:29:58 +0200 Subject: [PATCH 42/53] add utils --- .github/workflows/mutation.yml | 1 + packages/utils/jest.config.js | 2 +- packages/utils/stryker.config.mjs | 13 +++++++++++++ packages/utils/test/normalize.test.ts | 2 +- packages/utils/test/object.test.ts | 2 +- 5 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 packages/utils/stryker.config.mjs diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index ec44fbfad1ac..8a26d9d79567 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -144,6 +144,7 @@ jobs: '@sentry/node', '@sentry/svelte', '@sentry/sveltekit', + '@sentry/utils' ] steps: - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) diff --git a/packages/utils/jest.config.js b/packages/utils/jest.config.js index f9b7ccfa4502..83ed2b35951c 100644 --- a/packages/utils/jest.config.js +++ b/packages/utils/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('../../jest/jest.config.js'); +const baseConfig = require('@sentry-internal/jest-config'); module.exports = { ...baseConfig, diff --git a/packages/utils/stryker.config.mjs b/packages/utils/stryker.config.mjs new file mode 100644 index 000000000000..6d20e2af5b9e --- /dev/null +++ b/packages/utils/stryker.config.mjs @@ -0,0 +1,13 @@ +import baseConfig from '@sentry-internal/stryker-config/config'; + +/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ +const config = { + ...baseConfig, + testRunner: 'jest', + dashboard: { + ...baseConfig.dashboard, + module: '@sentry/utils', + }, +}; + +export default config; diff --git a/packages/utils/test/normalize.test.ts b/packages/utils/test/normalize.test.ts index 5a2414d52e43..c313553031ad 100644 --- a/packages/utils/test/normalize.test.ts +++ b/packages/utils/test/normalize.test.ts @@ -1,5 +1,5 @@ /** - * @jest-environment jsdom + * @jest-environment @stryker-mutator/jest-runner/jest-env/jsdom */ import * as isModule from '../src/is'; diff --git a/packages/utils/test/object.test.ts b/packages/utils/test/object.test.ts index 2ba5a6c58fa3..8dd036cc4e2f 100644 --- a/packages/utils/test/object.test.ts +++ b/packages/utils/test/object.test.ts @@ -1,5 +1,5 @@ /** - * @jest-environment jsdom + * @jest-environment @stryker-mutator/jest-runner/jest-env/jsdom */ import type { WrappedFunction } from '@sentry/types'; From d9e6ec417d9a9de4548eec8e702ec6bba0117d33 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 12:36:01 +0200 Subject: [PATCH 43/53] fix report upload name --- .github/workflows/mutation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 8a26d9d79567..071137d151b2 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -190,7 +190,7 @@ jobs: - name: Upload Results uses: actions/upload-artifact@v4 with: - name: ${{ matrix.package }} reports + name: test-reports path: | ${{ github.workspace }}/packages/**/mutation.json ${{ github.workspace }}/packages/**/mutation.html From 7ed9b1d13d86f189ce237209f4b2e243efdb1d20 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 15:10:04 +0200 Subject: [PATCH 44/53] matrix change --- .github/workflows/mutation.yml | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 071137d151b2..f4a74502d8d9 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -139,12 +139,12 @@ jobs: fail-fast: false matrix: package: [ - '@sentry/core', - '@sentry/browser', - '@sentry/node', - '@sentry/svelte', - '@sentry/sveltekit', - '@sentry/utils' + 'core', + 'browser', + 'node', + 'svelte', + 'sveltekit', + 'utils' ] steps: - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) @@ -175,22 +175,15 @@ jobs: echo "SENTRY_MUT_SENTRY_TRACE=${{ needs.job_build.outputs.sentry_trace }}" >> $GITHUB_ENV echo "SENTRY_MUT_BAGGAGE=${{ needs.job_build.outputs.baggage }}" >> $GITHUB_ENV - - name: Test 2 - run: | - ls -la node_modules/.bin - ls -la packages/core/node_modules/.bin - ls -la packages/svelte/node_modules/.bin - ls -la packages/browser/node_modules/.bin - - name: Run mutation test - run: yarn nx run ${{ matrix.package }}:test:mutation + run: yarn nx run @sentry/${{ matrix.package }}:test:mutation env: NODE_VERSION: ${{ matrix.node }} - name: Upload Results uses: actions/upload-artifact@v4 with: - name: test-reports + name: test-reports ${{ matrix.package }} path: | ${{ github.workspace }}/packages/**/mutation.json ${{ github.workspace }}/packages/**/mutation.html From f4d74b5d149df91b1929ed3240957cc618d0c415 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 15:14:15 +0200 Subject: [PATCH 45/53] add angular --- .github/workflows/mutation.yml | 1 + packages/angular/package.json | 3 ++- packages/angular/vitest.config.ts | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index f4a74502d8d9..697379d740ac 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -139,6 +139,7 @@ jobs: fail-fast: false matrix: package: [ + 'angular', 'core', 'browser', 'node', diff --git a/packages/angular/package.json b/packages/angular/package.json index a6c6bb06ef94..16fbd55a2137 100644 --- a/packages/angular/package.json +++ b/packages/angular/package.json @@ -57,7 +57,8 @@ "test": "yarn test:unit", "test:unit": "vitest run", "test:unit:watch": "vitest --watch", - "yalc:publish": "yalc publish --push --sig" + "yalc:publish": "yalc publish --push --sig", + "test:mutation": "node ./../../scripts/stryker/run-with-sentry.mjs" }, "volta": { "extends": "../../package.json" diff --git a/packages/angular/vitest.config.ts b/packages/angular/vitest.config.ts index 9f09af3b153e..dcdf1d7f1f98 100644 --- a/packages/angular/vitest.config.ts +++ b/packages/angular/vitest.config.ts @@ -1,6 +1,6 @@ +import baseConfig from '@sentry-internal/vitest-config'; import type { UserConfig } from 'vitest'; import { defineConfig } from 'vitest/config'; -import baseConfig from '../../vite/vite.config'; export default defineConfig({ test: { From 264f8a18847749ed6852678f4ae4cdefdcdea7d9 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 15:33:46 +0200 Subject: [PATCH 46/53] add astro --- .github/workflows/mutation.yml | 1 + packages/astro/package.json | 1 + packages/astro/vite.config.ts | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 697379d740ac..a1c9b9504b30 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -140,6 +140,7 @@ jobs: matrix: package: [ 'angular', + 'astro', 'core', 'browser', 'node', diff --git a/packages/astro/package.json b/packages/astro/package.json index b5fd94e25d3a..d2668ed7a2f6 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -84,6 +84,7 @@ "test": "yarn test:unit", "test:unit": "vitest run", "test:watch": "vitest --watch", + "test:mutation": "node ./../../scripts/stryker/run-with-sentry.mjs", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/astro/vite.config.ts b/packages/astro/vite.config.ts index f18ec92095bc..2b6ccf9389bd 100644 --- a/packages/astro/vite.config.ts +++ b/packages/astro/vite.config.ts @@ -1,4 +1,4 @@ -import baseConfig from '../../vite/vite.config'; +import baseConfig from '@sentry-internal/vitest-config'; export default { ...baseConfig, From 3d2860c0a7f58b888bd1f7ce75abf82982d4925e Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 15:43:57 +0200 Subject: [PATCH 47/53] aws-serverless --- .github/workflows/mutation.yml | 1 + packages/angular/stryker.config.mjs | 12 ++++++++++++ packages/astro/stryker.config.mjs | 12 ++++++++++++ packages/aws-serverless/jest.config.js | 2 +- packages/aws-serverless/package.json | 1 + packages/aws-serverless/stryker.config.mjs | 13 +++++++++++++ 6 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 packages/angular/stryker.config.mjs create mode 100644 packages/astro/stryker.config.mjs create mode 100644 packages/aws-serverless/stryker.config.mjs diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index a1c9b9504b30..99d2963e6e7f 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -141,6 +141,7 @@ jobs: package: [ 'angular', 'astro', + 'aws-serverless', 'core', 'browser', 'node', diff --git a/packages/angular/stryker.config.mjs b/packages/angular/stryker.config.mjs new file mode 100644 index 000000000000..ca96c0d4d9a3 --- /dev/null +++ b/packages/angular/stryker.config.mjs @@ -0,0 +1,12 @@ +import baseConfig from '@sentry-internal/stryker-config/config'; + +/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ +const config = { + ...baseConfig, + dashboard: { + ...baseConfig.dashboard, + module: '@sentry/angular', + }, +}; + +export default config; diff --git a/packages/astro/stryker.config.mjs b/packages/astro/stryker.config.mjs new file mode 100644 index 000000000000..64b2ed66fd72 --- /dev/null +++ b/packages/astro/stryker.config.mjs @@ -0,0 +1,12 @@ +import baseConfig from '@sentry-internal/stryker-config/config'; + +/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ +const config = { + ...baseConfig, + dashboard: { + ...baseConfig.dashboard, + module: '@sentry/astro', + }, +}; + +export default config; diff --git a/packages/aws-serverless/jest.config.js b/packages/aws-serverless/jest.config.js index 24f49ab59a4c..8cdf86519208 100644 --- a/packages/aws-serverless/jest.config.js +++ b/packages/aws-serverless/jest.config.js @@ -1 +1 @@ -module.exports = require('../../jest/jest.config.js'); +module.exports = require('@sentry-internal/jest-config'); diff --git a/packages/aws-serverless/package.json b/packages/aws-serverless/package.json index 881976a8db34..16a981238024 100644 --- a/packages/aws-serverless/package.json +++ b/packages/aws-serverless/package.json @@ -94,6 +94,7 @@ "fix": "eslint . --format stylish --fix", "lint": "eslint . --format stylish", "test": "jest", + "test:mutation": "node ./../../scripts/stryker/run-with-sentry.mjs", "test:watch": "jest --watch", "yalc:publish": "yalc publish --push --sig" }, diff --git a/packages/aws-serverless/stryker.config.mjs b/packages/aws-serverless/stryker.config.mjs new file mode 100644 index 000000000000..5614a0e5671a --- /dev/null +++ b/packages/aws-serverless/stryker.config.mjs @@ -0,0 +1,13 @@ +import baseConfig from '@sentry-internal/stryker-config/config'; + +/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ +const config = { + ...baseConfig, + testRunner: 'jest', + dashboard: { + ...baseConfig.dashboard, + module: '@sentry/aws-serverless', + }, +}; + +export default config; From d7194d4c40b2e58eed282f1469dc7d7c2e2d2c75 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 15:45:46 +0200 Subject: [PATCH 48/53] formatting --- scripts/stryker-collect-results.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/stryker-collect-results.ts b/scripts/stryker-collect-results.ts index dd27b987096c..74306c61066f 100644 --- a/scripts/stryker-collect-results.ts +++ b/scripts/stryker-collect-results.ts @@ -66,6 +66,7 @@ function getMutationTestResults(): schema.MutationTestResult[] { function getMutationTestResultAggregation(mutationResults: schema.MutationTestResult): MutationTestResultAggregation { const total = Object.values(mutationResults.files).reduce((acc, file) => acc + file.mutants.length, 0); const allMutants = Object.values(mutationResults.files).reduce( + // biome-ignore lint/performance/noAccumulatingSpread: (acc, file) => [...acc, ...file.mutants], [] as schema.MutantResult[], ); From b1c00fea13cd6a53b0b0261cce8097a4ac32a198 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 15:56:24 +0200 Subject: [PATCH 49/53] add gatsby --- .github/workflows/mutation.yml | 3 ++- packages/gatsby/jest.config.js | 2 +- packages/gatsby/package.json | 1 + packages/gatsby/stryker.config.mjs | 13 +++++++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 packages/gatsby/stryker.config.mjs diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 99d2963e6e7f..914c2973fc43 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -142,8 +142,9 @@ jobs: 'angular', 'astro', 'aws-serverless', - 'core', 'browser', + 'core', + 'gatsby', 'node', 'svelte', 'sveltekit', diff --git a/packages/gatsby/jest.config.js b/packages/gatsby/jest.config.js index 3770aa5b0db2..c88fde2a2a62 100644 --- a/packages/gatsby/jest.config.js +++ b/packages/gatsby/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('../../jest/jest.config.js'); +const baseConfig = require('@sentry-internal/jest-config'); module.exports = { ...baseConfig, diff --git a/packages/gatsby/package.json b/packages/gatsby/package.json index 4bfd08a2dc80..2b761353566a 100644 --- a/packages/gatsby/package.json +++ b/packages/gatsby/package.json @@ -79,6 +79,7 @@ "lint": "eslint . --format stylish", "test": "yarn ts-node scripts/pretest.ts && yarn jest", "test:watch": "yarn ts-node scripts/pretest.ts && yarn jest --watch", + "test:mutation": "node ./../../scripts/stryker/run-with-sentry.mjs", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/gatsby/stryker.config.mjs b/packages/gatsby/stryker.config.mjs new file mode 100644 index 000000000000..7e4f908dd303 --- /dev/null +++ b/packages/gatsby/stryker.config.mjs @@ -0,0 +1,13 @@ +import baseConfig from '@sentry-internal/stryker-config/config'; + +/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ +const config = { + ...baseConfig, + testRunner: 'jest', + dashboard: { + ...baseConfig.dashboard, + module: '@sentry/gatsby', + }, +}; + +export default config; From 745238251b8d2ea10c09c9c3741780a9420b059b Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 16:06:43 +0200 Subject: [PATCH 50/53] add google-cloud-serverless --- .github/workflows/mutation.yml | 1 + packages/google-cloud-serverless/jest.config.js | 2 +- packages/google-cloud-serverless/package.json | 1 + packages/google-cloud-serverless/stryker.config.mjs | 13 +++++++++++++ 4 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 packages/google-cloud-serverless/stryker.config.mjs diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 914c2973fc43..f0140f1657a4 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -145,6 +145,7 @@ jobs: 'browser', 'core', 'gatsby', + 'google-cloud-serverless', 'node', 'svelte', 'sveltekit', diff --git a/packages/google-cloud-serverless/jest.config.js b/packages/google-cloud-serverless/jest.config.js index 24f49ab59a4c..8cdf86519208 100644 --- a/packages/google-cloud-serverless/jest.config.js +++ b/packages/google-cloud-serverless/jest.config.js @@ -1 +1 @@ -module.exports = require('../../jest/jest.config.js'); +module.exports = require('@sentry-internal/jest-config'); diff --git a/packages/google-cloud-serverless/package.json b/packages/google-cloud-serverless/package.json index d8bcc758752b..2d973b1769ba 100644 --- a/packages/google-cloud-serverless/package.json +++ b/packages/google-cloud-serverless/package.json @@ -81,6 +81,7 @@ "lint": "eslint . --format stylish", "test": "jest", "test:watch": "jest --watch", + "test:mutation": "node ./../../scripts/stryker/run-with-sentry.mjs", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/google-cloud-serverless/stryker.config.mjs b/packages/google-cloud-serverless/stryker.config.mjs new file mode 100644 index 000000000000..5b87279bc750 --- /dev/null +++ b/packages/google-cloud-serverless/stryker.config.mjs @@ -0,0 +1,13 @@ +import baseConfig from '@sentry-internal/stryker-config/config'; + +/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ +const config = { + ...baseConfig, + testRunner: 'jest', + dashboard: { + ...baseConfig.dashboard, + module: '@sentry/google-cloud-serverless', + }, +}; + +export default config; From 29c675b850d8a764aeea02cb3c29677625265698 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 23 Aug 2024 16:11:39 +0200 Subject: [PATCH 51/53] add nestjs --- packages/nestjs/package.json | 1 + packages/nestjs/stryker.config.mjs | 12 ++++++++++++ packages/nestjs/vite.config.ts | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 packages/nestjs/stryker.config.mjs diff --git a/packages/nestjs/package.json b/packages/nestjs/package.json index 902b89d11591..44ede8835de0 100644 --- a/packages/nestjs/package.json +++ b/packages/nestjs/package.json @@ -75,6 +75,7 @@ "lint": "eslint . --format stylish", "test": "vitest run", "test:watch": "vitest --watch", + "test:mutation": "node ./../../scripts/stryker/run-with-sentry.mjs", "yalc:publish": "yalc publish --push --sig" }, "volta": { diff --git a/packages/nestjs/stryker.config.mjs b/packages/nestjs/stryker.config.mjs new file mode 100644 index 000000000000..64b2ed66fd72 --- /dev/null +++ b/packages/nestjs/stryker.config.mjs @@ -0,0 +1,12 @@ +import baseConfig from '@sentry-internal/stryker-config/config'; + +/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ +const config = { + ...baseConfig, + dashboard: { + ...baseConfig.dashboard, + module: '@sentry/astro', + }, +}; + +export default config; diff --git a/packages/nestjs/vite.config.ts b/packages/nestjs/vite.config.ts index ff64487a9265..21c9ed50e171 100644 --- a/packages/nestjs/vite.config.ts +++ b/packages/nestjs/vite.config.ts @@ -1,5 +1,5 @@ +import baseConfig from '@sentry-internal/vitest-config'; import { defineConfig } from 'vitest/config'; -import baseConfig from '../../vite/vite.config'; export default defineConfig({ ...baseConfig, From 59f326abee7280d96294537d82777543ced095db Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 26 Aug 2024 13:45:25 +0200 Subject: [PATCH 52/53] add nextjs --- packages/nestjs/stryker.config.mjs | 2 +- packages/nextjs/jest.config.js | 2 +- packages/nextjs/package.json | 1 + packages/nextjs/stryker.config.mjs | 15 +++++++++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 packages/nextjs/stryker.config.mjs diff --git a/packages/nestjs/stryker.config.mjs b/packages/nestjs/stryker.config.mjs index 64b2ed66fd72..cc47e46823ef 100644 --- a/packages/nestjs/stryker.config.mjs +++ b/packages/nestjs/stryker.config.mjs @@ -5,7 +5,7 @@ const config = { ...baseConfig, dashboard: { ...baseConfig.dashboard, - module: '@sentry/astro', + module: '@sentry/nestjs', }, }; diff --git a/packages/nextjs/jest.config.js b/packages/nextjs/jest.config.js index fd23311e1656..fcb41de5d46b 100644 --- a/packages/nextjs/jest.config.js +++ b/packages/nextjs/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('../../jest/jest.config.js'); +const baseConfig = require('@sentry-internal/jest-config'); module.exports = { ...baseConfig, diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 466a98f8512f..54a8856f0d11 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -119,6 +119,7 @@ "test:unit": "jest", "test:types": "cd test/types && yarn test", "test:watch": "jest --watch", + "test:mutation": "node ./../../scripts/stryker/run-with-sentry.mjs", "vercel:branch": "source vercel/set-up-branch-for-test-app-use.sh", "vercel:project": "source vercel/make-project-use-current-branch.sh", "yalc:publish": "yalc publish --push --sig" diff --git a/packages/nextjs/stryker.config.mjs b/packages/nextjs/stryker.config.mjs new file mode 100644 index 000000000000..c92c975a9249 --- /dev/null +++ b/packages/nextjs/stryker.config.mjs @@ -0,0 +1,15 @@ +import baseConfig from '@sentry-internal/stryker-config/config'; + +/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */ +const config = { + ...baseConfig, + dashboard: { + ...baseConfig.dashboard, + module: '@sentry/nextjs', + }, + mutate: ['src/**/*.ts', '!src/config/templates/*.ts', 'src/**/*.tsx'], + testRunner: 'jest', + disableTypeChecks: true, +}; + +export default config; From f6a05b83144daf046878306aa9a946380ab56bef Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 26 Aug 2024 14:09:13 +0200 Subject: [PATCH 53/53] add nextjs run to ci --- .github/workflows/mutation.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index f0140f1657a4..7732578dfe1e 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -146,6 +146,7 @@ jobs: 'core', 'gatsby', 'google-cloud-serverless', + 'nextjs', 'node', 'svelte', 'sveltekit',