UNPKG

@clerk/testing

Version:

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

1 lines 9.37 kB
{"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/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"]}