Skip to content
Back to Testing, Deployment and Maintenance course

Work & Development · Backend & Full Stack Development

Free preview

Set up the project and test the rules that matter

Lesson 1 of Testing, Deployment and Maintenance. Anyone can read this lesson with no account. Every lesson after this one is for students.

Choose meaningful checks

Create a small site and test its title rules, including the exact minimum and maximum lengths.

After this lesson you will have a small project that the whole course tests and deploys, and you will be able to choose unit tests by the risk they cover and run them with Node's built-in test runner.

This course follows Programming Foundations with JavaScript and Git and GitHub for Your Projects; it does not need React. You need Node.js 22 or newer, a GitHub account and the GitHub CLI login from the Git course.

Test a promise, not an implementation detail

Start with a promise the user depends on. For example, a title with 80 characters must be accepted, but 81 must be rejected. A broken rule may lose someone's work. Whether the function uses one loop or another matters less.

Write what would go wrong if each promise failed. That is its risk. Choose a small test that gives useful evidence about the most important risks.

A unit test checks one small function by itself. It can be quick and show exactly which rule broke. This unit test uses no browser, network or database. It cannot prove the whole page works or the live site is reachable. Later lessons add those checks.

Set up the course project

The project is a one-page resource list. A visitor types a title, and the page validates it and adds it to a list. Create a folder called study-site, open a terminal in it and run:

npm init -y
npm pkg set type=module
mkdir site test test/unit

type=module lets Node treat every .js file as an ES module, so the browser and the tests can share the same code. Save these four files in site/.

site/index.html:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Resource list</title>
  <link rel="stylesheet" href="styles.css">
  <script type="module" src="app.js"></script>
</head>
<body>
<main>
  <h1>Resource list</h1>
  <form id="add-form">
    <label for="title">Resource title</label>
    <input id="title" name="title" autocomplete="off">
    <button type="submit">Add resource</button>
  </form>
  <p id="message" role="status"></p>
  <ul id="resources"></ul>
</main>
</body>
</html>

site/styles.css:

body { font: 1rem/1.5 system-ui, sans-serif; margin: 0; color: #1f2d27; }
main { width: min(100% - 2rem, 40rem); margin: 2rem auto; }
form { display: flex; flex-wrap: wrap; gap: .5rem; align-items: end; }
label { width: 100%; font-weight: 600; }
input, button { font: inherit; padding: .5rem; }
:focus-visible { outline: 3px solid #7a4a00; outline-offset: 2px; }

site/title.js holds the rule we will test:

export function cleanTitle(value) {
  if (typeof value !== 'string') throw new TypeError('Use text');
  const title = value.trim();
  if (title.length < 3 || title.length > 80) throw new RangeError('Use 3 to 80 characters');
  return title;
}

site/app.js connects the rule to the page:

import { cleanTitle } from './title.js';

const form = document.querySelector('#add-form');
const input = document.querySelector('#title');
const message = document.querySelector('#message');
const list = document.querySelector('#resources');

form.addEventListener('submit', (event) => {
  event.preventDefault();
  try {
    const title = cleanTitle(input.value);
    const item = document.createElement('li');
    item.textContent = title;
    list.append(item);
    message.textContent = `Added ${title}.`;
    input.value = '';
  } catch (error) {
    message.textContent = error.message;
  }
  input.focus();
});

Start a local preview with npx http-server@14.1.1 site -a 127.0.0.1 -p 4173 and open http://127.0.0.1:4173/. Add Algebra guide: it appears in the list and the status reads Added Algebra guide. Try ab: the status reads Use 3 to 80 characters. Stop the server with Ctrl+C.

Worked example: a rule with meaningful boundaries

Save test/unit/title.test.js:

import test from 'node:test';
import assert from 'node:assert/strict';
import { cleanTitle } from '../../site/title.js';

test('surrounding whitespace does not become part of a stored title', () => {
  assert.equal(cleanTitle('  Algebra guide  '), 'Algebra guide');
});
test('missing and unusably short titles are rejected', () => {
  assert.throws(() => cleanTitle(null), TypeError);
  assert.throws(() => cleanTitle('  a '), RangeError);
});
test('the maximum-length contract has an exact boundary', () => {
  assert.equal(cleanTitle('a'.repeat(80)).length, 80);
  assert.throws(() => cleanTitle('a'.repeat(81)), RangeError);
});

Run it:

node --test test/unit/title.test.js

You should see # tests 3, # pass 3 and # fail 0. These checks describe the function's contract, its promised behavior: trim spaces, reject missing or short input, and accept at most 80 characters. You could change how cleanTitle works internally while keeping these tests. A one-character boundary mistake would still fail.

Practice

  1. Make a risk table for this project with five things a user depends on, what breaks if each fails, and which kind of check fits: unit, page (simulated browser), browser journey, or deployed smoke check.
  2. Break the code on purpose, one change at a time: remove .trim(), then change > 80 to > 81. Run the tests after each change and note which test catches it. Restore the code.
  3. Add a test that a title of exactly 3 characters is accepted.

Expected result: two caught defects, a passing fourth test and a risk table you will reuse.

Check yourself

  1. Can a unit test prove the deployed site is reachable?
  2. Why test both 80 and 81 characters?
  3. Does a green test run mean every risk is covered?

Answers

  1. No. It never touches a server or a browser.
  2. 80 is the last accepted length and 81 the first rejected one, so together they pin the boundary exactly.
  3. No. It covers only the cases you wrote, in the environment where they ran.

Commit the project and push it to a new public GitHub repository named study-site, as in the Git course (it must be public for free GitHub Pages hosting later; it contains no personal information). Next, you will test the page itself in a simulated browser.

Sources: Node test runner, Node assertions.

Continue with the full course

This free preview is lesson 1 only. Enroll to open the rest of Testing, Deployment and Maintenance.