From 869b08ec0e6e28eba41af67835132cf57e59b09e Mon Sep 17 00:00:00 2001 From: colin Date: Sun, 6 Jul 2025 16:05:03 -0400 Subject: [PATCH] Integrate CSP hash update process into test framework --- tests/README.md | 97 ++++++++++ tests/integration/csp-hash-test.sh | 92 ++++++++++ tests/integration/csv-tool/test-csv-tool.sh | 52 ++++++ tests/integration/functional-test.sh | 122 +++++++++++++ tests/integration/includes-test.sh | 108 +++++++++++ tests/integration/main-page-test.sh | 63 +++++++ tests/integration/stories-test.sh | 76 ++++++++ tests/integration/theme-test.sh | 88 +++++++++ tests/pre-test-setup.sh | 35 ++++ tests/run-all-tests.sh | 112 ++++++++++++ tests/run-tests.sh | 192 ++++++++++++++++++++ tests/unit/includes-test.sh | 48 +++++ tests/unit/theme-test.sh | 45 +++++ 13 files changed, 1130 insertions(+) create mode 100644 tests/README.md create mode 100755 tests/integration/csp-hash-test.sh create mode 100755 tests/integration/csv-tool/test-csv-tool.sh create mode 100755 tests/integration/functional-test.sh create mode 100755 tests/integration/includes-test.sh create mode 100755 tests/integration/main-page-test.sh create mode 100755 tests/integration/stories-test.sh create mode 100755 tests/integration/theme-test.sh create mode 100755 tests/pre-test-setup.sh create mode 100755 tests/run-all-tests.sh create mode 100755 tests/run-tests.sh create mode 100755 tests/unit/includes-test.sh create mode 100755 tests/unit/theme-test.sh diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..2544d44 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,97 @@ +# Resume Site Tests + +This directory contains tests for the resume site. + +## Directory Structure + +- `unit/`: Unit tests for JavaScript files and other components +- `integration/`: Integration tests that test components working together +- `e2e/`: End-to-end tests that simulate user interactions +- `*.test.js`, `*.spec.js`: Playwright test files +- `lighthouse.js`: Lighthouse performance and accessibility tests +- `serve.js`: Simple Node.js server for testing +- `server.js`: Alternative server implementation +- `pre-test-setup.sh`: Script to set up the test environment, including updating CSP hashes + +## Running Tests + +To run all tests: + +```bash +./run-all-tests.sh +``` + +Or using npm: + +```bash +npm test +``` + +This will: +1. Run the pre-test setup script to update CSP hashes +2. Check if the server is running +3. Run all shell script tests +4. Run Playwright tests if available +5. Run Lighthouse tests + +## Content Security Policy (CSP) Testing + +The CSP hash update process is an important part of the testing framework. It ensures that: + +1. All JavaScript and CSS files have integrity hashes +2. All inline styles have proper CSP hashes +3. The Caddyfile and HTML files have the correct CSP headers/meta tags + +The `pre-test-setup.sh` script runs the `update-csp-hashes.sh` script to update all CSP hashes before running the tests. This ensures that any changes to the website are properly reflected in the CSP hashes. + +The `csp-hash-test.sh` integration test checks if the CSP hash update process is working properly by verifying that: + +- CSP headers are present in the response +- CSP headers contain the required directives +- JavaScript and CSS files have integrity attributes +- HTML files have CSP meta tags + +## Running Specific Tests + +### JavaScript Tests + +```bash +npm run test:js +``` + +### Lighthouse Tests + +```bash +npm run test:lighthouse +``` + +### Starting the Test Server + +```bash +npm run serve +``` + +## Adding New Tests + +### Shell Script Tests + +Add new test scripts to the appropriate directory: +- `unit/`: For unit tests +- `integration/`: For integration tests +- `e2e/`: For end-to-end tests + +Shell script tests should: +- Be executable bash scripts +- Return exit code 0 for success, non-zero for failure +- For integration and e2e tests, accept a base URL as the first argument + +### Playwright Tests + +Add new Playwright tests with the `.test.js` or `.spec.js` extension in the tests directory. + +## Test Requirements + +As per the project guidelines, all tests must: +- Pass for both mobile and desktop viewports +- Maintain Lighthouse scores: 100/100 for accessibility and SEO +- Include meaningful assertions, not placeholders diff --git a/tests/integration/csp-hash-test.sh b/tests/integration/csp-hash-test.sh new file mode 100755 index 0000000..434dd34 --- /dev/null +++ b/tests/integration/csp-hash-test.sh @@ -0,0 +1,92 @@ +#!/bin/bash +# ===================================================================== +# csp-hash-test.sh - Test the CSP hash update process +# ===================================================================== +# This script checks if the CSP hash update process is working properly +# ===================================================================== + +# Check if base URL is provided +if [ -z "$1" ]; then + BASE_URL="http://localhost:8080" +else + BASE_URL="$1" +fi + +echo "=== Testing CSP Hash Update Process ===" +echo "Using base URL: $BASE_URL" + +# Array to track failures +FAILURES=0 + +# Check if the CSP headers are present +echo "Checking if CSP headers are present..." +RESPONSE=$(curl -s -I "$BASE_URL/") +if echo "$RESPONSE" | grep -q "Content-Security-Policy"; then + echo "✅ CSP header found in response" +else + echo "❌ CSP header not found in response" + FAILURES=$((FAILURES+1)) +fi + +# Check if the CSP header contains the required directives +echo "Checking if CSP header contains required directives..." +CSP_HEADER=$(curl -s -I "$BASE_URL/" | grep -i "Content-Security-Policy" | sed 's/.*: //') + +for directive in "default-src" "script-src" "style-src" "img-src" "font-src" "connect-src" "object-src" "frame-ancestors" "base-uri" "form-action"; do + if echo "$CSP_HEADER" | grep -q "$directive"; then + echo "✅ CSP header contains $directive directive" + else + echo "❌ CSP header does not contain $directive directive" + FAILURES=$((FAILURES+1)) + fi +done + +# Check if JavaScript files have integrity attributes +echo "Checking if JavaScript files have integrity attributes..." +for js_file in "theme.js" "includes.js"; do + HTML=$(curl -s "$BASE_URL/") + if echo "$HTML" | grep -q "$js_file.*integrity"; then + echo "✅ $js_file has integrity attribute" + else + echo "❌ $js_file does not have integrity attribute" + FAILURES=$((FAILURES+1)) + fi +done + +# Check if CSS files have integrity attributes +echo "Checking if CSS files have integrity attributes..." +HTML=$(curl -s "$BASE_URL/") +if echo "$HTML" | grep -q "styles.css.*integrity"; then + echo "✅ styles.css has integrity attribute" +else + echo "❌ styles.css does not have integrity attribute" + FAILURES=$((FAILURES+1)) +fi + +# Check if HTML files have CSP meta tags +echo "Checking if HTML files have CSP meta tags..." +HTML=$(curl -s "$BASE_URL/") +if echo "$HTML" | grep -q ' /tmp/test.csv + +# Check if the page loads properly +echo "Checking if the CSV tool page loads properly..." +RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/one-pager-tools/csv-tool.html") + +if [ "$RESPONSE" -eq 200 ]; then + echo "✅ CSV tool page loads successfully (HTTP $RESPONSE)" +else + echo "❌ CSV tool page failed to load (HTTP $RESPONSE)" + rm -f /tmp/test.csv + exit 1 +fi + +# Check for CSP errors in the response headers +echo "Checking for CSP errors in response headers..." +CSP_HEADER=$(curl -s -I "$BASE_URL/one-pager-tools/csv-tool.html" | grep -i "Content-Security-Policy") + +if [ -n "$CSP_HEADER" ]; then + echo "✅ CSP header found in response" +else + echo "❌ CSP header not found in response" + rm -f /tmp/test.csv + exit 1 +fi + +# Clean up +rm -f /tmp/test.csv + +echo "=== CSV Tool Test Completed Successfully ===" +exit 0 diff --git a/tests/integration/functional-test.sh b/tests/integration/functional-test.sh new file mode 100755 index 0000000..7f76099 --- /dev/null +++ b/tests/integration/functional-test.sh @@ -0,0 +1,122 @@ +#!/bin/bash +# ===================================================================== +# functional-test.sh - Test the main functionality of the website +# ===================================================================== +# This script checks if the main features of the website are working +# ===================================================================== + +# Check if base URL is provided +if [ -z "$1" ]; then + BASE_URL="http://localhost:8080" +else + BASE_URL="$1" +fi + +echo "=== Testing Website Functionality ===" +echo "Using base URL: $BASE_URL" + +# Array to track failures +FAILURES=0 + +# Function to test a page and check for expected content +test_page() { + local url="$1" + local name="$2" + local expected_title="$3" + local expected_content="$4" + + echo "Testing $name page at $url" + + # Check if the page loads + RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$url") + if [ "$RESPONSE" -eq 200 ]; then + echo "✅ $name page loads successfully (HTTP $RESPONSE)" + else + echo "❌ $name page failed to load (HTTP $RESPONSE)" + FAILURES=$((FAILURES+1)) + return + fi + + # Check page title + TITLE=$(curl -s "$url" | grep -o ".*" | sed 's/\(.*\)<\/title>/\1/') + if [[ "$TITLE" == *"$expected_title"* ]]; then + echo "✅ Page title matches: $TITLE" + else + echo "❌ Page title doesn't match. Expected: $expected_title, Got: $TITLE" + FAILURES=$((FAILURES+1)) + fi + + # Check for expected content + if [ -n "$expected_content" ]; then + CONTENT=$(curl -s "$url") + if echo "$CONTENT" | grep -q "$expected_content"; then + echo "✅ Page contains expected content: $expected_content" + else + echo "❌ Page doesn't contain expected content: $expected_content" + FAILURES=$((FAILURES+1)) + fi + fi + + echo "---" +} + +# Test main page +test_page "$BASE_URL/" "Main" "Colin Knapp - Portfolio" "Colin Knapp" + +# Test stories page +test_page "$BASE_URL/stories/" "Stories" "Stories" "Case Studies" + +# Test CSV tool +test_page "$BASE_URL/one-pager-tools/csv-tool.html" "CSV Tool" "CSV Viewer" "Paste your CSV data here" + +# Check for JavaScript files +echo "Checking for required JavaScript files..." +JS_FILES=("theme.js" "includes.js" "utils.js") +for js_file in "${JS_FILES[@]}"; do + RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/$js_file") + if [ "$RESPONSE" -eq 200 ]; then + echo "✅ $js_file loads successfully (HTTP $RESPONSE)" + else + echo "❌ $js_file failed to load (HTTP $RESPONSE)" + FAILURES=$((FAILURES+1)) + fi +done + +# Check for CSS files +echo "Checking for required CSS files..." +CSS_FILES=("styles.css") +for css_file in "${CSS_FILES[@]}"; do + RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/$css_file") + if [ "$RESPONSE" -eq 200 ]; then + echo "✅ $css_file loads successfully (HTTP $RESPONSE)" + else + echo "❌ $css_file failed to load (HTTP $RESPONSE)" + FAILURES=$((FAILURES+1)) + fi +done + +# Check for security headers +echo "Checking for security headers..." +HEADERS=$(curl -s -I "$BASE_URL/") +if echo "$HEADERS" | grep -q "Content-Security-Policy"; then + echo "✅ Content-Security-Policy header found" +else + echo "❌ Content-Security-Policy header not found" + FAILURES=$((FAILURES+1)) +fi + +if echo "$HEADERS" | grep -q "X-Frame-Options"; then + echo "✅ X-Frame-Options header found" +else + echo "❌ X-Frame-Options header not found" + FAILURES=$((FAILURES+1)) +fi + +# Check if any failures occurred +if [ "$FAILURES" -eq 0 ]; then + echo "=== All Functionality Tests Passed ===" + exit 0 +else + echo "=== Functionality Tests Failed: $FAILURES failures ===" + exit 1 +fi diff --git a/tests/integration/includes-test.sh b/tests/integration/includes-test.sh new file mode 100755 index 0000000..2b992d3 --- /dev/null +++ b/tests/integration/includes-test.sh @@ -0,0 +1,108 @@ +#!/bin/bash +# ===================================================================== +# includes-test.sh - Test the includes functionality +# ===================================================================== +# This script checks if the includes system is working properly +# ===================================================================== + +# Check if base URL is provided +if [ -z "$1" ]; then + BASE_URL="http://localhost:8080" +else + BASE_URL="$1" +fi + +echo "=== Testing Includes Functionality ===" +echo "Using base URL: $BASE_URL" + +# Array to track failures +FAILURES=0 + +# Test if includes.js exists and loads properly +echo "Checking if includes.js exists and loads properly..." +RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/includes.js") +if [ "$RESPONSE" -eq 200 ]; then + echo "✅ includes.js loads successfully (HTTP $RESPONSE)" + + # Check includes.js content + INCLUDES_JS=$(curl -s "$BASE_URL/includes.js") + if echo "$INCLUDES_JS" | grep -q "includeHTML"; then + echo "✅ includes.js contains includeHTML function" + else + echo "❌ includes.js doesn't contain includeHTML function" + FAILURES=$((FAILURES+1)) + fi + + if echo "$INCLUDES_JS" | grep -q "DOMContentLoaded"; then + echo "✅ includes.js contains DOMContentLoaded event listener" + else + echo "❌ includes.js doesn't contain DOMContentLoaded event listener" + FAILURES=$((FAILURES+1)) + fi +else + echo "❌ includes.js failed to load (HTTP $RESPONSE)" + FAILURES=$((FAILURES+1)) +fi + +# Check if the includes/header.html file exists +echo "Checking includes/header.html file..." +RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/includes/header.html") +if [ "$RESPONSE" -eq 200 ] || [ "$RESPONSE" -eq 403 ]; then + echo "✅ includes/header.html file exists (HTTP $RESPONSE)" +else + echo "❌ includes/header.html file doesn't exist (HTTP $RESPONSE)" + FAILURES=$((FAILURES+1)) +fi + +# Check if pages with includes load correctly +echo "Checking pages that use includes..." +INCLUDE_PAGES=( + "template-with-includes.html" + "stories/story-with-includes.html" + "one-pager-tools/tool-with-includes.html" +) + +for page in "${INCLUDE_PAGES[@]}"; do + RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/$page") + if [ "$RESPONSE" -eq 200 ]; then + echo "✅ $page loads successfully (HTTP $RESPONSE)" + + # Check if the page has include placeholders + CONTENT=$(curl -s "$BASE_URL/$page") + if echo "$CONTENT" | grep -q "id=\"header-include\""; then + echo "✅ $page has header include placeholder" + else + echo "❌ $page doesn't have header include placeholder" + FAILURES=$((FAILURES+1)) + fi + + if echo "$CONTENT" | grep -q "id=\"footer-include\""; then + echo "✅ $page has footer include placeholder" + else + echo "❌ $page doesn't have footer include placeholder" + FAILURES=$((FAILURES+1)) + fi + + # Check if includes.js is included in the page + if echo "$CONTENT" | grep -q "includes.js"; then + echo "✅ $page includes the includes.js script" + else + echo "❌ $page doesn't include the includes.js script" + FAILURES=$((FAILURES+1)) + fi + else + echo "❌ $page failed to load (HTTP $RESPONSE)" + FAILURES=$((FAILURES+1)) + fi + + echo "---" +done + +# Check if any failures occurred +if [ "$FAILURES" -eq 0 ]; then + echo "=== All Includes Tests Passed ===" + exit 0 +else + echo "=== Includes Tests Failed: $FAILURES failures ===" + exit 1 +fi diff --git a/tests/integration/main-page-test.sh b/tests/integration/main-page-test.sh new file mode 100755 index 0000000..f005e3c --- /dev/null +++ b/tests/integration/main-page-test.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# ===================================================================== +# main-page-test.sh - Test the main page functionality +# ===================================================================== +# This script checks if the main page loads correctly +# ===================================================================== + +# Check if base URL is provided +if [ -z "$1" ]; then + BASE_URL="http://localhost:8080" +else + BASE_URL="$1" +fi + +echo "=== Testing Main Page ===" +echo "Using base URL: $BASE_URL" + +# Check if the main page loads properly +echo "Checking if the main page loads properly..." +RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/index.html") + +if [ "$RESPONSE" -eq 200 ]; then + echo "✅ Main page loads successfully (HTTP $RESPONSE)" +else + echo "❌ Main page failed to load (HTTP $RESPONSE)" + exit 1 +fi + +# Check for page title +echo "Checking page title..." +TITLE=$(curl -s "$BASE_URL/index.html" | grep -o "<title>.*") + +if [ -n "$TITLE" ]; then + echo "✅ Page title found: $TITLE" +else + echo "❌ Page title not found" + exit 1 +fi + +# Check for CSS loading +echo "Checking if CSS loads properly..." +CSS_LINK=$(curl -s "$BASE_URL/index.html" | grep -o ']*href="[^"]*styles.css[^"]*"[^>]*>') + +if [ -n "$CSS_LINK" ]; then + echo "✅ CSS link found: $CSS_LINK" + + # Check if the CSS file itself loads + CSS_URL=$(echo "$CSS_LINK" | grep -o 'href="[^"]*"' | sed 's/href="//;s/"$//') + CSS_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/$CSS_URL") + + if [ "$CSS_RESPONSE" -eq 200 ]; then + echo "✅ CSS file loads successfully (HTTP $CSS_RESPONSE)" + else + echo "❌ CSS file failed to load (HTTP $CSS_RESPONSE)" + exit 1 + fi +else + echo "❌ CSS link not found" + exit 1 +fi + +echo "=== Main Page Test Completed Successfully ===" +exit 0 diff --git a/tests/integration/stories-test.sh b/tests/integration/stories-test.sh new file mode 100755 index 0000000..3faf5f7 --- /dev/null +++ b/tests/integration/stories-test.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# ===================================================================== +# stories-test.sh - Test all story pages +# ===================================================================== +# This script checks if all story pages load correctly +# ===================================================================== + +# Check if base URL is provided +if [ -z "$1" ]; then + BASE_URL="http://localhost:8080" +else + BASE_URL="$1" +fi + +echo "=== Testing Story Pages ===" +echo "Using base URL: $BASE_URL" + +# Get the list of story pages from the stories index +echo "Getting list of story pages..." +STORY_LINKS=$(curl -s "$BASE_URL/stories/index.html" | grep -o 'href="[^"]*\.html"' | grep -v 'index.html' | sed 's/href="//;s/"$//') + +if [ -z "$STORY_LINKS" ]; then + echo "❌ No story links found in stories/index.html" + exit 1 +fi + +echo "Found story links: $STORY_LINKS" + +# Test each story page +FAILED=0 +for link in $STORY_LINKS; do + # Make sure the link is properly formed + if [[ "$link" != /* && "$link" != http* ]]; then + # Relative link, add stories/ prefix if needed + if [[ "$link" != stories/* ]]; then + STORY_URL="$BASE_URL/stories/$link" + else + STORY_URL="$BASE_URL/$link" + fi + elif [[ "$link" == /* ]]; then + # Absolute path + STORY_URL="$BASE_URL$link" + else + # Full URL + STORY_URL="$link" + fi + + echo "Testing story page: $STORY_URL" + RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$STORY_URL") + + if [ "$RESPONSE" -eq 200 ]; then + echo "✅ Story page loads successfully (HTTP $RESPONSE)" + + # Check for required elements + CONTENT=$(curl -s "$STORY_URL") + if echo "$CONTENT" | grep -q "

