M220: Chap 2 -- user management

Hi
I’m trying to avoid going down a rabbit hole again

I’m getting the. following error:

User Management › it can add a new user to the database

    expect(received).toEqual(expected) // deep equality

    - Expected  - 1
    + Received  + 0

      Object {
    -   "_id": "630fc3bbc5768736e9aa5f10",
        "email": "magicz@cats.com",
        "name": "Magical Mr. Mistoffelees",
        "password": "somehashedpw",
      }

        expect(user).toEqual(testUser)
                            ^

I did some digging :grinning: and it looks like testUser object has the _id after it was inserted

  console.log. -- BEFORE INSERT
    testuser1:  {
      name: 'Magical Mr. Mistoffelees',
      email: 'magicz@cats.com',
      password: 'somehashedpw'
    }
      at log (test/user-management.test.js:30:14)

console.log -- AFTER INSERT
    testuser2 {
      name: 'Magical Mr. Mistoffelees',
      email: 'magicz@cats.com',
      password: 'somehashedpw',
      _id: 630fc3bbc5768736e9aa5f10
    }
    at log (test/user-management.test.js:35:13)

This is my code:

  static async getUser(email) {
    // TODO Ticket: User Management
    // Retrieve the user document corresponding with the user's email.
    return await users.findOne({ email })
  }

  static async addUser(userInfo) {

    try {
      // TODO Ticket: User Management
      // Insert a user with the "name", "email", and "password" fields.
      // TODO Ticket: Durable Writes
      // Use a more durable Write Concern for this operation.
      await users.insertOne(userInfo)
      return { success: true }
    } catch (e) {
      if (String(e).startsWith("MongoError: E11000 duplicate key error")) {
        return { error: "A user with the given email already exists." }
      }
      console.error(`Error occurred while adding new user, ${e}.`)
      return { error: e }
    }
  }

Please let me know if I did wrong

Thanks

Just to respect the requirements of the TODO:

You could try to insertOne with only the 3 field specified. With your current insertOne(), one could insert arbitrary data since you simply insert the whole object you received. Yes it is more code but it safer to copy the required fields into a new object. You then use this new object for insertOne(). The added benefit is that your input parameter is not modified.

1 Like

This one is an interesting error. the test is expected to delete the _id field (delete user._id) before the assertion, but somehow it fails to do so. And it is caused by a should-be-working way of passing objects around in Javascript. I can’t say why without digging too much.

Anyways, in your queries, I suggest you follow object destructuring or similar things like @steevej mentioned above, to control what fields you pass to the query.

objectA = { propA:"valA", propB:"valB", propC:"valC" }
objectB = { ...objectA } // only if you want all fields from ObjectA
objectC = { newprop: objectA.propA, otherprop: objectA.propC } // only props you need

tests work in this way

dug around a bit.

seems the driver keeps the reference to the object sent and modifies it for reasons I don’t know.

since you are sending userInfo directly to the driver, it changes it (adds _id). and since it is an object sent by the test file that is kept in a variable for test purposes, the domino effect chains back to the original test object to add an _id field to it. and then the test deletes the _id field from the query result thus objects become unequal.

working with objects makes life pretty easy but they have this kind of hiccup when passing around. so my above suggestion is one that is better to follow.

Good Luck

As I wrote, it is not good practice to simply add what ever object you receive in your API into your database.

The requirements in the TODO are clear. Insert an object with 3 fields, you must do at least the minimum validation to insert only the 3 fields required. Simply adding whatever object somebody send to your API opens yourself to DOS attacks if such object has extra fields with huge amount of data.

Thanks again for clarifying what I needed to do.

Initially, I did try to pass the 3 key/value pairs but couldn’t figure out how to get the values!! (i.e. dot notation) so I went down another rabbit hole!!
Note to self: I have to do a deep dive into JSON.

@steevej : Thanks for the added information!! Now I understand the why!!
I did a console.log on userInfo and saw that it had what I was looking for and naively passed the object.

1 Like

So I passed test 1,2, and 4. Test 3 failed
It’s returning a null value. What am I missing?

/**

  • Gets a user from the sessions collection
  • @param {string} email - The email of the user to search for in sessions
  • @returns {Object | null} Returns a user session Object, an “error” Object
  • if something went wrong, or null if user was not found.
    */
    static async getUserSession(email) {
    try {
    // TODO Ticket: User Management
    // Retrieve the session document corresponding with the user’s email.
    return sessions.findOne({ user_id: email })
    } catch (e) {
    console.error(Error occurred while retrieving user session, ${e})
    return null
    }
    }

Error message
FAIL test/user-management.test.js
User Management
✓ it can add a new user to the database (175ms)
✓ it returns an error when trying to register duplicate user (37ms)
✕ it allows a user to login (248ms)
✓ it allows a user to logout (62ms)

● User Management › it allows a user to login

TypeError: Cannot convert undefined or null to object

  50 |     expect(actual.success).toBeTruthy()
  51 |     const sessionResult = await UsersDAO.getUserSession(testUser.email)
> 52 |     delete sessionResult._id
     |     ^
  53 |     expect(sessionResult).toEqual(sessionUser)
  54 |   })
  55 |

strongly possible your loginUser is not correct.

I suggest you pause working on the mflix app for a few days, and study the “object” nature of Javascript, creating objects, reading properties, changing properties and passing them around, and most importantly the similarity to MongoDB documents along with JSON. There lies the nature of key-value pairs.

Hint: MongoDB uses BSON format, an extended form of JSON by new object types such as ObjectId and Date.

That’s my task for the next few days… thanks

@Yilmaz_Durmaz
I did my deep dive and completed the lesson!! Thanks for the assist

3 Likes

It’s definitely useful to study the “object” nature of Javascript, but pay attention to other options too.

1 Like