scalascala.jsutest

How to deeply compare two js like objects in scala.js?


Since js.Dynamic.literal() != js.Dynamic.literal(), what is the suggested way to test equality for two literals?

I don't want to characterize those literals with traits. I want to know if they are deeply equal.

What I'm doing right now is the following

val js1 = literal()
val js2 = literal()
val json1 = JSON.stringify(js1)
val json2 = JSON.stringify(js2)
assert(json1 == json2) // true

Note: even in javascript {} === {} evaluates to false, so I shouldn't have been surprised in the first place.


Solution

  • You could define your own structural equality for JS object-like structures:

    def jsStructuralEqual(a: Any, b: Any): Boolean = {
      (a, b) match {
        case (a: js.Array[_], b: js.Array[_]) =>
          a.length == b.length &&
          a.zip(b).forall((jsStructuralEqual _).tupled)
    
        case _ if a.constructor == js.constructorOf[js.Object] &&
            b.constructor == js.constructorOf[js.Object] =>
          val aDict = a.asInstanceOf[js.Dictionary[Any]]
          val bDict = b.asInstanceOf[js.Dictionary[Any]]
          (aDict.keySet == bDict.keySet) &&
          aDict.keySet.forall(key => jsStructuralEqual(aDict(key), bDict(key))
    
        case _ =>
          a == b
      }
    }
    

    (not tested)