Skip to content

Error Setting Up jest.mock("@react-native-async-storage/async-storage") #849

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 of 5 tasks
Silthus opened this issue Oct 11, 2022 · 13 comments · Fixed by #865
Closed
1 of 5 tasks

Error Setting Up jest.mock("@react-native-async-storage/async-storage") #849

Silthus opened this issue Oct 11, 2022 · 13 comments · Fixed by #865
Labels
bug Something isn't working

Comments

@Silthus
Copy link

Silthus commented Oct 11, 2022

What happened?

I just upgraded my dependencies and now I get the following error during my setup when running jest:

  ● Test suite failed to run                                                                                                                                                                                                                                                          

    ReferenceError: C:\dev\projects\climbers-atlas\ClimbersAtlas\test\setup.ts: The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.
    Invalid variable access: async_storage_mock_1
    Allowed objects: AbortController, AbortSignal, AggregateError, Array, ArrayBuffer, Atomics, BigInt, BigInt64Array, BigUint64Array, Boolean, Buffer, DataView, Date, Error, EvalError, Event, EventTarget, FinalizationRegistry, Float32Array, Float64Array, Function, Generator, GeneratorFunction, Infinity, Int16Array, Int32Array, Int8Array, InternalError, Intl, JSON, Map, Math, MessageChannel, MessageEvent, MessagePort, NaN, Number, Object, Promise, Proxy, RangeError, ReferenceError, Reflect, RegExp, Set, SharedArrayBuffer, String, Symbol, SyntaxError, TextDecoder, TextEncoder, TypeError, URIError, URL, URLSearchParams, Uint16Array, Uint32Array, Uint8Array, Uint8ClampedArray, WeakMap, WeakRef, WeakSet, WebAssembly, __dirname, __filename, arguments, atob, btoa, clearImmediate, clearInterval, clearTimeout, console, decodeURI, decodeURIComponent, encodeURI, encodeURIComponent, escape, eval, expect, exports, global, globalThis, isFinite, isNaN, jest, module, parseFloat, parseInt, performance, process, queueMicrotask, require, setImmediate, setInterval, setTimeout, undefined, unescape.
    Note: This is a precaution to guard against uninitialized mock variables. If it is ensured that the mock is required lazily, variable names prefixed with `mock` (case insensitive) are permitted.

      28 | Object.defineProperty(exports, "__esModule", { value: true });
      29 | jest.mock("@react-native-async-storage/async-storage", () => {
    > 30 |     return async_storage_mock_1.default;
         |            ^^^^^^^^^^^^^^^^^^^^
      31 | });
      32 | jest.mock("i18n-js", () => ({
      33 |     currentLocale: () => "en",

      at File.buildCodeFrameError (node_modules/@babel/core/lib/transformation/file/file.js:249:12)
      at NodePath.buildCodeFrameError (node_modules/@babel/traverse/lib/path/index.js:145:21)
      at newFn (node_modules/@babel/traverse/lib/visitors.js:181:21)
      at NodePath._call (node_modules/@babel/traverse/lib/path/context.js:53:20)
      at NodePath.call (node_modules/@babel/traverse/lib/path/context.js:40:17)
      at NodePath.visit (node_modules/@babel/traverse/lib/path/context.js:100:31)
      at TraversalContext.visitQueue (node_modules/@babel/traverse/lib/context.js:105:16)
      at TraversalContext.visitMultiple (node_modules/@babel/traverse/lib/context.js:74:17)
      at TraversalContext.visit (node_modules/@babel/traverse/lib/context.js:131:19)
      at traverseNode (node_modules/@babel/traverse/lib/traverse-node.js:24:17)
      at NodePath.visit (node_modules/@babel/traverse/lib/path/context.js:107:52)
      at TraversalContext.visitQueue (node_modules/@babel/traverse/lib/context.js:105:16)
      at TraversalContext.visitSingle (node_modules/@babel/traverse/lib/context.js:79:19)
      at TraversalContext.visit (node_modules/@babel/traverse/lib/context.js:133:19)
      at traverseNode (node_modules/@babel/traverse/lib/traverse-node.js:24:17)
      at traverse (node_modules/@babel/traverse/lib/index.js:62:34)
      at transformFile (node_modules/@babel/core/lib/transformation/index.js:108:29)
          at transformFile.next (<anonymous>)
      at run (node_modules/@babel/core/lib/transformation/index.js:35:12)
          at run.next (<anonymous>)
      at transform (node_modules/@babel/core/lib/transform.js:29:41)
          at transform.next (<anonymous>)
      at evaluateSync (node_modules/gensync/index.js:251:28)
      at sync (node_modules/gensync/index.js:89:14)
      at stopHiding - secret - don't use this - v1 (node_modules/@babel/core/lib/errors/rewrite-stack-trace.js:50:12)
      at transformSync (node_modules/@babel/core/lib/transform.js:56:76)
      at TsJestTransformer.process (node_modules/ts-jest/dist/legacy/ts-jest-transformer.js:193:32)
      at ScriptTransformer.transformSource (node_modules/@jest/transform/build/ScriptTransformer.js:615:31)
      at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:757:40)
      at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:814:19)

Moving the mock into the __mocks__ folder or changing it to jest.doMock(...) fixes the error but then times out on the tests consuming AsyncStorage.

Version

1.17.10

What platforms are you seeing this issue on?

  • Android
  • iOS
  • macOS
  • Windows
  • web

System Information

System:                                                                                                                                                                                                                                                                               
    OS: Windows 10 10.0.22000
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
    Memory: 14.56 GB / 31.81 GB
  Binaries:
    Node: 16.15.1 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.5 - C:\Program Files (x86)\Yarn\bin\yarn.CMD
    npm: 8.19.2 - C:\dev\projects\climbers-atlas\ClimbersAtlas\node_modules\.bin\npm.CMD
    Watchman: Not Found
  SDKs:
    Android SDK:
      API Levels: 32
      Build Tools: 32.0.0, 32.1.0, 33.0.0
      System Images: android-31 | Google Play Intel x86 Atom_64
      Android NDK: Not Found
    Windows SDK:
      AllowAllTrustedApps: Disabled
      Versions: 10.0.17763.0
  IDEs:
    Android Studio: AI-212.5712.43.2112.8512546
    Visual Studio: 17.2.32516.85 (Visual Studio Community 2022)
  Languages:
    Java: 17.0.1 - /c/Program Files/Java/jdk-17.0.1/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 18.2.0 => 18.2.0
    react-native: 0.70.2 => 0.70.2
    react-native-windows: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Steps to Reproduce

I uploaded a repo that reproduces the issue here to make things quicker: https://github.com/Silthus/jest-async-storage-error

Just clone it and run yarn install then yarn test to reproduce the error.

The repo was created the following way:

  1. npx ignite-cli new JestDemo \ --bundle=test.jest \ --git \ --install-deps \ --packager=yarn \ --target-path=C:\temp\jest-demo\JestDemo \ --remove-demo
  2. Remove android and ios folders.
  3. Pin all dependencies to a fixed version.
  4. Run yarn upgrade-interactive --latest -E and upgrade all dependencies to the latest version.
  5. Add missing jest-environment-jsdom: yarn add --dev jest-environment-jsdom
  6. Fix "private method error" by adding @babel/plugin-proposal-private-methods to babel.config.js
const plugins = [
  [
      "@babel/plugin-proposal-decorators",
      {
          legacy: true,
      },
  ],
  [
      "@babel/plugin-proposal-private-methods",
      {
          loose: true
      }
  ],
  ["@babel/plugin-proposal-optional-catch-binding"],
  "react-native-reanimated/plugin", // NOTE: this must be last in the plugins
]

const vanillaConfig = {
    presets: ["module:metro-react-native-babel-preset"],
    env: {
        production: {},
    },
    plugins,
}

const expoConfig = {
    presets: ["babel-preset-expo"],
    env: {
        production: {},
    },
    plugins,
}

let isExpo = false
try {
    const Constants = require("expo-constants")
    // True if the app is running in an `expo build` app or if it's running in Expo Go.
    isExpo =
        Constants.executionEnvironment === "standalone" ||
        Constants.executionEnvironment === "storeClient"
} catch {
}

const babelConfig = isExpo ? expoConfig : vanillaConfig

module.exports = babelConfig
  1. Run yarn test and see the tests fail
@Silthus Silthus added the bug Something isn't working label Oct 11, 2022
@tido64
Copy link
Member

tido64 commented Oct 14, 2022

Does this work with Jest 26? Afaik, react-native doesn't support Jest 29 until 0.71.

@varemenos
Copy link
Contributor

varemenos commented Nov 8, 2022

Just tried to upgrade to 0.71-rc0, getting the same issue. We are using the setupTests approach described in the docs.

    ReferenceError: /__tests__/setupTests.ts: The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.
    Invalid variable access: async_storage_mock_1
    Allowed objects: AbortController, AbortSignal, AggregateError, Array, ArrayBuffer, Atomics, BigInt, BigInt64Array, BigUint64Array, Blob, Boolean, BroadcastChannel, Buffer, ByteLengthQueuingStrategy, CompressionStream, CountQueuingStrategy, Crypto, CryptoKey, CustomEvent, DOMException, DataView, Date, DecompressionStream, Error, EvalError, Event, EventTarget, FinalizationRegistry, Float32Array, Float64Array, FormData, Function, Generator, GeneratorFunction, Headers, Infinity, Int16Array, Int32Array, Int8Array, InternalError, Intl, JSON, Map, Math, MessageChannel, MessageEvent, MessagePort, NaN, Number, Object, Performance, PerformanceEntry, PerformanceMark, PerformanceMeasure, PerformanceObserver, PerformanceObserverEntryList, PerformanceResourceTiming, Promise, Proxy, RangeError, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, ReferenceError, Reflect, RegExp, Request, Response, Set, SharedArrayBuffer, String, SubtleCrypto, Symbol, SyntaxError, TextDecoder, TextDecoderStream, TextEncoder, TextEncoderStream, TransformStream, TransformStreamDefaultController, TypeError, URIError, URL, URLSearchParams, Uint16Array, Uint32Array, Uint8Array, Uint8ClampedArray, WeakMap, WeakRef, WeakSet, WebAssembly, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter, __dirname, __filename, arguments, atob, btoa, clearImmediate, clearInterval, clearTimeout, console, crypto, decodeURI, decodeURIComponent, encodeURI, encodeURIComponent, escape, eval, expect, exports, fetch, global, globalThis, isFinite, isNaN, jest, module, parseFloat, parseInt, performance, process, queueMicrotask, require, setImmediate, setInterval, setTimeout, structuredClone, undefined, unescape.
    Note: This is a precaution to guard against uninitialized mock variables. If it is ensured that the mock is required lazily, variable names prefixed with `mock` (case insensitive) are permitted.

      4 | };
      5 | Object.defineProperty(exports, "__esModule", { value: true });
    > 6 | jest.mock('@react-native-async-storage/async-storage', () => async_storage_mock_1.default);
        |                                                              ^^^^^^^^^^^^^^^^^^^^

