Web Deployment Checklist: Release and Roll Back a Course App

Practical Web Development — Lesson 10 of 10 · Senior A successful deployment command does not prove a course application works. A release is complete when important user journeys work in the target environment and the team can recognize and recover from a bad change. This lesson turns a small course app into a practical release exercise with explicit acceptance and rollback criteria. Describe the change and its risk Suppose a release adds saved course shortlists. Separate the new browser interface, the server endpoint and any database change. Identify what happens when old browser code talks to the new server, and when the previous server version reads newly written data. Rolling back code is not the same as reversing a data migration. Write a short release record before deploying. Use real commit and build identifiers in your own project; the values below are placeholders for the exercise. Change: Add saved course shortlists Build: <immutable build identifier> Owner: <person ...

Playwright Tutorial: Test a Course Filter and Empty State

Web Development Learning Series — Part 9 of 10 · Advanced

A useful browser test protects behavior that matters to a visitor. For a course catalog, that might be finding a beginner lesson and understanding when a filter has no results. A test that only proves a button exists gives less confidence.

This guide assumes an application with a visible Difficulty label, a select control, course cards, and a status message. Use the official Playwright setup instructions for a project that does not already have the test runner installed.

Define the behavior you want to protect

Prepare a controlled test catalog with one beginner course and one advanced course. The all-levels view shows both. Selecting Beginner shows only HTML Foundations. A fixture containing no advanced courses should show an honest empty state when Advanced is chosen.

Keep test data predictable. If the test depends on a public service changing its course list, you may be testing that service's content rather than your filtering logic.

A focused interaction test

With the local application running at the URL below, save this in a test file in your configured test directory. Adjust the URL and exact labels to match the application.

import { test, expect } from '@playwright/test';

test('a learner can find beginner courses', async ({ page }) => {
  await page.goto('http://127.0.0.1:3000');
  await expect(page.getByRole('heading', {
    name: 'Course catalog', exact: true
  })).toBeVisible();

  await page.getByLabel('Difficulty', { exact: true })
    .selectOption('beginner');

  await expect(page.getByRole('heading', {
    name: 'HTML Foundations', exact: true
  })).toBeVisible();
  await expect(page.getByRole('heading', {
    name: 'Web Architecture', exact: true
  })).toHaveCount(0);
  await expect(page.getByRole('status'))
    .toHaveText('1 courses found');
});

Why accessible locators help

Locating a control through its label ties the test to a feature a person can understand. A brittle selector based on a long chain of nested div elements can break when the layout changes even though the experience remains correct.

This does not mean every test must avoid test identifiers. A deliberate test identifier can be appropriate where a meaningful semantic locator is unavailable. The goal is a stable contract, not a rule applied mechanically.

Test the empty state separately

Use a fixture or test route containing only beginner courses. Choose Advanced and verify the empty message and zero count. Do not alter production content just to make a test pass. If your application fetches data, a controlled response can isolate the UI behavior from the live backend.

Also check a load failure if the application has an API. A network error should not display “No courses at this level yet,” because the program has not successfully learned whether any courses exist.

Wait for behavior, not a guessed delay

Use assertions that wait for the required result. A fixed five-second pause can be too short on a slow machine and wasteful on a fast one. When a test fails, inspect its trace or screenshot and determine which state actually appeared.

Keep independent tests independent. A beginner-filter test should not rely on another test having opened the page or changed a setting. Each test should establish its own starting state.

Choose a small, valuable test set

For this catalog, begin with all courses visible, a matching filter, an empty result, and an API failure. Add checks for navigation and keyboard use when those are part of the feature. Avoid duplicating every line of implementation in the test suite.

Practice task

Introduce a bug that ignores the selected level and confirm the matching-filter test fails. Restore the logic, then rename the visible label intentionally and update the test as part of the same change. This helps you distinguish a real behavior regression from a deliberate interface revision.

Continue your learning

Previous lesson: Core Web Vitals: Diagnose LCP, INP, and CLS on a Course Website. Explore our web development series and the HTML multimedia project.

Reference: Official documentation for this lesson. Examples are learning exercises; adapt and test them for your own application.

Comments

Popular posts from this blog

What Is Multimedia? Examples and a Beginner Course Guide

VR vs AR: Differences, Uses and Multimedia Design

Internet vs World Wide Web: HTML and Multimedia Explained