Feature Tests
Test your installed guestbook against the expected specifications.
The .feature files on this page are Gherkin specifications. npx y2k-guestbook test runs them with Playwright against your installation of the guestbook:
- A
.featurefile says what should happen. - A step definition is the TypeScript that applies that behaviour in the browser.
Install Playwright
From your Next.js app root:
npm install --save-dev @playwright/test playwright-bdd
npx playwright install chromium
@playwright/test— Runs the scenarios and writes the HTML report.playwright-bdd— Reads the.featurefiles and calls your step definitions.
Confirm the package installations by running:
npm ls @playwright/test playwright-bdd
Setup
Test Reports
A test run writes to a Playwright report folder — open index.html inside to view results:
- A later run will overwrite the previous report.
- A failed scenario keeps recording in the report you can use to debug.
The default folder is features/reports/results/ — in this setup, we'll use this default folder for user tests.
-p admin writes features/reports/admin/ instead of features/reports/results/ — we'll use this custom folder for admin tests.
Support Files
features/support/ contains files that help Playwright run tests by giving them shared context:
features/support/world.ts holds the page, the guestbook URL, and values a later step needs to read:
export class PlaywrightWorld {
page!: Page;
baseUrl: string;
guestbookPath: string;
adminPath: string;
postedName?: string;
constructor() {
this.baseUrl = String(process.env.BASE_URL ?? "http://localhost:3000").replace(/\/$/, "");
this.guestbookPath = process.env.NEXT_PUBLIC_GUESTBOOK_PATH || "/";
this.adminPath = process.env.NEXT_PUBLIC_GUESTBOOK_ADMIN_PATH || "/admin";
}
}
features/support/fixtures.ts gives every step that same world.
features/support/ui.ts holds the shared locators so step definitions click visible names (submit, display name) instead of copying CSS class names.
features/support/seed.ts writes to the database when a scenario needs rows already on the board, and resets rate limits and settings so one run does not leak into the next.
Step Definitions
Example features/step_definitions/ map each Given / When / Then to clicks in the browser, covering the basic functionality of the guestbook, aligning with the Gherkin .feature files below.
You will need to write step definitions for any additional functionality you opt into (notifications, analytics) or any other features that you add.
Running Tests
Run .feature Tests
These tests do not require any admin authentication, so they can be run without any additional setup.
-
Start the guestbook preview server:
npm run dev -
In a second terminal at the app root, call:
To run a specific test in a feature file, append the
--nameflag naming a Scenario. For example:# Writes to features/reports/results/index.html npx y2k-guestbook test features/features/guestbook/guestbook-comments.feature --name "User submits a valid comment"For a specific set of tests under one Rule, append the
--tags @example-rule-nameflag:# Writes to features/reports/results/index.html npx y2k-guestbook test features/features/guestbook/guestbook-comments.feature --tags @submit-commentsFor example, the full
guestbook-nav.featurefile:# Writes to features/reports/results/index.html npx y2k-guestbook test features/features/guestbook/guestbook-nav.feature# Writes to features/reports/results/index.html npx y2k-guestbook test features/features/guestbook
-
Start the guestbook preview server:
npm run dev -
In a second terminal at the app root, call:
-
You'll need to run Chrome in debugging mode. Close all Chrome windows you might have open first, then call (replace the
--user-data-dirpaths with your own):"/c/Program Files/Google/Chrome/Application/chrome.exe" --remote-debugging-port=9222 --remote-allow-origins=* --user-data-dir="C:/Users/username/path/to/your-app/features/support/.auth/chrome-debug"open -a "Google Chrome" --args --remote-debugging-port=9222 --remote-allow-origins=* --user-data-dir="~/path/to/your-app/features/support/.auth/chrome-debug"Confirm that debugging is enabled by using the open Chrome window to view: http://127.0.0.1:9222/json/version
-
Leave the Chrome window that opens up and in a third terminal call:
To run a specific test in a feature file, append the
--nameflag naming a Scenario. For example:# Writes to features/reports/admin/index.html HEADED=1 npx y2k-guestbook test -p admin features/features/admin/admin-settings.feature --name "Admin can update the guestbook title"For a specific set of tests under one Rule, append the
--tags @example-rule-nameflag:# Writes to features/reports/admin/index.html HEADED=1 npx y2k-guestbook test -p admin features/features/admin/admin-nav.feature --tags @mobile-menuFor example, the full
admin-nav.featurefile:# Writes to features/reports/admin/index.html HEADED=1 npx y2k-guestbook test -p admin features/features/admin/admin-nav.feature# Writes to features/reports/admin/index.html HEADED=1 npx y2k-guestbook test -p admin features/features/admin -
When Google's login screen appears, sign in with your allow-listed admin user.
For gated (unauthorized) scenarios, sign in with a Google account that is not an administrator.
Optional Prefixes
By default, Playwright hides the browser window. To watch a run:
# Headed runs will run in Chrome by default
HEADED=1 npx y2k-guestbook test
To hit a deployed URL instead of localhost:
BASE_URL=https://<your-deployed-url>.vercel.app npx y2k-guestbook test
Gherkin .feature Files
Poetry Landing Page
Feature: Original Poetry landing navigation (`/`)
@desktop-nav
Rule: Hanging bookmarks serve as navigation on desktop
Background:
Given a user is on the poetry landing page on desktop
Scenario: View Docs link works on desktop
When a user clicks the `view docs` link
Then a new tab or window opens to the y2k Guestbook Docs
Scenario: Admin Login link becomes visible on hover on desktop
When a user hovers over the hidden `admin login` link
Then the `admin login` link becomes visible
Scenario: Admin Login link works on desktop
When a user clicks the `admin login` link
Then they are directed to the Google SSO page for the admin dashboard
@mobile-nav
Rule: Drop-down menu serves as navigation on mobile
Background:
Given a user is on the poetry landing page on mobile
Scenario: View Docs link works on mobile
When a user clicks the drop-down `menu` button and selects the `view docs` link
Then a new tab or window opens to the y2k Guestbook Docs
Scenario: Admin Login link works on mobile
When a user clicks the drop-down `menu` button and selects the `admin login` link
Then they are directed to the Google SSO page for the admin dashboard
@report-issue
Rule: Report Issue link takes users to the repo Issues page
Scenario: Report Issue link works on desktop
Given a user is on the poetry landing page on desktop
When a user clicks the `report issue` link
Then a new tab or window opens to `https://github.com/beck-chan/guestbook/issues`
Scenario: Report Issue link works on mobile
Given a user is on the poetry landing page on mobile
When a user clicks the drop-down `menu` button and selects the `report issue` link
Then a new tab or window opens to `https://github.com/beck-chan/guestbook/issues`
Feature: Original Poetry volume
@desktop-book
Rule: Original Poetry volume behaves as a book on desktop
Scenario: Original Poetry book opens flat
Given a user is on the poetry guestbook page on desktop (`/`)
When a user clicks the `Open Book` button
Then the Original Poetry book opens flat
Scenario: Original Poetry book closes
Given the Original Poetry book is opened flat on desktop
When a user clicks the `Close Book` button
Then the Original Poetry book closes to its original first load state
@mobile-book
Rule: Original Poetry volume scrolls on mobile
Scenario: Original Poetry book opens on mobile by scrolling
Given a user is on the poetry guestbook page on mobile (`/`)
When a user scrolls down
Then the introduction page of the Original Poetry book reveals
Scenario: Original Poetry book opens on mobile with Open Book
Given a user is on the poetry guestbook page on mobile
When a user clicks the `Open Book` button
Then the introduction page of the Original Poetry book reveals
Scenario: Original Poetry book closes on mobile
Given the user is on the introduction page of the Original Poetry book on mobile
When a user clicks the `Close Book` button
Then they are taken back up to the cover page of the Original Poetry book
Scenario: Original Poetry book poem pages turn
Given the user is on the introduction page of the Original Poetry book on mobile
When a user clicks the `Turn Page` button
Then they are taken to the poem page of the Original Poetry book
@interactive-book
Rule: Book pages are interactive
Background:
Given the Original Poetry book is opened on desktop
Scenario: Portfolio link works
Given the user is on the introduction page of the Original Poetry book
When a user clicks the `Visit Beck's Portfolio` link
Then a new tab or window opens to Beck's portfolio
Scenario: Original Poetry heart function
When a user clicks the `Like This Poem` button
Then the heart fills with colour
And the count of likes increases by 1
Scenario: Original Poetry unlike function
Given the heart is filled with colour
When a user clicks the `Like This Poem` button
Then the heart is no longer filled with colour
And the count of likes decreases by 1
Scenario: Poem page turn
When a user clicks the `Turn Page` button on a poem page
Then the poem text on the page changes
@mobile-font-size
Rule: Poem font size can be changed on mobile
Background:
Given a user is interacting with a poem page on mobile
Scenario: Users can increase poem font size
When they click the `Increase font size` button
Then the poem page font increases in size
Scenario: Users can decrease poem font size
When they click the `Decrease font size` button
Then the poem page font decreases in size
Feature: Original Poetry landing page guestbook (`/`)
@submit-comments
Rule: Guestbook allows users to submit comments
Background:
Given a user is interacting with the guestbook on the poetry landing page
Scenario: User submits a valid comment
When a user enters in a valid display name and comment body
And they click the `submit` button
Then their comment displays as the topmost guestbook entry
Scenario: User submits an empty display name
When a user leaves the display name empty
And they click the `submit` button
Then the comment is not submitted
Scenario: User submits an empty comment body
When a user leaves the comment body empty
And they click the `submit` button
Then the comment is not submitted
Scenario: User submits a comment with an email
When a user submits a valid comment with a valid email address
Then their comment displays without their email
Scenario: User submits a comment with an invalid email
When a user submits a comment with an invalid email address
Then the comment is not submitted
Scenario: User submits a comment with English profanity
When a user enters a valid display name
And enters a comment body that contains English profanity
And they click the `submit` button
Then their comment is rejected and not submitted
And the user is shown an error message
# Default display name limit is 128 characters
Scenario: User submits a display name above the character limit
When a user submits a comment with a display name longer than 128 characters
Then their comment is rejected and not submitted
And the user is shown an error message
# Default email limit is 254 characters
Scenario: User submits an email above the character limit
When a user submits a comment with an email longer than 254 characters
Then their comment is rejected and not submitted
And the user is shown an error message
# Default comment body limit is 1000 characters; 10000 is the maximum allowed configuration
Scenario: User submits a comment body above the configured character limit
When a user submits a comment with a comment body longer than 1000 characters
Then their comment is rejected and not submitted
And the user is shown an error message
# Default rate limit is 1 comment every 5 minutes and 2 comments per 24 hours
Scenario: User submissions are rate limited
When a user submits more than 1 comment within 5 minutes
Then their comment is rejected and not submitted
And the user is shown an error message
@mobile-guestbook
Rule: Guestbook is hidden on mobile by default
Background:
Given a user is on the poetry landing page on mobile (`/`)
Scenario: Guestbook can be opened on mobile
Given a user is interacting with the poetry book
When a user clicks the `Open guestbook` button
Then the guestbook opens and shows the user the commenting form
Scenario: Guestbook can be closed on mobile
Given a user has opened the guestbook on mobile
When they click the `Close guestbook` button
Then the guestbook closes and reveals the poetry book again
# Poetry guestbook always shows 4 comments per page
@pagination
Rule: Guestbook entries are paginated
Background:
Given a user is interacting with the guestbook on the poetry landing page
And there are enough comments to trigger pagination
Scenario: User views the next page of comments
When a user clicks the `next` button for comment pagination
Then the next page of comments displays
Scenario: User views the previous page of comments
When a user clicks the `prev` button for comment pagination
Then the previous page of comments displays
Admin Dashboard
Feature: Unauthorized admin login
@no-auth-desktop
Rule: Visitors without admin authorization are denied the dashboard on desktop
Background:
Given the user does not have admin authorization
And a user is on the guestbook page
Scenario: Unauthorized user is denied the dashboard on desktop
When a user clicks the `admin login` link
And they sign in successfully with Google
Then they are redirected to the landing page
And they are shown a message that they do not have admin authorization
Scenario: Unauthorized visitor message can be dismissed on desktop
Given the user is shown a message that they do not have admin authorization
When they click the `Boo hiss! Fine.` button
Then the message closes
@no-auth-mobile
Rule: Visitors without admin authorization are denied the dashboard on mobile
Background:
Given the user does not have admin authorization
And a user is on the guestbook page on mobile
Scenario: Unauthorized user is denied the dashboard on mobile
When a user clicks the drop-down `menu` button and selects the `admin login` link
And they sign in successfully with Google
Then they are redirected to the landing page
And they are shown a message that they do not have admin authorization
Scenario: Unauthorized visitor message can be dismissed on mobile
Given the user is shown a message that they do not have admin authorization
When they click the `Boo hiss! Fine.` button
Then the message closes
Feature: Authorized admin login
@desktop-auth
Rule: Allow-listed admins can access the admin dashboard on desktop
Background:
Given a user is on the main landing page of the poetry guestbook on desktop
And the user has admin authorization
Scenario: Authorized admin reaches the dashboard on desktop
When a user clicks the `admin login` link
And they sign in successfully with Google
Then they are redirected to the `/admin` dashboard
Rule: Allow-listed admins can access the admin dashboard on mobile
Background:
Given a user is on the main landing page of the poetry guestbook on mobile
And the user has admin authorization
Scenario: Authorized admin reaches the dashboard on mobile
When a user clicks the drop-down `menu` button and selects the `admin login` link
And they sign in successfully with Google
Then they are redirected to the `/admin` dashboard
Feature: Admin Dashboard page navigation
@desktop-nav
Rule: Hanging bookmark works as a link on desktop
# Hanging bookmarks are visible only above 1280px
Background:
Given an authorized admin is signed in with Google SSO
And they are on the admin dashboard on desktop (`/admin`)
Scenario: View Book link works
When an admin clicks the `view book` link
Then they are taken to the Original Poetry landing page (`/`)
@mobile-nav
Rule: Navigation is handled by a button on mobile
Background:
Given an authorized admin is signed in with Google SSO
And they are on the admin dashboard on mobile (`/admin`)
Scenario: Return to book works on mobile
When an admin clicks the `return` link
Then they are taken to the Original Poetry landing page (`/`)
@mobile-menu
Rule: Comment sort, filter, and search are in a drop-down menu on mobile
Background:
Given an authorized admin is signed in with Google SSO
And they are on the admin dashboard on mobile (`/admin`)
Scenario: Drop-down menu contains comment sort, filter, and search options
When an admin clicks the drop-down `comments menu` button
Then the `comments menu` opens showing comment sort, filter, and search options
Feature: Admin Dashboard comment interactions
Background:
Given an authorized admin is signed in with Google SSO
And they are on the admin dashboard (`/admin`)
@manage-comments
Rule: Admins can interact with comments
Scenario: Admins can filter comments by read status
When admins filter comments by read status
Then comments without the selected criteria are hidden
Scenario: Admins can filter comments by date range
When admins filter comments by date range
Then comments without the selected criteria are hidden
Scenario: Admins can filter comments by email presence
When admins filter comments by whether they were submitted with an email
Then comments without the selected criteria are hidden
Scenario: Admins can sort comments by newest
When admins sort comments by newest timestamps
Then the comments sort according to the selected criteria
And the sort display indicator updates accordingly
Scenario: Admins can sort comments by oldest
When admins sort comments by oldest timestamps
Then the comments sort according to the selected criteria
And the sort display indicator updates accordingly
Scenario: Admins can search comments
When admins search comments by keywords
Then comments not matching submitted keywords are hidden
Scenario: Filter, sort, and search results stack
Given admins have applied a sort, a filter, and a search to comments
Then results stack on top of other sorts, filters, or searches
Scenario: Admins can clear applied filters or sorting
Given admins have applied search keywords, sorting, or filters to comments
When they click the `clear all` link
Then search, filter, or sort results are cleared
Scenario: Admins can change a comment's read status
When admins mark a comment read or unread
Then the read status saves automatically
And the unread count updates accordingly
Scenario: Admins can mark all comments read
When admins click the `mark all read` button
Then all comments are marked read
And the unread count updates accordingly
Scenario: Admins can mark all comments unread
When admins click the `mark all unread` button
Then all comments are marked unread
And the unread count updates accordingly
Scenario: Admins can edit comments
When admins click on the `edit` button for a comment
And they edit the comment body
And they click away from the text editor
Then the changes are saved
Scenario: Admins can delete comments
When admins click on the `delete` button for a comment
And they click the `confirm` button
Then the comment is removed
Scenario: Admins can cancel deleting a comment
When admins click on the `delete` button for a comment
And they click the `cancel` button
Then the comment is not removed
@pagination
# Admin always shows 10 comments per page; seed only if fewer than 11 exist
Rule: Guestbook comments are paginated
Background:
Given there are enough comments to trigger pagination
Scenario: Admin views the next page of comments
When an admin clicks the `next` link for comment pagination
Then the next page of comments displays
Scenario: Admin views the previous page of comments
When an admin clicks the `prev` link for comment pagination
Then the previous page of comments displays
Feature: Admin Dashboard settings
Rule: Admin Dashboard settings apply changes
Background:
Given an authorized admin is signed in with Google SSO
And they are on the admin dashboard (`/admin`)
Scenario: Admin can update the guestbook title
When an admin updates the `title` setting
And they click the `save changes` button
Then those changes are applied to the admin dashboard
And those changes are applied to the guestbook page
Scenario: Admin can undo changes to guestbook settings
When an admin updates the `title` setting
And they click the `undo changes` button
Then those changes are not applied to the admin dashboard
And the settings revert to the previously entered values
Scenario: Admin can update the comment placeholder
When an admin updates the `placeholder` setting
And they click the `save changes` button
Then those changes are applied to the guestbook page
Scenario: Admin can turn off the title marquee
When an admin sets the `marquee` setting to `off`
And they click the `save changes` button
Then the guestbook title displays without a marquee
Scenario: Admin can set the main font and size
When an admin updates the `main font` and its `font size`
And they click the `save changes` button
Then those changes are applied to the guestbook page
Scenario: Admin can set the accent font and size
When an admin updates the `accent font` and its `font size`
And they click the `save changes` button
Then those changes are applied to the guestbook page
Scenario: Admin can set comments per page
When an admin updates the `comments per page` setting
And they click the `save changes` button
Then the guestbook page paginates at that page size
Scenario: Admin can turn off email capture
When an admin sets the `capture email` setting to `off`
And they click the `save changes` button
Then the email field is not shown on the guestbook page
Scenario: Admin can set a custom comment length
When an admin adjusts the `comment length` setting to an allowed limit
And they click the `save changes` button
Then those changes are applied to the guestbook page
Scenario: Admin can set custom rate limits
When an admin adjusts the `rate limits` settings to allowed limits
And they click the `save changes` button
Then those changes are applied to the guestbook page
Scenario: Admin can allow-list profanity
When an admin enters comma-separated values in the `profanity allow-list`
And they click the `save changes` button
Then those changes are applied to the guestbook page
Scenario: Admin can view custom CSS example file
When an admin clicks on the `view example` link for the `custom theme` setting
Then a new tab or window opens to the custom CSS example file
Write Additional Tests
If a Given / When / Then already has a matching function, Playwright runs that function. A line with no match fails with Missing step: and the text of that line. Create features/step_definitions/your-steps.ts for that line, and import the testing functions:
import { Given, When, Then } from "y2k-guestbook/testing";
Given("your scenario here", async function () {
await this.page.goto(this.guestbookUrl());
});
Fill in the body with the appropriate code to execute the step. Instruction should be written the way a human user would find things on the page — for example, reference the submit button, the display name field, the prev / next links, and not CSS class names or code.
- It doesn't matter what the file is called, as long as it's in the
features/step_definitions/directory and has the.tsextension. - Stash values you will need later on the World object (for example
this.postedName).