简体   繁体   中英

Create a user programatically using Firebase Auth emulator

I am trying to write jest tests using the Firebase Auth emulator and continue to receive the following CORS error.

console.error
    Error: Headers X-Client-Version forbidden
        at dispatchError (/Users/me/my-project/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js:62:19)
        at validCORSPreflightHeaders (/Users/me/my-project/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js:99:5)
        at Request.<anonymous> (/Users/me/my-project/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js:367:12)
        at Request.emit (events.js:315:20)
        at Request.onRequestResponse (/Users/me/my-project/node_modules/request/request.js:1059:10)
        at ClientRequest.emit (events.js:315:20)
        at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:641:27)
        at HTTPParser.parserOnHeadersComplete (_http_common.js:126:17)
        at Socket.socketOnData (_http_client.js:509:22)
        at Socket.emit (events.js:315:20) undefined

The test is very simple:

import { renderHook, act } from "@testing-library/react-hooks"
import faker from "faker"
import { useAuth, FirebaseProvider, firebase } from "./index"


const wrapper = ({ firebase, children }) => {
  return <FirebaseProvider firebase={firebase}>{children}</FirebaseProvider>
}

const createUser = ({ email = faker.internet.email(), password = faker.internet.password({ length: 6 }) } = {}) => {
  return firebase
    .auth()
    .createUserWithEmailAndPassword(email, password)
    .then(user => user)
}

const signUserIn = ({ email, password } = {}) => {
  return firebase
    .auth()
    .signInWithEmailAndPassword(email, password)
    .then(user => user)
}

describe("useAuth", () => {
  it("will return the user", async () => {
    const { result } = renderHook(() => useAuth(), { wrapper, initialProps: { firebase } })
    const email = faker.internet.email()
    const password = faker.internet.password()
    await act(async () => {
      const user = await createUser({ email, password }) // this fails
      await signUserIn({ email, password }) //and so does this
    })
    expect(result.user).toEqual({ email, password })
  })
})

And for reference, the index file:

const FirebaseProvider = ({ children, firebase }) => {
  const firestore = firebase.firestore()
  const auth = firebase.auth()

  if (useEmulator()) {
    firestore.useEmulator("localhost", 8080)
    auth.useEmulator("http://localhost:9099/")
  }

  const value = { firestore, auth }

  return <FirebaseContext.Provider value={value}>{children}</FirebaseContext.Provider>
}

const throwError = hook => {
  throw new Error(`${hook} must be used within a FirebaseProvider`)
}

const useAuth = () => {
  const context = useContext(FirebaseContext)
  if (context === undefined) throwError("useAuth")

  const [user, setUser] = useState()

  useEffect(() => {
    const cleanup = context.auth.onAuthStateChanged(authUser => {
      authUser ? setUser(authUser) : setUser(null)
    })
    return () => cleanup()
  })

  return { ...context.auth, user }
}

I have tried using the REST endpoint that the actual emulator uses (below) and it errors in the same way.

http://localhost:9099/identitytoolkit.googleapis.com/v1/projects/<my-project>/accounts

Is there anyway to get this to run when using jest? Or do I need to create the accounts using the emulator UI, export them and re-import when I am running tests?

I have found I can use the REST endpoint below to make a user in the test, however it bypasses the emulator and makes a real user.

https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=<api-key>

Update jsdom version 16.5.2

This new version now supports wildcards for access-control-allow-headers, so updating to this version or using it as resolution, for projects created with Create React App, solves the problem.

Solution for jsdom prior to version 16.5.2

The error is thrown by jsdom because it doesn't support wildcard for access-control-allow-headers, but firebase uses the wildcard (see this issue for jsdom and this pull request related to firebase ). There are two open pull requests to fix this issue: https://github.com/jsdom/jsdom/pull/3073 and https://github.com/jsdom/jsdom/pull/2867 .

The issue can be fixed by either changing the relevant code manually in the node_modules folder or by using the fork as dependency in the package.json :

"jsdom": "silviot/jsdom#fix/allow-headers"

If jsdom isn't a direct dependency, then you can add the following to the package.json at the top level:

"resolutions": {
  "jsdom": "silviot/jsdom#fix/allow-headers"
}

If the fork is used there are some auto-generated files missing in the jsdom folder. These can be generated by running npm install or yarn install in the folder. To automate this you can add a prepare script to the package.json :

"scripts": {
  "prepare": "cd node_modules/jsdom && yarn"
},

I also had problems making users programaticly in the firebase auth emulator.

Instead of using

https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]

You have to use the following format:

http://localhost:9099/identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]

Then giving a JSON body like this, and hit post

{
"email": "test@test.com",
"password": "test12"
}

And voila. You have a user in your emulator. Combine this with fetch or axios and you seed your emulator with users, If you need to add custom claims or other info. create function in the functions emulator that triggers on user creation.

functions.auth.user().onCreate

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM