mardi 30 janvier 2018

Button outcomes in Zombie.js tests

I'm trying to write some tests for my bowling scorecard. I mainly want to use it to check the totals of various score entry combinations. But I'm finding it difficult in getting the correct syntax to refer to the buttons.

I'm also wondering if I should give each bowl a separate id tag to make the expect easier. If not I would have to find a way of using an index number of the spans to refer to that.

index.html

<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="css/styles.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <title>Bowling Scorecard</title>
</head>

<body>

  <h2>Bowling Scorecard</h2>

  <div class="scorecard">
    <table>
      <tr class="frame-title-container">
        <th></th>
        <th>Frame 1</th>
        <th>Frame 2</th>
        <th>Frame 3</th>
        <th>Frame 4</th>
        <th>Frame 5</th>
        <th>Frame 6</th>
        <th>Frame 7</th>
        <th>Frame 8</th>
        <th>Frame 9</th>
        <th>Frame 10</th>
      </tr>
      <tr class="score-container">
        <td id="name">Player 1</td>
        <td class="frame-one">
          <div><span class="first"></span>&emsp;<span class="second"></span></div>
          <br>
          <div class="total"></div>
        </td>
        <td class="frame-two">
          <div><span class="first"></span>&emsp;<span class="second"></span></div>
          <br>
          <div class="total"></div>
        </td>
        <td class="frame-three">
          <div><span class="first"></span>&emsp;<span class="second"></span></div>
          <br>
          <div class="total"></div>
        </td>
        <td class="frame-four">
          <div><span class="first"></span>&emsp;<span class="second"></span></div>
          <br>
          <div class="total"></div>
        </td>
        <td class="frame-five">
          <div><span class="first"></span>&emsp;<span class="second"></span></div>
          <br>
          <div class="total"></div>
        </td>
        <td class="frame-six">
          <div><span class="first"></span>&emsp;<span class="second"></span></div>
          <br>
          <div class="total"></div>
        </td>
        <td class="frame-seven">
          <div><span class="first"></span>&emsp;<span class="second"></span></div>
          <br>
          <div class="total"></div>
        </td>
        <td class="frame-eight">
          <div><span class="first"></span>&emsp;<span class="second"></span></div>
          <br>
          <div class="total"></div>
        </td>
        <td class="frame-nine">
          <div><span class="first"></span>&emsp;<span class="second"></span></div>
          <br>
          <div class="total"></div>
        </td>
        <td class="frame-ten">
          <div><span class="first"></span>&emsp;<span class="second"></span>&emsp;<span id=frame-ten-third></span></div>
          <br>
          <div class="total"></div>
        </td>
      </tr>
    </table>
  </div>
  <br>
  <div class="score-inputs">
    <form class="buttons">
      <input id="0" class="button" type="button" value="0"></input>
      <input id="1" class="button" type="button" value="1"></input>
      <input id="2" class="button" type="button" value="2"></input>
      <input id="3" class="button" type="button" value="3"></input>
      <input id="4" class="button" type="button" value="4"></input>
      <input id="5" class="button" type="button" value="5"></input>
      <input id="6" class="button" type="button" value="6"></input>
      <input id="7" class="button" type="button" value="7"></input>
      <input id="8" class="button" type="button" value="8"></input>
      <input id="9" class="button" type="button" value="9"></input>
      <input id="10" class="button" type="button" value="10"></input>
    </form>
  </div>

  <script src="src/interface.js"></script>

</body>

</html>

styles.css

table {
  border-collapse: collapse;
  border: 1px solid black;
}

th {
  border: 1px solid black;
}

td {
  text-align: center;
  height: 100px;
  width: 100px;
  border: 1px solid black;
}

.innercell {
  height: 50px;
  width: 50px;
}

input {
  width: 50px;
  height: 25px;
}

.button[disabled] {
  background-color: #ccc;
}

interface.js