@tido64
Copy link
Member

tido64 commented Nov 8, 2022

I don't know if this is new with Jest 29, but if you do a require inside the callback passed to jest.mock, it should start working again:

diff --git a/test/setup.ts b/test/setup.ts
index 63b666c..7fefe9d 100644
--- a/test/setup.ts
+++ b/test/setup.ts
@@ -1,6 +1,5 @@
 // we always make sure 'react-native' gets included first
 import * as ReactNative from "react-native"
-import mockAsyncStorage from "@react-native-async-storage/async-storage/jest/async-storage-mock"
 import mockFile from "./mockFile"

 // libraries to mock
@@ -24,7 +23,9 @@ jest.doMock("react-native", () => {
   )
 })

-jest.mock("@react-native-async-storage/async-storage", () => mockAsyncStorage)
+jest.mock("@react-native-async-storage/async-storage", () =>
+  require("@react-native-async-storage/async-storage/jest/async-storage-mock"),
+)

 jest.mock("i18n-js", () => ({
   currentLocale: () => "en",

@krizzu: Do you know anything about this? Do we need to update the docs?

@krizzu
Copy link
Member

krizzu commented Nov 8, 2022

@varemenos Can you show your jest config file?

If @tido64 solution works, I think we should update the docs. I think I saw this issue when using ts-jest.

Note: This is a precaution to guard against uninitialized mock variables. If it is ensured that the mock is required lazily, variable names prefixed with mock (case insensitive) are permitted.

I wonder if changing the name to jest/mock-async-storage would fix that? 🤔

@varemenos
Copy link
Contributor

varemenos commented Nov 8, 2022

I tried the inline require but it didn't seem to have any effect.

You are correct in assuming that I'm using ts-jest, here is my eslint config file:

module.exports = {
  preset: 'react-native',
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
  setupFiles: ['./__tests__/setupTests.ts'],
  setupFilesAfterEnv: ['@testing-library/jest-native/extend-expect'],
  watchPlugins: [
    'jest-watch-typeahead/filename',
    'jest-watch-typeahead/testname',
  ],
  testMatch: ['**/__tests__/*.spec.(js|jsx|ts|tsx)'],
  transformIgnorePatterns: [
    '/node_modules/(?!react-native)/.+',
    '\\.snap$',
    'jest-runner',
  ],
  cacheDirectory: '.jest/cache',
  transform: {
    '^.+\\.jsx$': 'babel-jest',
    '^.+\\.tsx?$': [
      'ts-jest',
      {
        tsconfig: 'tsconfig.spec.json',
        babelConfig: 'babel.config.js',
        diagnostics: false,
        isolatedModules: true,
      },
    ],
  },
}

I was also experiencing the "private method error", but I just made

module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: ['react-native-reanimated/plugin'],
  env: { production: { plugins: ['transform-remove-console'] } },
}
// tsconfig.json
{
  "extends": "@tsconfig/react-native/tsconfig.json",
  "compilerOptions": {
    "typeRoots": ["node_modules/@types", "lib/typings"],
    "skipLibCheck": true
  }
}

// tsconfig.spec.json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "jsx": "react"
  }
}

