@clerk/testing 2.0.0-snapshot.v07d9254 → 2.0.0-snapshot.v20251203203405
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -41
- package/cypress/package.json +5 -0
- package/dist/chunk-JDNEQWYI.mjs +10 -0
- package/dist/chunk-JDNEQWYI.mjs.map +1 -0
- package/dist/chunk-M5YIJ3SE.mjs +2 -0
- package/dist/chunk-M5YIJ3SE.mjs.map +1 -0
- package/dist/chunk-YFUXUEZ5.mjs +2 -0
- package/dist/chunk-YFUXUEZ5.mjs.map +1 -0
- package/dist/cypress/index.js +10 -0
- package/dist/cypress/index.js.map +1 -0
- package/dist/cypress/index.mjs +2 -0
- package/dist/cypress/index.mjs.map +1 -0
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -0
- package/dist/index.mjs.map +1 -0
- package/dist/playwright/index.js +10 -0
- package/dist/playwright/index.js.map +1 -0
- package/dist/playwright/index.mjs +2 -0
- package/dist/playwright/index.mjs.map +1 -0
- package/dist/playwright/unstable/index.js +2 -0
- package/dist/playwright/unstable/index.js.map +1 -0
- package/dist/playwright/unstable/index.mjs +2 -0
- package/dist/playwright/unstable/index.mjs.map +1 -0
- package/dist/types/common/constants.d.ts +2 -0
- package/dist/types/common/constants.d.ts.map +1 -0
- package/dist/types/common/errors.d.ts +2 -0
- package/dist/types/common/errors.d.ts.map +1 -0
- package/dist/types/common/helpers-utils.d.ts +3 -0
- package/dist/types/common/helpers-utils.d.ts.map +1 -0
- package/dist/types/common/index.d.ts +6 -0
- package/dist/types/common/index.d.ts.map +1 -0
- package/dist/types/common/setup.d.ts +3 -0
- package/dist/types/common/setup.d.ts.map +1 -0
- package/dist/types/common/types.d.ts +30 -0
- package/dist/types/common/types.d.ts.map +1 -0
- package/dist/types/cypress/custom-commands.d.ts +60 -0
- package/dist/types/cypress/custom-commands.d.ts.map +1 -0
- package/dist/types/cypress/index.d.ts +4 -0
- package/dist/types/cypress/index.d.ts.map +1 -0
- package/dist/types/cypress/setup.d.ts +23 -0
- package/dist/types/cypress/setup.d.ts.map +1 -0
- package/dist/types/cypress/setupClerkTestingToken.d.ts +22 -0
- package/dist/types/cypress/setupClerkTestingToken.d.ts.map +1 -0
- package/dist/types/index.d.ts +1 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/playwright/helpers.d.ts +101 -0
- package/dist/types/playwright/helpers.d.ts.map +1 -0
- package/dist/types/playwright/index.d.ts +4 -0
- package/dist/types/playwright/index.d.ts.map +1 -0
- package/dist/types/{setup.d.ts → playwright/setup.d.ts} +2 -7
- package/dist/types/playwright/setup.d.ts.map +1 -0
- package/dist/types/playwright/setupClerkTestingToken.d.ts +28 -0
- package/dist/types/playwright/setupClerkTestingToken.d.ts.map +1 -0
- package/dist/types/playwright/unstable/index.d.ts +5 -0
- package/dist/types/playwright/unstable/index.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/apiKeys.d.ts +52 -0
- package/dist/types/playwright/unstable/page-objects/apiKeys.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/app.d.ts +28 -0
- package/dist/types/playwright/unstable/page-objects/app.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/checkout.d.ts +56 -0
- package/dist/types/playwright/unstable/page-objects/checkout.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/clerk.d.ts +12 -0
- package/dist/types/playwright/unstable/page-objects/clerk.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/common.d.ts +29 -0
- package/dist/types/playwright/unstable/page-objects/common.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/expect.d.ts +14 -0
- package/dist/types/playwright/unstable/page-objects/expect.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/impersonation.d.ts +8 -0
- package/dist/types/playwright/unstable/page-objects/impersonation.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/index.d.ts +626 -0
- package/dist/types/playwright/unstable/page-objects/index.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/keylessPopover.d.ts +13 -0
- package/dist/types/playwright/unstable/page-objects/keylessPopover.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/organizationSwitcher.d.ts +43 -0
- package/dist/types/playwright/unstable/page-objects/organizationSwitcher.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/planDetails.d.ts +39 -0
- package/dist/types/playwright/unstable/page-objects/planDetails.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/pricingTable.d.ts +55 -0
- package/dist/types/playwright/unstable/page-objects/pricingTable.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/sessionTask.d.ts +45 -0
- package/dist/types/playwright/unstable/page-objects/sessionTask.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/signIn.d.ts +61 -0
- package/dist/types/playwright/unstable/page-objects/signIn.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/signUp.d.ts +57 -0
- package/dist/types/playwright/unstable/page-objects/signUp.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/subscriptionDetails.d.ts +41 -0
- package/dist/types/playwright/unstable/page-objects/subscriptionDetails.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/testingToken.d.ts +7 -0
- package/dist/types/playwright/unstable/page-objects/testingToken.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/userAvatar.d.ts +11 -0
- package/dist/types/playwright/unstable/page-objects/userAvatar.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/userButton.d.ts +14 -0
- package/dist/types/playwright/unstable/page-objects/userButton.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/userProfile.d.ts +60 -0
- package/dist/types/playwright/unstable/page-objects/userProfile.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/userVerification.d.ts +43 -0
- package/dist/types/playwright/unstable/page-objects/userVerification.d.ts.map +1 -0
- package/dist/types/playwright/unstable/page-objects/waitlist.d.ts +48 -0
- package/dist/types/playwright/unstable/page-objects/waitlist.d.ts.map +1 -0
- package/package.json +52 -23
- package/playwright/package.json +5 -0
- package/dist/esm/index.js +0 -2
- package/dist/esm/index.js.map +0 -1
- package/dist/types/setup.d.ts.map +0 -1
- package/dist/types/setupClerkTestingToken.d.ts +0 -29
- package/dist/types/setupClerkTestingToken.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -5,11 +5,10 @@
|
|
|
5
5
|
<img src="https://images.clerk.com/static/logo-light-mode-400x400.png" height="64">
|
|
6
6
|
</picture>
|
|
7
7
|
</a>
|
|
8
|
-
<br />
|
|
8
|
+
<br />
|
|
9
|
+
<h1 align="center">@clerk/testing</h1>
|
|
9
10
|
</p>
|
|
10
11
|
|
|
11
|
-
# @clerk/testing
|
|
12
|
-
|
|
13
12
|
<div align="center">
|
|
14
13
|
|
|
15
14
|
[](https://clerk.com/discord)
|
|
@@ -22,26 +21,23 @@
|
|
|
22
21
|
·
|
|
23
22
|
[Request a Feature](https://feedback.clerk.com/roadmap)
|
|
24
23
|
·
|
|
25
|
-
[
|
|
24
|
+
[Get help](https://clerk.com/contact/support?utm_source=github&utm_medium=clerk_testing)
|
|
26
25
|
|
|
27
26
|
</div>
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
## Overview
|
|
28
|
+
## Getting started
|
|
32
29
|
|
|
33
30
|
This package provides utilities for testing Clerk applications.
|
|
34
31
|
|
|
35
32
|
It currently supports the following testing frameworks:
|
|
36
33
|
|
|
37
34
|
- [Playwright](https://playwright.dev/), a Node.js library to automate browsers and web pages.
|
|
38
|
-
|
|
39
|
-
## Getting started
|
|
35
|
+
- [Cypress](https://www.cypress.io/), a JavaScript-based end-to-end testing framework.
|
|
40
36
|
|
|
41
37
|
### Prerequisites
|
|
42
38
|
|
|
43
39
|
- Node.js `>=18.17.0` or later
|
|
44
|
-
- Playwright v1+
|
|
40
|
+
- Playwright v1+ or Cypress v13.x or 14.x
|
|
45
41
|
|
|
46
42
|
### Installation
|
|
47
43
|
|
|
@@ -51,47 +47,21 @@ npm install @clerk/testing --save-dev
|
|
|
51
47
|
|
|
52
48
|
## Usage
|
|
53
49
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
On your global setup file for Playwright, you must use the `clerkSetup` function to set up Clerk for your tests.
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
// global-setup.ts
|
|
60
|
-
import { clerkSetup } from '@clerk/testing/playwright';
|
|
61
|
-
import { test as setup } from '@playwright/test';
|
|
50
|
+
Learn how to use `@clerk/testing` with different frameworks:
|
|
62
51
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
...
|
|
66
|
-
});
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Then, you can use the `setupClerkTestingToken` function to bypass bot protection on your tests.
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
// my-test.spec.ts
|
|
73
|
-
import { setupClerkTestingToken } from "@clerk/testing/playwright";
|
|
74
|
-
import { test } from "@playwright/test";
|
|
75
|
-
|
|
76
|
-
test("sign up", async ({ page }) => {
|
|
77
|
-
await setupClerkTestingToken({ page });
|
|
78
|
-
|
|
79
|
-
await page.goto("/sign-up");
|
|
80
|
-
...
|
|
81
|
-
});
|
|
82
|
-
```
|
|
52
|
+
- [Testing with Playwright](https://clerk.com/docs/testing/playwright?utm_source=github&utm_medium=clerk_testing)
|
|
53
|
+
- [Testing with Cypress](https://clerk.com/docs/testing/cypress?utm_source=github&utm_medium=clerk_testing)
|
|
83
54
|
|
|
84
55
|
## Support
|
|
85
56
|
|
|
86
57
|
You can get in touch with us in any of the following ways:
|
|
87
58
|
|
|
88
59
|
- Join our official community [Discord server](https://clerk.com/discord)
|
|
89
|
-
-
|
|
90
|
-
- Contact options listed on [our Support page](https://clerk.com/support?utm_source=github&utm_medium=clerk_testing)
|
|
60
|
+
- On [our support page](https://clerk.com/contact/support?utm_source=github&utm_medium=clerk_testing)
|
|
91
61
|
|
|
92
62
|
## Contributing
|
|
93
63
|
|
|
94
|
-
We're open to all community contributions! If you'd like to contribute in any way, please read [our contribution guidelines](https://github.com/clerk/javascript/blob/main/docs/CONTRIBUTING.md).
|
|
64
|
+
We're open to all community contributions! If you'd like to contribute in any way, please read [our contribution guidelines](https://github.com/clerk/javascript/blob/main/docs/CONTRIBUTING.md) and [code of conduct](https://github.com/clerk/javascript/blob/main/docs/CODE_OF_CONDUCT.md).
|
|
95
65
|
|
|
96
66
|
## Security
|
|
97
67
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import{createClerkClient as l}from"@clerk/backend";import{parsePublishableKey as d}from"@clerk/shared/keys";import p from"dotenv";var k=async s=>{let{debug:c=!1,dotenv:o=!0,...t}=s||{},r=i=>{c&&console.log(`Clerk: ${i}`)};r("Setting up Clerk..."),o&&p.config({path:[".env.local",".env"]});let n=t.publishableKey||process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY||process.env.VITE_CLERK_PUBLISHABLE_KEY||process.env.CLERK_PUBLISHABLE_KEY||process.env.REACT_APP_CLERK_PUBLISHABLE_KEY||process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY,e=t.secretKey||process.env.CLERK_SECRET_KEY,a=process.env.CLERK_TESTING_TOKEN;if(!n)throw new Error("You need to set the CLERK_PUBLISHABLE_KEY environment variable.");if(!e&&!a)throw new Error("You need to set the CLERK_SECRET_KEY or the CLERK_TESTING_TOKEN environment variable.");if(e&&!a){r("Fetching testing token from Clerk Backend API...");try{let i=t?.apiUrl||process.env.CLERK_API_URL;a=(await l({secretKey:e,apiUrl:i}).testingTokens.createTestingToken()).token}catch(i){throw console.error("Failed to fetch testing token from Clerk API."),i}}return{CLERK_FAPI:s?.frontendApiUrl||d(n)?.frontendApi,CLERK_TESTING_TOKEN:a}};var f=async({signInParams:s,windowObject:c})=>{try{let o=c||window;if(!o.Clerk.client)return;let t=o.Clerk.client.signIn;switch(s.strategy){case"password":{let r=await t.create(s);await o.Clerk.setActive({session:r.createdSessionId});break}case"ticket":{let r=await t.create({strategy:"ticket",ticket:s.ticket});if(r.status==="complete")await o.Clerk.setActive({session:r.createdSessionId});else throw new Error(`Sign-in with ticket failed. Status: ${r.status}`);break}case"phone_code":{if(!/^\+1\d{3}55501\d{2}$/.test(s.identifier))throw new Error(`Phone number should be a test phone number.
|
|
2
|
+
|
|
3
|
+
Example: +1XXX55501XX.
|
|
4
|
+
|
|
5
|
+
Learn more here: https://clerk.com/docs/testing/test-emails-and-phones#phone-numbers`);let{supportedFirstFactors:r}=await t.create({identifier:s.identifier}),n=r?.find(e=>e.strategy==="phone_code");if(n){await t.prepareFirstFactor({strategy:"phone_code",phoneNumberId:n.phoneNumberId});let e=await t.attemptFirstFactor({strategy:"phone_code",code:"424242"});if(e.status==="complete")await o.Clerk.setActive({session:e.createdSessionId});else throw new Error(`Status is ${e.status}`)}else throw new Error("phone_code is not enabled.");break}case"email_code":{if(!s.identifier.includes("+clerk_test"))throw new Error(`Email should be a test email.
|
|
6
|
+
|
|
7
|
+
Any email with the +clerk_test subaddress is a test email address.
|
|
8
|
+
|
|
9
|
+
Learn more here: https://clerk.com/docs/testing/test-emails-and-phones#email-addresses`);let{supportedFirstFactors:r}=await t.create({identifier:s.identifier}),n=r?.find(e=>e.strategy==="email_code");if(n){await t.prepareFirstFactor({strategy:"email_code",emailAddressId:n.emailAddressId});let e=await t.attemptFirstFactor({strategy:"email_code",code:"424242"});if(e.status==="complete")await o.Clerk.setActive({session:e.createdSessionId});else throw new Error(`Status is ${e.status}`)}else throw new Error("email_code is not enabled.");break}default:throw new Error(`Unsupported strategy: ${s.strategy}`)}}catch(o){throw new Error(`Clerk: Failed to sign in: ${o?.message}`)}};export{k as a,f as b};
|
|
10
|
+
//# sourceMappingURL=chunk-JDNEQWYI.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/common/setup.ts","../src/common/helpers-utils.ts"],"sourcesContent":["import { createClerkClient } from '@clerk/backend';\nimport { parsePublishableKey } from '@clerk/shared/keys';\nimport dotenv from 'dotenv';\n\nimport type { ClerkSetupOptions, ClerkSetupReturn } from './types';\n\nexport const fetchEnvVars = async (options?: ClerkSetupOptions): Promise<ClerkSetupReturn> => {\n const { debug = false, dotenv: loadDotEnv = true, ...rest } = options || {};\n\n const log = (msg: string) => {\n if (debug) {\n console.log(`Clerk: ${msg}`);\n }\n };\n\n log('Setting up Clerk...');\n\n if (loadDotEnv) {\n dotenv.config({ path: ['.env.local', '.env'] });\n }\n\n const publishableKey =\n rest.publishableKey ||\n process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY ||\n process.env.VITE_CLERK_PUBLISHABLE_KEY ||\n process.env.CLERK_PUBLISHABLE_KEY ||\n process.env.REACT_APP_CLERK_PUBLISHABLE_KEY ||\n process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY;\n\n const secretKey = rest.secretKey || process.env.CLERK_SECRET_KEY;\n let testingToken = process.env.CLERK_TESTING_TOKEN;\n\n if (!publishableKey) {\n throw new Error('You need to set the CLERK_PUBLISHABLE_KEY environment variable.');\n }\n\n if (!secretKey && !testingToken) {\n throw new Error('You need to set the CLERK_SECRET_KEY or the CLERK_TESTING_TOKEN environment variable.');\n }\n\n if (secretKey && !testingToken) {\n log('Fetching testing token from Clerk Backend API...');\n\n try {\n const apiUrl = (rest as any)?.apiUrl || process.env.CLERK_API_URL;\n const clerkClient = createClerkClient({ secretKey, apiUrl });\n const tokenData = await clerkClient.testingTokens.createTestingToken();\n testingToken = tokenData.token;\n } catch (err) {\n console.error('Failed to fetch testing token from Clerk API.');\n throw err;\n }\n }\n\n return {\n CLERK_FAPI: options?.frontendApiUrl || parsePublishableKey(publishableKey)?.frontendApi,\n CLERK_TESTING_TOKEN: testingToken,\n };\n};\n","import type { EmailCodeFactor, PhoneCodeFactor, SignInFirstFactor } from '@clerk/shared/types';\n\nimport type { SignInHelperParams } from './types';\n\n// This function is serialized and executed in the browser context\nexport const signInHelper = async ({ signInParams, windowObject }: SignInHelperParams) => {\n try {\n const w = windowObject || window;\n if (!w.Clerk.client) {\n return;\n }\n\n const signIn = w.Clerk.client.signIn;\n\n switch (signInParams.strategy) {\n case 'password': {\n const res = await signIn.create(signInParams);\n await w.Clerk.setActive({\n session: res.createdSessionId,\n });\n break;\n }\n\n case 'ticket': {\n const res = await signIn.create({\n strategy: 'ticket',\n ticket: signInParams.ticket,\n });\n\n if (res.status === 'complete') {\n await w.Clerk.setActive({\n session: res.createdSessionId,\n });\n } else {\n throw new Error(`Sign-in with ticket failed. Status: ${res.status}`);\n }\n break;\n }\n\n case 'phone_code': {\n // Assert that the identifier is a test phone number\n if (!/^\\+1\\d{3}55501\\d{2}$/.test(signInParams.identifier)) {\n throw new Error(\n `Phone number should be a test phone number.\\n\n Example: +1XXX55501XX.\\n\n Learn more here: https://clerk.com/docs/testing/test-emails-and-phones#phone-numbers`,\n );\n }\n\n // Sign in with phone code\n const { supportedFirstFactors } = await signIn.create({\n identifier: signInParams.identifier,\n });\n const phoneFactor = supportedFirstFactors?.find(\n (factor: SignInFirstFactor): factor is PhoneCodeFactor => factor.strategy === 'phone_code',\n );\n\n if (phoneFactor) {\n await signIn.prepareFirstFactor({\n strategy: 'phone_code',\n phoneNumberId: phoneFactor.phoneNumberId,\n });\n const signInAttempt = await signIn.attemptFirstFactor({\n strategy: 'phone_code',\n code: '424242',\n });\n\n if (signInAttempt.status === 'complete') {\n await w.Clerk.setActive({ session: signInAttempt.createdSessionId });\n } else {\n throw new Error(`Status is ${signInAttempt.status}`);\n }\n } else {\n throw new Error('phone_code is not enabled.');\n }\n break;\n }\n\n case 'email_code': {\n // Assert that the identifier is a test email\n if (!signInParams.identifier.includes('+clerk_test')) {\n throw new Error(\n `Email should be a test email.\\n\n Any email with the +clerk_test subaddress is a test email address.\\n\n Learn more here: https://clerk.com/docs/testing/test-emails-and-phones#email-addresses`,\n );\n }\n\n // Sign in with email code\n const { supportedFirstFactors } = await signIn.create({\n identifier: signInParams.identifier,\n });\n const emailFactor = supportedFirstFactors?.find(\n (factor: SignInFirstFactor): factor is EmailCodeFactor => factor.strategy === 'email_code',\n );\n\n if (emailFactor) {\n await signIn.prepareFirstFactor({\n strategy: 'email_code',\n emailAddressId: emailFactor.emailAddressId,\n });\n const signInAttempt = await signIn.attemptFirstFactor({\n strategy: 'email_code',\n code: '424242',\n });\n\n if (signInAttempt.status === 'complete') {\n await w.Clerk.setActive({ session: signInAttempt.createdSessionId });\n } else {\n throw new Error(`Status is ${signInAttempt.status}`);\n }\n } else {\n throw new Error('email_code is not enabled.');\n }\n break;\n }\n\n default:\n throw new Error(`Unsupported strategy: ${(signInParams as any).strategy}`);\n }\n } catch (err: any) {\n throw new Error(`Clerk: Failed to sign in: ${err?.message}`);\n }\n};\n"],"mappings":"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","names":["createClerkClient","parsePublishableKey","dotenv","fetchEnvVars","options","debug","loadDotEnv","rest","log","msg","publishableKey","secretKey","testingToken","apiUrl","err","signInHelper","signInParams","windowObject","w","signIn","res","supportedFirstFactors","phoneFactor","factor","signInAttempt","emailFactor","err"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e="__clerk_testing_token";var o="The Clerk Frontend API URL is required to bypass bot protection. Make sure the clerkSetup function is called during your global setup before setupClerkTestingToken is called.";export{e as a,o as b};
|
|
2
|
+
//# sourceMappingURL=chunk-M5YIJ3SE.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/common/constants.ts","../src/common/errors.ts"],"sourcesContent":["export const TESTING_TOKEN_PARAM = '__clerk_testing_token';\n","export const ERROR_MISSING_FRONTEND_API_URL =\n 'The Clerk Frontend API URL is required to bypass bot protection. ' +\n 'Make sure the clerkSetup function is called during your global setup before setupClerkTestingToken is called.';\n"],"mappings":"AAAO,IAAMA,EAAsB,wBCA5B,IAAMC,EACX","names":["TESTING_TOKEN_PARAM","ERROR_MISSING_FRONTEND_API_URL"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as p,b as i}from"./chunk-M5YIJ3SE.mjs";var h=async({context:c,options:l,page:T})=>{let o=c??T?.context();if(!o)throw new Error("Either context or page must be provided to setup testing token");let r=l?.frontendApiUrl||process.env.CLERK_FAPI;if(!r)throw new Error(i);let g=r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),f=new RegExp(`^https://${g}/v1/.*?(\\?.*)?$`);await o.route(f,async e=>{let s=new URL(e.request().url()),n=process.env.CLERK_TESTING_TOKEN;n&&s.searchParams.set(p,n);try{let a=await e.fetch({url:s.toString()}),t=await a.json();t?.response?.captcha_bypass===!1&&(t.response.captcha_bypass=!0),t?.client?.captcha_bypass===!1&&(t.client.captcha_bypass=!0),await e.fulfill({response:a,json:t})}catch{await e.continue({url:s.toString()}).catch(console.error)}})};export{h as a};
|
|
2
|
+
//# sourceMappingURL=chunk-YFUXUEZ5.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/playwright/setupClerkTestingToken.ts"],"sourcesContent":["import type { BrowserContext, Page } from '@playwright/test';\n\nimport type { SetupClerkTestingTokenOptions } from '../common';\nimport { ERROR_MISSING_FRONTEND_API_URL, TESTING_TOKEN_PARAM } from '../common';\n\ntype SetupClerkTestingTokenParams = {\n context?: BrowserContext;\n page?: Page;\n options?: SetupClerkTestingTokenOptions;\n};\n\n/**\n * Bypasses bot protection by appending the testing token in the Frontend API requests.\n *\n * @param params.context - The Playwright browser context object.\n * @param params.page - The Playwright page object.\n * @param params.options.frontendApiUrl - The frontend API URL for your Clerk dev instance, without the protocol.\n * @returns A promise that resolves when the bot protection bypass is set up.\n * @throws An error if the Frontend API URL is not provided.\n * @example\n * import { setupClerkTestingToken } from '@clerk/testing/playwright';\n *\n * test('should bypass bot protection', async ({ context }) => {\n * await setupClerkTestingToken({ context });\n * const page = await context.newPage();\n * await page.goto('https://your-app.com');\n * // Continue with your test...\n * });\n */\nexport const setupClerkTestingToken = async ({ context, options, page }: SetupClerkTestingTokenParams) => {\n const browserContext = context ?? page?.context();\n\n if (!browserContext) {\n throw new Error('Either context or page must be provided to setup testing token');\n }\n\n const fapiUrl = options?.frontendApiUrl || process.env.CLERK_FAPI;\n if (!fapiUrl) {\n throw new Error(ERROR_MISSING_FRONTEND_API_URL);\n }\n\n const escapedFapiUrl = fapiUrl.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const apiUrl = new RegExp(`^https://${escapedFapiUrl}/v1/.*?(\\\\?.*)?$`);\n\n await browserContext.route(apiUrl, async route => {\n const originalUrl = new URL(route.request().url());\n const testingToken = process.env.CLERK_TESTING_TOKEN;\n\n if (testingToken) {\n originalUrl.searchParams.set(TESTING_TOKEN_PARAM, testingToken);\n }\n\n try {\n const response = await route.fetch({\n url: originalUrl.toString(),\n });\n\n const json = await response.json();\n\n // Override captcha_bypass in /v1/client\n if (json?.response?.captcha_bypass === false) {\n json.response.captcha_bypass = true;\n }\n\n // Override captcha_bypass in piggybacking\n if (json?.client?.captcha_bypass === false) {\n json.client.captcha_bypass = true;\n }\n\n await route.fulfill({\n response,\n json,\n });\n } catch {\n await route\n .continue({\n url: originalUrl.toString(),\n })\n .catch(console.error);\n }\n });\n};\n"],"mappings":"gDA6BO,IAAMA,EAAyB,MAAO,CAAE,QAAAC,EAAS,QAAAC,EAAS,KAAAC,CAAK,IAAoC,CACxG,IAAMC,EAAiBH,GAAWE,GAAM,QAAQ,EAEhD,GAAI,CAACC,EACH,MAAM,IAAI,MAAM,gEAAgE,EAGlF,IAAMC,EAAUH,GAAS,gBAAkB,QAAQ,IAAI,WACvD,GAAI,CAACG,EACH,MAAM,IAAI,MAAMC,CAA8B,EAGhD,IAAMC,EAAiBF,EAAQ,QAAQ,sBAAuB,MAAM,EAC9DG,EAAS,IAAI,OAAO,YAAYD,CAAc,kBAAkB,EAEtE,MAAMH,EAAe,MAAMI,EAAQ,MAAMC,GAAS,CAChD,IAAMC,EAAc,IAAI,IAAID,EAAM,QAAQ,EAAE,IAAI,CAAC,EAC3CE,EAAe,QAAQ,IAAI,oBAE7BA,GACFD,EAAY,aAAa,IAAIE,EAAqBD,CAAY,EAGhE,GAAI,CACF,IAAME,EAAW,MAAMJ,EAAM,MAAM,CACjC,IAAKC,EAAY,SAAS,CAC5B,CAAC,EAEKI,EAAO,MAAMD,EAAS,KAAK,EAG7BC,GAAM,UAAU,iBAAmB,KACrCA,EAAK,SAAS,eAAiB,IAI7BA,GAAM,QAAQ,iBAAmB,KACnCA,EAAK,OAAO,eAAiB,IAG/B,MAAML,EAAM,QAAQ,CAClB,SAAAI,EACA,KAAAC,CACF,CAAC,CACH,MAAQ,CACN,MAAML,EACH,SAAS,CACR,IAAKC,EAAY,SAAS,CAC5B,CAAC,EACA,MAAM,QAAQ,KAAK,CACxB,CACF,CAAC,CACH","names":["setupClerkTestingToken","context","options","page","browserContext","fapiUrl","ERROR_MISSING_FRONTEND_API_URL","escapedFapiUrl","apiUrl","route","originalUrl","testingToken","TESTING_TOKEN_PARAM","response","json"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";var S=Object.create;var l=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var w=Object.getPrototypeOf,I=Object.prototype.hasOwnProperty;var b=(e,o)=>{for(var r in o)l(e,r,{get:o[r],enumerable:!0})},d=(e,o,r,t)=>{if(o&&typeof o=="object"||typeof o=="function")for(let n of T(o))!I.call(e,n)&&n!==r&&l(e,n,{get:()=>o[n],enumerable:!(t=y(o,n))||t.enumerable});return e};var L=(e,o,r)=>(r=e!=null?S(w(e)):{},d(o||!e||!e.__esModule?l(r,"default",{value:e,enumerable:!0}):r,e)),K=e=>d(l({},"__esModule",{value:!0}),e);var R={};b(R,{addClerkCommands:()=>g,clerkSetup:()=>f,setupClerkTestingToken:()=>p});module.exports=K(R);var C="__clerk_testing_token";var k=require("@clerk/backend"),m=require("@clerk/shared/keys"),u=L(require("dotenv")),E=async e=>{let{debug:o=!1,dotenv:r=!0,...t}=e||{},n=a=>{o&&console.log(`Clerk: ${a}`)};n("Setting up Clerk..."),r&&u.default.config({path:[".env.local",".env"]});let i=t.publishableKey||process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY||process.env.VITE_CLERK_PUBLISHABLE_KEY||process.env.CLERK_PUBLISHABLE_KEY||process.env.REACT_APP_CLERK_PUBLISHABLE_KEY||process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY,s=t.secretKey||process.env.CLERK_SECRET_KEY,c=process.env.CLERK_TESTING_TOKEN;if(!i)throw new Error("You need to set the CLERK_PUBLISHABLE_KEY environment variable.");if(!s&&!c)throw new Error("You need to set the CLERK_SECRET_KEY or the CLERK_TESTING_TOKEN environment variable.");if(s&&!c){n("Fetching testing token from Clerk Backend API...");try{let a=t?.apiUrl||process.env.CLERK_API_URL;c=(await(0,k.createClerkClient)({secretKey:s,apiUrl:a}).testingTokens.createTestingToken()).token}catch(a){throw console.error("Failed to fetch testing token from Clerk API."),a}}return{CLERK_FAPI:e?.frontendApiUrl||(0,m.parsePublishableKey)(i)?.frontendApi,CLERK_TESTING_TOKEN:c}};var h="The Clerk Frontend API URL is required to bypass bot protection. Make sure the clerkSetup function is called during your global setup before setupClerkTestingToken is called.";var _=async({signInParams:e,windowObject:o})=>{try{let r=o||window;if(!r.Clerk.client)return;let t=r.Clerk.client.signIn;switch(e.strategy){case"password":{let n=await t.create(e);await r.Clerk.setActive({session:n.createdSessionId});break}case"ticket":{let n=await t.create({strategy:"ticket",ticket:e.ticket});if(n.status==="complete")await r.Clerk.setActive({session:n.createdSessionId});else throw new Error(`Sign-in with ticket failed. Status: ${n.status}`);break}case"phone_code":{if(!/^\+1\d{3}55501\d{2}$/.test(e.identifier))throw new Error(`Phone number should be a test phone number.
|
|
2
|
+
|
|
3
|
+
Example: +1XXX55501XX.
|
|
4
|
+
|
|
5
|
+
Learn more here: https://clerk.com/docs/testing/test-emails-and-phones#phone-numbers`);let{supportedFirstFactors:n}=await t.create({identifier:e.identifier}),i=n?.find(s=>s.strategy==="phone_code");if(i){await t.prepareFirstFactor({strategy:"phone_code",phoneNumberId:i.phoneNumberId});let s=await t.attemptFirstFactor({strategy:"phone_code",code:"424242"});if(s.status==="complete")await r.Clerk.setActive({session:s.createdSessionId});else throw new Error(`Status is ${s.status}`)}else throw new Error("phone_code is not enabled.");break}case"email_code":{if(!e.identifier.includes("+clerk_test"))throw new Error(`Email should be a test email.
|
|
6
|
+
|
|
7
|
+
Any email with the +clerk_test subaddress is a test email address.
|
|
8
|
+
|
|
9
|
+
Learn more here: https://clerk.com/docs/testing/test-emails-and-phones#email-addresses`);let{supportedFirstFactors:n}=await t.create({identifier:e.identifier}),i=n?.find(s=>s.strategy==="email_code");if(i){await t.prepareFirstFactor({strategy:"email_code",emailAddressId:i.emailAddressId});let s=await t.attemptFirstFactor({strategy:"email_code",code:"424242"});if(s.status==="complete")await r.Clerk.setActive({session:s.createdSessionId});else throw new Error(`Status is ${s.status}`)}else throw new Error("email_code is not enabled.");break}default:throw new Error(`Unsupported strategy: ${e.strategy}`)}}catch(r){throw new Error(`Clerk: Failed to sign in: ${r?.message}`)}};var f=async({config:e,options:o})=>{if(!e)throw new Error("The Cypress config object is required.");let{CLERK_FAPI:r,CLERK_TESTING_TOKEN:t}=await E(o);return e.env.CLERK_FAPI=r,e.env.CLERK_TESTING_TOKEN=t,e};var p=e=>{let o=e?.options?.frontendApiUrl||Cypress.env("CLERK_FAPI");if(!o)throw new Error(h);let r=`https://${o}/v1/**`;cy.intercept(r,t=>{let n=Cypress.env("CLERK_TESTING_TOKEN");n&&(t.query[C]=n),t.continue(),t.on("response",i=>{i.body?.response?.captcha_bypass===!1&&(i.body.response.captcha_bypass=!0),i.body?.client?.captcha_bypass===!1&&(i.body.client.captcha_bypass=!0)})})};var g=({Cypress:e,cy:o})=>{e.Commands.add("clerkSignIn",r=>{p(),o.log("Clerk: Signing in..."),o.window().should(t=>{expect(t).to.not.have.property("Clerk",void 0),expect(t.Clerk.loaded).to.eq(!0)}).then(async t=>{await _({windowObject:t,signInParams:r}),o.log("Clerk: Finished signing in.")})}),e.Commands.add("clerkSignOut",r=>{o.log("Clerk: Signing out..."),o.window().should(t=>{expect(t).to.not.have.property("Clerk",void 0),expect(t.Clerk.loaded).to.eq(!0)}).then(async t=>{await t.Clerk.signOut(r),o.log("Clerk: Finished signing out.")})}),e.Commands.add("clerkLoaded",()=>{o.window().should(r=>{expect(r).to.not.have.property("Clerk",void 0),expect(r.Clerk.loaded).to.eq(!0)})})};0&&(module.exports={addClerkCommands,clerkSetup,setupClerkTestingToken});
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cypress/index.ts","../../src/common/constants.ts","../../src/common/setup.ts","../../src/common/errors.ts","../../src/common/helpers-utils.ts","../../src/cypress/setup.ts","../../src/cypress/setupClerkTestingToken.ts","../../src/cypress/custom-commands.ts"],"sourcesContent":["export { clerkSetup } from './setup';\nexport { setupClerkTestingToken } from './setupClerkTestingToken';\nexport { addClerkCommands } from './custom-commands';\n","export const TESTING_TOKEN_PARAM = '__clerk_testing_token';\n","import { createClerkClient } from '@clerk/backend';\nimport { parsePublishableKey } from '@clerk/shared/keys';\nimport dotenv from 'dotenv';\n\nimport type { ClerkSetupOptions, ClerkSetupReturn } from './types';\n\nexport const fetchEnvVars = async (options?: ClerkSetupOptions): Promise<ClerkSetupReturn> => {\n const { debug = false, dotenv: loadDotEnv = true, ...rest } = options || {};\n\n const log = (msg: string) => {\n if (debug) {\n console.log(`Clerk: ${msg}`);\n }\n };\n\n log('Setting up Clerk...');\n\n if (loadDotEnv) {\n dotenv.config({ path: ['.env.local', '.env'] });\n }\n\n const publishableKey =\n rest.publishableKey ||\n process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY ||\n process.env.VITE_CLERK_PUBLISHABLE_KEY ||\n process.env.CLERK_PUBLISHABLE_KEY ||\n process.env.REACT_APP_CLERK_PUBLISHABLE_KEY ||\n process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY;\n\n const secretKey = rest.secretKey || process.env.CLERK_SECRET_KEY;\n let testingToken = process.env.CLERK_TESTING_TOKEN;\n\n if (!publishableKey) {\n throw new Error('You need to set the CLERK_PUBLISHABLE_KEY environment variable.');\n }\n\n if (!secretKey && !testingToken) {\n throw new Error('You need to set the CLERK_SECRET_KEY or the CLERK_TESTING_TOKEN environment variable.');\n }\n\n if (secretKey && !testingToken) {\n log('Fetching testing token from Clerk Backend API...');\n\n try {\n const apiUrl = (rest as any)?.apiUrl || process.env.CLERK_API_URL;\n const clerkClient = createClerkClient({ secretKey, apiUrl });\n const tokenData = await clerkClient.testingTokens.createTestingToken();\n testingToken = tokenData.token;\n } catch (err) {\n console.error('Failed to fetch testing token from Clerk API.');\n throw err;\n }\n }\n\n return {\n CLERK_FAPI: options?.frontendApiUrl || parsePublishableKey(publishableKey)?.frontendApi,\n CLERK_TESTING_TOKEN: testingToken,\n };\n};\n","export const ERROR_MISSING_FRONTEND_API_URL =\n 'The Clerk Frontend API URL is required to bypass bot protection. ' +\n 'Make sure the clerkSetup function is called during your global setup before setupClerkTestingToken is called.';\n","import type { EmailCodeFactor, PhoneCodeFactor, SignInFirstFactor } from '@clerk/shared/types';\n\nimport type { SignInHelperParams } from './types';\n\n// This function is serialized and executed in the browser context\nexport const signInHelper = async ({ signInParams, windowObject }: SignInHelperParams) => {\n try {\n const w = windowObject || window;\n if (!w.Clerk.client) {\n return;\n }\n\n const signIn = w.Clerk.client.signIn;\n\n switch (signInParams.strategy) {\n case 'password': {\n const res = await signIn.create(signInParams);\n await w.Clerk.setActive({\n session: res.createdSessionId,\n });\n break;\n }\n\n case 'ticket': {\n const res = await signIn.create({\n strategy: 'ticket',\n ticket: signInParams.ticket,\n });\n\n if (res.status === 'complete') {\n await w.Clerk.setActive({\n session: res.createdSessionId,\n });\n } else {\n throw new Error(`Sign-in with ticket failed. Status: ${res.status}`);\n }\n break;\n }\n\n case 'phone_code': {\n // Assert that the identifier is a test phone number\n if (!/^\\+1\\d{3}55501\\d{2}$/.test(signInParams.identifier)) {\n throw new Error(\n `Phone number should be a test phone number.\\n\n Example: +1XXX55501XX.\\n\n Learn more here: https://clerk.com/docs/testing/test-emails-and-phones#phone-numbers`,\n );\n }\n\n // Sign in with phone code\n const { supportedFirstFactors } = await signIn.create({\n identifier: signInParams.identifier,\n });\n const phoneFactor = supportedFirstFactors?.find(\n (factor: SignInFirstFactor): factor is PhoneCodeFactor => factor.strategy === 'phone_code',\n );\n\n if (phoneFactor) {\n await signIn.prepareFirstFactor({\n strategy: 'phone_code',\n phoneNumberId: phoneFactor.phoneNumberId,\n });\n const signInAttempt = await signIn.attemptFirstFactor({\n strategy: 'phone_code',\n code: '424242',\n });\n\n if (signInAttempt.status === 'complete') {\n await w.Clerk.setActive({ session: signInAttempt.createdSessionId });\n } else {\n throw new Error(`Status is ${signInAttempt.status}`);\n }\n } else {\n throw new Error('phone_code is not enabled.');\n }\n break;\n }\n\n case 'email_code': {\n // Assert that the identifier is a test email\n if (!signInParams.identifier.includes('+clerk_test')) {\n throw new Error(\n `Email should be a test email.\\n\n Any email with the +clerk_test subaddress is a test email address.\\n\n Learn more here: https://clerk.com/docs/testing/test-emails-and-phones#email-addresses`,\n );\n }\n\n // Sign in with email code\n const { supportedFirstFactors } = await signIn.create({\n identifier: signInParams.identifier,\n });\n const emailFactor = supportedFirstFactors?.find(\n (factor: SignInFirstFactor): factor is EmailCodeFactor => factor.strategy === 'email_code',\n );\n\n if (emailFactor) {\n await signIn.prepareFirstFactor({\n strategy: 'email_code',\n emailAddressId: emailFactor.emailAddressId,\n });\n const signInAttempt = await signIn.attemptFirstFactor({\n strategy: 'email_code',\n code: '424242',\n });\n\n if (signInAttempt.status === 'complete') {\n await w.Clerk.setActive({ session: signInAttempt.createdSessionId });\n } else {\n throw new Error(`Status is ${signInAttempt.status}`);\n }\n } else {\n throw new Error('email_code is not enabled.');\n }\n break;\n }\n\n default:\n throw new Error(`Unsupported strategy: ${(signInParams as any).strategy}`);\n }\n } catch (err: any) {\n throw new Error(`Clerk: Failed to sign in: ${err?.message}`);\n }\n};\n","/// <reference types=\"cypress\" />\nimport type { ClerkSetupOptions } from '../common';\nimport { fetchEnvVars } from '../common';\n\ntype ClerkSetupParams = {\n config: Cypress.PluginConfigOptions;\n options?: ClerkSetupOptions;\n};\n\n/**\n * Sets up Clerk for testing by fetching the testing token from the Clerk Backend API.\n *\n * @param config - The Cypress config object.\n * @param options - The Clerk setup options.\n * @param options.publishableKey - The publishable key for your Clerk dev instance.\n * @param options.frontendApiUrl - The frontend API URL for your Clerk dev instance, without the protocol. It overrides the Frontend API URL parsed from the publishable key.\n * @param options.debug - Enable debug logs.\n * @returns The Cypress config object with the Clerk environment variables set.\n *\n * @throws An error if the publishable key or the secret key is not provided.\n * @throws An error if the secret key is from a production instance.\n * @throws An error if the testing token cannot be fetched from the Clerk Backend API.\n * @throws An error if the Cypress config object is not provided.\n */\nexport const clerkSetup = async ({ config, options }: ClerkSetupParams) => {\n if (!config) {\n throw new Error('The Cypress config object is required.');\n }\n const { CLERK_FAPI, CLERK_TESTING_TOKEN } = await fetchEnvVars(options);\n config.env.CLERK_FAPI = CLERK_FAPI;\n config.env.CLERK_TESTING_TOKEN = CLERK_TESTING_TOKEN;\n return config;\n};\n","/// <reference types=\"cypress\" />\nimport type { SetupClerkTestingTokenOptions } from '../common';\nimport { ERROR_MISSING_FRONTEND_API_URL, TESTING_TOKEN_PARAM } from '../common';\n\ntype SetupClerkTestingTokenParams = {\n options?: SetupClerkTestingTokenOptions;\n};\n\n/**\n * Bypasses bot protection by appending the testing token in the Frontend API requests.\n *\n * @param params.options.frontendApiUrl - The frontend API URL for your Clerk dev instance, without the protocol.\n * @returns A promise that resolves when the bot protection bypass is set up.\n * @throws An error if the Frontend API URL is not provided.\n * @example\n * import { setupClerkTestingToken } from '@clerk/testing/cypress';\n *\n * it(\"sign up\", () => {\n * setupClerkTestingToken();\n * cy.visit(\"http://localhost:3000\");\n * // Continue with your test...\n * });\n */\nexport const setupClerkTestingToken = (params?: SetupClerkTestingTokenParams) => {\n const fapiUrl = params?.options?.frontendApiUrl || Cypress.env('CLERK_FAPI');\n if (!fapiUrl) {\n throw new Error(ERROR_MISSING_FRONTEND_API_URL);\n }\n const apiUrl = `https://${fapiUrl}/v1/**`;\n\n cy.intercept(apiUrl, req => {\n const testingToken = Cypress.env('CLERK_TESTING_TOKEN');\n if (testingToken) {\n req.query[TESTING_TOKEN_PARAM] = testingToken;\n }\n\n req.continue();\n\n req.on('response', res => {\n // Override captcha_bypass in /v1/client\n if (res.body?.response?.captcha_bypass === false) {\n res.body.response.captcha_bypass = true;\n }\n\n // Override captcha_bypass in piggybacking\n if (res.body?.client?.captcha_bypass === false) {\n res.body.client.captcha_bypass = true;\n }\n });\n });\n};\n","/// <reference types=\"cypress\" />\nimport type { Clerk, SignOutOptions } from '@clerk/shared/types';\n\nimport type { ClerkSignInParams } from '../common';\nimport { signInHelper } from '../common';\nimport { setupClerkTestingToken } from './setupClerkTestingToken';\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Cypress {\n interface Chainable {\n /**\n * Signs in a user using Clerk. This custom command supports only password, phone_code and email_code first factor strategies.\n * Multi-factor is not supported.\n * This helper is using the `setupClerkTestingToken` internally.\n * It is required to call `cy.visit` before calling this command, and navigate to a not protected page that loads Clerk.\n *\n * If the strategy is password, the command will sign in the user using the provided password and identifier.\n * If the strategy is phone_code, you are required to have a user with a test phone number as an identifier (e.g. +15555550100).\n * If the strategy is email_code, you are required to have a user with a test email as an identifier (e.g. your_email+clerk_test@example.com).\n *\n * @param signInParams - The sign in parameters.\n * @param signInParams.strategy - The sign in strategy. Supported strategies are 'password', 'phone_code' and 'email_code'.\n * @param signInParams.identifier - The user's identifier. Could be a username, a phone number or an email.\n * @param signInParams.password - The user's password. Required only if the strategy is 'password'.\n *\n * @example\n * it(\"sign in\", () => {\n * cy.visit(`/`);\n * cy.clerkSignIn({ strategy: 'phone_code', identifier: '+15555550100' });\n * cy.visit('/protected');\n * });\n */\n clerkSignIn(signInParams: ClerkSignInParams): Chainable<void>;\n\n /**\n * Signs out the current user using Clerk.\n * It is required to call `cy.visit` before calling this command, and navigate to a page that loads Clerk.\n * @param signOutOptions - A SignOutOptions object.\n *\n * @example\n * it(\"sign out\", () => {\n * cy.visit(`/`);\n * cy.clerkSignIn({ strategy: 'phone_code', identifier: '+15555550100' });\n * cy.visit('/protected');\n * cy.clerkSignOut();\n * });\n */\n clerkSignOut(signOutOptions?: SignOutOptions): Chainable<void>;\n\n /**\n * Asserts that Clerk has been loaded.\n * It is required to call `cy.visit` before calling this command, and navigate to a page that loads Clerk.\n */\n clerkLoaded(): Chainable<void>;\n }\n }\n interface Window {\n Clerk: Clerk;\n }\n}\n\ntype AddClerkCommandsParams = {\n Cypress: typeof Cypress;\n cy: Cypress.Chainable;\n};\n\nexport const addClerkCommands = ({ Cypress, cy }: AddClerkCommandsParams) => {\n Cypress.Commands.add(`clerkSignIn`, signInParams => {\n setupClerkTestingToken();\n cy.log(`Clerk: Signing in...`);\n\n cy.window()\n .should(window => {\n expect(window).to.not.have.property(`Clerk`, undefined);\n expect(window.Clerk.loaded).to.eq(true);\n })\n .then(async window => {\n await signInHelper({ windowObject: window, signInParams });\n cy.log(`Clerk: Finished signing in.`);\n });\n });\n\n Cypress.Commands.add(`clerkSignOut`, signOutOptions => {\n cy.log(`Clerk: Signing out...`);\n\n cy.window()\n .should(window => {\n expect(window).to.not.have.property(`Clerk`, undefined);\n expect(window.Clerk.loaded).to.eq(true);\n })\n .then(async window => {\n await window.Clerk.signOut(signOutOptions);\n cy.log(`Clerk: Finished signing out.`);\n });\n });\n\n Cypress.Commands.add(`clerkLoaded`, () => {\n cy.window().should(window => {\n expect(window).to.not.have.property(`Clerk`, undefined);\n expect(window.Clerk.loaded).to.eq(true);\n });\n });\n};\n"],"mappings":"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","names":["cypress_exports","__export","addClerkCommands","clerkSetup","setupClerkTestingToken","__toCommonJS","TESTING_TOKEN_PARAM","import_backend","import_keys","import_dotenv","fetchEnvVars","options","debug","loadDotEnv","rest","log","msg","dotenv","publishableKey","secretKey","testingToken","apiUrl","err","ERROR_MISSING_FRONTEND_API_URL","signInHelper","signInParams","windowObject","w","signIn","res","supportedFirstFactors","phoneFactor","factor","signInAttempt","emailFactor","err","clerkSetup","config","options","CLERK_FAPI","CLERK_TESTING_TOKEN","fetchEnvVars","setupClerkTestingToken","params","fapiUrl","ERROR_MISSING_FRONTEND_API_URL","apiUrl","req","testingToken","TESTING_TOKEN_PARAM","res","addClerkCommands","Cypress","cy","signInParams","setupClerkTestingToken","window","signInHelper","signOutOptions"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a,b as C}from"../chunk-JDNEQWYI.mjs";import{a as p,b as l}from"../chunk-M5YIJ3SE.mjs";var d=async({config:n,options:t})=>{if(!n)throw new Error("The Cypress config object is required.");let{CLERK_FAPI:o,CLERK_TESTING_TOKEN:e}=await a(t);return n.env.CLERK_FAPI=o,n.env.CLERK_TESTING_TOKEN=e,n};var s=n=>{let t=n?.options?.frontendApiUrl||Cypress.env("CLERK_FAPI");if(!t)throw new Error(l);let o=`https://${t}/v1/**`;cy.intercept(o,e=>{let i=Cypress.env("CLERK_TESTING_TOKEN");i&&(e.query[p]=i),e.continue(),e.on("response",r=>{r.body?.response?.captcha_bypass===!1&&(r.body.response.captcha_bypass=!0),r.body?.client?.captcha_bypass===!1&&(r.body.client.captcha_bypass=!0)})})};var m=({Cypress:n,cy:t})=>{n.Commands.add("clerkSignIn",o=>{s(),t.log("Clerk: Signing in..."),t.window().should(e=>{expect(e).to.not.have.property("Clerk",void 0),expect(e.Clerk.loaded).to.eq(!0)}).then(async e=>{await C({windowObject:e,signInParams:o}),t.log("Clerk: Finished signing in.")})}),n.Commands.add("clerkSignOut",o=>{t.log("Clerk: Signing out..."),t.window().should(e=>{expect(e).to.not.have.property("Clerk",void 0),expect(e.Clerk.loaded).to.eq(!0)}).then(async e=>{await e.Clerk.signOut(o),t.log("Clerk: Finished signing out.")})}),n.Commands.add("clerkLoaded",()=>{t.window().should(o=>{expect(o).to.not.have.property("Clerk",void 0),expect(o.Clerk.loaded).to.eq(!0)})})};export{m as addClerkCommands,d as clerkSetup,s as setupClerkTestingToken};
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cypress/setup.ts","../../src/cypress/setupClerkTestingToken.ts","../../src/cypress/custom-commands.ts"],"sourcesContent":["/// <reference types=\"cypress\" />\nimport type { ClerkSetupOptions } from '../common';\nimport { fetchEnvVars } from '../common';\n\ntype ClerkSetupParams = {\n config: Cypress.PluginConfigOptions;\n options?: ClerkSetupOptions;\n};\n\n/**\n * Sets up Clerk for testing by fetching the testing token from the Clerk Backend API.\n *\n * @param config - The Cypress config object.\n * @param options - The Clerk setup options.\n * @param options.publishableKey - The publishable key for your Clerk dev instance.\n * @param options.frontendApiUrl - The frontend API URL for your Clerk dev instance, without the protocol. It overrides the Frontend API URL parsed from the publishable key.\n * @param options.debug - Enable debug logs.\n * @returns The Cypress config object with the Clerk environment variables set.\n *\n * @throws An error if the publishable key or the secret key is not provided.\n * @throws An error if the secret key is from a production instance.\n * @throws An error if the testing token cannot be fetched from the Clerk Backend API.\n * @throws An error if the Cypress config object is not provided.\n */\nexport const clerkSetup = async ({ config, options }: ClerkSetupParams) => {\n if (!config) {\n throw new Error('The Cypress config object is required.');\n }\n const { CLERK_FAPI, CLERK_TESTING_TOKEN } = await fetchEnvVars(options);\n config.env.CLERK_FAPI = CLERK_FAPI;\n config.env.CLERK_TESTING_TOKEN = CLERK_TESTING_TOKEN;\n return config;\n};\n","/// <reference types=\"cypress\" />\nimport type { SetupClerkTestingTokenOptions } from '../common';\nimport { ERROR_MISSING_FRONTEND_API_URL, TESTING_TOKEN_PARAM } from '../common';\n\ntype SetupClerkTestingTokenParams = {\n options?: SetupClerkTestingTokenOptions;\n};\n\n/**\n * Bypasses bot protection by appending the testing token in the Frontend API requests.\n *\n * @param params.options.frontendApiUrl - The frontend API URL for your Clerk dev instance, without the protocol.\n * @returns A promise that resolves when the bot protection bypass is set up.\n * @throws An error if the Frontend API URL is not provided.\n * @example\n * import { setupClerkTestingToken } from '@clerk/testing/cypress';\n *\n * it(\"sign up\", () => {\n * setupClerkTestingToken();\n * cy.visit(\"http://localhost:3000\");\n * // Continue with your test...\n * });\n */\nexport const setupClerkTestingToken = (params?: SetupClerkTestingTokenParams) => {\n const fapiUrl = params?.options?.frontendApiUrl || Cypress.env('CLERK_FAPI');\n if (!fapiUrl) {\n throw new Error(ERROR_MISSING_FRONTEND_API_URL);\n }\n const apiUrl = `https://${fapiUrl}/v1/**`;\n\n cy.intercept(apiUrl, req => {\n const testingToken = Cypress.env('CLERK_TESTING_TOKEN');\n if (testingToken) {\n req.query[TESTING_TOKEN_PARAM] = testingToken;\n }\n\n req.continue();\n\n req.on('response', res => {\n // Override captcha_bypass in /v1/client\n if (res.body?.response?.captcha_bypass === false) {\n res.body.response.captcha_bypass = true;\n }\n\n // Override captcha_bypass in piggybacking\n if (res.body?.client?.captcha_bypass === false) {\n res.body.client.captcha_bypass = true;\n }\n });\n });\n};\n","/// <reference types=\"cypress\" />\nimport type { Clerk, SignOutOptions } from '@clerk/shared/types';\n\nimport type { ClerkSignInParams } from '../common';\nimport { signInHelper } from '../common';\nimport { setupClerkTestingToken } from './setupClerkTestingToken';\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Cypress {\n interface Chainable {\n /**\n * Signs in a user using Clerk. This custom command supports only password, phone_code and email_code first factor strategies.\n * Multi-factor is not supported.\n * This helper is using the `setupClerkTestingToken` internally.\n * It is required to call `cy.visit` before calling this command, and navigate to a not protected page that loads Clerk.\n *\n * If the strategy is password, the command will sign in the user using the provided password and identifier.\n * If the strategy is phone_code, you are required to have a user with a test phone number as an identifier (e.g. +15555550100).\n * If the strategy is email_code, you are required to have a user with a test email as an identifier (e.g. your_email+clerk_test@example.com).\n *\n * @param signInParams - The sign in parameters.\n * @param signInParams.strategy - The sign in strategy. Supported strategies are 'password', 'phone_code' and 'email_code'.\n * @param signInParams.identifier - The user's identifier. Could be a username, a phone number or an email.\n * @param signInParams.password - The user's password. Required only if the strategy is 'password'.\n *\n * @example\n * it(\"sign in\", () => {\n * cy.visit(`/`);\n * cy.clerkSignIn({ strategy: 'phone_code', identifier: '+15555550100' });\n * cy.visit('/protected');\n * });\n */\n clerkSignIn(signInParams: ClerkSignInParams): Chainable<void>;\n\n /**\n * Signs out the current user using Clerk.\n * It is required to call `cy.visit` before calling this command, and navigate to a page that loads Clerk.\n * @param signOutOptions - A SignOutOptions object.\n *\n * @example\n * it(\"sign out\", () => {\n * cy.visit(`/`);\n * cy.clerkSignIn({ strategy: 'phone_code', identifier: '+15555550100' });\n * cy.visit('/protected');\n * cy.clerkSignOut();\n * });\n */\n clerkSignOut(signOutOptions?: SignOutOptions): Chainable<void>;\n\n /**\n * Asserts that Clerk has been loaded.\n * It is required to call `cy.visit` before calling this command, and navigate to a page that loads Clerk.\n */\n clerkLoaded(): Chainable<void>;\n }\n }\n interface Window {\n Clerk: Clerk;\n }\n}\n\ntype AddClerkCommandsParams = {\n Cypress: typeof Cypress;\n cy: Cypress.Chainable;\n};\n\nexport const addClerkCommands = ({ Cypress, cy }: AddClerkCommandsParams) => {\n Cypress.Commands.add(`clerkSignIn`, signInParams => {\n setupClerkTestingToken();\n cy.log(`Clerk: Signing in...`);\n\n cy.window()\n .should(window => {\n expect(window).to.not.have.property(`Clerk`, undefined);\n expect(window.Clerk.loaded).to.eq(true);\n })\n .then(async window => {\n await signInHelper({ windowObject: window, signInParams });\n cy.log(`Clerk: Finished signing in.`);\n });\n });\n\n Cypress.Commands.add(`clerkSignOut`, signOutOptions => {\n cy.log(`Clerk: Signing out...`);\n\n cy.window()\n .should(window => {\n expect(window).to.not.have.property(`Clerk`, undefined);\n expect(window.Clerk.loaded).to.eq(true);\n })\n .then(async window => {\n await window.Clerk.signOut(signOutOptions);\n cy.log(`Clerk: Finished signing out.`);\n });\n });\n\n Cypress.Commands.add(`clerkLoaded`, () => {\n cy.window().should(window => {\n expect(window).to.not.have.property(`Clerk`, undefined);\n expect(window.Clerk.loaded).to.eq(true);\n });\n });\n};\n"],"mappings":"6FAwBO,IAAMA,EAAa,MAAO,CAAE,OAAAC,EAAQ,QAAAC,CAAQ,IAAwB,CACzE,GAAI,CAACD,EACH,MAAM,IAAI,MAAM,wCAAwC,EAE1D,GAAM,CAAE,WAAAE,EAAY,oBAAAC,CAAoB,EAAI,MAAMC,EAAaH,CAAO,EACtE,OAAAD,EAAO,IAAI,WAAaE,EACxBF,EAAO,IAAI,oBAAsBG,EAC1BH,CACT,ECTO,IAAMK,EAA0BC,GAA0C,CAC/E,IAAMC,EAAUD,GAAQ,SAAS,gBAAkB,QAAQ,IAAI,YAAY,EAC3E,GAAI,CAACC,EACH,MAAM,IAAI,MAAMC,CAA8B,EAEhD,IAAMC,EAAS,WAAWF,CAAO,SAEjC,GAAG,UAAUE,EAAQC,GAAO,CAC1B,IAAMC,EAAe,QAAQ,IAAI,qBAAqB,EAClDA,IACFD,EAAI,MAAME,CAAmB,EAAID,GAGnCD,EAAI,SAAS,EAEbA,EAAI,GAAG,WAAYG,GAAO,CAEpBA,EAAI,MAAM,UAAU,iBAAmB,KACzCA,EAAI,KAAK,SAAS,eAAiB,IAIjCA,EAAI,MAAM,QAAQ,iBAAmB,KACvCA,EAAI,KAAK,OAAO,eAAiB,GAErC,CAAC,CACH,CAAC,CACH,ECiBO,IAAMC,EAAmB,CAAC,CAAE,QAAAC,EAAS,GAAAC,CAAG,IAA8B,CAC3ED,EAAQ,SAAS,IAAI,cAAeE,GAAgB,CAClDC,EAAuB,EACvBF,EAAG,IAAI,sBAAsB,EAE7BA,EAAG,OAAO,EACP,OAAOG,GAAU,CAChB,OAAOA,CAAM,EAAE,GAAG,IAAI,KAAK,SAAS,QAAS,MAAS,EACtD,OAAOA,EAAO,MAAM,MAAM,EAAE,GAAG,GAAG,EAAI,CACxC,CAAC,EACA,KAAK,MAAMA,GAAU,CACpB,MAAMC,EAAa,CAAE,aAAcD,EAAQ,aAAAF,CAAa,CAAC,EACzDD,EAAG,IAAI,6BAA6B,CACtC,CAAC,CACL,CAAC,EAEDD,EAAQ,SAAS,IAAI,eAAgBM,GAAkB,CACrDL,EAAG,IAAI,uBAAuB,EAE9BA,EAAG,OAAO,EACP,OAAOG,GAAU,CAChB,OAAOA,CAAM,EAAE,GAAG,IAAI,KAAK,SAAS,QAAS,MAAS,EACtD,OAAOA,EAAO,MAAM,MAAM,EAAE,GAAG,GAAG,EAAI,CACxC,CAAC,EACA,KAAK,MAAMA,GAAU,CACpB,MAAMA,EAAO,MAAM,QAAQE,CAAc,EACzCL,EAAG,IAAI,8BAA8B,CACvC,CAAC,CACL,CAAC,EAEDD,EAAQ,SAAS,IAAI,cAAe,IAAM,CACxCC,EAAG,OAAO,EAAE,OAAOG,GAAU,CAC3B,OAAOA,CAAM,EAAE,GAAG,IAAI,KAAK,SAAS,QAAS,MAAS,EACtD,OAAOA,EAAO,MAAM,MAAM,EAAE,GAAG,GAAG,EAAI,CACxC,CAAC,CACH,CAAC,CACH","names":["clerkSetup","config","options","CLERK_FAPI","CLERK_TESTING_TOKEN","fetchEnvVars","setupClerkTestingToken","params","fapiUrl","ERROR_MISSING_FRONTEND_API_URL","apiUrl","req","testingToken","TESTING_TOKEN_PARAM","res","addClerkCommands","Cypress","cy","signInParams","setupClerkTestingToken","window","signInHelper","signOutOptions"]}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";throw new Error(`No exports are available from the top-level "@clerk/testing" package.
|
|
2
|
+
Use specific subpath imports instead, e.g. "@clerk/testing/playwright" or "@clerk/testing/cypress".
|
|
3
|
+
|
|
4
|
+
Find all available exports in the documentation:
|
|
5
|
+
https://clerk.com/docs/testing/overview`);
|
|
2
6
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["throw new Error(`No exports are available from the top-level \"@clerk/testing\" package.\nUse specific subpath imports instead, e.g. \"@clerk/testing/playwright\" or \"@clerk/testing/cypress\".\n\nFind all available exports in the documentation:\nhttps://clerk.com/docs/testing/overview`);\n"],"mappings":"aAAA,MAAM,IAAI,MAAM;AAAA;AAAA;AAAA;AAAA,wCAIwB","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
throw new Error(`No exports are available from the top-level "@clerk/testing" package.
|
|
2
|
+
Use specific subpath imports instead, e.g. "@clerk/testing/playwright" or "@clerk/testing/cypress".
|
|
3
|
+
|
|
4
|
+
Find all available exports in the documentation:
|
|
5
|
+
https://clerk.com/docs/testing/overview`);
|
|
6
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["throw new Error(`No exports are available from the top-level \"@clerk/testing\" package.\nUse specific subpath imports instead, e.g. \"@clerk/testing/playwright\" or \"@clerk/testing/cypress\".\n\nFind all available exports in the documentation:\nhttps://clerk.com/docs/testing/overview`);\n"],"mappings":"AAAA,MAAM,IAAI,MAAM;AAAA;AAAA;AAAA;AAAA,wCAIwB","names":[]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";var I=Object.create;var p=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var K=Object.getOwnPropertyNames;var R=Object.getPrototypeOf,F=Object.prototype.hasOwnProperty;var v=(e,r)=>{for(var t in r)p(e,t,{get:r[t],enumerable:!0})},u=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of K(r))!F.call(e,s)&&s!==t&&p(e,s,{get:()=>r[s],enumerable:!(n=L(r,s))||n.enumerable});return e};var A=(e,r,t)=>(t=e!=null?I(R(e)):{},u(r||!e||!e.__esModule?p(t,"default",{value:e,enumerable:!0}):t,e)),O=e=>u(p({},"__esModule",{value:!0}),e);var U={};v(U,{clerk:()=>S,clerkSetup:()=>T,setupClerkTestingToken:()=>d});module.exports=O(U);var C="__clerk_testing_token";var E=require("@clerk/backend"),h=require("@clerk/shared/keys"),f=A(require("dotenv")),_=async e=>{let{debug:r=!1,dotenv:t=!0,...n}=e||{},s=l=>{r&&console.log(`Clerk: ${l}`)};s("Setting up Clerk..."),t&&f.default.config({path:[".env.local",".env"]});let i=n.publishableKey||process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY||process.env.VITE_CLERK_PUBLISHABLE_KEY||process.env.CLERK_PUBLISHABLE_KEY||process.env.REACT_APP_CLERK_PUBLISHABLE_KEY||process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY,o=n.secretKey||process.env.CLERK_SECRET_KEY,a=process.env.CLERK_TESTING_TOKEN;if(!i)throw new Error("You need to set the CLERK_PUBLISHABLE_KEY environment variable.");if(!o&&!a)throw new Error("You need to set the CLERK_SECRET_KEY or the CLERK_TESTING_TOKEN environment variable.");if(o&&!a){s("Fetching testing token from Clerk Backend API...");try{let l=n?.apiUrl||process.env.CLERK_API_URL;a=(await(0,E.createClerkClient)({secretKey:o,apiUrl:l}).testingTokens.createTestingToken()).token}catch(l){throw console.error("Failed to fetch testing token from Clerk API."),l}}return{CLERK_FAPI:e?.frontendApiUrl||(0,h.parsePublishableKey)(i)?.frontendApi,CLERK_TESTING_TOKEN:a}};var y="The Clerk Frontend API URL is required to bypass bot protection. Make sure the clerkSetup function is called during your global setup before setupClerkTestingToken is called.";var m=async({signInParams:e,windowObject:r})=>{try{let t=r||window;if(!t.Clerk.client)return;let n=t.Clerk.client.signIn;switch(e.strategy){case"password":{let s=await n.create(e);await t.Clerk.setActive({session:s.createdSessionId});break}case"ticket":{let s=await n.create({strategy:"ticket",ticket:e.ticket});if(s.status==="complete")await t.Clerk.setActive({session:s.createdSessionId});else throw new Error(`Sign-in with ticket failed. Status: ${s.status}`);break}case"phone_code":{if(!/^\+1\d{3}55501\d{2}$/.test(e.identifier))throw new Error(`Phone number should be a test phone number.
|
|
2
|
+
|
|
3
|
+
Example: +1XXX55501XX.
|
|
4
|
+
|
|
5
|
+
Learn more here: https://clerk.com/docs/testing/test-emails-and-phones#phone-numbers`);let{supportedFirstFactors:s}=await n.create({identifier:e.identifier}),i=s?.find(o=>o.strategy==="phone_code");if(i){await n.prepareFirstFactor({strategy:"phone_code",phoneNumberId:i.phoneNumberId});let o=await n.attemptFirstFactor({strategy:"phone_code",code:"424242"});if(o.status==="complete")await t.Clerk.setActive({session:o.createdSessionId});else throw new Error(`Status is ${o.status}`)}else throw new Error("phone_code is not enabled.");break}case"email_code":{if(!e.identifier.includes("+clerk_test"))throw new Error(`Email should be a test email.
|
|
6
|
+
|
|
7
|
+
Any email with the +clerk_test subaddress is a test email address.
|
|
8
|
+
|
|
9
|
+
Learn more here: https://clerk.com/docs/testing/test-emails-and-phones#email-addresses`);let{supportedFirstFactors:s}=await n.create({identifier:e.identifier}),i=s?.find(o=>o.strategy==="email_code");if(i){await n.prepareFirstFactor({strategy:"email_code",emailAddressId:i.emailAddressId});let o=await n.attemptFirstFactor({strategy:"email_code",code:"424242"});if(o.status==="complete")await t.Clerk.setActive({session:o.createdSessionId});else throw new Error(`Status is ${o.status}`)}else throw new Error("email_code is not enabled.");break}default:throw new Error(`Unsupported strategy: ${e.strategy}`)}}catch(t){throw new Error(`Clerk: Failed to sign in: ${t?.message}`)}};var T=async e=>{let{CLERK_FAPI:r,CLERK_TESTING_TOKEN:t}=await _(e);process.env.CLERK_FAPI=r,process.env.CLERK_TESTING_TOKEN=t};var d=async({context:e,options:r,page:t})=>{let n=e??t?.context();if(!n)throw new Error("Either context or page must be provided to setup testing token");let s=r?.frontendApiUrl||process.env.CLERK_FAPI;if(!s)throw new Error(y);let i=s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),o=new RegExp(`^https://${i}/v1/.*?(\\?.*)?$`);await n.route(o,async a=>{let l=new URL(a.request().url()),g=process.env.CLERK_TESTING_TOKEN;g&&l.searchParams.set(C,g);try{let k=await a.fetch({url:l.toString()}),c=await k.json();c?.response?.captcha_bypass===!1&&(c.response.captcha_bypass=!0),c?.client?.captcha_bypass===!1&&(c.client.captcha_bypass=!0),await a.fulfill({response:k,json:c})}catch{await a.continue({url:l.toString()}).catch(console.error)}})};var P=require("@clerk/backend");var w=async({page:e})=>{await e.waitForFunction(()=>window.Clerk!==void 0),await e.waitForFunction(()=>window.Clerk.loaded)},b=async e=>{let r=e.page.context();if(!r)throw new Error("Page context is not available. Make sure the page is properly initialized.");if(await d({context:r,options:"setupClerkTestingTokenOptions"in e?e.setupClerkTestingTokenOptions:void 0}),await w({page:e.page}),"emailAddress"in e){let{emailAddress:t,page:n}=e,s=process.env.CLERK_SECRET_KEY;if(!s)throw new Error("CLERK_SECRET_KEY environment variable is required for email-based sign-in");let i=(0,P.createClerkClient)({secretKey:s});try{let o=await i.users.getUserList({emailAddress:[t]});if(!o.data||o.data.length===0)throw new Error(`No user found with email: ${t}`);let a=o.data[0],l=await i.signInTokens.createSignInToken({userId:a.id,expiresInSeconds:300});await n.evaluate(m,{signInParams:{strategy:"ticket",ticket:l.token}}),await n.waitForFunction(()=>window.Clerk?.user!==null)}catch(o){throw new Error(`Failed to sign in with email ${t}: ${o?.message}`)}}else{let{page:t,signInParams:n}=e;await t.evaluate(m,{signInParams:n})}},N=async({page:e,signOutOptions:r})=>{await w({page:e}),await e.evaluate(async t=>{await window.Clerk.signOut(t)},r)},S={signIn:b,signOut:N,loaded:w};0&&(module.exports={clerk,clerkSetup,setupClerkTestingToken});
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/playwright/index.ts","../../src/common/constants.ts","../../src/common/setup.ts","../../src/common/errors.ts","../../src/common/helpers-utils.ts","../../src/playwright/setup.ts","../../src/playwright/setupClerkTestingToken.ts","../../src/playwright/helpers.ts"],"sourcesContent":["export { clerkSetup } from './setup';\nexport { setupClerkTestingToken } from './setupClerkTestingToken';\nexport { clerk } from './helpers';\n","export const TESTING_TOKEN_PARAM = '__clerk_testing_token';\n","import { createClerkClient } from '@clerk/backend';\nimport { parsePublishableKey } from '@clerk/shared/keys';\nimport dotenv from 'dotenv';\n\nimport type { ClerkSetupOptions, ClerkSetupReturn } from './types';\n\nexport const fetchEnvVars = async (options?: ClerkSetupOptions): Promise<ClerkSetupReturn> => {\n const { debug = false, dotenv: loadDotEnv = true, ...rest } = options || {};\n\n const log = (msg: string) => {\n if (debug) {\n console.log(`Clerk: ${msg}`);\n }\n };\n\n log('Setting up Clerk...');\n\n if (loadDotEnv) {\n dotenv.config({ path: ['.env.local', '.env'] });\n }\n\n const publishableKey =\n rest.publishableKey ||\n process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY ||\n process.env.VITE_CLERK_PUBLISHABLE_KEY ||\n process.env.CLERK_PUBLISHABLE_KEY ||\n process.env.REACT_APP_CLERK_PUBLISHABLE_KEY ||\n process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY;\n\n const secretKey = rest.secretKey || process.env.CLERK_SECRET_KEY;\n let testingToken = process.env.CLERK_TESTING_TOKEN;\n\n if (!publishableKey) {\n throw new Error('You need to set the CLERK_PUBLISHABLE_KEY environment variable.');\n }\n\n if (!secretKey && !testingToken) {\n throw new Error('You need to set the CLERK_SECRET_KEY or the CLERK_TESTING_TOKEN environment variable.');\n }\n\n if (secretKey && !testingToken) {\n log('Fetching testing token from Clerk Backend API...');\n\n try {\n const apiUrl = (rest as any)?.apiUrl || process.env.CLERK_API_URL;\n const clerkClient = createClerkClient({ secretKey, apiUrl });\n const tokenData = await clerkClient.testingTokens.createTestingToken();\n testingToken = tokenData.token;\n } catch (err) {\n console.error('Failed to fetch testing token from Clerk API.');\n throw err;\n }\n }\n\n return {\n CLERK_FAPI: options?.frontendApiUrl || parsePublishableKey(publishableKey)?.frontendApi,\n CLERK_TESTING_TOKEN: testingToken,\n };\n};\n","export const ERROR_MISSING_FRONTEND_API_URL =\n 'The Clerk Frontend API URL is required to bypass bot protection. ' +\n 'Make sure the clerkSetup function is called during your global setup before setupClerkTestingToken is called.';\n","import type { EmailCodeFactor, PhoneCodeFactor, SignInFirstFactor } from '@clerk/shared/types';\n\nimport type { SignInHelperParams } from './types';\n\n// This function is serialized and executed in the browser context\nexport const signInHelper = async ({ signInParams, windowObject }: SignInHelperParams) => {\n try {\n const w = windowObject || window;\n if (!w.Clerk.client) {\n return;\n }\n\n const signIn = w.Clerk.client.signIn;\n\n switch (signInParams.strategy) {\n case 'password': {\n const res = await signIn.create(signInParams);\n await w.Clerk.setActive({\n session: res.createdSessionId,\n });\n break;\n }\n\n case 'ticket': {\n const res = await signIn.create({\n strategy: 'ticket',\n ticket: signInParams.ticket,\n });\n\n if (res.status === 'complete') {\n await w.Clerk.setActive({\n session: res.createdSessionId,\n });\n } else {\n throw new Error(`Sign-in with ticket failed. Status: ${res.status}`);\n }\n break;\n }\n\n case 'phone_code': {\n // Assert that the identifier is a test phone number\n if (!/^\\+1\\d{3}55501\\d{2}$/.test(signInParams.identifier)) {\n throw new Error(\n `Phone number should be a test phone number.\\n\n Example: +1XXX55501XX.\\n\n Learn more here: https://clerk.com/docs/testing/test-emails-and-phones#phone-numbers`,\n );\n }\n\n // Sign in with phone code\n const { supportedFirstFactors } = await signIn.create({\n identifier: signInParams.identifier,\n });\n const phoneFactor = supportedFirstFactors?.find(\n (factor: SignInFirstFactor): factor is PhoneCodeFactor => factor.strategy === 'phone_code',\n );\n\n if (phoneFactor) {\n await signIn.prepareFirstFactor({\n strategy: 'phone_code',\n phoneNumberId: phoneFactor.phoneNumberId,\n });\n const signInAttempt = await signIn.attemptFirstFactor({\n strategy: 'phone_code',\n code: '424242',\n });\n\n if (signInAttempt.status === 'complete') {\n await w.Clerk.setActive({ session: signInAttempt.createdSessionId });\n } else {\n throw new Error(`Status is ${signInAttempt.status}`);\n }\n } else {\n throw new Error('phone_code is not enabled.');\n }\n break;\n }\n\n case 'email_code': {\n // Assert that the identifier is a test email\n if (!signInParams.identifier.includes('+clerk_test')) {\n throw new Error(\n `Email should be a test email.\\n\n Any email with the +clerk_test subaddress is a test email address.\\n\n Learn more here: https://clerk.com/docs/testing/test-emails-and-phones#email-addresses`,\n );\n }\n\n // Sign in with email code\n const { supportedFirstFactors } = await signIn.create({\n identifier: signInParams.identifier,\n });\n const emailFactor = supportedFirstFactors?.find(\n (factor: SignInFirstFactor): factor is EmailCodeFactor => factor.strategy === 'email_code',\n );\n\n if (emailFactor) {\n await signIn.prepareFirstFactor({\n strategy: 'email_code',\n emailAddressId: emailFactor.emailAddressId,\n });\n const signInAttempt = await signIn.attemptFirstFactor({\n strategy: 'email_code',\n code: '424242',\n });\n\n if (signInAttempt.status === 'complete') {\n await w.Clerk.setActive({ session: signInAttempt.createdSessionId });\n } else {\n throw new Error(`Status is ${signInAttempt.status}`);\n }\n } else {\n throw new Error('email_code is not enabled.');\n }\n break;\n }\n\n default:\n throw new Error(`Unsupported strategy: ${(signInParams as any).strategy}`);\n }\n } catch (err: any) {\n throw new Error(`Clerk: Failed to sign in: ${err?.message}`);\n }\n};\n","import type { ClerkSetupOptions } from '../common';\nimport { fetchEnvVars } from '../common';\n\n/**\n * Sets up Clerk for testing by fetching the testing token from the Clerk Backend API.\n *\n * @param options.publishableKey - The publishable key for your Clerk dev instance.\n * @param options.frontendApiUrl - The frontend API URL for your Clerk dev instance, without the protocol. It overrides the Frontend API URL parsed from the publishable key.\n * @param options.debug - Enable debug logs.\n * @returns A promise that resolves when Clerk is set up.\n *\n * @throws An error if the publishable key or the secret key is not provided.\n * @throws An error if the secret key is from a production instance.\n * @throws An error if the testing token cannot be fetched from the Clerk Backend API.\n */\nexport const clerkSetup = async (options?: ClerkSetupOptions) => {\n const { CLERK_FAPI, CLERK_TESTING_TOKEN } = await fetchEnvVars(options);\n process.env.CLERK_FAPI = CLERK_FAPI;\n process.env.CLERK_TESTING_TOKEN = CLERK_TESTING_TOKEN;\n};\n","import type { BrowserContext, Page } from '@playwright/test';\n\nimport type { SetupClerkTestingTokenOptions } from '../common';\nimport { ERROR_MISSING_FRONTEND_API_URL, TESTING_TOKEN_PARAM } from '../common';\n\ntype SetupClerkTestingTokenParams = {\n context?: BrowserContext;\n page?: Page;\n options?: SetupClerkTestingTokenOptions;\n};\n\n/**\n * Bypasses bot protection by appending the testing token in the Frontend API requests.\n *\n * @param params.context - The Playwright browser context object.\n * @param params.page - The Playwright page object.\n * @param params.options.frontendApiUrl - The frontend API URL for your Clerk dev instance, without the protocol.\n * @returns A promise that resolves when the bot protection bypass is set up.\n * @throws An error if the Frontend API URL is not provided.\n * @example\n * import { setupClerkTestingToken } from '@clerk/testing/playwright';\n *\n * test('should bypass bot protection', async ({ context }) => {\n * await setupClerkTestingToken({ context });\n * const page = await context.newPage();\n * await page.goto('https://your-app.com');\n * // Continue with your test...\n * });\n */\nexport const setupClerkTestingToken = async ({ context, options, page }: SetupClerkTestingTokenParams) => {\n const browserContext = context ?? page?.context();\n\n if (!browserContext) {\n throw new Error('Either context or page must be provided to setup testing token');\n }\n\n const fapiUrl = options?.frontendApiUrl || process.env.CLERK_FAPI;\n if (!fapiUrl) {\n throw new Error(ERROR_MISSING_FRONTEND_API_URL);\n }\n\n const escapedFapiUrl = fapiUrl.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const apiUrl = new RegExp(`^https://${escapedFapiUrl}/v1/.*?(\\\\?.*)?$`);\n\n await browserContext.route(apiUrl, async route => {\n const originalUrl = new URL(route.request().url());\n const testingToken = process.env.CLERK_TESTING_TOKEN;\n\n if (testingToken) {\n originalUrl.searchParams.set(TESTING_TOKEN_PARAM, testingToken);\n }\n\n try {\n const response = await route.fetch({\n url: originalUrl.toString(),\n });\n\n const json = await response.json();\n\n // Override captcha_bypass in /v1/client\n if (json?.response?.captcha_bypass === false) {\n json.response.captcha_bypass = true;\n }\n\n // Override captcha_bypass in piggybacking\n if (json?.client?.captcha_bypass === false) {\n json.client.captcha_bypass = true;\n }\n\n await route.fulfill({\n response,\n json,\n });\n } catch {\n await route\n .continue({\n url: originalUrl.toString(),\n })\n .catch(console.error);\n }\n });\n};\n","import { createClerkClient } from '@clerk/backend';\nimport type { Clerk, SignOutOptions } from '@clerk/shared/types';\nimport type { Page } from '@playwright/test';\n\nimport type { ClerkSignInParams, SetupClerkTestingTokenOptions } from '../common';\nimport { signInHelper } from '../common';\nimport { setupClerkTestingToken } from './setupClerkTestingToken';\n\ndeclare global {\n interface Window {\n Clerk: Clerk;\n }\n}\n\ntype PlaywrightClerkLoadedParams = {\n page: Page;\n};\n\ntype PlaywrightClerkSignInParamsWithEmail = {\n page: Page;\n emailAddress: string;\n setupClerkTestingTokenOptions?: SetupClerkTestingTokenOptions;\n};\n\ntype ClerkHelperParams = {\n /**\n * Signs in a user using Clerk. This helper supports multiple sign-in strategies:\n * 1. Using signInParams object (password, phone_code, email_code strategies)\n * 2. Using emailAddress for automatic ticket-based sign-in\n *\n * Multi-factor is not supported.\n * This helper is using the `setupClerkTestingToken` internally.\n * It is required to call `page.goto` before calling this helper, and navigate to a not protected page that loads Clerk.\n *\n * For strategy-based sign-in:\n * If the strategy is password, the helper will sign in the user using the provided password and identifier.\n * If the strategy is phone_code, you are required to have a user with a test phone number as an identifier (e.g. +15555550100).\n * If the strategy is email_code, you are required to have a user with a test email as an identifier (e.g. your_email+clerk_test@example.com).\n *\n * For email-based sign-in:\n * The helper finds the user by email, creates a sign-in token using Clerk's backend API, and uses the ticket strategy.\n *\n * @example Strategy-based sign-in\n * import { clerk } from \"@clerk/testing/playwright\";\n *\n * test(\"sign in with strategy\", async ({ page }) => {\n * await page.goto(\"/\");\n * await clerk.signIn({\n * page,\n * signInParams: { strategy: 'phone_code', identifier: '+15555550100' },\n * });\n * await page.goto(\"/protected\");\n * });\n *\n * @example Email-based sign-in\n * import { clerk } from \"@clerk/testing/playwright\";\n *\n * test(\"sign in with email\", async ({ page }) => {\n * await page.goto(\"/\");\n * await clerk.signIn({ emailAddress: \"bryce@clerk.dev\", page });\n * await page.goto(\"/protected\");\n * });\n */\n signIn: {\n (opts: PlaywrightClerkSignInParams): Promise<void>;\n (opts: PlaywrightClerkSignInParamsWithEmail): Promise<void>;\n };\n /**\n * Signs out the current user using Clerk.\n * It is required to call `page.goto` before calling this helper, and navigate to a page that loads Clerk.\n * @param opts.signOutOptions - A SignOutOptions object.\n * @param opts.page - The Playwright page object.\n *\n * @example\n * import { clerk } from \"@clerk/testing/playwright\";\n *\n * test(\"sign out\", async ({ page }) => {\n * await page.goto(\"/\");\n * await clerk.signIn({\n * page,\n * signInParams: { strategy: 'phone_code', identifier: '+15555550100' },\n * });\n * await page.goto(\"/protected\");\n * await clerk.signOut({ page });\n * await page.goto(\"/protected\");\n * // should redirect to sign in page\n * });\n */\n signOut: (opts: PlaywrightClerkSignOutParams) => Promise<void>;\n /**\n * Asserts that Clerk has been loaded.\n * It is required to call `page.goto` before calling this helper, and navigate to a page that loads Clerk.\n *\n * @param opts.page - The Playwright page object.\n */\n loaded: (opts: PlaywrightClerkLoadedParams) => Promise<void>;\n};\n\nconst loaded = async ({ page }: PlaywrightClerkLoadedParams) => {\n await page.waitForFunction(() => window.Clerk !== undefined);\n await page.waitForFunction(() => window.Clerk.loaded);\n};\n\ntype PlaywrightClerkSignInParams = {\n page: Page;\n signInParams: ClerkSignInParams;\n setupClerkTestingTokenOptions?: SetupClerkTestingTokenOptions;\n};\n\nconst signIn = async (opts: PlaywrightClerkSignInParams | PlaywrightClerkSignInParamsWithEmail) => {\n const context = opts.page.context();\n if (!context) {\n throw new Error('Page context is not available. Make sure the page is properly initialized.');\n }\n\n await setupClerkTestingToken({\n context,\n options: 'setupClerkTestingTokenOptions' in opts ? opts.setupClerkTestingTokenOptions : undefined,\n });\n await loaded({ page: opts.page });\n\n if ('emailAddress' in opts) {\n // Email-based sign-in using ticket strategy\n const { emailAddress, page } = opts;\n\n const secretKey = process.env.CLERK_SECRET_KEY;\n if (!secretKey) {\n throw new Error('CLERK_SECRET_KEY environment variable is required for email-based sign-in');\n }\n\n const clerkClient = createClerkClient({ secretKey });\n\n try {\n // Find user by email\n const userList = await clerkClient.users.getUserList({ emailAddress: [emailAddress] });\n if (!userList.data || userList.data.length === 0) {\n throw new Error(`No user found with email: ${emailAddress}`);\n }\n\n const user = userList.data[0];\n\n const signInToken = await clerkClient.signInTokens.createSignInToken({\n userId: user.id,\n expiresInSeconds: 300, // 5 minutes\n });\n\n await page.evaluate(signInHelper, {\n signInParams: { strategy: 'ticket' as const, ticket: signInToken.token },\n });\n\n await page.waitForFunction(() => window.Clerk?.user !== null);\n } catch (err: any) {\n throw new Error(`Failed to sign in with email ${emailAddress}: ${err?.message}`);\n }\n } else {\n // Strategy-based sign-in: signIn(opts)\n const { page, signInParams } = opts;\n await page.evaluate(signInHelper, { signInParams });\n }\n};\n\ntype PlaywrightClerkSignOutParams = {\n page: Page;\n signOutOptions?: SignOutOptions;\n};\n\nconst signOut = async ({ page, signOutOptions }: PlaywrightClerkSignOutParams) => {\n await loaded({ page });\n\n await page.evaluate(async options => {\n await window.Clerk.signOut(options);\n }, signOutOptions);\n};\n\nexport const clerk: ClerkHelperParams = {\n signIn: signIn as ClerkHelperParams['signIn'],\n signOut,\n loaded,\n};\n"],"mappings":"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","names":["playwright_exports","__export","clerk","clerkSetup","setupClerkTestingToken","__toCommonJS","TESTING_TOKEN_PARAM","import_backend","import_keys","import_dotenv","fetchEnvVars","options","debug","loadDotEnv","rest","log","msg","dotenv","publishableKey","secretKey","testingToken","apiUrl","err","ERROR_MISSING_FRONTEND_API_URL","signInHelper","signInParams","windowObject","w","signIn","res","supportedFirstFactors","phoneFactor","factor","signInAttempt","emailFactor","err","clerkSetup","options","CLERK_FAPI","CLERK_TESTING_TOKEN","fetchEnvVars","setupClerkTestingToken","context","options","page","browserContext","fapiUrl","ERROR_MISSING_FRONTEND_API_URL","escapedFapiUrl","apiUrl","route","originalUrl","testingToken","TESTING_TOKEN_PARAM","response","json","import_backend","loaded","page","signIn","opts","context","setupClerkTestingToken","emailAddress","secretKey","clerkClient","userList","user","signInToken","signInHelper","err","signInParams","signOut","signOutOptions","options","clerk"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as p,b as n}from"../chunk-JDNEQWYI.mjs";import{a as s}from"../chunk-YFUXUEZ5.mjs";import"../chunk-M5YIJ3SE.mjs";var c=async e=>{let{CLERK_FAPI:t,CLERK_TESTING_TOKEN:r}=await p(e);process.env.CLERK_FAPI=t,process.env.CLERK_TESTING_TOKEN=r};import{createClerkClient as w}from"@clerk/backend";var o=async({page:e})=>{await e.waitForFunction(()=>window.Clerk!==void 0),await e.waitForFunction(()=>window.Clerk.loaded)},d=async e=>{let t=e.page.context();if(!t)throw new Error("Page context is not available. Make sure the page is properly initialized.");if(await s({context:t,options:"setupClerkTestingTokenOptions"in e?e.setupClerkTestingTokenOptions:void 0}),await o({page:e.page}),"emailAddress"in e){let{emailAddress:r,page:a}=e,l=process.env.CLERK_SECRET_KEY;if(!l)throw new Error("CLERK_SECRET_KEY environment variable is required for email-based sign-in");let g=w({secretKey:l});try{let i=await g.users.getUserList({emailAddress:[r]});if(!i.data||i.data.length===0)throw new Error(`No user found with email: ${r}`);let m=i.data[0],k=await g.signInTokens.createSignInToken({userId:m.id,expiresInSeconds:300});await a.evaluate(n,{signInParams:{strategy:"ticket",ticket:k.token}}),await a.waitForFunction(()=>window.Clerk?.user!==null)}catch(i){throw new Error(`Failed to sign in with email ${r}: ${i?.message}`)}}else{let{page:r,signInParams:a}=e;await r.evaluate(n,{signInParams:a})}},C=async({page:e,signOutOptions:t})=>{await o({page:e}),await e.evaluate(async r=>{await window.Clerk.signOut(r)},t)},P={signIn:d,signOut:C,loaded:o};export{P as clerk,c as clerkSetup,s as setupClerkTestingToken};
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/playwright/setup.ts","../../src/playwright/helpers.ts"],"sourcesContent":["import type { ClerkSetupOptions } from '../common';\nimport { fetchEnvVars } from '../common';\n\n/**\n * Sets up Clerk for testing by fetching the testing token from the Clerk Backend API.\n *\n * @param options.publishableKey - The publishable key for your Clerk dev instance.\n * @param options.frontendApiUrl - The frontend API URL for your Clerk dev instance, without the protocol. It overrides the Frontend API URL parsed from the publishable key.\n * @param options.debug - Enable debug logs.\n * @returns A promise that resolves when Clerk is set up.\n *\n * @throws An error if the publishable key or the secret key is not provided.\n * @throws An error if the secret key is from a production instance.\n * @throws An error if the testing token cannot be fetched from the Clerk Backend API.\n */\nexport const clerkSetup = async (options?: ClerkSetupOptions) => {\n const { CLERK_FAPI, CLERK_TESTING_TOKEN } = await fetchEnvVars(options);\n process.env.CLERK_FAPI = CLERK_FAPI;\n process.env.CLERK_TESTING_TOKEN = CLERK_TESTING_TOKEN;\n};\n","import { createClerkClient } from '@clerk/backend';\nimport type { Clerk, SignOutOptions } from '@clerk/shared/types';\nimport type { Page } from '@playwright/test';\n\nimport type { ClerkSignInParams, SetupClerkTestingTokenOptions } from '../common';\nimport { signInHelper } from '../common';\nimport { setupClerkTestingToken } from './setupClerkTestingToken';\n\ndeclare global {\n interface Window {\n Clerk: Clerk;\n }\n}\n\ntype PlaywrightClerkLoadedParams = {\n page: Page;\n};\n\ntype PlaywrightClerkSignInParamsWithEmail = {\n page: Page;\n emailAddress: string;\n setupClerkTestingTokenOptions?: SetupClerkTestingTokenOptions;\n};\n\ntype ClerkHelperParams = {\n /**\n * Signs in a user using Clerk. This helper supports multiple sign-in strategies:\n * 1. Using signInParams object (password, phone_code, email_code strategies)\n * 2. Using emailAddress for automatic ticket-based sign-in\n *\n * Multi-factor is not supported.\n * This helper is using the `setupClerkTestingToken` internally.\n * It is required to call `page.goto` before calling this helper, and navigate to a not protected page that loads Clerk.\n *\n * For strategy-based sign-in:\n * If the strategy is password, the helper will sign in the user using the provided password and identifier.\n * If the strategy is phone_code, you are required to have a user with a test phone number as an identifier (e.g. +15555550100).\n * If the strategy is email_code, you are required to have a user with a test email as an identifier (e.g. your_email+clerk_test@example.com).\n *\n * For email-based sign-in:\n * The helper finds the user by email, creates a sign-in token using Clerk's backend API, and uses the ticket strategy.\n *\n * @example Strategy-based sign-in\n * import { clerk } from \"@clerk/testing/playwright\";\n *\n * test(\"sign in with strategy\", async ({ page }) => {\n * await page.goto(\"/\");\n * await clerk.signIn({\n * page,\n * signInParams: { strategy: 'phone_code', identifier: '+15555550100' },\n * });\n * await page.goto(\"/protected\");\n * });\n *\n * @example Email-based sign-in\n * import { clerk } from \"@clerk/testing/playwright\";\n *\n * test(\"sign in with email\", async ({ page }) => {\n * await page.goto(\"/\");\n * await clerk.signIn({ emailAddress: \"bryce@clerk.dev\", page });\n * await page.goto(\"/protected\");\n * });\n */\n signIn: {\n (opts: PlaywrightClerkSignInParams): Promise<void>;\n (opts: PlaywrightClerkSignInParamsWithEmail): Promise<void>;\n };\n /**\n * Signs out the current user using Clerk.\n * It is required to call `page.goto` before calling this helper, and navigate to a page that loads Clerk.\n * @param opts.signOutOptions - A SignOutOptions object.\n * @param opts.page - The Playwright page object.\n *\n * @example\n * import { clerk } from \"@clerk/testing/playwright\";\n *\n * test(\"sign out\", async ({ page }) => {\n * await page.goto(\"/\");\n * await clerk.signIn({\n * page,\n * signInParams: { strategy: 'phone_code', identifier: '+15555550100' },\n * });\n * await page.goto(\"/protected\");\n * await clerk.signOut({ page });\n * await page.goto(\"/protected\");\n * // should redirect to sign in page\n * });\n */\n signOut: (opts: PlaywrightClerkSignOutParams) => Promise<void>;\n /**\n * Asserts that Clerk has been loaded.\n * It is required to call `page.goto` before calling this helper, and navigate to a page that loads Clerk.\n *\n * @param opts.page - The Playwright page object.\n */\n loaded: (opts: PlaywrightClerkLoadedParams) => Promise<void>;\n};\n\nconst loaded = async ({ page }: PlaywrightClerkLoadedParams) => {\n await page.waitForFunction(() => window.Clerk !== undefined);\n await page.waitForFunction(() => window.Clerk.loaded);\n};\n\ntype PlaywrightClerkSignInParams = {\n page: Page;\n signInParams: ClerkSignInParams;\n setupClerkTestingTokenOptions?: SetupClerkTestingTokenOptions;\n};\n\nconst signIn = async (opts: PlaywrightClerkSignInParams | PlaywrightClerkSignInParamsWithEmail) => {\n const context = opts.page.context();\n if (!context) {\n throw new Error('Page context is not available. Make sure the page is properly initialized.');\n }\n\n await setupClerkTestingToken({\n context,\n options: 'setupClerkTestingTokenOptions' in opts ? opts.setupClerkTestingTokenOptions : undefined,\n });\n await loaded({ page: opts.page });\n\n if ('emailAddress' in opts) {\n // Email-based sign-in using ticket strategy\n const { emailAddress, page } = opts;\n\n const secretKey = process.env.CLERK_SECRET_KEY;\n if (!secretKey) {\n throw new Error('CLERK_SECRET_KEY environment variable is required for email-based sign-in');\n }\n\n const clerkClient = createClerkClient({ secretKey });\n\n try {\n // Find user by email\n const userList = await clerkClient.users.getUserList({ emailAddress: [emailAddress] });\n if (!userList.data || userList.data.length === 0) {\n throw new Error(`No user found with email: ${emailAddress}`);\n }\n\n const user = userList.data[0];\n\n const signInToken = await clerkClient.signInTokens.createSignInToken({\n userId: user.id,\n expiresInSeconds: 300, // 5 minutes\n });\n\n await page.evaluate(signInHelper, {\n signInParams: { strategy: 'ticket' as const, ticket: signInToken.token },\n });\n\n await page.waitForFunction(() => window.Clerk?.user !== null);\n } catch (err: any) {\n throw new Error(`Failed to sign in with email ${emailAddress}: ${err?.message}`);\n }\n } else {\n // Strategy-based sign-in: signIn(opts)\n const { page, signInParams } = opts;\n await page.evaluate(signInHelper, { signInParams });\n }\n};\n\ntype PlaywrightClerkSignOutParams = {\n page: Page;\n signOutOptions?: SignOutOptions;\n};\n\nconst signOut = async ({ page, signOutOptions }: PlaywrightClerkSignOutParams) => {\n await loaded({ page });\n\n await page.evaluate(async options => {\n await window.Clerk.signOut(options);\n }, signOutOptions);\n};\n\nexport const clerk: ClerkHelperParams = {\n signIn: signIn as ClerkHelperParams['signIn'],\n signOut,\n loaded,\n};\n"],"mappings":"yHAeO,IAAMA,EAAa,MAAOC,GAAgC,CAC/D,GAAM,CAAE,WAAAC,EAAY,oBAAAC,CAAoB,EAAI,MAAMC,EAAaH,CAAO,EACtE,QAAQ,IAAI,WAAaC,EACzB,QAAQ,IAAI,oBAAsBC,CACpC,ECnBA,OAAS,qBAAAE,MAAyB,iBAkGlC,IAAMC,EAAS,MAAO,CAAE,KAAAC,CAAK,IAAmC,CAC9D,MAAMA,EAAK,gBAAgB,IAAM,OAAO,QAAU,MAAS,EAC3D,MAAMA,EAAK,gBAAgB,IAAM,OAAO,MAAM,MAAM,CACtD,EAQMC,EAAS,MAAOC,GAA6E,CACjG,IAAMC,EAAUD,EAAK,KAAK,QAAQ,EAClC,GAAI,CAACC,EACH,MAAM,IAAI,MAAM,4EAA4E,EAS9F,GANA,MAAMC,EAAuB,CAC3B,QAAAD,EACA,QAAS,kCAAmCD,EAAOA,EAAK,8BAAgC,MAC1F,CAAC,EACD,MAAMH,EAAO,CAAE,KAAMG,EAAK,IAAK,CAAC,EAE5B,iBAAkBA,EAAM,CAE1B,GAAM,CAAE,aAAAG,EAAc,KAAAL,CAAK,EAAIE,EAEzBI,EAAY,QAAQ,IAAI,iBAC9B,GAAI,CAACA,EACH,MAAM,IAAI,MAAM,2EAA2E,EAG7F,IAAMC,EAAcC,EAAkB,CAAE,UAAAF,CAAU,CAAC,EAEnD,GAAI,CAEF,IAAMG,EAAW,MAAMF,EAAY,MAAM,YAAY,CAAE,aAAc,CAACF,CAAY,CAAE,CAAC,EACrF,GAAI,CAACI,EAAS,MAAQA,EAAS,KAAK,SAAW,EAC7C,MAAM,IAAI,MAAM,6BAA6BJ,CAAY,EAAE,EAG7D,IAAMK,EAAOD,EAAS,KAAK,CAAC,EAEtBE,EAAc,MAAMJ,EAAY,aAAa,kBAAkB,CACnE,OAAQG,EAAK,GACb,iBAAkB,GACpB,CAAC,EAED,MAAMV,EAAK,SAASY,EAAc,CAChC,aAAc,CAAE,SAAU,SAAmB,OAAQD,EAAY,KAAM,CACzE,CAAC,EAED,MAAMX,EAAK,gBAAgB,IAAM,OAAO,OAAO,OAAS,IAAI,CAC9D,OAASa,EAAU,CACjB,MAAM,IAAI,MAAM,gCAAgCR,CAAY,KAAKQ,GAAK,OAAO,EAAE,CACjF,CACF,KAAO,CAEL,GAAM,CAAE,KAAAb,EAAM,aAAAc,CAAa,EAAIZ,EAC/B,MAAMF,EAAK,SAASY,EAAc,CAAE,aAAAE,CAAa,CAAC,CACpD,CACF,EAOMC,EAAU,MAAO,CAAE,KAAAf,EAAM,eAAAgB,CAAe,IAAoC,CAChF,MAAMjB,EAAO,CAAE,KAAAC,CAAK,CAAC,EAErB,MAAMA,EAAK,SAAS,MAAMiB,GAAW,CACnC,MAAM,OAAO,MAAM,QAAQA,CAAO,CACpC,EAAGD,CAAc,CACnB,EAEaE,EAA2B,CACtC,OAAQjB,EACR,QAAAc,EACA,OAAAhB,CACF","names":["clerkSetup","options","CLERK_FAPI","CLERK_TESTING_TOKEN","fetchEnvVars","createClerkClient","loaded","page","signIn","opts","context","setupClerkTestingToken","emailAddress","secretKey","clerkClient","createClerkClient","userList","user","signInToken","signInHelper","err","signInParams","signOut","signOutOptions","options","clerk"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var w=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var Z=Object.prototype.hasOwnProperty;var Q=(a,e)=>{for(var r in e)w(a,r,{get:e[r],enumerable:!0})},X=(a,e,r,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Y(e))!Z.call(a,o)&&o!==r&&w(a,o,{get:()=>e[o],enumerable:!(t=J(e,o))||t.enumerable});return a};var ee=a=>X(w({},"__esModule",{value:!0}),a);var te={};Q(te,{createAppPageObject:()=>d,createPageObjects:()=>W});module.exports=ee(te);var i=({page:a})=>{let e={continue:()=>a.getByRole("button",{name:"Continue",exact:!0}).click(),setEmailAddress:r=>e.getEmailAddressInput().fill(r),setPassword:r=>e.getPasswordInput().fill(r),setPasswordConfirmation:r=>a.locator("input[name=confirmPassword]").fill(r),enterOtpCode:async(r,t)=>{let{name:o="Enter verification code",awaitAttempt:n=!0,awaitPrepare:s=!0,awaitRequests:l=!0}=t??{};l&&s&&await a.waitForResponse(p=>p.request().method()==="POST"&&(p.url().includes("prepare_verification")||p.url().includes("prepare_first_factor")));let c=a.getByRole("textbox",{name:"Enter verification code. Digit 1"});await c.isVisible()?(console.warn("Using the original OTP input"),await c.click(),await a.keyboard.type(r,{delay:100})):await a.getByLabel(o).fill(r),l&&n&&await a.waitForResponse(p=>p.request().method()==="POST"&&(p.url().includes("attempt_verification")||p.url().includes("attempt_first_factor")))},enterTestOtpCode:async r=>e.enterOtpCode("424242",r),fillTestOtpCode:async(r,t)=>e.enterOtpCode("424242",{name:r,...t}),getIdentifierInput:()=>a.locator("input[name=identifier]"),getEmailAddressInput:()=>a.locator("input[name=emailAddress]"),getPhoneNumberInput:()=>a.locator("input[name=phoneNumber]"),getUsernameInput:()=>a.locator("input[name=username]"),getPasswordInput:()=>a.locator("input[name=password]"),getLegalAccepted:()=>a.locator("input[name=legalAccepted]"),getFirstNameInput:()=>a.locator("input[name=firstName]"),getLastNameInput:()=>a.locator("input[name=lastName]"),waitForSession:async()=>a.waitForFunction(()=>!!window.Clerk?.session)};return e};var P=a=>{let{page:e}=a,r={never:"Never","1d":"1 Day","7d":"7 Days","30d":"30 Days","60d":"60 Days","90d":"90 Days","180d":"180 Days","1y":"1 Year"};return{...i(a),waitForMounted:()=>e.waitForSelector(".cl-apiKeys-root",{state:"attached"}),clickAddButton:()=>e.getByText(/Add new key/i).click(),waitForFormOpened:()=>e.waitForSelector(".cl-apiKeysCreateForm",{state:"attached"}),waitForFormClosed:()=>e.waitForSelector(".cl-apiKeysCreateForm",{state:"detached"}),waitForRevokeModalOpened:()=>e.waitForSelector(".cl-apiKeysRevokeModal",{state:"attached"}),waitForRevokeModalClosed:()=>e.waitForSelector(".cl-apiKeysRevokeModal",{state:"detached"}),waitForCopyModalOpened:()=>e.waitForSelector(".cl-apiKeysCopyModal",{state:"attached"}),waitForCopyModalClosed:()=>e.waitForSelector(".cl-apiKeysCopyModal",{state:"detached"}),clickCopyAndCloseButton:()=>e.locator(".cl-apiKeysCopyModal .cl-apiKeysCopyModalSubmitButton").click(),typeName:o=>e.getByLabel(/Secret key name/i).fill(o),typeDescription:o=>e.getByLabel(/Description/i).fill(o),selectExpiration:async o=>(await e.getByRole("button",{name:/Select date/i}).click(),e.getByText(r[o??"never"],{exact:!0}).click({force:!0})),clickSaveButton:()=>e.getByText(/Create key/i).click(),typeRevokeConfirmation:o=>e.getByLabel(/Type "Revoke" to confirm/i).fill(o),clickConfirmRevokeButton:()=>e.getByText(/Revoke key/i).click()}};var F="__clerk_testing_token";var k="The Clerk Frontend API URL is required to bypass bot protection. Make sure the clerkSetup function is called during your global setup before setupClerkTestingToken is called.";var g=async({context:a,options:e,page:r})=>{let t=a??r?.context();if(!t)throw new Error("Either context or page must be provided to setup testing token");let o=e?.frontendApiUrl||process.env.CLERK_FAPI;if(!o)throw new Error(k);let n=o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),s=new RegExp(`^https://${n}/v1/.*?(\\?.*)?$`);await t.route(s,async l=>{let c=new URL(l.request().url()),u=process.env.CLERK_TESTING_TOKEN;u&&c.searchParams.set(F,u);try{let p=await l.fetch({url:c.toString()}),m=await p.json();m?.response?.captcha_bypass===!1&&(m.response.captcha_bypass=!0),m?.client?.captcha_bypass===!1&&(m.client.captcha_bypass=!0),await l.fulfill({response:p,json:m})}catch{await l.continue({url:c.toString()}).catch(console.error)}})};var d=(a,e)=>{let{page:r,useTestingToken:t=!0}=a,o=Object.create(r);return Object.assign(o,{goToAppHome:async()=>{if(!e.baseURL)throw new Error("Attempted to call method requiring baseURL, but baseURL was not provided to createPageObjects.");try{t&&await g({page:r}),await r.goto(e.baseURL)}catch{}},goToRelative:async(s,l={})=>{if(!e.baseURL)throw new Error("Attempted to call method requiring baseURL, but baseURL was not provided to createPageObjects.");let c;try{r.url().includes("about:blank")?c=new URL(s,e.baseURL):c=new URL(s,r.url())}catch{c=new URL(s,e.baseURL)}return l.searchParams&&(c.search=l.searchParams.toString()),t&&await g({page:r}),r.goto(c.toString(),{timeout:l.timeout??2e4,waitUntil:l.waitUntil})},waitForClerkJsLoaded:async()=>r.waitForFunction(()=>window.Clerk?.loaded),signOut:async()=>r.waitForFunction(()=>window.Clerk?.signOut({})),waitForClerkComponentMounted:async()=>r.waitForSelector(".cl-rootBox",{state:"attached"}),waitForAppUrl:async s=>{if(!e.baseURL)throw new Error("Attempted to call method requiring baseURL, but baseURL was not provided to createPageObjects.");return r.waitForURL(new URL(s,e.baseURL).toString())},cookies:async()=>{let s=await r.context().cookies(),l=s.reduce((c,u)=>(u.name.match(/^(__.*_)(.{8})$/)?c.set(u.name.replace(/^(__.*_)(.{8})$/,"$1*"),u):c.set(u.name,u),c),new Map);return Object.assign(l,{raw:()=>s})}})};var S=a=>{let{page:e}=a,r={...i(a),waitForMounted:(t=".cl-checkout-root")=>e.waitForSelector(t,{state:"attached",timeout:2e4}),closeDrawer:()=>e.locator(".cl-drawerClose").click(),fillTestCard:async()=>{await r.fillCard({number:"4242424242424242",expiration:"1234",cvc:"123",country:"United States",zip:"12345"})},fillCard:async t=>{await r.waitForStripeElements({state:"visible"});let o=e.frameLocator('iframe[src*="elements-inner-payment"]');await o.getByLabel("Card number").fill(t.number),await o.getByLabel("Expiration date").fill(t.expiration),await o.getByLabel("Security code").fill(t.cvc),await o.getByLabel("Country").selectOption(t.country),await o.getByLabel("ZIP code").fill(t.zip)},waitForStripeElements:async({state:t="visible"}={})=>{let o=e.locator('iframe[src*="elements-inner-payment"]');t==="visible"?(await o.waitFor({state:"attached",timeout:2e4}),await e.frameLocator('iframe[src*="elements-inner-payment"]').getByLabel("Card number").waitFor({state:"visible",timeout:2e4})):await e.frameLocator('iframe[src*="elements-inner-payment"]').getByLabel("Card number").waitFor({state:"hidden",timeout:2e4})},clickPayOrSubscribe:async()=>{await r.root.getByRole("button",{name:/subscribe|pay\s\$|start/i}).click()},waitForSubscribeButton:async()=>{await r.root.getByRole("button",{name:/^subscribe$/i}).waitFor({state:"visible"})},confirmAndContinue:async()=>{await r.root.getByRole("button",{name:/^continue$/i}).click()},clickAddPaymentMethod:async()=>{await r.root.getByRole("radio",{name:"Add payment method"}).click()},clickPaymentMethods:async()=>{await r.root.getByRole("radio",{name:"Payment Methods"}).click()},root:e.locator(".cl-checkout-root")};return r};var T=({page:a})=>({toBeLoaded:async()=>a.waitForFunction(()=>!!window.Clerk?.loaded),getClientSideActor:()=>a.evaluate(()=>window.Clerk?.session?.actor),toBeLoading:async()=>a.waitForFunction(()=>window.Clerk?.status==="loading"),toBeReady:async()=>a.waitForFunction(()=>window.Clerk?.status==="ready"),toBeDegraded:async()=>a.waitForFunction(()=>window.Clerk?.status==="degraded"),getClientSideUser:()=>a.evaluate(()=>window.Clerk?.user)});var y=require("@playwright/test"),C=({page:a})=>({toBeHandshake:async e=>{let r=await e.request().redirectedFrom()?.redirectedFrom()?.response();(0,y.expect)(r?.status()).toBe(307),(0,y.expect)(r?.headers()["x-clerk-auth-status"]).toContain("handshake")},toBeSignedOut:e=>a.waitForFunction(()=>!window.Clerk?.user,null,{timeout:e?.timeOut}),toBeSignedIn:async()=>a.waitForFunction(()=>!!window.Clerk?.user),toBeSignedInAsActor:async()=>a.waitForFunction(()=>!!window.Clerk?.session?.actor),toHaveResolvedTask:async()=>a.waitForFunction(()=>!window.Clerk?.session?.currentTask)});var B=a=>{let{page:e}=a;return{waitForMounted:(t=".cl-impersonationFab")=>e.waitForSelector(t,{state:"attached"}),getSignOutLink:()=>e.locator(".cl-impersonationFab").getByText("Sign out")}};var R=a=>{let{page:e}=a,r="#--clerk-keyless-prompt-button";return{waitForMounted:()=>e.waitForSelector(r,{state:"attached"}),waitForUnmounted:()=>e.waitForSelector(r,{state:"detached"}),isExpanded:()=>e.locator(r).getAttribute("aria-expanded").then(o=>o==="true"),toggle:()=>e.locator(r).click(),promptsToClaim:()=>e.getByRole("link",{name:/^claim application$/i}),promptToUseClaimedKeys:()=>e.getByRole("link",{name:/^get api keys$/i}),promptToDismiss:()=>e.getByRole("button",{name:/^dismiss$/i})}};var f=require("@playwright/test");var O=a=>{let{page:e}=a,r={...i(a),goTo:async(t="/switcher")=>(await e.goToRelative(t),r.waitForMounted()),waitForMounted:()=>e.waitForSelector(".cl-organizationSwitcher-root",{state:"attached"}),expectNoOrganizationSelected:()=>(0,f.expect)(e.getByText(/No organization selected/i)).toBeVisible(),expectPersonalAccount:()=>(0,f.expect)(e.getByText(/personal account/i)).toBeVisible(),toggleTrigger:()=>e.locator(".cl-organizationSwitcherTrigger").click(),waitForAnOrganizationToSelected:()=>e.waitForSelector(".cl-userPreviewMainIdentifier__personalWorkspace",{state:"detached"})};return r};var E=a=>{let{page:e}=a;return{...i(a),waitForMounted:(t=".cl-planDetails-root")=>e.waitForSelector(t,{state:"attached"}),root:e.locator(".cl-planDetails-root")}};var x=a=>{let{page:e}=a,r={toggle:n=>e.locator(`.cl-pricingTableCard__${n} .cl-pricingTableCardPeriodToggle`),indicator:n=>e.locator(`.cl-pricingTableCard__${n} .cl-switchIndicator`),badge:n=>e.locator(`.cl-pricingTableCard__${n} .cl-badge`),footer:n=>e.locator(`.cl-pricingTableCard__${n} .cl-pricingTableCardFooter`)},t=async(n,s)=>{async function l(u,p,m,q=5e3){return e.waitForFunction(({sel:z,attr:G,val:H})=>document.querySelector(z)?.getAttribute(G)===H,{sel:u,attr:p,val:m},{timeout:q}).then(()=>!0).catch(()=>!1)}let c=await l(`.cl-pricingTableCard__${n} .cl-switchIndicator`,"data-checked","true",500);c&&s==="monthly"&&await r.toggle(n).click(),!c&&s==="annually"&&await r.toggle(n).click()};return{...i(a),waitForMounted:(n=".cl-pricingTable-root")=>e.waitForSelector(n,{state:"attached"}),clickResubscribe:async()=>{await e.getByText("Re-subscribe").click()},waitToBeActive:async({planSlug:n})=>r.badge(n).getByText("Active").waitFor({state:"visible"}),waitToBeFreeTrial:async({planSlug:n})=>r.badge(n).getByText("Free trial").waitFor({state:"visible"}),getPlanCardCTA:({planSlug:n})=>r.footer(n).getByRole("button",{name:/get|switch|subscribe/i}),startCheckout:async({planSlug:n,shouldSwitch:s,period:l})=>{let c=s===!0?"Switch to this plan":s===!1?/subscribe/i:/get|switch|subscribe|Start \d+-day free trial/i;l&&await t(n,l),await r.footer(n).getByRole("button",{name:c}).click()}}};var b=require("@playwright/test");var U=a=>{let{page:e}=a;return{...i(a),resolveForceOrganizationSelectionTask:async t=>{let o=e.getByRole("button",{name:/continue/i});await(0,b.expect)(o).toBeVisible(),await e.locator("input[name=name]").fill(t.name),t.slug&&await e.locator("input[name=slug]").fill(t.slug),await o.click()},resolveResetPasswordTask:async({newPassword:t,confirmPassword:o})=>{await e.locator("input[name=newPassword]").fill(t),await e.locator("input[name=confirmPassword]").fill(o);let n=e.getByRole("button",{name:/reset password/i});await(0,b.expect)(n).toBeVisible(),await n.click()}}};var h=require("@playwright/test");var v=a=>{let{page:e}=a,r={...i(a),goTo:async t=>{let o=await e.goToRelative("/sign-in",t);return typeof t?.headlessSelector<"u"?await r.waitForMounted(t.headlessSelector):await r.waitForMounted(),o},waitForMounted:(t=".cl-signIn-root")=>e.waitForSelector(t,{state:"attached"}),waitForModal:t=>e.waitForSelector(".cl-modalContent:has(.cl-signIn-root)",{state:t==="closed"?"detached":"attached"}),setIdentifier:t=>r.getIdentifierInput().fill(t),setInstantPassword:async t=>{let o=r.getPasswordInput();await(0,h.expect)(o).toBeVisible(),await o.fill(t,{force:!0})},usePhoneNumberIdentifier:()=>e.getByRole("link",{name:/^use phone/i}),useEmailIdentifier:()=>e.getByRole("link",{name:/^use email/i}),useUsernameIdentifier:()=>e.getByRole("link",{name:/^username$/i}),getForgotPassword:()=>e.getByRole("link",{name:/forgot password/i}),getGoToSignUp:()=>e.getByRole("link",{name:/sign up/i}),getResetPassword:()=>e.getByRole("button",{name:/(reset password|reset your password)/i}),getUseAnotherMethodLink:()=>e.getByRole("link",{name:/use another method/i}),getAltMethodsEmailCodeButton:()=>e.getByRole("button",{name:/email code to/i}),getAltMethodsEmailLinkButton:()=>e.getByRole("button",{name:/email link to/i}),signInWithOauth:t=>e.getByRole("button",{name:new RegExp(`continue with ${t}`,"gi")}),signInWithEmailAndInstantPassword:async({email:t,password:o,waitForSession:n=!0})=>{let s=r.getIdentifierInput();await(0,h.expect)(s).toBeVisible(),await s.fill(t),await r.setInstantPassword(o),await r.continue(),n&&await r.waitForSession()}};return r};var I=a=>{let{page:e}=a,r={...i(a),goTo:async t=>(await e.goToRelative("/sign-up",{searchParams:t?.searchParams}),typeof t?.headlessSelector<"u"?r.waitForMounted(t.headlessSelector):r.waitForMounted()),waitForMounted:(t=".cl-signUp-root")=>e.waitForSelector(t,{state:"attached"}),waitForModal:t=>e.waitForSelector(".cl-modalContent:has(.cl-signUp-root)",{state:t==="closed"?"detached":"attached"}),signUpWithOauth:t=>e.getByRole("button",{name:new RegExp(`continue with ${t}`,"gi")}),signUp:async t=>{t.firstName&&await r.getFirstNameInput().fill(t.firstName),t.lastName&&await r.getLastNameInput().fill(t.lastName),t.email&&await r.getEmailAddressInput().fill(t.email),t.username&&await r.getUsernameInput().fill(t.username),t.phoneNumber&&await r.getPhoneNumberInput().fill(t.phoneNumber),t.password&&await r.getPasswordInput().fill(t.password),t.legalAccepted&&await r.getLegalAccepted().check(),await r.continue()},signUpWithEmailAndPassword:async t=>{await r.signUp({email:t.email,password:t.password})},waitForEmailVerificationScreen:async()=>{await e.waitForURL(/verify/),await e.getByRole("heading",{name:/Verify your email/i}).waitFor()}};return r};var L=a=>{let{page:e}=a,r={...i(a),waitForMounted:(t=".cl-subscriptionDetails-root")=>e.waitForSelector(t,{state:"attached"}),waitForUnmounted:()=>r.root.locator(".cl-drawerRoot").waitFor({state:"detached"}),closeDrawer:()=>r.root.locator(".cl-drawerClose").click(),root:e.locator(".cl-subscriptionDetails-root")};return r};var A=({page:a})=>({setup:async()=>g({page:a})});var j=require("@playwright/test"),M=".cl-userAvatarBox",_=a=>{let{page:e}=a,r={goTo:async t=>(await e.goToRelative("/user-avatar",t),r.waitForMounted()),waitForMounted:(t=M)=>e.waitForSelector(t,{state:"attached"}),toBeVisible:async(t=M)=>await(0,j.expect)(e.locator(t).getByRole("img")).toBeVisible()};return r};var N=require("@playwright/test"),D=a=>{let{page:e}=a;return{waitForMounted:()=>e.waitForSelector(".cl-userButtonTrigger",{state:"attached"}),toggleTrigger:()=>e.locator(".cl-userButtonTrigger").click(),waitForPopover:()=>e.waitForSelector(".cl-userButtonPopoverCard",{state:"visible"}),waitForPopoverClosed:()=>e.waitForSelector(".cl-userButtonPopoverCard",{state:"detached"}),toHaveVisibleMenuItems:async t=>{(typeof t=="string"||t instanceof RegExp)&&(t=[t]);for(let o of t)await(0,N.expect)(e.getByRole("menuitem",{name:o})).toBeVisible()},triggerSignOut:()=>e.getByRole("menuitem",{name:/Sign out$/i}).click(),triggerManageAccount:()=>e.getByRole("menuitem",{name:/Manage account/i}).click(),switchAccount:t=>e.getByText(t).click()}};var $=a=>{let{page:e}=a,r={...i(a),goTo:async t=>(await e.goToRelative("/user",t),r.waitForMounted()),switchToSecurityTab:async()=>{await e.getByText(/Security/i).click()},switchToBillingTab:async()=>{await e.getByText(/Billing/i).click()},switchToAPIKeysTab:async()=>{await e.getByText(/API keys/i).click()},waitForMounted:()=>e.waitForSelector(".cl-userProfile-root",{state:"attached"}),clickSetUsername:()=>e.getByText(/Set username/i).click(),clickToUpdateProfile:()=>e.getByText(/update profile/i).click(),clickUpdateUsername:()=>e.getByText(/update username/i).click(),clickSetPassword:()=>e.getByText(/Set password/i).click(),waitForSectionCard:(t,o)=>e.waitForSelector(`.cl-profileSectionContent__${t} .cl-headerTitle`,{state:o?"visible":"detached"}),waitForSectionCardOpened:t=>r.waitForSectionCard(t,!0),waitForSectionCardClosed:t=>r.waitForSectionCard(t,!1),typeUsername:t=>r.getUsernameInput().fill(t),typeFirstName:t=>r.getFirstNameInput().fill(t),typeLastName:t=>r.getLastNameInput().fill(t),typePhoneNumber:t=>r.getPhoneNumberInput().fill(t),clickAddEmailAddress:()=>e.getByText(/add email address/i).click(),clickAddPhoneNumber:()=>e.getByText(/add phone number/i).click(),typeEmailAddress:t=>e.getByLabel(/Email address/i).fill(t),waitForUserProfileModal:t=>e.waitForSelector(".cl-modalContent:has(.cl-userProfile-root)",{state:t==="closed"?"detached":"attached"})};return r};var V=a=>{let{page:e}=a;return{...i(a),waitForMounted:(t=".cl-userVerification-root")=>e.waitForSelector(t,{state:"attached"}),waitForClosed:(t=".cl-userVerification-root")=>e.waitForSelector(t,{state:"detached"}),closeReverificationModal:()=>e.getByLabel("Close modal").click(),getUseAnotherMethodLink:()=>e.getByRole("link",{name:/use another method/i}),getAltMethodsEmailCodeButton:()=>e.getByRole("button",{name:/email code to/i}),getAltMethodsEmailLinkButton:()=>e.getByRole("button",{name:/email link to/i})}};var K=a=>{let{page:e}=a,r={...i(a),goTo:async t=>(await e.goToRelative("/waitlist",{searchParams:t?.searchParams}),typeof t?.headlessSelector<"u"?r.waitForMounted(t.headlessSelector):r.waitForMounted()),waitForMounted:(t=".cl-waitlist-root")=>e.waitForSelector(t,{state:"attached"}),joinWaitlist:async t=>{await r.getEmailAddressInput().fill(t.email),await r.joinWaitlistContinue()},joinWaitlistContinue:()=>e.getByRole("button",{name:"Join the waitlist",exact:!0}).click()};return r};var W=({page:a,useTestingToken:e=!0,baseURL:r})=>{let t=d({page:a,useTestingToken:e},{baseURL:r}),o={page:t};return{page:t,clerk:T(o),checkout:S(o),expect:C(o),impersonation:B(o),keylessPopover:R(o),organizationSwitcher:O(o),pricingTable:x(o),sessionTask:U(o),signIn:v(o),signUp:I(o),testingToken:A(o),userAvatar:_(o),userButton:D(o),userProfile:$(o),userVerification:V(o),waitlist:K(o),apiKeys:P(o),subscriptionDetails:L(o),planDetails:E(o)}};0&&(module.exports={createAppPageObject,createPageObjects});
|
|
2
|
+
//# sourceMappingURL=index.js.map
|