Testing methods that use Expo SDK with Jest

I started adding unit tests to our Expo project.

I’m having problem with testing a method that ask for location permission and locates the user.

The error:

TypeError: Cannot convert undefined or null to object
        at Function.keys (<anonymous>)

      at keys (node_modules/expo-permissions/src/Permissions.js:15:20)
      at call (node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:45:40)
      at Generator.tryCatch [as _invoke] (node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:271:22)
      at Generator._invoke [as next] (node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:97:21)
      at call (node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:45:40)
      at tryCatch (node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:135:20)
      at invoke (node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:145:13)
      at fn (node_modules/promise/lib/core.js:37:12)
      at tryCallOne (node_modules/promise/lib/core.js:123:15)

The line for asking permission:
const { status } = await Permissions.askAsync(Permissions.LOCATION);

I’d like to know what is the recommended way of testing these kind of methods?

Expo SDK: 32.0.0
jest-expo: 32.0.0

If you google “jest mock imports”, you’ll get a handful of different methods. I’m here to tell you that I don’t like any of them. Maybe the least-worst option is to override the method you use in your tests, like…

beforeEach(() => {
   Platform.askAsync = jest.fn(() => Promise.resolve()); 

But, that doesn’t get undone automatically unless you undo it in afterEach(), and even then, I’m not sure if that causes weird stuff due to tests running asynchronously. So, I’m not a big fan.

I end up doing things the old-fashioned way: I inject any dependencies outside of very basic utilities (like lodash or numeraljs). Regardless of where you draw the line, I think anything that requires actual device capabilities is a prime target for dependency injection.

So, my class might be:

class ThingThatIWillTest {
   // dependencies

   constructor({ Platform }) {
      this._Platform = Platform;

   async functionThatIWillTest() {
      await this._Platform.askAsync();
     // etc.

Then I can pass in a mock Platform in my tests, like:

const systemUnderTest = new ThingThatIWillTest({ Platform: { askAsync: jest.fn(() => Promise.resolve()) } );

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.