This is most likely irrelevant to the issue but the current package json for async storage has the following range. Which I assume will need to change when RN 0.71 lands.

"peerDependencies": {
  "react-native": "^0.0.0-0 || 0.60 - 0.70 || 1000.0.0"
}

@tido64
Copy link
Member

tido64 commented Nov 8, 2022

@varemenos: What's the content of your ./__tests__/setupTests.ts?

@varemenos
Copy link
Contributor

A bunch of overrides/mocks

import { Image } from 'react-native'
Image.getSize = jest.fn()

import mockAsyncStorage from '@react-native-async-storage/async-storage/jest/async-storage-mock'
jest.mock('@react-native-async-storage/async-storage', () => mockAsyncStorage)

import mockRNCNetInfo from '@react-native-community/netinfo/jest/netinfo-mock.js'

import mockClipboard from '@react-native-clipboard/clipboard/jest/clipboard-mock.js'

import mockRNGestureHandler from 'react-native-gesture-handler/jestSetup.js'
jest.mock('react-native-gesture-handler', () => mockRNGestureHandler)

jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper')

jest.mock('@react-native-community/netinfo', () => mockRNCNetInfo)
jest.mock('@react-native-clipboard/clipboard', () => mockClipboard)

global.__DEV__ = true

global.ReanimatedDataMock = { now: () => 0 }
global.__reanimatedWorkletInit = jest.fn()

