Git Product home page Git Product logo

ci-lab's Introduction

CI Lab Instructions

You're going to introduce Continuous Integration to a simple JavaScript application. The application is going to be built using the 'npm' build tool. The application code is versioned using Git, and the central repo will be hosted at GitHub. You'll have your own personal GitHub central repo so as to stay isolated from others. Finally, you'll be using CircleCI as your online CI server. CircleCI is free to use, and is highly integrated with GitHub.

Environment Setup

Check that node and npm are installed (version agnostic)

node -v
npm -v

Complete your Git setup (also verifies that git is working on your computer):

git status
git config --global user.email "<github_username>@users.noreply.github.com"
git config --global user.name "<github_username>"

Project Setup

  1. Create a GitHub account for yourself if you don't have one already (it is free!)

  2. From the GitHub website, fork this repository

    • your new repository will be associated with your own account on GitHub
    • you should be able to see your new repository within GitHub - including its history; select commits to see this history
  3. Open a terminal, navigate to a directory that you normally use for your own development, and make a local clone of your new GitHub repository

    git clone https://github.com/{GITHUB_USER_NAME}/ci-lab.git
    

    This will automatically create a directory named ci-lab

  4. Examine the structure of this project. Take a look at the site/index.html file. See that it references bundle.js, and that this file does not currently exist.

  5. Also see that there is very little so far in your top-level directory.

  6. Take a look at package.json. This is a descriptor for the project, and it drives our build tool, which is npm. Settings to note:

    • dependencies (third-party libraries) declared at the bottom of the file
    • a 'build' script that invokes a command called 'browserify' with some arguments
    • a 'start' script that invokes a 'node' server
  7. NPM is our build tool and is installed on your machine. We're going to run a few npm commands to get our project up and running. The behaviour of the commands is driven by the package.json file. Start with:

    npm install
    

    This command will connect to a remote npm repository and download the packages specified. You can see them now in the node_modules directory.

  8. We now have the libraries we need to build, test and run our app, but we still need to produce that missing 'bundle.js' file. This is going to be produced by the 'browserify' tool that is made available to us via the 'browserify' dependency. The tool can be invoked via the script labelled 'build' in the package.json. It bundles all the .js files from the site directory into a single .js file.

    npm run build
    

    See that the bundle.js now exists.

  9. You should now be able to start the server. Open a new terminal window, navigate to the top-level directory of this repo and run

    npm start
    

    This command should start up an http server which hosts our application. This command also blocks the terminal, so you should use the first terminal to continue working. (You can kill the server at any time with Ctrl+C, but this will bring down the app).

  10. You can now access the web application by launching a browser and navigating to http://localhost:3000/. As you can see, it's a very simple game of Tic-Tac-Toe / Noughts-and-Crosses. The app is entirely self-contained - to play against an opponent you need to take turns with the mouse! Have a click around - note that to restart the game you need to reload the whole web page.

