Skip to content
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

[bug] Cannot run Jest Testing: cannot read properties of undefined (reading 'map') #15125

Closed
charlestbell opened this issue Nov 9, 2021 · 6 comments
Labels
jest-expo pending closure awaiting final response before closing SQLite

Comments

@charlestbell
Copy link

charlestbell commented Nov 9, 2021

Summary

Using Jest and Testing Library and Expo SQLite.

When I run Jest, I get an error that says

    TypeError: Cannot read properties of undefined (reading 'map')
    
      at node_modules/expo-sqlite/src/SQLite.ts:27:41

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        2.208 s, estimated 3 s
Ran all test suites.
error Command failed with exit code 1.

If I remove the init() call, the error dissapears, and the tests run.

I made a repo to demonstrate this, see that below.

Managed or bare workflow? If you have ios/ or android/ directories in your project, the answer is bare!

managed

What platform(s) does this occur on?

iOS

SDK Version (managed workflow only)

43

Environment

Expo CLI 4.12.12 environment info:
System:
OS: Windows 10 10.0.19042
Binaries:
Node: 16.9.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.17 - C:\Program Files\nodejs\yarn.CMD
npm: 7.21.1 - C:\Program Files\nodejs\npm.CMD
SDKs:
Android SDK:
API Levels: 28, 29, 30, 31
Build Tools: 28.0.3, 29.0.3, 32.0.0
System Images: android-28 | Google APIs Intel x86 Atom_64, android-30 | Google APIs Intel x86 Atom, android-30 | Google Play Intel x86 Atom
IDEs:
Android Studio: Version 4.2.0.0 AI-202.7660.26.42.7351085
npmPackages:
expo: ^43.0.0 => 43.0.2
react: 17.0.1 => 17.0.1
react-dom: 17.0.1 => 17.0.1
react-native: 0.64.2 => 0.64.2
react-native-web: 0.17.1 => 0.17.1
Expo Workflow: managed

Reproducible demo or steps to reproduce from a blank project

Link to demo repo
https://github.com/charlestbell/Expo-SQLite-Map-Bug

Steps:

  • Download the repo
  • Unzip it
  • Open the Expo-SQLite-Map-Bug folder. (I use vscode)
  • Install dependencies. (I use yarn)
  • Run the test. (I use yarn test)

Test should fail to run

  • Go into the app.js file.
  • Comment out lines 29-36
  • Run the test. (I use yarn test)

Test should run

@charlestbell charlestbell added the needs validation Issue needs to be validated label Nov 9, 2021
@Simek
Copy link
Collaborator

Simek commented Nov 10, 2021

Hi @charlestbell,

I think the problem is in the way in which you are trying to open the existing database. Please check the guide on that in the SQLite docs:

After implementing the suggested openDatabase method (and adding expo-asset) the test succeeds, but it still cannot load the database, since the *.db file did not exist.

Screenshot 2021-11-10 at 13 21 00

@Simek Simek added pending closure awaiting final response before closing and removed needs validation Issue needs to be validated labels Nov 10, 2021
@charlestbell
Copy link
Author

charlestbell commented Nov 12, 2021

I was not able to replicate your results.

I installed expo-asset and expo-file system and created the metro.config.js file as per the documentation you listed.

If there was more than that I was supposed to do, it was not aparent.

I still get the same 'Cannot reac properties of undefined (reading 'map') error when I run yarn test

  • The only code example given was for initializing an existing db, and the example it gave was in Typescript.

    • Why is it in typescript? Where there a js version?
  • I think maybe the person writing it just copied the code directly from the module itself, instead of showing the usage. Not sure what's going on there.

  • I'm curious why you suggested using the docs for openning an 'existing' database? This isn't an existing database, that's what 'CREATE TABLE IF NOT EXISTS' is for.

The code I have in the example is exact syntax to what's explained in this course: https://www.udemy.com/course/react-native-the-practical-guide/learn/lecture/15675384?start=165

  • I understand if the syntax has changed over the years, but I don't see the migration docs. Could you link me to the migration docs?

Please share your code.

Thanks,

@charlestbell
Copy link
Author

charlestbell commented Nov 12, 2021

I got it. Used some syntax from a youtube video. https://www.youtube.com/watch?v=wAyizHBFQEs

It appears that in the current version, you can't have a seperated init() statement like in Max's tutorial.

