Skip to content

Jest testing failing with new import entry points #1465

Closed

Description

@Brian-McBride

Enviornment

  • Operating System version: Mac OS 11.6
  • Firebase SDK version: 10.0.0
  • Firebase Product: auth, firestore, (probably all)
  • Node.js version: 16.0.0
  • NPM version: 8.0.0

Unable to use new imports with Jest for testing

Unable to use new imports with Jest for testing.
When using Jest on a very, very simple project we get one error.
On a more complex project, ESM errors start arriving.

I'm pretty sure all this is around Babel and how it is not grabbing the correct setup around how this lib exposed the experimental ESM syntax.

###- Problem One

Jest fails on a very simple project.

Error

 FAIL  src/example.test.ts
  ● Test suite failed to run

    Cannot find module 'firebase-admin/app' from 'src/example.ts'

    Require stack:
      src/example.ts
      src/example.test.ts

    > 1 | import { initializeApp, applicationDefault, App } from 'firebase-admin/app';
        | ^
      2 | import {
      3 |   getFirestore,
      4 |   Firestore,

      at Resolver.resolveModule (node_modules/jest-resolve/build/resolver.js:322:11)
      at Object.<anonymous> (src/example.ts:1:1)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        2.489 s

Steps to reproduce:

Created a new project. Steps VERY basic:

mkdir fail-example
cd fail-example
npm init -y
npx tsc --init
npm i -D jest ts-jest @types/jest
npm i firebase-admin

I've created a function:

import { initializeApp, applicationDefault, App } from 'firebase-admin/app';

export const getFirebaseApp = (): App => {
  const app = initializeApp({
    credential: applicationDefault(),
  });
  return app;
};

And the Jest test:

import { getFirebaseApp } from './example';

describe('Testing firebase-admin imports', () => {
  it('Should import a firebase instance without a problem', () => {
    const result = getFirebaseApp();
    expect(result).toBeDefined();
  });
});

###- Problem Two

I have a MUCH more complex project using nrwl/nx for mono-repo support.
My tsconfig files and overall config are more complex.
This starts to fail around ES Modules

error

 FAIL   server-database  libs/server/database/src/lib/firebase.spec.ts
  ● Test suite failed to run

    Jest encountered an unexpected token

    Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.

    Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.

    By default "node_modules" folder is ignored by transformers.

    Here's what you can do:
     • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
     • If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/configuration
    For information about custom transformations, see:
    https://jestjs.io/docs/code-transformation

    Details:

    /Users/brian/Development/yet-another-project/graphql-core/node_modules/firebase-admin/lib/auth/index.d.ts:22
    import { App } from '../app/index';
    ^^^^^^

    SyntaxError: Cannot use import statement outside a module

Activity

  1. Brian-McBride commented on Oct 15, 2021

    @Brian-McBride
    Author

    I'll add to that with v10 the old import style will work.

    import * as firebase from 'firebase-admin';
    
    export const getFirebaseApp = (): firebase.app.App => {
      const app = firebase.initializeApp({
        credential: firebase.credential.applicationDefault(),
      });
      return app;
    };

    That works as expected.

    For the heck of it, I also went through all the JEST steps to set up ES module support. When I did that, the error vanished. HOWEVER, every import returned undefined.

    That I mean, literally every function imported from firebase-admin was undefined when using node --experimental-vm-modules and setting up ts-jest using ESM as well.

  2. hiranya911 commented on Oct 15, 2021

    @hiranya911
    Contributor

    Problem 1

    Probably has to do something with how jest resolves modules. The same exact code works fine with Mocha. Do you know anything about how jest module resolution works, or how we can configure it? As far as our library is concerned, we declare both exports and the typeVersions in our package.json file as required by NPM. It seems Jest just ignores all that, and only looks at the main module, which is still set to the old firebase-admin entry point.

    Problem 2

    SyntaxError: Cannot use import statement outside a module
    

    This is saying that you're using import in a file that is not recognized as a module. You will have to setup your project accordingly. See Node.js docs: https://nodejs.org/api/packages.html#packages_modules_packages

  3. hiranya911 commented on Oct 15, 2021

    @hiranya911
    Contributor

    I believe this is related: jestjs/jest#9771

    Basically their resolver doesn't support multiple module entry points of dependencies. But it looks like they have plans to address it. In the meantime you will have to use the old namespaced API, or implement one of the workarounds mentioned in the above issue.

    Update: FWIW, I tried the workaround discussed in the following comment, and it worked for me: jestjs/jest#9771 (comment)

    % npx jest example.test.ts
     PASS  ./example.test.ts
      Testing firebase-admin imports
        ✓ Should import a firebase instance without a problem (2 ms)
    
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        0.539 s, estimated 1 s
    
  4. Brian-McBride commented on Oct 15, 2021

    @Brian-McBride
    Author

    @hiranya911 Thank you for finding this.
    It does seem that Jest 28 will include proper resolving.

    A solution that covers more edge cases is here:
    https://github.com/k-g-a/jest-node-exports-resolver

    I used the information provided from these links to create this:
    https://gist.github.com/Brian-McBride/ab81588f1278aa7708ca3a36c01d8d49

    So far, I have firebase-admin working in Nx monorepo.

  5. hiranya911 commented on Oct 21, 2021

    @hiranya911
    Contributor

    Closing this since there's no concrete action items for this repo.

  6. mikehardy commented on Oct 21, 2021

    @mikehardy

    Just worked around this myself using a trick from the linked jest issue:

    yarn add jest-node-exports-resolver -D coupled with resolver: 'jest-node-exports-resolver', in jest.config.js, a happy surprise it was so easy, thanks to https://github.com/k-g-a/jest-node-exports-resolver

  7. yairopro commented on Dec 2, 2021

    @yairopro

    Thanks @mikehardy !

  8. tettoffensive commented on Apr 15, 2022

    @tettoffensive

    @mikehardy Didn't work for me with firebase/auth. Maybe it's somehow different from firebase-admin? I'm getting:

    Jest encountered an unexpected token
    
     ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export * from '@firebase/auth';
                                                                                          ^^^^^^
    
        SyntaxError: Unexpected token 'export'
    
    import { getAuth } from 'firebase/auth';

    Perhaps this will still be fixed in jest 28

  9. mikehardy commented on Apr 15, 2022

    @mikehardy

    Firebase/auth and firebase admin are definitely different SDKs, that much I know. Thus is still working for me for admin SDK at least

  10. why-not-try-calmer commented on May 5, 2022

    @why-not-try-calmer

    resolver: 'jest-node-exports-resolver',

    Awesome, thanks for adding this, this is the best solution so far.

  11. chiubaka commented on Jun 4, 2022

    @chiubaka

    In case anyone else is having this issue, I tried @mikehardy's fix, but found that this messed with resolution of ts-jest for some reason. Might have something to do with my monorepo setup.

    Ultimately, I was able to get past this by upgrading to the latest version of jest and ts-jest. Seems like newer version of jest have updates to the resolver (or dependency resolver libraries) that fix this issue.

    At time of writing, I'm now on jest v28.1.0 and ts-jest v28.0.4. When I was having issues, I was on jest v26.6.3 and ts-jest v26.4.3.

  12. TheCeloReis commented on Jun 10, 2022

    @TheCeloReis

    I found a much simpler solution, just moduleNameMapper the issue. In my case since I was only using the app and auth submodules, so I made these changes:

    jest.config.ts

      moduleNameMapper: {
        "^firebase-admin/app$":
          "<rootDir>/node_modules/firebase-admin/lib/app/index.js",
        "^firebase-admin/auth$":
          "<rootDir>/node_modules/firebase-admin/lib/auth/index.js",
      },
  13. iankitverma commented on Jun 16, 2022

    @iankitverma

    Did you a solution?

  14. unshame commented on Jul 1, 2022

    @unshame

    I ended up adopting a solution from here: microsoft/accessibility-insights-web#5421 (comment) which is adding a custom resolver:

    // Copyright (c) Microsoft Corporation. All rights reserved.
    // Licensed under the MIT License.
    
    // Taken from
    // https://github.com/microsoft/accessibility-insights-web/pull/5421#issuecomment-1109168149
    
    module.exports = (path, options) => {
        const firebaseRegex = /^@?firebase/;
    
        // Call the defaultResolver, so we leverage its cache, error handling, etc.
        return options.defaultResolver(path, {
            ...options,
            // Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb)
            packageFilter: (pkg) => {
                if (firebaseRegex.test(pkg.name)) {
                    delete pkg.exports;
                    delete pkg.module;
                    delete pkg.browser;
                }
    
                return pkg;
            },
        });
    };
  15. Deliaz commented on Jul 17, 2022

    @Deliaz

    Hi @tettoffensive,
    I am having the same issue and none of the advice listed above helped so far.
    May I know if you happened to find a solution?

  16. IchordeDionysos commented on Jul 29, 2022

    @IchordeDionysos
    Contributor

    Updating to Jest 28 helps :)

  17. faces-of-eth commented on Aug 1, 2022

    @faces-of-eth

    Having this same issue in a monorepo with Next.js 12.2.3, typescript 4.7.4, jest 28.1.3, and firebase 9.9.1. Tried all above things, and I get to a point where it clears the issues with firebase using the custom resolvers posted above.

    Stuck on importing a @font-face now :(

        /node_modules/@fontsource/unifrakturmaguntia/index.css:2
        @font-face {
        ^
    
        SyntaxError: Invalid or unexpected token
    
          16 |   sm: '40em',
          17 |   md: '52em',
        > 18 |   lg: '64em',
             | ^
          19 |   xl: '80em',
          20 | });
          21 |
    
  18. pasindu-pr commented on Feb 3, 2023

    @pasindu-pr

    @tettoffensive, @Deliaz, Did you find any solution for this case? I'm having the exact same issue.

  19. tran-simon commented on Jul 4, 2025

    @tran-simon

    I had a similar issue with firebase/auth and firebase/firestore

    Adding this to my jest.config.js fixed the issue:

      moduleNameMapper: {
        'firebase/auth': require.resolve('firebase/auth'),
        'firebase/firestore': require.resolve('firebase/firestore'),
      }
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions