Writing Unit Tests For Metric-Imperial Converter Project

When I try to input just “gal” on the example app, it reports “invalid number”. Same when I try " 4gal". So yeah, we aren’t supposed to trim and should have it error on spaces.

No, that’s not what trim does. I’ve literally copy pasted some working code into the basic structure of the app, so mine will probably break, but trim does not just remove whitespace in a string, it removes whitespace from the start and end of a string, "4 gal".trim() is "4 gal"

I’m saying the example code seems to reject white space at the beginning and the end of the string, which I think means that it doesn’t remove that space but just errors on it.

How are you submitting URLs with whitespace?

I know it’s actually treated as a query parameter, but I’m entering it through the input field on the front-end side. And if I include a space in the beginning, it says, “invalid number”.

That’s not a constraint of the FCC tests though? I can run input sanitisation on the field, that’s what I’d normally do but I just haven’t altered anything in the FCC index template.

We’re only supposed to edit convertHandler.js and api.js, though, no? I don’t think we’re supposed to change anything anywhere else.

I see what you mean. Not sure something to do with what’s being submitted, may just be URL encoded spaces it’s tripping up on. As I say, it’s not a constraint of the tests, which only care whether URL query input to API produces the JSON object it expects, nothing else. How the front end actually works, doesn’t matter, it’s only there as an example

Edit: you can alter anything you want except a. structure, with those files and b. the contents of the files which have a comment at the top saying “do not edit this file”.

As I say this is just an example, and I need to look at your code again, I don’t understand why there are issues if you’ve already written functions that do the the things you want, which is what it looks like

Anyway, right now I have this on the FCC tests:

If the number is invalid, returned will be 'invalid number'.
If both the unit and number are invalid, returned will be 'invalid number and unit'.

And it does check if it’s converting units correctly since there are tests for it. It’s just that it also wants us to write tests and get them to pass.

The main problem on mine seems to be that the number validation is failing. I don’t know why.

convertHandler.js:

function ConvertHandler() {
  const checkNumber = (number) => {
    if (!/^(\d*(\.\d+)?(\/\d+(\.\d+)?)?)$/.test(number)) {
      return false;
    }

    if (isNaN(number) && !Number(number)) {
      return false;
    }
    return true;
  }

  const checkUnit = (unit) => {
    if (!/^(mi|km|L|lbs|kg|gal)$/i.test(unit)) {
      return false;
    }
    return true;
  }

  this.getNum = function(input) {
    // check if a number was entered;
    // return 1 if not
    if (/^([a-z]+)$/i.test(input)) {
      return 1;
    }

    const [number, unit] = input.split(/([a-z]+)/i);

    // check if we've got a fraction (indexOf returns -1 when the character is not found)
    if (number.toString().indexOf("/") !== -1) {
      const numbers = number.split("/");

      if (numbers.length === 2) {
        const numerator = Number(numbers[0]);
        const denominator = Number(numbers[1]);
        return Number(numerator / denominator);
      }
    }
    return Number(number);
  };

  this.getUnit = function(input) {
    const [number, unit] = input.split(/([a-z]+)/i);
    if (unit === "l" || unit === "L") {
      return "L";
    }

    return unit.toLowerCase();
  };
  
  this.getReturnUnit = function(initUnit) {
    let result;
    switch (initUnit.toLowerCase()) {
      case "mi":
        result = "km";
        break;
      case "gal":
        result = "L";
        break;
      case "km":
        result = "mi";
        break;
      case "lbs":
        result = "kg";
        break;
      case "kg":
        result = "lbs";
        break;
      case "l":
        result = "gal";
        break;
    }
    
    return result;
  };

  this.spellOutUnit = function(unit) {
    let result;
    switch (unit.toLowerCase()) {
      case "mi":
        result = "miles";
        break;
      case "gal":
        result = "gallons";
        break;
      case "km":
        result = "kilometers";
        break;
      case "lbs":
        result = "pounds";
        break;
      case "kg":
        result = "kilograms";
        break;
      case "l":
        result = "liters";
        break;
    }
    
    return result;
  };
  
  this.convert = function(initNum, initUnit) {
    if (checkNumber(initNum) && checkUnit(initUnit)) {
      const galToL = 3.78541;
      const lbsToKg = 0.453592;
      const miToKm = 1.60934;
      let result;
      switch (initUnit.toLowerCase()) {
        case "gal":
          result = initNum * galToL;
          break;
        case "lbs":
          result = initNum * lbsToKg;
          break;
        case "mi":
          result = initNum * miToKm;
          break;
        case "l":
          result = initNum / galToL;
          break;
        case "kg":
          result = initNum / lbsToKg;
          break;
        case "km":
          result = initNum / miToKm;
          break;
      }
  
      return Number(result).toFixed(5);
    } else if (!checkNumber(initNum) && !checkUnit(initUnit)) {
      throw new Error("invalid number and unit");
    } else if (!checkNumber(initNum) && checkUnit(initUnit)) {
      throw new Error("invalid number");
    } else if (checkNumber(initNum) && !checkUnit(initUnit)) {
      throw new Error("invalid unit");
    }
  };
  
  this.getString = function(initNum, initUnit, returnNum, returnUnit) {
    let result = `${initNum} ${this.spellOutUnit(initUnit)} converts to ${returnNum} ${this.spellOutUnit(returnUnit)}`;
    
    return result;
  };
  
}

module.exports = ConvertHandler;

@DanCouper I’ve written the functions, but like I said there seems to something wrong with checkNumber or something related to it. I don’t know what.

You misunderstand what I’m saying: yes there need to be tests for the unit converter, and functional tests for the api, but you decide how they work: they just need to be there and test the things it asks to test. But the specific ones that are failing are hitting the API endpoint with a query and checking properties on the JSON object returned from it. They don’t care what the convertHandler looks like, or how it works.

Anyway I’ll have a look at later this evening

I understood what you’re saying.

What I’m saying is that the FCC tests do check if the converter is working properly. They may just be looking at the returned JSON object, but they do look at whether the conversions are done properly.

I’ll write the tests later. I did try before but I had problems with how to write them correctly. I’ll try again later.

So there should be 16 tests that look something like this (slightly pseudocode, and apologies if I’ve mixed up the TDD and BDD test syntaxes) but you should just be able to basically copy past this block 16 times and change the description, method, value and the expected value

test("DESCRIPTION", (done) => {
  const converter = new conversionHandler();
  const input = converter.METHOD(VALUE);
  const output = EXPECTED_VALUE;
  expect(input).toBe(output);
  done();
}

Thanks.

That’s kind of what I did but I guess I still did something wrong in them because even the ones that should’ve been passing weren’t. I’ll post the tests I write next time here so you can see them. Hope it’s not too much trouble.

Anyway. When you get to reading through my code, please let me know. Thanks.