{"id":15629696,"url":"https://github.com/prescottprue/cypress-firebase","last_synced_at":"2025-05-15T00:06:49.374Z","repository":{"id":38854623,"uuid":"153763478","full_name":"prescottprue/cypress-firebase","owner":"prescottprue","description":"Cypress plugin and custom commands for testing Firebase projects","archived":false,"fork":false,"pushed_at":"2025-05-10T12:19:52.000Z","size":20064,"stargazers_count":270,"open_issues_count":34,"forks_count":50,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-05-10T13:28:51.871Z","etag":null,"topics":["cypress","firebase","firestore"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/prescottprue.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["prescottprue"]}},"created_at":"2018-10-19T10:05:04.000Z","updated_at":"2025-05-10T12:19:53.000Z","dependencies_parsed_at":"2023-10-13T01:45:17.901Z","dependency_job_id":"894a74b2-5d83-4f95-836b-2f7dbd5cbf03","html_url":"https://github.com/prescottprue/cypress-firebase","commit_stats":{"total_commits":830,"total_committers":26,"mean_commits":"31.923076923076923","dds":"0.29156626506024097","last_synced_commit":"6e8a3c896e3228ecc320402c04b545413e8f95c6"},"previous_names":[],"tags_count":86,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prescottprue%2Fcypress-firebase","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prescottprue%2Fcypress-firebase/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prescottprue%2Fcypress-firebase/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prescottprue%2Fcypress-firebase/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/prescottprue","download_url":"https://codeload.github.com/prescottprue/cypress-firebase/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253422631,"owners_count":21905954,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cypress","firebase","firestore"],"created_at":"2024-10-03T10:28:11.708Z","updated_at":"2025-05-15T00:06:49.323Z","avatar_url":"https://github.com/prescottprue.png","language":"TypeScript","funding_links":["https://github.com/sponsors/prescottprue"],"categories":[],"sub_categories":[],"readme":"# cypress-firebase\n\n\u003e Cypress plugin and custom commands for testing Firebase projects\n\n[![NPM version][npm-image]][npm-url]\n[![NPM downloads][npm-downloads-image]][npm-url]\n[![Build Status][build-status-image]][build-status-url]\n[![Coverage][coverage-image]][coverage-url]\n[![License][license-image]][license-url]\n[![Code Style][code-style-image]][code-style-url]\n[![semantic-release][semantic-release-image]][semantic-release-url]\n\n## What?\n\n0 dependency plugin which adds [custom cypress commands](https://docs.cypress.io/api/cypress-api/custom-commands.html#Syntax) for interactions with Firebase:\n\n- [cy.createUserWithClaims][createUserWClaims]\n- [cy.login][login]\n- [cy.loginWithEmailAndPassword][loginEmail]\n- [cy.logout][logout]\n- [cy.deleteAllAuthUsers][delAllUsers]\n- [cy.callRtdb][callRtdb]\n- [cy.callFirestore][callFirestore]\n- [cy.\\[authFunction\\]][authFunctions]\n\nIf you are interested in what drove the need for this checkout [the why section](#why)\n\n## Usage\n\n### Pre-Setup\n\n1. If you do not already have it installed, install Cypress and add it to your package file: `npm i --save-dev cypress` or `yarn add -D cypress`\n1. Make sure you have a `cypress` folder containing Cypress tests\n\n### Setup\n\n1. Make Google Cloud project name available to cypress-firebase to pass to firebase-admin on initialization by doing one of the following:\n   - _suggested_ Set `GCLOUD_PROJECT` environment variable to match the Google Project you would like to use. This needs to be on the process running cypress, so it should be before `cypress open` or `cypress run` in npm scripts. cross-env is a helpful way to do this to support multiple platforms and is how it is done in examples.\n   - Pass `projectId` into `cypressFirebasePlugin` options when initializing (see comment in next step)\n1. Generate and download a service account as described in [the firebase-admin setup documentation](https://firebase.google.com/docs/admin/setup#initialize-sdk). Save this to a local file within the project which you confirm is within your `.gitignore` - often `./serviceAccount.json`. Make sure YOU DO NOT COMMIT THIS FILE - it is sensitive and will give others admin access to your project.\n   - **Note**: When running tests locally, ensure the `SERVICE_ACCOUNT` is in your environment variables. I.E. `SERVICE_ACCOUNT=$(cat ./serviceAccount.json) cypress open`\n1. Set the following config in your `cypress.config.js` or `cypress.config.ts`\n\nWith [Firebase Web SDK versions up to 8](https://firebase.google.com/docs/web/modular-upgrade)\n\n```js\nimport admin from 'firebase-admin';\nimport { defineConfig } from 'cypress';\nimport { plugin as cypressFirebasePlugin } from 'cypress-firebase';\n\nexport default defineConfig({\n  e2e: {\n    baseUrl: 'http://localhost:3000',\n    // NOTE: Add \"supportFile\" setting if separate location is used\n    setupNodeEvents(on, config) {\n      // e2e testing node events setup code\n      return cypressFirebasePlugin(on, config, admin, {\n        // Here is where you can pass special options.\n        // If you have not set the GCLOUD_PROJECT environment variable, give the projectId here, like so:\n        //    projectId: 'some-project',\n        // if your databaseURL is not just your projectId plus \".firebaseio.com\", then you _must_ give it here, like so:\n        //    databaseURL: 'some-project-default-rtdb.europe-west1.firebasedatabase.app',\n      });\n    },\n  },\n});\n```\n\nor if you are not using TS, then within `cypress.config.js`:\n\n```js\nconst { defineConfig } = require('cypress');\nconst cypressFirebasePlugin = require('cypress-firebase').plugin;\nconst admin = require('firebase-admin');\n\nmodule.exports = defineConfig({\n  e2e: {\n    baseUrl: 'http://localhost:3000',\n    // NOTE: Make supportFile exists if separate location is provided\n    setupNodeEvents(on, config) {\n      // e2e testing node events setup code\n      return cypressFirebasePlugin(on, config, admin, {\n        // Here is where you can pass special options.\n        // If you have not set the GCLOUD_PROJECT environment variable, give the projectId here, like so:\n        //    projectId: 'some-project',\n        // if your databaseURL is not just your projectId plus \".firebaseio.com\", then you _must_ give it here, like so:\n        //    databaseURL: 'some-project-default-rtdb.europe-west1.firebasedatabase.app',\n      });\n    },\n  },\n});\n```\n\n1. Add the following your custom commands file (`cypress/support/e2e.js` or `cypress/support/e2e.ts`):\n\n   ```js\n   import firebase from 'firebase/app';\n   import 'firebase/auth';\n   import 'firebase/database';\n   import 'firebase/firestore';\n   import { attachCustomCommands } from 'cypress-firebase';\n\n   const fbConfig = {\n     // Your config from Firebase Console\n   };\n\n   firebase.initializeApp(fbConfig);\n\n   attachCustomCommands({ Cypress, cy, firebase });\n   ```\n\n   With [Firebase Web SDK version 9](https://firebase.google.com/docs/web/modular-upgrade)\n\n   ```js\n   import firebase from 'firebase/compat/app';\n   import 'firebase/compat/auth';\n   import 'firebase/compat/database';\n   import 'firebase/compat/firestore';\n   import { attachCustomCommands } from 'cypress-firebase';\n\n   const fbConfig = {\n     // Your config from Firebase Console\n   };\n\n   firebase.initializeApp(fbConfig);\n\n   attachCustomCommands({ Cypress, cy, firebase });\n   ```\n\n1. To confirm things are working, create a new test file (`cypress/integration/examples/test_hello_world.cy.js`) adding a test that uses the cypress-firebase custom command (`cy.callFirestore`):\n\n   ```js\n   describe('Some Test', () =\u003e {\n     it('Adds document to test_hello_world collection of Firestore', () =\u003e {\n       cy.callFirestore('add', 'test_hello_world', { some: 'value' });\n     });\n   });\n   ```\n\n1. From the root of your project, start Cypress with the command `$(npm bin)/cypress open`. In the Cypress window, click your new test (`test_hello_world.js`) to run it.\n1. Look in your Firestore instance and see the `test_hello_world` collection to confirm that a document was added.\n1. Pat yourself on the back, you are all setup to access Firebase/Firestore from within your tests!\n\n#### Auth\n\n1. Go to Authentication page of the Firebase Console and select an existing user to use as the testing account or create a new user. This will be the account which you use to login while running tests.\n1. Get the UID of the account you have selected, we will call this UID `TEST_UID`\n1. Set the UID of the user you created earlier to the Cypress environment. You can do this using a number of methods:\n\n   - Adding `CYPRESS_TEST_UID` to a `.env` file which is gitignored\n   - Adding `TEST_UID` to `cypress.env.json` (make sure you place this within your `.gitignore`)\n   - Adding as part of your npm script to run tests with a tool such as `cross-env` [here](https://github.com/kentcdodds/cross-env):\n\n     ```json\n     \"test\": \"cross-env CYPRESS_TEST_UID=your-uid cypress open\"\n     ```\n\n1. Call `cy.login()` with the `before` or `beforeEach` sections of your tests\n\n### Running\n\n1. Start your local dev server (usually `npm start`) - for faster alternative checkout the [test built version section](#test-built-version)\n1. Open cypress test running by running `npm run test:open` in another terminal window\n\n### Considerations For CI\n\n1. Add the following environment variables in your CI:\n\n   - `CYPRESS_TEST_UID` - UID of your test user\n   - `SERVICE_ACCOUNT` - service account object\n\n### Named app support\n\nWhen using a custom app name or running more than one firebase instance in your app:\n\n```js\nconst namedApp = firebase.initializeApp(fbConfig, 'app_name');\n\nattachCustomCommands({ Cypress, cy, firebase, app: namedApp });\n```\n\n## Docs\n\n### Custom Cypress Commands\n\n#### Table of Contents\n\n- [cy.createUserWithClaims][createUserWClaims]\n  - [Parameters][createUserWClaims-params]\n  - [Examples][createUserWClaims-ex]\n- [cy.login][login]\n  - [Parameters][login-params]\n  - [Examples][login-ex]\n- [cy.loginWithEmailAndPassword][loginEmail]\n  - [Parameters][loginEmail-params]\n  - [Examples][loginEmail-ex]\n- [cy.logout][logout]\n  - [Parameters][logout-params]\n  - [Examples][logout-ex]\n- [cy.deleteAllAuthUsers][delAllUsers]\n  - [Parameters][delAllUsers-params]\n  - [Examples][delAllUsers-ex]\n- [cy.callRtdb][callRtdb]\n  - [Parameters][callRtdb-params]\n  - [Examples][callRtdb-ex]\n- [cy.callFirestore][callFirestore]\n  - [Parameters][callFirestore-params]\n  - [Examples][callFirestore-ex]\n- [cy.\\[authFunction\\]][authFunctions]\n  - [Parameters][authFunctions-params]\n  - [Examples][authFunctions-ex]\n\n#### cy.createUserWithClaims\n\nCommand to create a user and give the user custom claims in one command.\n\n##### Parameters\n\n- `properties` **[CreateRequest][firebase-createrequest]** The properties of the new user\n- `customClaims` **[object][mdn-object] | [null][mdn-null]** Optional custom claims to be set, or null to remove custom claims\n- `tenantId` **[string][mdn-string]** Optional ID of tenant used for multi-tenancy. Can also be set with environment variable TEST_TENANT_ID\n\n##### Examples\n\n```javascript\nconst uid = '123SomeUid';\nconst claims = { role: 'Admin' };\ncy.createUserWithClaims(uid, claims);\n```\n\n#### cy.login\n\nLogin to Firebase using custom auth token.\n\nTo specify a tenant ID, either pass the ID as a parameter to `cy.login`, or set it as environment variable `TEST_TENANT_ID`. Read more about [Firebase multi-tenancy](https://cloud.google.com/identity-platform/docs/multi-tenancy-authentication).\n\n##### Parameters\n\n- `uid` **[string][mdn-string]** UID of user to login as. Can also be set with environment variable TEST_UID\n- `customClaims` **[string][mdn-string]** Optional custom claims to attach to the custom token\n- `tenantId` **[string][mdn-string]** Optional ID of tenant used for multi-tenancy. Can also be set with environment variable TEST_TENANT_ID\n\n##### Examples\n\n_Loading `TEST_UID` automatically from Cypress env_\n\n```javascript\ncy.login();\n```\n\n_Passing a UID_\n\n```javascript\nconst uid = '123SomeUid';\ncy.login(uid);\n```\n\n_Passing a tenant ID_\n\n```javascript\nconst uid = '123SomeUid';\nconst tenantId = '123SomeTenantId';\ncy.login(uid, undefined, tenantId);\n```\n\n#### cy.loginWithEmailAndPassword\n\nLogin to Firebase using an email and password account.\n\n##### Parameters\n\n- `email` **[string][mdn-string]** Email of user to login as. Can also be set with environment variable TEST_EMAIL\n- `password` **[string][mdn-string]** Password of user to login as. Can also be set with environment variable TEST_PASSWORD\n- `extraInfo` **[CreateRequest][firebase-createrequest]** Optional additional CreateRequest parameters except for email and password\n- `tenantId` **[string][mdn-string]** Optional ID of tenant used for multi-tenancy. Can also be set with environment variable TEST_TENANT_ID\n\n##### Examples\n\n_Loading `TEST_EMAIL` and `TEST_PASSWORD` automatically from Cypress env_\n\n```javascript\ncy.loginWithEmailAndPassword();\n```\n\n_Passing an email and password_\n\n```javascript\nconst email = 'some@user.com';\nconst psswd = 'password123';\ncy.loginWithEmailAndPassword(email, psswd);\n```\n\n_Passing a tenant ID_\n\n```javascript\nconst email = 'some@user.com';\nconst psswd = 'password123';\nconst tenantId = '123SomeTenantId';\ncy.loginWithEmailAndPassword(email, psswd, undefined, tenantId);\n```\n\n#### cy.logout\n\nLog out of Firebase instance\n\n##### Parameters\n\n- `tenantId` **[string][mdn-string]** Optional ID of tenant used for multi-tenancy. Can also be set with environment variable TEST_TENANT_ID\n\n##### Examples\n\n```javascript\ncy.logout();\n```\n\n_Passing a tenant ID_\n\n```javascript\nconst tenantId = '123SomeTenantId';\ncy.logout(tenantId);\n```\n\n#### cy.deleteAllAuthUsers\n\nCommand to recursively delete all firebase auth users. The firebase deleteUsers function (cy.authDeleteUsers) can only remove a maximum amount of users at a time. This command calls the deleteUsers function recursively for every pageToken returned by the previous iteration.\n\n##### Parameters\n\n- `tenantId` **[string][mdn-string]** Optional ID of tenant used for multi-tenancy. Can also be set with environment variable TEST_TENANT_ID\n\n##### Examples\n\n```javascript\ncy.deleteAllAuthUsers();\n```\n\n_Passing a tenant ID_\n\n```javascript\nconst tenantId = '123SomeTenantId';\ncy.deleteAllAuthUsers(tenantId);\n```\n\n#### cy.callRtdb\n\nCall Real Time Database path with some specified action such as `set`, `update` and `remove`\n\n##### Parameters\n\n- `action` **[string][mdn-string]** The action type to call with (set, push, update, remove)\n- `actionPath` **[string][mdn-string]** Path within RTDB that action should be applied\n- `options` **[object][mdn-object]** Options\n  - `options.limitToFirst` **[number][mdn-number]|[boolean][mdn-boolean]** Limit to the first `\u003cnum\u003e` results. If true is passed than query is limited to last 1 item.\n  - `options.limitToLast` **[number][mdn-number]|[boolean][mdn-boolean]** Limit to the last `\u003cnum\u003e` results. If true is passed than query is limited to last 1 item.\n  - `options.orderByKey` **[boolean][mdn-boolean]** Order by key name\n  - `options.orderByValue` **[boolean][mdn-boolean]** Order by primitive value\n  - `options.orderByChild` **[string][mdn-string]** Select a child key by which to order results\n  - `options.equalTo` **[string][mdn-string]** Restrict results to `\u003cval\u003e` (based on specified ordering)\n  - `options.startAt` **[string][mdn-string]** Start results at `\u003cval\u003e` (based on specified ordering)\n  - `options.endAt` **[string][mdn-string]** End results at `\u003cval\u003e` (based on specified ordering)\n\n##### Examples\n\n_Set data_\n\n```javascript\nconst fakeProject = { some: 'data' };\ncy.callRtdb('set', 'projects/ABC123', fakeProject);\n```\n\n_Set Data With Meta_\n\n```javascript\nconst fakeProject = { some: 'data' };\n// Adds createdAt and createdBy (current user's uid) on data\ncy.callRtdb('set', 'projects/ABC123', fakeProject, { withMeta: true });\n```\n\n_Set Data With Timestamps_\n\n```javascript\nimport firebase from 'firebase/app';\nimport 'firebase/database';\n\nconst fakeProject = {\n  some: 'data',\n  createdAt: firebase.database.ServerValue.TIMESTAMP,\n};\ncy.callRtdb('set', 'projects/ABC123', fakeProject);\n```\n\nWith [Firebase Web SDK version 9](https://firebase.google.com/docs/web/modular-upgrade)\n\n```javascript\nimport firebase from 'firebase/compat/app';\nimport 'firebase/compat/database';\n\nconst fakeProject = {\n  some: 'data',\n  createdAt: firebase.database.ServerValue.TIMESTAMP,\n};\ncy.callRtdb('set', 'projects/ABC123', fakeProject);\n```\n\n_Delete Data_\n\n```javascript\n// Delete document\ncy.callRtdb('delete', 'projects/ABC123');\n// Delete filtered collection\ncy.callRtdb('delete', 'projects', { where: ['name', '==', 'Test Project'] });\n// Delete whole collection - BE CAREFUL!!\ncy.callRtdb('delete', 'projectsToDelete');\n```\n\n_Get/Verify Data_\n\n```javascript\ncy.callRtdb('get', 'projects/ABC123').then((project) =\u003e {\n  // Confirm new data has users uid\n  cy.wrap(project).its('createdBy').should('equal', Cypress.env('TEST_UID'));\n});\n```\n\n_Other Args_\n\n```javascript\nconst opts = { args: ['-d'] };\nconst fakeProject = { some: 'data' };\ncy.callRtdb('update', 'project/test-project', fakeProject, opts);\n```\n\n#### cy.callFirestore\n\nCall Firestore instance with some specified action. Authentication is through serviceAccount.json since it is at the base\nlevel.\n\n##### Parameters\n\n- `action` **[string][mdn-string]** The action type to call with (set, push, update, delete)\n- `actionPath` **[string][mdn-string]** Path within Firestore that action should be applied\n- `dataOrOptions` **[string][mdn-string]|[object][mdn-object]** Data for write actions or options for get action\n- `options` **[object][mdn-object]** Options\n  - `options.withMeta` **[boolean][mdn-boolean]** Whether or not to include `createdAt` and `createdBy`\n  - `options.merge` **[boolean][mdn-boolean]** Merge data during set\n  - `options.batchSize` **[number][mdn-number]** Size of batch to use while deleting\n  - `options.where` **[array][mdn-array]** Filter documents by the specified field and the value should satisfy\n  * the relation constraint provided\n  - `options.orderBy` **[string][mdn-string]|[array][mdn-array]** Order documents\n  - `options.limit` **[number][mdn-number]** Limit to n number of documents\n  - `options.limitToLast` **[number][mdn-number]** Limit to last n number of documents\n  - `options.statics` **admin.firestore** Firestore statics (i.e. `admin.firestore`). This should only be needed during testing due to @firebase/testing not containing statics\n\n##### Examples\n\n_Basic_\n\n```javascript\ncy.callFirestore('set', 'project/test-project', 'fakeProject.json');\n```\n\n_Set Data With Server Timestamps_\n\n```javascript\nimport firebase from 'firebase/app';\nimport 'firebase/firestore';\n\nconst fakeProject = {\n  some: 'data',\n  // Use new firebase.firestore.Timestamp.now in place of serverTimestamp()\n  createdAt: firebase.firestore.Timestamp.now(),\n  // Or use fromDate if you would like to specify a date\n  // createdAt: firebase.firestore.Timestamp.fromDate(new Date())\n};\ncy.callFirestore('set', 'projects/ABC123', fakeProject);\n```\n\nWith [Firebase Web SDK version 9](https://firebase.google.com/docs/web/modular-upgrade)\n\n```javascript\nimport firebase from 'firebase/compat/app';\nimport 'firebase/compat/firestore';\n\nconst fakeProject = {\n  some: 'data',\n  // Use new firebase.firestore.Timestamp.now in place of serverTimestamp()\n  createdAt: firebase.firestore.Timestamp.now(),\n  // Or use fromDate if you would like to specify a date\n  // createdAt: firebase.firestore.Timestamp.fromDate(new Date())\n};\ncy.callFirestore('set', 'projects/ABC123', fakeProject);\n```\n\n_Full_\n\n```javascript\ndescribe('Test firestore', () =\u003e {\n  const TEST_UID = Cypress.env('TEST_UID');\n  const mockAge = 8;\n\n  beforeEach(() =\u003e {\n    cy.visit('/');\n    cy.callFirestore('delete', 'testCollection');\n  });\n\n  it('read/write test', () =\u003e {\n    cy.log('Starting test');\n\n    cy.callFirestore('set', `testCollection/${TEST_UID}`, {\n      name: 'axa',\n      age: 8,\n    });\n    cy.callFirestore('get', `testCollection/${TEST_UID}`).then((r) =\u003e {\n      cy.log('get returned: ', r);\n      cy.wrap(r).its('data.age').should('equal', mockAge);\n    });\n    cy.log('Ended test');\n  });\n});\n```\n\n#### cy.[authFunction]\n\nUse any of the [firebase admin auth methods](https://firebase.google.com/docs/reference/admin/node/firebase-admin.auth.baseauth#methods):\n\n- `authCreateAuthUser`\n- `authImportAuthUsers`\n- `authListAuthUsers`\n- `authGetAuthUser`\n- `authGetAuthUserByEmail`\n- `authGetAuthUserByPhoneNumber`\n- `authGetAuthUserByProviderUid`\n- `authGetAuthUsers`\n- `authUpdateAuthUser`\n- `authSetAuthUserCustomClaims`\n- `authDeleteAuthUser`\n- `authDeleteAuthUsers`\n- `authCreateCustomToken`\n- `authCreateSessionCookie`\n- `authVerifyIdToken`\n- `authRevokeRefreshTokens`\n- `authGenerateEmailVerificationLink`\n- `authGeneratePasswordResetLink`\n- `authGenerateSignInWithEmailLink`\n- `authGenerateVerifyAndChangeEmailLink`\n- `authGreateProviderConfig`\n- `authGetProviderConfig`\n- `authListProviderConfigs`\n- `authUpdateProviderCondig`\n- `authDeleteProviderConfig`\n\n##### Parameters\n\nThe parameters (and return type) depend on the function used. They are the same as for the firebase api function it refers to, with addition of an optional `tenantId` parameter as last parameter:\n\n- `tenantId` **[string][mdn-string]** Optional ID of tenant used for multi-tenancy. Can also be set with environment variable TEST_TENANT_ID\n\n##### Examples\n\n```javascript\nconst uid = '123SomeUid';\nconst email = 'some@user.com';\ncy.authCreateUser({ uid });\ncy.authUpdateUser(uid, { displayName: 'Test User', email });\ncy.authSetCustomUserClaims(uid, { role: 'admin' });\ncy.authGetUserByEmail(email).then((user) =\u003e {\n  console.log(user?.displayName); // Test User\n  console.log(user?.customClaims?.['role']); // admin\n});\n```\n\n### Plugin\n\nPlugin attaches cypress tasks, which are called by custom commands, and initializes firebase-admin instance. By default cypress-firebase internally initializes firebase-admin using `GCLOUD_PROJECT` environment variable for project identification and application-default credentials (set by providing path to service account in `GOOGLE_APPLICATION_CREDENTIALS` environment variable) [matching Google documentation](https://firebase.google.com/docs/admin/setup#initialize-sdk). This default functionality can be overriden by passing a forth argument to the plugin - this argument is passed directly into the firebase-admin instance as [AppOptions](https://firebase.google.com/docs/reference/admin/dotnet/class/firebase-admin/app-options#constructors-and-destructors) on init which means any other config such as `databaseURL`, `credential`, or `databaseAuthVariableOverride` can be included.\n\n```js\nimport admin from 'firebase-admin';\nimport { defineConfig } from 'cypress';\nimport { plugin as cypressFirebasePlugin } from 'cypress-firebase';\n\nconst cypressConfig = defineConfig({\n  e2e: {\n    baseUrl: 'http://localhost:3000',\n    // NOTE: Make supportFile exists if separate location is provided\n    setupNodeEvents(on, config) {\n      // e2e testing node events setup code\n      return cypressFirebasePlugin(on, config, admin);\n      // NOTE: If not setting GCLOUD_PROJECT env variable, project can be set like so:\n      // return cypressFirebasePlugin(on, config, admin, { projectId: 'some-project' });\n    },\n  },\n});\n\nexport default cypressConfig;\n```\n\n#### Plugin Configuration\n\nA fifth argument is used for further configuration of the plugin.\n\n##### protectProduction\n\nThe plugin tries to detect whether or not the firebase emulators are running, based on the respective environment variables being set or not. When the an emulator isn't running, production could be targeted instead which might be dangerous. The `protectProduction` key configures the behaviour when the emulator for a specific firebase service hasn't been detected. The options for the behaviour when an emalator is not running are:\n\n- `'none'` _(default)_ no protection is granted in this case, nor will a warning be output to the console. Production could be targeted.\n- `'warn'` a warning will be output to the console, but no further protection is granted. Production could be targeted.\n- `'error'` an error is thrown, preventing cypress starting alltogether. This makes sure your production cannot be targeted for this service.\n\n```js\nimport admin from 'firebase-admin';\nimport { defineConfig } from 'cypress';\nimport { plugin as cypressFirebasePlugin } from 'cypress-firebase';\n\nconst cypressConfig = defineConfig({\n  e2e: {\n    baseUrl: 'http://localhost:3000',\n    setupNodeEvents(on, config) {\n      return cypressFirebasePlugin(\n        on,\n        config,\n        admin,\n        {}, // AppOptions override\n        {\n          protectProduction: {\n            // when rtdb emulator isn't detected, a console warning will appear\n            rtdb: 'warn',\n            // plugin will be indifferent to the firestore emulator running or not\n            firestore: 'none',\n            // when auth emulator isn't detected, an error is thrown halting cypress\n            auth: 'error',\n          },\n        },\n      );\n    },\n  },\n});\n\nexport default cypressConfig;\n```\n\n## Recipes\n\n### Using Emulators\n\n1. Install cross-env for cross system environment variable support: `npm i --save-dev cross-env`\n1. Add the following to the `scripts` section of your `package.json`:\n\n   ```json\n   \"emulators\": \"firebase emulators:start --only database,firestore\",\n   \"test\": \"cypress run\",\n   \"test:open\": \"cypress open\",\n   \"test:emulate\": \"cross-env FIREBASE_AUTH_EMULATOR_HOST=\\\"localhost:$(cat firebase.json | jq .emulators.auth.port)\\\" FIREBASE_DATABASE_EMULATOR_HOST=\\\"localhost:$(cat firebase.json | jq .emulators.database.port)\\\" FIRESTORE_EMULATOR_HOST=\\\"localhost:$(cat firebase.json | jq .emulators.firestore.port)\\\" yarn test:open\"\n   ```\n\n1. If not already set by `firebase init`, add emulator ports to `firebase.json`:\n\n   ```json\n   \"emulators\": {\n     \"database\": {\n       \"port\": 9000\n     },\n     \"firestore\": {\n       \"port\": 8080\n     },\n     \"auth\": {\n      \"port\": 9099\n     }\n   }\n   ```\n\n1. Modify your application code to connect to the emulators (where your code calls `firebase.initializeApp(...)`), updating the localhost ports as appropriate from the `emulators` values in the previous step:\n\n   ```js\n   const shouldUseEmulator = window.location.hostname === 'localhost'; // or other logic to determine when to use\n   // Emulate RTDB\n   if (shouldUseEmulator) {\n     fbConfig.databaseURL = `http://localhost:9000?ns=${fbConfig.projectId}`; // from node v17 use 127.0.0.1 instad of localhost\n     console.debug(`Using RTDB emulator: ${fbConfig.databaseURL}`);\n   }\n\n   // Initialize Firebase instance\n   firebase.initializeApp(fbConfig);\n\n   const firestoreSettings = {};\n   // Pass long polling setting to Firestore when running in Cypress\n   if (window.Cypress) {\n     // Needed for Firestore support in Cypress (see https://github.com/cypress-io/cypress/issues/6350)\n     firestoreSettings.experimentalForceLongPolling = true;\n   }\n\n   // Emulate Firestore\n   if (shouldUseEmulator) {\n     firestoreSettings.host = 'localhost:8080';\n     firestoreSettings.ssl = false;\n     console.debug(`Using Firestore emulator: ${firestoreSettings.host}`);\n\n     firebase.firestore().settings(firestoreSettings);\n   }\n\n   // Emulate Auth\n   if (shouldUseEmulator) {\n     firebase.auth().useEmulator(`http://localhost:9099/`);\n     console.debug(`Using Auth emulator: http://localhost:9099/`);\n   }\n   ```\n\n1. Make sure you also have init logic in `cypress/support/commands.js` or `cypress/support/index.js`:\n\nWith [Firebase Web SDK versions up to 8](https://firebase.google.com/docs/web/modular-upgrade)\n\n```js\nimport firebase from 'firebase/app';\nimport 'firebase/auth';\nimport 'firebase/database';\nimport 'firebase/firestore';\nimport { attachCustomCommands } from 'cypress-firebase';\n\nconst fbConfig = {\n  // Your Firebase Config\n};\n\n// Emulate RTDB if Env variable is passed\nconst rtdbEmulatorHost = Cypress.env('FIREBASE_DATABASE_EMULATOR_HOST');\nif (rtdbEmulatorHost) {\n  fbConfig.databaseURL = `http://${rtdbEmulatorHost}?ns=${fbConfig.projectId}`;\n}\n\nfirebase.initializeApp(fbConfig);\n\n// Emulate Firestore if Env variable is passed\nconst firestoreEmulatorHost = Cypress.env('FIRESTORE_EMULATOR_HOST');\nif (firestoreEmulatorHost) {\n  firebase.firestore().settings({\n    host: firestoreEmulatorHost,\n    ssl: false,\n  });\n}\n\nconst authEmulatorHost = Cypress.env('FIREBASE_AUTH_EMULATOR_HOST');\nif (authEmulatorHost) {\n  firebase.auth().useEmulator(`http://${authEmulatorHost}/`);\n  console.debug(`Using Auth emulator: http://${authEmulatorHost}/`);\n}\n\nattachCustomCommands({ Cypress, cy, firebase });\n```\n\nWith [Firebase Web SDK version 9](https://firebase.google.com/docs/web/modular-upgrade) in compat mode (same API as v8 with different import)\n\n```js\nimport firebase from 'firebase/compat/app';\nimport 'firebase/compat/auth';\nimport 'firebase/compat/database';\nimport 'firebase/compat/firestore';\nimport { attachCustomCommands } from 'cypress-firebase';\n\nconst fbConfig = {\n  // Your Firebase Config\n};\n\n// Emulate RTDB if Env variable is passed\nconst rtdbEmulatorHost = Cypress.env('FIREBASE_DATABASE_EMULATOR_HOST');\nif (rtdbEmulatorHost) {\n  fbConfig.databaseURL = `http://${rtdbEmulatorHost}?ns=${fbConfig.projectId}`;\n}\n\nfirebase.initializeApp(fbConfig);\n\n// Emulate Firestore if Env variable is passed\nconst firestoreEmulatorHost = Cypress.env('FIRESTORE_EMULATOR_HOST');\nif (firestoreEmulatorHost) {\n  firebase.firestore().settings({\n    host: firestoreEmulatorHost,\n    ssl: false,\n  });\n}\n\nconst authEmulatorHost = Cypress.env('FIREBASE_AUTH_EMULATOR_HOST');\nif (authEmulatorHost) {\n  firebase.auth().useEmulator(`http://${authEmulatorHost}/`);\n  console.debug(`Using Auth emulator: http://${authEmulatorHost}/`);\n}\n\nattachCustomCommands({ Cypress, cy, firebase });\n```\n\n1. Start emulators: `npm run emulators`\n1. In another terminal window, start the application: `npm start`\n1. In another terminal window, open test runner with emulator settings: `npm run test:emulate`\n\n**NOTE**: If you are using `react-scripts` (from [create-react-app](https://reactjs.org/docs/create-a-new-react-app.html)) or other environment management, you can use environment variables to pass settings into your app:\n\n```js\nconst {\n  REACT_APP_FIREBASE_DATABASE_EMULATOR_HOST,\n  REACT_APP_FIRESTORE_EMULATOR_HOST,\n} = process.env;\n\n// Emulate RTDB if REACT_APP_FIREBASE_DATABASE_EMULATOR_HOST exists in environment\nif (REACT_APP_FIREBASE_DATABASE_EMULATOR_HOST) {\n  console.debug(`Using RTDB emulator: ${fbConfig.databaseURL}`);\n  fbConfig.databaseURL = `http://${REACT_APP_FIREBASE_DATABASE_EMULATOR_HOST}?ns=${fbConfig.projectId}`;\n}\n\n// Initialize Firebase instance\nfirebase.initializeApp(fbConfig);\n\nconst firestoreSettings = {};\n\nif (window.Cypress) {\n  // Needed for Firestore support in Cypress (see https://github.com/cypress-io/cypress/issues/6350)\n  firestoreSettings.experimentalForceLongPolling = true;\n}\n\n// Emulate RTDB if REACT_APP_FIRESTORE_EMULATOR_HOST exists in environment\nif (REACT_APP_FIRESTORE_EMULATOR_HOST) {\n  firestoreSettings.host = REACT_APP_FIRESTORE_EMULATOR_HOST;\n  firestoreSettings.ssl = false;\n\n  console.debug(`Using Firestore emulator: ${firestoreSettings.host}`);\n\n  firebase.firestore().settings(firestoreSettings);\n}\n```\n\n### Use Different RTDB Instance\n\nFirebase instance config can be overriden by passing another argument to the cypress-firebase plugin. We can use this to override the `databaseURL`:\n\n1. Setup the config within plugin (`cypress/plugins/index.js`):\n\n   ```js\n   const admin = require('firebase-admin');\n   const cypressFirebasePlugin = require('cypress-firebase').plugin;\n\n   module.exports = (on, config) =\u003e {\n     const overrideFirebaseConfig = {\n       databaseURL: 'http://localhost:9000?ns=my-other-namespace',\n     };\n     const extendedConfig = cypressFirebasePlugin(\n       on,\n       config,\n       admin,\n       overrideFirebaseConfig,\n     );\n\n     // Add other plugins/tasks such as code coverage here\n\n     return extendedConfig;\n   };\n   ```\n\n1. Make sure you use the same `databaseURL` when initializing the firebase instance within cypress (`cypress/support/index.js`)\n1. Make sure you use the same `databaseURL` when initializing the firebase instance within your app code\n\n### Test Built Version\n\nIt is often required to run tests against the built version of your app instead of your dev version (with hot module reloading and other dev tools). You can do that by running a build script before spinning up the:\n\n1. Adding the following npm script:\n   ```json\n   \"start:dist\": \"npm run build \u0026\u0026 firebase emulators:start --only hosting\",\n   ```\n1. Add the emulator port to `firebase.json`:\n   ```json\n   \"emulators\": {\n     \"hosting\": {\n       \"port\": 3000\n     }\n   }\n   ```\n1. Run `npm run start:dist` to build your app and serve it with firebase\n1. In another terminal window, run a test command such as `npm run test:open`\n\nNOTE: You can also use `firebase serve`:\n\n```json\n\"start:dist\": \"npm run build \u0026\u0026 firebase serve --only hosting -p 3000\",\n```\n\n### Changing Custom Command Names\n\nPass `commandNames` in the `options` object to `attachCustomCommands`:\n\n```js\nconst options = {\n  // Key is current command name, value is new command name\n  commandNames: {\n    login: 'newNameForLogin',\n    logout: 'newNameForLogout',\n    callRtdb: 'newNameForCallRtdb',\n    callFirestore: 'newNameForCallFirestore',\n    getAuthUser: 'newNameForGetAuthUser',\n  },\n};\nattachCustomCommands({ Cypress, cy, firebase }, options);\n```\n\nFor more information about this feature, please see the [original feature request](https://github.com/prescottprue/cypress-firebase/issues/15).\n\n### Webpack File Preprocessing\n\nIf you are using a file preprocessor which is building for the browser environment, such as Webpack, you will need to make sure usage of `fs` is handled since it is used within the cypress-firebase plugin. To do this with webpack, add the following to your config:\n\n```js\nnode: {\n  fs: 'empty';\n}\n```\n\nSee [#120](https://github.com/prescottprue/cypress-firebase/issues/120) for more info\n\n## Examples\n\n### Github Actions\n\n**Separate Install**\n\n```yml\nname: Test Build\n\non: [pull_request]\n\njobs:\n  ui-tests:\n    name: UI Tests\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v2\n\n      # Cypress action manages installing/caching npm dependencies and Cypress binary.\n      - name: Cypress Run\n        uses: cypress-io/github-action@v2\n        with:\n          group: 'E2E Tests'\n        env:\n          # pass the Dashboard record key as an environment variable\n          CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_KEY }}\n          # UID of User to login as during tests\n          CYPRESS_TEST_UID: ${{ secrets.TEST_UID }}\n          # Service Account (used for creating custom auth tokens)\n          SERVICE_ACCOUNT: ${{ secrets.SERVICE_ACCOUNT }}\n          # Branch settings\n          GITHUB_HEAD_REF: ${{ github.head_ref }}\n          GITHUB_REF: ${{ github.ref }}\n```\n\n**Using Start For Local**\n\n```yml\nname: Test\n\non: [pull_request]\n\njobs:\n  ui-tests:\n    name: UI Tests\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v2\n\n      # Cypress action manages installing/caching npm dependencies and Cypress binary\n      - name: Cypress Run\n        uses: cypress-io/github-action@v2\n        with:\n          group: 'E2E Tests'\n          start: npm start\n          wait-on: http://localhost:3000\n        env:\n          # pass the Dashboard record key as an environment variable\n          CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_KEY }}\n          # UID of User to login as during tests\n          CYPRESS_TEST_UID: ${{ secrets.TEST_UID }}\n          # Service Account (used for creating custom auth tokens)\n          SERVICE_ACCOUNT: ${{ secrets.SERVICE_ACCOUNT }}\n          # Branch settings\n          GITHUB_HEAD_REF: ${{ github.head_ref }}\n          GITHUB_REF: ${{ github.ref }}\n```\n\n## Why?\n\nWhen testing, tests should have admin read/write access to the database for seeding/verifying data. It isn't currently possible to use Firebase's `firebase-admin` SDK directly within Cypress tests due to dependencies not being able to be loaded into the Browser environment. Since the admin SDK is necessary to generate custom tokens and interact with Real Time Database and Firestore with admin privileges, this library provides convenience methods (`cy.callRtdb`, `cy.callFirestore`, `cy.login`, etc...) which call custom tasks which have access to the node environment.\n\n## Projects Using It\n\n- [fireadmin.io][fireadmin-url] - A Firebase project management tool ([here is the source][fireadmin-source])\n- [cv19assist.com](https://cv19assist.com) - App for connecting volunteers with at-health-risk population during the coronavirus pandemic. ([here is the source](https://github.com/CV19Assist/app))\n\n## Troubleshooting\n\n1. An error is coming from cypress mentioning \"Error converting circular structure to JSON\"\n\nThe issue is most likely due to a circular object, such as a timestamp, being included in data you are attempting to write to Firestore. Instead of using `firebase.firestore.FieldValue.serverTimestamp()` you should instead use `firebase.firestore.Timestamp.now()` or you would like to specify a certain date `firebase.firestore.Timestamp.fromDate(new Date('01/01/18'))`.\n\nThis comes from the fact that cypress stringifies values as it is passing them from the browser environment to the node environment through `cy.task`.\n\n1. An error is causing tests to fail mentioning \"firebaseinstallations.googleapis.com blocked by CORS policy\"\n\nThis has to do with the Firebase JS SDK having problems calling a Google API - this issue has mostly been seen with older versions of Firebase SDK (pre v8) when being tested on Firebase Hosting (as opposed to a local server).\n\nThe following should help prevent the issue from failing tests:\n\n```js\nCypress.on('uncaught:exception', (err) =\u003e {\n  // Prevent test failure from errors from firebase installations API\n  return err.message.includes('firebaseinstallations.googleapis.com');\n});\n```\n\nIf you experience this with an SDK version newer than v7 please create a new issue.\n\n## Future Plans\n\n- firebase-admin v10 module support\n- Drop support for service account file in favor of application default credentails env variable (path to file set in `GOOGLE_APPLICATION_CREDENTIALS`)\n- Support for Auth emulators (this will become the suggested method instead of needing a service account)\n\n[createUserWClaims]: #cycreateuserwithclaims\n[createUserWClaims-params]: #parameters\n[createUserWClaims-ex]: #examples\n[login]: #cylogin\n[login-params]: #parameters-1\n[login-ex]: #examples-1\n[loginEmail]: #cyloginwithemailandpassword\n[loginEmail-params]: #parameters-2\n[loginEmail-ex]: #examples-2\n[currentUser]: #currentuser\n[logout]: #cylogout\n[logout-params]: #parameters-3\n[logout-ex]: #examples-3\n[delAllUsers]: #cydeleteallauthusers\n[delAllUsers-params]: #examples-4\n[delAllUsers-ex]: #examples-4\n[callRtdb]: #cycallrtdb\n[callRtdb-params]: #parameters-5\n[callRtdb-ex]: #examples-5\n[callFirestore]: #cycallfirestore\n[callFirestore-params]: #parameters-6\n[callFirestore-ex]: #examples-6\n[authFunctions]: #cyauthfunction\n[authFunctions-params]: #parameters-7\n[authFunctions-ex]: #examples-7\n[mdn-string]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String\n[mdn-number]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number\n[mdn-boolean]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean\n[mdn-object]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object\n[mdn-array]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array\n[mdn-null]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/null\n[firebase-createrequest]: https://firebase.google.com/docs/reference/admin/node/firebase-admin.auth.createrequest.md#createrequest_interface\n[fireadmin-url]: https://fireadmin.io\n[fireadmin-source]: https://github.com/prescottprue/fireadmin\n[npm-image]: https://img.shields.io/npm/v/cypress-firebase.svg?style=flat-square\n[npm-url]: https://npmjs.org/package/cypress-firebase\n[npm-downloads-image]: https://img.shields.io/npm/dm/cypress-firebase.svg?style=flat-square\n[build-status-image]: https://img.shields.io/github/actions/workflow/status/prescottprue/cypress-firebase/publish.yml?branch=main\u0026style=flat-square\n[build-status-url]: https://github.com/prescottprue/cypress-firebase/actions/workflows/publish.yml\n[coverage-image]: https://img.shields.io/codecov/c/gh/prescottprue/cypress-firebase?style=flat-square\u0026logo=codecov\n[coverage-url]: https://codecov.io/gh/prescottprue/cypress-firebase\n[license-image]: https://img.shields.io/npm/l/cypress-firebase.svg?style=flat-square\n[license-url]: https://github.com/prescottprue/cypress-firebase/blob/master/LICENSE\n[code-style-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square\n[code-style-url]: http://standardjs.com/\n[semantic-release-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square\n[semantic-release-url]: https://github.com/semantic-release/semantic-release\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprescottprue%2Fcypress-firebase","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprescottprue%2Fcypress-firebase","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprescottprue%2Fcypress-firebase/lists"}