Project Design

  1. Back to your terminal. Time to take a look at the design of this simple application. What we have here is a 'Single Page Application' (SPA). This means that all the logic for the application is served up to the browser as JavaScript alongside the regular HTML elements.

    Ignore the server directory - this is just serving our entire application to our web browser when you first load the page. The interesting stuff - the HTML and the JavaScript logic - is in the site directory. Take a quick look at each file in turn (don't worry about completely absorbing everything here - just get the gist of each file):

    • index.html lays out our game board in HTML. Each <span> element corresponds to a cell in the game and is identified with a two-digit co-ordinate.
    • model.js has a function, createModel to create a representation of the game as a JavaScript object. This returns an object that is initialised to an 'empty board' state (see Model.prototype.reset), and that has another function to update the state of the game when a given cell is clicked (Model.prototype.applyClick). This function contains all the core game logic - including how to decide if the game has ended.
    • view.js has a single function that updates the HTML on the web page to reflect a given model object.
    • controller.js has a function which attaches a 'click listener' to each of the cells in the HTML grid. When a cell is clicked, the controller invokes the applyClick method on the model and finally updates the HTML by invoking the function on the view object.
    • main.js simply ties everything together and initiates the controller.

Testing

  1. As mentioned, the core of the game logic is in the model.js file. We have some unit tests for this file - look in the site/spec directory. The file here, model.spec.js, is written in JavaScript using functions from a library called 'chai'. (You may have noticed that 'chai' was one our dependencies in package.json). Take a look:

    • At the top of the file is a builder function that makes it easy to prepare a game model in any given state.
    • The tests are lower down. We're only testing the 'applyClick' function, but we're testing several scenarios. See how each test declares what is required, before building a model, invoking applyClick, and verifying the end state of the model. Again, it's not essential to fully understand the syntax here - the key takeaway is that we have unit tests to verify the behaviour of the model object.
  2. The tests can be run using a tool called 'mocha' (another dependency declared in package.json). From the top-level directory, run

    ./node_modules/.bin/mocha site/spec/*.spec.js
    

    You should get some output on your console telling you that all the tests passed.

Continuous Integration with CircleCI - unit testing

  1. Now we'll get these tests running on every check in. Navigate to circle ci in your web browser https://circleci.com/. Log In with your GitHub credentials, and give authorisation to CircleCI to access your repositories (CircleCI needs read-only access in order to checkout and build your code).

  2. Request an initial build of your project by clicking 'Build Project'. You should be able to watch the build in real-time running through various steps including npm install. However, the build will fail, complaining that there is no test step configured. We need to fix that.

  3. Edit your local version of package.json. Add a new 'script' line alongside 'build' and 'start' (GOTCHA: commas are needed after each script declaration except the last one):

    "test": "mocha site/spec/*.spec.js"
    

    The name 'test' is significant to the npm build tool - it expects it to be there, and its absence is what is causing the failure in CircleCI. The rest of the line is just the command to invoke - it will automatically find the 'mocha' script in ./node_modules directory.

    Having made this change, you should now be able to run your tests from your terminal with

    npm test
    

    The tests should all pass, just as before.

  4. You now need to push your changed package.json to the GitHub repository. Let's just check exactly what has changed. Run the following:

    git status
    

    This should tell you that your package.json file has change. It is the only file we have changed so far. If you're wondering why the the generated files like bundle.js and the ./node_modules directory are not recognised by this command, the repo already has a .gitignore file configured to explicitly ignore these.

    git diff
    

    This command gives an in-depth look at what you've changed (just added one line).

    git commit -a -m "Specified a test script in package.json"
    git push
    

    The 'commit' command adds all the changes you've made to your local Git repository as a 'commit', and associates a message explaining the change. The 'push' command transmits the commit to the remote GitHub repository.

    Take a look at GitHub now, you should be able to see your commit. Also take a look at CircleCI. It will recognise that your repository has changed, and it will re-run the build. This time, the test command will be executed, the tests should all pass, and the overall build will be considered a success. You should even get a marker on GitHub showing that your latest commit resulted in a successful build.

  5. So right now, the project looks good. But in fact there are bugs with the game - you may have already noticed. It's just that there are no automated tests to expose those bugs. For example, once someone has won the game, the game ought to end. But in fact, you can continue placing more tokens. Try it and see for yourself.

    This is part of the normal development lifecycle. We have identified a bug that was missed during initial development. Rather than fixing the bug immediately, we should first write an automated test to highlight the bug. By adding this test to our code base, we ensure that this bug can never be accidentally reintroduced.

    As we've seen, with 'chai', your tests describe expected behaviour. The expected behaviour here is that no more clicks are allowed when the game is over. There is a commented-out test case in site/spec/model.spec.js to define this behaviour. Uncomment it and re-run the tests with npm test. This test should fail.

  6. Normally, a developer would now fix the bug right away. But let's demonstrate that CircleCI will fail a build if there is a test failure. Use the above git commands to double-check your change, commit with a sensible message, and push to GitHub. Check on CircleCI that the build does indeed fail.

  7. Now go ahead and fix the problem. You'll need to make a change to the 'applyClick' function in site/model.js. HINT: look at what the the first 'if' clause is doing and see if you can modify its conditional check.

  8. Once you've made your fix locally, re-run your tests and check that they all pass.

  9. Now commit and push your fix to GitHub, and check that CircleCI builds again.

Continuous Integration with CircleCI - linting

  1. Another class of problem with an application's code base is stylistic errors. Processes called 'linters' can analyse your code for errors and can fail a build in the same way a test runner would.

  2. We'll use a tool called 'eslint'. For starters, we need to make this tool available by declaring it as a dependency of our project. We could do this by hand-editing package.json, but a faster and more reliable way is with an npm command:

    npm install eslint --save
    

    This command installs the module to node_modules and the --save flag adds an entry to your package.json.

  3. We'll also need to supply some stylistic rules for eslint to check. Style is, after all, a matter of taste, and you're free to configure the style you want for your team. However, configuring all rules from scratch would take ages, so let's use some rules from Google to get started. Install another dependency:

    npm install eslint-config-google --save
    
  4. Now let's add some custom rules. Create a file in your local repository root directory called .eslintrc.json. Give it the following content (don't worry about understanding what these rules mean; not important for this lab):

    {
        "extends": "google",
        "installedESLint": true,
        "env": {
          "browser": true
        },
        "rules": {
          "linebreak-style": 0,
          "one-var": 0
        }
    }
    
  5. Specify that eslint should run immediately before the unit tests by editing the 'test' script in package.json. Change it to:

    "test": "eslint site/*.js && mocha site/spec/*.spec.js",
    
  6. Now try running npm test again. There should be linting failures. Run the Git commands again to commit and push to GitHub. See that CircleCI fails your build again.

  7. Now fix the linting problems locally - you'll have to read each problem carefully to determine what needs fixing.

  8. When you can run npm test successfully again, commit and push to GitHub again. Check that CircleCI passes the build.

Additional features of CircleCI

Explore extra features (provide link).

Extension 1

The game has another bug!

  1. Find the bug
  2. Write any tests to cover the bug
  3. Make the tests pass
  4. Push your changes

Extension 2

See the following guide to setting up continuous deployment using heroku:

https://circleci.com/docs/continuous-deployment-with-heroku/

ci-lab's People

Contributors

simonhall-scottlogic avatar sl-csmith avatar chrisprice avatar

Watchers

James Cloos avatar Alessio Zakaria avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.