Code before:

    //In db.js file:

   const db = SQLite.openDatabase('logbook.db');
  
  export const init = drop => {
    const promise = new Promise((resolve, reject) => {
      db.transaction(tx => {
        drop ? tx.executeSql('DROP TABLE entries') : null;
        tx.executeSql(
          'CREATE TABLE IF NOT EXISTS entries (id INTEGER PRIMARY KEY NOT NULL, logBook_id INTEGER NOT NULL , recordType TEXT NOT NULL, title TEXT, date INTEGER, description TEXT, imageUri TEXT, address TEXT, lat REAL, lng REAL);',
                                                          [],
          () => {
            resolve();
          }, //if succeed
          (_, err) => {
            console.log('db init error', err);
          } // if fail
        );
      });
    });
    return promise;
  };

   // In App.js file:   
   
  init()
    .then(() => {
      console.log('Initialized database');
    })
    .catch(err => {
      console.log('Initializing db failed.');
      console.log(err);
    });

Code after

 // db.js file:
  const db = SQLite.openDatabase(
    { name: 'logbook.db', location: 'default' },
    () => {
      console.log('Initialized database');
    },
    error => {
      console.log('Initializing db failed.');
      console.log(error);
    }
  );
  
  export const init = drop => {
    const promise = new Promise((resolve, reject) => {
      db.transaction(tx => {
        drop ? tx.executeSql('DROP TABLE entries') : null;
        tx.executeSql(
          'CREATE TABLE IF NOT EXISTS entries (id INTEGER PRIMARY KEY NOT NULL, logBook_id INTEGER NOT NULL , recordType TEXT NOT NULL, title TEXT, date INTEGER, description TEXT, imageUri TEXT, address TEXT, lat REAL, lng REAL);',
          [],
          () => {
            resolve();
          }, //if succeed
          (_, err) => {
            console.log('db init error', err);
          } // if fail
        );
      });
    });
    return promise;
  };

Note: I removed the init statement from App.js

Edit: Code example

@gnprice
Copy link

gnprice commented Dec 9, 2021

@charlestbell Were you in fact able to get Expo SQLite running in your Jest tests? Can you share what the code looked like for doing so?

I'm experimenting with using it and would like to have it in my Jest tests, and I'm getting the same error message you quoted in the original description. From the implementation code, it looks to me like it just can't run in Jest -- there's a native module for Android and one for iOS, and not one that would run in the Jest environment on Node. But I'd love to see a demonstration of how it can work after all.

In the before/after in your last comment, it looks like the only difference was to remove the call to init, so that no executeSql calls actually happen. That'll avoid the error as long as you're only importing the library, but it won't help if you try to actually test code that uses it.

In the YouTube tutorial you link to, the test is here:
https://github.com/mahdi-sharifimehr/RN-Tutorial-Main/blob/75b97025585138f9f3fb9bb3c0525f1262ad87ba/__tests__/App-test.js
and the screen it renders is here:
https://github.com/mahdi-sharifimehr/RN-Tutorial-Main/blob/75b97025585138f9f3fb9bb3c0525f1262ad87ba/src/screens/Login.js
The one thing the test does is render that screen. (The tutorial doesn't discuss testing, focusing on other things.) And the screen's code doesn't touch the database on first render; it just sets up an effect that will do so. So the test doesn't exercise any of the code that interacts with the database.

@charlestbell
Copy link
Author

Hi gnprice,
Yes, I messed up the before/after code in my last post, I will fix it.

I did get it working for a bit. And by working, I mean my tests would run. However, they were tests that didn't use expo-sqlite.

Later, I tried to write tests that do use expo-sqlite, but that requireds the package to be mocked, and I couldn't make sense of the documentation there, so I moved on because it wasn't part of my minimum viable product.

I'll post here when I get it. Sorry I can't be more helpful.

@gnprice
Copy link

gnprice commented Dec 10, 2021

Very helpful, thanks for the followup! So that matches my understanding of the current state of things.

I actually went on yesterday to write up a mock, and I now have tests that do use expo-sqlite running in Jest. (If "mock" is even the right word -- it uses a real SQLite database, as it has to in order to faithfully test code that might be trying to run all kinds of SQL statements. Fortunately SQLite is super lightweight and can do that in memory, without even making a database file or anything.)

I expect to have that ready to merge in our own codebase next week, and then I'll post something here in expo/expo and add a link from this thread. Not sure exactly the right way to integrate it into Expo so everyone can just have it work out of the box, but I'll ask. And if that turns out to be hard or gets stalled, my version should be pretty easy to copy-paste.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
jest-expo pending closure awaiting final response before closing SQLite
Projects
None yet
Development

No branches or pull requests

4 participants