Search code examples
nearprotocol

How to test a PersistentMap item is correctly saved to storage?


I have a function that takes a number of values, creates a new model, and then saves this in storage via a PersistentMap.

I would like to test that the item is successfully saved in storage. This is how I'm going about it:

    it("saves a new item to storage", () => {
      VMContext.setCurrent_account_id("test_account_id");

      contract.createMyPersistantMapItem(
        "value 1",
        "value 2",
        "value 3"
      );
   
      expect(storage.hasKey("myPersistantMap::test_account_id")).toBeTruthy();
    });

However the test fails with the following:

  [Actual]: false
[Expected]: Truthy
   [Stack]: RuntimeError: unreachable
            at node_modules/@as-pect/assembly/assembly/internal/assert/assert (wasm-function[53]:0xd71)
            at start:src/simple/__tests__/index.unit.spec~anonymous|0~anonymous|0~anonymous|0 (wasm-function[130]:0x2a84)
            at node_modules/@as-pect/assembly/assembly/internal/call/__call (wasm-function[134]:0x2aac)

Am I going about this the wrong way?

Also I would like to test the values in the item are correct. In the todos example the created todo is returned from the function that creates it, and then this returned value is tested. Is this the best way of doing things to make testing easier?

EDIT

This is the createMyPersistantMapItem function - edited a bit to make things clearer:

export function createMyPersistantMapItem(
    blah1: string,
    blah2: string,
    blah3: string,
  ): void {
    const accountId = context.sender;
  
    assert(
      !storage.hasKey("myPersistantMap::" + accountId),
      "Item already exists"
    );
  
    const newPersistantMapItem = new PersistantMapItem(
      blah1,
      blah2,
      blah3
    );
  
    myPersistantMap.set(accountId, newPersistantMapItem);
  }

Solution

  • About the first question:

    Does myPersistentMap use the "myPersistantMap" prefix when initialized? Does PersistantMapItem use the @nearBingden annotation on the class?

    Also, in your test, I think you should use

    VMContext.setSigner_account_id("test_account_id") 
    
    //instead of
    VMContext.setCurrent_account_id("test_account_id")
    

    Because you are using context.sender when you call createMyPersistantMapItem

    About the second question:

    In the todos example the created todo is returned from the function that creates it, and then this returned value is tested. Is this the best way of doing things to make testing easier?

    This question is primarily opinion based, so I can only answer for myself. Testing the returned value is completely fine. In a smart contract however, I would probably test if the value is actually stored on the contract. And I think they are doing that in the TODO example. They just use the ID of the generated TODO to do a query on the smart contract.

    const a = Todo.insert("Drink water");
    // They use the id of the todo (a) to check if it was actually stored, and is in fact the same object. I think this is fine.
    expect(getById(a.id)).toStrictEqual(a);