UNB/ CS/ David Bremner/ teaching/ cs2613/ labs/ Lab 9

Background

Main Background:

Going into more depth:

JavaScript equality and type coercion

Time
15 Minutes
Activity
Demo

We remember from Lab 8, Eloquent JavaScript Chapter 1, and the WAT talk by Gary Bernhardt, that type coercion is an important part of evaluating JS experessions. This is sometimes useful

``````> 42 + 'is a big number'
``````

But just as often a source of errors and confusion.

``````> "" + 1
> x=""
> x++
``````

One operator where type coercion can be particularly surprising is the standard equality test `==`. Not only does type coercion apply:

``````> "" == 0
> false == 0
> "" == 0
``````

but special rules apply to "undefined" and "null"

``````> false == undefined
> undefined == null
> undefined == undefined
``````

even though they would normally be considered falsy (considered false in boolean contexts).

``````   > if (undefined) { console.log("truthy") } else { console.log("falsey") }
``````

`NaN` is another falsy value not `==` to the other falsy values, not even itself:

``````   > NaN == undefined
> NaN == NaN
``````

To avoid this twisty maze of "helpful" type coercion, you can use the "strict equality" checker `===`

``````   > "" === 0
> false === 0
> "" === 0
> false === undefined
> undefined === null
> undefined === undefined
``````

Javascript functions

Time
20 minutes
Activity
Individual / Small groups

Reference for this section is JavaScript functions Like Racket, JavaScript has two different ways of defining functions. The first way is by assigning an anonymous function to a variable.

```    (define square (lambda (x) (* x x)))
```
```    var square = function (x) { return x*x }
```
• How is assignment (`=`) in racket different from binding (`let`, `define`) in Racket?

• syntax is slightly different, although the mapping is fairly clear

• `return` is mandatory. What does it mean?

The more compact way of defining functions in both Racket and JavaScript combines the binding and creation of a `function`/`lambda`

```    (define (square x) (* x x))
```
```    function square(x) { return x*x }
```
• Start a new file `~/fcshome/cs2613/labs/L09/loop-arith.js`, and fill in the following definition for `mult` using `plus` and `for`.
```function plus(a,b) {
for (var i=0; i < a; i++){
b++;
}
return b;
}

function mult(a,b) {
sum=0;

return sum;
}
```
• Test your file manually, using e.g. the `node` REPL.

Node.js modules

Time
10 minutes
Activity
Demo

Chapter 10 contains a comprehensive explanation of the module system we will be using, but we don't want to wait that long to use modules. So the extremely quick and dirty guide to modules follows.

Exporting
This is analogous to `provide` in Racket. The syntax will make more sense when we know about Javascript objects. Add to `arithmetic.js` (like `provide` in racket)
```    exports.plus = plus;
exports.mult = mult;
```
``````For now, let's put these at the bottom of our files.
``````
Requiring
This is analogous to the form of the same name in Racket. Create a new file `client.js`
```    var arith=require("./loop-arith.js");
console.log(arith.plus(2,2));
```

Jasmine

There are several unit testing frameworks for JavaScript; we will be using one of the more popular ones called Jasmine.

Getting Started with Jasmine

Time
10 minutes
Activity
Demo
• run `jasmine init` in `~/fcshome/cs2613/labs/L09`. This creates a jasmine configuration under `spec`

• Save the following as `~/fcshome/cs2613/labs/L09/spec/builtins.spec.js`. Jasmine can be configured to run all files matching a certain pattern; the convention is to use `.spec.js` as the file suffix.

```    describe("identity",
function() {
it("1 === 1", function() { expect(1).toBe(1); });
it("null === null", function() { expect(null).toBe(null); })
});

describe("arithmetic",
function() {
it("1 + 1 === 2", function() { expect(1 + 1).toBe(2); });
it("6 * 7  === 42", function() { expect(6*7).toBe(42); });
});
```
• run the tests with:

\$ jasmine

• The Jasmine tutorial introduces

• test suites, created with the function `describe`
• individual test specs created with `it` and `expect`
• matchers, of which we will mainly use `toBe` which invokes `===`
• Unlike `rackunit`

• the grouping of tests into suites is not optional in Jasmine
• tests must be run from the command line

Making a test module

Time
20 minutes
Activity
Individual / Small Groups
• Unlike our first example, useful test suites will need to use `require` to access user code.

• Save the following as `~/fcshome/cs2613/labs/L09/spec/loop-arith.spec.js`

```    var arith=require ("../loop-arith.js");

function() {
it("1 + 1 = 2",
function() {
expect(                ).toBe(2);
});
it("0 + x = x",
function() {

});
});

describe("mult",
function() {
it("0 * 2 = 0",   );

it("1 * 2 = 2",
function() {
expect(arith.mult(1,2)).toBe(   );
});
it("2 * 2 = 4", );
});
```
• fill in the missing pieces to make a passing test suite.

• In order to get test coverage information, we need to run jasmine via another tool called nyc. Run the following from within `~/fcshome/cs2613/labs/L09`.

``````  % nyc jasmine
``````
• Notice that in addition to the information reported by running `jasmine`, `nyc jasmine` reports coverage figures. In these simple examples you should see 100% test coverage. You will be expected to provide 100% test coverage on assignments.

Recursion in Javascript

Time
20 Minutes
Activity
Individual / Small groups
• Fill in the recursive definition of `mult` using `plus'
```    function plus(a,b) {
if (a === 0) {
return b;
} else {
return plus(a-1, b+1);
}
}

function mult(a,b) {
if (a===0) {
return 0;
} else {

}
}
```
• One solution for the previous question would be to translate the following racket solution:
```    (define (mult a b)
(if (zero? a)
0
(plus (mult (sub1 a) b) b)))
```
• Make copy and modify `loop-arith.spec.js` to make a test suite for your new file. This should only mean changing the `require` line.

• Make a second test suite for the two modules to test them against each other. You will need two `require` statements.