firebase / firebase-js-sdk

Firebase Javascript SDK
https://firebase.google.com/docs/web/setup
Other
4.8k stars 884 forks source link

ReferenceError: self is not defined on Jest tests firebase@10.12.3 #8365

Closed atomassoni closed 1 month ago

atomassoni commented 1 month ago

Operating System

iOS 16+

Browser Version

Chrome latest

Firebase SDK Version

10.12.3

Firebase SDK Product:

Analytics, Auth, Firestore, Functions, Remote-Config

Describe your project's tooling

Ionic Stencil app with Jest

Describe the problem

Running Jest tests I got this error anywhere I had imported firebase, I'm using the emulator on jest. Here is my command:

"test.ci": "firebase emulators:exec --only firestore 'stencil test --spec --ci --coverage --exit'",

Rolling back to firebase@10.12.2 fixed the issue.

FAIL src/components/pages/sw-subscribe-success-page/sw-subscribe-success-page.spec.ts
  ● Test suite failed to run
    ReferenceError: self is not defined
       9 | import { Analytics, getAnalytics } from "firebase/analytics"
    > 11 | import firebaseCompat from "firebase/compat/app"
         | ^
      12 | import "firebase/compat/auth"
      13 | import "firebase/compat/firestore"
      14 | import "firebase/compat/functions"
      at Object.<anonymous> (node_modules/@firebase/app-compat/src/index.ts:26:21)
      at Object.<anonymous> (node_modules/firebase/compat/app/dist/index.cjs.js:3:16)
      at Object.require (src/global/firebase.ts:11:1)
      at Object.require (src/global/native.ts:4:1)
      at Object.require (src/global/workout-utils.ts:2:1)
      at Object.require (src/reducers/edit-workout.ts:2:1)
      at Object.require (src/reducers/index.ts:5:1)
      at Object.require (src/store/index.ts:3:1)
      at Object.require (src/components/pages/sw-subscribe-success-page/sw-subscribe-success-page.tsx:3:1)
      at Object.<anonymous> (src/components/pages/sw-subscribe-success-page/sw-subscribe-success-page.spec.ts:1:1)

Steps and code to reproduce issue

For our app I can update from Firebase 10.12.2 to 10.12.3 to trigger the error. Rolling back to 10.12.2 fixes it.

google-oss-bot commented 1 month ago

I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.

hsubox76 commented 1 month ago

May be related to https://github.com/firebase/firebase-js-sdk/pull/8315. The change seems to cause isBrowser() to pass in this environment where it previously failed, which causes this check: https://github.com/firebase/firebase-js-sdk/blob/master/packages/app-compat/src/index.ts#L26 to no longer short-circuit on the first condition, but continue to the second, where it fails to find global self. Need to check which of these assumptions is wrong.

Edit: Jest runs in Node so self doesn't exist. However, because it's using JSDOM to mimic the DOM for browser tests, window does exist. I guess we should probably leave isBrowser() as is, because when you're running Jest in JSDOM mode, you do want it to pass the isBrowser() check as it's pretending to be a browser. We should probably fix the (self as any).firebase check.

hsubox76 commented 1 month ago

Actually I looked further into this and it looks like Jest is supposed to have self, if you are using JSDOM mode. https://stackoverflow.com/questions/68678854/jest-test-suite-fails-with-message-self-is-not-defined

I'm not actually sure what kind of environment you have where window exists but self doesn't. I've tried to reproduce using the latest version of Jest, using both the node and jsdom testEnvironments. Can you share your Jest config? What Jest version are you using?

atomassoni commented 1 month ago

Hi, I'm using the @stencil preset "jest": { "preset": "@stencil/core/testing", }

with jest 29.

  "@types/jest": "^29.5.11",
    "jest": "^29.7.0",
    "jest-cli": "^29.7.0",

Now get this:

I tried rolling back my @stencil/core version from the latest 4.19.2 to what I was using before which was version 4.12.0 and that ALSO fixed the issue with the latest version of firebase. There are some reports on the stencil github of errors on the latest version, so maybe I'll file a bug with them if I could get a clearer picture of what's happening.

Sorry, I got ahead of myself. I rolled stencil forward and back again and I could not "reproduce" the fix. I double checked and the version of Firebase was actually rolled back which caused it to function with both versions of Stencil.

hsubox76 commented 1 month ago

Looks like stencil does not use either Jest's provided jest-environment-node nor jest-environment-jsdom for the Jest test environment but creates a custom one https://github.com/ionic-team/stencil/blob/main/src/testing/jest/jest-29/jest-environment.ts

The custom environment is built off of Jest's jest-environment-node which, due to being for Node, has neither self nor window. If you were using Jest's jest-environment-jsdom it would inject both window and self into the global scope, as both should exist in a simulated browser environment. I'm guessing that when stencil's custom environment calls puppeteer to set up the simulated browser, it only adds window and not self. I don't think that's an accurately simulated browser environment if it's missing self so I think it might be a bug on stencil/puppeteer's end?

In your case, maybe a quick hacky workaround would be to assign const self = window anywhere in the global scope of your tests, like at the top of the test file, or if you have any kind of pre-test setup function, or if there's a way to inject it into the test environment config.