jest.mock('../lib/config', () => ({
  BASE_URL: 'localhost:3000',
}))

@tido64
Copy link
Member

tido64 commented Nov 8, 2022

Right, this is the file where you would substitute the import for an inline require. Can you try that and report back?

@varemenos
Copy link
Contributor

varemenos commented Nov 8, 2022

Ya, that's where I changed the snippet you sent earlier.
It didn't have any effect.

This is far fetched but is there a chance the removal of AsyncStorage from RN in 0.71 could somehow indirectly affect this? (or it's existence somehow prevented the problem from surfacing?)

@tido64
Copy link
Member

tido64 commented Nov 8, 2022

Just tried to upgrade to 0.71-rc0, getting the same issue. We are using the setupTests approach described in the docs.

    ReferenceError: /__tests__/setupTests.ts: The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.
    Invalid variable access: async_storage_mock_1
    Allowed objects: AbortController, AbortSignal, AggregateError, Array, ArrayBuffer, Atomics, BigInt, BigInt64Array, BigUint64Array, Blob, Boolean, BroadcastChannel, Buffer, ByteLengthQueuingStrategy, CompressionStream, CountQueuingStrategy, Crypto, CryptoKey, CustomEvent, DOMException, DataView, Date, DecompressionStream, Error, EvalError, Event, EventTarget, FinalizationRegistry, Float32Array, Float64Array, FormData, Function, Generator, GeneratorFunction, Headers, Infinity, Int16Array, Int32Array, Int8Array, InternalError, Intl, JSON, Map, Math, MessageChannel, MessageEvent, MessagePort, NaN, Number, Object, Performance, PerformanceEntry, PerformanceMark, PerformanceMeasure, PerformanceObserver, PerformanceObserverEntryList, PerformanceResourceTiming, Promise, Proxy, RangeError, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, ReferenceError, Reflect, RegExp, Request, Response, Set, SharedArrayBuffer, String, SubtleCrypto, Symbol, SyntaxError, TextDecoder, TextDecoderStream, TextEncoder, TextEncoderStream, TransformStream, TransformStreamDefaultController, TypeError, URIError, URL, URLSearchParams, Uint16Array, Uint32Array, Uint8Array, Uint8ClampedArray, WeakMap, WeakRef, WeakSet, WebAssembly, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter, __dirname, __filename, arguments, atob, btoa, clearImmediate, clearInterval, clearTimeout, console, crypto, decodeURI, decodeURIComponent, encodeURI, encodeURIComponent, escape, eval, expect, exports, fetch, global, globalThis, isFinite, isNaN, jest, module, parseFloat, parseInt, performance, process, queueMicrotask, require, setImmediate, setInterval, setTimeout, structuredClone, undefined, unescape.
    Note: This is a precaution to guard against uninitialized mock variables. If it is ensured that the mock is required lazily, variable names prefixed with `mock` (case insensitive) are permitted.

      4 | };
      5 | Object.defineProperty(exports, "__esModule", { value: true });
    > 6 | jest.mock('@react-native-async-storage/async-storage', () => async_storage_mock_1.default);
        |                                                              ^^^^^^^^^^^^^^^^^^^^

Do you still get this exact error after the change? I find that peculiar because we are doing exactly what the error message tells us to.

@varemenos
Copy link
Contributor

No actually you are 100% right, the root cause of the issue doesn't seem related to AsyncStorage after all. Since when I did what you recommended and replace the import with an inline require, the next library that I mocked had the same exception (which I was careless enough not to notice until you asked me to double-check).

So I replaced all of them with inline requires, and now the issue has gone away.

@tido64
Copy link
Member

tido64 commented Nov 8, 2022

Thanks for checking. I've updated the docs.

@krizzu
Copy link
Member

krizzu commented Nov 11, 2022

🎉 This issue has been resolved in version 1.17.11 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants