UNPKG

@clerk/testing

Version:

Utilities to help you create E2E test suites for apps using Clerk

12 lines (8 loc) • 9.11 kB
"use strict";var G=Object.create;var u=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var q=Object.getPrototypeOf,X=Object.prototype.hasOwnProperty;var W=(e,n)=>{for(var t in n)u(e,t,{get:n[t],enumerable:!0})},R=(e,n,t,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let a of H(n))!X.call(e,a)&&a!==t&&u(e,a,{get:()=>n[a],enumerable:!(r=D(n,a))||r.enumerable});return e};var J=(e,n,t)=>(t=e!=null?G(q(e)):{},R(n||!e||!e.__esModule?u(t,"default",{value:e,enumerable:!0}):t,e)),V=e=>R(u({},"__esModule",{value:!0}),e);var ie={};W(ie,{clerk:()=>B,clerkSetup:()=>N,createAgentTestingTask:()=>U,setupClerkTestingToken:()=>C});module.exports=V(ie);var P=require("@clerk/backend"),j="A secretKey is required to create agent tasks. Pass it directly or set the CLERK_SECRET_KEY environment variable.";var z="Failed to create agent task: ";async function I(e){let{apiUrl:n,secretKey:t,clerkClient:r,...a}=e;if(!r&&!t)throw new Error(j);let i=r??(0,P.createClerkClient)({apiUrl:n,secretKey:t});try{return await i.agentTasks.create(a)}catch(s){throw new Error(z+(s instanceof Error?s.message:String(s)))}}var A="__clerk_testing_token";var K=require("@clerk/backend"),w=require("@clerk/shared/error"),O=require("@clerk/shared/keys"),v=J(require("dotenv")),_=5,Q=1e3,Z=500,L=3e4,ee=new Set([408,429,500,502,503,504]),te=new Set(["ECONNREFUSED","ECONNRESET","ENOTFOUND","ETIMEDOUT","EAI_AGAIN"]);function re(e){return e instanceof Error&&"code"in e&&te.has(e.code??"")}async function se(e,n){for(let t=0;t<=_;t++)try{return await e()}catch(r){let a=(0,w.isClerkAPIResponseError)(r)&&ee.has(r.status),i=re(r);if(!a&&!i||t===_)throw r;let s=(0,w.isClerkAPIResponseError)(r)?r.status:r.code,o=Q*Math.pow(2,t)+Math.random()*Z,c=(0,w.isClerkAPIResponseError)(r)&&typeof r.retryAfter=="number"?Math.min(Math.max(r.retryAfter*1e3,o),L):Math.min(o,L);console.warn(`[Retry] ${s} for ${n}, attempt ${t+1}/${_}, waiting ${Math.round(c)}ms`),await new Promise(d=>setTimeout(d,c))}throw new Error("Unreachable")}var F=async e=>{let{debug:n=!1,dotenv:t=!0,...r}=e||{},a=c=>{n&&console.log(`Clerk: ${c}`)};a("Setting up Clerk..."),t&&v.default.config({path:[".env.local",".env"]});let i=r.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=r.secretKey||process.env.CLERK_SECRET_KEY,o=process.env.CLERK_TESTING_TOKEN;if(!i)throw new Error("You need to set the CLERK_PUBLISHABLE_KEY environment variable.");if(!s&&!o)throw new Error("You need to set the CLERK_SECRET_KEY or the CLERK_TESTING_TOKEN environment variable.");if(s&&!o){a("Fetching testing token from Clerk Backend API...");try{let c=r?.apiUrl||process.env.CLERK_API_URL,d=(0,K.createClerkClient)({secretKey:s,apiUrl:c});o=(await se(()=>d.testingTokens.createTestingToken(),"testingTokens.createTestingToken")).token}catch(c){throw console.error("Failed to fetch testing token from Clerk API."),c}}return{CLERK_FAPI:e?.frontendApiUrl||(0,O.parsePublishableKey)(i)?.frontendApi,CLERK_TESTING_TOKEN:o}};var b="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 f=async({signInParams:e,windowObject:n})=>{try{let t=n||window;if(!t.Clerk.client)return;let r=t.Clerk.client.signIn;switch(e.strategy){case"password":{let a=await r.create(e);await t.Clerk.setActive({session:a.createdSessionId});break}case"ticket":{let a=await r.create({strategy:"ticket",ticket:e.ticket});if(a.status==="complete")await t.Clerk.setActive({session:a.createdSessionId});else throw new Error(`Sign-in with ticket failed. Status: ${a.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. Example: +1XXX55501XX. Learn more here: https://clerk.com/docs/testing/test-emails-and-phones#phone-numbers`);let{supportedFirstFactors:a}=await r.create({identifier:e.identifier}),i=a?.find(s=>s.strategy==="phone_code");if(i){await r.prepareFirstFactor({strategy:"phone_code",phoneNumberId:i.phoneNumberId});let s=await r.attemptFirstFactor({strategy:"phone_code",code:"424242"});if(s.status==="complete")await t.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. Any email with the +clerk_test subaddress is a test email address. Learn more here: https://clerk.com/docs/testing/test-emails-and-phones#email-addresses`);let{supportedFirstFactors:a}=await r.create({identifier:e.identifier}),i=a?.find(s=>s.strategy==="email_code");if(i){await r.prepareFirstFactor({strategy:"email_code",emailAddressId:i.emailAddressId});let s=await r.attemptFirstFactor({strategy:"email_code",code:"424242"});if(s.status==="complete")await t.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(t){throw new Error(`Clerk: Failed to sign in: ${t?.message}`)}};var N=async e=>{let{CLERK_FAPI:n,CLERK_TESTING_TOKEN:t}=await F(e);process.env.CLERK_FAPI=n,process.env.CLERK_TESTING_TOKEN=t};function U(e){return I({...e,apiUrl:e.apiUrl||process.env.CLERK_API_URL,secretKey:e.secretKey||process.env.CLERK_SECRET_KEY})}var y=new WeakSet,ne=new Set([429,502,503,504]),g=3,$=500,x=250,C=async({context:e,options:n,page:t})=>{let r=e??t?.context();if(!r)throw new Error("Either context or page must be provided to setup testing token");if(y.has(r)){process.env.CLERK_TESTING_DEBUG&&console.log("[Clerk Testing] Route handler already registered for this context, skipping duplicate setup");return}let a=n?.frontendApiUrl||process.env.CLERK_FAPI;if(!a)throw new Error(b);let i=a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),s=new RegExp(`^https://${i}/v1/.*?(\\?.*)?$`);y.add(r);try{await r.route(s,async o=>{let c=new URL(o.request().url()),d=process.env.CLERK_TESTING_TOKEN;d&&c.searchParams.set(A,d);let T=c.toString();for(let p=0;p<=g;p++)try{let l=await o.fetch({url:T}),m=l.status();if(ne.has(m)){if(p<g){let k=$*Math.pow(2,p)+Math.random()*x;process.env.CLERK_TESTING_DEBUG&&console.log(`[Clerk Testing] FAPI returned ${m}, retrying (attempt ${p+1}/${g}, delay ${Math.round(k)}ms): ${o.request().url()}`),await new Promise(Y=>setTimeout(Y,k));continue}let h="";try{let k=l.headers();h=` cf-ray: ${k["cf-ray"]??"n/a"}, retry-after: ${k["retry-after"]??"n/a"}, content-type: ${k["content-type"]??"n/a"}`,h+=` body: ${(await l.text()).slice(0,500)}`}catch{}console.warn(`[Clerk Testing] FAPI request failed with status ${m} after ${g+1} attempts: ${o.request().url()}${h}`),await o.fulfill({response:l});return}let E=await l.json();E?.response?.captcha_bypass===!1&&(E.response.captcha_bypass=!0),E?.client?.captcha_bypass===!1&&(E.client.captcha_bypass=!0),await o.fulfill({response:l,json:E});return}catch(l){if(p<g){let m=$*Math.pow(2,p)+Math.random()*x;process.env.CLERK_TESTING_DEBUG&&console.log(`[Clerk Testing] FAPI request error, retrying (attempt ${p+1}/${g}, delay ${Math.round(m)}ms): ${o.request().url()}`,l),await new Promise(E=>setTimeout(E,m));continue}console.warn(`[Clerk Testing] FAPI request failed after ${g+1} attempts: ${o.request().url()} (${String(l)})`),await o.continue({url:T}).catch(console.error);return}})}catch(o){throw y.delete(r),o}};var M=require("@clerk/backend");var S=async({page:e})=>{await e.waitForFunction(()=>window.Clerk!==void 0),await e.waitForFunction(()=>window.Clerk.loaded)},ae=async e=>{let n=e.page.context();if(!n)throw new Error("Page context is not available. Make sure the page is properly initialized.");if(await C({context:n,options:"setupClerkTestingTokenOptions"in e?e.setupClerkTestingTokenOptions:void 0}),await S({page:e.page}),"emailAddress"in e){let{emailAddress:t,page:r}=e,a=process.env.CLERK_SECRET_KEY;if(!a)throw new Error("CLERK_SECRET_KEY environment variable is required for email-based sign-in");let i=(0,M.createClerkClient)({secretKey:a});try{let s=await i.users.getUserList({emailAddress:[t]});if(!s.data||s.data.length===0)throw new Error(`No user found with email: ${t}`);let o=s.data[0],c=await i.signInTokens.createSignInToken({userId:o.id,expiresInSeconds:300});await r.evaluate(f,{signInParams:{strategy:"ticket",ticket:c.token}}),await r.waitForFunction(()=>window.Clerk?.user!==null)}catch(s){throw new Error(`Failed to sign in with email ${t}: ${s?.message}`)}}else{let{page:t,signInParams:r}=e;await t.evaluate(f,{signInParams:r})}},oe=async({page:e,signOutOptions:n})=>{await S({page:e}),await e.evaluate(async t=>{await window.Clerk.signOut(t)},n)},B={signIn:ae,signOut:oe,loaded:S};0&&(module.exports={clerk,clerkSetup,createAgentTestingTask,setupClerkTestingToken}); //# sourceMappingURL=index.js.map