Search code examples
arraysnode.jsv8

What is the correct way to use array.sort(a, b) following changes made in node.js v11.0.0^


Ok, so we had some code that was working fine and passing tests fine on node 10, now following upgrading to node 11 the code now fails unit tests. Code maps over array of objects altering properties then sorts based on a string name value i.e. array.sort(a, b) => a.toLowerCase() > b.toLowerCase().

It now maps correctly but the sort does not work and returns the mapped array only without sorting, when i've tried splitting the two functions out into individual map then sort the sort returns undefined.

Have researched and tried to find some examples to see what needs to be changed but not found a great deal other than suggestions of the sort algorithm changing to timsort in v8.

simple code

export default places => places
   .map(place => ({
    value: place.properties.code, label: place.properties.name
   }))
   .sort((placeA, placeB) => placeA.label.toLowerCase() > 
   placeB.label.toLowerCase())

test array:

      type: 'Place',
      properties: {
        code: 'CA076757',
        name: 'Brockway'
      }
    }, {
      type: 'Place',
      properties: {
        code: 'MN486464',
        name: 'Ogdenville'
      }
    }, {
      type: 'Place',
      properties: {
        code: 'S4889785',
        name: 'North Haverbrook'
      }
    }]

expected result

      {value: 'CA076757', label: 'Brockway'},
      {value: 'S4889785', label: 'North Haverbrook'},
      {value: 'MN486464', label: 'Ogdenville'}
    ]

actual result

      {value: 'CA076757', label: 'Brockway'},
      {value: 'MN486464', label: 'Ogdenville'}.
      {value: 'S4889785', label: 'North Haverbrook'}
    ]

Solution

  • we had some code that was working fine and passing tests fine on node 10, now following upgrading to node 11 the code now fails unit tests

    To be blunt, that means that your tests are not providing sufficient coverage ;-)

    In JavaScript, a comparator function cmp(a, b) for Array.sort should return:

    • a value less than zero if a is less than b
    • zero if a is equal to b
    • a value greater than zero if a is greater than b

    If you use a comparator function that returns a boolean value, then false will silently map to 0, and true will silently map to 1. There is no way to signal the a < b case. If your test cases get (or used to get) sorted correctly anyway, then they didn't cover that case.

    A suitable comparator function for your example, regardless of which Node version or which browser you're using, would be:

    (placeA, placeB) => {
      let a = placeA.label.toLowerCase();
      let b = placeB.label.toLowerCase();
      if (a < b) return -1;
      if (a > b) return 1;
      return 0;
    }