From 75a75af1b4e97f8cc4130fde9fe403572589ee2d Mon Sep 17 00:00:00 2001 From: feugy Date: Thu, 7 Nov 2024 11:35:10 +0100 Subject: [PATCH] feat: supports reloading beforeSend for next/react/remix$ --- packages/web/jest.setup.ts | 9 +- packages/web/package.json | 5 +- packages/web/src/generic.test.ts | 11 +- packages/web/src/react/index.test.tsx | 64 ++++++++++++ packages/web/src/react/index.tsx | 4 + packages/web/tsconfig.json | 2 +- pnpm-lock.yaml | 145 ++++++-------------------- 7 files changed, 121 insertions(+), 119 deletions(-) create mode 100644 packages/web/src/react/index.test.tsx diff --git a/packages/web/jest.setup.ts b/packages/web/jest.setup.ts index 28463d8..bc72741 100644 --- a/packages/web/jest.setup.ts +++ b/packages/web/jest.setup.ts @@ -1,8 +1,13 @@ +import { beforeEach } from '@jest/globals'; import '@testing-library/jest-dom'; +// Adds helpers like `.toHaveAttribute` +import '@testing-library/jest-dom/jest-globals'; beforeEach(() => { if ('document' in global) { - /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- there is an HTML element */ - document.querySelector('html')!.innerHTML = ''; + const html = document.querySelector('html'); + if (html) { + html.innerHTML = ''; + } } }); diff --git a/packages/web/package.json b/packages/web/package.json index 35a8f2c..fa418d2 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -94,9 +94,8 @@ "@sveltejs/kit": "^2.7", "@swc/core": "^1.3.103", "@swc/jest": "^0.2.29", - "@testing-library/jest-dom": "^6.2.0", - "@testing-library/react": "^14.1.2", - "@types/jest": "^29.5.11", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^16.0.1", "@types/node": "^20.11.4", "@types/react": "^18.2.48", "copyfiles": "^2.4.1", diff --git a/packages/web/src/generic.test.ts b/packages/web/src/generic.test.ts index 389a104..5f237a3 100644 --- a/packages/web/src/generic.test.ts +++ b/packages/web/src/generic.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from '@jest/globals'; -import { injectSpeedInsights } from './generic'; +import { injectSpeedInsights, type SpeedInsightsProps } from './generic'; describe('injectSpeedInsights()', () => { it('allows no parameters', () => { @@ -16,6 +16,15 @@ describe('injectSpeedInsights()', () => { }); expectInjectedScript({ framework }); }); + + it('can set beforeSend', () => { + const beforeSend: Required['beforeSend'] = (event) => + event; + injectSpeedInsights({ beforeSend }); + + expect(window.siq?.[0]).toEqual(['beforeSend', beforeSend]); + expect(window.siq).toHaveLength(1); + }); }); function expectInjectedScript({ diff --git a/packages/web/src/react/index.test.tsx b/packages/web/src/react/index.test.tsx new file mode 100644 index 0000000..fdcdcab --- /dev/null +++ b/packages/web/src/react/index.test.tsx @@ -0,0 +1,64 @@ +import * as React from 'react'; +import { afterEach, beforeEach, describe, it, expect } from '@jest/globals'; +import { cleanup, render } from '@testing-library/react'; +import type { SpeedInsightsProps } from '../types'; +import { SpeedInsights } from '.'; + +describe('', () => { + afterEach(() => { + cleanup(); + }); + + describe.each([ + { + mode: 'development', + file: 'https://va.vercel-scripts.com/v1/speed-insights/script.debug.js', + }, + { + mode: 'production', + file: 'http://localhost/_vercel/speed-insights/script.js', + }, + ])('in $mode mode', ({ mode, file }) => { + const env = process.env.NODE_ENV; + beforeEach(() => { + process.env.NODE_ENV = mode; + window.si = undefined; + window.siq = undefined; + }); + + afterEach(() => { + process.env.NODE_ENV = env; + }); + + it('adds the script tag correctly', () => { + render(); + + const scripts = document.getElementsByTagName('script'); + expect(scripts).toHaveLength(1); + + const script = document.head.querySelector('script'); + expect(script).toBeDefined(); + expect(script?.src).toEqual(file); + expect(script).toHaveAttribute('defer'); + }); + + it('sets and changes beforeSend', () => { + const beforeSend: Required['beforeSend'] = (event) => + event; + const beforeSend2: Required['beforeSend'] = (event) => + event; + const { rerender } = render(); + + expect(window.siq?.[0]).toEqual(['beforeSend', beforeSend]); + expect(window.siq).toHaveLength(1); + window.siq?.splice(0, 1); + + rerender(); + expect(window.siq).toHaveLength(0); + + rerender(); + expect(window.siq?.[0]).toEqual(['beforeSend', beforeSend2]); + expect(window.siq).toHaveLength(1); + }); + }); +}); diff --git a/packages/web/src/react/index.tsx b/packages/web/src/react/index.tsx index 4b9cb58..2200281 100644 --- a/packages/web/src/react/index.tsx +++ b/packages/web/src/react/index.tsx @@ -8,6 +8,10 @@ export function SpeedInsights( framework?: string; }, ): JSX.Element | null { + useEffect(() => { + window.si?.('beforeSend', props.beforeSend); + }, [props.beforeSend]); + const setScriptRoute = useRef<((path: string) => void) | null>(null); useEffect(() => { if (!setScriptRoute.current) { diff --git a/packages/web/tsconfig.json b/packages/web/tsconfig.json index 9936b82..6a4fe18 100644 --- a/packages/web/tsconfig.json +++ b/packages/web/tsconfig.json @@ -3,5 +3,5 @@ "compilerOptions": { "module": "esnext" }, - "include": ["src"] + "include": ["src", "./jest.setup.ts"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a655380..0037024 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -194,14 +194,11 @@ importers: specifier: ^0.2.29 version: 0.2.29(@swc/core@1.3.103) '@testing-library/jest-dom': - specifier: ^6.2.0 - version: 6.2.0(@jest/globals@29.7.0)(@types/jest@29.5.11)(jest@29.7.0) + specifier: ^6.6.3 + version: 6.6.3 '@testing-library/react': - specifier: ^14.1.2 - version: 14.1.2(react-dom@18.2.0)(react@18.2.0) - '@types/jest': - specifier: ^29.5.11 - version: 29.5.11 + specifier: ^16.0.1 + version: 16.0.1(@testing-library/dom@10.4.0)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) '@types/node': specifier: ^20.11.4 version: 20.11.4 @@ -246,8 +243,8 @@ packages: engines: {node: '>=0.10.0'} dev: true - /@adobe/css-tools@4.3.2: - resolution: {integrity: sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw==} + /@adobe/css-tools@4.4.0: + resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==} dev: true /@ampproject/remapping@2.2.1: @@ -764,13 +761,6 @@ packages: dependencies: '@babel/types': 7.25.8 - /@babel/parser@7.23.6: - resolution: {integrity: sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.25.8 - /@babel/parser@7.25.8: resolution: {integrity: sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==} engines: {node: '>=6.0.0'} @@ -1081,7 +1071,7 @@ packages: dependencies: '@babel/core': 7.23.3 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.22.15 + '@babel/helper-validator-option': 7.25.7 '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.23.3) '@babel/plugin-transform-modules-commonjs': 7.23.0(@babel/core@7.23.3) '@babel/plugin-transform-typescript': 7.23.4(@babel/core@7.23.3) @@ -2533,13 +2523,6 @@ packages: jest-mock: 29.7.0 dev: true - /@jest/expect-utils@29.6.4: - resolution: {integrity: sha512-FEhkJhqtvBwgSpiTrocquJCdXPsyvNKcl/n7A3u7X4pVoF4bswm11c9d4AV+kfq2Gpv/mM8x7E7DsRvH+djkrg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-get-type: 29.6.3 - dev: true - /@jest/expect-utils@29.7.0: resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4425,25 +4408,25 @@ packages: resolution: {integrity: sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==} dev: true - /@testing-library/dom@8.20.1: - resolution: {integrity: sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==} - engines: {node: '>=12'} + /@testing-library/dom@10.4.0: + resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} + engines: {node: '>=18'} dependencies: '@babel/code-frame': 7.25.7 '@babel/runtime': 7.22.15 '@types/aria-query': 5.0.1 - aria-query: 5.1.3 + aria-query: 5.3.0 chalk: 4.1.2 dom-accessibility-api: 0.5.16 lz-string: 1.5.0 pretty-format: 27.5.1 dev: true - /@testing-library/dom@9.3.1: - resolution: {integrity: sha512-0DGPd9AR3+iDTjGoMpxIkAsUihHZ3Ai6CneU6bRRrffXMgzCdlNk43jTrD2/5LT6CBb3MWTP8v510JzYtahD2w==} - engines: {node: '>=14'} + /@testing-library/dom@8.20.1: + resolution: {integrity: sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==} + engines: {node: '>=12'} dependencies: - '@babel/code-frame': 7.23.4 + '@babel/code-frame': 7.25.7 '@babel/runtime': 7.22.15 '@types/aria-query': 5.0.1 aria-query: 5.1.3 @@ -4453,47 +4436,37 @@ packages: pretty-format: 27.5.1 dev: true - /@testing-library/jest-dom@6.2.0(@jest/globals@29.7.0)(@types/jest@29.5.11)(jest@29.7.0): - resolution: {integrity: sha512-+BVQlJ9cmEn5RDMUS8c2+TU6giLvzaHZ8sU/x0Jj7fk+6/46wPdwlgOPcpxS17CjcanBi/3VmGMqVr2rmbUmNw==} + /@testing-library/jest-dom@6.6.3: + resolution: {integrity: sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==} engines: {node: '>=14', npm: '>=6', yarn: '>=1'} - peerDependencies: - '@jest/globals': '>= 28' - '@types/jest': '>= 28' - jest: '>= 28' - vitest: '>= 0.32' - peerDependenciesMeta: - '@jest/globals': - optional: true - '@types/jest': - optional: true - jest: - optional: true - vitest: - optional: true dependencies: - '@adobe/css-tools': 4.3.2 - '@babel/runtime': 7.22.15 - '@jest/globals': 29.7.0 - '@types/jest': 29.5.11 - aria-query: 5.3.0 + '@adobe/css-tools': 4.4.0 + aria-query: 5.3.2 chalk: 3.0.0 css.escape: 1.5.1 dom-accessibility-api: 0.6.3 - jest: 29.7.0(@types/node@20.11.4) lodash: 4.17.21 redent: 3.0.0 dev: true - /@testing-library/react@14.1.2(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-z4p7DVBTPjKM5qDZ0t5ZjzkpSNb+fZy1u6bzO7kk8oeGagpPCAtgh4cx1syrfp7a+QWkM021jGqjJaxJJnXAZg==} - engines: {node: '>=14'} + /@testing-library/react@16.0.1(@testing-library/dom@10.4.0)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==} + engines: {node: '>=18'} peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 + '@types/react-dom': ^18.0.0 react: ^18.0.0 react-dom: ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true dependencies: '@babel/runtime': 7.22.15 - '@testing-library/dom': 9.3.1 - '@types/react-dom': 18.2.18 + '@testing-library/dom': 10.4.0 + '@types/react': 18.2.48 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true @@ -4602,13 +4575,6 @@ packages: '@types/istanbul-lib-report': 3.0.0 dev: true - /@types/jest@29.5.11: - resolution: {integrity: sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ==} - dependencies: - expect: 29.6.4 - pretty-format: 29.6.3 - dev: true - /@types/jsdom@20.0.1: resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} dependencies: @@ -5361,7 +5327,7 @@ packages: /@vue/compiler-sfc@3.4.14: resolution: {integrity: sha512-1vHc9Kv1jV+YBZC/RJxQJ9JCxildTI+qrhtDh6tPkR1O8S+olBUekimY0km0ZNn8nG1wjtFAe9XHij+YLR8cRQ==} dependencies: - '@babel/parser': 7.23.6 + '@babel/parser': 7.25.8 '@vue/compiler-core': 3.4.14 '@vue/compiler-dom': 3.4.14 '@vue/compiler-ssr': 3.4.14 @@ -8453,17 +8419,6 @@ packages: dev: false optional: true - /expect@29.6.4: - resolution: {integrity: sha512-F2W2UyQ8XYyftHT57dtfg8Ue3X5qLgm2sSug0ivvLRH/VKNRL/pDxg/TH7zVzbQB0tu80clNFy6LU7OS/VSEKA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/expect-utils': 29.6.4 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.6.4 - jest-message-util: 29.6.3 - jest-util: 29.7.0 - dev: true - /expect@29.7.0: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -10193,16 +10148,6 @@ packages: pretty-format: 29.7.0 dev: true - /jest-matcher-utils@29.6.4: - resolution: {integrity: sha512-KSzwyzGvK4HcfnserYqJHYi7sZVqdREJ9DMPAKVbS98JsIAvumihaNUbjrWw0St7p9IY7A9UskCW5MYlGmBQFQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - dev: true - /jest-matcher-utils@29.7.0: resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -10213,21 +10158,6 @@ packages: pretty-format: 29.7.0 dev: true - /jest-message-util@29.6.3: - resolution: {integrity: sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/code-frame': 7.25.7 - '@jest/types': 29.6.3 - '@types/stack-utils': 2.0.1 - chalk: 4.1.2 - graceful-fs: 4.2.11 - micromatch: 4.0.5 - pretty-format: 29.7.0 - slash: 3.0.0 - stack-utils: 2.0.6 - dev: true - /jest-message-util@29.7.0: resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -13616,15 +13546,6 @@ packages: react-is: 17.0.2 dev: true - /pretty-format@29.6.3: - resolution: {integrity: sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.2.0 - dev: true - /pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}