" && echo "$CONTENT" | grep -q "

"; then + echo "✅ Story page has required elements (h1 and p tags)" + else + echo "❌ Story page is missing required elements" + FAILED=1 + fi + else + echo "❌ Story page failed to load (HTTP $RESPONSE)" + FAILED=1 + fi + + echo "---" +done + +if [ "$FAILED" -eq 0 ]; then + echo "=== All Story Pages Test Completed Successfully ===" + exit 0 +else + echo "=== Story Pages Test Failed ===" + exit 1 +fi diff --git a/tests/integration/theme-test.sh b/tests/integration/theme-test.sh new file mode 100755 index 0000000..c62d69b --- /dev/null +++ b/tests/integration/theme-test.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# ===================================================================== +# theme-test.sh - Test the theme functionality +# ===================================================================== +# This script checks if the theme system is working properly +# ===================================================================== + +# Check if base URL is provided +if [ -z "$1" ]; then + BASE_URL="http://localhost:8080" +else + BASE_URL="$1" +fi + +echo "=== Testing Theme Functionality ===" +echo "Using base URL: $BASE_URL" + +# Array to track failures +FAILURES=0 + +# Test if theme.js exists and loads properly +echo "Checking if theme.js exists and loads properly..." +RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/theme.js") +if [ "$RESPONSE" -eq 200 ]; then + echo "✅ theme.js loads successfully (HTTP $RESPONSE)" + + # Check theme.js content + THEME_JS=$(curl -s "$BASE_URL/theme.js") + if echo "$THEME_JS" | grep -q "DOMContentLoaded"; then + echo "✅ theme.js contains DOMContentLoaded event listener" + else + echo "❌ theme.js doesn't contain DOMContentLoaded event listener" + FAILURES=$((FAILURES+1)) + fi + + if echo "$THEME_JS" | grep -q "themeToggle"; then + echo "✅ theme.js contains themeToggle functionality" + else + echo "❌ theme.js doesn't contain themeToggle functionality" + FAILURES=$((FAILURES+1)) + fi + + if echo "$THEME_JS" | grep -q "localStorage"; then + echo "✅ theme.js uses localStorage for theme persistence" + else + echo "❌ theme.js doesn't use localStorage for theme persistence" + FAILURES=$((FAILURES+1)) + fi +else + echo "❌ theme.js failed to load (HTTP $RESPONSE)" + FAILURES=$((FAILURES+1)) +fi + +# Check if CSS has theme-related styles +echo "Checking if styles.css has theme-related styles..." +RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/styles.css") +if [ "$RESPONSE" -eq 200 ]; then + echo "✅ styles.css loads successfully (HTTP $RESPONSE)" + + # Check styles.css content for theme-related styles + STYLES_CSS=$(curl -s "$BASE_URL/styles.css") + if echo "$STYLES_CSS" | grep -q "data-theme"; then + echo "✅ styles.css contains data-theme attribute selectors" + else + echo "❌ styles.css doesn't contain data-theme attribute selectors" + FAILURES=$((FAILURES+1)) + fi + + # Check for dark mode styles + if echo "$STYLES_CSS" | grep -q "dark"; then + echo "✅ styles.css contains dark mode styles" + else + echo "❌ styles.css doesn't contain dark mode styles" + FAILURES=$((FAILURES+1)) + fi +else + echo "❌ styles.css failed to load (HTTP $RESPONSE)" + FAILURES=$((FAILURES+1)) +fi + +# Check if any failures occurred +if [ "$FAILURES" -eq 0 ]; then + echo "=== All Theme Tests Passed ===" + exit 0 +else + echo "=== Theme Tests Failed: $FAILURES failures ===" + exit 1 +fi diff --git a/tests/pre-test-setup.sh b/tests/pre-test-setup.sh new file mode 100755 index 0000000..5b49655 --- /dev/null +++ b/tests/pre-test-setup.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# ===================================================================== +# pre-test-setup.sh - Setup for tests +# ===================================================================== +# This script sets up the environment for testing +# ===================================================================== + +set -e # Exit on any error + +TESTS_DIR="$(dirname "$0")" +RESUME_DIR="$(pwd)/docker/resume" + +echo "=== Setting Up Test Environment ===" + +# Check if we're in the correct directory +if [ ! -d "$RESUME_DIR" ]; then + echo "Error: Could not find the resume directory at $RESUME_DIR" + echo "Make sure you're running this script from the project root" + exit 1 +fi + +# Run the CSP hash update script +echo "Running CSP hash update script..." +cd "$RESUME_DIR" +if [ -f "./update-csp-hashes.sh" ]; then + ./update-csp-hashes.sh +else + echo "Error: Could not find update-csp-hashes.sh script" + exit 1 +fi + +# Return to the original directory +cd - > /dev/null + +echo "=== Test Environment Setup Complete ===" diff --git a/tests/run-all-tests.sh b/tests/run-all-tests.sh new file mode 100755 index 0000000..2c0884e --- /dev/null +++ b/tests/run-all-tests.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# ===================================================================== +# run-all-tests.sh - Run all tests against an existing server +# ===================================================================== +# This script runs all tests against an existing server +# ===================================================================== + +set -e # Exit on any error + +# Define constants +BASE_URL="http://localhost:8080" +TESTS_DIR="$(dirname "$0")" + +# Run pre-test setup +echo "Running pre-test setup..." +if [ -f "$TESTS_DIR/pre-test-setup.sh" ]; then + "$TESTS_DIR/pre-test-setup.sh" +else + echo "Warning: pre-test-setup.sh not found, skipping setup" +fi + +# Check if the server is running +echo "Checking if server is running at $BASE_URL..." +if ! curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/" | grep -q "200"; then + echo "Server is not running at $BASE_URL. Please start it using:" + echo "cd docker/resume && ./caddy.sh" + exit 1 +fi + +echo "Server is running at $BASE_URL" + +# Run shell script tests +run_shell_tests() { + echo "Running shell script tests..." + + # Run unit tests + echo "Running unit tests..." + if [ -d "$TESTS_DIR/unit" ] && [ "$(ls -A "$TESTS_DIR/unit")" ]; then + for test in "$TESTS_DIR/unit"/*.sh; do + if [ -f "$test" ] && [ -x "$test" ]; then + echo "Running unit test: $(basename "$test")" + "$test" || echo "FAILED: $(basename "$test")" + fi + done + else + echo "No unit tests found." + fi + + # Run integration tests + echo "Running integration tests..." + if [ -d "$TESTS_DIR/integration" ] && [ "$(ls -A "$TESTS_DIR/integration")" ]; then + for test in "$TESTS_DIR/integration"/*.sh; do + if [ -f "$test" ] && [ -x "$test" ]; then + echo "Running integration test: $(basename "$test")" + "$test" "$BASE_URL" || echo "FAILED: $(basename "$test")" + fi + done + + # Check for subdirectories + for dir in "$TESTS_DIR/integration"/*/; do + if [ -d "$dir" ]; then + for test in "$dir"*.sh; do + if [ -f "$test" ] && [ -x "$test" ]; then + echo "Running integration test: $(basename "$test")" + "$test" "$BASE_URL" || echo "FAILED: $(basename "$test")" + fi + done + fi + done + else + echo "No integration tests found." + fi + + # Run e2e tests + echo "Running e2e tests..." + if [ -d "$TESTS_DIR/e2e" ] && [ "$(ls -A "$TESTS_DIR/e2e")" ]; then + for test in "$TESTS_DIR/e2e"/*.sh; do + if [ -f "$test" ] && [ -x "$test" ]; then + echo "Running e2e test: $(basename "$test")" + "$test" "$BASE_URL" || echo "FAILED: $(basename "$test")" + fi + done + else + echo "No e2e tests found." + fi +} + +# Run JavaScript tests +run_js_tests() { + echo "Running JavaScript tests..." + + # Check if Playwright is installed + if command -v npx &> /dev/null && npx playwright --version &> /dev/null; then + # Run Playwright tests + echo "Running Playwright tests..." + npx playwright test || echo "FAILED: Playwright tests" + else + echo "Playwright not found, skipping Playwright tests." + fi + + # Run Lighthouse tests if available + if [ -f "$TESTS_DIR/lighthouse.js" ]; then + echo "Running Lighthouse tests..." + node "$TESTS_DIR/lighthouse.js" "$BASE_URL" || echo "FAILED: Lighthouse tests" + fi +} + +# Main execution +echo "=== Starting Test Suite ===" +run_shell_tests +run_js_tests +echo "=== Test Suite Completed ===" diff --git a/tests/run-tests.sh b/tests/run-tests.sh new file mode 100755 index 0000000..04e1936 --- /dev/null +++ b/tests/run-tests.sh @@ -0,0 +1,192 @@ +#!/bin/bash +# ===================================================================== +# run-tests.sh - Main test runner for the resume site +# ===================================================================== +# This script starts a local Caddy server and runs all tests against it +# ===================================================================== + +set -e # Exit on any error + +# Define constants +TEST_PORT=8080 +CADDY_DIR="docker/resume" +CADDY_FILE="Caddyfile.local" +TESTS_DIR="$(dirname "$0")" +LOG_FILE="$TESTS_DIR/test-run.log" + +# Function to clean up processes on exit +cleanup() { + echo "Cleaning up..." + # Find and kill any Caddy processes we started + if [ -f "$TESTS_DIR/.caddy.pid" ]; then + CADDY_PID=$(cat "$TESTS_DIR/.caddy.pid") + if ps -p $CADDY_PID > /dev/null; then + echo "Stopping Caddy server (PID: $CADDY_PID)" + kill $CADDY_PID + fi + rm "$TESTS_DIR/.caddy.pid" + fi + + echo "Cleanup complete" +} + +# Register the cleanup function to run on exit +trap cleanup EXIT + +# Start the Caddy server +start_caddy() { + echo "Starting Caddy server on port $TEST_PORT..." + + # Navigate to the Caddy directory + cd "$CADDY_DIR" + + # Check if Caddyfile.local exists, if not, create it from Caddyfile + if [ ! -f "$CADDY_FILE" ]; then + echo "Creating $CADDY_FILE from Caddyfile..." + cp Caddyfile "$CADDY_FILE" + # Modify the Caddyfile.local to use the test port + sed -i '' "s/:80/:$TEST_PORT/g" "$CADDY_FILE" + fi + + # Start Caddy in the background using the local config + echo "Running: caddy run --config $CADDY_FILE" + mkdir -p $(dirname "$LOG_FILE") && caddy run --config "$CADDY_FILE" > "$LOG_FILE" 2>&1 & + CADDY_PID=$! + mkdir -p "$TESTS_DIR" && echo $CADDY_PID > "$TESTS_DIR/.caddy.pid" + + # Return to the original directory + cd - > /dev/null + + # Wait for Caddy to start + echo "Waiting for Caddy to start..." + sleep 2 + + # Check if Caddy is running + if ! ps -p $CADDY_PID > /dev/null; then + echo "Failed to start Caddy server. Check $LOG_FILE for details." + exit 1 + fi + + echo "Caddy server started with PID: $CADDY_PID" + + # Wait a bit more to ensure Caddy is fully initialized + sleep 3 +} + +# Run Node.js server for tests that require it +start_node_server() { + if [ -f "$TESTS_DIR/serve.js" ]; then + echo "Starting Node.js server for tests..." + node "$TESTS_DIR/serve.js" > "$TESTS_DIR/node-server.log" 2>&1 & + NODE_SERVER_PID=$! + echo $NODE_SERVER_PID > "$TESTS_DIR/.node-server.pid" + + # Wait for Node.js server to start + sleep 2 + + # Check if Node.js server is running + if ! ps -p $NODE_SERVER_PID > /dev/null; then + echo "Failed to start Node.js server. Check $TESTS_DIR/node-server.log for details." + exit 1 + fi + + echo "Node.js server started with PID: $NODE_SERVER_PID" + fi +} + +# Clean up Node.js server +cleanup_node_server() { + if [ -f "$TESTS_DIR/.node-server.pid" ]; then + NODE_SERVER_PID=$(cat "$TESTS_DIR/.node-server.pid") + if ps -p $NODE_SERVER_PID > /dev/null; then + echo "Stopping Node.js server (PID: $NODE_SERVER_PID)" + kill $NODE_SERVER_PID + fi + rm "$TESTS_DIR/.node-server.pid" + fi +} + +# Run shell script tests +run_shell_tests() { + echo "Running shell script tests..." + + # Run unit tests + echo "Running unit tests..." + if [ -d "$TESTS_DIR/unit" ] && [ "$(ls -A "$TESTS_DIR/unit")" ]; then + for test in "$TESTS_DIR/unit"/*.sh; do + if [ -f "$test" ] && [ -x "$test" ]; then + echo "Running unit test: $(basename "$test")" + "$test" || echo "FAILED: $(basename "$test")" + fi + done + else + echo "No unit tests found." + fi + + # Run integration tests + echo "Running integration tests..." + if [ -d "$TESTS_DIR/integration" ] && [ "$(ls -A "$TESTS_DIR/integration")" ]; then + for test in "$TESTS_DIR/integration"/*.sh; do + if [ -f "$test" ] && [ -x "$test" ]; then + echo "Running integration test: $(basename "$test")" + "$test" "http://localhost:$TEST_PORT" || echo "FAILED: $(basename "$test")" + fi + done + + # Check for subdirectories + for dir in "$TESTS_DIR/integration"/*/; do + if [ -d "$dir" ]; then + for test in "$dir"*.sh; do + if [ -f "$test" ] && [ -x "$test" ]; then + echo "Running integration test: $(basename "$test")" + "$test" "http://localhost:$TEST_PORT" || echo "FAILED: $(basename "$test")" + fi + done + fi + done + else + echo "No integration tests found." + fi + + # Run e2e tests + echo "Running e2e tests..." + if [ -d "$TESTS_DIR/e2e" ] && [ "$(ls -A "$TESTS_DIR/e2e")" ]; then + for test in "$TESTS_DIR/e2e"/*.sh; do + if [ -f "$test" ] && [ -x "$test" ]; then + echo "Running e2e test: $(basename "$test")" + "$test" "http://localhost:$TEST_PORT" || echo "FAILED: $(basename "$test")" + fi + done + else + echo "No e2e tests found." + fi +} + +# Run JavaScript tests +run_js_tests() { + echo "Running JavaScript tests..." + + # Check if Playwright is installed + if command -v npx &> /dev/null && npx playwright --version &> /dev/null; then + # Run Playwright tests + echo "Running Playwright tests..." + npx playwright test || echo "FAILED: Playwright tests" + else + echo "Playwright not found, skipping Playwright tests." + fi + + # Run Lighthouse tests if available + if [ -f "$TESTS_DIR/lighthouse.js" ]; then + echo "Running Lighthouse tests..." + node "$TESTS_DIR/lighthouse.js" "http://localhost:$TEST_PORT" || echo "FAILED: Lighthouse tests" + fi +} + +# Main execution +echo "=== Starting Test Suite ===" +start_caddy +start_node_server +run_shell_tests +run_js_tests +cleanup_node_server +echo "=== Test Suite Completed ===" diff --git a/tests/unit/includes-test.sh b/tests/unit/includes-test.sh new file mode 100755 index 0000000..03d26e3 --- /dev/null +++ b/tests/unit/includes-test.sh @@ -0,0 +1,48 @@ +#!/bin/bash +# ===================================================================== +# includes-test.sh - Test the includes.js functionality +# ===================================================================== +# This script checks if the includes.js file is valid JavaScript +# ===================================================================== + +echo "=== Testing includes.js ===" + +# Path to the includes.js file +INCLUDES_JS="docker/resume/includes.js" + +# Check if the file exists +if [ ! -f "$INCLUDES_JS" ]; then + echo "❌ File not found: $INCLUDES_JS" + exit 1 +fi + +echo "✅ File exists: $INCLUDES_JS" + +# Check if the file is valid JavaScript using node +if command -v node &> /dev/null; then + echo "Checking if the file is valid JavaScript..." + if node --check "$INCLUDES_JS" &> /dev/null; then + echo "✅ File is valid JavaScript" + else + echo "❌ File contains JavaScript syntax errors" + node --check "$INCLUDES_JS" + exit 1 + fi +else + echo "⚠️ Node.js not found, skipping JavaScript syntax check" +fi + +# Check for required functions +echo "Checking for required functions..." +REQUIRED_FUNCTIONS=("includeHTML") +for func in "${REQUIRED_FUNCTIONS[@]}"; do + if grep -q "function $func" "$INCLUDES_JS"; then + echo "✅ Required function found: $func" + else + echo "❌ Required function not found: $func" + exit 1 + fi +done + +echo "=== includes.js Test Completed Successfully ===" +exit 0 diff --git a/tests/unit/theme-test.sh b/tests/unit/theme-test.sh new file mode 100755 index 0000000..86116c2 --- /dev/null +++ b/tests/unit/theme-test.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# ===================================================================== +# theme-test.sh - Test the theme.js functionality +# ===================================================================== +# This script checks if the theme.js file is valid JavaScript +# ===================================================================== + +echo "=== Testing theme.js ===" + +# Path to the theme.js file +THEME_JS="docker/resume/theme.js" + +# Check if the file exists +if [ ! -f "$THEME_JS" ]; then + echo "❌ File not found: $THEME_JS" + exit 1 +fi + +echo "✅ File exists: $THEME_JS" + +# Check if the file is valid JavaScript using node +if command -v node &> /dev/null; then + echo "Checking if the file is valid JavaScript..." + if node --check "$THEME_JS" &> /dev/null; then + echo "✅ File is valid JavaScript" + else + echo "❌ File contains JavaScript syntax errors" + node --check "$THEME_JS" + exit 1 + fi +else + echo "⚠️ Node.js not found, skipping JavaScript syntax check" +fi + +# Check for theme-related functionality +echo "Checking for theme-related functionality..." +if grep -q "dark" "$THEME_JS" || grep -q "light" "$THEME_JS" || grep -q "theme" "$THEME_JS"; then + echo "✅ Theme-related functionality found" +else + echo "❌ No theme-related functionality found" + exit 1 +fi + +echo "=== theme.js Test Completed Successfully ===" +exit 0