Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ _site
.jekyll-cache
.jekyll-metadata
vendor
node_modules
test-results
playwright-report
visual-regression-current.png
visual-regression-result.png
54 changes: 54 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Managerbot Website

## Development

### Prerequisites

- Ruby (with Bundler)
- Node.js (for visual regression tests)

### Running locally

```bash
bundle install
bundle exec jekyll serve
```

The site will be available at `http://localhost:4000`.

## Visual Regression Testing

Visual regression tests use Playwright to capture screenshots of the home page and compare them against a baseline to detect unintended visual changes.

### Setup

```bash
npm install
npx playwright install chromium
```

### Running tests

1. Start the Jekyll server:
```bash
bundle exec jekyll serve
```

2. In a separate terminal, run the visual regression test:
```bash
npm run visual-regression:check
```

### Updating the baseline

If you've made intentional visual changes, update the baseline snapshot:

```bash
npm run visual-regression
```

### Output

Each test run saves images in the root directory:
- `visual-regression-current.png` - the current screenshot (always saved)
- `visual-regression-diff.png` - diff image highlighting visual changes (only when differences detected)
27 changes: 8 additions & 19 deletions _config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,11 @@ sass:

plugins:
- jekyll-feed
# Exclude from processing.
# The following items will not be processed, by default.
# Any item listed under the `exclude:` key here will be automatically added to
# the internal "default list".
#
# Excluded items can be processed by explicitly listing the directories or
# their entries' file path in the `include:` list.
#
# exclude:
# - .sass-cache/
# - .jekyll-cache/
# - gemfiles/
# - Gemfile
# - Gemfile.lock
# - node_modules/
# - vendor/bundle/
# - vendor/cache/
# - vendor/gems/
# - vendor/ruby/
exclude:
- node_modules/
- tests/
- package.json
- package-lock.json
- playwright.config.ts
- test-results/
- playwright-report/
96 changes: 96 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "hyper-unearthing-visual-tests",
"version": "1.0.0",
"scripts": {
"visual-regression": "npx playwright test visual-regression.spec.ts --update-snapshots",
"visual-regression:check": "npx playwright test visual-regression.spec.ts"
},
"devDependencies": {
"@playwright/test": "^1.40.0",
"@types/node": "^20.0.0"
}
}
20 changes: 20 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { defineConfig } from '@playwright/test';

export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: 0,
workers: 1,
reporter: 'list',
use: {
baseURL: 'http://localhost:4000',
trace: 'off',
},
snapshotPathTemplate: '{testDir}/__snapshots__/{testFilePath}/{arg}{ext}',
expect: {
toHaveScreenshot: {
maxDiffPixelRatio: 0.01,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using a lower tolerance value for maxDiffPixelRatio. 0.01 (1%) might still allow noticeable visual differences to pass. Depending on your UI complexity, values between 0.001-0.005 might be more appropriate.

},
},
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 48 additions & 0 deletions tests/visual-regression.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { test, expect } from '@playwright/test';
import * as fs from 'fs';
import * as path from 'path';

const OUTPUT_DIR = path.join(__dirname, '..');
const DIFF_IMAGE = path.join(OUTPUT_DIR, 'visual-regression-diff.png');
const CURRENT_IMAGE = path.join(OUTPUT_DIR, 'visual-regression-current.png');

test('home page visual regression', async ({ page }, testInfo) => {
await page.goto('/');

// Wait for the page to be fully loaded
await page.waitForLoadState('networkidle');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

networkidle can be flaky for pages with continuous background activity. Consider adding additional stabilization checks or a fixed timeout if needed.


// Always save the current screenshot
const screenshot = await page.screenshot({ fullPage: true });
fs.writeFileSync(CURRENT_IMAGE, screenshot);

try {
await expect(page).toHaveScreenshot('home-page.png', {
fullPage: true,
maxDiffPixelRatio: 0.01,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplicates the maxDiffPixelRatio setting that's already in the global config. Consider removing it here to keep configuration in one place.

});

// Test passed - remove diff image if it exists
if (fs.existsSync(DIFF_IMAGE)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider wrapping file operations in try/catch blocks to handle potential file system errors gracefully.

fs.unlinkSync(DIFF_IMAGE);
}
console.log(`✓ No visual differences detected.`);
console.log(` Current screenshot: ${CURRENT_IMAGE}`);
} catch (error) {
// Test failed - find and copy the diff image
const attachments = testInfo.attachments;
const diffAttachment = attachments.find(a => a.name === 'home-page-diff.png');

if (diffAttachment && diffAttachment.path) {
fs.copyFileSync(diffAttachment.path, DIFF_IMAGE);
console.log(`✗ Visual differences detected!`);
console.log(` Diff image: ${DIFF_IMAGE}`);
console.log(` Current screenshot: ${CURRENT_IMAGE}`);
} else {
console.log(`✗ Visual differences detected.`);
console.log(` Current screenshot: ${CURRENT_IMAGE}`);
}

throw error;
}
});