From f19ab8e9dd5efa1f905ed25224739ee964d1711b Mon Sep 17 00:00:00 2001 From: Daniel Choudhury Date: Tue, 23 Jan 2024 23:19:29 +0700 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d35207faae85b02fe60baf929e203bfe34c725bb Author: Daniel Choudhury Date: Tue Jan 23 22:59:56 2024 +0700 Remove this.init from inside class, call them in the tests instead commit d4ce8557af3a62a4cc15e2d148cd121924a1f527 Merge: ed74729d2 fca8d7add Author: Daniel Choudhury Date: Mon Jan 22 22:23:24 2024 +0700 Merge branch 'main' into feat/dbauth-fetch-handler commit ed74729d2e4750d72eff56f62560708a549825e4 Merge: 8fdbec056 b8a5e5345 Author: Daniel Choudhury Date: Mon Jan 22 16:04:02 2024 +0700 Merge branch 'main' into feat/dbauth-fetch-handler commit 8fdbec056187ac2c9ea2b3a4894f5bc05be52308 Merge: 61d4664f8 74a9b0add Author: Daniel Choudhury Date: Mon Jan 22 10:56:29 2024 +0700 Merge branch 'main' into feat/dbauth-fetch-handler commit 61d4664f86a057dcddc0d1911a8d74ea1d47ad53 Merge: b32eca708 7491bdfd5 Author: Daniel Choudhury Date: Sun Jan 21 17:53:18 2024 +0700 Merge branch 'feat/dbauth-fetch-handler' of github.com:dac09/redwood into feat/dbauth-fetch-handler * 'feat/dbauth-fetch-handler' of github.com:dac09/redwood: commit b32eca708569fdad61240899a052811655dbd863 Author: Daniel Choudhury Date: Sun Jan 21 17:52:57 2024 +0700 Fix merge after vitest commit 590062937019da46a27a2ba31fdc40e5843696ba Merge: bf2b58979 41ac72814 Author: Daniel Choudhury Date: Sun Jan 21 17:48:07 2024 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into feat/dbauth-fetch-handler * 'main' of github.com:redwoodjs/redwood: feat(server file): add `createServer` (#9845) chore(crwa): set `REDWOOD_CI` and `REDWOOD_DISABLE_TELEMETRY` (#9857) Fix(crwa): Exit 0 after Quit install (#9856) chore(crwa): switch to vitest (#9855) chore(api): Switch to use vitest over jest (#9853) fix(server): ensure consistency between CLI serve entrypoints regarding help and strict (#9809) Improve how the api-server watch command works (#9841) docs(typo): correct grammar in realtime docs (#9850) Add support for Prisma Bytes and GraphQL scalar Byte (#9847) packages/cli: Switch from substr (deprecated) to slice (#9849) commit 7491bdfd5c6f1cea5e6c87f51b87bea2c9739b11 Merge: abf3a9576 41ac72814 Author: Daniel Choudhury Date: Sun Jan 21 16:36:13 2024 +0700 Merge branch 'main' into feat/dbauth-fetch-handler commit abf3a9576faf614b8726de9d4041979c39efc894 Merge: bf2b58979 b759ad1aa Author: Daniel Choudhury Date: Fri Jan 19 16:20:01 2024 +0700 Merge branch 'main' into feat/dbauth-fetch-handler commit bf2b58979df01aa7262afb27d81fa19092ba0c87 Author: Daniel Choudhury Date: Fri Jan 19 16:18:43 2024 +0700 Remove unused function commit 06c07dcddc8bf6c5b58bcf965027224ba08c45b5 Author: Daniel Choudhury Date: Fri Jan 19 16:16:55 2024 +0700 Undo bearer token change commit 38b3584e1d5f6412203856a2429efdeee11f2200 Author: Daniel Choudhury Date: Fri Jan 19 16:14:17 2024 +0700 Remove old comment commit 2bdb5e066bd84b2980d2445daf5da26137475750 Author: Daniel Choudhury Date: Fri Jan 19 16:03:11 2024 +0700 Cleanup, update shared.test commit 3cdb37d15e212a6cb027b9f13998140621ecac17 Author: Daniel Choudhury Date: Fri Jan 19 01:48:47 2024 +0700 Update packages/auth-providers/dbAuth/api/src/decoder.ts commit 875080010a50fa1d458eeb71e4235097e6d73032 Author: Daniel Choudhury Date: Fri Jan 19 01:13:54 2024 +0700 FIX ALL THE TESTS! commit d773116f02b1093545058f02c5637659be3b2c6b Merge: 6a31c004a 6d74a227d Author: Daniel Choudhury Date: Fri Jan 19 00:57:31 2024 +0700 Merge main commit 6a31c004a2c03e806213bb4d3a17b02f938a4b0c Author: Daniel Choudhury Date: Tue Jan 16 14:33:21 2024 +0700 Just keep the dbAuth fetch-api related changes, revert everything else commit c3a2ebb690c9980310889e0d1d1a7a40c2b06057 Merge: be84acec6 d9892f4cc Author: Daniel Choudhury Date: Tue Jan 16 13:51:39 2024 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into feat/dbauth-fetch-handler * 'main' of github.com:redwoodjs/redwood: Add missing cli-helpers test file (#9833) Add cli-helpers util to update redwood.toml (#9832) Tweak graphiql setup messages (#9831) exp setup sentry: Fix file extension (#9829) Fastify config: Use exact file extension in log message (#9828) Remove unused Fastify plugin (#9827) Add trusted-documents to fragments CI smoke-test (#9826) prerender: Enable Trusted Documents support (#9825) trustedDocuments.test.ts: Format source cli: add missing dep jscodeshift (#9823) graphql setup fragments: Move telemetry to main handler (#9819) feat: Adds Setup CLI Command to Configure GraphQL Trusted Documents (#9800) Update cli tsconfig to reference used packages (#9822) fragments setup: newline fix + refactor->rename (#9821) yarn rw setup graphql fragments (#9811) commit be84acec664748401551cc521eec6a8871b8a8e8 Author: Daniel Choudhury Date: Tue Jan 16 13:51:10 2024 +0700 Restore unneeded changes commit 5ce187028d8af18e6f1f43504275a18a6132c314 Merge: 0d62479bc 80e4a4f56 Author: Daniel Choudhury Date: Tue Jan 9 11:51:41 2024 +0600 Merge branch 'main' of github.com:redwoodjs/redwood into feat/dbauth-cookie+generic-handler * 'main' of github.com:redwoodjs/redwood: chore: Improved Possible Types DX and Framework integration for GraphQL Fragments with Union and Interface support (#9594) fix(server): error early on incompatible config (apiHost and apiUrl) (#9808) chore(esm): convert crwa to esm and bundle (#9786) chore(cli): More robust isAwaitable (#9806) chore(ci): Update task names to say "node 20" (#9805) Use TS for rebuild-test-project-fixture script (#9804) chore: bump TSTyche (#9803) docs(fragments): Typo, grammar and formatting fixes (#9802) Revert accidental changes to test-project chore(deps): update dependency @apollo/experimental-nextjs-app-support to v0.5.2 (#9716) fix(deps): update dependency react-helmet-async to v2 (#9697) fix(deps): update dependency sqlite to v5 (#9698) data migrate: Clean up upHandler test (#9796) chore(data-migration): Fix test exit code (#9795) Add routeParams to useMatch (#9793) fix(fastify): Prevent duplicate `@fastify/url-data` registration (#9794) useRoutePath(): Get the path for the current route by default (#9790) Router: Use a single RouterContext (#9792) commit 0d62479bcf764d495ff1d69e86820a00f4495211 Author: Daniel Choudhury Date: Thu Jan 4 14:39:48 2024 +0700 ServerAuthState types and stuff Inject initial server auth state on ssr commit d25ed51ba66eb1df9da9de8a2fa93f1ab0dd37c0 Merge: 9b1affd4c 3e08e20ac Author: Daniel Choudhury Date: Wed Jan 3 13:18:27 2024 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into feat/dbauth-cookie+generic-handler * 'main' of github.com:redwoodjs/redwood: chore: yarn install to update `yarn.lock` (follow up to #9669) chore(deps): update dependency @envelop/core to v5 (#9669) Use regex to make test pass in VSCode (#9791) fix(dbAuth): Correct hardcoded DB column (#9788) fix(deps): update dependency graphql-yoga to v5 (#9688) commit 9b1affd4c1a6488a21423a5c28291b218b959b97 Merge: e05a906ac 1075258d6 Author: Daniel Choudhury Date: Tue Jan 2 13:41:53 2024 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into feat/dbauth-cookie+generic-handler * 'main' of github.com:redwoodjs/redwood: (125 commits) chore(release-tooling): Reminder to update Algolia chore(release-tooling): Add note about generating release notes chore(release-tooling): Add more detailed instructions for after releasing chore(release-tooling): Fix PR count message fix(crwa): use `fs.renameSync` instead of `fs.rename` (#9787) chore(release-tooling): Update to node 20 in version check chore(deps): bump @adobe/css-tools from 4.3.1 to 4.3.2 in /__fixtures__/example-todo-main (#9785) chore(crwa): add e2e tests for create-redwood-app (#9783) chore(release-tooling): fetch -> pull (#9784) feat(scaffold/cell): Adds TypedDocument Support to Cell and Scaffold Generators (#9693) fix: Support Custom Id Field Names in when generating Cells (#9778) chore(framework-tools): .gitignore (#9782) Use build:pack for dbauth when rebuilding the test project (#9781) chore(test-project): Fix test-project generation script, and regenerate fixture (#9779) Fix dbAuth allowUserFields initialization syntax (#9780) chore(framework-tools): add `project:tarsync` script (#9766) fix(otel): Fix OTel sdk loading (#9777) fix: Fixes way OpenTelemetry setup template uses project-config for port setting (#9775) chore(router): Miniscule fixes chore(router): Move useMatch to its own file (#9770) ... commit e05a906ac32047b0c394601e32ef6124a1320755 Author: Daniel Choudhury Date: Thu Dec 28 14:33:11 2023 +0700 Add nx to gitignore commit 4e268aaa0ea88526de9753617b89202d63f1566b Author: Daniel Choudhury Date: Mon Dec 25 14:38:11 2023 +0700 Refactor and reuse getEventHeader Improve Fetch Request detection commit 5e0c1c2bcf67ad093600d40ed43883a9e695f316 Author: Daniel Choudhury Date: Mon Dec 25 13:26:11 2023 +0700 Change detection of fetch event commit fe40f6120188169838b8407da64f2af929bce693 Author: Daniel Choudhury Date: Fri Dec 22 18:09:11 2023 +0700 Cleanup isFetchRequest commit 1a3cbd4125befc2baa57139910c52778104479c4 Author: Daniel Choudhury Date: Fri Dec 22 14:41:48 2023 +0700 Undo decoder type changes commit 097972530692732c847f01009f5c61d127d73d08 Author: Daniel Choudhury Date: Fri Dec 22 14:36:20 2023 +0700 Get it working with middleware! commit 3f0a32b98b7848ca0bdc21bb84a1648bee728fe1 Author: Daniel Choudhury Date: Fri Dec 22 13:28:51 2023 +0700 Fix more tests Normalize request differently to be more compatible commit 82badfd2bb08fa6977a35b610fecbd41f6c2b3fd Author: Daniel Choudhury Date: Wed Dec 20 14:44:10 2023 +0700 Fix authContext tests and dbauth handler commit 67c4ace57ef4745f03ff31838a95f1f29fcff3c2 Author: Daniel Choudhury Date: Mon Dec 11 14:46:57 2023 +0700 I think I have it working with failing tests commit b275d9f11d5f7a65bd6083eeb559118e8581db8a Author: Daniel Choudhury Date: Fri Dec 8 11:05:23 2023 +0700 Fix building! commit 0542ca7b6651d0ba69be239f5f9bbd22f2ae5f8f Merge: 37adfa502 fb3f1fb52 Author: Daniel Choudhury Date: Fri Dec 8 10:50:56 2023 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into try/dbauth-ssr-updated-forward-cookies * 'main' of github.com:redwoodjs/redwood: (163 commits) chore(deps): update dependency @clerk/clerk-react to v4.28.3 (#9643) fix(deps): update prisma monorepo to v5.7.0 (#9642) fix(CLI): merge NODE_OPTIONS in `yarn rw dev` (#9585) chore(release): configure aloglia to index docs chore(release): handle OTP for lerna publish RSC: No need to patch Vite anymore (#9636) RSC: Remove unused code. Improve code organization (#9631) chore(release): improve tooling chore: Linting and disable some console logs (#9635) chore: Update Testing documentation to link to How to Test Email/Mailer (#9634) chore(release): fix open answer Add vscode web debugger and compound (#9567) RSC: Use Routes.tsx for (client-side) routing (#9630) RSC: Add RW env var definitions to Vite config and include FatalErrorBoundary (#9622) chore(release): add notes on #9624 chore(release): add release:notes scripts, fix docs chore(deps): update dependency @clerk/clerk-react to v4.28.2 (#9625) fix(deps): update dependency @vitejs/plugin-react to v4.2.1 (#9626) fix(deps): update dependency vite to v4.5.1 (#9627) fix(deps): update storybook monorepo to v7.6.3 (#9628) ... commit 37adfa502772ba5428f3393967a679280bd9dd99 Author: Daniel Choudhury Date: Mon Nov 20 16:05:31 2023 +0700 Make it forward cookies from authState commit a8f0e33d29fd499918730d22f20edee898c94cc8 Author: Daniel Choudhury Date: Wed Nov 15 22:52:00 2023 +0700 Fix some merged changes commit 4bb543af47aa24eaf2e1df57375ddc758da3fa81 Merge: 2b66173bd bbe222615 Author: Daniel Choudhury Date: Wed Nov 15 22:51:44 2023 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into try/dbauth-ssr-updated * 'main' of github.com:redwoodjs/redwood: (80 commits) fix(deps): update dependency @fastify/http-proxy to v9.3.0 (#9451) fix(deps): update dependency @fastify/static to v6.12.0 (#9452) chore: migrate type tests to TSTyche (#9394) fix(deps): update dependency @testing-library/user-event to v14.5.1 (#9455) fix(deps): update dependency @vitejs/plugin-react to v4.1.1 (#9456) fix(deps): update dependency pino to v8.16.1 (#9459) fix(deps): update dependency firebase-admin to v11.11.0 (#9458) chore(deps): update dependency firebase to v10.6.0 (#9449) fix(deps): update dependency @fastify/url-data to v5.4.0 (#9453) fix(deps): update dependency @simplewebauthn/browser to v7.4.0 (#9454) chore(deps): update actions/setup-node action to v4 (#9461) chore(deps): update actions/checkout action to v4 (#9460) fix(deps): update dependency @graphql-yoga/plugin-graphql-sse to v2.0.5 (#9440) fix(deps): update prisma monorepo to v5.6.0 (#9447) fix(deps): update dependency nodemailer to v6.9.7 (#9444) chore(deps): update dependency esbuild to v0.19.5 (#9359) fix(deps): update dependency @envelop/on-resolve to v3.0.3 (#9436) fix(deps): update dependency semver to v7.5.4 (#9445) fix(deps): update dependency jsonwebtoken to v9.0.2 (#9443) fix(deps): update dependency systeminformation to v5.21.17 (#9446) ... commit 2b66173bdfe9a1df755489330beb54e9d13f09b0 Author: Daniel Choudhury Date: Wed Nov 15 21:48:27 2023 +0700 Get it building again commit 9fafcf8b116701ecfb8d432ecd42ec76785ccfd0 Author: Daniel Choudhury Date: Thu Nov 2 23:50:43 2023 +0700 SHIP IT commit bb0b36ec6462782e1fcadf8ea87912356bcd6e85 Merge: 5f1deedf9 7ab07a25c Author: Daniel Choudhury Date: Thu Nov 2 22:23:40 2023 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into try/dbauth-ssr * 'main' of github.com:redwoodjs/redwood: (26 commits) fix(api-server): copy fallback fix from #9272 (#9369) fix(deps): update dependency concurrently to v8.2.2 (#9361) chore(k6): Fix function context test (#9368) feat(cli): Setup command for mailer (#9335) feature: Support defer and stream GraphQL Directives in RedwoodRealtime (#9235) chore(deps): update dependency rimraf to v5.0.5 (#9360) chore(k6): Fix function context test (#9358) chore(deps): bump undici from 5.22.1 to 5.26.3 (#9307) fix(babel): Fix opentelemetry api wrapping and allow it to be disabled (#9298) chore(api-server): remove server survey tests in CI (#9348) chore(deps): update babel monorepo to v7.23.2 (#9344) chore(deps): bump @babel/traverse from 7.18.9 to 7.23.2 in /docs (#9311) chore(deps): update dependency @tsconfig/docusaurus to v2 (#9347) fix(deps): update dependency react-player to v2.13.0 (#9346) fix(deps): update docusaurus monorepo to v2.4.3 (#9345) fix(deps): update dependency @babel/traverse to v7.23.2 [security] (#9322) chore: increase server test timeout, fix `yarn build:clean` (#9336) feature: Adds utility functions to add envars and update Redwood toml for plugin packages to cli helpers for use in simplifying CLI setup commands (#9324) fix(cli): Tailwind setup updates `scaffold.css` when needed (#9290) fix(cli): Exit with non-zero exit code when `yarn rw g types` has errors (#9280) ... commit 5f1deedf998c5e798e2e1ad1de084d2097ff299e Author: Daniel Choudhury Date: Thu Oct 26 12:57:44 2023 +0700 NOT WORKING: try extracting session passed into a cookie commit 9e8613504f0992bd13ba48e2bb52a6ab7d75e016 Author: Daniel Choudhury Date: Wed Oct 25 12:48:33 2023 +0700 Simple auth state parsing with middleware in entry server Squashed commit of the following: commit 616bd225a743edbcdad6ad12f781baf10ab6bb86 Author: Daniel Choudhury Date: Tue Jan 23 23:33:24 2024 +0700 Also convert fetch handler test to vitest commit 81b787fb1def4577d7358fd13282b0ac665a4111 Merge: d35207faa 352af6200 Author: Daniel Choudhury Date: Tue Jan 23 23:33:09 2024 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into feat/dbauth-fetch-handler * 'main' of github.com:redwoodjs/redwood: chore(auth-providers): switch to vitest (mostly) (#9869) chore(esm): convert `@redwoodjs/project-config` to ESM (#9870) fix(createServer): use addHook instead of ready (#9871) commit d35207faae85b02fe60baf929e203bfe34c725bb Author: Daniel Choudhury Date: Tue Jan 23 22:59:56 2024 +0700 Remove this.init from inside class, call them in the tests instead commit 352af6200db41fd26ed78559c6c41bb421c8b649 Author: Josh GM Walker <56300765+Josh-Walker-GM@users.noreply.github.com> Date: Mon Jan 22 22:03:28 2024 +0000 chore(auth-providers): switch to vitest (mostly) (#9869) This PR updates the auth providers with the exception of two: 1. `@redwoodjs/auth-firebase-web` It contains jest specific code for specifically resolving uuid to CJS. I'm sure it's possible to switch it over but I have not yet tried. 3. `@redwoodjs/auth-dbauth-web` I encountered errors that WebAuthn was not supported within the test environment. Even with the `jsdom` environment set. commit 68ed27abc07d23e9292123b9c2d13d421ffb5e67 Author: Dominic Saadi Date: Mon Jan 22 13:22:38 2024 -0800 chore(esm): convert `@redwoodjs/project-config` to ESM (#9870) I'm still working through a few things. The motivation for tackling `@redwoodjs/project-config` first was 1) most of our other package's depend on it 2) it's small 3) it would make merging the PR that converts the CLI's Jest tests to Vitest easier because Vitest can't mock require (see https://github.com/redwoodjs/redwood/pull/9863). I used [`arethetypeswrong/cli`](https://github.com/arethetypeswrong/arethetypeswrong.github.io) extensively. Right now I'm deeming the "Masquerading as ESM" error it emits acceptable. The code between the ESM and CJS files doesn't differ in functionality, only syntax; shipping two declaration copies of all the declaration files is shipping extra code. Mark Erikson did something similar at first at least here: > Unfortunately, no build tool that I knew of at that time did this by default, and the idea of shipping 99%-duplicate typedefs bothered me. So, I opted to not try to fix this "FalseCJS" issue for our packages (at least for the time being). (Source: https://blog.isquaredsoftware.com/2023/08/esm-modernization-lessons/#typescript-declarations.) Note that FalseCJS's fancier name is "Masquerading as CJS". We have "Masquerading as ESM", not CJS. I'm not sure if it's an issue that it's flipped yet. ``` $ attw ./redwoodjs-project-config.tgz @redwoodjs/project-config v6.0.7 Build tools: - typescript@5.3.3 - esbuild@0.19.9 👺 Import resolved to an ESM type declaration file, but a CommonJS JavaScript file. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/FalseESM.md ┌───────────────────┬─────────────────────────────┐ │ │ "@redwoodjs/project-config" │ ├───────────────────┼─────────────────────────────┤ │ node10 │ 🟢 │ ├───────────────────┼─────────────────────────────┤ │ node16 (from CJS) │ 👺 Masquerading as ESM │ ├───────────────────┼─────────────────────────────┤ │ node16 (from ESM) │ 🟢 (ESM) │ ├───────────────────┼─────────────────────────────┤ │ bundler │ 🟢 │ └───────────────────┴─────────────────────────────┘ ``` Regarding the `.js` extensions (which are necessary for relative imports in ESM) in TS code, see https://github.com/redwoodjs/redwood/pull/8456. commit 49347fd79c14ad8d18ca25b6ed9606ad44dfa416 Author: Dominic Saadi Date: Mon Jan 22 12:08:01 2024 -0800 fix(createServer): use addHook instead of ready (#9871) Fixes the issue @Tobbe and I were seeing in studio: ``` ~/redwood-project/node_modules/avvio/boot.js:244 throw new AVV_ERR_ROOT_PLG_BOOTED() ^ AvvioError [Error]: Root plugin has already booted ... ``` `fastify.ready` actually starts the server. All this is doing is logging. We want to use `addHook` instead. Follow up to https://github.com/redwoodjs/redwood/pull/9845. commit d4ce8557af3a62a4cc15e2d148cd121924a1f527 Merge: ed74729d2 fca8d7add Author: Daniel Choudhury Date: Mon Jan 22 22:23:24 2024 +0700 Merge branch 'main' into feat/dbauth-fetch-handler commit ed74729d2e4750d72eff56f62560708a549825e4 Merge: 8fdbec056 b8a5e5345 Author: Daniel Choudhury Date: Mon Jan 22 16:04:02 2024 +0700 Merge branch 'main' into feat/dbauth-fetch-handler commit 8fdbec056187ac2c9ea2b3a4894f5bc05be52308 Merge: 61d4664f8 74a9b0add Author: Daniel Choudhury Date: Mon Jan 22 10:56:29 2024 +0700 Merge branch 'main' into feat/dbauth-fetch-handler commit 61d4664f86a057dcddc0d1911a8d74ea1d47ad53 Merge: b32eca708 7491bdfd5 Author: Daniel Choudhury Date: Sun Jan 21 17:53:18 2024 +0700 Merge branch 'feat/dbauth-fetch-handler' of github.com:dac09/redwood into feat/dbauth-fetch-handler * 'feat/dbauth-fetch-handler' of github.com:dac09/redwood: commit b32eca708569fdad61240899a052811655dbd863 Author: Daniel Choudhury Date: Sun Jan 21 17:52:57 2024 +0700 Fix merge after vitest commit 590062937019da46a27a2ba31fdc40e5843696ba Merge: bf2b58979 41ac72814 Author: Daniel Choudhury Date: Sun Jan 21 17:48:07 2024 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into feat/dbauth-fetch-handler * 'main' of github.com:redwoodjs/redwood: feat(server file): add `createServer` (#9845) chore(crwa): set `REDWOOD_CI` and `REDWOOD_DISABLE_TELEMETRY` (#9857) Fix(crwa): Exit 0 after Quit install (#9856) chore(crwa): switch to vitest (#9855) chore(api): Switch to use vitest over jest (#9853) fix(server): ensure consistency between CLI serve entrypoints regarding help and strict (#9809) Improve how the api-server watch command works (#9841) docs(typo): correct grammar in realtime docs (#9850) Add support for Prisma Bytes and GraphQL scalar Byte (#9847) packages/cli: Switch from substr (deprecated) to slice (#9849) commit 7491bdfd5c6f1cea5e6c87f51b87bea2c9739b11 Merge: abf3a9576 41ac72814 Author: Daniel Choudhury Date: Sun Jan 21 16:36:13 2024 +0700 Merge branch 'main' into feat/dbauth-fetch-handler commit abf3a9576faf614b8726de9d4041979c39efc894 Merge: bf2b58979 b759ad1aa Author: Daniel Choudhury Date: Fri Jan 19 16:20:01 2024 +0700 Merge branch 'main' into feat/dbauth-fetch-handler commit bf2b58979df01aa7262afb27d81fa19092ba0c87 Author: Daniel Choudhury Date: Fri Jan 19 16:18:43 2024 +0700 Remove unused function commit 06c07dcddc8bf6c5b58bcf965027224ba08c45b5 Author: Daniel Choudhury Date: Fri Jan 19 16:16:55 2024 +0700 Undo bearer token change commit 38b3584e1d5f6412203856a2429efdeee11f2200 Author: Daniel Choudhury Date: Fri Jan 19 16:14:17 2024 +0700 Remove old comment commit 2bdb5e066bd84b2980d2445daf5da26137475750 Author: Daniel Choudhury Date: Fri Jan 19 16:03:11 2024 +0700 Cleanup, update shared.test commit 3cdb37d15e212a6cb027b9f13998140621ecac17 Author: Daniel Choudhury Date: Fri Jan 19 01:48:47 2024 +0700 Update packages/auth-providers/dbAuth/api/src/decoder.ts commit 875080010a50fa1d458eeb71e4235097e6d73032 Author: Daniel Choudhury Date: Fri Jan 19 01:13:54 2024 +0700 FIX ALL THE TESTS! commit d773116f02b1093545058f02c5637659be3b2c6b Merge: 6a31c004a 6d74a227d Author: Daniel Choudhury Date: Fri Jan 19 00:57:31 2024 +0700 Merge main commit 6a31c004a2c03e806213bb4d3a17b02f938a4b0c Author: Daniel Choudhury Date: Tue Jan 16 14:33:21 2024 +0700 Just keep the dbAuth fetch-api related changes, revert everything else commit c3a2ebb690c9980310889e0d1d1a7a40c2b06057 Merge: be84acec6 d9892f4cc Author: Daniel Choudhury Date: Tue Jan 16 13:51:39 2024 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into feat/dbauth-fetch-handler * 'main' of github.com:redwoodjs/redwood: Add missing cli-helpers test file (#9833) Add cli-helpers util to update redwood.toml (#9832) Tweak graphiql setup messages (#9831) exp setup sentry: Fix file extension (#9829) Fastify config: Use exact file extension in log message (#9828) Remove unused Fastify plugin (#9827) Add trusted-documents to fragments CI smoke-test (#9826) prerender: Enable Trusted Documents support (#9825) trustedDocuments.test.ts: Format source cli: add missing dep jscodeshift (#9823) graphql setup fragments: Move telemetry to main handler (#9819) feat: Adds Setup CLI Command to Configure GraphQL Trusted Documents (#9800) Update cli tsconfig to reference used packages (#9822) fragments setup: newline fix + refactor->rename (#9821) yarn rw setup graphql fragments (#9811) commit be84acec664748401551cc521eec6a8871b8a8e8 Author: Daniel Choudhury Date: Tue Jan 16 13:51:10 2024 +0700 Restore unneeded changes commit 5ce187028d8af18e6f1f43504275a18a6132c314 Merge: 0d62479bc 80e4a4f56 Author: Daniel Choudhury Date: Tue Jan 9 11:51:41 2024 +0600 Merge branch 'main' of github.com:redwoodjs/redwood into feat/dbauth-cookie+generic-handler * 'main' of github.com:redwoodjs/redwood: chore: Improved Possible Types DX and Framework integration for GraphQL Fragments with Union and Interface support (#9594) fix(server): error early on incompatible config (apiHost and apiUrl) (#9808) chore(esm): convert crwa to esm and bundle (#9786) chore(cli): More robust isAwaitable (#9806) chore(ci): Update task names to say "node 20" (#9805) Use TS for rebuild-test-project-fixture script (#9804) chore: bump TSTyche (#9803) docs(fragments): Typo, grammar and formatting fixes (#9802) Revert accidental changes to test-project chore(deps): update dependency @apollo/experimental-nextjs-app-support to v0.5.2 (#9716) fix(deps): update dependency react-helmet-async to v2 (#9697) fix(deps): update dependency sqlite to v5 (#9698) data migrate: Clean up upHandler test (#9796) chore(data-migration): Fix test exit code (#9795) Add routeParams to useMatch (#9793) fix(fastify): Prevent duplicate `@fastify/url-data` registration (#9794) useRoutePath(): Get the path for the current route by default (#9790) Router: Use a single RouterContext (#9792) commit 0d62479bcf764d495ff1d69e86820a00f4495211 Author: Daniel Choudhury Date: Thu Jan 4 14:39:48 2024 +0700 ServerAuthState types and stuff Inject initial server auth state on ssr commit d25ed51ba66eb1df9da9de8a2fa93f1ab0dd37c0 Merge: 9b1affd4c 3e08e20ac Author: Daniel Choudhury Date: Wed Jan 3 13:18:27 2024 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into feat/dbauth-cookie+generic-handler * 'main' of github.com:redwoodjs/redwood: chore: yarn install to update `yarn.lock` (follow up to #9669) chore(deps): update dependency @envelop/core to v5 (#9669) Use regex to make test pass in VSCode (#9791) fix(dbAuth): Correct hardcoded DB column (#9788) fix(deps): update dependency graphql-yoga to v5 (#9688) commit 9b1affd4c1a6488a21423a5c28291b218b959b97 Merge: e05a906ac 1075258d6 Author: Daniel Choudhury Date: Tue Jan 2 13:41:53 2024 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into feat/dbauth-cookie+generic-handler * 'main' of github.com:redwoodjs/redwood: (125 commits) chore(release-tooling): Reminder to update Algolia chore(release-tooling): Add note about generating release notes chore(release-tooling): Add more detailed instructions for after releasing chore(release-tooling): Fix PR count message fix(crwa): use `fs.renameSync` instead of `fs.rename` (#9787) chore(release-tooling): Update to node 20 in version check chore(deps): bump @adobe/css-tools from 4.3.1 to 4.3.2 in /__fixtures__/example-todo-main (#9785) chore(crwa): add e2e tests for create-redwood-app (#9783) chore(release-tooling): fetch -> pull (#9784) feat(scaffold/cell): Adds TypedDocument Support to Cell and Scaffold Generators (#9693) fix: Support Custom Id Field Names in when generating Cells (#9778) chore(framework-tools): .gitignore (#9782) Use build:pack for dbauth when rebuilding the test project (#9781) chore(test-project): Fix test-project generation script, and regenerate fixture (#9779) Fix dbAuth allowUserFields initialization syntax (#9780) chore(framework-tools): add `project:tarsync` script (#9766) fix(otel): Fix OTel sdk loading (#9777) fix: Fixes way OpenTelemetry setup template uses project-config for port setting (#9775) chore(router): Miniscule fixes chore(router): Move useMatch to its own file (#9770) ... commit e05a906ac32047b0c394601e32ef6124a1320755 Author: Daniel Choudhury Date: Thu Dec 28 14:33:11 2023 +0700 Add nx to gitignore commit 4e268aaa0ea88526de9753617b89202d63f1566b Author: Daniel Choudhury Date: Mon Dec 25 14:38:11 2023 +0700 Refactor and reuse getEventHeader Improve Fetch Request detection commit 5e0c1c2bcf67ad093600d40ed43883a9e695f316 Author: Daniel Choudhury Date: Mon Dec 25 13:26:11 2023 +0700 Change detection of fetch event commit fe40f6120188169838b8407da64f2af929bce693 Author: Daniel Choudhury Date: Fri Dec 22 18:09:11 2023 +0700 Cleanup isFetchRequest commit 1a3cbd4125befc2baa57139910c52778104479c4 Author: Daniel Choudhury Date: Fri Dec 22 14:41:48 2023 +0700 Undo decoder type changes commit 097972530692732c847f01009f5c61d127d73d08 Author: Daniel Choudhury Date: Fri Dec 22 14:36:20 2023 +0700 Get it working with middleware! commit 3f0a32b98b7848ca0bdc21bb84a1648bee728fe1 Author: Daniel Choudhury Date: Fri Dec 22 13:28:51 2023 +0700 Fix more tests Normalize request differently to be more compatible commit 82badfd2bb08fa6977a35b610fecbd41f6c2b3fd Author: Daniel Choudhury Date: Wed Dec 20 14:44:10 2023 +0700 Fix authContext tests and dbauth handler commit 67c4ace57ef4745f03ff31838a95f1f29fcff3c2 Author: Daniel Choudhury Date: Mon Dec 11 14:46:57 2023 +0700 I think I have it working with failing tests commit b275d9f11d5f7a65bd6083eeb559118e8581db8a Author: Daniel Choudhury Date: Fri Dec 8 11:05:23 2023 +0700 Fix building! commit 0542ca7b6651d0ba69be239f5f9bbd22f2ae5f8f Merge: 37adfa502 fb3f1fb52 Author: Daniel Choudhury Date: Fri Dec 8 10:50:56 2023 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into try/dbauth-ssr-updated-forward-cookies * 'main' of github.com:redwoodjs/redwood: (163 commits) chore(deps): update dependency @clerk/clerk-react to v4.28.3 (#9643) fix(deps): update prisma monorepo to v5.7.0 (#9642) fix(CLI): merge NODE_OPTIONS in `yarn rw dev` (#9585) chore(release): configure aloglia to index docs chore(release): handle OTP for lerna publish RSC: No need to patch Vite anymore (#9636) RSC: Remove unused code. Improve code organization (#9631) chore(release): improve tooling chore: Linting and disable some console logs (#9635) chore: Update Testing documentation to link to How to Test Email/Mailer (#9634) chore(release): fix open answer Add vscode web debugger and compound (#9567) RSC: Use Routes.tsx for (client-side) routing (#9630) RSC: Add RW env var definitions to Vite config and include FatalErrorBoundary (#9622) chore(release): add notes on #9624 chore(release): add release:notes scripts, fix docs chore(deps): update dependency @clerk/clerk-react to v4.28.2 (#9625) fix(deps): update dependency @vitejs/plugin-react to v4.2.1 (#9626) fix(deps): update dependency vite to v4.5.1 (#9627) fix(deps): update storybook monorepo to v7.6.3 (#9628) ... commit 37adfa502772ba5428f3393967a679280bd9dd99 Author: Daniel Choudhury Date: Mon Nov 20 16:05:31 2023 +0700 Make it forward cookies from authState commit a8f0e33d29fd499918730d22f20edee898c94cc8 Author: Daniel Choudhury Date: Wed Nov 15 22:52:00 2023 +0700 Fix some merged changes commit 4bb543af47aa24eaf2e1df57375ddc758da3fa81 Merge: 2b66173bd bbe222615 Author: Daniel Choudhury Date: Wed Nov 15 22:51:44 2023 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into try/dbauth-ssr-updated * 'main' of github.com:redwoodjs/redwood: (80 commits) fix(deps): update dependency @fastify/http-proxy to v9.3.0 (#9451) fix(deps): update dependency @fastify/static to v6.12.0 (#9452) chore: migrate type tests to TSTyche (#9394) fix(deps): update dependency @testing-library/user-event to v14.5.1 (#9455) fix(deps): update dependency @vitejs/plugin-react to v4.1.1 (#9456) fix(deps): update dependency pino to v8.16.1 (#9459) fix(deps): update dependency firebase-admin to v11.11.0 (#9458) chore(deps): update dependency firebase to v10.6.0 (#9449) fix(deps): update dependency @fastify/url-data to v5.4.0 (#9453) fix(deps): update dependency @simplewebauthn/browser to v7.4.0 (#9454) chore(deps): update actions/setup-node action to v4 (#9461) chore(deps): update actions/checkout action to v4 (#9460) fix(deps): update dependency @graphql-yoga/plugin-graphql-sse to v2.0.5 (#9440) fix(deps): update prisma monorepo to v5.6.0 (#9447) fix(deps): update dependency nodemailer to v6.9.7 (#9444) chore(deps): update dependency esbuild to v0.19.5 (#9359) fix(deps): update dependency @envelop/on-resolve to v3.0.3 (#9436) fix(deps): update dependency semver to v7.5.4 (#9445) fix(deps): update dependency jsonwebtoken to v9.0.2 (#9443) fix(deps): update dependency systeminformation to v5.21.17 (#9446) ... commit 2b66173bdfe9a1df755489330beb54e9d13f09b0 Author: Daniel Choudhury Date: Wed Nov 15 21:48:27 2023 +0700 Get it building again commit 9fafcf8b116701ecfb8d432ecd42ec76785ccfd0 Author: Daniel Choudhury Date: Thu Nov 2 23:50:43 2023 +0700 SHIP IT commit bb0b36ec6462782e1fcadf8ea87912356bcd6e85 Merge: 5f1deedf9 7ab07a25c Author: Daniel Choudhury Date: Thu Nov 2 22:23:40 2023 +0700 Merge branch 'main' of github.com:redwoodjs/redwood into try/dbauth-ssr * 'main' of github.com:redwoodjs/redwood: (26 commits) fix(api-server): copy fallback fix from #9272 (#9369) fix(deps): update dependency concurrently to v8.2.2 (#9361) chore(k6): Fix function context test (#9368) feat(cli): Setup command for mailer (#9335) feature: Support defer and stream GraphQL Directives in RedwoodRealtime (#9235) chore(deps): update dependency rimraf to v5.0.5 (#9360) chore(k6): Fix function context test (#9358) chore(deps): bump undici from 5.22.1 to 5.26.3 (#9307) fix(babel): Fix opentelemetry api wrapping and allow it to be disabled (#9298) chore(api-server): remove server survey tests in CI (#9348) chore(deps): update babel monorepo to v7.23.2 (#9344) chore(deps): bump @babel/traverse from 7.18.9 to 7.23.2 in /docs (#9311) chore(deps): update dependency @tsconfig/docusaurus to v2 (#9347) fix(deps): update dependency react-player to v2.13.0 (#9346) fix(deps): update docusaurus monorepo to v2.4.3 (#9345) fix(deps): update dependency @babel/traverse to v7.23.2 [security] (#9322) chore: increase server test timeout, fix `yarn build:clean` (#9336) feature: Adds utility functions to add envars and update Redwood toml for plugin packages to cli helpers for use in simplifying CLI setup commands (#9324) fix(cli): Tailwind setup updates `scaffold.css` when needed (#9290) fix(cli): Exit with non-zero exit code when `yarn rw g types` has errors (#9280) ... commit 5f1deedf998c5e798e2e1ad1de084d2097ff299e Author: Daniel Choudhury Date: Thu Oct 26 12:57:44 2023 +0700 NOT WORKING: try extracting session passed into a cookie commit 9e8613504f0992bd13ba48e2bb52a6ab7d75e016 Author: Daniel Choudhury Date: Wed Oct 25 12:48:33 2023 +0700 Simple auth state parsing with middleware in entry server --- packages/api-server/src/plugins/graphql.ts | 4 +- .../src/__tests__/normalizeRequest.test.ts | 15 +- packages/api/src/auth/index.ts | 19 +- packages/api/src/transforms.ts | 20 +- .../auth-providers/auth0/api/jest.config.js | 4 - .../auth-providers/auth0/api/package.json | 8 +- .../auth0/api/src/__tests__/auth0.test.ts | 9 +- .../auth0/api/vitest.config.mts | 7 + .../auth-providers/auth0/setup/jest.config.js | 4 - .../auth-providers/auth0/setup/package.json | 8 +- .../auth0/setup/src/__tests__/setup.test.ts | 4 +- .../auth0/setup/vitest.config.mts | 7 + .../auth-providers/auth0/web/jest.config.js | 5 - .../auth-providers/auth0/web/package.json | 8 +- .../auth0/web/src/__tests__/auth0.test.tsx | 3 +- .../auth0/web/vitest.config.mts | 8 + .../azureActiveDirectory/api/jest.config.js | 4 - .../azureActiveDirectory/api/package.json | 8 +- .../__tests__/azureActiveDirectory.test.ts | 9 +- .../api/vitest.config.mts | 7 + .../azureActiveDirectory/setup/jest.config.js | 4 - .../azureActiveDirectory/setup/package.json | 8 +- .../setup/src/__tests__/setup.test.ts | 8 +- .../setup/vitest.config.mts | 7 + .../azureActiveDirectory/web/jest.config.js | 5 - .../azureActiveDirectory/web/package.json | 8 +- .../__tests__/azureActiveDirectory.test.tsx | 3 +- .../web/vitest.config.mts | 8 + .../auth-providers/clerk/api/jest.config.js | 4 - .../auth-providers/clerk/api/package.json | 8 +- .../clerk/api/src/__tests__/clerk.test.ts | 1 + .../clerk/api/vitest.config.mts | 7 + .../auth-providers/clerk/setup/jest.config.js | 4 - .../auth-providers/clerk/setup/package.json | 5 +- .../auth-providers/clerk/web/jest.config.js | 5 - .../auth-providers/clerk/web/package.json | 8 +- .../clerk/web/src/__tests__/clerk.test.tsx | 3 +- .../clerk/web/vitest.config.mts | 8 + .../custom/setup/jest.config.js | 4 - .../auth-providers/custom/setup/package.json | 8 +- .../custom/setup/src/__tests__/setup.test.ts | 8 +- .../custom/setup/vitest.config.mts | 7 + .../auth-providers/dbAuth/api/jest.config.js | 4 - .../auth-providers/dbAuth/api/package.json | 8 +- .../dbAuth/api/src/DbAuthHandler.ts | 18 +- .../src/__tests__/DbAuthHandler.fetch.test.js | 367 +++++++++++------- .../api/src/__tests__/DbAuthHandler.test.js | 305 ++++++++++----- .../dbAuth/api/src/__tests__/shared.test.ts | 54 ++- .../auth-providers/dbAuth/api/src/decoder.ts | 3 +- .../auth-providers/dbAuth/api/src/shared.ts | 45 ++- .../dbAuth/api/vitest.config.mts | 7 + .../dbAuth/setup/jest.config.js | 4 - .../auth-providers/dbAuth/setup/package.json | 5 +- .../firebase/api/jest.config.js | 4 - .../auth-providers/firebase/api/package.json | 8 +- .../api/src/__tests__/firebase.test.ts | 5 +- .../firebase/api/vitest.config.mts | 7 + .../firebase/setup/jest.config.js | 4 - .../firebase/setup/package.json | 8 +- .../setup/src/__tests__/setup.test.ts | 8 +- .../firebase/setup/vitest.config.mts | 7 + .../auth-providers/netlify/api/jest.config.js | 4 - .../auth-providers/netlify/api/package.json | 8 +- .../netlify/api/src/__tests__/netlify.test.ts | 29 +- .../netlify/api/vitest.config.mts | 7 + .../netlify/setup/jest.config.js | 4 - .../auth-providers/netlify/setup/package.json | 8 +- .../netlify/setup/src/__tests__/setup.test.ts | 8 +- .../netlify/setup/vitest.config.mts | 7 + .../auth-providers/netlify/web/jest.config.js | 5 - .../auth-providers/netlify/web/package.json | 8 +- .../web/src/__tests__/netlify.test.tsx | 3 +- .../netlify/web/vitest.config.mts | 8 + .../supabase/api/jest.config.js | 4 - .../auth-providers/supabase/api/package.json | 8 +- .../api/src/__tests__/supabase.test.ts | 17 +- .../supabase/api/vitest.config.mts | 7 + .../supabase/setup/jest.config.js | 4 - .../supabase/setup/package.json | 5 +- .../supabase/web/jest.config.js | 5 - .../auth-providers/supabase/web/package.json | 8 +- .../web/src/__tests__/supabase.test.tsx | 3 +- .../supabase/web/vitest.config.mts | 8 + .../supertokens/api/jest.config.js | 4 - .../supertokens/api/package.json | 8 +- .../api/src/__tests__/supertokens.test.ts | 9 +- .../supertokens/api/vitest.config.mts | 7 + .../supertokens/setup/__mocks__/fs.js | 220 ----------- .../supertokens/setup/jest.config.js | 4 - .../supertokens/setup/package.json | 9 +- .../setup/src/__tests__/setup.test.ts | 8 +- .../setup/src/__tests__/setupHandler.test.ts | 30 +- .../supertokens/setup/vitest.config.mts | 7 + .../supertokens/web/jest.config.js | 5 - .../supertokens/web/package.json | 8 +- .../web/src/__tests__/supertokens.test.tsx | 3 +- .../supertokens/web/vitest.config.mts | 8 + .../__tests__/normalizeRequest.test.ts | 99 ----- packages/project-config/build.js | 28 ++ packages/project-config/build.mjs | 22 -- packages/project-config/package.json | 7 +- packages/project-config/src/config.ts | 2 +- packages/project-config/src/configPath.ts | 2 +- packages/project-config/src/index.ts | 8 +- packages/project-config/src/paths.ts | 4 +- packages/project-config/tsconfig.json | 2 + packages/vite/bins/rw-vite-dev.mjs | 4 +- .../src/__tests__/viteNestedPages.test.mts | 3 +- yarn.lock | 44 +-- 109 files changed, 962 insertions(+), 924 deletions(-) delete mode 100644 packages/auth-providers/auth0/api/jest.config.js create mode 100644 packages/auth-providers/auth0/api/vitest.config.mts delete mode 100644 packages/auth-providers/auth0/setup/jest.config.js create mode 100644 packages/auth-providers/auth0/setup/vitest.config.mts delete mode 100644 packages/auth-providers/auth0/web/jest.config.js create mode 100644 packages/auth-providers/auth0/web/vitest.config.mts delete mode 100644 packages/auth-providers/azureActiveDirectory/api/jest.config.js create mode 100644 packages/auth-providers/azureActiveDirectory/api/vitest.config.mts delete mode 100644 packages/auth-providers/azureActiveDirectory/setup/jest.config.js create mode 100644 packages/auth-providers/azureActiveDirectory/setup/vitest.config.mts delete mode 100644 packages/auth-providers/azureActiveDirectory/web/jest.config.js create mode 100644 packages/auth-providers/azureActiveDirectory/web/vitest.config.mts delete mode 100644 packages/auth-providers/clerk/api/jest.config.js create mode 100644 packages/auth-providers/clerk/api/vitest.config.mts delete mode 100644 packages/auth-providers/clerk/setup/jest.config.js delete mode 100644 packages/auth-providers/clerk/web/jest.config.js create mode 100644 packages/auth-providers/clerk/web/vitest.config.mts delete mode 100644 packages/auth-providers/custom/setup/jest.config.js create mode 100644 packages/auth-providers/custom/setup/vitest.config.mts delete mode 100644 packages/auth-providers/dbAuth/api/jest.config.js create mode 100644 packages/auth-providers/dbAuth/api/vitest.config.mts delete mode 100644 packages/auth-providers/dbAuth/setup/jest.config.js delete mode 100644 packages/auth-providers/firebase/api/jest.config.js create mode 100644 packages/auth-providers/firebase/api/vitest.config.mts delete mode 100644 packages/auth-providers/firebase/setup/jest.config.js create mode 100644 packages/auth-providers/firebase/setup/vitest.config.mts delete mode 100644 packages/auth-providers/netlify/api/jest.config.js create mode 100644 packages/auth-providers/netlify/api/vitest.config.mts delete mode 100644 packages/auth-providers/netlify/setup/jest.config.js create mode 100644 packages/auth-providers/netlify/setup/vitest.config.mts delete mode 100644 packages/auth-providers/netlify/web/jest.config.js create mode 100644 packages/auth-providers/netlify/web/vitest.config.mts delete mode 100644 packages/auth-providers/supabase/api/jest.config.js create mode 100644 packages/auth-providers/supabase/api/vitest.config.mts delete mode 100644 packages/auth-providers/supabase/setup/jest.config.js delete mode 100644 packages/auth-providers/supabase/web/jest.config.js create mode 100644 packages/auth-providers/supabase/web/vitest.config.mts delete mode 100644 packages/auth-providers/supertokens/api/jest.config.js create mode 100644 packages/auth-providers/supertokens/api/vitest.config.mts delete mode 100644 packages/auth-providers/supertokens/setup/__mocks__/fs.js delete mode 100644 packages/auth-providers/supertokens/setup/jest.config.js create mode 100644 packages/auth-providers/supertokens/setup/vitest.config.mts delete mode 100644 packages/auth-providers/supertokens/web/jest.config.js create mode 100644 packages/auth-providers/supertokens/web/vitest.config.mts delete mode 100644 packages/graphql-server/src/functions/__tests__/normalizeRequest.test.ts create mode 100644 packages/project-config/build.js delete mode 100644 packages/project-config/build.mjs diff --git a/packages/api-server/src/plugins/graphql.ts b/packages/api-server/src/plugins/graphql.ts index 86bdb7980eba..0d97050a3ecc 100644 --- a/packages/api-server/src/plugins/graphql.ts +++ b/packages/api-server/src/plugins/graphql.ts @@ -115,7 +115,7 @@ export async function redwoodFastifyGraphQLServer( }) } - fastify.ready(() => { + fastify.addHook('onReady', (done) => { console.info(`GraphQL Yoga Server endpoint at ${yoga.graphqlEndpoint}`) console.info( `GraphQL Yoga Server Health Check endpoint at ${yoga.graphqlEndpoint}/health` @@ -123,6 +123,8 @@ export async function redwoodFastifyGraphQLServer( console.info( `GraphQL Yoga Server Readiness endpoint at ${yoga.graphqlEndpoint}/readiness` ) + + done() }) done() diff --git a/packages/api/src/__tests__/normalizeRequest.test.ts b/packages/api/src/__tests__/normalizeRequest.test.ts index 5be836c166ac..c39e316eceda 100644 --- a/packages/api/src/__tests__/normalizeRequest.test.ts +++ b/packages/api/src/__tests__/normalizeRequest.test.ts @@ -1,5 +1,6 @@ import { Headers } from '@whatwg-node/fetch' import type { APIGatewayProxyEvent } from 'aws-lambda' +import { test, expect, describe } from 'vitest' import { normalizeRequest } from '../transforms' @@ -54,7 +55,7 @@ export const createMockedLambdaEvent = ( } describe('Lambda Request', () => { - it('Normalizes an aws event with base64', async () => { + test('Normalizes an aws event with base64', async () => { const corsEventB64 = createMockedLambdaEvent( 'POST', Buffer.from(JSON.stringify({ bazinga: 'hello_world' }), 'utf8').toString( @@ -73,14 +74,14 @@ describe('Lambda Request', () => { }) }) - it('Handles CORS requests with and without b64 encoded', async () => { + test('Handles CORS requests with and without b64 encoded', async () => { const corsEventB64 = createMockedLambdaEvent('OPTIONS', undefined, true) expect(await normalizeRequest(corsEventB64)).toEqual({ headers: new Headers(corsEventB64.headers as Record), // headers returned as symbol method: 'OPTIONS', query: null, - jsonBody: undefined, + jsonBody: {}, }) const corsEventWithoutB64 = createMockedLambdaEvent( @@ -93,13 +94,13 @@ describe('Lambda Request', () => { headers: new Headers(corsEventB64.headers as Record), // headers returned as symbol method: 'OPTIONS', query: null, - jsonBody: undefined, + jsonBody: {}, }) }) }) describe('Fetch API Request', () => { - it('Normalizes a fetch event', async () => { + test('Normalizes a fetch event', async () => { const fetchEvent = new Request( 'http://localhost:9210/graphql?whatsup=doc&its=bugs', { @@ -128,7 +129,7 @@ describe('Fetch API Request', () => { expect(partial.headers.get('content-type')).toEqual('application/json') }) - it('Handles an empty body', async () => { + test('Handles an empty body', async () => { const headers = { 'content-type': 'application/json', 'x-custom-header': 'bazinga', @@ -151,7 +152,7 @@ describe('Fetch API Request', () => { whatsup: 'doc', its: 'bugs', }, - jsonBody: undefined, + jsonBody: {}, // @NOTE empty body is {} not undefined }) expect(partial.headers.get('content-type')).toEqual(headers['content-type']) diff --git a/packages/api/src/auth/index.ts b/packages/api/src/auth/index.ts index 7f1706675926..90bd84c54b86 100644 --- a/packages/api/src/auth/index.ts +++ b/packages/api/src/auth/index.ts @@ -5,6 +5,8 @@ import { parse as parseCookie } from 'cookie' import { getEventHeader } from '../event' +import { getEventHeader } from '../event' + import type { Decoded } from './parseJWT' export type { Decoded } @@ -64,16 +66,24 @@ export const parseAuthorizationHeader = ( return { schema, token } } +/** @MARK Note that we do not send LambdaContext when making fetch requests + * + * This part is incomplete, as we need to decide how we will make the breaking change to + * 1. getCurrentUser + * 2. authDecoders + + */ + export type AuthContextPayload = [ Decoded, { type: string } & AuthorizationHeader, - { event: APIGatewayProxyEvent; context: LambdaContext } + { event: APIGatewayProxyEvent | Request; context: LambdaContext } ] export type Decoder = ( token: string, type: string, - req: { event: APIGatewayProxyEvent; context: LambdaContext } + req: { event: APIGatewayProxyEvent | Request; context: LambdaContext } ) => Promise /** @@ -134,8 +144,9 @@ export const getAuthenticationContext = async ({ let i = 0 while (!decoded && i < authDecoders.length) { decoded = await authDecoders[i](token, type, { - // @TODO We will need to make a breaking change to auth decoders maybe - event: event as any, + // @TODO: We will need to make a breaking change to support `Request` objects. + // We can remove this typecast + event: event, context, }) i++ diff --git a/packages/api/src/transforms.ts b/packages/api/src/transforms.ts index 4a457e8d2f67..3fb7eb010f86 100644 --- a/packages/api/src/transforms.ts +++ b/packages/api/src/transforms.ts @@ -5,7 +5,7 @@ import type { APIGatewayProxyEvent } from 'aws-lambda' // We do this to keep the API consistent between the two // When we support only the FetchAPI request, we should remove this export interface PartialRequest> { - jsonBody?: TBody + jsonBody: TBody headers: Headers method: string query: any @@ -16,7 +16,7 @@ export interface PartialRequest> { */ export const parseLambdaEventBody = (event: APIGatewayProxyEvent) => { if (!event.body) { - return + return {} } if (event.isBase64Encoded) { @@ -28,23 +28,19 @@ export const parseLambdaEventBody = (event: APIGatewayProxyEvent) => { /** * Extracts and parses body payload from Fetch Request - * with check for empty body (and base64 later) + * with check for empty body + * + * NOTE: whatwg/server expects that you will decode the base64 body yourself + * see readme here: https://github.com/ardatan/whatwg-node/tree/master/packages/server#aws-lambda */ export const parseFetchEventBody = async (event: Request) => { if (!event.body) { - return + return {} } - // @TODO: We need to understand what happens on Vercel - // if (event.isBase64Encoded) { - // return JSON.parse(Buffer.from(event.body, 'base64').toString('utf-8')) - // } else { - // return JSON.parse(event.body) - // } - const body = await event.text() - return body ? JSON.parse(body) : undefined + return body ? JSON.parse(body) : {} } export const isFetchApiRequest = ( diff --git a/packages/auth-providers/auth0/api/jest.config.js b/packages/auth-providers/auth0/api/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/auth0/api/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/auth0/api/package.json b/packages/auth-providers/auth0/api/package.json index 01aad3357389..640d627f0c66 100644 --- a/packages/auth-providers/auth0/api/package.json +++ b/packages/auth-providers/auth0/api/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -33,8 +33,8 @@ "@babel/core": "^7.22.20", "@redwoodjs/api": "6.0.7", "@types/jsonwebtoken": "9.0.5", - "jest": "29.7.0", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/auth0/api/src/__tests__/auth0.test.ts b/packages/auth-providers/auth0/api/src/__tests__/auth0.test.ts index 5bc90f1f303f..8ca10945be3f 100644 --- a/packages/auth-providers/auth0/api/src/__tests__/auth0.test.ts +++ b/packages/auth-providers/auth0/api/src/__tests__/auth0.test.ts @@ -1,10 +1,13 @@ import jwt from 'jsonwebtoken' +import { vi, test, expect } from 'vitest' import { verifyAuth0Token } from '../decoder' -jest.mock('jsonwebtoken', () => ({ - verify: jest.fn(), - decode: jest.fn(), +vi.mock('jsonwebtoken', () => ({ + default: { + verify: vi.fn(), + decode: vi.fn(), + }, })) test('verify, and not decode, should be called in production', () => { diff --git a/packages/auth-providers/auth0/api/vitest.config.mts b/packages/auth-providers/auth0/api/vitest.config.mts new file mode 100644 index 000000000000..4c8730d4808b --- /dev/null +++ b/packages/auth-providers/auth0/api/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + }, +}) diff --git a/packages/auth-providers/auth0/setup/jest.config.js b/packages/auth-providers/auth0/setup/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/auth0/setup/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/auth0/setup/package.json b/packages/auth-providers/auth0/setup/package.json index 9902868d89ca..609f1b631cad 100644 --- a/packages/auth-providers/auth0/setup/package.json +++ b/packages/auth-providers/auth0/setup/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -31,8 +31,8 @@ "@babel/cli": "7.23.4", "@babel/core": "^7.22.20", "@types/yargs": "17.0.32", - "jest": "29.7.0", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/auth0/setup/src/__tests__/setup.test.ts b/packages/auth-providers/auth0/setup/src/__tests__/setup.test.ts index 9d1abf7d4e00..ea77ef05fa0a 100644 --- a/packages/auth-providers/auth0/setup/src/__tests__/setup.test.ts +++ b/packages/auth-providers/auth0/setup/src/__tests__/setup.test.ts @@ -1,7 +1,9 @@ +import { vi, test, expect } from 'vitest' + import { command, description, builder, handler } from '../setup' // mock Telemetry for CLI commands so they don't try to spawn a process -jest.mock('@redwoodjs/telemetry', () => { +vi.mock('@redwoodjs/telemetry', () => { return { errorTelemetry: () => jest.fn(), timedTelemetry: () => jest.fn(), diff --git a/packages/auth-providers/auth0/setup/vitest.config.mts b/packages/auth-providers/auth0/setup/vitest.config.mts new file mode 100644 index 000000000000..4c8730d4808b --- /dev/null +++ b/packages/auth-providers/auth0/setup/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + }, +}) diff --git a/packages/auth-providers/auth0/web/jest.config.js b/packages/auth-providers/auth0/web/jest.config.js deleted file mode 100644 index e691bb8f6dbd..000000000000 --- a/packages/auth-providers/auth0/web/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testEnvironment: 'jest-environment-jsdom', - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/auth0/web/package.json b/packages/auth-providers/auth0/web/package.json index 834e79ded6e2..931a159e2820 100644 --- a/packages/auth-providers/auth0/web/package.json +++ b/packages/auth-providers/auth0/web/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -32,9 +32,9 @@ "@babel/cli": "7.23.4", "@babel/core": "^7.22.20", "@types/react": "18.2.37", - "jest": "29.7.0", "react": "0.0.0-experimental-e5205658f-20230913", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "peerDependencies": { "@auth0/auth0-spa-js": "2.1.2" 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 d939ea483e70..62f821cafbab 100644 --- a/packages/auth-providers/auth0/web/src/__tests__/auth0.test.tsx +++ b/packages/auth-providers/auth0/web/src/__tests__/auth0.test.tsx @@ -5,6 +5,7 @@ import type { User, } from '@auth0/auth0-spa-js' import { renderHook, act } from '@testing-library/react' +import { vi, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { CurrentUser } from '@redwoodjs/auth' @@ -52,7 +53,7 @@ const auth0MockClient: Partial = { }, } -const fetchMock = jest.fn() +const fetchMock = vi.fn() fetchMock.mockImplementation(async (_url, options) => { const body = options?.body ? JSON.parse(options.body) : {} diff --git a/packages/auth-providers/auth0/web/vitest.config.mts b/packages/auth-providers/auth0/web/vitest.config.mts new file mode 100644 index 000000000000..52ec6b09db8f --- /dev/null +++ b/packages/auth-providers/auth0/web/vitest.config.mts @@ -0,0 +1,8 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + environment: 'jsdom', + }, +}) diff --git a/packages/auth-providers/azureActiveDirectory/api/jest.config.js b/packages/auth-providers/azureActiveDirectory/api/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/azureActiveDirectory/api/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/azureActiveDirectory/api/package.json b/packages/auth-providers/azureActiveDirectory/api/package.json index ec16c01ba49f..2164e6e249dc 100644 --- a/packages/auth-providers/azureActiveDirectory/api/package.json +++ b/packages/auth-providers/azureActiveDirectory/api/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -34,8 +34,8 @@ "@redwoodjs/api": "6.0.7", "@types/aws-lambda": "8.10.126", "@types/jsonwebtoken": "9.0.5", - "jest": "29.7.0", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/azureActiveDirectory/api/src/__tests__/azureActiveDirectory.test.ts b/packages/auth-providers/azureActiveDirectory/api/src/__tests__/azureActiveDirectory.test.ts index 1afa1ecd1b4b..f58e3c9ee3e9 100644 --- a/packages/auth-providers/azureActiveDirectory/api/src/__tests__/azureActiveDirectory.test.ts +++ b/packages/auth-providers/azureActiveDirectory/api/src/__tests__/azureActiveDirectory.test.ts @@ -1,11 +1,14 @@ import type { APIGatewayProxyEvent, Context as LambdaContext } from 'aws-lambda' import jwt from 'jsonwebtoken' +import { vi, test, beforeAll, afterAll, expect, describe } from 'vitest' import { authDecoder } from '../decoder' -jest.mock('jsonwebtoken', () => ({ - verify: jest.fn(), - decode: jest.fn(), +vi.mock('jsonwebtoken', () => ({ + default: { + verify: vi.fn(), + decode: vi.fn(), + }, })) const req = { diff --git a/packages/auth-providers/azureActiveDirectory/api/vitest.config.mts b/packages/auth-providers/azureActiveDirectory/api/vitest.config.mts new file mode 100644 index 000000000000..4c8730d4808b --- /dev/null +++ b/packages/auth-providers/azureActiveDirectory/api/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + }, +}) diff --git a/packages/auth-providers/azureActiveDirectory/setup/jest.config.js b/packages/auth-providers/azureActiveDirectory/setup/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/azureActiveDirectory/setup/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/azureActiveDirectory/setup/package.json b/packages/auth-providers/azureActiveDirectory/setup/package.json index b642e6ab6ea1..19d3f655439b 100644 --- a/packages/auth-providers/azureActiveDirectory/setup/package.json +++ b/packages/auth-providers/azureActiveDirectory/setup/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -31,8 +31,8 @@ "@babel/cli": "7.23.4", "@babel/core": "^7.22.20", "@types/yargs": "17.0.32", - "jest": "29.7.0", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/azureActiveDirectory/setup/src/__tests__/setup.test.ts b/packages/auth-providers/azureActiveDirectory/setup/src/__tests__/setup.test.ts index 15b0eecace52..3f3e336466aa 100644 --- a/packages/auth-providers/azureActiveDirectory/setup/src/__tests__/setup.test.ts +++ b/packages/auth-providers/azureActiveDirectory/setup/src/__tests__/setup.test.ts @@ -1,10 +1,12 @@ +import { vi, test, expect } from 'vitest' + import { command, description, builder, handler } from '../setup' // mock Telemetry for CLI commands so they don't try to spawn a process -jest.mock('@redwoodjs/telemetry', () => { +vi.mock('@redwoodjs/telemetry', () => { return { - errorTelemetry: () => jest.fn(), - timedTelemetry: () => jest.fn(), + errorTelemetry: () => vi.fn(), + timedTelemetry: () => vi.fn(), } }) diff --git a/packages/auth-providers/azureActiveDirectory/setup/vitest.config.mts b/packages/auth-providers/azureActiveDirectory/setup/vitest.config.mts new file mode 100644 index 000000000000..4c8730d4808b --- /dev/null +++ b/packages/auth-providers/azureActiveDirectory/setup/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + }, +}) diff --git a/packages/auth-providers/azureActiveDirectory/web/jest.config.js b/packages/auth-providers/azureActiveDirectory/web/jest.config.js deleted file mode 100644 index e691bb8f6dbd..000000000000 --- a/packages/auth-providers/azureActiveDirectory/web/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testEnvironment: 'jest-environment-jsdom', - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/azureActiveDirectory/web/package.json b/packages/auth-providers/azureActiveDirectory/web/package.json index 6fe008d43522..c3c33a9612dc 100644 --- a/packages/auth-providers/azureActiveDirectory/web/package.json +++ b/packages/auth-providers/azureActiveDirectory/web/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -33,9 +33,9 @@ "@babel/core": "^7.22.20", "@types/netlify-identity-widget": "1.9.6", "@types/react": "18.2.37", - "jest": "29.7.0", "react": "0.0.0-experimental-e5205658f-20230913", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "peerDependencies": { "@azure/msal-browser": "2.38.3" 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 f34c4103bcd1..ef8032bfa58d 100644 --- a/packages/auth-providers/azureActiveDirectory/web/src/__tests__/azureActiveDirectory.test.tsx +++ b/packages/auth-providers/azureActiveDirectory/web/src/__tests__/azureActiveDirectory.test.tsx @@ -4,6 +4,7 @@ import type { RedirectRequest, } from '@azure/msal-browser' import { renderHook, act } from '@testing-library/react' +import { vi, it, expect, describe, beforeAll, beforeEach } from 'vitest' import type { CurrentUser } from '@redwoodjs/auth' @@ -79,7 +80,7 @@ const azureActiveDirectoryMockClient: Partial = { }, } -const fetchMock = jest.fn() +const fetchMock = vi.fn() fetchMock.mockImplementation(async (_url, options) => { const body = options?.body ? JSON.parse(options.body) : {} diff --git a/packages/auth-providers/azureActiveDirectory/web/vitest.config.mts b/packages/auth-providers/azureActiveDirectory/web/vitest.config.mts new file mode 100644 index 000000000000..52ec6b09db8f --- /dev/null +++ b/packages/auth-providers/azureActiveDirectory/web/vitest.config.mts @@ -0,0 +1,8 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + environment: 'jsdom', + }, +}) diff --git a/packages/auth-providers/clerk/api/jest.config.js b/packages/auth-providers/clerk/api/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/clerk/api/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/clerk/api/package.json b/packages/auth-providers/clerk/api/package.json index 1cd8f651f5e4..8d92f5421b2b 100644 --- a/packages/auth-providers/clerk/api/package.json +++ b/packages/auth-providers/clerk/api/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -32,8 +32,8 @@ "@babel/core": "^7.22.20", "@redwoodjs/api": "6.0.7", "@types/aws-lambda": "8.10.126", - "jest": "29.7.0", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/clerk/api/src/__tests__/clerk.test.ts b/packages/auth-providers/clerk/api/src/__tests__/clerk.test.ts index d80fe627d223..1ccea2ef70a4 100644 --- a/packages/auth-providers/clerk/api/src/__tests__/clerk.test.ts +++ b/packages/auth-providers/clerk/api/src/__tests__/clerk.test.ts @@ -1,4 +1,5 @@ import type { APIGatewayProxyEvent, Context as LambdaContext } from 'aws-lambda' +import { beforeAll, afterAll, describe, test, expect } from 'vitest' import { authDecoder, clerkAuthDecoder } from '../decoder' diff --git a/packages/auth-providers/clerk/api/vitest.config.mts b/packages/auth-providers/clerk/api/vitest.config.mts new file mode 100644 index 000000000000..4c8730d4808b --- /dev/null +++ b/packages/auth-providers/clerk/api/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + }, +}) diff --git a/packages/auth-providers/clerk/setup/jest.config.js b/packages/auth-providers/clerk/setup/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/clerk/setup/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/clerk/setup/package.json b/packages/auth-providers/clerk/setup/package.json index b6747fe513eb..8336bede7098 100644 --- a/packages/auth-providers/clerk/setup/package.json +++ b/packages/auth-providers/clerk/setup/package.json @@ -18,9 +18,7 @@ "build:pack": "yarn pack -o redwoodjs-auth-clerk-setup.tgz", "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", - "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src --passWithNoTests", - "test:watch": "yarn test --watch" + "prepublishOnly": "NODE_ENV=production yarn build" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -31,7 +29,6 @@ "@babel/cli": "7.23.4", "@babel/core": "^7.22.20", "@types/yargs": "17.0.32", - "jest": "29.7.0", "typescript": "5.3.3" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" diff --git a/packages/auth-providers/clerk/web/jest.config.js b/packages/auth-providers/clerk/web/jest.config.js deleted file mode 100644 index e691bb8f6dbd..000000000000 --- a/packages/auth-providers/clerk/web/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testEnvironment: 'jest-environment-jsdom', - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/clerk/web/package.json b/packages/auth-providers/clerk/web/package.json index bdf2ae2e5c88..19f29506bcd6 100644 --- a/packages/auth-providers/clerk/web/package.json +++ b/packages/auth-providers/clerk/web/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -33,9 +33,9 @@ "@clerk/clerk-react": "4.28.3", "@clerk/types": "3.60.0", "@types/react": "18.2.37", - "jest": "29.7.0", "react": "0.0.0-experimental-e5205658f-20230913", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "peerDependencies": { "@clerk/clerk-react": "4.28.3" 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 93d6faccbabf..2ddaa1974573 100644 --- a/packages/auth-providers/clerk/web/src/__tests__/clerk.test.tsx +++ b/packages/auth-providers/clerk/web/src/__tests__/clerk.test.tsx @@ -5,6 +5,7 @@ import type { ActiveSessionResource, } from '@clerk/types' import { renderHook, act } from '@testing-library/react' +import { vi, expect, describe, it, beforeAll, beforeEach } from 'vitest' import type { CurrentUser } from '@redwoodjs/auth' @@ -63,7 +64,7 @@ const clerkMockClient: Partial = { }, } -const fetchMock = jest.fn() +const fetchMock = vi.fn() fetchMock.mockImplementation(async (_url, options) => { const body = options?.body ? JSON.parse(options.body) : {} diff --git a/packages/auth-providers/clerk/web/vitest.config.mts b/packages/auth-providers/clerk/web/vitest.config.mts new file mode 100644 index 000000000000..52ec6b09db8f --- /dev/null +++ b/packages/auth-providers/clerk/web/vitest.config.mts @@ -0,0 +1,8 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + environment: 'jsdom', + }, +}) diff --git a/packages/auth-providers/custom/setup/jest.config.js b/packages/auth-providers/custom/setup/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/custom/setup/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/custom/setup/package.json b/packages/auth-providers/custom/setup/package.json index ebc3c711846a..300958d96bc6 100644 --- a/packages/auth-providers/custom/setup/package.json +++ b/packages/auth-providers/custom/setup/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -31,8 +31,8 @@ "@babel/cli": "7.23.4", "@babel/core": "^7.22.20", "@types/yargs": "17.0.32", - "jest": "29.7.0", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/custom/setup/src/__tests__/setup.test.ts b/packages/auth-providers/custom/setup/src/__tests__/setup.test.ts index 1383a37488b8..27eac4ac2bde 100644 --- a/packages/auth-providers/custom/setup/src/__tests__/setup.test.ts +++ b/packages/auth-providers/custom/setup/src/__tests__/setup.test.ts @@ -1,10 +1,12 @@ +import { vi, test, expect } from 'vitest' + import { command, description, builder, handler } from '../setup' // mock Telemetry for CLI commands so they don't try to spawn a process -jest.mock('@redwoodjs/telemetry', () => { +vi.mock('@redwoodjs/telemetry', () => { return { - errorTelemetry: () => jest.fn(), - timedTelemetry: () => jest.fn(), + errorTelemetry: () => vi.fn(), + timedTelemetry: () => vi.fn(), } }) diff --git a/packages/auth-providers/custom/setup/vitest.config.mts b/packages/auth-providers/custom/setup/vitest.config.mts new file mode 100644 index 000000000000..4c8730d4808b --- /dev/null +++ b/packages/auth-providers/custom/setup/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + }, +}) diff --git a/packages/auth-providers/dbAuth/api/jest.config.js b/packages/auth-providers/dbAuth/api/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/dbAuth/api/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/dbAuth/api/package.json b/packages/auth-providers/dbAuth/api/package.json index 61ed80ea4628..694be84376b3 100644 --- a/packages/auth-providers/dbAuth/api/package.json +++ b/packages/auth-providers/dbAuth/api/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -37,8 +37,8 @@ "@simplewebauthn/server": "7.4.0", "@types/md5": "2.3.5", "@types/uuid": "9.0.7", - "jest": "29.7.0", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/dbAuth/api/src/DbAuthHandler.ts b/packages/auth-providers/dbAuth/api/src/DbAuthHandler.ts index 532e2d239260..9ca96bca1d7f 100644 --- a/packages/auth-providers/dbAuth/api/src/DbAuthHandler.ts +++ b/packages/auth-providers/dbAuth/api/src/DbAuthHandler.ts @@ -539,8 +539,6 @@ export class DbAuthHandler< ) } - await this.init() - const { username } = this.normalizedRequest.jsonBody || {} // was the username sent in at all? if (!username || username.trim() === '') { @@ -608,6 +606,8 @@ export class DbAuthHandler< } } + // In SSR this never gets called... + // @TODO remove? async getToken() { try { // Just return the encrypted session cookie, to be passed back in the Authorization header @@ -631,7 +631,6 @@ export class DbAuthHandler< ) } - await this.init() const { username, password } = this.normalizedRequest.jsonBody || {} const dbUser = await this._verifyUser(username, password) const handlerUser = await (this.options.login as LoginFlowOptions).handler( @@ -661,7 +660,6 @@ export class DbAuthHandler< ) } - await this.init() const { password, resetToken } = this.normalizedRequest.jsonBody || {} // is the resetToken present? @@ -757,7 +755,6 @@ export class DbAuthHandler< } async validateResetToken() { - await this.init() const { resetToken } = this.normalizedRequest.jsonBody || {} // is token present at all? if (!resetToken || String(resetToken).trim() === '') { @@ -790,6 +787,12 @@ export class DbAuthHandler< throw new DbAuthError.WebAuthnError('Missing Id in request') } + const { rawId } = this.normalizedRequest.jsonBody || {} + + if (!rawId) { + throw new DbAuthError.WebAuthnError('Missing Id in request') + } + if (!webAuthnOptions || !webAuthnOptions.enabled) { throw new DbAuthError.WebAuthnError('WebAuthn is not enabled') } @@ -875,7 +878,6 @@ export class DbAuthHandler< if (this.options.webAuthn === undefined || !this.options.webAuthn.enabled) { throw new DbAuthError.WebAuthnError('WebAuthn is not enabled') } - await this.init() const webAuthnOptions = this.options.webAuthn @@ -1227,7 +1229,7 @@ export class DbAuthHandler< // checks the CSRF token in the header against the CSRF token in the session // and throw an error if they are not the same (not used yet) - _validateCsrf() { + async _validateCsrf() { if ( this.sessionCsrfToken !== this.normalizedRequest.headers.get('csrf-token') ) { @@ -1419,7 +1421,6 @@ export class DbAuthHandler< // creates and returns a user, first checking that the username/password // values pass validation async _createUser() { - await this.init() const { username, password, ...userAttributes } = this.normalizedRequest.jsonBody || {} if ( @@ -1457,7 +1458,6 @@ export class DbAuthHandler< // figure out which auth method we're trying to call async _getAuthMethod() { - await this.init() // try getting it from the query string, /.redwood/functions/auth?method=[methodName] let methodName = this.normalizedRequest.query.method as AuthMethodNames diff --git a/packages/auth-providers/dbAuth/api/src/__tests__/DbAuthHandler.fetch.test.js b/packages/auth-providers/dbAuth/api/src/__tests__/DbAuthHandler.fetch.test.js index 1976f45173c5..7f78bd11097f 100644 --- a/packages/auth-providers/dbAuth/api/src/__tests__/DbAuthHandler.fetch.test.js +++ b/packages/auth-providers/dbAuth/api/src/__tests__/DbAuthHandler.fetch.test.js @@ -1,6 +1,17 @@ import crypto from 'node:crypto' import path from 'node:path' +import { + vi, + describe, + it, + expect, + beforeAll, + afterAll, + beforeEach, + afterEach, +} from 'vitest' + import { DbAuthHandler } from '../DbAuthHandler' import * as dbAuthError from '../errors' import { hashToken } from '../shared' @@ -136,7 +147,7 @@ let req, context, options describe('dbAuth', () => { beforeEach(() => { // hide deprecation warnings during test - jest.spyOn(console, 'warn').mockImplementation(() => {}) + vi.spyOn(console, 'warn').mockImplementation(() => {}) // encryption key so results are consistent regardless of settings in .env process.env.SESSION_SECRET = SESSION_SECRET delete process.env.DBAUTH_COOKIE_DOMAIN @@ -221,7 +232,7 @@ describe('dbAuth', () => { }) afterEach(async () => { - jest.spyOn(console, 'warn').mockRestore() + vi.spyOn(console, 'warn').mockRestore() await db.user.deleteMany({ where: { email: 'rob@redwoodjs.com' }, }) @@ -250,22 +261,25 @@ describe('dbAuth', () => { }) describe('dbAccessor', () => { - it('returns the prisma db accessor for a model', () => { + it('returns the prisma db accessor for a model', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect(dbAuth.dbAccessor).toEqual(db.user) }) }) describe('dbCredentialAccessor', () => { - it('returns the prisma db accessor for a UserCredential model', () => { + it('returns the prisma db accessor for a UserCredential model', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect(dbAuth.dbCredentialAccessor).toEqual(db.userCredential) }) }) describe('sessionExpiresDate', () => { - it('returns a date in the future as a UTCString', () => { + it('returns a date in the future as a UTCString', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const expiresAt = new Date() expiresAt.setSeconds(expiresAt.getSeconds() + options.login.expires) @@ -274,8 +288,9 @@ describe('dbAuth', () => { }) describe('webAuthnExpiresDate', () => { - it('returns a date in the future as a UTCString', () => { + it('returns a date in the future as a UTCString', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const expiresAt = new Date() expiresAt.setSeconds(expiresAt.getSeconds() + options.webAuthn.expires) @@ -284,8 +299,9 @@ describe('dbAuth', () => { }) describe('_deleteSessionHeader', () => { - it('returns a Set-Cookie header to delete the session cookie', () => { + it('returns a Set-Cookie header to delete the session cookie', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const headers = dbAuth._deleteSessionHeader expect(Object.keys(headers).length).toEqual(1) @@ -295,7 +311,7 @@ describe('dbAuth', () => { }) describe('constructor', () => { - it('initializes some variables with passed values', () => { + it('initializes some variables with passed values', async () => { req = { headers: {} } context = { foo: 'bar' } options = { @@ -315,6 +331,7 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect(dbAuth.event).toEqual(req) expect(dbAuth.options).toEqual(options) @@ -513,6 +530,7 @@ describe('dbAuth', () => { it('parses params from a plain text body', async () => { req = { headers: {}, body: `{"foo":"bar", "baz":123}` } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() // Need to wait for reqq to be parsed await dbAuth.init() @@ -523,89 +541,53 @@ describe('dbAuth', () => { }) }) - it.skip('parses an empty plain text body and still sets params', async () => { - // @TODO(Rob): This test is failing due to refactor, not sure its necessary - req = { isBase64Encoded: false, headers: {}, body: '' } - context = { foo: 'bar' } - const dbAuth = new DbAuthHandler(req, context, options) - await dbAuth.init() - - expect(dbAuth.normalizedRequest.jsonBody).toEqual({}) - }) - - it.skip('parses params from an undefined body when isBase64Encoded == false', async () => { - // @TODO(Rob): This test is failing due to refactor, not sure its necessary + it('parses an empty plain text body and still sets params', async () => { + const req = new Request('http://localhost:8910/_rw_mw', { + method: 'POST', + body: '', + }) - req = { - isBase64Encoded: false, - headers: {}, - } context = { foo: 'bar' } const dbAuth = new DbAuthHandler(req, context, options) await dbAuth.init() + await dbAuth.init() expect(dbAuth.normalizedRequest.jsonBody).toEqual({}) }) - it('parses params from a base64 encoded body', async () => { - req = { - isBase64Encoded: true, - headers: {}, - body: Buffer.from(`{"foo":"bar", "baz":123}`, 'utf8'), - } - const dbAuth = new DbAuthHandler(req, context, options) - await dbAuth.init() - expect(dbAuth.normalizedRequest.jsonBody).toEqual({ - foo: 'bar', - baz: 123, - }) - }) - - it('parses params from an undefined body when isBase64Encoded == true', async () => { - // @TODO(Rob): Not sure this is necessary any more? + it('parses params from an undefined body', async () => { req = { - isBase64Encoded: true, + isBase64Encoded: false, headers: {}, } context = { foo: 'bar' } const dbAuth = new DbAuthHandler(req, context, options) await dbAuth.init() - - expect(dbAuth.normalizedRequest.jsonBody).toEqual(undefined) - }) - - it('parses params from an empty body when isBase64Encoded == true', async () => { - // @TODO(Rob): Not sure this is necessary any more? - req = { - isBase64Encoded: true, - headers: {}, - body: '', - } - context = { foo: 'bar' } - const dbAuth = new DbAuthHandler(req, context, options) await dbAuth.init() - expect(dbAuth.normalizedRequest.jsonBody).toEqual(undefined) + expect(dbAuth.normalizedRequest.jsonBody).toEqual({}) }) it('sets header-based CSRF token', async () => { req = { headers: { 'csrf-token': 'qwerty' } } const dbAuth = new DbAuthHandler(req, context, options) await dbAuth.init() + await dbAuth.init() expect(dbAuth.normalizedRequest.headers.get('csrf-token')).toEqual( 'qwerty' ) }) - it('sets session variables to nothing if session cannot be decrypted', () => { + it('sets session variables to nothing if session cannot be decrypted', async () => { req = { headers: { 'csrf-token': 'qwerty' } } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect(dbAuth.session).toBeUndefined() expect(dbAuth.sessionCsrfToken).toBeUndefined() }) - it('sets session variables to valid session data', () => { + it('sets session variables to valid session data', async () => { req = { headers: { cookie: @@ -613,6 +595,7 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect(dbAuth.session).toEqual({ foo: 'bar' }) expect(dbAuth.sessionCsrfToken).toEqual('abcd') @@ -658,6 +641,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(fetchEvent, context, options) + await dbAuth.init() const response = await dbAuth.invoke() expect(response.statusCode).toEqual(404) @@ -673,6 +657,7 @@ describe('dbAuth', () => { body: JSON.stringify({ method: 'foobar' }), }) const dbAuth = new DbAuthHandler(fetchEvent, context, options) + const response = await dbAuth.invoke() expect(response.statusCode).toEqual(404) @@ -689,7 +674,9 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(fetchEvent, context, options) - dbAuth.logout = jest.fn(() => { + await dbAuth.init() + + dbAuth.logout = vi.fn(() => { throw Error('Logout error') }) const response = await dbAuth.invoke() @@ -711,7 +698,7 @@ describe('dbAuth', () => { credentials: true, }, }) - dbAuth.logout = jest.fn(() => { + dbAuth.logout = vi.fn(() => { throw Error('Logout error') }) const response = await dbAuth.invoke() @@ -734,7 +721,8 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(fetchEvent, context, options) - dbAuth.logout = jest.fn(() => ['body', { foo: 'bar' }]) + await dbAuth.init() + dbAuth.logout = vi.fn(() => ['body', { foo: 'bar' }]) const response = await dbAuth.invoke() expect(dbAuth.logout).toHaveBeenCalled() @@ -762,6 +750,7 @@ describe('dbAuth', () => { options.forgotPassword.enabled = false const dbAuth = new DbAuthHandler(fetchEvent, context, options) + await dbAuth.init() try { await dbAuth.forgotPassword() @@ -789,6 +778,7 @@ describe('dbAuth', () => { flowNotEnabled: 'Custom flow not enabled error', } const dbAuth = new DbAuthHandler(fetchEvent, context, options) + await dbAuth.init() try { await dbAuth.forgotPassword() @@ -806,6 +796,7 @@ describe('dbAuth', () => { }) let dbAuth = new DbAuthHandler(emptyBodyReq, context, options) + await dbAuth.init() try { await dbAuth.forgotPassword() @@ -820,6 +811,7 @@ describe('dbAuth', () => { }) dbAuth = new DbAuthHandler(emptyStringReq, context, options) + await dbAuth.init() try { await dbAuth.forgotPassword() @@ -842,6 +834,7 @@ describe('dbAuth', () => { }) let dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.forgotPassword() @@ -864,6 +857,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect(user.resetToken).toEqual(undefined) expect(user.resetTokenExpiresAt).toEqual(undefined) @@ -901,6 +895,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.forgotPassword() expectLoggedOutResponse(response) @@ -921,6 +916,7 @@ describe('dbAuth', () => { expect(handlerUser.id).toEqual(user.id) } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() await dbAuth.forgotPassword() expect.assertions(1) }) @@ -936,14 +932,16 @@ describe('dbAuth', () => { body, }) - options.forgotPassword.handler = (handlerUser) => { - // user should have the raw resetToken NOT the hash + options.forgotPassword.handler = (handlerUser, token) => { + // tokens should be the raw resetToken NOT the hash // resetToken consists of 16 base64 characters - expect(handlerUser.resetToken).toMatch(/^\w{16}$/) + expect(handlerUser.resetToken).toBeUndefined() + expect(token).toMatch(/^[A-Za-z0-9/+]{16}$/) } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() await dbAuth.forgotPassword() - expect.assertions(1) + expect.assertions(2) }) it('removes the token from the forgotPassword response', async () => { @@ -961,6 +959,7 @@ describe('dbAuth', () => { return handlerUser } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.forgotPassword() const jsonResponse = JSON.parse(response[0]) @@ -981,6 +980,7 @@ describe('dbAuth', () => { // invalid db client const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() dbAuth.dbAccessor = undefined try { @@ -1008,6 +1008,7 @@ describe('dbAuth', () => { options.login.enabled = false const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.login() @@ -1035,6 +1036,7 @@ describe('dbAuth', () => { flowNotEnabled: 'Custom flow not enabled error', } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.login() @@ -1058,6 +1060,7 @@ describe('dbAuth', () => { body, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.login() @@ -1079,6 +1082,7 @@ describe('dbAuth', () => { body, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.login() @@ -1103,6 +1107,7 @@ describe('dbAuth', () => { body, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.login() @@ -1128,6 +1133,7 @@ describe('dbAuth', () => { body, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() await dbAuth.login() }) @@ -1145,6 +1151,7 @@ describe('dbAuth', () => { body, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.login() } catch (e) { @@ -1168,6 +1175,7 @@ describe('dbAuth', () => { body, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.login() } catch (e) { @@ -1187,10 +1195,11 @@ describe('dbAuth', () => { body, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.login() - expect(response[0]).toEqual({ id: user.id }) + expect(response[0].id).toEqual(user.id) }) it('returns a CSRF token in the header', async () => { @@ -1204,6 +1213,7 @@ describe('dbAuth', () => { body, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.login() expect(response[1]['csrf-token']).toMatch(UUID_REGEX) @@ -1220,6 +1230,7 @@ describe('dbAuth', () => { body, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.login() @@ -1237,6 +1248,7 @@ describe('dbAuth', () => { body, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.login() @@ -1244,8 +1256,8 @@ describe('dbAuth', () => { }) it('login db check is called with insensitive string when user has provided one in LoginFlowOptions', async () => { - jest.clearAllMocks() - const spy = jest.spyOn(db.user, 'findFirst') + vi.clearAllMocks() + const spy = vi.spyOn(db.user, 'findFirst') options.signup.usernameMatch = 'insensitive' options.login.usernameMatch = 'insensitive' @@ -1262,6 +1274,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.login() @@ -1277,8 +1290,8 @@ describe('dbAuth', () => { }) it('login db check is not called with insensitive string when user has not provided one in LoginFlowOptions', async () => { - jest.clearAllMocks() - const spy = jest.spyOn(db.user, 'findFirst') + vi.clearAllMocks() + const spy = vi.spyOn(db.user, 'findFirst') delete options.signup.usernameMatch delete options.login.usernameMatch @@ -1295,6 +1308,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() await dbAuth.login() @@ -1309,6 +1323,7 @@ describe('dbAuth', () => { describe('logout', () => { it('returns set-cookie header for removing session', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = dbAuth.logout() expectLoggedOutResponse(response) @@ -1330,6 +1345,7 @@ describe('dbAuth', () => { options.resetPassword.enabled = false const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1357,6 +1373,7 @@ describe('dbAuth', () => { flowNotEnabled: 'Custom flow not enabled error', } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1373,6 +1390,7 @@ describe('dbAuth', () => { }) let dbAuth = new DbAuthHandler(emptyBody, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1386,6 +1404,7 @@ describe('dbAuth', () => { body: JSON.stringify({ resetToken: ' ' }), }) dbAuth = new DbAuthHandler(emptyString, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1403,6 +1422,7 @@ describe('dbAuth', () => { body: JSON.stringify({ resetToken: '1234' }), }) let dbAuth = new DbAuthHandler(noPwd, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1416,6 +1436,7 @@ describe('dbAuth', () => { body: JSON.stringify({ resetToken: '1234', password: ' ' }), }) dbAuth = new DbAuthHandler(pwdEmpty, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1434,6 +1455,7 @@ describe('dbAuth', () => { }) let dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1460,6 +1482,7 @@ describe('dbAuth', () => { }) let dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1489,6 +1512,7 @@ describe('dbAuth', () => { }) let dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1523,6 +1547,7 @@ describe('dbAuth', () => { options.resetPassword.allowReusedPassword = false let dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() await expect(dbAuth.resetPassword()).rejects.toThrow( dbAuthError.ReusedPasswordError @@ -1550,6 +1575,7 @@ describe('dbAuth', () => { }) let dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() await expect(dbAuth.resetPassword()).resolves.not.toThrow() }) @@ -1573,6 +1599,7 @@ describe('dbAuth', () => { }) let dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() await expect(dbAuth.resetPassword()).resolves.not.toThrow() @@ -1604,6 +1631,7 @@ describe('dbAuth', () => { }) let dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() await expect(dbAuth.resetPassword()).resolves.not.toThrow() @@ -1637,6 +1665,7 @@ describe('dbAuth', () => { }) let dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() await dbAuth.resetPassword() expect.assertions(1) @@ -1662,6 +1691,7 @@ describe('dbAuth', () => { }) let dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.resetPassword() @@ -1688,6 +1718,7 @@ describe('dbAuth', () => { }) let dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.resetPassword() @@ -1711,6 +1742,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect.assertions(1) await expect(dbAuth.signup()).rejects.toThrow('Cannot signup') @@ -1729,6 +1761,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.signup() @@ -1755,6 +1788,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.signup() @@ -1781,6 +1815,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.signup() @@ -1807,6 +1842,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect(() => dbAuth.signup()).not.toThrow() }) @@ -1824,6 +1860,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect(() => dbAuth.signup()).not.toThrow() }) @@ -1841,6 +1878,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.signup() const newUserCount = await db.user.count() @@ -1868,6 +1906,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.signup() @@ -1887,7 +1926,6 @@ describe('dbAuth', () => { JSON.stringify({ id: user.id }) + ';' + 'token' ) - const justEncryptedSession = cookie.split('session=')[1] const headers = { cookie, } @@ -1899,19 +1937,20 @@ describe('dbAuth', () => { req.headers.get('cookie') const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.getToken() - expect(response[0]).toEqual(justEncryptedSession) + expect(response[0]).toEqual(user.id) }) it('returns nothing if user is not logged in', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.getToken() expect(response[0]).toEqual('') }) - // @TODO(Rob) HELP, change in behaviour it('returns any other error', async () => { req = { headers: { @@ -1922,12 +1961,12 @@ describe('dbAuth', () => { } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.getToken() expect(response[0]).toEqual('{"error":"User not found"}') }) - // @TODO(Rob) HELP, change in behaviour it('re-encrypts the session cookie if using the legacy algorithm', async () => { await createDbUser({ id: 7 }) req = { @@ -1940,6 +1979,7 @@ describe('dbAuth', () => { 'QKxN2vFSHAf94XYynK8LUALfDuDSdFowG6evfkFX8uszh4YZqhTiqEdshrhWbwbw' const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const [userId, headers] = await dbAuth.getToken() expect(userId).toEqual(7) @@ -1950,11 +1990,7 @@ describe('dbAuth', () => { }) }) - // @TODO: Studio should not use body to send auth impersonation details - // @TODO: Studio should not use body to send auth impersonation details - // @TODO: Studio should not use body to send auth impersonation details - // @TODO: Studio should not use body to send auth impersonation details - describe.skip('When a developer has set GraphiQL headers to mock a session cookie', () => { + describe('When a developer has set GraphiQL headers to mock a session cookie', () => { describe('when in development environment', () => { const curNodeEnv = process.env.NODE_ENV @@ -1968,44 +2004,49 @@ describe('dbAuth', () => { expect(process.env.NODE_ENV).toBe('test') }) - it('authenticates the user based on GraphiQL headers when no event.headers present', async () => { - // setup graphiQL header cookie in extensions + it('authenticates the user based on GraphiQL impersonated headers when no cookie present', async () => { + // Making Fetch API Requests with GraphiQL Headers in the body does not work because it's async + // but we can set the new 'rw-studio-impersonation-cookie' header const dbUser = await createDbUser() - req.body = JSON.stringify({ - extensions: { - headers: { - 'auth-provider': 'dbAuth', - cookie: encryptToCookie(JSON.stringify({ id: dbUser.id })), - authorization: 'Bearer ' + dbUser.id, - }, - }, + const headers = { + 'auth-provider': 'dbAuth', + 'rw-studio-impersonation-cookie': encryptToCookie( + JSON.stringify({ id: dbUser.id }) + ), + } + + const req = new Request('http://localhost:8910/_rw_mw', { + method: 'POST', + headers, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const user = await dbAuth._getCurrentUser() expect(user.id).toEqual(dbUser.id) }) - it('Cookie from GraphiQLHeaders takes precedence over event headers when authenticating user', async () => { + it('Cookie from GraphiQLHeaders takes precedence over real headers when authenticating user', async () => { // setup session cookie in GraphiQL header const dbUser = await createDbUser() const dbUserId = dbUser.id - req.body = JSON.stringify({ - extensions: { - headers: { - 'auth-provider': 'dbAuth', - cookie: encryptToCookie(JSON.stringify({ id: dbUserId })), - authorization: 'Bearer ' + dbUserId, - }, + const req = new Request('http://localhost:8910/_rw_mw', { + method: 'POST', + headers: { + 'auth-provider': 'dbAuth', + authorization: 'Bearer ' + dbUserId, + cookie: encryptToCookie(JSON.stringify({ id: 9999999999 })), // The "real" cookie with an invalid userId + // 👇 The impersonated header takes precendence + 'rw-studio-impersonation-cookie': encryptToCookie( + JSON.stringify({ id: dbUser.id }) + ), }, }) - // create session cookie in event header - req.headers.cookie = encryptToCookie(JSON.stringify({ id: 9999999999 })) - // should read session from graphiQL header, not from cookie const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const user = await dbAuth._getCurrentUser() expect(user.id).toEqual(dbUserId) }) @@ -2016,18 +2057,20 @@ describe('dbAuth', () => { const dbUser = await createDbUser() const dbUserId = dbUser.id - req.body = JSON.stringify({ - extensions: { - headers: { - 'auth-provider': 'dbAuth', - cookie: encryptToCookie(JSON.stringify({ id: dbUserId })), - authorization: 'Bearer ' + dbUserId, - }, + const req = new Request('http://localhost:8910/_rw_mw', { + method: 'POST', + headers: { + 'auth-provider': 'dbAuth', + 'rw-studio-impersonation-cookie': encryptToCookie( + JSON.stringify({ id: dbUserId }) + ), + authorization: 'Bearer ' + dbUserId, }, }) try { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() await dbAuth._getCurrentUser() } catch (e) { expect(e.message).toEqual( @@ -2053,7 +2096,6 @@ describe('dbAuth', () => { expect.assertions(1) }) - // @TODO(Rob) Failing test here it('throws an error if WebAuthn is disabled', async () => { const req = new Request('http://localhost:8910/_rw_mw', { method: 'POST', @@ -2062,6 +2104,7 @@ describe('dbAuth', () => { options.webAuthn.enabled = false const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect.assertions(1) await expect(dbAuth.webAuthnAuthenticate()).rejects.toThrow( @@ -2080,6 +2123,7 @@ describe('dbAuth', () => { headers, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect.assertions(1) await expect(dbAuth.webAuthnAuthenticate()).rejects.toThrow( @@ -2107,6 +2151,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect.assertions(1) await expect(dbAuth.webAuthnAuthenticate()).rejects.toThrow( @@ -2134,6 +2179,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect.assertions(1) try { @@ -2172,6 +2218,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const [body, headers] = await dbAuth.webAuthnAuthenticate() @@ -2183,13 +2230,13 @@ describe('dbAuth', () => { }) describe('webAuthnAuthOptions', () => { - // @TODO(Rob): HELP, failing test here it('throws an error if user is not logged in', async () => { const req = new Request('http://localhost:8910/_rw_mw', { method: 'POST', headers: {}, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.webAuthnAuthOptions() @@ -2205,6 +2252,7 @@ describe('dbAuth', () => { } options.webAuthn.enabled = false const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.webAuthnAuthOptions() @@ -2224,6 +2272,7 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.webAuthnAuthOptions() const regOptions = response[0] @@ -2251,6 +2300,7 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.webAuthnAuthOptions() const regOptions = response[0] @@ -2272,6 +2322,7 @@ describe('dbAuth', () => { headers: {}, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.webAuthnRegOptions() @@ -2289,6 +2340,7 @@ describe('dbAuth', () => { options.webAuthn.enabled = false const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth.webAuthnRegOptions() @@ -2312,6 +2364,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.webAuthnRegOptions() const regOptions = response[0] @@ -2343,6 +2396,7 @@ describe('dbAuth', () => { options.webAuthn.timeout = null const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.webAuthnRegOptions() expect(response[0].timeout).toEqual(60000) @@ -2362,6 +2416,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = await dbAuth.webAuthnRegOptions() user = await db.user.findFirst({ where: { id: user.id } }) @@ -2384,6 +2439,7 @@ describe('dbAuth', () => { body: '{"method":"webAuthnRegister","id":"GqjZOuYYppObBDeVknbrcBLkaa9imS5EJJwtCV740asUz24sdAmGFg","rawId":"GqjZOuYYppObBDeVknbrcBLkaa9imS5EJJwtCV740asUz24sdAmGFg","response":{"attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVisSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAK3OAAI1vMYKZIsLJfHwVQMAKBqo2TrmGKaTmwQ3lZJ263AS5GmvYpkuRCScLQle-NGrFM9uLHQJhhalAQIDJiABIVggGIipTQt-gcoDPOpW6Zje_Av9C0-jWb2R2PBmXJJL-c8iWCC76wxo3uzG8cPqb0A8Vij-dqMbrEytEHjuFOtiQ2dt8A","clientDataJSON":"eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiSHVHUHJRcUs3ZjUzTkx3TVpNc3RfREw5RGlnMkJCaXZEWVdXcGF3SVBWTSIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODkxMCIsImNyb3NzT3JpZ2luIjpmYWxzZSwib3RoZXJfa2V5c19jYW5fYmVfYWRkZWRfaGVyZSI6ImRvIG5vdCBjb21wYXJlIGNsaWVudERhdGFKU09OIGFnYWluc3QgYSB0ZW1wbGF0ZS4gU2VlIGh0dHBzOi8vZ29vLmdsL3lhYlBleCJ9"},"type":"public-key","clientExtensionResults":{},"transports":["internal"]}', } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() await dbAuth.webAuthnRegister() @@ -2415,6 +2471,7 @@ describe('dbAuth', () => { ), } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() await dbAuth.webAuthnRegister() @@ -2501,6 +2558,7 @@ describe('dbAuth', () => { ...options, cookie: { Secure: true }, }) + const attributes = dbAuth._cookieAttributes({}) expect(attributes[0]).toEqual('Secure') @@ -2547,8 +2605,9 @@ describe('dbAuth', () => { }) describe('_createSessionHeader()', () => { - it('returns a Set-Cookie header', () => { + it('returns a Set-Cookie header', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const headers = dbAuth._createSessionHeader({ foo: 'bar' }, 'abcd') expect(Object.keys(headers).length).toEqual(1) @@ -2564,23 +2623,27 @@ describe('dbAuth', () => { }) }) - // @TODO(Rob): Not used yet. - describe.skip('_validateCsrf()', () => { - it('returns true if session and header token match', () => { + describe('_validateCsrf()', () => { + it('returns true if session and header token match', async () => { const data = { foo: 'bar' } const token = 'abcd' - req = { + + const req = new Request('http://localhost:8910/_rw_mw', { + method: 'POST', headers: { cookie: encryptToCookie(JSON.stringify(data) + ';' + token), 'csrf-token': token, }, - } + }) + const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() + const output = await dbAuth._validateCsrf() - expect(dbAuth._validateCsrf()).toEqual(true) + expect(output).toEqual(true) }) - it('throws an error if session and header token do not match', () => { + it('throws an error if session and header token do not match', async () => { const data = { foo: 'bar' } const token = 'abcd' req = { @@ -2590,16 +2653,18 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() - expect(() => { - dbAuth._validateCsrf() - }).toThrow(dbAuthError.CsrfTokenMismatchError) + expect(async () => { + await dbAuth._validateCsrf() + }).rejects.toThrow(dbAuthError.CsrfTokenMismatchError) }) }) describe('_verifyUser()', () => { it('throws an error if username is missing', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._verifyUser(null, 'password') @@ -2621,6 +2686,7 @@ describe('dbAuth', () => { it('throws an error if password is missing', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._verifyUser('username') @@ -2654,6 +2720,7 @@ describe('dbAuth', () => { const defaultMessage = options.login.errors.usernameOrPasswordMissing delete options.login.errors.usernameOrPasswordMissing const dbAuth1 = new DbAuthHandler(req, context, options) + await dbAuth1.init() try { await dbAuth1._verifyUser(null, 'password') } catch (e) { @@ -2676,6 +2743,7 @@ describe('dbAuth', () => { it('throws a default error message if user is not found', async () => { delete options.login.errors.usernameNotFound const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._verifyUser('username', 'password') } catch (e) { @@ -2689,6 +2757,7 @@ describe('dbAuth', () => { it('throws a custom error message if user is not found', async () => { options.login.errors.usernameNotFound = 'Cannot find ${username}' const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._verifyUser('Alice', 'password') @@ -2704,6 +2773,7 @@ describe('dbAuth', () => { delete options.login.errors.incorrectPassword const dbUser = await createDbUser() const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._verifyUser(dbUser.email, 'incorrect') @@ -2719,6 +2789,7 @@ describe('dbAuth', () => { options.login.errors.incorrectPassword = 'Wrong password for ${username}' const dbUser = await createDbUser() const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._verifyUser(dbUser.email, 'incorrect') @@ -2734,6 +2805,7 @@ describe('dbAuth', () => { const dbUser = await createDbUser() // invalid db client const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() dbAuth.dbAccessor = undefined try { @@ -2748,6 +2820,7 @@ describe('dbAuth', () => { it('returns the user with matching username and password', async () => { const dbUser = await createDbUser() const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const user = await dbAuth._verifyUser(dbUser.email, 'password') expect(user.id).toEqual(dbUser.id) @@ -2761,6 +2834,7 @@ describe('dbAuth', () => { salt: '2ef27f4073c603ba8b7807c6de6d6a89', }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const user = await dbAuth._verifyUser(dbUser.email, 'password') expect(user.id).toEqual(dbUser.id) @@ -2774,6 +2848,7 @@ describe('dbAuth', () => { salt: '2ef27f4073c603ba8b7807c6de6d6a89', }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() await dbAuth._verifyUser(dbUser.email, 'password') const user = await db.user.findFirst({ where: { id: dbUser.id } }) @@ -2789,6 +2864,7 @@ describe('dbAuth', () => { describe('_getCurrentUser()', () => { it('throw an error if user is not logged in', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._getCurrentUser() @@ -2811,6 +2887,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._getCurrentUser() @@ -2836,6 +2913,7 @@ describe('dbAuth', () => { // invalid db client const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() dbAuth.dbAccessor = undefined try { @@ -2861,6 +2939,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const user = await dbAuth._getCurrentUser() expect(user.id).toEqual(dbUser.id) @@ -2884,6 +2963,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._createUser() @@ -2911,6 +2991,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._createUser() @@ -2923,7 +3004,7 @@ describe('dbAuth', () => { }) it('createUser db check is called with insensitive string when user has provided one in SignupFlowOptions', async () => { - const spy = jest.spyOn(db.user, 'findFirst') + const spy = vi.spyOn(db.user, 'findFirst') options.signup.usernameMatch = 'insensitive' const dbUser = await createDbUser() @@ -2936,6 +3017,7 @@ describe('dbAuth', () => { body, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() await dbAuth._createUser() expect(spy).toHaveBeenCalled() @@ -2947,11 +3029,11 @@ describe('dbAuth', () => { }) it('createUser db check is not called with insensitive string when user has not provided one in SignupFlowOptions', async () => { - jest.resetAllMocks() - jest.clearAllMocks() + vi.resetAllMocks() + vi.clearAllMocks() const defaultMessage = options.signup.errors.usernameTaken - const spy = jest.spyOn(db.user, 'findFirst') + const spy = vi.spyOn(db.user, 'findFirst') delete options.signup.usernameMatch const dbUser = await createDbUser() @@ -2965,6 +3047,7 @@ describe('dbAuth', () => { body, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._createUser() @@ -2996,6 +3079,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._createUser() @@ -3021,6 +3105,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._createUser() @@ -3045,6 +3130,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._createUser() } catch (e) { @@ -3068,6 +3154,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { await dbAuth._createUser() @@ -3094,6 +3181,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() try { const user = await dbAuth._createUser() @@ -3115,6 +3203,7 @@ describe('dbAuth', () => { headers: {}, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect(await dbAuth._getAuthMethod()).toEqual('logout') }) @@ -3127,6 +3216,7 @@ describe('dbAuth', () => { headers: {}, } const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect(await dbAuth._getAuthMethod()).toEqual('signup') }) @@ -3138,14 +3228,16 @@ describe('dbAuth', () => { headers: {}, }) const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect(await dbAuth._getAuthMethod()).toBeUndefined() }) }) describe('validateField', () => { - it('checks for the presence of a field', () => { + it('checks for the presence of a field', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect(() => { dbAuth._validateField('username', null) @@ -3158,24 +3250,27 @@ describe('dbAuth', () => { }).toThrow(dbAuth.FieldRequiredError) }) - it('passes validation if everything is present', () => { + it('passes validation if everything is present', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() expect(dbAuth._validateField('username', 'cannikin')).toEqual(true) }) }) describe('logoutResponse', () => { - it('returns the response array necessary to log user out', () => { + it('returns the response array necessary to log user out', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const [body, headers] = dbAuth._logoutResponse() expect(body).toEqual('') expect(headers['set-cookie']).toMatch(/^session=;/) }) - it('can accept an object to return in the body', () => { + it('can accept an object to return in the body', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const [body, _headers] = dbAuth._logoutResponse({ error: 'error message', }) @@ -3185,29 +3280,33 @@ describe('dbAuth', () => { }) describe('ok', () => { - it('returns a 200 response by default', () => { + it('returns a 200 response by default', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = dbAuth._ok('', {}) expect(response.statusCode).toEqual(200) }) - it('can return other status codes', () => { + it('can return other status codes', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = dbAuth._ok('', {}, { statusCode: 201 }) expect(response.statusCode).toEqual(201) }) - it('stringifies a JSON body', () => { + it('stringifies a JSON body', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = dbAuth._ok({ foo: 'bar' }, {}, { statusCode: 201 }) expect(response.body).toEqual('{"foo":"bar"}') }) - it('does not stringify a body that is a string already', () => { + it('does not stringify a body that is a string already', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = dbAuth._ok('{"foo":"bar"}', {}, { statusCode: 201 }) expect(response.body).toEqual('{"foo":"bar"}') @@ -3215,8 +3314,9 @@ describe('dbAuth', () => { }) describe('_notFound', () => { - it('returns a 404 response', () => { + it('returns a 404 response', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = dbAuth._notFound() expect(response.statusCode).toEqual(404) @@ -3225,8 +3325,9 @@ describe('dbAuth', () => { }) describe('_badRequest', () => { - it('returns a 400 response', () => { + it('returns a 400 response', async () => { const dbAuth = new DbAuthHandler(req, context, options) + await dbAuth.init() const response = dbAuth._badRequest('bad') expect(response.statusCode).toEqual(400) diff --git a/packages/auth-providers/dbAuth/api/src/__tests__/DbAuthHandler.test.js b/packages/auth-providers/dbAuth/api/src/__tests__/DbAuthHandler.test.js index cb3a030e7e3f..72ba44f25e9e 100644 --- a/packages/auth-providers/dbAuth/api/src/__tests__/DbAuthHandler.test.js +++ b/packages/auth-providers/dbAuth/api/src/__tests__/DbAuthHandler.test.js @@ -1,6 +1,17 @@ import crypto from 'node:crypto' import path from 'node:path' +import { + vi, + describe, + it, + expect, + beforeAll, + afterAll, + beforeEach, + afterEach, +} from 'vitest' + import { DbAuthHandler } from '../DbAuthHandler' import * as dbAuthError from '../errors' import { hashToken } from '../shared' @@ -136,7 +147,7 @@ let event, context, options describe('dbAuth', () => { beforeEach(() => { // hide deprecation warnings during test - jest.spyOn(console, 'warn').mockImplementation(() => {}) + vi.spyOn(console, 'warn').mockImplementation(() => {}) // encryption key so results are consistent regardless of settings in .env process.env.SESSION_SECRET = SESSION_SECRET delete process.env.DBAUTH_COOKIE_DOMAIN @@ -221,7 +232,7 @@ describe('dbAuth', () => { }) afterEach(async () => { - jest.spyOn(console, 'warn').mockRestore() + vi.spyOn(console, 'warn').mockRestore() await db.user.deleteMany({ where: { email: 'rob@redwoodjs.com' }, }) @@ -250,22 +261,25 @@ describe('dbAuth', () => { }) describe('dbAccessor', () => { - it('returns the prisma db accessor for a model', () => { + it('returns the prisma db accessor for a model', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect(dbAuth.dbAccessor).toEqual(db.user) }) }) describe('dbCredentialAccessor', () => { - it('returns the prisma db accessor for a UserCredential model', () => { + it('returns the prisma db accessor for a UserCredential model', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect(dbAuth.dbCredentialAccessor).toEqual(db.userCredential) }) }) describe('sessionExpiresDate', () => { - it('returns a date in the future as a UTCString', () => { + it('returns a date in the future as a UTCString', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const expiresAt = new Date() expiresAt.setSeconds(expiresAt.getSeconds() + options.login.expires) @@ -274,8 +288,9 @@ describe('dbAuth', () => { }) describe('webAuthnExpiresDate', () => { - it('returns a date in the future as a UTCString', () => { + it('returns a date in the future as a UTCString', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const expiresAt = new Date() expiresAt.setSeconds(expiresAt.getSeconds() + options.webAuthn.expires) @@ -284,8 +299,9 @@ describe('dbAuth', () => { }) describe('_deleteSessionHeader', () => { - it('returns a Set-Cookie header to delete the session cookie', () => { + it('returns a Set-Cookie header to delete the session cookie', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const headers = dbAuth._deleteSessionHeader expect(Object.keys(headers).length).toEqual(1) @@ -294,8 +310,8 @@ describe('dbAuth', () => { }) }) - describe.only('constructor', () => { - it('initializes some variables with passed values', () => { + describe('constructor', () => { + it('initializes some variables with passed values', async () => { event = { headers: {} } context = { foo: 'bar' } options = { @@ -315,6 +331,7 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect(dbAuth.event).toEqual(event) expect(dbAuth.options).toEqual(options) @@ -523,9 +540,14 @@ describe('dbAuth', () => { }) }) - it.skip('parses an empty plain text body and still sets params', async () => { - // @TODO(Rob): This test is failing due to refactor, not sure its necessary - event = { isBase64Encoded: false, headers: {}, body: '' } + it('parses an empty plain text body and still sets params', async () => { + event = { + isBase64Encoded: false, + headers: { + bazomga: 'yo', + }, + body: '', + } context = { foo: 'bar' } const dbAuth = new DbAuthHandler(event, context, options) await dbAuth.init() @@ -533,9 +555,7 @@ describe('dbAuth', () => { expect(dbAuth.normalizedRequest.jsonBody).toEqual({}) }) - it.skip('parses params from an undefined body when isBase64Encoded == false', async () => { - // @TODO(Rob): This test is failing due to refactor, not sure its necessary - + it('parses params from an undefined body when isBase64Encoded == false', async () => { event = { isBase64Encoded: false, headers: {}, @@ -555,6 +575,7 @@ describe('dbAuth', () => { } const dbAuth = new DbAuthHandler(event, context, options) await dbAuth.init() + expect(dbAuth.normalizedRequest.jsonBody).toEqual({ foo: 'bar', baz: 123, @@ -562,7 +583,6 @@ describe('dbAuth', () => { }) it('parses params from an undefined body when isBase64Encoded == true', async () => { - // @TODO(Rob): Not sure this is necessary any more? event = { isBase64Encoded: true, headers: {}, @@ -571,11 +591,10 @@ describe('dbAuth', () => { const dbAuth = new DbAuthHandler(event, context, options) await dbAuth.init() - expect(dbAuth.normalizedRequest.jsonBody).toEqual(undefined) + expect(dbAuth.normalizedRequest.jsonBody).toEqual({}) }) it('parses params from an empty body when isBase64Encoded == true', async () => { - // @TODO(Rob): Not sure this is necessary any more? event = { isBase64Encoded: true, headers: {}, @@ -585,7 +604,7 @@ describe('dbAuth', () => { const dbAuth = new DbAuthHandler(event, context, options) await dbAuth.init() - expect(dbAuth.normalizedRequest.jsonBody).toEqual(undefined) + expect(dbAuth.normalizedRequest.jsonBody).toEqual({}) }) it('sets header-based CSRF token', async () => { @@ -597,15 +616,16 @@ describe('dbAuth', () => { ) }) - it('sets session variables to nothing if session cannot be decrypted', () => { + it('sets session variables to nothing if session cannot be decrypted', async () => { event = { headers: { 'csrf-token': 'qwerty' } } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect(dbAuth.session).toBeUndefined() expect(dbAuth.sessionCsrfToken).toBeUndefined() }) - it('sets session variables to valid session data', () => { + it('sets session variables to valid session data', async () => { event = { headers: { cookie: @@ -613,6 +633,7 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect(dbAuth.session).toEqual({ foo: 'bar' }) expect(dbAuth.sessionCsrfToken).toEqual('abcd') @@ -633,6 +654,7 @@ describe('dbAuth', () => { event.httpMethod = 'GET' event.headers.cookie = 'session=invalid' const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.invoke() expect(response.headers['set-cookie']).toEqual(LOGOUT_COOKIE) @@ -644,6 +666,7 @@ describe('dbAuth', () => { event.headers.cookie = 'session=ko6iXKV11DSjb6kFJ4iwcf1FEqa5wPpbL1sdtKiV51Y=|cQaYkOPG/r3ILxWiFiz90w==' const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.invoke() expect(response.statusCode).toEqual(404) @@ -655,6 +678,7 @@ describe('dbAuth', () => { event.headers.cookie = 'session=ko6iXKV11DSjb6kFJ4iwcf1FEqa5wPpbL1sdtKiV51Y=|cQaYkOPG/r3ILxWiFiz90w==' const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.invoke() expect(response.statusCode).toEqual(404) @@ -666,7 +690,8 @@ describe('dbAuth', () => { event.headers.cookie = 'session=ko6iXKV11DSjb6kFJ4iwcf1FEqa5wPpbL1sdtKiV51Y=|cQaYkOPG/r3ILxWiFiz90w==' const dbAuth = new DbAuthHandler(event, context, options) - dbAuth.logout = jest.fn(() => { + await dbAuth.init() + dbAuth.logout = vi.fn(() => { throw Error('Logout error') }) const response = await dbAuth.invoke() @@ -686,7 +711,9 @@ describe('dbAuth', () => { credentials: true, }, }) - dbAuth.logout = jest.fn(() => { + await dbAuth.init() + + dbAuth.logout = vi.fn(() => { throw Error('Logout error') }) const response = await dbAuth.invoke() @@ -704,7 +731,8 @@ describe('dbAuth', () => { event.headers.cookie = 'session=ko6iXKV11DSjb6kFJ4iwcf1FEqa5wPpbL1sdtKiV51Y=|cQaYkOPG/r3ILxWiFiz90w==' const dbAuth = new DbAuthHandler(event, context, options) - dbAuth.logout = jest.fn(() => ['body', { foo: 'bar' }]) + await dbAuth.init() + dbAuth.logout = vi.fn(() => ['body', { foo: 'bar' }]) const response = await dbAuth.invoke() expect(dbAuth.logout).toHaveBeenCalled() @@ -726,6 +754,7 @@ describe('dbAuth', () => { }) options.forgotPassword.enabled = false const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.forgotPassword() @@ -747,6 +776,7 @@ describe('dbAuth', () => { flowNotEnabled: 'Custom flow not enabled error', } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.forgotPassword() @@ -759,7 +789,8 @@ describe('dbAuth', () => { it('throws an error if username is blank', async () => { // missing completely event.body = JSON.stringify({}) - let dbAuth = new DbAuthHandler(event, context, options) + const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.forgotPassword() @@ -769,10 +800,10 @@ describe('dbAuth', () => { // empty string event.body = JSON.stringify({ username: ' ' }) - dbAuth = new DbAuthHandler(event, context, options) - + const dbAuth2 = new DbAuthHandler(event, context, options) + await dbAuth2.init() try { - await dbAuth.forgotPassword() + await dbAuth2.forgotPassword() } catch (e) { expect(e).toBeInstanceOf(dbAuthError.UsernameRequiredError) } @@ -786,6 +817,7 @@ describe('dbAuth', () => { username: 'notfound', }) let dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.forgotPassword() @@ -802,6 +834,7 @@ describe('dbAuth', () => { username: user.email, }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect(user.resetToken).toEqual(undefined) expect(user.resetTokenExpiresAt).toEqual(undefined) @@ -834,6 +867,7 @@ describe('dbAuth', () => { username: user.email, }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.forgotPassword() expectLoggedOutResponse(response) @@ -849,6 +883,7 @@ describe('dbAuth', () => { expect(token).toMatch(/^[A-Za-z0-9/+]{16}$/) } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() await dbAuth.forgotPassword() expect.assertions(2) }) @@ -865,6 +900,7 @@ describe('dbAuth', () => { expect(token).toMatch(/^[A-Za-z0-9/+]{16}$/) } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() await dbAuth.forgotPassword() expect.assertions(2) }) @@ -878,6 +914,7 @@ describe('dbAuth', () => { return handlerUser } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.forgotPassword() const jsonResponse = JSON.parse(response[0]) @@ -892,14 +929,13 @@ describe('dbAuth', () => { }) // invalid db client const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() dbAuth.dbAccessor = undefined - try { await dbAuth.forgotPassword() } catch (e) { expect(e).toBeInstanceOf(dbAuthError.GenericError) } - expect.assertions(1) }) }) @@ -913,6 +949,7 @@ describe('dbAuth', () => { }) options.login.enabled = false const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.login() @@ -934,6 +971,7 @@ describe('dbAuth', () => { flowNotEnabled: 'Custom flow not enabled error', } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.login() @@ -952,6 +990,7 @@ describe('dbAuth', () => { password: 'password', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.login() @@ -969,6 +1008,7 @@ describe('dbAuth', () => { password: 'incorrect', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.login() @@ -989,6 +1029,7 @@ describe('dbAuth', () => { throw new Error('Cannot log in') } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.login() @@ -1010,6 +1051,7 @@ describe('dbAuth', () => { return user } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() await dbAuth.login() }) @@ -1023,6 +1065,7 @@ describe('dbAuth', () => { return null } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.login() } catch (e) { @@ -1042,6 +1085,7 @@ describe('dbAuth', () => { return { name: 'Rob' } } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.login() } catch (e) { @@ -1057,6 +1101,7 @@ describe('dbAuth', () => { password: 'password', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.login() @@ -1070,6 +1115,7 @@ describe('dbAuth', () => { password: 'password', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.login() expect(response[1]['csrf-token']).toMatch(UUID_REGEX) @@ -1082,6 +1128,7 @@ describe('dbAuth', () => { password: 'password', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.login() @@ -1095,6 +1142,7 @@ describe('dbAuth', () => { password: 'password', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.login() @@ -1102,8 +1150,8 @@ describe('dbAuth', () => { }) it('login db check is called with insensitive string when user has provided one in LoginFlowOptions', async () => { - jest.clearAllMocks() - const spy = jest.spyOn(db.user, 'findFirst') + vi.clearAllMocks() + const spy = vi.spyOn(db.user, 'findFirst') options.signup.usernameMatch = 'insensitive' options.login.usernameMatch = 'insensitive' @@ -1115,6 +1163,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.login() @@ -1130,8 +1179,8 @@ describe('dbAuth', () => { }) it('login db check is not called with insensitive string when user has not provided one in LoginFlowOptions', async () => { - jest.clearAllMocks() - const spy = jest.spyOn(db.user, 'findFirst') + vi.clearAllMocks() + const spy = vi.spyOn(db.user, 'findFirst') delete options.signup.usernameMatch delete options.login.usernameMatch @@ -1143,6 +1192,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() await dbAuth.login() @@ -1157,6 +1207,7 @@ describe('dbAuth', () => { describe('logout', () => { it('returns set-cookie header for removing session', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = dbAuth.logout() expectLoggedOutResponse(response) @@ -1172,6 +1223,7 @@ describe('dbAuth', () => { }) options.resetPassword.enabled = false const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1193,6 +1245,7 @@ describe('dbAuth', () => { flowNotEnabled: 'Custom flow not enabled error', } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1205,7 +1258,7 @@ describe('dbAuth', () => { // missing completely event.body = JSON.stringify({}) let dbAuth = new DbAuthHandler(event, context, options) - + await dbAuth.init() try { await dbAuth.resetPassword() } catch (e) { @@ -1215,6 +1268,7 @@ describe('dbAuth', () => { // empty string event.body = JSON.stringify({ resetToken: ' ' }) dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1229,6 +1283,7 @@ describe('dbAuth', () => { // missing completely event.body = JSON.stringify({ resetToken: '1234' }) let dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1239,6 +1294,7 @@ describe('dbAuth', () => { // empty string event.body = JSON.stringify({ resetToken: '1234', password: ' ' }) dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1252,6 +1308,7 @@ describe('dbAuth', () => { it('throws an error if no user found with resetToken', async () => { event.body = JSON.stringify({ resetToken: '1234', password: 'password' }) let dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1273,6 +1330,7 @@ describe('dbAuth', () => { event.body = JSON.stringify({ resetToken: '1234', password: 'password1' }) let dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1297,6 +1355,7 @@ describe('dbAuth', () => { password: 'password1', }) let dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.resetPassword() @@ -1326,6 +1385,7 @@ describe('dbAuth', () => { }) options.resetPassword.allowReusedPassword = false let dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() await expect(dbAuth.resetPassword()).rejects.toThrow( dbAuthError.ReusedPasswordError @@ -1348,6 +1408,7 @@ describe('dbAuth', () => { }) options.resetPassword.allowReusedPassword = true let dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() await expect(dbAuth.resetPassword()).resolves.not.toThrow() }) @@ -1366,6 +1427,7 @@ describe('dbAuth', () => { password: 'new-password', }) let dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() await expect(dbAuth.resetPassword()).resolves.not.toThrow() @@ -1392,6 +1454,7 @@ describe('dbAuth', () => { password: 'new-password', }) let dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() await expect(dbAuth.resetPassword()).resolves.not.toThrow() @@ -1420,6 +1483,7 @@ describe('dbAuth', () => { expect(handlerUser.id).toEqual(user.id) } let dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() await dbAuth.resetPassword() expect.assertions(1) @@ -1440,6 +1504,7 @@ describe('dbAuth', () => { }) options.resetPassword.handler = () => false let dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.resetPassword() @@ -1461,7 +1526,7 @@ describe('dbAuth', () => { }) options.resetPassword.handler = () => true let dbAuth = new DbAuthHandler(event, context, options) - + await dbAuth.init() const response = await dbAuth.resetPassword() expectLoggedInResponse(response) @@ -1479,6 +1544,7 @@ describe('dbAuth', () => { throw Error('Cannot signup') } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect.assertions(1) await expect(dbAuth.signup()).rejects.toThrow('Cannot signup') @@ -1492,6 +1558,7 @@ describe('dbAuth', () => { }) options.signup.enabled = false const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.signup() @@ -1513,6 +1580,7 @@ describe('dbAuth', () => { flowNotEnabled: 'Custom flow not enabled error', } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.signup() @@ -1534,6 +1602,7 @@ describe('dbAuth', () => { } } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.signup() @@ -1555,6 +1624,7 @@ describe('dbAuth', () => { } } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect(() => dbAuth.signup()).not.toThrow() }) @@ -1567,6 +1637,7 @@ describe('dbAuth', () => { }) delete options.signup.passwordValidation const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect(() => dbAuth.signup()).not.toThrow() }) @@ -1579,6 +1650,7 @@ describe('dbAuth', () => { }) const oldUserCount = await db.user.count() const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.signup() const newUserCount = await db.user.count() @@ -1601,6 +1673,7 @@ describe('dbAuth', () => { return 'Hello, world' } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.signup() @@ -1613,29 +1686,28 @@ describe('dbAuth', () => { }) }) - describe.only('getToken', () => { + describe('getToken', () => { it('returns the token from the cookie', async () => { const user = await createDbUser() const cookie = encryptToCookie( JSON.stringify({ id: user.id }) + ';' + 'token' ) - const justEncryptedSession = cookie.split('session=')[1] - event = { headers: { cookie, }, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.getToken() - expect(response[0]).toEqual(justEncryptedSession) + expect(response[0]).toEqual(user.id) }) - // @TODO Rob HELP, change in behaviour it('returns nothing if user is not logged in', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.getToken() expect(response[0]).toEqual('') @@ -1651,12 +1723,12 @@ describe('dbAuth', () => { } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.getToken() expect(response[0]).toEqual('{"error":"User not found"}') }) - // @TODO Rob HELP, change in behaviour it('re-encrypts the session cookie if using the legacy algorithm', async () => { await createDbUser({ id: 7 }) event = { @@ -1669,6 +1741,7 @@ describe('dbAuth', () => { 'QKxN2vFSHAf94XYynK8LUALfDuDSdFowG6evfkFX8uszh4YZqhTiqEdshrhWbwbw' const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const [userId, headers] = await dbAuth.getToken() expect(userId).toEqual(7) @@ -1679,11 +1752,7 @@ describe('dbAuth', () => { }) }) - // @TODO: Studio should not use body to send auth impersonation details - // @TODO: Studio should not use body to send auth impersonation details - // @TODO: Studio should not use body to send auth impersonation details - // @TODO: Studio should not use body to send auth impersonation details - describe.skip('When a developer has set GraphiQL headers to mock a session cookie', () => { + describe('When a developer has set GraphiQL headers to mock a session cookie', () => { describe('when in development environment', () => { const curNodeEnv = process.env.NODE_ENV @@ -1711,6 +1780,7 @@ describe('dbAuth', () => { }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const user = await dbAuth._getCurrentUser() expect(user.id).toEqual(dbUser.id) }) @@ -1737,6 +1807,7 @@ describe('dbAuth', () => { // should read session from graphiQL header, not from cookie const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const user = await dbAuth._getCurrentUser() expect(user.id).toEqual(dbUserId) }) @@ -1759,6 +1830,7 @@ describe('dbAuth', () => { try { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() await dbAuth._getCurrentUser() } catch (e) { expect(e.message).toEqual( @@ -1790,6 +1862,7 @@ describe('dbAuth', () => { } options.webAuthn.enabled = false const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect.assertions(1) await expect(dbAuth.webAuthnAuthenticate()).rejects.toThrow( @@ -1803,6 +1876,7 @@ describe('dbAuth', () => { body: '{"method":"webAuthnAuthenticate","id":"CxMJqILwYufSaEQsJX6rKHw_LkMXAGU64PaKU55l6ejZ4FNO5kBLiA","rawId":"CxMJqILwYufSaEQsJX6rKHw_LkMXAGU64PaKU55l6ejZ4FNO5kBLiA","response":{"authenticatorData":"SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFAAAAAA","clientDataJSON":"eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiTHRnV3BoWUtfZU41clhjX0hkdlVMdk9xcFBXeW9SdmJtbDJQbzAwVUhhZyIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODkxMCIsImNyb3NzT3JpZ2luIjpmYWxzZSwib3RoZXJfa2V5c19jYW5fYmVfYWRkZWRfaGVyZSI6ImRvIG5vdCBjb21wYXJlIGNsaWVudERhdGFKU09OIGFnYWluc3QgYSB0ZW1wbGF0ZS4gU2VlIGh0dHBzOi8vZ29vLmdsL3lhYlBleCJ9","signature":"MEUCIQD3NOM7Aw0HxPw6EFGf86iwf2yd3p4NncNNLcjd-86zgwIgHuh80bLNV7EcwBi4IAcH57iueLg0X2gLtO5_Y6PMCFE","userHandle":"2"},"type":"public-key","clientExtensionResults":{}}', } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect.assertions(1) await expect(dbAuth.webAuthnAuthenticate()).rejects.toThrow( @@ -1827,6 +1901,7 @@ describe('dbAuth', () => { body: '{"method":"webAuthnAuthenticate","id":"CxMJqILwYufSaEQsJX6rKHw_LkMXAGU64PaKU55l6ejZ4FNO5kBLiA","rawId":"CxMJqILwYufSaEQsJX6rKHw_LkMXAGU64PaKU55l6ejZ4FNO5kBLiA","response":{"authenticatorData":"SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFAAAAAA","clientDataJSON":"eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiTHRnV3BoWUtfZU41clhjX0hkdlVMdk9xcFBXeW9SdmJtbDJQbzAwVUhhZyIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODkxMCIsImNyb3NzT3JpZ2luIjpmYWxzZSwib3RoZXJfa2V5c19jYW5fYmVfYWRkZWRfaGVyZSI6ImRvIG5vdCBjb21wYXJlIGNsaWVudERhdGFKU09OIGFnYWluc3QgYSB0ZW1wbGF0ZS4gU2VlIGh0dHBzOi8vZ29vLmdsL3lhYlBleCJ9","signature":"MEUCIQD3NOM7Aw0HxPw6EFGf86iwf2yd3p4NncNNLcjd-86zgwIgHuh80bLNV7EcwBi4IAcH57iueLg0X2gLtO5_Y6PMCFE","userHandle":"2"},"type":"public-key","clientExtensionResults":{}}', } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect.assertions(1) await expect(dbAuth.webAuthnAuthenticate()).rejects.toThrow( @@ -1851,6 +1926,7 @@ describe('dbAuth', () => { body: '{"method":"webAuthnAuthenticate","id":"CxMJqILwYufSaEQsJX6rKHw_LkMXAGU64PaKU55l6ejZ4FNO5kBLiA","rawId":"CxMJqILwYufSaEQsJX6rKHw_LkMXAGU64PaKU55l6ejZ4FNO5kBLiA","response":{"authenticatorData":"SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFAAAAAA","clientDataJSON":"eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiTHRnV3BoWUtfZU41clhjX0hkdlVMdk9xcFBXeW9SdmJtbDJQbzAwVUhhZyIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODkxMCIsImNyb3NzT3JpZ2luIjpmYWxzZSwib3RoZXJfa2V5c19jYW5fYmVfYWRkZWRfaGVyZSI6ImRvIG5vdCBjb21wYXJlIGNsaWVudERhdGFKU09OIGFnYWluc3QgYSB0ZW1wbGF0ZS4gU2VlIGh0dHBzOi8vZ29vLmdsL3lhYlBleCJ9","signature":"MEUCIQD3NOM7Aw0HxPw6EFGf86iwf2yd3p4NncNNLcjd-86zgwIgHuh80bLNV7EcwBi4IAcH57iueLg0X2gLtO5_Y6PMCFE","userHandle":"2"},"type":"public-key","clientExtensionResults":{}}', } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect.assertions(1) try { @@ -1887,6 +1963,7 @@ describe('dbAuth', () => { body: '{"method":"webAuthnAuthenticate","id":"CxMJqILwYufSaEQsJX6rKHw_LkMXAGU64PaKU55l6ejZ4FNO5kBLiA","rawId":"CxMJqILwYufSaEQsJX6rKHw_LkMXAGU64PaKU55l6ejZ4FNO5kBLiA","response":{"authenticatorData":"SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFAAAAAA","clientDataJSON":"eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiTHRnV3BoWUtfZU41clhjX0hkdlVMdk9xcFBXeW9SdmJtbDJQbzAwVUhhZyIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODkxMCIsImNyb3NzT3JpZ2luIjpmYWxzZSwib3RoZXJfa2V5c19jYW5fYmVfYWRkZWRfaGVyZSI6ImRvIG5vdCBjb21wYXJlIGNsaWVudERhdGFKU09OIGFnYWluc3QgYSB0ZW1wbGF0ZS4gU2VlIGh0dHBzOi8vZ29vLmdsL3lhYlBleCJ9","signature":"MEUCIQD3NOM7Aw0HxPw6EFGf86iwf2yd3p4NncNNLcjd-86zgwIgHuh80bLNV7EcwBi4IAcH57iueLg0X2gLtO5_Y6PMCFE","userHandle":"2"},"type":"public-key","clientExtensionResults":{}}', } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const [body, headers] = await dbAuth.webAuthnAuthenticate() @@ -1903,6 +1980,7 @@ describe('dbAuth', () => { headers: {}, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.webAuthnAuthOptions() @@ -1918,6 +1996,7 @@ describe('dbAuth', () => { } options.webAuthn.enabled = false const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.webAuthnAuthOptions() @@ -1937,6 +2016,7 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.webAuthnAuthOptions() const regOptions = response[0] @@ -1964,6 +2044,7 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.webAuthnAuthOptions() const regOptions = response[0] @@ -1984,6 +2065,7 @@ describe('dbAuth', () => { headers: {}, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.webAuthnRegOptions() @@ -1999,6 +2081,7 @@ describe('dbAuth', () => { } options.webAuthn.enabled = false const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth.webAuthnRegOptions() @@ -2018,6 +2101,7 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.webAuthnRegOptions() const regOptions = response[0] @@ -2045,6 +2129,7 @@ describe('dbAuth', () => { } options.webAuthn.timeout = null const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.webAuthnRegOptions() expect(response[0].timeout).toEqual(60000) @@ -2060,6 +2145,7 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = await dbAuth.webAuthnRegOptions() user = await db.user.findFirst({ where: { id: user.id } }) @@ -2082,6 +2168,7 @@ describe('dbAuth', () => { body: '{"method":"webAuthnRegister","id":"GqjZOuYYppObBDeVknbrcBLkaa9imS5EJJwtCV740asUz24sdAmGFg","rawId":"GqjZOuYYppObBDeVknbrcBLkaa9imS5EJJwtCV740asUz24sdAmGFg","response":{"attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVisSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAK3OAAI1vMYKZIsLJfHwVQMAKBqo2TrmGKaTmwQ3lZJ263AS5GmvYpkuRCScLQle-NGrFM9uLHQJhhalAQIDJiABIVggGIipTQt-gcoDPOpW6Zje_Av9C0-jWb2R2PBmXJJL-c8iWCC76wxo3uzG8cPqb0A8Vij-dqMbrEytEHjuFOtiQ2dt8A","clientDataJSON":"eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiSHVHUHJRcUs3ZjUzTkx3TVpNc3RfREw5RGlnMkJCaXZEWVdXcGF3SVBWTSIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODkxMCIsImNyb3NzT3JpZ2luIjpmYWxzZSwib3RoZXJfa2V5c19jYW5fYmVfYWRkZWRfaGVyZSI6ImRvIG5vdCBjb21wYXJlIGNsaWVudERhdGFKU09OIGFnYWluc3QgYSB0ZW1wbGF0ZS4gU2VlIGh0dHBzOi8vZ29vLmdsL3lhYlBleCJ9"},"type":"public-key","clientExtensionResults":{},"transports":["internal"]}', } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() await dbAuth.webAuthnRegister() @@ -2113,6 +2200,7 @@ describe('dbAuth', () => { ), } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() await dbAuth.webAuthnRegister() @@ -2149,14 +2237,16 @@ describe('dbAuth', () => { }) describe('_webAuthnCookie', () => { - it('returns the parts needed for the webAuthn cookie, defaulted to future expire', () => { + it('returns the parts needed for the webAuthn cookie, defaulted to future expire', async () => { const dbAuth = new DbAuthHandler({ headers: {} }, context, options) + await dbAuth.init() expect(dbAuth._webAuthnCookie('1234')).toMatch('webAuthn=1234;Expires=') }) - it('returns the parts needed for the expire the webAuthn cookie', () => { + it('returns the parts needed for the expire the webAuthn cookie', async () => { const dbAuth = new DbAuthHandler({ headers: {} }, context, options) + await dbAuth.init() expect(dbAuth._webAuthnCookie('1234', 'now')).toMatch( 'webAuthn=1234;Expires=Thu, 01 Jan 1970 00:00:00 GMT' @@ -2182,6 +2272,7 @@ describe('dbAuth', () => { }, } ) + const attributes = dbAuth._cookieAttributes({}) expect(attributes.length).toEqual(6) @@ -2245,8 +2336,9 @@ describe('dbAuth', () => { }) describe('_createSessionHeader()', () => { - it('returns a Set-Cookie header', () => { + it('returns a Set-Cookie header', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const headers = dbAuth._createSessionHeader({ foo: 'bar' }, 'abcd') expect(Object.keys(headers).length).toEqual(1) @@ -2263,7 +2355,7 @@ describe('dbAuth', () => { }) describe('_validateCsrf()', () => { - it('returns true if session and header token match', () => { + it('returns true if session and header token match', async () => { const data = { foo: 'bar' } const token = 'abcd' event = { @@ -2273,11 +2365,14 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() - expect(dbAuth._validateCsrf()).toEqual(true) + const output = await dbAuth._validateCsrf() + + expect(output).toEqual(true) }) - it('throws an error if session and header token do not match', () => { + it('throws an error if session and header token do not match', async () => { const data = { foo: 'bar' } const token = 'abcd' event = { @@ -2287,16 +2382,18 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() - expect(() => { - dbAuth._validateCsrf() - }).toThrow(dbAuthError.CsrfTokenMismatchError) + expect(async () => { + await dbAuth._validateCsrf() + }).rejects.toThrow(dbAuthError.CsrfTokenMismatchError) }) }) describe('_verifyUser()', () => { it('throws an error if username is missing', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._verifyUser(null, 'password') @@ -2318,25 +2415,23 @@ describe('dbAuth', () => { it('throws an error if password is missing', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._verifyUser('username') } catch (e) { expect(e).toBeInstanceOf(dbAuthError.UsernameAndPasswordRequiredError) } - try { await dbAuth._verifyUser('username', null) } catch (e) { expect(e).toBeInstanceOf(dbAuthError.UsernameAndPasswordRequiredError) } - try { await dbAuth._verifyUser('username', '') } catch (e) { expect(e).toBeInstanceOf(dbAuthError.UsernameAndPasswordRequiredError) } - try { await dbAuth._verifyUser('username', ' ') } catch (e) { @@ -2351,6 +2446,7 @@ describe('dbAuth', () => { const defaultMessage = options.login.errors.usernameOrPasswordMissing delete options.login.errors.usernameOrPasswordMissing const dbAuth1 = new DbAuthHandler(event, context, options) + await dbAuth1.init() try { await dbAuth1._verifyUser(null, 'password') } catch (e) { @@ -2360,7 +2456,6 @@ describe('dbAuth', () => { // custom error message options.login.errors.usernameOrPasswordMissing = 'Missing!' const customMessage = new DbAuthHandler(event, context, options) - try { await customMessage._verifyUser(null, 'password') } catch (e) { @@ -2373,6 +2468,7 @@ describe('dbAuth', () => { it('throws a default error message if user is not found', async () => { delete options.login.errors.usernameNotFound const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._verifyUser('username', 'password') } catch (e) { @@ -2386,6 +2482,7 @@ describe('dbAuth', () => { it('throws a custom error message if user is not found', async () => { options.login.errors.usernameNotFound = 'Cannot find ${username}' const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._verifyUser('Alice', 'password') @@ -2401,6 +2498,7 @@ describe('dbAuth', () => { delete options.login.errors.incorrectPassword const dbUser = await createDbUser() const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._verifyUser(dbUser.email, 'incorrect') @@ -2416,6 +2514,7 @@ describe('dbAuth', () => { options.login.errors.incorrectPassword = 'Wrong password for ${username}' const dbUser = await createDbUser() const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._verifyUser(dbUser.email, 'incorrect') @@ -2431,20 +2530,20 @@ describe('dbAuth', () => { const dbUser = await createDbUser() // invalid db client const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() dbAuth.dbAccessor = undefined - try { await dbAuth._verifyUser(dbUser.email, 'password') } catch (e) { expect(e).toBeInstanceOf(dbAuthError.GenericError) } - expect.assertions(1) }) it('returns the user with matching username and password', async () => { const dbUser = await createDbUser() const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const user = await dbAuth._verifyUser(dbUser.email, 'password') expect(user.id).toEqual(dbUser.id) @@ -2458,6 +2557,7 @@ describe('dbAuth', () => { salt: '2ef27f4073c603ba8b7807c6de6d6a89', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const user = await dbAuth._verifyUser(dbUser.email, 'password') expect(user.id).toEqual(dbUser.id) @@ -2471,6 +2571,7 @@ describe('dbAuth', () => { salt: '2ef27f4073c603ba8b7807c6de6d6a89', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() await dbAuth._verifyUser(dbUser.email, 'password') const user = await db.user.findFirst({ where: { id: dbUser.id } }) @@ -2486,13 +2587,13 @@ describe('dbAuth', () => { describe('_getCurrentUser()', () => { it('throw an error if user is not logged in', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._getCurrentUser() } catch (e) { expect(e).toBeInstanceOf(dbAuthError.NotLoggedInError) } - expect.assertions(1) }) @@ -2504,13 +2605,13 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._getCurrentUser() } catch (e) { expect(e).toBeInstanceOf(dbAuthError.UserNotFoundError) } - expect.assertions(1) }) @@ -2525,14 +2626,13 @@ describe('dbAuth', () => { } // invalid db client const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() dbAuth.dbAccessor = undefined - try { await dbAuth._getCurrentUser() } catch (e) { expect(e).toBeInstanceOf(dbAuthError.GenericError) } - expect.assertions(1) }) @@ -2546,6 +2646,7 @@ describe('dbAuth', () => { }, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const user = await dbAuth._getCurrentUser() expect(user.id).toEqual(dbUser.id) @@ -2562,6 +2663,7 @@ describe('dbAuth', () => { password: 'password', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._createUser() @@ -2583,6 +2685,7 @@ describe('dbAuth', () => { password: 'password', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._createUser() @@ -2595,7 +2698,7 @@ describe('dbAuth', () => { }) it('createUser db check is called with insensitive string when user has provided one in SignupFlowOptions', async () => { - const spy = jest.spyOn(db.user, 'findFirst') + const spy = vi.spyOn(db.user, 'findFirst') options.signup.usernameMatch = 'insensitive' const dbUser = await createDbUser() @@ -2604,6 +2707,7 @@ describe('dbAuth', () => { password: 'password', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() await dbAuth._createUser() expect(spy).toHaveBeenCalled() @@ -2615,11 +2719,11 @@ describe('dbAuth', () => { }) it('createUser db check is not called with insensitive string when user has not provided one in SignupFlowOptions', async () => { - jest.resetAllMocks() - jest.clearAllMocks() + vi.resetAllMocks() + vi.clearAllMocks() const defaultMessage = options.signup.errors.usernameTaken - const spy = jest.spyOn(db.user, 'findFirst') + const spy = vi.spyOn(db.user, 'findFirst') delete options.signup.usernameMatch const dbUser = await createDbUser() @@ -2628,6 +2732,7 @@ describe('dbAuth', () => { password: 'password', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._createUser() @@ -2653,6 +2758,7 @@ describe('dbAuth', () => { password: 'password', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._createUser() @@ -2672,6 +2778,7 @@ describe('dbAuth', () => { password: 'password', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._createUser() @@ -2690,6 +2797,7 @@ describe('dbAuth', () => { username: 'user@redwdoodjs.com', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._createUser() } catch (e) { @@ -2708,6 +2816,7 @@ describe('dbAuth', () => { username: 'user@redwdoodjs.com', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { await dbAuth._createUser() @@ -2727,6 +2836,7 @@ describe('dbAuth', () => { name: 'Rob', }) const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() try { const user = await dbAuth._createUser() @@ -2741,7 +2851,7 @@ describe('dbAuth', () => { }) describe('getAuthMethod', () => { - it('gets methodName out of the query string', () => { + it('gets methodName out of the query string', async () => { event = { path: '/.redwood/functions/auth', queryStringParameters: { method: 'logout' }, @@ -2749,11 +2859,12 @@ describe('dbAuth', () => { headers: {}, } const dbAuth = new DbAuthHandler(event, context, options) - - expect(dbAuth._getAuthMethod()).toEqual('logout') + await dbAuth.init() + const method = await dbAuth._getAuthMethod() + expect(method).toEqual('logout') }) - it('gets methodName out of a JSON body', () => { + it('gets methodName out of a JSON body', async () => { event = { path: '/.redwood/functions/auth', queryStringParameters: {}, @@ -2761,11 +2872,13 @@ describe('dbAuth', () => { headers: {}, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() + const method = await dbAuth._getAuthMethod() - expect(dbAuth._getAuthMethod()).toEqual('signup') + expect(method).toEqual('signup') }) - it('otherwise returns undefined', () => { + it('otherwise returns undefined', async () => { event = { path: '/.redwood/functions/auth', queryStringParameters: {}, @@ -2773,14 +2886,17 @@ describe('dbAuth', () => { headers: {}, } const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() - expect(dbAuth._getAuthMethod()).toBeUndefined() + const method = await dbAuth._getAuthMethod() + expect(method).toBeUndefined() }) }) describe('validateField', () => { - it('checks for the presence of a field', () => { + it('checks for the presence of a field', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect(() => { dbAuth._validateField('username', null) @@ -2793,24 +2909,27 @@ describe('dbAuth', () => { }).toThrow(dbAuth.FieldRequiredError) }) - it('passes validation if everything is present', () => { + it('passes validation if everything is present', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() expect(dbAuth._validateField('username', 'cannikin')).toEqual(true) }) }) describe('logoutResponse', () => { - it('returns the response array necessary to log user out', () => { + it('returns the response array necessary to log user out', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const [body, headers] = dbAuth._logoutResponse() expect(body).toEqual('') expect(headers['set-cookie']).toMatch(/^session=;/) }) - it('can accept an object to return in the body', () => { + it('can accept an object to return in the body', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const [body, _headers] = dbAuth._logoutResponse({ error: 'error message', }) @@ -2820,29 +2939,33 @@ describe('dbAuth', () => { }) describe('ok', () => { - it('returns a 200 response by default', () => { + it('returns a 200 response by default', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = dbAuth._ok('', {}) expect(response.statusCode).toEqual(200) }) - it('can return other status codes', () => { + it('can return other status codes', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = dbAuth._ok('', {}, { statusCode: 201 }) expect(response.statusCode).toEqual(201) }) - it('stringifies a JSON body', () => { + it('stringifies a JSON body', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = dbAuth._ok({ foo: 'bar' }, {}, { statusCode: 201 }) expect(response.body).toEqual('{"foo":"bar"}') }) - it('does not stringify a body that is a string already', () => { + it('does not stringify a body that is a string already', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = dbAuth._ok('{"foo":"bar"}', {}, { statusCode: 201 }) expect(response.body).toEqual('{"foo":"bar"}') @@ -2850,8 +2973,9 @@ describe('dbAuth', () => { }) describe('_notFound', () => { - it('returns a 404 response', () => { + it('returns a 404 response', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = dbAuth._notFound() expect(response.statusCode).toEqual(404) @@ -2860,8 +2984,9 @@ describe('dbAuth', () => { }) describe('_badRequest', () => { - it('returns a 400 response', () => { + it('returns a 400 response', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const response = dbAuth._badRequest('bad') expect(response.statusCode).toEqual(400) @@ -2870,8 +2995,9 @@ describe('dbAuth', () => { }) describe('_sanitizeUser', () => { - it('removes all but the default fields [id, email] on user', () => { + it('removes all but the default fields [id, email] on user', async () => { const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const user = { id: 1, email: 'rob@redwoodjs.com', @@ -2883,9 +3009,10 @@ describe('dbAuth', () => { expect(dbAuth._sanitizeUser(user).secret).toBeUndefined() }) - it('removes any fields not explictly allowed in allowedUserFields', () => { + it('removes any fields not explictly allowed in allowedUserFields', async () => { options.allowedUserFields = ['foo'] const dbAuth = new DbAuthHandler(event, context, options) + await dbAuth.init() const user = { id: 1, email: 'rob@redwoodjs.com', diff --git a/packages/auth-providers/dbAuth/api/src/__tests__/shared.test.ts b/packages/auth-providers/dbAuth/api/src/__tests__/shared.test.ts index d3bafbea8c39..094a59e83dc3 100644 --- a/packages/auth-providers/dbAuth/api/src/__tests__/shared.test.ts +++ b/packages/auth-providers/dbAuth/api/src/__tests__/shared.test.ts @@ -2,6 +2,7 @@ import crypto from 'node:crypto' import path from 'node:path' import type { APIGatewayProxyEvent } from 'aws-lambda' +import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest' import * as error from '../errors' import { @@ -303,9 +304,7 @@ describe('session cookie extraction', () => { expect(extractCookie(event)).toBeUndefined() }) - // @TODO: Disabled Studio Auth Implementation - // we need to avoid using body instead of headers - it.skip('extracts GraphiQL cookie from the header extensions', () => { + it('extracts GraphiQL cookie from the body extensions', () => { const dbUserId = 42 const cookie = encryptToCookie(JSON.stringify({ id: dbUserId })) @@ -322,33 +321,46 @@ describe('session cookie extraction', () => { expect(extractCookie(event)).toEqual(cookie) }) - // @TODO: Disabled Studio Auth Implementation - // we need to avoid using body instead of headers - it.skip('overwrites cookie with event header GraphiQL when in dev', () => { - const sessionCookie = encryptToCookie( - JSON.stringify({ id: 9999999999 }) + ';' + 'token' + it('extracts GraphiQL cookie from the rw-studio header (Fetch request)', () => { + const dbUserId = 42 + + const impersonatedCookie = encryptToCookie( + JSON.stringify({ id: dbUserId }) ) - event = { + const req = new Request('http://localhost:8910/_rw_mw', { + method: 'POST', headers: { - cookie: sessionCookie, + 'auth-provider': 'dbAuth', + 'rw-studio-impersonation-cookie': impersonatedCookie, + authorization: 'Bearer ' + dbUserId, }, - } + }) + + expect(extractCookie(req)).toEqual(impersonatedCookie) + }) + + it('impersonation cookie takes precendence', () => { + const sessionCookie = encryptToCookie( + JSON.stringify({ id: 9999999999 }) + ';' + 'token' + ) const dbUserId = 42 - const cookie = encryptToCookie(JSON.stringify({ id: dbUserId })) - event.body = JSON.stringify({ - extensions: { - headers: { - 'auth-provider': 'dbAuth', - cookie, - authorization: 'Bearer ' + dbUserId, - }, + const impersonatedCookie = encryptToCookie( + JSON.stringify({ id: dbUserId }) + ) + + event = { + headers: { + cookie: sessionCookie, // This user doesn't exist + 'auth-provider': 'dbAuth', + 'rw-studio-impersonation-cookie': impersonatedCookie, + authorization: 'Bearer ' + dbUserId, }, - }) + } - expect(extractCookie(event)).toEqual(cookie) + expect(extractCookie(event)).toEqual(impersonatedCookie) }) }) }) diff --git a/packages/auth-providers/dbAuth/api/src/decoder.ts b/packages/auth-providers/dbAuth/api/src/decoder.ts index 8f47c0f04363..d479f64025b8 100644 --- a/packages/auth-providers/dbAuth/api/src/decoder.ts +++ b/packages/auth-providers/dbAuth/api/src/decoder.ts @@ -13,7 +13,6 @@ export const createAuthDecoder = (cookieNameOption: string): Decoder => { const session = dbAuthSession(req.event, cookieNameOption) // We no longer compare the session id with the bearer token - // Because we only pass around the encrypted session (in both cookie and header) return session } } @@ -22,7 +21,7 @@ export const createAuthDecoder = (cookieNameOption: string): Decoder => { export const authDecoder: Decoder = async ( _authHeaderValue: string, type: string, - req: { event: APIGatewayProxyEvent } + req: { event: APIGatewayProxyEvent | Request } ) => { if (type !== 'dbAuth') { return null diff --git a/packages/auth-providers/dbAuth/api/src/shared.ts b/packages/auth-providers/dbAuth/api/src/shared.ts index 99e889f99075..2ef2dc00cd96 100644 --- a/packages/auth-providers/dbAuth/api/src/shared.ts +++ b/packages/auth-providers/dbAuth/api/src/shared.ts @@ -2,7 +2,7 @@ import crypto from 'node:crypto' import type { APIGatewayProxyEvent } from 'aws-lambda' -import { getEventHeader } from '@redwoodjs/api' +import { getEventHeader, isFetchApiRequest } from '@redwoodjs/api' import { getConfig, getConfigPath } from '@redwoodjs/project-config' import * as DbAuthError from './errors' @@ -36,9 +36,38 @@ const getPort = () => { return getConfig(configPath).api.port } -// @TODO: reimplement eventGraphiQLHeadersCookie -// Needs a re-implementation on the studio side, because using -// body to send Auth headers requires this function to be async +// When in development environment, check for auth impersonation cookie +// if user has generated graphiql headers +const eventGraphiQLHeadersCookie = (event: APIGatewayProxyEvent | Request) => { + if (process.env.NODE_ENV === 'development') { + const impersationationHeader = getEventHeader( + event, + 'rw-studio-impersonation-cookie' + ) + + if (impersationationHeader) { + return impersationationHeader + } + + // TODO: Remove code below when we remove the old way of passing the cookie + // from Studio, and decide it's OK to break compatibility with older Studio + // versions + try { + if (!isFetchApiRequest(event)) { + const jsonBody = JSON.parse(event.body ?? '{}') + return ( + jsonBody?.extensions?.headers?.cookie || + jsonBody?.extensions?.headers?.Cookie + ) + } + } catch { + // sometimes the event body isn't json + return + } + } + + return +} // decrypts session text using old CryptoJS algorithm (using node:crypto library) const legacyDecryptSession = (encryptedText: string) => { @@ -65,11 +94,7 @@ const legacyDecryptSession = (encryptedText: string) => { // Extracts the session cookie from an event, handling both // development environment GraphiQL headers and production environment headers. export const extractCookie = (event: APIGatewayProxyEvent | Request) => { - // @TODO Disabling Studio Auth impersonation: it uses body instead of headers - // this feels a bit off, but also requires the parsing to become async - - // return eventGraphiQLHeadersCookie(event) || eventHeadersCookie(event) - return getEventHeader(event, 'Cookie') + return eventGraphiQLHeadersCookie(event) || getEventHeader(event, 'Cookie') } function extractEncryptedSessionFromHeader( @@ -191,7 +216,7 @@ export const webAuthnSession = (event: APIGatewayProxyEvent | Request) => { return null } - const webAuthnCookie = cookieHeader.split(';').find((cook) => { + const webAuthnCookie = cookieHeader.split(';').find((cook: string) => { return cook.split('=')[0].trim() === 'webAuthn' }) diff --git a/packages/auth-providers/dbAuth/api/vitest.config.mts b/packages/auth-providers/dbAuth/api/vitest.config.mts new file mode 100644 index 000000000000..4c8730d4808b --- /dev/null +++ b/packages/auth-providers/dbAuth/api/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + }, +}) diff --git a/packages/auth-providers/dbAuth/setup/jest.config.js b/packages/auth-providers/dbAuth/setup/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/dbAuth/setup/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/dbAuth/setup/package.json b/packages/auth-providers/dbAuth/setup/package.json index a12106f6d30c..a80a2e321fae 100644 --- a/packages/auth-providers/dbAuth/setup/package.json +++ b/packages/auth-providers/dbAuth/setup/package.json @@ -18,9 +18,7 @@ "build:pack": "yarn pack -o redwoodjs-auth-dbauth-setup.tgz", "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", - "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src --passWithNoTests", - "test:watch": "yarn test --watch" + "prepublishOnly": "NODE_ENV=production yarn build" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -35,7 +33,6 @@ "@babel/core": "^7.22.20", "@simplewebauthn/typescript-types": "7.4.0", "@types/yargs": "17.0.32", - "jest": "29.7.0", "typescript": "5.3.3" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" diff --git a/packages/auth-providers/firebase/api/jest.config.js b/packages/auth-providers/firebase/api/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/firebase/api/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/firebase/api/package.json b/packages/auth-providers/firebase/api/package.json index e90b4cb93bb4..45841bf6e9a1 100644 --- a/packages/auth-providers/firebase/api/package.json +++ b/packages/auth-providers/firebase/api/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -32,8 +32,8 @@ "@babel/core": "^7.22.20", "@redwoodjs/api": "6.0.7", "@types/aws-lambda": "8.10.126", - "jest": "29.7.0", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/firebase/api/src/__tests__/firebase.test.ts b/packages/auth-providers/firebase/api/src/__tests__/firebase.test.ts index f65556edf46e..a7267c2b0e29 100644 --- a/packages/auth-providers/firebase/api/src/__tests__/firebase.test.ts +++ b/packages/auth-providers/firebase/api/src/__tests__/firebase.test.ts @@ -1,11 +1,12 @@ import type { APIGatewayProxyEvent, Context as LambdaContext } from 'aws-lambda' import admin from 'firebase-admin' +import { vi, test, expect } from 'vitest' import { authDecoder } from '../decoder' -const verifyIdToken = jest.fn() +const verifyIdToken = vi.fn() -jest.spyOn(admin, 'auth').mockImplementation((() => { +vi.spyOn(admin, 'auth').mockImplementation((() => { return { verifyIdToken, } diff --git a/packages/auth-providers/firebase/api/vitest.config.mts b/packages/auth-providers/firebase/api/vitest.config.mts new file mode 100644 index 000000000000..4c8730d4808b --- /dev/null +++ b/packages/auth-providers/firebase/api/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + }, +}) diff --git a/packages/auth-providers/firebase/setup/jest.config.js b/packages/auth-providers/firebase/setup/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/firebase/setup/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/firebase/setup/package.json b/packages/auth-providers/firebase/setup/package.json index 7b341fe7a0ff..c0d8c2713fe0 100644 --- a/packages/auth-providers/firebase/setup/package.json +++ b/packages/auth-providers/firebase/setup/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -31,8 +31,8 @@ "@babel/cli": "7.23.4", "@babel/core": "^7.22.20", "@types/yargs": "17.0.32", - "jest": "29.7.0", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/firebase/setup/src/__tests__/setup.test.ts b/packages/auth-providers/firebase/setup/src/__tests__/setup.test.ts index b83698bd800a..6a5cb4dc2a22 100644 --- a/packages/auth-providers/firebase/setup/src/__tests__/setup.test.ts +++ b/packages/auth-providers/firebase/setup/src/__tests__/setup.test.ts @@ -1,10 +1,12 @@ +import { vi, test, expect } from 'vitest' + import { command, description, builder, handler } from '../setup' // mock Telemetry for CLI commands so they don't try to spawn a process -jest.mock('@redwoodjs/telemetry', () => { +vi.mock('@redwoodjs/telemetry', () => { return { - errorTelemetry: () => jest.fn(), - timedTelemetry: () => jest.fn(), + errorTelemetry: () => vi.fn(), + timedTelemetry: () => vi.fn(), } }) diff --git a/packages/auth-providers/firebase/setup/vitest.config.mts b/packages/auth-providers/firebase/setup/vitest.config.mts new file mode 100644 index 000000000000..4c8730d4808b --- /dev/null +++ b/packages/auth-providers/firebase/setup/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + }, +}) diff --git a/packages/auth-providers/netlify/api/jest.config.js b/packages/auth-providers/netlify/api/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/netlify/api/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/netlify/api/package.json b/packages/auth-providers/netlify/api/package.json index 80246e749102..6b860fd80dce 100644 --- a/packages/auth-providers/netlify/api/package.json +++ b/packages/auth-providers/netlify/api/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -33,8 +33,8 @@ "@redwoodjs/api": "6.0.7", "@types/aws-lambda": "8.10.126", "@types/jsonwebtoken": "9.0.5", - "jest": "29.7.0", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/netlify/api/src/__tests__/netlify.test.ts b/packages/auth-providers/netlify/api/src/__tests__/netlify.test.ts index d47cacb985dd..cb4cebf3ee8e 100644 --- a/packages/auth-providers/netlify/api/src/__tests__/netlify.test.ts +++ b/packages/auth-providers/netlify/api/src/__tests__/netlify.test.ts @@ -1,22 +1,27 @@ import type { APIGatewayProxyEvent, Context as LambdaContext } from 'aws-lambda' import jwt from 'jsonwebtoken' +import { vi, beforeAll, afterAll, test, expect } from 'vitest' import { authDecoder } from '../decoder' -jest.mock('jsonwebtoken', () => { - const jsonwebtoken = jest.requireActual('jsonwebtoken') +vi.mock('jsonwebtoken', async (importOriginal) => { + // eslint-disable-next-line @typescript-eslint/consistent-type-imports + const originalJWT = await importOriginal() return { - ...jsonwebtoken, - verify: jest.fn(), - decode: jest.fn((token: string) => { - const exp = - token === 'expired-token' - ? Math.floor(Date.now() / 1000) - 3600 - : Math.floor(Date.now() / 1000) + 3600 - - return { exp, sub: 'abc123' } - }), + ...originalJWT, + default: { + verify: vi.fn(), + decode: vi.fn((token: string) => { + const exp = + token === 'expired-token' + ? Math.floor(Date.now() / 1000) - 3600 + : Math.floor(Date.now() / 1000) + 3600 + + return { exp, sub: 'abc123' } + }), + }, + TokenExpiredError: originalJWT.TokenExpiredError, } }) diff --git a/packages/auth-providers/netlify/api/vitest.config.mts b/packages/auth-providers/netlify/api/vitest.config.mts new file mode 100644 index 000000000000..4c8730d4808b --- /dev/null +++ b/packages/auth-providers/netlify/api/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + }, +}) diff --git a/packages/auth-providers/netlify/setup/jest.config.js b/packages/auth-providers/netlify/setup/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/netlify/setup/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/netlify/setup/package.json b/packages/auth-providers/netlify/setup/package.json index 39ba5ebc3504..ccca83faf34a 100644 --- a/packages/auth-providers/netlify/setup/package.json +++ b/packages/auth-providers/netlify/setup/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -31,8 +31,8 @@ "@babel/cli": "7.23.4", "@babel/core": "^7.22.20", "@types/yargs": "17.0.32", - "jest": "29.7.0", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/netlify/setup/src/__tests__/setup.test.ts b/packages/auth-providers/netlify/setup/src/__tests__/setup.test.ts index 5e33db38575a..9cf0b13b8fd0 100644 --- a/packages/auth-providers/netlify/setup/src/__tests__/setup.test.ts +++ b/packages/auth-providers/netlify/setup/src/__tests__/setup.test.ts @@ -1,10 +1,12 @@ +import { vi, test, expect } from 'vitest' + import { command, description, builder, handler } from '../setup' // mock Telemetry for CLI commands so they don't try to spawn a process -jest.mock('@redwoodjs/telemetry', () => { +vi.mock('@redwoodjs/telemetry', () => { return { - errorTelemetry: () => jest.fn(), - timedTelemetry: () => jest.fn(), + errorTelemetry: () => vi.fn(), + timedTelemetry: () => vi.fn(), } }) diff --git a/packages/auth-providers/netlify/setup/vitest.config.mts b/packages/auth-providers/netlify/setup/vitest.config.mts new file mode 100644 index 000000000000..4c8730d4808b --- /dev/null +++ b/packages/auth-providers/netlify/setup/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + }, +}) diff --git a/packages/auth-providers/netlify/web/jest.config.js b/packages/auth-providers/netlify/web/jest.config.js deleted file mode 100644 index e691bb8f6dbd..000000000000 --- a/packages/auth-providers/netlify/web/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testEnvironment: 'jest-environment-jsdom', - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/netlify/web/package.json b/packages/auth-providers/netlify/web/package.json index 3b48f28847e7..a3ef51f526fc 100644 --- a/packages/auth-providers/netlify/web/package.json +++ b/packages/auth-providers/netlify/web/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -32,9 +32,9 @@ "@babel/core": "^7.22.20", "@types/netlify-identity-widget": "1.9.6", "@types/react": "18.2.37", - "jest": "29.7.0", "react": "0.0.0-experimental-e5205658f-20230913", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "peerDependencies": { "netlify-identity-widget": "1.9.2" 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 f6d3feeb905b..f8b692d5f761 100644 --- a/packages/auth-providers/netlify/web/src/__tests__/netlify.test.tsx +++ b/packages/auth-providers/netlify/web/src/__tests__/netlify.test.tsx @@ -1,5 +1,6 @@ import { renderHook, act } from '@testing-library/react' import type * as NetlifyIdentityNS from 'netlify-identity-widget' +import { vi, expect, it, beforeAll, beforeEach, describe } from 'vitest' import type { CurrentUser } from '@redwoodjs/auth' @@ -56,7 +57,7 @@ const netlifyIdentityMockClient: Partial = { currentUser: () => loggedInUser || null, } -const fetchMock = jest.fn() +const fetchMock = vi.fn() fetchMock.mockImplementation(async (_url, options) => { const body = options?.body ? JSON.parse(options.body) : {} diff --git a/packages/auth-providers/netlify/web/vitest.config.mts b/packages/auth-providers/netlify/web/vitest.config.mts new file mode 100644 index 000000000000..52ec6b09db8f --- /dev/null +++ b/packages/auth-providers/netlify/web/vitest.config.mts @@ -0,0 +1,8 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + environment: 'jsdom', + }, +}) diff --git a/packages/auth-providers/supabase/api/jest.config.js b/packages/auth-providers/supabase/api/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/supabase/api/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/supabase/api/package.json b/packages/auth-providers/supabase/api/package.json index 6dffb7b0842f..c65687452e68 100644 --- a/packages/auth-providers/supabase/api/package.json +++ b/packages/auth-providers/supabase/api/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -33,8 +33,8 @@ "@redwoodjs/api": "6.0.7", "@types/aws-lambda": "8.10.126", "@types/jsonwebtoken": "9.0.5", - "jest": "29.7.0", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/supabase/api/src/__tests__/supabase.test.ts b/packages/auth-providers/supabase/api/src/__tests__/supabase.test.ts index dfd872a68836..dc15eef8dc05 100644 --- a/packages/auth-providers/supabase/api/src/__tests__/supabase.test.ts +++ b/packages/auth-providers/supabase/api/src/__tests__/supabase.test.ts @@ -1,16 +1,19 @@ import type { APIGatewayProxyEvent, Context as LambdaContext } from 'aws-lambda' import jwt from 'jsonwebtoken' +import { vi, beforeAll, afterAll, test, expect } from 'vitest' import { authDecoder } from '../decoder' -jest.mock('jsonwebtoken', () => { +vi.mock('jsonwebtoken', () => { return { - verify: jest.fn(() => { - return { - sub: 'abc123', - } - }), - decode: jest.fn(), + default: { + verify: vi.fn(() => { + return { + sub: 'abc123', + } + }), + decode: vi.fn(), + }, } }) diff --git a/packages/auth-providers/supabase/api/vitest.config.mts b/packages/auth-providers/supabase/api/vitest.config.mts new file mode 100644 index 000000000000..4c8730d4808b --- /dev/null +++ b/packages/auth-providers/supabase/api/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + }, +}) diff --git a/packages/auth-providers/supabase/setup/jest.config.js b/packages/auth-providers/supabase/setup/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/supabase/setup/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/supabase/setup/package.json b/packages/auth-providers/supabase/setup/package.json index 1a699a6d47ef..1d743c41ea48 100644 --- a/packages/auth-providers/supabase/setup/package.json +++ b/packages/auth-providers/supabase/setup/package.json @@ -18,9 +18,7 @@ "build:pack": "yarn pack -o redwoodjs-auth-supabase-setup.tgz", "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", - "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src --passWithNoTests", - "test:watch": "yarn test --watch" + "prepublishOnly": "NODE_ENV=production yarn build" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -31,7 +29,6 @@ "@babel/cli": "7.23.4", "@babel/core": "^7.22.20", "@types/yargs": "17.0.32", - "jest": "29.7.0", "typescript": "5.3.3" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" diff --git a/packages/auth-providers/supabase/web/jest.config.js b/packages/auth-providers/supabase/web/jest.config.js deleted file mode 100644 index e691bb8f6dbd..000000000000 --- a/packages/auth-providers/supabase/web/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testEnvironment: 'jest-environment-jsdom', - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/supabase/web/package.json b/packages/auth-providers/supabase/web/package.json index f0e9076d49c0..c5df68d883f1 100644 --- a/packages/auth-providers/supabase/web/package.json +++ b/packages/auth-providers/supabase/web/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -31,9 +31,9 @@ "@babel/core": "^7.22.20", "@supabase/supabase-js": "2.39.0", "@types/react": "18.2.37", - "jest": "29.7.0", "react": "0.0.0-experimental-e5205658f-20230913", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "peerDependencies": { "@supabase/supabase-js": "2.39.0" 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 a9d79a252cd7..096e3692307d 100644 --- a/packages/auth-providers/supabase/web/src/__tests__/supabase.test.tsx +++ b/packages/auth-providers/supabase/web/src/__tests__/supabase.test.tsx @@ -14,6 +14,7 @@ import type { } from '@supabase/supabase-js' import { AuthError } from '@supabase/supabase-js' import { renderHook, act } from '@testing-library/react' +import { vi, it, describe, beforeAll, beforeEach, expect } from 'vitest' import type { CurrentUser } from '@redwoodjs/auth' @@ -250,7 +251,7 @@ const supabaseMockClient: Partial = { auth: mockSupabaseAuthClient as SupabaseClient['auth'], } -const fetchMock = jest.fn() +const fetchMock = vi.fn() fetchMock.mockImplementation(async (_url, options) => { const body = options?.body ? JSON.parse(options.body) : {} diff --git a/packages/auth-providers/supabase/web/vitest.config.mts b/packages/auth-providers/supabase/web/vitest.config.mts new file mode 100644 index 000000000000..52ec6b09db8f --- /dev/null +++ b/packages/auth-providers/supabase/web/vitest.config.mts @@ -0,0 +1,8 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + environment: 'jsdom', + }, +}) diff --git a/packages/auth-providers/supertokens/api/jest.config.js b/packages/auth-providers/supertokens/api/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/supertokens/api/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/supertokens/api/package.json b/packages/auth-providers/supertokens/api/package.json index 6a3ebd3dadd9..4c961275eb6c 100644 --- a/packages/auth-providers/supertokens/api/package.json +++ b/packages/auth-providers/supertokens/api/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -33,8 +33,8 @@ "@babel/core": "^7.22.20", "@redwoodjs/api": "6.0.7", "@types/jsonwebtoken": "9.0.5", - "jest": "29.7.0", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "peerDependencies": { "supertokens-node": "15.2.1" diff --git a/packages/auth-providers/supertokens/api/src/__tests__/supertokens.test.ts b/packages/auth-providers/supertokens/api/src/__tests__/supertokens.test.ts index be12ae1a8b1f..d30873686b08 100644 --- a/packages/auth-providers/supertokens/api/src/__tests__/supertokens.test.ts +++ b/packages/auth-providers/supertokens/api/src/__tests__/supertokens.test.ts @@ -1,12 +1,15 @@ import type { APIGatewayProxyEvent, Context as LambdaContext } from 'aws-lambda' import jwt from 'jsonwebtoken' +import { vi, beforeAll, afterAll, test, expect } from 'vitest' import { authDecoder } from '../decoder' -jest.mock('jsonwebtoken', () => { +vi.mock('jsonwebtoken', () => { return { - verify: jest.fn(), - decode: jest.fn(), + default: { + verify: vi.fn(), + decode: vi.fn(), + }, } }) diff --git a/packages/auth-providers/supertokens/api/vitest.config.mts b/packages/auth-providers/supertokens/api/vitest.config.mts new file mode 100644 index 000000000000..4c8730d4808b --- /dev/null +++ b/packages/auth-providers/supertokens/api/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + }, +}) diff --git a/packages/auth-providers/supertokens/setup/__mocks__/fs.js b/packages/auth-providers/supertokens/setup/__mocks__/fs.js deleted file mode 100644 index 99fec09d82ed..000000000000 --- a/packages/auth-providers/supertokens/setup/__mocks__/fs.js +++ /dev/null @@ -1,220 +0,0 @@ -import path from 'path' - -const fs = { - ...jest.requireActual('fs'), -} - -let mockFiles = {} - -const pathSeparator = path.sep - -const getParentDir = (path) => { - return path.substring(0, path.lastIndexOf(pathSeparator)) -} - -const makeParentDirs = (path) => { - const parentDir = getParentDir(path) - if (parentDir && !(parentDir in mockFiles)) { - mockFiles[parentDir] = undefined - makeParentDirs(parentDir) - } -} - -/** - * This is a custom function that our tests can use during setup to specify - * what the files on the "mock" filesystem should look like when any of the - * `fs` APIs are used. - * - * Sets the state of the mocked file system - * @param newMockFiles - {[filepath]: contents} - */ -fs.__setMockFiles = (newMockFiles) => { - mockFiles = { ...newMockFiles } - - // Generate all the directories which implicitly exist - Object.keys(mockFiles).forEach((mockPath) => { - if (mockPath.includes(pathSeparator)) { - makeParentDirs(mockPath) - } - }) -} - -fs.__getMockFiles = () => { - return mockFiles -} - -fs.readFileSync = (path) => { - // In prisma v4.3.0, prisma format uses a Wasm module. See https://github.com/prisma/prisma/releases/tag/4.3.0. - // We shouldn't mock this, so we'll use the real fs.readFileSync. - if (path.includes('prisma_fmt_build_bg.wasm')) { - return jest.requireActual('fs').readFileSync(path) - } - - if (path in mockFiles) { - return mockFiles[path] - } else { - const fakeError = new Error( - `Error: ENOENT: no such file or directory, open '${path}'` - ) - fakeError.errno = -2 - fakeError.syscall = 'open' - fakeError.code = 'ENOENT' - fakeError.path = path - throw fakeError - } -} - -fs.writeFileSync = (path, contents) => { - const parentDir = getParentDir(path) - if (parentDir && !fs.existsSync(parentDir)) { - const fakeError = new Error( - `Error: ENOENT: no such file or directory, open '${path}'` - ) - fakeError.errno = -2 - fakeError.syscall = 'open' - fakeError.code = 'ENOENT' - fakeError.path = path - throw fakeError - } - mockFiles[path] = contents -} - -fs.appendFileSync = (path, contents) => { - if (path in mockFiles) { - mockFiles[path] = mockFiles[path] + contents - } else { - fs.writeFileSync(path, contents) - } -} - -fs.rmSync = (path, options = {}) => { - if (fs.existsSync(path)) { - if (options.recursive) { - Object.keys(mockFiles).forEach((mockedPath) => { - if (mockedPath.startsWith(path)) { - delete mockFiles[mockedPath] - } - }) - } else { - if (mockFiles[path] === undefined) { - const children = fs.readdirSync(path) - if (children.length !== 0) { - const fakeError = new Error( - `NodeError [SystemError]: Path is a directory: rm returned EISDIR (is a directory) ${path}` - ) - fakeError.errno = 21 - fakeError.syscall = 'rm' - fakeError.code = 'ERR_FS_EISDIR' - fakeError.path = path - throw fakeError - } - } - delete mockFiles[path] - } - } else { - const fakeError = new Error( - `Error: ENOENT: no such file or directory, stat '${path}'` - ) - fakeError.errno = -2 - fakeError.syscall = 'stat' - fakeError.code = 'ENOENT' - fakeError.path = path - throw fakeError - } -} - -fs.unlinkSync = (path) => { - if (path in mockFiles) { - delete mockFiles[path] - } else { - const fakeError = new Error( - `Error: ENOENT: no such file or directory, stat '${path}'` - ) - fakeError.errno = -2 - fakeError.syscall = 'unlink' - fakeError.code = 'ENOENT' - fakeError.path = path - throw fakeError - } -} - -fs.existsSync = (path) => { - return path in mockFiles -} - -fs.copyFileSync = (src, dist) => { - fs.writeFileSync(dist, fs.readFileSync(src)) -} - -fs.readdirSync = (path) => { - if (!fs.existsSync(path)) { - const fakeError = new Error( - `Error: ENOENT: no such file or directory, scandir '${path}'` - ) - fakeError.errno = -2 - fakeError.syscall = 'scandir' - fakeError.code = 'ENOENT' - fakeError.path = path - throw fakeError - } - - if (mockFiles[path] !== undefined) { - const fakeError = new Error( - `Error: ENOTDIR: not a directory, scandir '${path}'` - ) - fakeError.errno = -20 - fakeError.syscall = 'scandir' - fakeError.code = 'ENOTDIR' - fakeError.path = path - throw fakeError - } - - const content = [] - Object.keys(mockFiles).forEach((mockedPath) => { - const childPath = mockedPath.substring(path.length + 1) - if ( - mockedPath.startsWith(path) && - !childPath.includes(pathSeparator) && - childPath - ) { - content.push(childPath) - } - }) - return content -} - -fs.mkdirSync = (path, options = {}) => { - if (options.recursive) { - makeParentDirs(path) - } - // Directories are represented as paths with an "undefined" value - fs.writeFileSync(path, undefined) -} - -fs.rmdirSync = (path, options = {}) => { - if (!fs.existsSync(path)) { - const fakeError = new Error( - `Error: ENOENT: no such file or directory, rmdir '${path}'` - ) - fakeError.errno = -2 - fakeError.syscall = 'rmdir' - fakeError.code = 'ENOENT' - fakeError.path = path - throw fakeError - } - - if (mockFiles[path] !== undefined) { - const fakeError = new Error( - `Error: ENOTDIR: not a directory, rmdir '${path}'` - ) - fakeError.errno = -20 - fakeError.syscall = 'rmdir' - fakeError.code = 'ENOTDIR' - fakeError.path = path - throw fakeError - } - - fs.rmSync(path, options) -} - -module.exports = fs diff --git a/packages/auth-providers/supertokens/setup/jest.config.js b/packages/auth-providers/supertokens/setup/jest.config.js deleted file mode 100644 index dee127c25474..000000000000 --- a/packages/auth-providers/supertokens/setup/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/supertokens/setup/package.json b/packages/auth-providers/supertokens/setup/package.json index c44702cc29c1..d85a20039801 100644 --- a/packages/auth-providers/supertokens/setup/package.json +++ b/packages/auth-providers/supertokens/setup/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src --passWithNoTests", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -31,8 +31,9 @@ "@babel/cli": "7.23.4", "@babel/core": "^7.22.20", "@types/yargs": "17.0.32", - "jest": "29.7.0", - "typescript": "5.3.3" + "memfs": "4.6.0", + "typescript": "5.3.3", + "vitest": "1.2.1" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/supertokens/setup/src/__tests__/setup.test.ts b/packages/auth-providers/supertokens/setup/src/__tests__/setup.test.ts index 7c108e1d2eb8..32d8a9fc0cac 100644 --- a/packages/auth-providers/supertokens/setup/src/__tests__/setup.test.ts +++ b/packages/auth-providers/supertokens/setup/src/__tests__/setup.test.ts @@ -1,10 +1,12 @@ +import { vi, test, expect } from 'vitest' + import { command, description, builder, handler } from '../setup' // mock Telemetry for CLI commands so they don't try to spawn a process -jest.mock('@redwoodjs/telemetry', () => { +vi.mock('@redwoodjs/telemetry', () => { return { - errorTelemetry: () => jest.fn(), - timedTelemetry: () => jest.fn(), + errorTelemetry: () => vi.fn(), + timedTelemetry: () => vi.fn(), } }) diff --git a/packages/auth-providers/supertokens/setup/src/__tests__/setupHandler.test.ts b/packages/auth-providers/supertokens/setup/src/__tests__/setupHandler.test.ts index 6789d79d940c..a19692eee4e4 100644 --- a/packages/auth-providers/supertokens/setup/src/__tests__/setupHandler.test.ts +++ b/packages/auth-providers/supertokens/setup/src/__tests__/setupHandler.test.ts @@ -1,12 +1,12 @@ // mock Telemetry for CLI commands so they don't try to spawn a process -jest.mock('@redwoodjs/telemetry', () => { +vi.mock('@redwoodjs/telemetry', () => { return { - errorTelemetry: () => jest.fn(), - timedTelemetry: () => jest.fn(), + errorTelemetry: () => vi.fn(), + timedTelemetry: () => vi.fn(), } }) -jest.mock('@redwoodjs/cli-helpers', () => { +vi.mock('@redwoodjs/cli-helpers', () => { return { getPaths: () => { return { @@ -18,24 +18,22 @@ jest.mock('@redwoodjs/cli-helpers', () => { base: '', } }, - standardAuthHandler: () => jest.fn(), + standardAuthHandler: () => vi.fn(), } }) -// This will load packages/auth-providers/supertokens/setup/__mocks__/fs.js -jest.mock('fs') - -const mockFS = fs as unknown as Omit, 'readdirSync'> & { - __setMockFiles: (files: Record) => void -} +vi.mock('fs', async () => ({ default: (await import('memfs')).fs })) import fs from 'fs' +import { vol } from 'memfs' +import { vi, describe, it, expect } from 'vitest' + import { addRoutingLogic } from '../setupHandler' describe('addRoutingLogic', () => { it('modifies the Routes.{jsx,tsx} file', () => { - mockFS.__setMockFiles({ + vol.fromJSON({ 'Routes.tsx': "// In this file, all Page components from 'src/pages' are auto-imported.\n" + ` @@ -59,7 +57,7 @@ export default Routes addRoutingLogic.task() - expect(mockFS.readFileSync('Routes.tsx')).toMatchInlineSnapshot(` + expect(fs.readFileSync('Routes.tsx', 'utf-8')).toMatchInlineSnapshot(` "// In this file, all Page components from 'src/pages' are auto-imported. import { canHandleRoute, getRoutingComponent } from 'supertokens-auth-react/ui' @@ -88,7 +86,7 @@ export default Routes }) it('handles a Routes.{jsx,tsx} file with a legacy setup', () => { - mockFS.__setMockFiles({ + vol.fromJSON({ 'Routes.tsx': "// In this file, all Page components from 'src/pages' are auto-imported.\n" + ` @@ -118,7 +116,7 @@ export default Routes addRoutingLogic.task() - expect(mockFS.readFileSync('Routes.tsx')).toMatchInlineSnapshot(` + expect(fs.readFileSync('Routes.tsx', 'utf-8')).toMatchInlineSnapshot(` "// In this file, all Page components from 'src/pages' are auto-imported. @@ -134,7 +132,7 @@ export default Routes return getRoutingComponent(PreBuiltUI) } - + return ( diff --git a/packages/auth-providers/supertokens/setup/vitest.config.mts b/packages/auth-providers/supertokens/setup/vitest.config.mts new file mode 100644 index 000000000000..4c8730d4808b --- /dev/null +++ b/packages/auth-providers/supertokens/setup/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + }, +}) diff --git a/packages/auth-providers/supertokens/web/jest.config.js b/packages/auth-providers/supertokens/web/jest.config.js deleted file mode 100644 index e691bb8f6dbd..000000000000 --- a/packages/auth-providers/supertokens/web/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - testEnvironment: 'jest-environment-jsdom', - testPathIgnorePatterns: ['fixtures', 'dist'], -} diff --git a/packages/auth-providers/supertokens/web/package.json b/packages/auth-providers/supertokens/web/package.json index 423f4ff54c7c..43d43e261621 100644 --- a/packages/auth-providers/supertokens/web/package.json +++ b/packages/auth-providers/supertokens/web/package.json @@ -19,8 +19,8 @@ "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"", "prepublishOnly": "NODE_ENV=production yarn build", - "test": "jest src", - "test:watch": "yarn test --watch" + "test": "vitest run src", + "test:watch": "vitest watch src" }, "dependencies": { "@babel/runtime-corejs3": "7.23.6", @@ -31,10 +31,10 @@ "@babel/cli": "7.23.4", "@babel/core": "^7.22.20", "@types/react": "18.2.37", - "jest": "29.7.0", "react": "0.0.0-experimental-e5205658f-20230913", "supertokens-auth-react": "0.34.0", - "typescript": "5.3.3" + "typescript": "5.3.3", + "vitest": "1.2.1" }, "peerDependencies": { "supertokens-auth-react": "0.34.0" 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 a740b41134e9..d20fdb9df410 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,5 @@ import { renderHook, act } from '@testing-library/react' +import { vi, it, expect, beforeAll, beforeEach, describe } from 'vitest' import type { CurrentUser } from '@redwoodjs/auth' @@ -49,7 +50,7 @@ const superTokensMockClient: SuperTokensAuth = { }, } -const fetchMock = jest.fn() +const fetchMock = vi.fn() fetchMock.mockImplementation(async (_url, options) => { const body = options?.body ? JSON.parse(options.body) : {} diff --git a/packages/auth-providers/supertokens/web/vitest.config.mts b/packages/auth-providers/supertokens/web/vitest.config.mts new file mode 100644 index 000000000000..52ec6b09db8f --- /dev/null +++ b/packages/auth-providers/supertokens/web/vitest.config.mts @@ -0,0 +1,8 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/fixtures'], + environment: 'jsdom', + }, +}) diff --git a/packages/graphql-server/src/functions/__tests__/normalizeRequest.test.ts b/packages/graphql-server/src/functions/__tests__/normalizeRequest.test.ts deleted file mode 100644 index 3f9590dbae46..000000000000 --- a/packages/graphql-server/src/functions/__tests__/normalizeRequest.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { Headers } from '@whatwg-node/fetch' -import type { APIGatewayProxyEvent } from 'aws-lambda' - -import { normalizeRequest } from '@redwoodjs/api' - -export const createMockedEvent = ( - httpMethod = 'POST', - body: any = undefined, - isBase64Encoded = false -): APIGatewayProxyEvent => { - return { - body, - headers: {}, - multiValueHeaders: {}, - httpMethod, - isBase64Encoded, - path: '/MOCK_PATH', - pathParameters: null, - queryStringParameters: null, - multiValueQueryStringParameters: null, - stageVariables: null, - requestContext: { - accountId: 'MOCKED_ACCOUNT', - apiId: 'MOCKED_API_ID', - authorizer: { name: 'MOCKED_AUTHORIZER' }, - protocol: 'HTTP', - identity: { - accessKey: null, - accountId: null, - apiKey: null, - apiKeyId: null, - caller: null, - clientCert: null, - cognitoAuthenticationProvider: null, - cognitoAuthenticationType: null, - cognitoIdentityId: null, - cognitoIdentityPoolId: null, - principalOrgId: null, - sourceIp: '123.123.123.123', - user: null, - userAgent: null, - userArn: null, - }, - httpMethod: 'POST', - path: '/MOCK_PATH', - stage: 'MOCK_STAGE', - requestId: 'MOCKED_REQUEST_ID', - requestTimeEpoch: 1, - resourceId: 'MOCKED_RESOURCE_ID', - resourcePath: 'MOCKED_RESOURCE_PATH', - }, - resource: 'MOCKED_RESOURCE', - } -} - -test('Normalizes an aws event with base64', () => { - const corsEventB64 = createMockedEvent( - 'POST', - Buffer.from(JSON.stringify({ bazinga: 'hello_world' }), 'utf8').toString( - 'base64' - ), - true - ) - - const normalizedRequest = normalizeRequest(corsEventB64) - const expectedRequest = { - headers: new Headers(corsEventB64.headers), - method: 'POST', - query: null, - body: { - bazinga: 'hello_world', - }, - } - - expect(normalizedRequest.method).toEqual(expectedRequest.method) - expect(normalizedRequest.query).toEqual(expectedRequest.query) - expect(normalizedRequest.body).toEqual(expectedRequest.body) - expectedRequest.headers.forEach((value, key) => { - expect(normalizedRequest.headers.get(key)).toEqual(value) - }) -}) - -test('Handles CORS requests with and without b64 encoded', () => { - const corsEventB64 = createMockedEvent('OPTIONS', undefined, true) - - const normalizedRequest = normalizeRequest(corsEventB64) - const expectedRequest = { - headers: new Headers(corsEventB64.headers), - method: 'OPTIONS', - query: null, - body: undefined, - } - expect(normalizedRequest.method).toEqual(expectedRequest.method) - expect(normalizedRequest.query).toEqual(expectedRequest.query) - expect(normalizedRequest.body).toEqual(expectedRequest.body) - expectedRequest.headers.forEach((value, key) => { - expect(normalizedRequest.headers.get(key)).toEqual(value) - }) -}) diff --git a/packages/project-config/build.js b/packages/project-config/build.js new file mode 100644 index 000000000000..4560f1d78590 --- /dev/null +++ b/packages/project-config/build.js @@ -0,0 +1,28 @@ +/* eslint-disable import/no-extraneous-dependencies */ + +import * as esbuild from 'esbuild' + +const options = { + entryPoints: ['./src/index.ts'], + outdir: 'dist', + + platform: 'node', + target: ['node20'], + bundle: true, + packages: 'external', + + logLevel: 'info', + metafile: true, +} + +await esbuild.build({ + ...options, + format: 'esm', + outExtension: { '.js': '.mjs' }, +}) + +await esbuild.build({ + ...options, + format: 'cjs', + outExtension: { '.js': '.cjs' }, +}) diff --git a/packages/project-config/build.mjs b/packages/project-config/build.mjs deleted file mode 100644 index 2cec19a1a453..000000000000 --- a/packages/project-config/build.mjs +++ /dev/null @@ -1,22 +0,0 @@ -import fs from 'node:fs' - -import * as esbuild from 'esbuild' - -const result = await esbuild.build({ - entryPoints: ['src/index.ts'], - outdir: 'dist', - - bundle: true, - - platform: 'node', - target: ['node20'], - packages: 'external', - - logLevel: 'info', - - // For visualizing the bundle. - // See https://esbuild.github.io/api/#metafile and https://esbuild.github.io/analyze/. - metafile: true, -}) - -fs.writeFileSync('meta.json', JSON.stringify(result.metafile)) diff --git a/packages/project-config/package.json b/packages/project-config/package.json index 6d3e4e692316..2c1e5f34767c 100644 --- a/packages/project-config/package.json +++ b/packages/project-config/package.json @@ -7,15 +7,18 @@ "directory": "packages/project-config" }, "license": "MIT", + "type": "module", "exports": { - ".": "./dist/index.js" + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs", + "default": "./dist/index.cjs" }, "types": "./dist/index.d.ts", "files": [ "dist" ], "scripts": { - "build": "yarn node ./build.mjs && run build:types", + "build": "yarn node ./build.js && run build:types", "build:pack": "yarn pack -o redwoodjs-project-config.tgz", "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,ts,tsx\" --ignore dist --exec \"yarn build\"", diff --git a/packages/project-config/src/config.ts b/packages/project-config/src/config.ts index e8dcdfda4146..4c226ac3ccde 100644 --- a/packages/project-config/src/config.ts +++ b/packages/project-config/src/config.ts @@ -4,7 +4,7 @@ import toml from '@iarna/toml' import merge from 'deepmerge' import { env as envInterpolation } from 'string-env-interpolation' -import { getConfigPath } from './configPath' +import { getConfigPath } from './configPath.js' export enum TargetEnum { NODE = 'node', diff --git a/packages/project-config/src/configPath.ts b/packages/project-config/src/configPath.ts index 697136284f2f..d24e85b039d9 100644 --- a/packages/project-config/src/configPath.ts +++ b/packages/project-config/src/configPath.ts @@ -1,4 +1,4 @@ -import { findUp } from './findUp' +import { findUp } from './findUp.js' const CONFIG_FILE_NAME = 'redwood.toml' diff --git a/packages/project-config/src/index.ts b/packages/project-config/src/index.ts index ae6da932ae6e..e420284a615d 100644 --- a/packages/project-config/src/index.ts +++ b/packages/project-config/src/index.ts @@ -1,4 +1,4 @@ -export * from './config' -export * from './configPath' -export * from './paths' -export * from './findUp' +export * from './config.js' +export * from './configPath.js' +export * from './paths.js' +export * from './findUp.js' diff --git a/packages/project-config/src/paths.ts b/packages/project-config/src/paths.ts index ed79fb75db34..62902ef16fa4 100644 --- a/packages/project-config/src/paths.ts +++ b/packages/project-config/src/paths.ts @@ -3,8 +3,8 @@ import path from 'path' import fg from 'fast-glob' -import { getConfig } from './config' -import { getConfigPath } from './configPath' +import { getConfig } from './config.js' +import { getConfigPath } from './configPath.js' export interface NodeTargetPaths { base: string diff --git a/packages/project-config/tsconfig.json b/packages/project-config/tsconfig.json index 74bdeb595478..78a31c197ddd 100644 --- a/packages/project-config/tsconfig.json +++ b/packages/project-config/tsconfig.json @@ -1,6 +1,8 @@ { "extends": "../../tsconfig.compilerOption.json", "compilerOptions": { + "moduleResolution": "NodeNext", + "module": "NodeNext", "baseUrl": ".", "rootDir": "src", "outDir": "dist", diff --git a/packages/vite/bins/rw-vite-dev.mjs b/packages/vite/bins/rw-vite-dev.mjs index ba0e4e5a205a..b136728048b6 100755 --- a/packages/vite/bins/rw-vite-dev.mjs +++ b/packages/vite/bins/rw-vite-dev.mjs @@ -2,9 +2,9 @@ import { createServer } from 'vite' import yargsParser from 'yargs-parser' -import projectConfig from '@redwoodjs/project-config' +import { getPaths } from '@redwoodjs/project-config' -const rwPaths = projectConfig.getPaths() +const rwPaths = getPaths() const startDevServer = async () => { const configFile = rwPaths.web.viteConfig diff --git a/packages/vite/src/__tests__/viteNestedPages.test.mts b/packages/vite/src/__tests__/viteNestedPages.test.mts index ba38be25bbb5..27805d40a1b5 100644 --- a/packages/vite/src/__tests__/viteNestedPages.test.mts +++ b/packages/vite/src/__tests__/viteNestedPages.test.mts @@ -6,7 +6,7 @@ import { transformWithEsbuild } from 'vite' import { test, describe, beforeEach, afterAll, beforeAll, it, expect, vi } from 'vitest' import * as babel from '@babel/core' -import projectConfig from '@redwoodjs/project-config' +import { getPaths } from '@redwoodjs/project-config' import { Flags, @@ -41,7 +41,6 @@ async function transform(srcPath: string) { const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) const FIXTURE_PATH = path.join(__dirname, 'fixtures/nestedPages') -const { getPaths } = projectConfig test('transform', async () => { vi.spyOn(fs, 'readFileSync').mockImplementationOnce(() => { diff --git a/yarn.lock b/yarn.lock index 41c9d6b4866e..6f8001bd4a4e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7596,10 +7596,10 @@ __metadata: "@redwoodjs/api": "npm:6.0.7" "@types/jsonwebtoken": "npm:9.0.5" core-js: "npm:3.34.0" - jest: "npm:29.7.0" jsonwebtoken: "npm:9.0.2" jwks-rsa: "npm:3.1.0" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" languageName: unknown linkType: soft @@ -7613,8 +7613,8 @@ __metadata: "@redwoodjs/cli-helpers": "npm:6.0.7" "@types/yargs": "npm:17.0.32" core-js: "npm:3.34.0" - jest: "npm:29.7.0" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" languageName: unknown linkType: soft @@ -7629,9 +7629,9 @@ __metadata: "@redwoodjs/auth": "npm:6.0.7" "@types/react": "npm:18.2.37" core-js: "npm:3.34.0" - jest: "npm:29.7.0" react: "npm:0.0.0-experimental-e5205658f-20230913" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" peerDependencies: "@auth0/auth0-spa-js": 2.1.2 languageName: unknown @@ -7648,10 +7648,10 @@ __metadata: "@types/aws-lambda": "npm:8.10.126" "@types/jsonwebtoken": "npm:9.0.5" core-js: "npm:3.34.0" - jest: "npm:29.7.0" jsonwebtoken: "npm:9.0.2" jwks-rsa: "npm:3.1.0" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" languageName: unknown linkType: soft @@ -7665,8 +7665,8 @@ __metadata: "@redwoodjs/cli-helpers": "npm:6.0.7" "@types/yargs": "npm:17.0.32" core-js: "npm:3.34.0" - jest: "npm:29.7.0" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" languageName: unknown linkType: soft @@ -7682,9 +7682,9 @@ __metadata: "@types/netlify-identity-widget": "npm:1.9.6" "@types/react": "npm:18.2.37" core-js: "npm:3.34.0" - jest: "npm:29.7.0" react: "npm:0.0.0-experimental-e5205658f-20230913" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" peerDependencies: "@azure/msal-browser": 2.38.3 languageName: unknown @@ -7701,8 +7701,8 @@ __metadata: "@redwoodjs/api": "npm:6.0.7" "@types/aws-lambda": "npm:8.10.126" core-js: "npm:3.34.0" - jest: "npm:29.7.0" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" languageName: unknown linkType: soft @@ -7716,7 +7716,6 @@ __metadata: "@redwoodjs/cli-helpers": "npm:6.0.7" "@types/yargs": "npm:17.0.32" core-js: "npm:3.34.0" - jest: "npm:29.7.0" typescript: "npm:5.3.3" languageName: unknown linkType: soft @@ -7733,9 +7732,9 @@ __metadata: "@redwoodjs/auth": "npm:6.0.7" "@types/react": "npm:18.2.37" core-js: "npm:3.34.0" - jest: "npm:29.7.0" react: "npm:0.0.0-experimental-e5205658f-20230913" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" peerDependencies: "@clerk/clerk-react": 4.28.3 languageName: unknown @@ -7751,8 +7750,8 @@ __metadata: "@redwoodjs/cli-helpers": "npm:6.0.7" "@types/yargs": "npm:17.0.32" core-js: "npm:3.34.0" - jest: "npm:29.7.0" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" languageName: unknown linkType: soft @@ -7770,10 +7769,10 @@ __metadata: "@types/uuid": "npm:9.0.7" base64url: "npm:3.0.1" core-js: "npm:3.34.0" - jest: "npm:29.7.0" md5: "npm:2.3.0" typescript: "npm:5.3.3" uuid: "npm:9.0.1" + vitest: "npm:1.2.1" languageName: unknown linkType: soft @@ -7789,7 +7788,6 @@ __metadata: "@simplewebauthn/typescript-types": "npm:7.4.0" "@types/yargs": "npm:17.0.32" core-js: "npm:3.34.0" - jest: "npm:29.7.0" prompts: "npm:2.4.2" terminal-link: "npm:2.1.1" typescript: "npm:5.3.3" @@ -7825,8 +7823,8 @@ __metadata: "@types/aws-lambda": "npm:8.10.126" core-js: "npm:3.34.0" firebase-admin: "npm:11.11.0" - jest: "npm:29.7.0" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" languageName: unknown linkType: soft @@ -7840,8 +7838,8 @@ __metadata: "@redwoodjs/cli-helpers": "npm:6.0.7" "@types/yargs": "npm:17.0.32" core-js: "npm:3.34.0" - jest: "npm:29.7.0" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" languageName: unknown linkType: soft @@ -7875,9 +7873,9 @@ __metadata: "@types/aws-lambda": "npm:8.10.126" "@types/jsonwebtoken": "npm:9.0.5" core-js: "npm:3.34.0" - jest: "npm:29.7.0" jsonwebtoken: "npm:9.0.2" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" languageName: unknown linkType: soft @@ -7891,8 +7889,8 @@ __metadata: "@redwoodjs/cli-helpers": "npm:6.0.7" "@types/yargs": "npm:17.0.32" core-js: "npm:3.34.0" - jest: "npm:29.7.0" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" languageName: unknown linkType: soft @@ -7907,9 +7905,9 @@ __metadata: "@types/netlify-identity-widget": "npm:1.9.6" "@types/react": "npm:18.2.37" core-js: "npm:3.34.0" - jest: "npm:29.7.0" react: "npm:0.0.0-experimental-e5205658f-20230913" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" peerDependencies: netlify-identity-widget: 1.9.2 languageName: unknown @@ -7926,9 +7924,9 @@ __metadata: "@types/aws-lambda": "npm:8.10.126" "@types/jsonwebtoken": "npm:9.0.5" core-js: "npm:3.34.0" - jest: "npm:29.7.0" jsonwebtoken: "npm:9.0.2" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" languageName: unknown linkType: soft @@ -7942,7 +7940,6 @@ __metadata: "@redwoodjs/cli-helpers": "npm:6.0.7" "@types/yargs": "npm:17.0.32" core-js: "npm:3.34.0" - jest: "npm:29.7.0" typescript: "npm:5.3.3" languageName: unknown linkType: soft @@ -7957,9 +7954,9 @@ __metadata: "@supabase/supabase-js": "npm:2.39.0" "@types/react": "npm:18.2.37" core-js: "npm:3.34.0" - jest: "npm:29.7.0" react: "npm:0.0.0-experimental-e5205658f-20230913" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" peerDependencies: "@supabase/supabase-js": 2.39.0 languageName: unknown @@ -7975,10 +7972,10 @@ __metadata: "@redwoodjs/api": "npm:6.0.7" "@types/jsonwebtoken": "npm:9.0.5" core-js: "npm:3.34.0" - jest: "npm:29.7.0" jsonwebtoken: "npm:9.0.2" jwks-rsa: "npm:3.1.0" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" peerDependencies: supertokens-node: 15.2.1 languageName: unknown @@ -7994,8 +7991,9 @@ __metadata: "@redwoodjs/cli-helpers": "npm:6.0.7" "@types/yargs": "npm:17.0.32" core-js: "npm:3.34.0" - jest: "npm:29.7.0" + memfs: "npm:4.6.0" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" languageName: unknown linkType: soft @@ -8009,10 +8007,10 @@ __metadata: "@redwoodjs/auth": "npm:6.0.7" "@types/react": "npm:18.2.37" core-js: "npm:3.34.0" - jest: "npm:29.7.0" react: "npm:0.0.0-experimental-e5205658f-20230913" supertokens-auth-react: "npm:0.34.0" typescript: "npm:5.3.3" + vitest: "npm:1.2.1" peerDependencies: supertokens-auth-react: 0.34.0 languageName: unknown