diff --git a/dev-utils/test-config.js b/dev-utils/test-config.js
index 1c13d6d12..77fbfff78 100644
--- a/dev-utils/test-config.js
+++ b/dev-utils/test-config.js
@@ -156,6 +156,12 @@ function getBrowserList(pkg = 'default') {
let browsers = []
if (pkg === 'default') {
browsers = getDefaultBrowsers()
+ } else if (pkg === 'react') {
+ // react router 6 doesn't support IE 11, we get rid of it
+ // https://github.com/remix-run/react-router/issues/8220#issuecomment-961326123
+ return getDefaultBrowsers().filter(
+ browser => browser.browserName != 'internet explorer'
+ )
} else if (pkg === 'vue') {
// Vue 3 dropped support for IE 11 and older browsers,
// so we use modern browsers ro run the tests
diff --git a/package-lock.json b/package-lock.json
index ea78d7964..5a9400f40 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10689,6 +10689,12 @@
"integrity": "sha512-15spi3V28QdevleWBNXE4pIls3nFZmBbUGrW9IVPwiQczuSb9n76TCB4bsk8TSel+I1OkHEdPhu5QKMfY6rQHA==",
"dev": true
},
+ "@remix-run/router": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.2.tgz",
+ "integrity": "sha512-7Lcn7IqGMV+vizMPoEl5F0XDshcdDYtMI6uJLQdQz5CfZAwy3vvGKYSUk789qndt5dEC4HfSjviSYlSoHGL2+A==",
+ "dev": true
+ },
"@rollup/plugin-commonjs": {
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-19.0.0.tgz",
@@ -22160,29 +22166,6 @@
"tslib": "^2.0.3"
}
},
- "history": {
- "version": "4.10.1",
- "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
- "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.1.2",
- "loose-envify": "^1.2.0",
- "resolve-pathname": "^3.0.0",
- "tiny-invariant": "^1.0.2",
- "tiny-warning": "^1.0.0",
- "value-equal": "^1.0.1"
- }
- },
- "hoist-non-react-statics": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
- "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
- "dev": true,
- "requires": {
- "react-is": "^16.7.0"
- }
- },
"hosted-git-info": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz",
@@ -27448,16 +27431,6 @@
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
"dev": true
},
- "mini-create-react-context": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz",
- "integrity": "sha512-b0TytUgFSbgFJGzJqXPKCFCBWigAjpjo+Fl7Vf7ZbKRDptszpppKxXH6DRXEABZ/gcEQczeb0iZ7JvL8e8jjCA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.5.5",
- "tiny-warning": "^1.0.3"
- }
- },
"mini-css-extract-plugin": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.5.1.tgz",
@@ -32536,53 +32509,22 @@
"integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA=="
},
"react-router": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz",
- "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==",
+ "version": "6.14.2",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.14.2.tgz",
+ "integrity": "sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==",
"dev": true,
"requires": {
- "@babel/runtime": "^7.1.2",
- "history": "^4.9.0",
- "hoist-non-react-statics": "^3.1.0",
- "loose-envify": "^1.3.1",
- "mini-create-react-context": "^0.4.0",
- "path-to-regexp": "^1.7.0",
- "prop-types": "^15.6.2",
- "react-is": "^16.6.0",
- "tiny-invariant": "^1.0.2",
- "tiny-warning": "^1.0.0"
- },
- "dependencies": {
- "isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
- "dev": true
- },
- "path-to-regexp": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
- "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
- "dev": true,
- "requires": {
- "isarray": "0.0.1"
- }
- }
+ "@remix-run/router": "1.7.2"
}
},
"react-router-dom": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz",
- "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==",
+ "version": "6.14.2",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.2.tgz",
+ "integrity": "sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==",
"dev": true,
"requires": {
- "@babel/runtime": "^7.1.2",
- "history": "^4.9.0",
- "loose-envify": "^1.3.1",
- "prop-types": "^15.6.2",
- "react-router": "5.2.0",
- "tiny-invariant": "^1.0.2",
- "tiny-warning": "^1.0.0"
+ "@remix-run/router": "1.7.2",
+ "react-router": "6.14.2"
}
},
"react-shallow-renderer": {
@@ -33148,12 +33090,6 @@
"global-dirs": "^0.1.1"
}
},
- "resolve-pathname": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
- "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==",
- "dev": true
- },
"resolve-url": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
@@ -36103,18 +36039,6 @@
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
"dev": true
},
- "tiny-invariant": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz",
- "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==",
- "dev": true
- },
- "tiny-warning": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
- "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
- "dev": true
- },
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -36743,12 +36667,6 @@
"builtins": "^1.0.3"
}
},
- "value-equal": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
- "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==",
- "dev": true
- },
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
diff --git a/package.json b/package.json
index 671454770..f9d98c7a2 100644
--- a/package.json
+++ b/package.json
@@ -166,8 +166,8 @@
"puppeteer": "^13.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
- "react-router": "^5.2.0",
- "react-router-dom": "^5.2.0",
+ "react-router": "^6.14.2",
+ "react-router-dom": "^6.14.2",
"regenerator-runtime": "^0.13.3",
"rimraf": "^3.0.0",
"rxjs": "^6.6.6",
diff --git a/packages/rum-react/karma.conf.js b/packages/rum-react/karma.conf.js
index fa3df5572..ef0293626 100644
--- a/packages/rum-react/karma.conf.js
+++ b/packages/rum-react/karma.conf.js
@@ -24,6 +24,7 @@
*/
const { baseConfig, prepareConfig } = require('../../dev-utils/karma.js')
+const { getBrowserList } = require('../../dev-utils/test-config')
const {
getWebpackConfig,
PACKAGE_TYPES,
@@ -33,7 +34,11 @@ const {
module.exports = function (config) {
config.set(baseConfig)
config.set({
- webpack: getWebpackConfig(BUNDLE_TYPES.BROWSER_DEV, PACKAGE_TYPES.REACT)
+ webpack: getWebpackConfig(BUNDLE_TYPES.BROWSER_DEV, PACKAGE_TYPES.REACT),
+ customLaunchers: getBrowserList('react').map(launcher => ({
+ ...launcher,
+ base: 'SauceLabs'
+ }))
})
const preparedConfig = prepareConfig(config, 'rum-react')
config.set(preparedConfig)
diff --git a/packages/rum-react/package.json b/packages/rum-react/package.json
index f969c099c..bf18b8421 100644
--- a/packages/rum-react/package.json
+++ b/packages/rum-react/package.json
@@ -46,7 +46,7 @@
},
"peerDependencies": {
"react": ">16.0.0",
- "react-router-dom": ">4.0.0"
+ "react-router-dom": ">=6.0.0"
},
"browserslist": [
"ie 11"
diff --git a/packages/rum-react/src/finish-transaction-effect.js b/packages/rum-react/src/finish-transaction-effect.js
new file mode 100644
index 000000000..219d0899d
--- /dev/null
+++ b/packages/rum-react/src/finish-transaction-effect.js
@@ -0,0 +1,53 @@
+/**
+ * MIT License
+ *
+ * Copyright (c) 2017-present, Elasticsearch BV
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+import React from 'react'
+import { afterFrame } from '@elastic/apm-rum-core'
+
+function useFinishTransactionEffect(transaction) {
+ /**
+ * React guarantees the parent component effects are run after the child components effects
+ * So once all the child components effects are run, we run the detectFinish logic
+ * which ensures if the transaction can be completed or not.
+ */
+ React.useEffect(() => {
+ afterFrame(() => {
+ transaction && transaction.detectFinish()
+ })
+ return () => {
+ /**
+ * Incase the transaction is never ended, we check if the transaction
+ * can be closed during unmount phase
+ *
+ * We call detectFinish instead of forcefully ending the transaction
+ * since it could be a redirect route and we might prematurely close
+ * the currently running transaction
+ */
+ transaction && transaction.detectFinish()
+ }
+ }, [])
+}
+
+export { useFinishTransactionEffect }
diff --git a/packages/rum-react/src/get-apm-route.js b/packages/rum-react/src/get-apm-route.js
deleted file mode 100644
index dd3db7cae..000000000
--- a/packages/rum-react/src/get-apm-route.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * MIT License
- *
- * Copyright (c) 2017-present, Elasticsearch BV
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-import React from 'react'
-import { Route } from 'react-router-dom'
-import { getWithTransaction } from './get-with-transaction'
-
-/**
- * If the path/name is given as array, use the computed path
- * to get the current transaction name
- */
-function getTransactionName(name, props) {
- const { match = {} } = props
-
- if (Array.isArray(name) && match.path) {
- return match.path
- }
- return name
-}
-
-function getApmRoute(apm) {
- const withTransaction = getWithTransaction(apm)
-
- return class ApmRoute extends React.Component {
- constructor(props) {
- super(props)
- this.state = {}
- }
-
- static getDerivedStateFromProps(nextProps, prevState) {
- const initial = prevState.apmComponent == null
- const { path, component } = nextProps
- const pathChanged = path != prevState.path
-
- /**
- * Should update the apmComponent state and re-render the component only on
- * initial mount and on route change.
- * Ex: Query param changes should not result in new apmComponent
- */
- if (initial || pathChanged) {
- return {
- path,
- apmComponent: withTransaction(
- path,
- 'route-change',
- (transaction, props) => {
- if (transaction) {
- const name = getTransactionName(path, props)
- name && (transaction.name = name)
- }
- }
- )(component)
- }
- }
- return null
- }
-
- render() {
- return