From e46f2c32e30613221124d1338da33cd7d3e402cd Mon Sep 17 00:00:00 2001
From: Allen Zhou <46854522+allenzhou101@users.noreply.github.com>
Date: Sun, 9 Jul 2023 19:34:30 +0900
Subject: [PATCH 1/7] Add Descope doc to testing strategies
---
 .../descope-authentication.mdx                | 310 ++++++++++++++++++
 1 file changed, 310 insertions(+)
 create mode 100644 docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
diff --git a/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx b/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
new file mode 100644
index 0000000000..2e69e55a08
--- /dev/null
+++ b/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
@@ -0,0 +1,310 @@
+---
+title: Descope Authentication
+slug: /guides/end-to-end-testing/descope-authentication
+---
+
+:::info
+
+##  What you'll learn
+
+- Log in to [Descope](https://descope.com) through the UI
+- Programmatically authenticate with [Descope](https://descope.com) via a custom
+  Cypress command
+- Adapt your [Descope](https://descope.com) application for programmatic
+  authentication during testing
+
+:::
+
+## Descope Application Setup
+
+To get started with Descope, an application needs to be setup within the
+[Descope Dashboard](https://app.descope.com/home) via the following steps:
+
+1. Visit the [Descope Dashboard](https://app.descope.com/home) and click the
+   "+ Project" button under the project dropdown.
+2. Enter the desired name for your application.
+3. Hit the "Create" button
+
+## Setting Descope app credentials in Cypress
+
+To have access to test user credentials within our tests we need to configure
+Cypress to use the [Descope](https://descope.com) environment variables set in the
+`.env` file.
+
+:::cypress-config-example
+
+```js
+// Populate process.env with values from .env file
+require('dotenv').config()
+```
+
+```js
+{
+  e2e: {
+    includeShadowDom: true, // For interacting with Descope components
+  },
+  env: {
+    descope_project_id: process.env.REACT_APP_DESCOPE_PROJECT_ID,
+    descope_management_key: process.env.REACT_APP_DESCOPE_MANAGEMENT_KEY
+  },
+}
+```
+
+:::
+
+## Custom Command for Descope Authentication
+
+There are two ways you can authenticate to Descope:
+
+- [Login with UI](#Login-with-UI)
+- [Programmatic Login](#Programmatic-Login)
+
+## Initialize test user
+For both UI and programatic login, you'll need to initialize a test user. 
+
+```js
+const projectId = Cypress.env('descope_project_id')
+const managementKey = Cypress.env('descope_management_key')
+const descopeAPIDomain = "api.descope.com"
+
+// Define the authorization header
+const authHeader = {
+    'Authorization': `Bearer ${projectId}:${managementKey}`,
+}
+
+// Define the base URL for Descope API
+const descopeApiBaseURL = `https://${descopeAPIDomain}/v1`;
+
+const testUserLoginId = "testUser" + Math.floor(1000 + Math.random() * 9000) + "@gmail.com"; // Must match email to pass validation
+
+// Define the test user details
+const testUser = {
+    loginId: testUserLoginId,
+    email: testUserLoginId,
+    phone: "+11231231234",
+    verifiedEmail: true,
+    verifiedPhone: true,
+    displayName: "Test User",
+    test: true,
+}
+```
+
+### Login with UI
+
+Next, we'll write a custom command called `loginToDescope` to perform a login to
+[Descope](https://descope.com) using the [Test User Management API](https://docs.descope.com/api/testusermanagement/)
+ and navigating via the user interface. This command will
+
+1. Navigate to the Descope login
+2. Input user credentials
+3. Sign in
+4. Cache the results with [`cy.session()`](/api/commands/session)
+
+```js
+// cypress/support/auth-provider-commands/descope.ts
+
+function loginViaDescopeUi() {
+  // App landing page redirects to Auth0.
+  cy.visit('/')
+
+  // Login on Auth0.
+  cy.origin(
+    Cypress.env('auth0_domain'),
+    { args: { username, password } },
+    ({ username, password }) => {
+      cy.get('input#username').type(username)
+      cy.get('input#password').type(password, { log: false })
+      cy.contains('button[value=default]', 'Continue').click()
+    }
+  )
+
+  // Ensure Auth0 has redirected us back to the RWA.
+  cy.url().should('equal', 'http://localhost:3000/')
+}
+
+Cypress.Commands.add('loginToAuth0', () => {
+  const log = Cypress.log({
+    displayName: 'Descope LOGIN',
+    message: [`🔐 Authenticating | ${username}`],
+    // @ts-ignore
+    autoEnd: false,
+  })
+  log.snapshot('before')
+
+  loginViaAuth0Ui(username, password)
+
+  log.snapshot('after')
+  log.end()
+})
+```
+
+Now, we can use our `loginToAuth0` command in the test. Below is our test to
+login as a user via Auth0 and run a basic sanity check.
+
+:::tip
+
+The
+[runnable version of this test](https://github.com/cypress-io/cypress-realworld-app/blob/develop/cypress/tests/ui-auth-providers/auth0.spec.ts)
+is in the
+[Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app).
+
+:::
+
+```js
+describe('Auth0', function () {
+  beforeEach(function () {
+    cy.task('db:seed')
+    cy.intercept('POST', '/graphql').as('createBankAccount')
+    cy.loginToAuth0(
+      Cypress.env('auth0_username'),
+      Cypress.env('auth0_password')
+    )
+    cy.visit('/')
+  })
+
+  it('shows onboarding', function () {
+    cy.contains('Get Started').should('be.visible')
+  })
+})
+```
+
+
+
+Lastly, we can refactor our login command to take advantage of
+[`cy.session()`](/api/commands/session) to store our logged in user so we don't
+have to reauthenticate before every test.
+
+```js
+Cypress.Commands.add('loginToAuth0', (username: string, password: string) => {
+  const log = Cypress.log({
+    displayName: 'AUTH0 LOGIN',
+    message: [`🔐 Authenticating | ${username}`],
+    // @ts-ignore
+    autoEnd: false,
+  })
+  log.snapshot('before')
+
+  cy.session(
+    `auth0-${username}`,
+    () => {
+      loginViaAuth0Ui(username, password)
+    },
+    {
+      validate: () => {
+        // Validate presence of access token in localStorage.
+        cy.wrap(localStorage)
+          .invoke('getItem', 'authAccessToken')
+          .should('exist')
+      },
+    }
+  )
+
+  log.snapshot('after')
+  log.end()
+})
+```
+
+
+
+### Programmatic Login
+
+Below is a command to programmatically login into [Auth0](https://auth0.com),
+using the
+[/oauth/token endpoint](https://auth0.com/docs/protocols/protocol-oauth2#token-endpoint)
+and set an item in `localStorage` with the authenticated users details, which we
+will use in our application code to verify we are authenticated under test.
+
+The `loginByAuth0Api` command will execute the following steps:
+
+1. Use the
+   [/oauth/token endpoint](https://auth0.com/docs/protocols/protocol-oauth2#token-endpoint)
+   to perform the programmatic login.
+2. Finally the `auth0Cypress` `localStorage` item is set with the
+   `access token`, `id_token` and user profile.
+
+```jsx
+// cypress/support/commands.js
+Cypress.Commands.add(
+  'loginByAuth0Api',
+  (username: string, password: string) => {
+    cy.log(`Logging in as ${username}`)
+    const client_id = Cypress.env('auth0_client_id')
+    const client_secret = Cypress.env('auth0_client_secret')
+    const audience = Cypress.env('auth0_audience')
+    const scope = Cypress.env('auth0_scope')
+
+    cy.request({
+      method: 'POST',
+      url: `https://${Cypress.env('auth0_domain')}/oauth/token`,
+      body: {
+        grant_type: 'password',
+        username,
+        password,
+        audience,
+        scope,
+        client_id,
+        client_secret,
+      },
+    }).then(({ body }) => {
+      const claims = jwt.decode(body.id_token)
+      const {
+        nickname,
+        name,
+        picture,
+        updated_at,
+        email,
+        email_verified,
+        sub,
+        exp,
+      } = claims
+
+      const item = {
+        body: {
+          ...body,
+          decodedToken: {
+            claims,
+            user: {
+              nickname,
+              name,
+              picture,
+              updated_at,
+              email,
+              email_verified,
+              sub,
+            },
+            audience,
+            client_id,
+          },
+        },
+        expiresAt: exp,
+      }
+
+      window.localStorage.setItem('auth0Cypress', JSON.stringify(item))
+
+      cy.visit('/')
+    })
+  }
+)
+```
+
+With our Auth0 app setup properly in the Auth0 Developer console, necessary
+environment variables in place, and our `loginByAuth0Api` command implemented,
+we will be able to authenticate with Auth0 while our app is under test. Below is
+a test to login as a user via [Auth0](https://auth0.com), complete the
+onboarding process and logout.
+
+```jsx
+describe('Auth0', function () {
+  beforeEach(function () {
+    cy.task('db:seed')
+    cy.loginByAuth0Api(
+      Cypress.env('auth0_username'),
+      Cypress.env('auth0_password')
+    )
+  })
+
+  it('shows onboarding', function () {
+    cy.contains('Get Started').should('be.visible')
+  })
+})
+```
From 4144e91feb1ed8d0c39d95f8c2a6899d8b7865ad Mon Sep 17 00:00:00 2001
From: Allen Zhou <46854522+allenzhou101@users.noreply.github.com>
Date: Sun, 9 Jul 2023 19:50:16 +0900
Subject: [PATCH 2/7] Update descope-authentication.mdx
---
 .../testing-strategies/descope-authentication.mdx           | 6 ------
 1 file changed, 6 deletions(-)
diff --git a/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx b/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
index 2e69e55a08..daa488bd7b 100644
--- a/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
+++ b/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
@@ -10,8 +10,6 @@ slug: /guides/end-to-end-testing/descope-authentication
 - Log in to [Descope](https://descope.com) through the UI
 - Programmatically authenticate with [Descope](https://descope.com) via a custom
   Cypress command
-- Adapt your [Descope](https://descope.com) application for programmatic
-  authentication during testing
 
 :::
 
@@ -168,8 +166,6 @@ describe('Auth0', function () {
 })
 ```
 
-
-
 Lastly, we can refactor our login command to take advantage of
 [`cy.session()`](/api/commands/session) to store our logged in user so we don't
 have to reauthenticate before every test.
@@ -204,8 +200,6 @@ Cypress.Commands.add('loginToAuth0', (username: string, password: string) => {
 })
 ```
 
-
-
 ### Programmatic Login
 
 Below is a command to programmatically login into [Auth0](https://auth0.com),
From 5f2ff02387387c8a42c094740a0e2f2ef8a56118 Mon Sep 17 00:00:00 2001
From: Allen Zhou <46854522+allenzhou101@users.noreply.github.com>
Date: Mon, 10 Jul 2023 18:24:16 +0900
Subject: [PATCH 3/7] Update descope-authentication.mdx
---
 .../descope-authentication.mdx                | 312 ++++++++----------
 1 file changed, 136 insertions(+), 176 deletions(-)
diff --git a/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx b/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
index daa488bd7b..58d74b6756 100644
--- a/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
+++ b/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
@@ -57,10 +57,13 @@ There are two ways you can authenticate to Descope:
 - [Login with UI](#Login-with-UI)
 - [Programmatic Login](#Programmatic-Login)
 
-## Initialize test user
-For both UI and programatic login, you'll need to initialize a test user. 
+### Initialize test user & variables
+For both UI and programatic login, you'll need to initialize a test user and get your env variables. 
+We'll do this in the `cypress/support/commands.js` file.
 
 ```js
+// cypress/support/commands.js
+
 const projectId = Cypress.env('descope_project_id')
 const managementKey = Cypress.env('descope_management_key')
 const descopeAPIDomain = "api.descope.com"
@@ -87,218 +90,175 @@ const testUser = {
 }
 ```
 
+We’ll also need to clean up the created testing users before starting so we don’t go over the limit. 
+This is done with the `deleteAllTestUsers` function.
+```js
+// cypress/support/commands.js
+
+Cypress.Commands.add('deleteAllTestUsers', () => {
+    cy.request({
+        method: 'DELETE',
+        url: `${descopeApiBaseURL}/mgmt/user/test/delete/all`,
+        headers: authHeader,
+    })
+})
+```
+
+
 ### Login with UI
 
-Next, we'll write a custom command called `loginToDescope` to perform a login to
+Next, we'll write a custom command called `loginViaDescopeUI` to perform a login to
 [Descope](https://descope.com) using the [Test User Management API](https://docs.descope.com/api/testusermanagement/)
  and navigating via the user interface. This command will
 
 1. Navigate to the Descope login
-2. Input user credentials
-3. Sign in
-4. Cache the results with [`cy.session()`](/api/commands/session)
+2. Use the [Test User Management API](https://docs.descope.com/api/testusermanagement/) to perform the login (create user and generate OTP code).
+3. Enter the user loginId and code that we just generated to log in via the user interface.
 
 ```js
-// cypress/support/auth-provider-commands/descope.ts
-
-function loginViaDescopeUi() {
-  // App landing page redirects to Auth0.
-  cy.visit('/')
-
-  // Login on Auth0.
-  cy.origin(
-    Cypress.env('auth0_domain'),
-    { args: { username, password } },
-    ({ username, password }) => {
-      cy.get('input#username').type(username)
-      cy.get('input#password').type(password, { log: false })
-      cy.contains('button[value=default]', 'Continue').click()
-    }
-  )
-
-  // Ensure Auth0 has redirected us back to the RWA.
-  cy.url().should('equal', 'http://localhost:3000/')
-}
-
-Cypress.Commands.add('loginToAuth0', () => {
-  const log = Cypress.log({
-    displayName: 'Descope LOGIN',
-    message: [`🔐 Authenticating | ${username}`],
-    // @ts-ignore
-    autoEnd: false,
-  })
-  log.snapshot('before')
-
-  loginViaAuth0Ui(username, password)
+// cypress/support/commands.js
 
-  log.snapshot('after')
-  log.end()
+Cypress.Commands.add('loginViaDescopeUI', () => {
+    cy.request({
+        method: 'POST',
+        url: `${descopeApiBaseURL}/mgmt/user/create`,
+        headers: authHeader,
+        body: testUser,
+    })
+        .then(({ body }) => {
+            const loginId = body["user"]["loginIds"][0];
+            cy.request({
+                method: 'POST',
+                url: `${descopeApiBaseURL}/mgmt/tests/generate/otp`,
+                headers: authHeader,
+                body: {
+                    "loginId": loginId,
+                    "deliveryMethod": "email"
+                }
+            })
+                .then(({ body }) => {
+                    const otpCode = body["code"]
+                    const loginID = body["loginId"]
+                    cy.visit('/login')
+                    cy.get('descope-wc')
+                        .find('input')
+                        .type(loginID)
+                    cy.get('descope-wc')
+                        .find('button').contains('Continue').click()
+                    cy.get('descope-wc').find('.descope-input-wrapper').find('input').should('exist') // Assertion added to wait for the OTP code input to appear
+                    let otpCodeArray = Array.from(otpCode); // Convert the OTP code string to an array
+                    for (var i = 0; i < otpCodeArray.length; i++) {
+                        cy.get('descope-wc').find('.descope-input-wrapper').find('input').eq(i + 1).type(otpCodeArray[i], { force: true })
+                    }
+                    cy.get('descope-wc')
+                        .find('button').contains('Submit').click()
+
+										// Customize these steps based on your authentication flow
+                })
+        })
 })
 ```
 
-Now, we can use our `loginToAuth0` command in the test. Below is our test to
-login as a user via Auth0 and run a basic sanity check.
-
-:::tip
-
-The
-[runnable version of this test](https://github.com/cypress-io/cypress-realworld-app/blob/develop/cypress/tests/ui-auth-providers/auth0.spec.ts)
-is in the
-[Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app).
-
-:::
+Now, we can use our `loginViaDescopeUI` command in the test. Below is our test to
+login as a user via Descope and run a basic sanity check.
 
 ```js
-describe('Auth0', function () {
+describe('Descope', function () {
   beforeEach(function () {
-    cy.task('db:seed')
-    cy.intercept('POST', '/graphql').as('createBankAccount')
-    cy.loginToAuth0(
-      Cypress.env('auth0_username'),
-      Cypress.env('auth0_password')
-    )
-    cy.visit('/')
+    cy.deleteAllTestUsers()
+    cy.loginViaDescopeUI()
+		cy.visit('/')
   })
 
-  it('shows onboarding', function () {
-    cy.contains('Get Started').should('be.visible')
+  it('shows welcome page', function () {
+    cy.contains('Welcome').should('be.visible')
   })
 })
 ```
 
-Lastly, we can refactor our login command to take advantage of
-[`cy.session()`](/api/commands/session) to store our logged in user so we don't
-have to reauthenticate before every test.
-
-```js
-Cypress.Commands.add('loginToAuth0', (username: string, password: string) => {
-  const log = Cypress.log({
-    displayName: 'AUTH0 LOGIN',
-    message: [`🔐 Authenticating | ${username}`],
-    // @ts-ignore
-    autoEnd: false,
-  })
-  log.snapshot('before')
-
-  cy.session(
-    `auth0-${username}`,
-    () => {
-      loginViaAuth0Ui(username, password)
-    },
-    {
-      validate: () => {
-        // Validate presence of access token in localStorage.
-        cy.wrap(localStorage)
-          .invoke('getItem', 'authAccessToken')
-          .should('exist')
-      },
-    }
-  )
-
-  log.snapshot('after')
-  log.end()
-})
-```
-
 ### Programmatic Login
 
-Below is a command to programmatically login into [Auth0](https://auth0.com),
-using the
-[/oauth/token endpoint](https://auth0.com/docs/protocols/protocol-oauth2#token-endpoint)
+We'll now write a command to programmatically login into 
+[Descope](https://descope.com) using the [Test User Management API](https://docs.descope.com/api/testusermanagement/)
 and set an item in `localStorage` with the authenticated users details, which we
 will use in our application code to verify we are authenticated under test.
 
-The `loginByAuth0Api` command will execute the following steps:
+The `loginViaDescopeApi` command will execute the following steps:
+
+1. Use the [Test User Management API](https://docs.descope.com/api/testusermanagement/) to perform the programmatic login (create user, generate OTP code, and verify OTP code).
+2. Set the `refreshToken` and `sessionToken` items in localStorage.
 
-1. Use the
-   [/oauth/token endpoint](https://auth0.com/docs/protocols/protocol-oauth2#token-endpoint)
-   to perform the programmatic login.
-2. Finally the `auth0Cypress` `localStorage` item is set with the
-   `access token`, `id_token` and user profile.
 
 ```jsx
 // cypress/support/commands.js
-Cypress.Commands.add(
-  'loginByAuth0Api',
-  (username: string, password: string) => {
-    cy.log(`Logging in as ${username}`)
-    const client_id = Cypress.env('auth0_client_id')
-    const client_secret = Cypress.env('auth0_client_secret')
-    const audience = Cypress.env('auth0_audience')
-    const scope = Cypress.env('auth0_scope')
-
+Cypress.Commands.add('loginViaDescopeAPI', () => {
     cy.request({
-      method: 'POST',
-      url: `https://${Cypress.env('auth0_domain')}/oauth/token`,
-      body: {
-        grant_type: 'password',
-        username,
-        password,
-        audience,
-        scope,
-        client_id,
-        client_secret,
-      },
-    }).then(({ body }) => {
-      const claims = jwt.decode(body.id_token)
-      const {
-        nickname,
-        name,
-        picture,
-        updated_at,
-        email,
-        email_verified,
-        sub,
-        exp,
-      } = claims
-
-      const item = {
-        body: {
-          ...body,
-          decodedToken: {
-            claims,
-            user: {
-              nickname,
-              name,
-              picture,
-              updated_at,
-              email,
-              email_verified,
-              sub,
-            },
-            audience,
-            client_id,
-          },
-        },
-        expiresAt: exp,
-      }
-
-      window.localStorage.setItem('auth0Cypress', JSON.stringify(item))
-
-      cy.visit('/')
+        method: 'POST',
+        url: `${descopeApiBaseURL}/mgmt/user/create`,
+        headers: authHeader,
+        body: testUser,
     })
-  }
-)
+        .then(({ body }) => {
+            const loginId = body["user"]["loginIds"][0];
+            cy.request({
+                method: 'POST',
+                url: `${descopeApiBaseURL}/mgmt/tests/generate/otp`,
+                headers: authHeader,
+                body: {
+                    "loginId": loginId,
+                    "deliveryMethod": "email"
+                }
+            })
+                .then(({ body }) => {
+                    const otpCode = body["code"]
+                    cy.request({
+                        method: 'POST',
+                        url: `${descopeApiBaseURL}/auth/otp/verify/email`,
+                        headers: authHeader,
+                        body: {
+                            "loginId": loginId,
+                            "code": otpCode
+                        }
+                    })
+                        .then(({ body }) => {
+                            const sessionJwt = body["sessionJwt"]
+                            const refreshJwt = body["refreshJwt"]
+
+                            /** Default name for the session cookie name / local storage key */
+                            const SESSION_TOKEN_KEY = 'DS';
+                            /** Default name for the refresh local storage key */
+                            const REFRESH_TOKEN_KEY = 'DSR';
+
+                            // // Store the JWT in the browser's local storage.
+                            cy.window().then((win) => {
+                                win.localStorage.setItem(SESSION_TOKEN_KEY, sessionJwt);
+                                win.localStorage.setItem(REFRESH_TOKEN_KEY, refreshJwt);
+                            });
+
+                            // // Now navigate to the root URL of your application.
+                            cy.visit('/')
+
+                        })
+                })
+        })
+})
 ```
 
-With our Auth0 app setup properly in the Auth0 Developer console, necessary
-environment variables in place, and our `loginByAuth0Api` command implemented,
-we will be able to authenticate with Auth0 while our app is under test. Below is
-a test to login as a user via [Auth0](https://auth0.com), complete the
-onboarding process and logout.
+With our Descope app setup properly in the Descope Developer console, 
+necessary environment variables in place, and our 
+`loginViaDescopeApi` command implemented, we will be able to authenticate
+ with Descope while our app is under test. Below is 
+ a test to login as a user using our loginViaDescopeAPI function and verify the welcome page is showing.
 
 ```jsx
-describe('Auth0', function () {
+describe('Descope', function () {
   beforeEach(function () {
-    cy.task('db:seed')
-    cy.loginByAuth0Api(
-      Cypress.env('auth0_username'),
-      Cypress.env('auth0_password')
-    )
+    cy.deleteAllTestUsers()
+    cy.loginViaDescopeAPI()
   })
 
-  it('shows onboarding', function () {
-    cy.contains('Get Started').should('be.visible')
-  })
+  it('shows welcome page', function () {
+    cy.contains('Welcome').should('be.visible')
+    })
 })
 ```
From c2d433b0f7218150ce64992fb8956fd130473d0f Mon Sep 17 00:00:00 2001
From: Allen Zhou <46854522+allenzhou101@users.noreply.github.com>
Date: Mon, 10 Jul 2023 18:24:29 +0900
Subject: [PATCH 4/7] Update descope-authentication.mdx
---
 .../testing-strategies/descope-authentication.mdx               | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx b/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
index 58d74b6756..a61e5f2a6b 100644
--- a/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
+++ b/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
@@ -90,7 +90,7 @@ const testUser = {
 }
 ```
 
-We’ll also need to clean up the created testing users before starting so we don’t go over the limit. 
+We’ll also need to clean up the created test users before starting so we don’t go over the limit. 
 This is done with the `deleteAllTestUsers` function.
 ```js
 // cypress/support/commands.js
From e7107ed57b68a9dffdeca98632591aaa08e907e7 Mon Sep 17 00:00:00 2001
From: Allen Zhou <46854522+allenzhou101@users.noreply.github.com>
Date: Mon, 10 Jul 2023 18:27:48 +0900
Subject: [PATCH 5/7] Update descope-authentication.mdx
---
 .../descope-authentication.mdx                   | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx b/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
index a61e5f2a6b..b3b74715d5 100644
--- a/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
+++ b/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
@@ -7,7 +7,7 @@ slug: /guides/end-to-end-testing/descope-authentication
 
 ##  What you'll learn
 
-- Log in to [Descope](https://descope.com) through the UI
+- Log in to [Descope](https://descope.com) via the UI
 - Programmatically authenticate with [Descope](https://descope.com) via a custom
   Cypress command
 
@@ -58,7 +58,7 @@ There are two ways you can authenticate to Descope:
 - [Programmatic Login](#Programmatic-Login)
 
 ### Initialize test user & variables
-For both UI and programatic login, you'll need to initialize a test user and get your env variables. 
+For both UI and programatic login, you'll need to initialize a test user, get your env variables, and create a delete users command. 
 We'll do this in the `cypress/support/commands.js` file.
 
 ```js
@@ -90,8 +90,8 @@ const testUser = {
 }
 ```
 
-We’ll also need to clean up the created test users before starting so we don’t go over the limit. 
-This is done with the `deleteAllTestUsers` function.
+To clean up the created test users so we don’t go over the test user limit,
+we'll have a `deleteAllTestUsers` function.
 ```js
 // cypress/support/commands.js
 
@@ -113,7 +113,7 @@ Next, we'll write a custom command called `loginViaDescopeUI` to perform a login
 
 1. Navigate to the Descope login
 2. Use the [Test User Management API](https://docs.descope.com/api/testusermanagement/) to perform the login (create user and generate OTP code).
-3. Enter the user loginId and code that we just generated to log in via the user interface.
+3. Enter the user login ID and code that we just generated to log in via the user interface.
 
 ```js
 // cypress/support/commands.js
@@ -183,7 +183,7 @@ We'll now write a command to programmatically login into
 and set an item in `localStorage` with the authenticated users details, which we
 will use in our application code to verify we are authenticated under test.
 
-The `loginViaDescopeApi` command will execute the following steps:
+The `loginViaDescopeAPI` command will execute the following steps:
 
 1. Use the [Test User Management API](https://docs.descope.com/api/testusermanagement/) to perform the programmatic login (create user, generate OTP code, and verify OTP code).
 2. Set the `refreshToken` and `sessionToken` items in localStorage.
@@ -246,9 +246,9 @@ Cypress.Commands.add('loginViaDescopeAPI', () => {
 
 With our Descope app setup properly in the Descope Developer console, 
 necessary environment variables in place, and our 
-`loginViaDescopeApi` command implemented, we will be able to authenticate
+`loginViaDescopeAPI` command implemented, we will be able to authenticate
  with Descope while our app is under test. Below is 
- a test to login as a user using our loginViaDescopeAPI function and verify the welcome page is showing.
+ a test to login as a user using our `loginViaDescopeAPI` function and verify the welcome page is showing.
 
 ```jsx
 describe('Descope', function () {
From 369ab58fb237a5468302f51e378d86f0b9614229 Mon Sep 17 00:00:00 2001
From: Allen Zhou <46854522+allenzhou101@users.noreply.github.com>
Date: Mon, 10 Jul 2023 18:37:44 +0900
Subject: [PATCH 6/7] Make page "Prettier"
---
 .../descope-authentication.mdx                | 212 +++++++++---------
 1 file changed, 105 insertions(+), 107 deletions(-)
diff --git a/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx b/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
index b3b74715d5..e7c2b47dc1 100644
--- a/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
+++ b/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
@@ -58,7 +58,8 @@ There are two ways you can authenticate to Descope:
 - [Programmatic Login](#Programmatic-Login)
 
 ### Initialize test user & variables
-For both UI and programatic login, you'll need to initialize a test user, get your env variables, and create a delete users command. 
+
+For both UI and programatic login, you'll need to initialize a test user, get your env variables, and create a delete users command.
 We'll do this in the `cypress/support/commands.js` file.
 
 ```js
@@ -66,50 +67,51 @@ We'll do this in the `cypress/support/commands.js` file.
 
 const projectId = Cypress.env('descope_project_id')
 const managementKey = Cypress.env('descope_management_key')
-const descopeAPIDomain = "api.descope.com"
+const descopeAPIDomain = 'api.descope.com'
 
 // Define the authorization header
 const authHeader = {
-    'Authorization': `Bearer ${projectId}:${managementKey}`,
+  Authorization: `Bearer ${projectId}:${managementKey}`,
 }
 
 // Define the base URL for Descope API
-const descopeApiBaseURL = `https://${descopeAPIDomain}/v1`;
+const descopeApiBaseURL = `https://${descopeAPIDomain}/v1`
 
-const testUserLoginId = "testUser" + Math.floor(1000 + Math.random() * 9000) + "@gmail.com"; // Must match email to pass validation
+const testUserLoginId =
+  'testUser' + Math.floor(1000 + Math.random() * 9000) + '@gmail.com' // Must match email to pass validation
 
 // Define the test user details
 const testUser = {
-    loginId: testUserLoginId,
-    email: testUserLoginId,
-    phone: "+11231231234",
-    verifiedEmail: true,
-    verifiedPhone: true,
-    displayName: "Test User",
-    test: true,
+  loginId: testUserLoginId,
+  email: testUserLoginId,
+  phone: '+11231231234',
+  verifiedEmail: true,
+  verifiedPhone: true,
+  displayName: 'Test User',
+  test: true,
 }
 ```
 
 To clean up the created test users so we don’t go over the test user limit,
 we'll have a `deleteAllTestUsers` function.
+
 ```js
 // cypress/support/commands.js
 
 Cypress.Commands.add('deleteAllTestUsers', () => {
-    cy.request({
-        method: 'DELETE',
-        url: `${descopeApiBaseURL}/mgmt/user/test/delete/all`,
-        headers: authHeader,
-    })
+  cy.request({
+    method: 'DELETE',
+    url: `${descopeApiBaseURL}/mgmt/user/test/delete/all`,
+    headers: authHeader,
+  })
 })
 ```
 
-
 ### Login with UI
 
 Next, we'll write a custom command called `loginViaDescopeUI` to perform a login to
 [Descope](https://descope.com) using the [Test User Management API](https://docs.descope.com/api/testusermanagement/)
- and navigating via the user interface. This command will
+and navigating via the user interface. This command will
 
 1. Navigate to the Descope login
 2. Use the [Test User Management API](https://docs.descope.com/api/testusermanagement/) to perform the login (create user and generate OTP code).
@@ -119,43 +121,44 @@ Next, we'll write a custom command called `loginViaDescopeUI` to perform a login
 // cypress/support/commands.js
 
 Cypress.Commands.add('loginViaDescopeUI', () => {
+  cy.request({
+    method: 'POST',
+    url: `${descopeApiBaseURL}/mgmt/user/create`,
+    headers: authHeader,
+    body: testUser,
+  }).then(({ body }) => {
+    const loginId = body['user']['loginIds'][0]
     cy.request({
-        method: 'POST',
-        url: `${descopeApiBaseURL}/mgmt/user/create`,
-        headers: authHeader,
-        body: testUser,
+      method: 'POST',
+      url: `${descopeApiBaseURL}/mgmt/tests/generate/otp`,
+      headers: authHeader,
+      body: {
+        loginId: loginId,
+        deliveryMethod: 'email',
+      },
+    }).then(({ body }) => {
+      const otpCode = body['code']
+      const loginID = body['loginId']
+      cy.visit('/login')
+      cy.get('descope-wc').find('input').type(loginID)
+      cy.get('descope-wc').find('button').contains('Continue').click()
+      cy.get('descope-wc')
+        .find('.descope-input-wrapper')
+        .find('input')
+        .should('exist') // Assertion added to wait for the OTP code input to appear
+      let otpCodeArray = Array.from(otpCode) // Convert the OTP code string to an array
+      for (var i = 0; i < otpCodeArray.length; i++) {
+        cy.get('descope-wc')
+          .find('.descope-input-wrapper')
+          .find('input')
+          .eq(i + 1)
+          .type(otpCodeArray[i], { force: true })
+      }
+      cy.get('descope-wc').find('button').contains('Submit').click()
+
+      // Customize these steps based on your authentication flow
     })
-        .then(({ body }) => {
-            const loginId = body["user"]["loginIds"][0];
-            cy.request({
-                method: 'POST',
-                url: `${descopeApiBaseURL}/mgmt/tests/generate/otp`,
-                headers: authHeader,
-                body: {
-                    "loginId": loginId,
-                    "deliveryMethod": "email"
-                }
-            })
-                .then(({ body }) => {
-                    const otpCode = body["code"]
-                    const loginID = body["loginId"]
-                    cy.visit('/login')
-                    cy.get('descope-wc')
-                        .find('input')
-                        .type(loginID)
-                    cy.get('descope-wc')
-                        .find('button').contains('Continue').click()
-                    cy.get('descope-wc').find('.descope-input-wrapper').find('input').should('exist') // Assertion added to wait for the OTP code input to appear
-                    let otpCodeArray = Array.from(otpCode); // Convert the OTP code string to an array
-                    for (var i = 0; i < otpCodeArray.length; i++) {
-                        cy.get('descope-wc').find('.descope-input-wrapper').find('input').eq(i + 1).type(otpCodeArray[i], { force: true })
-                    }
-                    cy.get('descope-wc')
-                        .find('button').contains('Submit').click()
-
-										// Customize these steps based on your authentication flow
-                })
-        })
+  })
 })
 ```
 
@@ -167,7 +170,7 @@ describe('Descope', function () {
   beforeEach(function () {
     cy.deleteAllTestUsers()
     cy.loginViaDescopeUI()
-		cy.visit('/')
+    cy.visit('/')
   })
 
   it('shows welcome page', function () {
@@ -178,7 +181,7 @@ describe('Descope', function () {
 
 ### Programmatic Login
 
-We'll now write a command to programmatically login into 
+We'll now write a command to programmatically login into
 [Descope](https://descope.com) using the [Test User Management API](https://docs.descope.com/api/testusermanagement/)
 and set an item in `localStorage` with the authenticated users details, which we
 will use in our application code to verify we are authenticated under test.
@@ -188,67 +191,62 @@ The `loginViaDescopeAPI` command will execute the following steps:
 1. Use the [Test User Management API](https://docs.descope.com/api/testusermanagement/) to perform the programmatic login (create user, generate OTP code, and verify OTP code).
 2. Set the `refreshToken` and `sessionToken` items in localStorage.
 
-
 ```jsx
 // cypress/support/commands.js
 Cypress.Commands.add('loginViaDescopeAPI', () => {
+  cy.request({
+    method: 'POST',
+    url: `${descopeApiBaseURL}/mgmt/user/create`,
+    headers: authHeader,
+    body: testUser,
+  }).then(({ body }) => {
+    const loginId = body['user']['loginIds'][0]
     cy.request({
+      method: 'POST',
+      url: `${descopeApiBaseURL}/mgmt/tests/generate/otp`,
+      headers: authHeader,
+      body: {
+        loginId: loginId,
+        deliveryMethod: 'email',
+      },
+    }).then(({ body }) => {
+      const otpCode = body['code']
+      cy.request({
         method: 'POST',
-        url: `${descopeApiBaseURL}/mgmt/user/create`,
+        url: `${descopeApiBaseURL}/auth/otp/verify/email`,
         headers: authHeader,
-        body: testUser,
-    })
-        .then(({ body }) => {
-            const loginId = body["user"]["loginIds"][0];
-            cy.request({
-                method: 'POST',
-                url: `${descopeApiBaseURL}/mgmt/tests/generate/otp`,
-                headers: authHeader,
-                body: {
-                    "loginId": loginId,
-                    "deliveryMethod": "email"
-                }
-            })
-                .then(({ body }) => {
-                    const otpCode = body["code"]
-                    cy.request({
-                        method: 'POST',
-                        url: `${descopeApiBaseURL}/auth/otp/verify/email`,
-                        headers: authHeader,
-                        body: {
-                            "loginId": loginId,
-                            "code": otpCode
-                        }
-                    })
-                        .then(({ body }) => {
-                            const sessionJwt = body["sessionJwt"]
-                            const refreshJwt = body["refreshJwt"]
-
-                            /** Default name for the session cookie name / local storage key */
-                            const SESSION_TOKEN_KEY = 'DS';
-                            /** Default name for the refresh local storage key */
-                            const REFRESH_TOKEN_KEY = 'DSR';
-
-                            // // Store the JWT in the browser's local storage.
-                            cy.window().then((win) => {
-                                win.localStorage.setItem(SESSION_TOKEN_KEY, sessionJwt);
-                                win.localStorage.setItem(REFRESH_TOKEN_KEY, refreshJwt);
-                            });
-
-                            // // Now navigate to the root URL of your application.
-                            cy.visit('/')
-
-                        })
-                })
+        body: {
+          loginId: loginId,
+          code: otpCode,
+        },
+      }).then(({ body }) => {
+        const sessionJwt = body['sessionJwt']
+        const refreshJwt = body['refreshJwt']
+
+        /** Default name for the session cookie name / local storage key */
+        const SESSION_TOKEN_KEY = 'DS'
+        /** Default name for the refresh local storage key */
+        const REFRESH_TOKEN_KEY = 'DSR'
+
+        // // Store the JWT in the browser's local storage.
+        cy.window().then((win) => {
+          win.localStorage.setItem(SESSION_TOKEN_KEY, sessionJwt)
+          win.localStorage.setItem(REFRESH_TOKEN_KEY, refreshJwt)
         })
+
+        // // Now navigate to the root URL of your application.
+        cy.visit('/')
+      })
+    })
+  })
 })
 ```
 
-With our Descope app setup properly in the Descope Developer console, 
-necessary environment variables in place, and our 
+With our Descope app setup properly in the Descope Developer console,
+necessary environment variables in place, and our
 `loginViaDescopeAPI` command implemented, we will be able to authenticate
- with Descope while our app is under test. Below is 
- a test to login as a user using our `loginViaDescopeAPI` function and verify the welcome page is showing.
+with Descope while our app is under test. Below is
+a test to login as a user using our `loginViaDescopeAPI` function and verify the welcome page is showing.
 
 ```jsx
 describe('Descope', function () {
@@ -259,6 +257,6 @@ describe('Descope', function () {
 
   it('shows welcome page', function () {
     cy.contains('Welcome').should('be.visible')
-    })
+  })
 })
 ```
From 7e0fb6276a8885fc7fecf2d595d1be2f4aa3ca6d Mon Sep 17 00:00:00 2001
From: Allen Zhou <46854522+allenzhou101@users.noreply.github.com>
Date: Mon, 23 Dec 2024 14:19:21 -0600
Subject: [PATCH 7/7] Move Descope Authentication Guide to App folder
---
 .../guides/authentication-testing}/descope-authentication.mdx     | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename docs/{guides/end-to-end-testing/testing-strategies => app/guides/authentication-testing}/descope-authentication.mdx (100%)
diff --git a/docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx b/docs/app/guides/authentication-testing/descope-authentication.mdx
similarity index 100%
rename from docs/guides/end-to-end-testing/testing-strategies/descope-authentication.mdx
rename to docs/app/guides/authentication-testing/descope-authentication.mdx