$(document).ready(() => {
  var allSpans = $("span");
  var totalClass = $(".total");
  var frameBowlIndex = 0;
  var frameTotalIndex = 0;
  var scoreCardArray = [];
  var spare = false;
  var strike = false;
  var runningTotal = 0;

  $(".button").click(function() {
    var bowlValue = $(this).val();
    updateScore(bowlValue);
  });

  var updateScore = function(bowlValue) {
    bowlValue = parseInt(bowlValue);
    scoreCardArray.push(bowlValue);
    hideButtonsIfSumOverTen(bowlValue);
    addSingleScoreToPage(bowlValue);
    ifStrikeNextBowlZero(bowlValue);
    calculateTotals();
    frameBowlIndex++;
  };

  var calculateTotals = function() {
    if (hasEvenIndex(scoreCardArray)) {
      addBowlsToTotal();
      addBonus();
      addTotalToPage(runningTotal);
      spareOrStrikeChecker();
      frameTotalIndex++;
      resetButtons();
    }
  };

  var addBonus = function() {
    if (spare) {
      addSpareBonus();
    }
    if (strike) {
      addStrikeBonus();
    }
  };

  var addBowlsToTotal = function() {
    var currentFrameTotal = bowlIndexFromLast(1) + bowlIndexFromLast(2);
    runningTotal += currentFrameTotal;
  };

  var bowlIndexFromLast = function(index) {
    return scoreCardArray[scoreCardArray.length - index];
  };

  var spareOrStrikeChecker = function() {
    var firstBowl = bowlIndexFromLast(2);
    var secondBowl = bowlIndexFromLast(1);
    isStrike(firstBowl, secondBowl);
    isSpare(firstBowl, secondBowl);
  };

  var isSpare = function(firstBowl, secondBowl) {
    if (firstBowl + secondBowl === 10 && secondBowl !== 0) {
      spare = true;
    }
  };

  var isStrike = function(firstBowl, secondBowl) {
    if (firstBowl === 10) {
      strike = true;
    }
  };

  var ifStrikeNextBowlZero = function(bowlValue) {
    if (bowlValue === 10 && !hasEvenIndex(scoreCardArray)) {
      frameBowlIndex++;
      addSingleScoreToPage(0);
      scoreCardArray.push(0);
    }
  };

  var addSpareBonus = function(total) {
    if (spare) {
      var firstBowlBonus = bowlIndexFromLast(2);
      var newPrevTotal = getPrevTotal() + firstBowlBonus;
      editPrevTotalToPage(newPrevTotal);
      runningTotal += firstBowlBonus;
      spare = false;
    }
  };

  var addStrikeBonus = function() {
    if (strike) {
      currentTotalBonus = bowlIndexFromLast(1) + bowlIndexFromLast(2);
      var newPrevTotal = getPrevTotal() + currentTotalBonus;
      editPrevTotalToPage(newPrevTotal);
      runningTotal = newPrevTotal + currentTotalBonus;
      strike = false;
    }
  };

  var getPrevTotal = function() {
    return parseInt(totalClass[frameTotalIndex - 1].innerText);
  };

  var hideButtonsIfSumOverTen = function(bowlValue) {
    if (bowlValue !== 10) {
      var remainingPins = 10 - bowlValue;
      var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

      array.forEach(function(value) {
        if (value > remainingPins) {
          $(`#${value}`).hide();
        }
      });
    }
  };

  var resetButtons = function() {
    $(".button").show();
  };

  var hasEvenIndex = function(array) {
    return array.length % 2 == 0;
  };

  var sumArray = function(array) {
    return array.reduce((a, b) => a + b, 0);
  };

  var addSingleScoreToPage = function(bowlValue) {
    bowlsSpan().innerText = bowlValue;
  };

  var addTotalToPage = function(total) {
    totalSpan().innerText = total;
  };

  var editPrevTotalToPage = function(total) {
    prevTotalSpan().innerText = total;
  };

  var bowlsSpan = function() {
    return allSpans[frameBowlIndex];
  };

  var totalSpan = function() {
    return totalClass[frameTotalIndex];
  };

  var prevTotalSpan = function() {
    return totalClass[frameTotalIndex - 1];
  };
});

intergration-test.js

const Browser = require("zombie");
const assert = require("assert");

url = "http://localhost:8080/";

describe("User visits page", function() {
  const browser = new Browser();

  before(function() {
    return browser.visit(url);
  });

  describe("zombie js works", function() {
    it("title of page should be Bowling Scorecard", function() {
      browser.assert.text("title", "Bowling Scorecard");
    });
  });

  describe("elements exist on page", function() {
    it("there is are containers on the page", function(done) {
      browser.assert.element(".scorecard");
      browser.assert.element(".frame-title-container");
      browser.assert.element(".score-container");
      done();
    });
  });

Top two tests pass, but I want the bottom one something like that.

  describe("button outcomes", function() {
    it("clicking a button shows it on the scorecard", function(done) {
      browser.pressButton("1");
      browser.assert.text("span", "1");
      done();
    });
  });
});

This gives me an error of;

1) User visits page
       button outcomes
         clicking a button shows it on the scorecard:

      AssertionError [ERR_ASSERTION]: '' deepEqual '1'
      + expected - actual

      +1

      at assertMatch (node_modules/zombie/lib/assert.js:24:212)
      at Assert.text (node_modules/zombie/lib/assert.js:370:7)
      at Context.<anonymous> (test/intergration-test.js:31:22)

It might be easier to clone this repo and run zombie there. That will not include the third test attempt, just the two passing ones.

git clone git@github.com:puyanwei/bowling-scorecard.git
cd bowling-challenge
npm install
npm start
npm test

I'm sure that my application has a lot of bad practices, but for now I'm just focusing on getting my tests working so that I can refactor later on. Thanks in advance.

Aucun commentaire:

Enregistrer un commentaire