diff --git a/__fixtures__/test-project/api/db/migrations/20220101120000_create_post_user/migration.sql b/__fixtures__/test-project/api/db/migrations/20230118153725_create_post_user/migration.sql
similarity index 100%
rename from __fixtures__/test-project/api/db/migrations/20220101120000_create_post_user/migration.sql
rename to __fixtures__/test-project/api/db/migrations/20230118153725_create_post_user/migration.sql
diff --git a/__fixtures__/test-project/api/db/migrations/20220102120000_create_contact/migration.sql b/__fixtures__/test-project/api/db/migrations/20230118153843_create_contact/migration.sql
similarity index 100%
rename from __fixtures__/test-project/api/db/migrations/20220102120000_create_contact/migration.sql
rename to __fixtures__/test-project/api/db/migrations/20230118153843_create_contact/migration.sql
diff --git a/__fixtures__/test-project/web/package.json b/__fixtures__/test-project/web/package.json
index 5ee0a9648f29..13ad823aacbb 100644
--- a/__fixtures__/test-project/web/package.json
+++ b/__fixtures__/test-project/web/package.json
@@ -19,8 +19,8 @@
"@redwoodjs/web": "3.2.0",
"humanize-string": "2.1.0",
"prop-types": "15.8.1",
- "react": "17.0.2",
- "react-dom": "17.0.2"
+ "react": "18.2.0",
+ "react-dom": "18.2.0"
},
"devDependencies": {
"autoprefixer": "^10.4.13",
diff --git a/__fixtures__/test-project/web/src/pages/ProfilePage/ProfilePage.tsx b/__fixtures__/test-project/web/src/pages/ProfilePage/ProfilePage.tsx
index 43848b6f6c13..39abea2fa43d 100644
--- a/__fixtures__/test-project/web/src/pages/ProfilePage/ProfilePage.tsx
+++ b/__fixtures__/test-project/web/src/pages/ProfilePage/ProfilePage.tsx
@@ -24,14 +24,18 @@ const ProfilePage = () => {
- {Object.keys(currentUser).map((key) => {
- return (
-
- {key.toUpperCase()} |
- {currentUser[key]} |
-
- )
- })}
+
+ ID |
+ {currentUser.id} |
+
+
+ ROLES |
+ {currentUser.roles} |
+
+
+ EMAIL |
+ {currentUser.email} |
+
isAuthenticated |
diff --git a/babel.config.js b/babel.config.js
index df2764c24df2..78e835b51e24 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -38,9 +38,47 @@ module.exports = {
},
],
'@babel/preset-react',
+ /**
+ * TODO(pc): w/ '@babel/plugin-transform-typescript' in plugins now, is '@babel/typescript' preset still needed?
+ *
+ * - Plugins run before Presets.
+ * - Plugin ordering is first to last.
+ * - Preset ordering is reversed (last to first).
+ *
+ * https://babeljs.io/docs/en/plugins/#plugin-ordering
+ */
'@babel/typescript',
],
plugins: [
+ /**
+ * NOTE
+ * Needed for react@18
+ *
+ * ```
+ * ✖ @redwoodjs/router:build
+ * SyntaxError: /code/redwood/packages/router/src/location.tsx: TypeScript 'declare' fields must first be transformed by @babel/plugin-transform-typescript.
+ * If you have already enabled that plugin (or '@babel/preset-typescript'), make sure that it runs before any plugin related to additional class features:
+ * - @babel/plugin-proposal-class-properties
+ * - @babel/plugin-proposal-private-methods
+ * - @babel/plugin-proposal-decorators
+ * 25 | // When prerendering, there might be more than one level of location
+ * 26 | // providers. Use the values from the one above.
+ * > 27 | declare context: React.ContextType
+ * | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * 28 | HISTORY_LISTENER_ID: string | undefined = undefined
+ * 29 |
+ * 30 | state = {
+ * ```
+ */
+ [
+ '@babel/plugin-transform-typescript',
+ {
+ allowDeclareFields: true,
+ /** needed in order build `packages/web/dist/entry/index.js` */
+ isTSX: true,
+ allExtensions: true,
+ },
+ ],
/**
* NOTE
* Experimental decorators are used in `@redwoodjs/structure`.
diff --git a/docs/docs/custom-web-index.md b/docs/docs/custom-web-index.md
index 97262a50285d..a713be6282bf 100644
--- a/docs/docs/custom-web-index.md
+++ b/docs/docs/custom-web-index.md
@@ -19,7 +19,7 @@ yarn rw setup custom-web-index
This generates a file named `index.js` in `web/src` that looks like this:
```jsx title="web/src/index.js"
-import ReactDOM from 'react-dom'
+import { hydrateRoot, createRoot } from 'react-dom/client'
import App from './App'
/**
@@ -31,9 +31,11 @@ import App from './App'
const rootElement = document.getElementById('redwood-app')
if (rootElement.hasChildNodes()) {
- ReactDOM.hydrate(, rootElement)
+ hydrateRoot(redwoodAppElement, )
} else {
- ReactDOM.render(, rootElement)
+ const root = createRoot(redwoodAppElement)
+ root.render()
+}
```
This's actually the same file Redwood uses [internally](https://github.com/redwoodjs/redwood/blob/main/packages/web/src/entry/index.js).
diff --git a/package.json b/package.json
index ed7f6bd46034..768000aa461b 100644
--- a/package.json
+++ b/package.json
@@ -27,12 +27,6 @@
"test-ci": "lerna run test --concurrency 2 -- --colors --maxWorkers"
},
"resolutions": {
- "@types/react": "17.0.53",
- "microtime": "3.1.1",
- "prop-types": "15.8.1",
- "react": "17.0.2",
- "react-dom": "17.0.2",
- "typescript": "4.7.4",
"vscode-languageserver": "6.1.1",
"vscode-languageserver-protocol": "3.15.3",
"vscode-languageserver-textdocument": "1.0.8",
@@ -61,8 +55,7 @@
"@playwright/test": "1.29.2",
"@replayio/playwright": "0.3.15",
"@testing-library/jest-dom": "5.16.5",
- "@testing-library/react": "12.1.5",
- "@testing-library/react-hooks": "8.0.1",
+ "@testing-library/react": "13.4.0",
"@testing-library/user-event": "14.4.3",
"@tsd/typescript": "4.9.4",
"@types/babel__generator": "7.6.4",
diff --git a/packages/auth-providers/auth0/web/package.json b/packages/auth-providers/auth0/web/package.json
index fd151b6ee1cd..6f5f3d2dcf86 100644
--- a/packages/auth-providers/auth0/web/package.json
+++ b/packages/auth-providers/auth0/web/package.json
@@ -30,10 +30,9 @@
"@auth0/auth0-spa-js": "1.22.6",
"@babel/cli": "7.20.7",
"@babel/core": "7.20.12",
- "@testing-library/react-hooks": "8.0.1",
- "@types/react": "17.0.53",
+ "@types/react": "18.0.27",
"jest": "29.3.1",
- "react": "17.0.2",
+ "react": "18.2.0",
"typescript": "4.7.4"
},
"peerDependencies": {
diff --git a/packages/auth-providers/auth0/web/src/__tests__/auth0.test.tsx b/packages/auth-providers/auth0/web/src/__tests__/auth0.test.tsx
index 4e4eed120b98..79c390734338 100644
--- a/packages/auth-providers/auth0/web/src/__tests__/auth0.test.tsx
+++ b/packages/auth-providers/auth0/web/src/__tests__/auth0.test.tsx
@@ -4,7 +4,7 @@ import type {
GetTokenSilentlyVerboseResponse,
User,
} from '@auth0/auth0-spa-js'
-import { renderHook, act } from '@testing-library/react-hooks'
+import { renderHook, act } from '@testing-library/react'
import { CurrentUser } from '@redwoodjs/auth'
diff --git a/packages/auth-providers/azureActiveDirectory/web/package.json b/packages/auth-providers/azureActiveDirectory/web/package.json
index a2227577c717..af9778d6b67c 100644
--- a/packages/auth-providers/azureActiveDirectory/web/package.json
+++ b/packages/auth-providers/azureActiveDirectory/web/package.json
@@ -30,11 +30,10 @@
"@azure/msal-browser": "2.32.2",
"@babel/cli": "7.20.7",
"@babel/core": "7.20.12",
- "@testing-library/react-hooks": "8.0.1",
"@types/netlify-identity-widget": "1.9.3",
- "@types/react": "17.0.53",
+ "@types/react": "18.0.27",
"jest": "29.3.1",
- "react": "17.0.2",
+ "react": "18.2.0",
"typescript": "4.7.4"
},
"peerDependencies": {
diff --git a/packages/auth-providers/azureActiveDirectory/web/src/__tests__/azureActiveDirectory.test.tsx b/packages/auth-providers/azureActiveDirectory/web/src/__tests__/azureActiveDirectory.test.tsx
index cb3b6a0bffc2..e60866f10837 100644
--- a/packages/auth-providers/azureActiveDirectory/web/src/__tests__/azureActiveDirectory.test.tsx
+++ b/packages/auth-providers/azureActiveDirectory/web/src/__tests__/azureActiveDirectory.test.tsx
@@ -3,7 +3,7 @@ import type {
PublicClientApplication as AzureActiveDirectoryClient,
RedirectRequest,
} from '@azure/msal-browser'
-import { renderHook, act } from '@testing-library/react-hooks'
+import { renderHook, act } from '@testing-library/react'
import { CurrentUser } from '@redwoodjs/auth'
diff --git a/packages/auth-providers/clerk/web/package.json b/packages/auth-providers/clerk/web/package.json
index 9fada5ba18eb..2db131560476 100644
--- a/packages/auth-providers/clerk/web/package.json
+++ b/packages/auth-providers/clerk/web/package.json
@@ -31,10 +31,9 @@
"@babel/core": "7.20.12",
"@clerk/clerk-react": "3.5.1",
"@clerk/types": "2.21.0",
- "@testing-library/react-hooks": "8.0.1",
- "@types/react": "17.0.53",
+ "@types/react": "18.0.27",
"jest": "29.3.1",
- "react": "17.0.2",
+ "react": "18.2.0",
"typescript": "4.7.4"
},
"peerDependencies": {
diff --git a/packages/auth-providers/clerk/web/src/__tests__/clerk.test.tsx b/packages/auth-providers/clerk/web/src/__tests__/clerk.test.tsx
index 68f8502c7351..826b5186dd22 100644
--- a/packages/auth-providers/clerk/web/src/__tests__/clerk.test.tsx
+++ b/packages/auth-providers/clerk/web/src/__tests__/clerk.test.tsx
@@ -4,7 +4,7 @@ import {
EmailAddressResource,
ActiveSessionResource,
} from '@clerk/types'
-import { renderHook, act } from '@testing-library/react-hooks'
+import { renderHook, act } from '@testing-library/react'
import { CurrentUser } from '@redwoodjs/auth'
diff --git a/packages/auth-providers/dbAuth/web/package.json b/packages/auth-providers/dbAuth/web/package.json
index 2a170064eac1..6c3777272717 100644
--- a/packages/auth-providers/dbAuth/web/package.json
+++ b/packages/auth-providers/dbAuth/web/package.json
@@ -32,10 +32,9 @@
"@babel/cli": "7.20.7",
"@babel/core": "7.20.12",
"@simplewebauthn/typescript-types": "6.2.1",
- "@testing-library/react-hooks": "8.0.1",
- "@types/react": "17.0.53",
+ "@types/react": "18.0.27",
"jest": "29.3.1",
- "react": "17.0.2",
+ "react": "18.2.0",
"typescript": "4.7.4"
},
"gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1"
diff --git a/packages/auth-providers/dbAuth/web/src/__tests__/dbAuth.test.ts b/packages/auth-providers/dbAuth/web/src/__tests__/dbAuth.test.ts
index 5dd5bb37f201..f6be7466faf5 100644
--- a/packages/auth-providers/dbAuth/web/src/__tests__/dbAuth.test.ts
+++ b/packages/auth-providers/dbAuth/web/src/__tests__/dbAuth.test.ts
@@ -1,4 +1,4 @@
-import { renderHook, act } from '@testing-library/react-hooks'
+import { renderHook, act } from '@testing-library/react'
import { CurrentUser } from '@redwoodjs/auth'
diff --git a/packages/auth-providers/firebase/web/package.json b/packages/auth-providers/firebase/web/package.json
index c37ead11d9bd..fb962be8e1d0 100644
--- a/packages/auth-providers/firebase/web/package.json
+++ b/packages/auth-providers/firebase/web/package.json
@@ -29,11 +29,10 @@
"devDependencies": {
"@babel/cli": "7.20.7",
"@babel/core": "7.20.12",
- "@testing-library/react-hooks": "8.0.1",
- "@types/react": "17.0.53",
+ "@types/react": "18.0.27",
"firebase": "9.16.0",
"jest": "29.3.1",
- "react": "17.0.2",
+ "react": "18.2.0",
"typescript": "4.7.4"
},
"peerDependencies": {
diff --git a/packages/auth-providers/firebase/web/src/__tests__/firebase.test.tsx b/packages/auth-providers/firebase/web/src/__tests__/firebase.test.tsx
index b39dc0c9709e..eec862b29d55 100644
--- a/packages/auth-providers/firebase/web/src/__tests__/firebase.test.tsx
+++ b/packages/auth-providers/firebase/web/src/__tests__/firebase.test.tsx
@@ -1,4 +1,4 @@
-import { renderHook, act } from '@testing-library/react-hooks'
+import { renderHook, act } from '@testing-library/react'
import type FirebaseAuthNamespace from 'firebase/auth'
import { User, OperationType, OAuthProvider, Auth } from 'firebase/auth'
diff --git a/packages/auth-providers/netlify/web/package.json b/packages/auth-providers/netlify/web/package.json
index 86cfe4a6fb39..da1cd9cb9db7 100644
--- a/packages/auth-providers/netlify/web/package.json
+++ b/packages/auth-providers/netlify/web/package.json
@@ -29,11 +29,10 @@
"devDependencies": {
"@babel/cli": "7.20.7",
"@babel/core": "7.20.12",
- "@testing-library/react-hooks": "8.0.1",
"@types/netlify-identity-widget": "1.9.3",
- "@types/react": "17.0.53",
+ "@types/react": "18.0.27",
"jest": "29.3.1",
- "react": "17.0.2",
+ "react": "18.2.0",
"typescript": "4.7.4"
},
"peerDependencies": {
diff --git a/packages/auth-providers/netlify/web/src/__tests__/netlify.test.tsx b/packages/auth-providers/netlify/web/src/__tests__/netlify.test.tsx
index bd6a0532746d..25a6f79cde80 100644
--- a/packages/auth-providers/netlify/web/src/__tests__/netlify.test.tsx
+++ b/packages/auth-providers/netlify/web/src/__tests__/netlify.test.tsx
@@ -1,4 +1,4 @@
-import { renderHook, act } from '@testing-library/react-hooks'
+import { renderHook, act } from '@testing-library/react'
import * as NetlifyIdentityNS from 'netlify-identity-widget'
import { CurrentUser } from '@redwoodjs/auth'
diff --git a/packages/auth-providers/supabase/web/package.json b/packages/auth-providers/supabase/web/package.json
index 52a39aae0a63..97a69eff4c18 100644
--- a/packages/auth-providers/supabase/web/package.json
+++ b/packages/auth-providers/supabase/web/package.json
@@ -29,10 +29,9 @@
"@babel/cli": "7.20.7",
"@babel/core": "7.20.12",
"@supabase/supabase-js": "1.35.7",
- "@testing-library/react-hooks": "8.0.1",
- "@types/react": "17.0.53",
+ "@types/react": "18.0.27",
"jest": "29.3.1",
- "react": "17.0.2",
+ "react": "18.2.0",
"typescript": "4.7.4"
},
"peerDependencies": {
diff --git a/packages/auth-providers/supabase/web/src/__tests__/supabase.test.tsx b/packages/auth-providers/supabase/web/src/__tests__/supabase.test.tsx
index 7b9b81d2dbdd..36edf9430bb5 100644
--- a/packages/auth-providers/supabase/web/src/__tests__/supabase.test.tsx
+++ b/packages/auth-providers/supabase/web/src/__tests__/supabase.test.tsx
@@ -1,5 +1,5 @@
import type { SupabaseClient, User } from '@supabase/supabase-js'
-import { renderHook, act } from '@testing-library/react-hooks'
+import { renderHook, act } from '@testing-library/react'
import { CurrentUser } from '@redwoodjs/auth'
diff --git a/packages/auth-providers/supertokens/web/package.json b/packages/auth-providers/supertokens/web/package.json
index 1f0d339e97bc..c9f2cbd1b51f 100644
--- a/packages/auth-providers/supertokens/web/package.json
+++ b/packages/auth-providers/supertokens/web/package.json
@@ -29,10 +29,9 @@
"devDependencies": {
"@babel/cli": "7.20.7",
"@babel/core": "7.20.12",
- "@testing-library/react-hooks": "8.0.1",
- "@types/react": "17.0.53",
+ "@types/react": "18.0.27",
"jest": "29.3.1",
- "react": "17.0.2",
+ "react": "18.2.0",
"typescript": "4.7.4"
},
"peerDependencies": {
diff --git a/packages/auth-providers/supertokens/web/src/__tests__/supertokens.test.tsx b/packages/auth-providers/supertokens/web/src/__tests__/supertokens.test.tsx
index 77d6fdb26986..f235f80f1924 100644
--- a/packages/auth-providers/supertokens/web/src/__tests__/supertokens.test.tsx
+++ b/packages/auth-providers/supertokens/web/src/__tests__/supertokens.test.tsx
@@ -1,4 +1,4 @@
-import { renderHook, act } from '@testing-library/react-hooks'
+import { renderHook, act } from '@testing-library/react'
import { CurrentUser } from '@redwoodjs/auth'
diff --git a/packages/auth/package.json b/packages/auth/package.json
index f15ce5882c84..a08beebd43b7 100644
--- a/packages/auth/package.json
+++ b/packages/auth/package.json
@@ -24,14 +24,13 @@
"dependencies": {
"@babel/runtime-corejs3": "7.20.13",
"core-js": "3.27.2",
- "react": "17.0.2"
+ "react": "18.2.0"
},
"devDependencies": {
"@babel/cli": "7.20.7",
"@babel/core": "7.20.12",
"@testing-library/jest-dom": "5.16.5",
- "@testing-library/react": "12.1.5",
- "@testing-library/react-hooks": "8.0.1",
+ "@testing-library/react": "13.4.0",
"jest": "29.3.1",
"msw": "0.49.3",
"typescript": "4.7.4"
diff --git a/packages/auth/src/__tests__/AuthProvider.test.tsx b/packages/auth/src/__tests__/AuthProvider.test.tsx
index 115d56709044..24eadacd6ea7 100644
--- a/packages/auth/src/__tests__/AuthProvider.test.tsx
+++ b/packages/auth/src/__tests__/AuthProvider.test.tsx
@@ -9,7 +9,7 @@ import {
waitFor,
configure,
} from '@testing-library/react'
-import { renderHook, act } from '@testing-library/react-hooks'
+import { renderHook, act } from '@testing-library/react'
import '@testing-library/jest-dom/extend-expect'
import { graphql } from 'msw'
import { setupServer } from 'msw/node'
@@ -711,9 +711,7 @@ describe('Custom auth provider', () => {
)
- await waitFor(() => mockedForgotPassword.mock.calls.length === 1)
-
- expect.assertions(1)
+ await waitFor(() => expect(mockedForgotPassword).toBeCalledWith('username'))
})
test('proxies resetPassword() calls to client', async () => {
diff --git a/packages/create-redwood-app/template/web/package.json b/packages/create-redwood-app/template/web/package.json
index bf290661ac8e..505d93d018d4 100644
--- a/packages/create-redwood-app/template/web/package.json
+++ b/packages/create-redwood-app/template/web/package.json
@@ -17,7 +17,7 @@
"@redwoodjs/router": "3.2.0",
"@redwoodjs/web": "3.2.0",
"prop-types": "15.8.1",
- "react": "17.0.2",
- "react-dom": "17.0.2"
+ "react": "18.2.0",
+ "react-dom": "18.2.0"
}
}
diff --git a/packages/forms/package.json b/packages/forms/package.json
index 2f1fab714715..5e108ce4155f 100644
--- a/packages/forms/package.json
+++ b/packages/forms/package.json
@@ -32,22 +32,22 @@
"@babel/core": "7.20.12",
"@testing-library/dom": "8.20.0",
"@testing-library/jest-dom": "5.16.5",
- "@testing-library/react": "12.1.5",
+ "@testing-library/react": "13.4.0",
"@testing-library/user-event": "14.4.3",
"@types/pascalcase": "1.0.1",
- "@types/react": "17.0.53",
- "@types/react-dom": "17.0.18",
+ "@types/react": "18.0.27",
+ "@types/react-dom": "18.0.10",
"@types/testing-library__jest-dom": "5.14.5",
"graphql": "16.6.0",
"jest": "29.3.1",
"nodemon": "2.0.20",
- "react": "17.0.2",
- "react-dom": "17.0.2",
+ "react": "18.2.0",
+ "react-dom": "18.2.0",
"typescript": "4.7.4"
},
"peerDependencies": {
"graphql": "16.6.0",
- "react": "17.0.2"
+ "react": "18.2.0"
},
"gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1"
}
diff --git a/packages/prerender/package.json b/packages/prerender/package.json
index 013a4fb2dcca..1a42d4005e62 100644
--- a/packages/prerender/package.json
+++ b/packages/prerender/package.json
@@ -46,8 +46,8 @@
"typescript": "4.7.4"
},
"peerDependencies": {
- "react": "17.0.2",
- "react-dom": "17.0.2"
+ "react": "18.2.0",
+ "react-dom": "18.2.0"
},
"externals": {
"react": "react",
diff --git a/packages/router/package.json b/packages/router/package.json
index b4ff4c1d5495..4c3ea44aaa66 100644
--- a/packages/router/package.json
+++ b/packages/router/package.json
@@ -30,16 +30,16 @@
"devDependencies": {
"@babel/cli": "7.20.7",
"@babel/core": "7.20.12",
- "@types/react": "17.0.53",
- "@types/react-dom": "17.0.18",
+ "@types/react": "18.0.27",
+ "@types/react-dom": "18.0.10",
"jest": "29.3.1",
- "react": "17.0.2",
- "react-dom": "17.0.2",
+ "react": "18.2.0",
+ "react-dom": "18.2.0",
"typescript": "4.7.4"
},
"peerDependencies": {
- "react": "17.0.2",
- "react-dom": "17.0.2"
+ "react": "18.2.0",
+ "react-dom": "18.2.0"
},
"gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1"
}
diff --git a/packages/router/src/__tests__/router.test.tsx b/packages/router/src/__tests__/router.test.tsx
index 4b7b8055514e..8f32891d7f7d 100644
--- a/packages/router/src/__tests__/router.test.tsx
+++ b/packages/router/src/__tests__/router.test.tsx
@@ -43,6 +43,10 @@ import { useParams } from '../params'
import { Set } from '../Set'
import { Spec } from '../util'
+/** running into intermittent test timeout behavior in https://github.com/redwoodjs/redwood/pull/4992
+ attempting to work around by bumping the default timeout of 5000 */
+const timeoutForFlakeyAsyncTests = 8000
+
type UnknownAuthContextInterface = AuthContextInterface<
unknown,
unknown,
@@ -284,209 +288,253 @@ describe('slow imports', () => {
mockDelay = 0
})
- test('Basic home page', async () => {
- const screen = render()
- await waitFor(() => screen.getByText('HomePagePlaceholder'))
- await waitFor(() => screen.getByText('Home Page'))
- })
-
- test('Navigation', async () => {
- const screen = render()
- // First we should render an empty page while waiting for pageLoadDelay to
- // pass
- expect(screen.container).toBeEmptyDOMElement()
-
- // Then we should render whileLoadingPage
- await waitFor(() => screen.getByText('HomePagePlaceholder'))
-
- // Finally we should render the actual page
- await waitFor(() => screen.getByText('Home Page'))
-
- act(() => navigate('/about'))
-
- // Now after navigating we should keep rendering the previous page until
- // the new page has loaded, or until pageLoadDelay has passed. This
- // ensures we don't show a "white flash", i.e. render an empty page, while
- // navigating the page
- expect(screen.container).not.toBeEmptyDOMElement()
- await waitFor(() => screen.getByText('Home Page'))
- expect(screen.container).not.toBeEmptyDOMElement()
-
- // As for HomePage we first render the placeholder...
- await waitFor(() => screen.getByText('AboutPagePlaceholder'))
- // ...and then the actual page
- await waitFor(() => screen.getByText('About Page'))
- })
-
- test('Redirect page', async () => {
- act(() => navigate('/redirect'))
- const screen = render()
- await waitFor(() => screen.getByText('RedirectPagePlaceholder'))
- await waitFor(() => screen.getByText('About Page'))
- })
-
- test('Redirect route', async () => {
- const screen = render()
- await waitFor(() => screen.getByText('HomePagePlaceholder'))
- await waitFor(() => screen.getByText('Home Page'))
- act(() => navigate('/redirect2/redirected?q=cue'))
- await waitFor(() => screen.getByText('ParamPagePlaceholder'))
- await waitFor(() => screen.getByText('param redirectedcue'))
- })
-
- test('Private page when not authenticated', async () => {
- act(() => navigate('/private'))
- const screen = render()
- await waitFor(() => {
- expect(
- screen.queryByText('PrivatePagePlaceholder')
- ).not.toBeInTheDocument()
- expect(screen.queryByText('Private Page')).not.toBeInTheDocument()
- expect(screen.queryByText('LoginPagePlaceholder')).toBeInTheDocument()
- })
- await waitFor(() => screen.getByText('Login Page'))
- })
-
- test('Private page when authenticated', async () => {
- act(() => navigate('/private'))
- const screen = render()
-
- await waitFor(() => screen.getByText('PrivatePagePlaceholder'))
- await waitFor(() => screen.getByText('Private Page'))
- await waitFor(() => {
- expect(screen.queryByText('Login Page')).not.toBeInTheDocument()
- })
- })
-
- test('Private page when authenticated but does not have the role', async () => {
- act(() => navigate('/private_with_role'))
- const screen = render()
-
- await waitFor(() => {
- expect(
- screen.queryByText('PrivatePagePlaceholder')
- ).not.toBeInTheDocument()
- expect(screen.queryByText('Private Page')).not.toBeInTheDocument()
- expect(screen.queryByText('LoginPagePlaceholder')).toBeInTheDocument()
- })
- await waitFor(() => screen.getByText('Login Page'))
- })
-
- test('Private page when authenticated but does have the role', async () => {
- act(() => navigate('/private_with_role'))
- const screen = render()
-
- await waitFor(() => {
- expect(
- screen.queryByText('PrivatePagePlaceholder')
- ).not.toBeInTheDocument()
- expect(screen.queryByText('Private Page')).toBeInTheDocument()
- })
- })
-
- test('useLocation', async () => {
- act(() => navigate('/location'))
- const screen = render()
- await waitFor(() => screen.getByText('Location Page'))
- await waitFor(() => screen.getByText('/location'))
-
- act(() => navigate('/about'))
- // After navigating we will keep rendering the previous page for 100 ms,
- // (which is our configured delay) before rendering the "whileLoading"
- // page.
- await waitFor(() => screen.getByText('Location Page'))
-
- // Because we're still rendering the LocationPage, the pathname returned
- // by useLocation should still be /location
- // But because of a limitation in our implementation, that's currently
- // not the case.
- // TODO: Update this test when #3779 is fixed. (It'll start failing)
- await waitFor(() => screen.getByText('/about'))
- // await waitFor(() => screen.getByText('/location'))
-
- // And then we'll render the placeholder...
- await waitFor(() => screen.getByText('AboutPagePlaceholder'))
- // ...followed by the actual page
- await waitFor(() => screen.getByText('About Page'))
- })
-
- test('path params should never be empty', async () => {
- const PathParamPage = ({ value }) => {
- expect(value).not.toBeFalsy()
- return {value}
- }
-
- const TestRouter = () => (
-
-
-
-
- )
-
- act(() => navigate('/path-param-test/test_value'))
- const screen = render()
+ test(
+ 'Basic home page',
+ async () => {
+ const screen = render()
+ await waitFor(() => screen.getByText('HomePagePlaceholder'))
+ await waitFor(() => screen.getByText('Home Page'))
+ },
+ timeoutForFlakeyAsyncTests
+ )
- // First we render the path parameter value "test_value"
- await waitFor(() => screen.getByText('test_value'))
+ test(
+ 'Navigation',
+ async () => {
+ const screen = render()
+ // First we should render an empty page while waiting for pageLoadDelay to
+ // pass
+ expect(screen.container).toBeEmptyDOMElement()
+
+ // Then we should render whileLoadingPage
+ await waitFor(() => screen.getByText('HomePagePlaceholder'))
+
+ // Finally we should render the actual page
+ await waitFor(() => screen.getByText('Home Page'))
+
+ act(() => navigate('/about'))
+
+ // Now after navigating we should keep rendering the previous page until
+ // the new page has loaded, or until pageLoadDelay has passed. This
+ // ensures we don't show a "white flash", i.e. render an empty page, while
+ // navigating the page
+ expect(screen.container).not.toBeEmptyDOMElement()
+ await waitFor(() => screen.getByText('Home Page'))
+ expect(screen.container).not.toBeEmptyDOMElement()
+
+ // As for HomePage we first render the placeholder...
+ await waitFor(() => screen.getByText('AboutPagePlaceholder'))
+ // ...and then the actual page
+ await waitFor(() => screen.getByText('About Page'))
+ },
+ timeoutForFlakeyAsyncTests
+ )
- act(() => navigate('/about'))
- // After navigating we should keep displaying the old path value...
- await waitFor(() => screen.getByText('test_value'))
- // ...until we switch over to render the about page loading component...
- await waitFor(() => screen.getByText('AboutPagePlaceholder'))
- // ...followed by the actual page
- await waitFor(() => screen.getByText('About Page'))
- })
+ test(
+ 'Redirect page',
+ async () => {
+ act(() => navigate('/redirect'))
+ const screen = render()
+ await waitFor(() => screen.getByText('RedirectPagePlaceholder'))
+ await waitFor(() => screen.getByText('About Page'))
+ },
+ timeoutForFlakeyAsyncTests
+ )
- test('usePageLoadingContext', async () => {
- // We want to show a loading indicator if loading pages is taking a long
- // time. But at the same time we don't want to show it right away, because
- // then there'll be a flash of the loading indicator on every page load.
- // So we have a `pageLoadingDelay` delay to control how long it waits
- // before showing the loading state (default is 1000 ms).
- //
- // RW lazy loads pages by default, that's why it could potentially take a
- // while to load a page. But during tests we don't do that. So we have to
- // fake a delay. That's what `mockDelay` is for. `mockDelay` has to be
- // longer than `pageLoadingDelay`, but not too long so the test takes
- // longer than it has to, and also not too long so the entire test times
- // out.
+ test(
+ 'Redirect route',
+ async () => {
+ const screen = render()
+ await waitFor(() => screen.getByText('HomePagePlaceholder'))
+ await waitFor(() => screen.getByText('Home Page'))
+ act(() => navigate('/redirect2/redirected?q=cue'))
+ await waitFor(() => screen.getByText('ParamPagePlaceholder'))
+ await waitFor(() => screen.getByText('param redirectedcue'))
+ },
+ timeoutForFlakeyAsyncTests
+ )
- // Had to increase this to make the test pass on Windows
- mockDelay = 700
+ test(
+ 'Private page when not authenticated',
+ async () => {
+ act(() => navigate('/private'))
+ const screen = render()
+ await waitFor(() => {
+ expect(
+ screen.queryByText('PrivatePagePlaceholder')
+ ).not.toBeInTheDocument()
+ expect(screen.queryByText('Private Page')).not.toBeInTheDocument()
+ expect(screen.queryByText('LoginPagePlaceholder')).toBeInTheDocument()
+ })
+ await waitFor(() => screen.getByText('Login Page'))
+ },
+ timeoutForFlakeyAsyncTests
+ )
- // sets pageLoadingDelay={200}. (Default is 1000.)
- const screen = render()
+ test(
+ 'Private page when authenticated',
+ async () => {
+ act(() => navigate('/private'))
+ const screen = render()
+
+ await waitFor(() => screen.getByText('PrivatePagePlaceholder'))
+ await waitFor(() => screen.getByText('Private Page'))
+ await waitFor(() => {
+ expect(screen.queryByText('Login Page')).not.toBeInTheDocument()
+ })
+ },
+ timeoutForFlakeyAsyncTests
+ )
- act(() => navigate('/page-loading-context'))
+ test(
+ 'Private page when authenticated but does not have the role',
+ async () => {
+ act(() => navigate('/private_with_role'))
+ const screen = render()
+
+ await waitFor(() => {
+ expect(
+ screen.queryByText('PrivatePagePlaceholder')
+ ).not.toBeInTheDocument()
+ expect(screen.queryByText('Private Page')).not.toBeInTheDocument()
+ expect(screen.queryByText('LoginPagePlaceholder')).toBeInTheDocument()
+ })
+ await waitFor(() => screen.getByText('Login Page'))
+ },
+ timeoutForFlakeyAsyncTests
+ )
- // 'Page Loading Context Layout' should always be shown
- await waitFor(() => screen.getByText('Page Loading Context Layout'))
+ test(
+ 'Private page when authenticated but does have the role',
+ async () => {
+ act(() => navigate('/private_with_role'))
+ const screen = render()
+
+ await waitFor(() => {
+ expect(
+ screen.queryByText('PrivatePagePlaceholder')
+ ).not.toBeInTheDocument()
+ expect(screen.queryByText('Private Page')).toBeInTheDocument()
+ })
+ },
+ timeoutForFlakeyAsyncTests
+ )
- // 'loading in layout...' should only be shown while the page is loading.
- // So in this case, for the first 700ms
- await waitFor(() => screen.getByText('loading in layout...'))
+ test(
+ 'useLocation',
+ async () => {
+ act(() => navigate('/location'))
+ const screen = render()
+ await waitFor(() => screen.getByText('Location Page'))
+ await waitFor(() => screen.getByText('/location'))
+
+ act(() => navigate('/about'))
+ // After navigating we will keep rendering the previous page for 100 ms,
+ // (which is our configured delay) before rendering the "whileLoading"
+ // page.
+ await waitFor(() => screen.getByText('Location Page'))
+
+ // Because we're still rendering the LocationPage, the pathname returned
+ // by useLocation should still be /location
+ // But because of a limitation in our implementation, that's currently
+ // not the case.
+ // TODO: Update this test when #3779 is fixed. (It'll start failing)
+ await waitFor(() => screen.getByText('/about'))
+ // await waitFor(() => screen.getByText('/location'))
+
+ // And then we'll render the placeholder...
+ await waitFor(() => screen.getByText('AboutPagePlaceholder'))
+ // ...followed by the actual page
+ await waitFor(() => screen.getByText('About Page'))
+ },
+ timeoutForFlakeyAsyncTests
+ )
- // After 700ms 'Page Loading Context Page' should be rendered
- await waitFor(() => screen.getByText('Page Loading Context Page'))
+ test(
+ 'path params should never be empty',
+ async () => {
+ const PathParamPage = ({ value }) => {
+ expect(value).not.toBeFalsy()
+ return {value}
+ }
- // This shouldn't show up, because the page shouldn't render before it's
- // fully loaded
- expect(screen.queryByText('loading in page...')).not.toBeInTheDocument()
+ const TestRouter = () => (
+
+
+
+
+ )
+
+ act(() => navigate('/path-param-test/test_value'))
+ const screen = render()
+
+ // First we render the path parameter value "test_value"
+ await waitFor(() => screen.getByText('test_value'))
+
+ act(() => navigate('/about'))
+ // After navigating we should keep displaying the old path value...
+ await waitFor(() => screen.getByText('test_value'))
+ // ...until we switch over to render the about page loading component...
+ await waitFor(() => screen.getByText('AboutPagePlaceholder'))
+ // ...followed by the actual page
+ await waitFor(() => screen.getByText('About Page'))
+ },
+ timeoutForFlakeyAsyncTests
+ )
- await waitFor(() => screen.getByText('done loading in page'))
- await waitFor(() => screen.getByText('done loading in layout'))
- })
+ test(
+ 'usePageLoadingContext',
+ async () => {
+ // We want to show a loading indicator if loading pages is taking a long
+ // time. But at the same time we don't want to show it right away, because
+ // then there'll be a flash of the loading indicator on every page load.
+ // So we have a `pageLoadingDelay` delay to control how long it waits
+ // before showing the loading state (default is 1000 ms).
+ //
+ // RW lazy loads pages by default, that's why it could potentially take a
+ // while to load a page. But during tests we don't do that. So we have to
+ // fake a delay. That's what `mockDelay` is for. `mockDelay` has to be
+ // longer than `pageLoadingDelay`, but not too long so the test takes
+ // longer than it has to, and also not too long so the entire test times
+ // out.
+
+ // Had to increase this to make the test pass on Windows
+ mockDelay = 700
+
+ // sets pageLoadingDelay={200}. (Default is 1000.)
+ const screen = render()
+
+ act(() => navigate('/page-loading-context'))
+
+ // 'Page Loading Context Layout' should always be shown
+ await waitFor(() => screen.getByText('Page Loading Context Layout'))
+
+ // 'loading in layout...' should only be shown while the page is loading.
+ // So in this case, for the first 700ms
+ await waitFor(() => screen.getByText('loading in layout...'))
+
+ // After 700ms 'Page Loading Context Page' should be rendered
+ await waitFor(() => screen.getByText('Page Loading Context Page'))
+
+ // This shouldn't show up, because the page shouldn't render before it's
+ // fully loaded
+ expect(screen.queryByText('loading in page...')).not.toBeInTheDocument()
+
+ await waitFor(() => screen.getByText('done loading in page'))
+ await waitFor(() => screen.getByText('done loading in layout'))
+ },
+ timeoutForFlakeyAsyncTests
+ )
})
describe('inits routes and navigates as expected', () => {
diff --git a/packages/router/src/__tests__/set.test.tsx b/packages/router/src/__tests__/set.test.tsx
index 369d86f725b4..3c73111137e8 100644
--- a/packages/router/src/__tests__/set.test.tsx
+++ b/packages/router/src/__tests__/set.test.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, { type ReactNode } from 'react'
import { render, waitFor } from '@testing-library/react'
import '@testing-library/jest-dom/extend-expect'
@@ -10,14 +10,14 @@ import { Set } from '../Set'
const ChildA = () => ChildA
const ChildB = () => ChildB
const ChildC = () => ChildC
-const GlobalLayout: React.FC = ({ children }) => (
+const GlobalLayout: React.FC<{ children?: ReactNode }> = ({ children }) => (
Global Layout
{children}
)
-const CustomWrapper: React.FC = ({ children }) => (
+const CustomWrapper: React.FC<{ children?: ReactNode }> = ({ children }) => (
Custom Wrapper
{children}
@@ -89,6 +89,7 @@ test('passes props to wrappers', async () => {
interface Props {
propOne: string
propTwo: string
+ children?: ReactNode
}
const PropWrapper: React.FC
= ({ children, propOne, propTwo }) => (
diff --git a/packages/router/src/active-route-loader.tsx b/packages/router/src/active-route-loader.tsx
index 20b2d4cd20dd..d2a6d2575a72 100644
--- a/packages/router/src/active-route-loader.tsx
+++ b/packages/router/src/active-route-loader.tsx
@@ -1,6 +1,10 @@
-import React, { useRef, useState, useEffect } from 'react'
-
-import { unstable_batchedUpdates } from 'react-dom'
+import React, {
+ useRef,
+ useState,
+ useEffect,
+ SetStateAction,
+ ReactNode,
+} from 'react'
import { getAnnouncement, getFocus, resetFocus } from './a11yUtils'
import {
@@ -97,19 +101,17 @@ export const ActiveRouteLoader = ({
// Consumers of the context can show a loading indicator
// to signal to the user that something is happening.
loadingTimeout.current = setTimeout(() => {
- unstable_batchedUpdates(() => {
- setLoadingState((loadingState) => ({
- ...loadingState,
- [path]: {
- page: whileLoadingPage || ArlWhileLoadingNullPage,
- specName: '',
- state: 'SHOW_LOADING',
- location,
- },
- }))
- setRenderedChildren(children)
- setRenderedPath(path)
- })
+ setLoadingState((loadingState) => ({
+ ...loadingState,
+ [path]: {
+ page: whileLoadingPage || ArlWhileLoadingNullPage,
+ specName: '',
+ state: 'SHOW_LOADING',
+ location,
+ },
+ }))
+ setRenderedChildren(children)
+ setRenderedPath(path)
}, delay)
// Wait to download and parse the page.
@@ -122,26 +124,25 @@ export const ActiveRouteLoader = ({
// Only update all state if we're still interested (i.e. we're still
// waiting for the page that just finished loading)
if (isMounted() && name === waitingFor.current) {
- unstable_batchedUpdates(() => {
- setLoadingState((loadingState) => ({
- ...loadingState,
- [path]: {
- page: module.default,
- specName: name,
- state: 'DONE',
- location,
- },
- }))
- // `children` could for example be a Set or a Route. Either way the
- // just-loaded page will be somewhere in the children tree. But
- // children could also be undefined, in which case we'll just render
- // the just-loaded page itself. For example, when we render the
- // NotFoundPage children will be undefined and the default export in
- // `module` will be the NotFoundPage itself.
- setRenderedChildren(children ?? module.default)
- setRenderedPath(path)
- setPageName(name)
- })
+ setLoadingState((loadingState) => ({
+ ...loadingState,
+ [path]: {
+ page: module.default,
+ specName: name,
+ state: 'DONE',
+ location,
+ },
+ }))
+ // `children` could for example be a Set or a Route. Either way the
+ // just-loaded page will be somewhere in the children tree. But
+ // children could also be undefined, in which case we'll just render
+ // the just-loaded page itself. For example, when we render the
+ // NotFoundPage children will be undefined and the default export in
+ // `module` will be the NotFoundPage itself.
+ const renderedChildren = children ?? module.default
+ setRenderedChildren(renderedChildren as SetStateAction) //FIXME: test this?
+ setRenderedPath(path)
+ setPageName(name)
}
}
@@ -149,32 +150,30 @@ export const ActiveRouteLoader = ({
clearLoadingTimeout()
startPageLoadTransition(spec, delay)
} else {
- unstable_batchedUpdates(() => {
- // Handle navigating to the same page again, but with different path
- // params (i.e. new `location` or route params)
- setLoadingState((loadingState) => {
- // If path is same, fetch the page again
- let existingPage = loadingState[path]?.page
- // If path is different, try to find the existing page
- if (!existingPage) {
- const pageState = Object.values(loadingState).find(
- (state) => state?.specName === spec.name
- )
- existingPage = pageState?.page
- }
- return {
- ...loadingState,
- [path]: {
- page: existingPage || ArlNullPage,
- specName: spec.name,
- state: 'DONE',
- location,
- },
- }
- })
- setRenderedChildren(children)
- setRenderedPath(path)
+ // Handle navigating to the same page again, but with different path
+ // params (i.e. new `location` or route params)
+ setLoadingState((loadingState) => {
+ // If path is same, fetch the page again
+ let existingPage = loadingState[path]?.page
+ // If path is different, try to find the existing page
+ if (!existingPage) {
+ const pageState = Object.values(loadingState).find(
+ (state) => state?.specName === spec.name
+ )
+ existingPage = pageState?.page
+ }
+ return {
+ ...loadingState,
+ [path]: {
+ page: existingPage || ArlNullPage,
+ specName: spec.name,
+ state: 'DONE',
+ location,
+ },
+ }
})
+ setRenderedChildren(children)
+ setRenderedPath(path)
}
return () => {
diff --git a/packages/router/src/location.tsx b/packages/router/src/location.tsx
index 9c734fbe7e2b..bccad5cdff37 100644
--- a/packages/router/src/location.tsx
+++ b/packages/router/src/location.tsx
@@ -25,6 +25,7 @@ class LocationProvider extends React.Component {
// When prerendering, there might be more than one level of location
// providers. Use the values from the one above.
static contextType = LocationContext
+ declare context: React.ContextType
HISTORY_LISTENER_ID: string | undefined = undefined
state = {
diff --git a/packages/testing/package.json b/packages/testing/package.json
index 507ed4c578af..5b53bf82bfe5 100644
--- a/packages/testing/package.json
+++ b/packages/testing/package.json
@@ -40,15 +40,14 @@
"@storybook/manager-webpack5": "6.5.15",
"@storybook/react": "6.5.15",
"@testing-library/jest-dom": "5.16.5",
- "@testing-library/react": "12.1.5",
- "@testing-library/react-hooks": "8.0.1",
+ "@testing-library/react": "13.4.0",
"@testing-library/user-event": "14.4.3",
"@types/aws-lambda": "8.10.109",
"@types/babel-core": "6.25.7",
"@types/jest": "29.2.6",
"@types/node": "16.18.11",
- "@types/react": "17.0.53",
- "@types/react-dom": "17.0.18",
+ "@types/react": "18.0.27",
+ "@types/react-dom": "18.0.10",
"@types/webpack": "5.28.0",
"babel-jest": "29.3.1",
"babel-plugin-inline-react-svg": "2.0.1",
diff --git a/packages/testing/src/web/customRender.tsx b/packages/testing/src/web/customRender.tsx
index dbea63cf3842..f6d353a8fd55 100644
--- a/packages/testing/src/web/customRender.tsx
+++ b/packages/testing/src/web/customRender.tsx
@@ -1,19 +1,17 @@
import React from 'react'
-import { render } from '@testing-library/react'
-import type { RenderResult, RenderOptions } from '@testing-library/react'
+import { render, renderHook } from '@testing-library/react'
import type {
+ RenderResult,
+ RenderOptions,
RenderHookOptions,
RenderHookResult,
-} from '@testing-library/react-hooks'
-// `@testing-library/react-hooks` is being deprecated
-// since the functionality is moving into v13 of `@testing-library/react`.
-// But v13 of `@testing-library/react` drops support for React 17, so we can't upgrade just yet.
-// We can remove `@testing-library/react-hooks` after upgrading Redwood to React 18.
-import { renderHook } from '@testing-library/react-hooks/dom'
+} from '@testing-library/react'
import { MockProviders } from './MockProviders'
+export type CustomRenderHookOptions = RenderHookOptions
+
export const customRender = (
ui: React.ReactElement,
options: RenderOptions = {}
@@ -26,8 +24,8 @@ export const customRender = (
export const customRenderHook = (
render: (props: Props) => Result,
- options?: RenderHookOptions
-): RenderHookResult => {
+ options?: CustomRenderHookOptions
+): RenderHookResult => {
return renderHook(render, {
wrapper: (props: any) => ,
...options,
diff --git a/packages/web/package.json b/packages/web/package.json
index d74f1a01e92b..4d15f20230c6 100644
--- a/packages/web/package.json
+++ b/packages/web/package.json
@@ -51,22 +51,22 @@
"@babel/cli": "7.20.7",
"@babel/core": "7.20.12",
"@testing-library/jest-dom": "5.16.5",
- "@testing-library/react": "12.1.5",
+ "@testing-library/react": "13.4.0",
"@types/prop-types": "15.7.5",
- "@types/react": "17.0.53",
- "@types/react-dom": "17.0.18",
+ "@types/react": "18.0.27",
+ "@types/react-dom": "18.0.10",
"@types/testing-library__jest-dom": "5.14.5",
"jest": "29.3.1",
"nodemon": "2.0.20",
"prop-types": "15.8.1",
- "react": "17.0.2",
- "react-dom": "17.0.2",
+ "react": "18.2.0",
+ "react-dom": "18.2.0",
"typescript": "4.7.4"
},
"peerDependencies": {
"prop-types": "15.8.1",
- "react": "17.0.2",
- "react-dom": "17.0.2"
+ "react": "18.2.0",
+ "react-dom": "18.2.0"
},
"gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1"
}
diff --git a/packages/web/src/entry/index.js b/packages/web/src/entry/index.js
index 6837340bc6c1..e45fd3b19f35 100644
--- a/packages/web/src/entry/index.js
+++ b/packages/web/src/entry/index.js
@@ -1,16 +1,17 @@
-import ReactDOM from 'react-dom'
+import { hydrateRoot, createRoot } from 'react-dom/client'
import App from '~redwood-app-root'
/**
* When `#redwood-app` isn't empty then it's very likely that you're using
* prerendering. So React attaches event listeners to the existing markup
* rather than replacing it.
- * https://reactjs.org/docs/react-dom.html#hydrate
+ * https://reactjs.org/docs/react-dom-client.html#hydrateroot
*/
-const rootElement = document.getElementById('redwood-app')
+const redwoodAppElement = document.getElementById('redwood-app')
-if (rootElement.children?.length > 0) {
- ReactDOM.hydrate(, rootElement)
+if (redwoodAppElement.children?.length > 0) {
+ hydrateRoot(redwoodAppElement, )
} else {
- ReactDOM.render(, rootElement)
+ const root = createRoot(redwoodAppElement)
+ root.render()
}
diff --git a/tasks/test-project/codemods/profilePage.js b/tasks/test-project/codemods/profilePage.js
index 9aba697730f7..3da4567fa0ca 100644
--- a/tasks/test-project/codemods/profilePage.js
+++ b/tasks/test-project/codemods/profilePage.js
@@ -18,14 +18,18 @@ return (
- {Object.keys(currentUser).map((key) => {
- return (
-
- {key.toUpperCase()} |
- {currentUser[key]} |
-
- )
- })}
+
+ ID |
+ {currentUser.id} |
+
+
+ ROLES |
+ {currentUser.roles} |
+
+
+ EMAIL |
+ {currentUser.email} |
+
isAuthenticated |
diff --git a/yarn.lock b/yarn.lock
index 8388218e1579..fe5840d6ee81 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6044,17 +6044,17 @@ __metadata:
linkType: hard
"@octokit/app@npm:^13.1.1":
- version: 13.1.1
- resolution: "@octokit/app@npm:13.1.1"
+ version: 13.1.2
+ resolution: "@octokit/app@npm:13.1.2"
dependencies:
"@octokit/auth-app": ^4.0.8
"@octokit/auth-unauthenticated": ^3.0.0
"@octokit/core": ^4.0.0
"@octokit/oauth-app": ^4.0.7
- "@octokit/plugin-paginate-rest": ^5.0.0
- "@octokit/types": ^8.0.0
+ "@octokit/plugin-paginate-rest": ^6.0.0
+ "@octokit/types": ^9.0.0
"@octokit/webhooks": ^10.0.0
- checksum: 02865fd0f7d8fa5688fd2f5ac53ff3ab0a7ee35de240e0345ab76423c2032d5eff67b2bac6230f77ae765b38cfb7a204a9dc41f51c70841934e1d6dd81abb6b4
+ checksum: 3127e8c95a8bf9ba50e5635dadfc7ae0fb9f0910bf411d2436fff95ffa239dab46331431f32b5a68c023c5c9e3e97738b5abaefc1e3f1f927e7be55f37e7b40c
languageName: node
linkType: hard
@@ -6242,6 +6242,17 @@ __metadata:
languageName: node
linkType: hard
+"@octokit/plugin-paginate-rest@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "@octokit/plugin-paginate-rest@npm:6.0.0"
+ dependencies:
+ "@octokit/types": ^9.0.0
+ peerDependencies:
+ "@octokit/core": ">=4"
+ checksum: 5dbde9bc44d5b70f977d343af7eb65b1a3c6d7178dc52440e5dc565ba2bb772d84a43a235161ae022b59b6a48b089fab0d3aa58157e0636a12fbcead0dc19d84
+ languageName: node
+ linkType: hard
+
"@octokit/plugin-request-log@npm:^1.0.4":
version: 1.0.4
resolution: "@octokit/plugin-request-log@npm:1.0.4"
@@ -6252,14 +6263,14 @@ __metadata:
linkType: hard
"@octokit/plugin-rest-endpoint-methods@npm:^6.7.0":
- version: 6.7.0
- resolution: "@octokit/plugin-rest-endpoint-methods@npm:6.7.0"
+ version: 6.8.1
+ resolution: "@octokit/plugin-rest-endpoint-methods@npm:6.8.1"
dependencies:
- "@octokit/types": ^8.0.0
+ "@octokit/types": ^8.1.1
deprecation: ^2.3.1
peerDependencies:
"@octokit/core": ">=3"
- checksum: 4f6290cb405ad0a8e9f149a259836ef1bd2d82670571a108c613385e4fde1f940c265fa7047441f234f7b659934545a22b9feaba2b0ca5abeeeef94b7fc2859b
+ checksum: 1ab8d3042fac9673f7152a783551c60cdbd3fa1383e6fc026f0ab5aca9105419e1cfa12c6e7955b5904a8c7dc9d2da413b31f3f6c45f6fb048cfb378b4e3dd66
languageName: node
linkType: hard
@@ -6336,12 +6347,12 @@ __metadata:
languageName: node
linkType: hard
-"@octokit/types@npm:^8.0.0":
- version: 8.1.1
- resolution: "@octokit/types@npm:8.1.1"
+"@octokit/types@npm:^8.0.0, @octokit/types@npm:^8.1.1":
+ version: 8.2.1
+ resolution: "@octokit/types@npm:8.2.1"
dependencies:
"@octokit/openapi-types": ^14.0.0
- checksum: 0b908a047c3fc307e18b0da0a4312c26a31fb67aa30694945e9ecb3e7bb441480096ea984a7acda2d09a680f50dce52739632bd521aa1249c2020def8d389ad3
+ checksum: 85a97bca714b88ea0d34066b4821e48ba4f8dda8f3970f1a00deb02b3e3f1cc315720d25430082dc651c400717510273193ac6af610268488160bb9e6a30bef8
languageName: node
linkType: hard
@@ -7019,11 +7030,10 @@ __metadata:
"@babel/core": 7.20.12
"@babel/runtime-corejs3": 7.20.13
"@redwoodjs/auth": 3.2.0
- "@testing-library/react-hooks": 8.0.1
- "@types/react": 17.0.53
+ "@types/react": 18.0.27
core-js: 3.27.2
jest: 29.3.1
- react: 17.0.2
+ react: 18.2.0
typescript: 4.7.4
peerDependencies:
"@auth0/auth0-spa-js": 1.22.6
@@ -7072,12 +7082,11 @@ __metadata:
"@babel/core": 7.20.12
"@babel/runtime-corejs3": 7.20.13
"@redwoodjs/auth": 3.2.0
- "@testing-library/react-hooks": 8.0.1
"@types/netlify-identity-widget": 1.9.3
- "@types/react": 17.0.53
+ "@types/react": 18.0.27
core-js: 3.27.2
jest: 29.3.1
- react: 17.0.2
+ react: 18.2.0
typescript: 4.7.4
peerDependencies:
"@azure/msal-browser": 2.32.2
@@ -7125,11 +7134,10 @@ __metadata:
"@clerk/clerk-react": 3.5.1
"@clerk/types": 2.21.0
"@redwoodjs/auth": 3.2.0
- "@testing-library/react-hooks": 8.0.1
- "@types/react": 17.0.53
+ "@types/react": 18.0.27
core-js: 3.27.2
jest: 29.3.1
- react: 17.0.2
+ react: 18.2.0
typescript: 4.7.4
peerDependencies:
"@clerk/clerk-react": 3.5.1
@@ -7204,11 +7212,10 @@ __metadata:
"@redwoodjs/auth": 3.2.0
"@simplewebauthn/browser": 6.2.2
"@simplewebauthn/typescript-types": 6.2.1
- "@testing-library/react-hooks": 8.0.1
- "@types/react": 17.0.53
+ "@types/react": 18.0.27
core-js: 3.27.2
jest: 29.3.1
- react: 17.0.2
+ react: 18.2.0
typescript: 4.7.4
languageName: unknown
linkType: soft
@@ -7252,12 +7259,11 @@ __metadata:
"@babel/core": 7.20.12
"@babel/runtime-corejs3": 7.20.13
"@redwoodjs/auth": 3.2.0
- "@testing-library/react-hooks": 8.0.1
- "@types/react": 17.0.53
+ "@types/react": 18.0.27
core-js: 3.27.2
firebase: 9.16.0
jest: 29.3.1
- react: 17.0.2
+ react: 18.2.0
typescript: 4.7.4
peerDependencies:
firebase: 9.16.0
@@ -7304,12 +7310,11 @@ __metadata:
"@babel/core": 7.20.12
"@babel/runtime-corejs3": 7.20.13
"@redwoodjs/auth": 3.2.0
- "@testing-library/react-hooks": 8.0.1
"@types/netlify-identity-widget": 1.9.3
- "@types/react": 17.0.53
+ "@types/react": 18.0.27
core-js: 3.27.2
jest: 29.3.1
- react: 17.0.2
+ react: 18.2.0
typescript: 4.7.4
peerDependencies:
netlify-identity-widget: 1.9.2
@@ -7356,11 +7361,10 @@ __metadata:
"@babel/core": 7.20.12
"@babel/runtime-corejs3": 7.20.13
"@supabase/supabase-js": 1.35.7
- "@testing-library/react-hooks": 8.0.1
- "@types/react": 17.0.53
+ "@types/react": 18.0.27
core-js: 3.27.2
jest: 29.3.1
- react: 17.0.2
+ react: 18.2.0
typescript: 4.7.4
peerDependencies:
"@supabase/supabase-js": 1.35.7
@@ -7409,11 +7413,10 @@ __metadata:
"@babel/core": 7.20.12
"@babel/runtime-corejs3": 7.20.13
"@redwoodjs/auth": 3.2.0
- "@testing-library/react-hooks": 8.0.1
- "@types/react": 17.0.53
+ "@types/react": 18.0.27
core-js: 3.27.2
jest: 29.3.1
- react: 17.0.2
+ react: 18.2.0
typescript: 4.7.4
peerDependencies:
supertokens-auth-react: 0.30.2
@@ -7428,12 +7431,11 @@ __metadata:
"@babel/core": 7.20.12
"@babel/runtime-corejs3": 7.20.13
"@testing-library/jest-dom": 5.16.5
- "@testing-library/react": 12.1.5
- "@testing-library/react-hooks": 8.0.1
+ "@testing-library/react": 13.4.0
core-js: 3.27.2
jest: 29.3.1
msw: 0.49.3
- react: 17.0.2
+ react: 18.2.0
typescript: 4.7.4
languageName: unknown
linkType: soft
@@ -7664,24 +7666,24 @@ __metadata:
"@babel/runtime-corejs3": 7.20.13
"@testing-library/dom": 8.20.0
"@testing-library/jest-dom": 5.16.5
- "@testing-library/react": 12.1.5
+ "@testing-library/react": 13.4.0
"@testing-library/user-event": 14.4.3
"@types/pascalcase": 1.0.1
- "@types/react": 17.0.53
- "@types/react-dom": 17.0.18
+ "@types/react": 18.0.27
+ "@types/react-dom": 18.0.10
"@types/testing-library__jest-dom": 5.14.5
core-js: 3.27.2
graphql: 16.6.0
jest: 29.3.1
nodemon: 2.0.20
pascalcase: 1.0.0
- react: 17.0.2
- react-dom: 17.0.2
+ react: 18.2.0
+ react-dom: 18.2.0
react-hook-form: 7.42.1
typescript: 4.7.4
peerDependencies:
graphql: 16.6.0
- react: 17.0.2
+ react: 18.2.0
languageName: unknown
linkType: soft
@@ -7799,8 +7801,8 @@ __metadata:
mime-types: 2.1.35
typescript: 4.7.4
peerDependencies:
- react: 17.0.2
- react-dom: 17.0.2
+ react: 18.2.0
+ react-dom: 18.2.0
languageName: unknown
linkType: soft
@@ -7828,16 +7830,16 @@ __metadata:
"@babel/runtime-corejs3": 7.20.13
"@reach/skip-nav": 0.18.0
"@redwoodjs/auth": 3.2.0
- "@types/react": 17.0.53
- "@types/react-dom": 17.0.18
+ "@types/react": 18.0.27
+ "@types/react-dom": 18.0.10
core-js: 3.27.2
jest: 29.3.1
- react: 17.0.2
- react-dom: 17.0.2
+ react: 18.2.0
+ react-dom: 18.2.0
typescript: 4.7.4
peerDependencies:
- react: 17.0.2
- react-dom: 17.0.2
+ react: 18.2.0
+ react-dom: 18.2.0
languageName: unknown
linkType: soft
@@ -7922,15 +7924,14 @@ __metadata:
"@storybook/manager-webpack5": 6.5.15
"@storybook/react": 6.5.15
"@testing-library/jest-dom": 5.16.5
- "@testing-library/react": 12.1.5
- "@testing-library/react-hooks": 8.0.1
+ "@testing-library/react": 13.4.0
"@testing-library/user-event": 14.4.3
"@types/aws-lambda": 8.10.109
"@types/babel-core": 6.25.7
"@types/jest": 29.2.6
"@types/node": 16.18.11
- "@types/react": 17.0.53
- "@types/react-dom": 17.0.18
+ "@types/react": 18.0.27
+ "@types/react-dom": 18.0.10
"@types/webpack": 5.28.0
babel-jest: 29.3.1
babel-plugin-inline-react-svg: 2.0.1
@@ -7977,10 +7978,10 @@ __metadata:
"@babel/runtime-corejs3": 7.20.13
"@redwoodjs/auth": 3.2.0
"@testing-library/jest-dom": 5.16.5
- "@testing-library/react": 12.1.5
+ "@testing-library/react": 13.4.0
"@types/prop-types": 15.7.5
- "@types/react": 17.0.53
- "@types/react-dom": 17.0.18
+ "@types/react": 18.0.27
+ "@types/react-dom": 18.0.10
"@types/testing-library__jest-dom": 5.14.5
core-js: 3.27.2
graphql: 16.6.0
@@ -7988,8 +7989,8 @@ __metadata:
jest: 29.3.1
nodemon: 2.0.20
prop-types: 15.8.1
- react: 17.0.2
- react-dom: 17.0.2
+ react: 18.2.0
+ react-dom: 18.2.0
react-helmet-async: 1.3.0
react-hot-toast: 2.4.0
stacktracey: 2.1.8
@@ -7997,8 +7998,8 @@ __metadata:
typescript: 4.7.4
peerDependencies:
prop-types: 15.8.1
- react: 17.0.2
- react-dom: 17.0.2
+ react: 18.2.0
+ react-dom: 18.2.0
bin:
build-storybook: ./dist/bins/build-storybook.js
cross-env: ./dist/bins/cross-env.js
@@ -9438,7 +9439,7 @@ __metadata:
languageName: node
linkType: hard
-"@testing-library/dom@npm:8.20.0, @testing-library/dom@npm:^8.0.0, @testing-library/dom@npm:^8.11.1":
+"@testing-library/dom@npm:8.20.0, @testing-library/dom@npm:^8.11.1, @testing-library/dom@npm:^8.5.0":
version: 8.20.0
resolution: "@testing-library/dom@npm:8.20.0"
dependencies:
@@ -9471,39 +9472,17 @@ __metadata:
languageName: node
linkType: hard
-"@testing-library/react-hooks@npm:8.0.1":
- version: 8.0.1
- resolution: "@testing-library/react-hooks@npm:8.0.1"
+"@testing-library/react@npm:13.4.0":
+ version: 13.4.0
+ resolution: "@testing-library/react@npm:13.4.0"
dependencies:
"@babel/runtime": ^7.12.5
- react-error-boundary: ^3.1.0
+ "@testing-library/dom": ^8.5.0
+ "@types/react-dom": ^18.0.0
peerDependencies:
- "@types/react": ^16.9.0 || ^17.0.0
- react: ^16.9.0 || ^17.0.0
- react-dom: ^16.9.0 || ^17.0.0
- react-test-renderer: ^16.9.0 || ^17.0.0
- peerDependenciesMeta:
- "@types/react":
- optional: true
- react-dom:
- optional: true
- react-test-renderer:
- optional: true
- checksum: 83bef2d4c437b84143213b5275ef00ef14e5bcd344f9ded12b162d253dc3c799138ead4428026b9c725e5a38dbebf611f2898aa43f3e43432bcaccbd7bf413e5
- languageName: node
- linkType: hard
-
-"@testing-library/react@npm:12.1.5":
- version: 12.1.5
- resolution: "@testing-library/react@npm:12.1.5"
- dependencies:
- "@babel/runtime": ^7.12.5
- "@testing-library/dom": ^8.0.0
- "@types/react-dom": <18.0.0
- peerDependencies:
- react: <18.0.0
- react-dom: <18.0.0
- checksum: 3c2433d2fdb6535261f62cd85d79657989cebd96f9072da03c098a1cfa56dec4dfec83d7c2e93633a3ccebdb178ea8578261533d11551600966edab77af00c8b
+ react: ^18.0.0
+ react-dom: ^18.0.0
+ checksum: 371bf982dd0deb27da004f368b06904353eac0f23f9c08ff0f24443c3f51a6d647009e366034417565d2484c40f1c7eff74413738abf4ec55209da9bd3253b0e
languageName: node
linkType: hard
@@ -10367,23 +10346,23 @@ __metadata:
languageName: node
linkType: hard
-"@types/react-dom@npm:17.0.18, @types/react-dom@npm:<18.0.0":
- version: 17.0.18
- resolution: "@types/react-dom@npm:17.0.18"
+"@types/react-dom@npm:18.0.10, @types/react-dom@npm:^18.0.0":
+ version: 18.0.10
+ resolution: "@types/react-dom@npm:18.0.10"
dependencies:
- "@types/react": ^17
- checksum: a787471157d66e834ee2afa57d81171c8cae26d3b0def23709da8256433d0b3c5c9f35c03913c9c4137f79acf78af9e2483ee1578197f77298344f33b7186791
+ "@types/react": "*"
+ checksum: a07b900a2d5559830f88b3e525cf279f9f04b4893f4d17e64f5adb08d8abe0e3151e0d3c0ea17d836104ae47594be577529a004265600e4304a43a93b0d5d61e
languageName: node
linkType: hard
-"@types/react@npm:17.0.53":
- version: 17.0.53
- resolution: "@types/react@npm:17.0.53"
+"@types/react@npm:*, @types/react@npm:18.0.27":
+ version: 18.0.27
+ resolution: "@types/react@npm:18.0.27"
dependencies:
"@types/prop-types": "*"
"@types/scheduler": "*"
csstype: ^3.0.2
- checksum: 4ff3fa58ab32deefacdbd0ee002e294548391238ce2dea2cad213e11b4cc61480be48cb2b7ed3c53220ee1a5b9cadf3417a20db817ab2ca4669c9a4a45042b92
+ checksum: 87711931b14cdca07c4149531b4c96e7a56609ed2d010c52bf6bde14b417ac128c326924b14b25667fdaeddacfe98c31fa9625a95af52dae45061df8e30b46a3
languageName: node
linkType: hard
@@ -26728,7 +26707,7 @@ __metadata:
languageName: node
linkType: hard
-"prop-types@npm:15.8.1":
+"prop-types@npm:15.8.1, prop-types@npm:^15.0.0, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
version: 15.8.1
resolution: "prop-types@npm:15.8.1"
dependencies:
@@ -27168,16 +27147,15 @@ __metadata:
languageName: node
linkType: hard
-"react-dom@npm:17.0.2":
- version: 17.0.2
- resolution: "react-dom@npm:17.0.2"
+"react-dom@npm:18.2.0":
+ version: 18.2.0
+ resolution: "react-dom@npm:18.2.0"
dependencies:
loose-envify: ^1.1.0
- object-assign: ^4.1.1
- scheduler: ^0.20.2
+ scheduler: ^0.23.0
peerDependencies:
- react: 17.0.2
- checksum: 51abbcb72450fe527ebf978c3bc989ba266630faaa53f47a2fae5392369729e8de62b2e4683598cbe651ea7873cd34ec7d5127e2f50bf4bfe6bd0c3ad9bddcb0
+ react: ^18.2.0
+ checksum: 66dfc5f93e13d0674e78ef41f92ed21dfb80f9c4ac4ac25a4b51046d41d4d2186abc915b897f69d3d0ebbffe6184e7c5876f2af26bfa956f179225d921be713a
languageName: node
linkType: hard
@@ -27195,17 +27173,6 @@ __metadata:
languageName: node
linkType: hard
-"react-error-boundary@npm:^3.1.0":
- version: 3.1.4
- resolution: "react-error-boundary@npm:3.1.4"
- dependencies:
- "@babel/runtime": ^7.12.5
- peerDependencies:
- react: ">=16.13.1"
- checksum: f977ca61823e43de2381d53dd7aa8b4d79ff6a984c9afdc88dc44f9973b99de7fd382d2f0f91f2688e24bb987c0185bf45d0b004f22afaaab0f990a830253bfb
- languageName: node
- linkType: hard
-
"react-fast-compare@npm:^3.2.0":
version: 3.2.0
resolution: "react-fast-compare@npm:3.2.0"
@@ -27310,13 +27277,12 @@ __metadata:
languageName: node
linkType: hard
-"react@npm:17.0.2":
- version: 17.0.2
- resolution: "react@npm:17.0.2"
+"react@npm:18.2.0":
+ version: 18.2.0
+ resolution: "react@npm:18.2.0"
dependencies:
loose-envify: ^1.1.0
- object-assign: ^4.1.1
- checksum: 07ae8959acf1596f0550685102fd6097d461a54a4fd46a50f88a0cd7daaa97fdd6415de1dcb4bfe0da6aa43221a6746ce380410fa848acc60f8ac41f6649c148
+ checksum: b562d9b569b0cb315e44b48099f7712283d93df36b19a39a67c254c6686479d3980b7f013dc931f4a5a3ae7645eae6386b4aa5eea933baa54ecd0f9acb0902b8
languageName: node
linkType: hard
@@ -28233,8 +28199,7 @@ __metadata:
"@playwright/test": 1.29.2
"@replayio/playwright": 0.3.15
"@testing-library/jest-dom": 5.16.5
- "@testing-library/react": 12.1.5
- "@testing-library/react-hooks": 8.0.1
+ "@testing-library/react": 13.4.0
"@testing-library/user-event": 14.4.3
"@tsd/typescript": 4.9.4
"@types/babel__generator": 7.6.4
@@ -28436,13 +28401,12 @@ __metadata:
languageName: node
linkType: hard
-"scheduler@npm:^0.20.2":
- version: 0.20.2
- resolution: "scheduler@npm:0.20.2"
+"scheduler@npm:^0.23.0":
+ version: 0.23.0
+ resolution: "scheduler@npm:0.23.0"
dependencies:
loose-envify: ^1.1.0
- object-assign: ^4.1.1
- checksum: b0982e4b0f34f4ffa4f2f486161c0fd9ce9b88680b045dccbf250eb1aa4fd27413570645455187a83535e2370f5c667a251045547765408492bd883cbe95fcdb
+ checksum: b777f7ca0115e6d93e126ac490dbd82642d14983b3079f58f35519d992fa46260be7d6e6cede433a92db70306310c6f5f06e144f0e40c484199e09c1f7be53dd
languageName: node
linkType: hard
@@ -30876,7 +30840,17 @@ __metadata:
languageName: node
linkType: hard
-"typescript@patch:typescript@npm%3A4.7.4#~builtin":
+"typescript@npm:^3 || ^4":
+ version: 4.9.4
+ resolution: "typescript@npm:4.9.4"
+ bin:
+ tsc: bin/tsc
+ tsserver: bin/tsserver
+ checksum: 5008b97a2a3afdbe57ea70e504ebc8ec98f18d888059dfb7932a41f566a1360a28afc8de2a440fd6143b4014cc6d2616079931dc690c7513c2d21fa53957e0ec
+ languageName: node
+ linkType: hard
+
+"typescript@patch:typescript@4.7.4#~builtin":
version: 4.7.4
resolution: "typescript@patch:typescript@npm%3A4.7.4#~builtin::version=4.7.4&hash=65a307"
bin:
@@ -30886,6 +30860,16 @@ __metadata:
languageName: node
linkType: hard
+"typescript@patch:typescript@^3 || ^4#~builtin":
+ version: 4.9.4
+ resolution: "typescript@patch:typescript@npm%3A4.9.4#~builtin::version=4.9.4&hash=ad5954"
+ bin:
+ tsc: bin/tsc
+ tsserver: bin/tsserver
+ checksum: a98c97a7abb391a00c51a427b074ab58c02df490358b7db7c3f4cc4fceb6d620457a0ef5d58e1c8db08fcb4ece9f3ba656cbfef3f81c12a383b0b8df8f198c7c
+ languageName: node
+ linkType: hard
+
"ua-parser-js@npm:^0.7.30":
version: 0.7.32
resolution: "ua-parser-js@npm:0.7.32"