Search code examples
javascriptalgorithmtddjasmine-nodeleap-year

How to write a leap year algorithm in Javascript with TDD?


I'm trying to write a leap year algorithm with a TDD suite. This is my first real attempt in working with TDD.

This is the code from the spec file.

var Year = require('./leap');

describe('Leap year', function() {

  it('is not very common', function() {
    var year = new Year(2015);
    expect(year.isLeap()).toBe(false);
  });

  it('is introduced every 4 years to adjust about a day', function() {
    var year = new Year(2016);
    expect(year.isLeap()).toBe(true);
  });

  it('is skipped every 100 years to remove an extra day', function() {
    var year = new Year(1900);
    expect(year.isLeap()).toBe(false);
  });

  it('is reintroduced every 400 years to adjust another day', function() {
    var year = new Year(2000);
    expect(year.isLeap()).toBe(true);
  });

This is the code so far from the leap.js file

var leapYear = function() {};

leapYear.prototype.isLeap = function(year) {
  if (year % 4 != 0) {
    return true;
  }
}

module.exports = leapYear;

I keep getting:

Failures:

1) Leap year is not very common Message: Expected true to be false. Stacktrace: Error: Expected true to be false. at null.

2) Leap year is skipped every 100 years to remove an extra day Message: Expected true to be false. Stacktrace: Error: Expected true to be false. at null.

Finished in 0.014 seconds 4 tests, 4 assertions, 2 failures, 0 skipped

Any ideas?


Solution

  • It should be as simple as:

    var leapYear = function(year) {this.year = year};
    
    leapYear.prototype.isLeap = function() {
      return this.year % 4 == 0 && this.year % 100 != 0 || this.year % 400 == 0;
    }
    
    module.exports = leapYear;
    

    If the year ends with 00 (in another word, year % 100 == 0), u should check if it can be divided by 400. Other wise just check if it can be divided by 4.

    Edit:

    Explanation:

    First the code

    • The test case wants a year object that constructs with a integer, hence your leapYear 'class' should take in a integer when constructing, and store it as a member variable.
    • The isLeap function takes no argument, hence yours shouldn't take any argument as well, it uses the year it get when constructing this object.

    Then the math

    • 1st test case simply mean if a year can't be divided by 4, it is not a leap year.
    • 2nd test case means if a year can be divided by 4, it is a leap year
    • 3rd test case means if a year can be divided by 4, but ends with 00(every 100 year), it is not a leap year.
    • 4th test case means if a year can be divided by 4, ends with 00, and can be divided by 400, it is a leap year.

    Combining all these we know:

    1. A year that cannot be divided by 4 is never a leap year.
    2. A year that can be divided by 400 must be a leap year.
    3. A year that can be divided by 4 is a leap year if it cannot be divided 100

    so if you just test all these 3 case one by one, then u get your answer