Skip to content
Merged
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
28 changes: 28 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Tests

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'

- name: Download dependencies
run: go mod download

- name: Generate templ files
run: go generate ./modules/...

- name: Run tests with race detector

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's just run the tests with the race detector - no need to bother with the "Run tests" step without it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed the redundant "Run tests" step. Now only running tests with the race detector. Commit: 89d7d69

run: go test ./... -race
63 changes: 63 additions & 0 deletions engine/errors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package engine

import (
"testing"

snaptest "github.com/TheLab-ms/conway/internal/testing"
)

func TestRenderError(t *testing.T) {
tests := []struct {
name string
error *httpError
fixtureName string
}{
{
name: "client_error_400",
error: &httpError{
StatusCode: 400,
Message: "Invalid request parameter",
},
fixtureName: "_client_error",
},
{
name: "client_error_404",
error: &httpError{
StatusCode: 404,
Message: "Page not found",
},
fixtureName: "_not_found",
},
{
name: "server_error_500",
error: &httpError{
StatusCode: 500,
Message: "Internal server error",
},
fixtureName: "_server_error",
},
{
name: "server_error_502",
error: &httpError{
StatusCode: 502,
Message: "Bad gateway",
},
fixtureName: "_bad_gateway",
},
{
name: "edge_case_499",
error: &httpError{
StatusCode: 499,
Message: "Client closed request",
},
fixtureName: "_edge_case_499",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
component := renderError(tt.error)
snaptest.RenderSnapshotWithName(t, component, tt.fixtureName)
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!doctype html><html lang="en" data-bs-theme=""><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Conway Makerspace System</title><link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet"><script src="/assets/bootstrap/js/bootstrap.bundle.min.js"></script><script src="/assets/htmx.min.js"></script></head><div class="container my-5"><div class="alert alert-warning"><h4 class="alert-heading">Bad Request</h4>Invalid request parameter</div></div></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!doctype html><html lang="en" data-bs-theme=""><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Conway Makerspace System</title><link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet"><script src="/assets/bootstrap/js/bootstrap.bundle.min.js"></script><script src="/assets/htmx.min.js"></script></head><div class="container my-5"><div class="alert alert-warning"><h4 class="alert-heading">Bad Request</h4>Page not found</div></div></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!doctype html><html lang="en" data-bs-theme=""><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Conway Makerspace System</title><link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet"><script src="/assets/bootstrap/js/bootstrap.bundle.min.js"></script><script src="/assets/htmx.min.js"></script></head><div class="container my-5"><div class="alert alert-warning"><h4 class="alert-heading">Bad Request</h4>Client closed request</div></div></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!doctype html><html lang="en" data-bs-theme=""><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Conway Makerspace System</title><link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet"><script src="/assets/bootstrap/js/bootstrap.bundle.min.js"></script><script src="/assets/htmx.min.js"></script></head><div class="container my-5"><div class="alert alert-danger"><h4 class="alert-heading">Uh oh</h4>Internal server error</div></div></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!doctype html><html lang="en" data-bs-theme=""><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Conway Makerspace System</title><link href="/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet"><script src="/assets/bootstrap/js/bootstrap.bundle.min.js"></script><script src="/assets/htmx.min.js"></script></head><div class="container my-5"><div class="alert alert-danger"><h4 class="alert-heading">Uh oh</h4>Bad gateway</div></div></html>
55 changes: 55 additions & 0 deletions internal/testing/templates.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package testing

import (
"context"
"os"
"path/filepath"
"strings"
"testing"

"github.com/a-h/templ"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// RenderSnapshot tests a templ component against a snapshot fixture.
// If RENDER_SNAPSHOTS environment variable is set, it will write/update the fixture file.
// Otherwise, it will compare the rendered output against the existing fixture.
func RenderSnapshot(t *testing.T, component templ.Component, fixturePath string) {
t.Helper()

// Render the component to string
var buf strings.Builder
err := component.Render(context.Background(), &buf)
require.NoError(t, err, "Failed to render template component")

rendered := buf.String()

if os.Getenv("RENDER_SNAPSHOTS") != "" {
// Write mode: create/update fixture files
err := os.MkdirAll(filepath.Dir(fixturePath), 0755)
require.NoError(t, err, "Failed to create fixture directory")

err = os.WriteFile(fixturePath, []byte(rendered), 0644)
require.NoError(t, err, "Failed to write fixture file")

t.Logf("Updated fixture: %s", fixturePath)
return
}

// Test mode: compare against existing fixture
expected, err := os.ReadFile(fixturePath)
require.NoError(t, err, "Failed to read fixture file: %s. Run tests with RENDER_SNAPSHOTS=1 to generate it.", fixturePath)

assert.Equal(t, string(expected), rendered, "Rendered output does not match fixture: %s", fixturePath)
}

// RenderSnapshotWithName is a convenience function that generates a fixture path
// based on the test name and an optional suffix.
func RenderSnapshotWithName(t *testing.T, component templ.Component, suffix string) {
t.Helper()

testName := strings.ReplaceAll(t.Name(), "/", "_")
fixturePath := filepath.Join("fixtures", testName+suffix+".html")
RenderSnapshot(t, component, fixturePath)
}
Loading