feat: implement core Go application with web server
- Add Go modules with required dependencies (Gin, UUID, JWT, etc.) - Implement main web server with landing page endpoint - Add comprehensive API endpoints for health and status - Include proper error handling and request validation - Set up CORS middleware and security headers
This commit is contained in:
324
output/tests/e2e/browser_test.go
Normal file
324
output/tests/e2e/browser_test.go
Normal file
@@ -0,0 +1,324 @@
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/chromedp/chromedp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
// End-to-End Test Suite
|
||||
type E2ETestSuite struct {
|
||||
suite.Suite
|
||||
baseURL string
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (suite *E2ETestSuite) SetupSuite() {
|
||||
suite.baseURL = "http://localhost:3000" // Assuming Nginx proxy on port 3000
|
||||
|
||||
// Setup Chrome context for browser testing
|
||||
opts := append(chromedp.DefaultExecAllocatorOptions[:],
|
||||
chromedp.Flag("headless", true),
|
||||
chromedp.Flag("disable-gpu", true),
|
||||
chromedp.Flag("no-sandbox", true),
|
||||
chromedp.Flag("disable-dev-shm-usage", true),
|
||||
chromedp.Flag("disable-web-security", true),
|
||||
chromedp.Flag("allow-running-insecure-content", true),
|
||||
)
|
||||
|
||||
allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts)
|
||||
suite.cancel = cancel
|
||||
|
||||
suite.ctx, cancel = chromedp.NewContext(allocCtx)
|
||||
suite.cancel = cancel
|
||||
|
||||
// Set a timeout
|
||||
suite.ctx, cancel = context.WithTimeout(suite.ctx, 45*time.Second)
|
||||
suite.cancel = cancel
|
||||
}
|
||||
|
||||
func (suite *E2ETestSuite) TearDownSuite() {
|
||||
if suite.cancel != nil {
|
||||
suite.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *E2ETestSuite) TestHomePageLoad() {
|
||||
var title string
|
||||
var h1Text string
|
||||
|
||||
err := chromedp.Run(suite.ctx,
|
||||
chromedp.Navigate(suite.baseURL),
|
||||
chromedp.WaitVisible("body", chromedp.ByQuery),
|
||||
chromedp.Title(&title),
|
||||
chromedp.Text("h1", &h1Text, chromedp.ByQuery),
|
||||
)
|
||||
|
||||
suite.NoError(err)
|
||||
suite.Contains(title, "YourDreamNameHere")
|
||||
suite.Contains(h1Text, "Sovereign Data Hosting")
|
||||
}
|
||||
|
||||
func (suite *E2ETestSuite) TestNavigation() {
|
||||
var navLinks []string
|
||||
|
||||
err := chromedp.Run(suite.ctx,
|
||||
chromedp.Navigate(suite.baseURL),
|
||||
chromedp.WaitVisible("nav", chromedp.ByQuery),
|
||||
chromedp.Nodes(".nav-link", &navLinks, chromedp.ByQuery),
|
||||
)
|
||||
|
||||
suite.NoError(err)
|
||||
suite.NotEmpty(navLinks)
|
||||
}
|
||||
|
||||
func (suite *E2ETestSuite) TestMobileMenuToggle() {
|
||||
// Test mobile menu toggle functionality
|
||||
var menuDisplayed bool
|
||||
|
||||
err := chromedp.Run(suite.ctx,
|
||||
chromedp.Emulate(device.IPhoneX),
|
||||
chromedp.Navigate(suite.baseURL),
|
||||
chromedp.WaitVisible(".nav-toggle-label", chromedp.ByQuery),
|
||||
chromedp.Click(".nav-toggle-label", chromedp.ByQuery),
|
||||
chromedp.WaitVisible(".nav-menu", chromedp.ByQuery),
|
||||
chromedp.Visible(".nav-menu", &menuDisplayed, chromedp.ByQuery),
|
||||
)
|
||||
|
||||
suite.NoError(err)
|
||||
suite.True(menuDisplayed)
|
||||
}
|
||||
|
||||
func (suite *E2ETestSuite) TestRegistrationFlow() {
|
||||
var successMessage string
|
||||
var currentURL string
|
||||
|
||||
err := chromedp.Run(suite.ctx,
|
||||
// Navigate to registration page
|
||||
chromedp.Navigate(suite.baseURL+"/register"),
|
||||
chromedp.WaitVisible("form", chromedp.ByQuery),
|
||||
|
||||
// Fill out registration form
|
||||
chromedp.SendKeys("#email", "e2e.test@example.com", chromedp.ByQuery),
|
||||
chromedp.SendKeys("#firstName", "E2E", chromedp.ByQuery),
|
||||
chromedp.SendKeys("#lastName", "Test", chromedp.ByQuery),
|
||||
chromedp.SendKeys("#password", "e2ePassword123", chromedp.ByQuery),
|
||||
|
||||
// Submit form
|
||||
chromedp.Click("button[type='submit']", chromedp.ByQuery),
|
||||
|
||||
// Wait for success message or redirect
|
||||
chromedp.WaitVisible(
|
||||
chromedp.Text("Account created successfully", chromedp.ByQuery),
|
||||
chromedp.ByQuery,
|
||||
),
|
||||
chromedp.Text(".notification-success", &successMessage, chromedp.ByQuery),
|
||||
chromedp.Location(¤tURL),
|
||||
)
|
||||
|
||||
suite.NoError(err)
|
||||
|
||||
if successMessage != "" {
|
||||
suite.Contains(successMessage, "Account created successfully")
|
||||
} else {
|
||||
// If redirected to login, that's also acceptable
|
||||
suite.Contains(currentURL, "/login")
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *E2ETestSuite) TestLoginFlow() {
|
||||
var authToken string
|
||||
var profileEmail string
|
||||
|
||||
// First ensure we have a test user
|
||||
suite.TestRegistrationFlow()
|
||||
|
||||
err := chromedp.Run(suite.ctx,
|
||||
// Navigate to login page
|
||||
chromedp.Navigate(suite.baseURL+"/login"),
|
||||
chromedp.WaitVisible("form", chromedp.ByQuery),
|
||||
|
||||
// Fill out login form
|
||||
chromedp.SendKeys("#email", "e2e.test@example.com", chromedp.ByQuery),
|
||||
chromedp.SendKeys("#password", "e2ePassword123", chromedp.ByQuery),
|
||||
|
||||
// Submit form
|
||||
chromedp.Click("button[type='submit']", chromedp.ByQuery),
|
||||
|
||||
// Wait for redirect or success message
|
||||
chromedp.WaitVisible(
|
||||
chromedp.Or(
|
||||
chromedp.Text("Login successful", chromedp.ByQuery),
|
||||
chromedp.Text("Profile", chromedp.ByQuery),
|
||||
),
|
||||
chromedp.ByQuery,
|
||||
),
|
||||
|
||||
// Check if we're logged in (try to access profile)
|
||||
chromedp.Navigate(suite.baseURL+"/api/v1/profile"),
|
||||
chromedp.WaitVisible("body", chromedp.ByQuery),
|
||||
chromedp.Evaluate("localStorage.getItem('authToken')", &authToken),
|
||||
)
|
||||
|
||||
suite.NoError(err)
|
||||
// Note: In a real implementation, you'd check for successful login indicators
|
||||
}
|
||||
|
||||
func (suite *E2ETestSuite) TestPricingPage() {
|
||||
var pricingTitle string
|
||||
var planPrice string
|
||||
var planFeatures []string
|
||||
|
||||
err := chromedp.Run(suite.ctx,
|
||||
chromedp.Navigate(suite.baseURL+"#pricing"),
|
||||
chromedp.WaitVisible(".pricing", chromedp.ByQuery),
|
||||
chromedp.Text(".pricing-title", &pricingTitle, chromedp.ByQuery),
|
||||
chromedp.Text(".amount", &planPrice, chromedp.ByQuery),
|
||||
chromedp.Nodes(".pricing-features li", &planFeatures, chromedp.ByQuery),
|
||||
)
|
||||
|
||||
suite.NoError(err)
|
||||
suite.Contains(pricingTitle, "Sovereign Hosting")
|
||||
suite.Contains(planPrice, "250")
|
||||
suite.NotEmpty(planFeatures)
|
||||
}
|
||||
|
||||
func (suite *E2ETestSuite) TestResponsiveDesign() {
|
||||
// Test desktop view
|
||||
err := chromedp.Run(suite.ctx,
|
||||
chromedp.Emulate(device.LaptopWithMDPI),
|
||||
chromedp.Navigate(suite.baseURL),
|
||||
chromedp.WaitVisible(".hero-content", chromedp.ByQuery),
|
||||
chromedp.WaitVisible(".features-grid", chromedd.ByQuery),
|
||||
)
|
||||
suite.NoError(err)
|
||||
|
||||
// Test tablet view
|
||||
err = chromedp.Run(suite.ctx,
|
||||
chromedp.Emulate(device.iPad),
|
||||
chromedp.Navigate(suite.baseURL),
|
||||
chromedp.WaitVisible(".hero-content", chromedp.ByQuery),
|
||||
chromedp.WaitVisible(".features-grid", chromedp.ByQuery),
|
||||
)
|
||||
suite.NoError(err)
|
||||
|
||||
// Test mobile view (already tested in mobile menu test)
|
||||
err = chromedp.Run(suite.ctx,
|
||||
chromedp.Emulate(device.IPhoneX),
|
||||
chromedp.Navigate(suite.baseURL),
|
||||
chromedp.WaitVisible(".hero-content", chromedp.ByQuery),
|
||||
chromedp.WaitVisible(".features-grid", chromedp.ByQuery),
|
||||
)
|
||||
suite.NoError(err)
|
||||
}
|
||||
|
||||
func (suite *E2ETestSuite) TestAccessibility() {
|
||||
var altTexts []string
|
||||
|
||||
err := chromedp.Run(suite.ctx,
|
||||
chromedp.Navigate(suite.baseURL),
|
||||
chromedp.WaitVisible("body", chromedp.ByQuery),
|
||||
chromedp.Attributes("img", "alt", &altTexts, chromedp.ByQuery),
|
||||
)
|
||||
|
||||
suite.NoError(err)
|
||||
|
||||
// Check that all images have alt text
|
||||
for i, alt := range altTexts {
|
||||
suite.NotEmptyf(alt, "Image %d should have alt text", i)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *E2ETestSuite) TestFormValidation() {
|
||||
var emailError string
|
||||
var passwordError string
|
||||
|
||||
err := chromedp.Run(suite.ctx,
|
||||
chromedp.Navigate(suite.baseURL+"/register"),
|
||||
chromedp.WaitVisible("form", chromedp.ByQuery),
|
||||
|
||||
// Try to submit empty form
|
||||
chromedp.Click("button[type='submit']", chromedp.ByQuery),
|
||||
|
||||
// Check for validation errors
|
||||
chromedp.Text("#email-error", &emailError, chromedp.ByQuery),
|
||||
chromedp.Text("#password-error", &passwordError, chromedp.ByQuery),
|
||||
)
|
||||
|
||||
suite.NoError(err)
|
||||
// Note: Validation might be handled by HTML5 validation or JavaScript
|
||||
}
|
||||
|
||||
func (suite *E2ETestSuite) TestPerformance() {
|
||||
var loadTime time.Duration
|
||||
start := time.Now()
|
||||
|
||||
err := chromedp.Run(suite.ctx,
|
||||
chromedp.Navigate(suite.baseURL),
|
||||
chromedp.WaitVisible("body", chromedp.ByQuery),
|
||||
)
|
||||
|
||||
loadTime = time.Since(start)
|
||||
|
||||
suite.NoError(err)
|
||||
// Page should load within 5 seconds
|
||||
suite.Less(loadTime, 5*time.Second, "Page should load within 5 seconds")
|
||||
}
|
||||
|
||||
func (suite *E2ETestSuite) TestErrorHandling() {
|
||||
var statusCode int
|
||||
|
||||
// Test 404 page
|
||||
err := chromedp.Run(suite.ctx,
|
||||
chromedp.Navigate(suite.baseURL+"/nonexistent-page"),
|
||||
chromedp.WaitVisible("body", chromedp.ByQuery),
|
||||
chromedp.Evaluate(`
|
||||
fetch('/api/v1/nonexistent-endpoint')
|
||||
.then(response => response.status)
|
||||
`, &statusCode),
|
||||
)
|
||||
|
||||
suite.NoError(err)
|
||||
suite.Equal(404, statusCode)
|
||||
}
|
||||
|
||||
// Mock device configurations for responsive testing
|
||||
var device = map[string]chromedp.EmulatedDevice{
|
||||
"IPhoneX": {
|
||||
Name: "iPhone X",
|
||||
UserAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1",
|
||||
Screen: &chromedp.Screen{Width: 375, Height: 812, DeviceScaleFactor: 3, IsMobile: true, HasTouch: true},
|
||||
},
|
||||
"iPad": {
|
||||
Name: "iPad",
|
||||
UserAgent: "Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1",
|
||||
Screen: &chromedp.Screen{Width: 768, Height: 1024, DeviceScaleFactor: 2, IsMobile: true, HasTouch: true},
|
||||
},
|
||||
"LaptopWithMDPI": {
|
||||
Name: "Laptop with MDPI screen",
|
||||
UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
|
||||
Screen: &chromedp.Screen{Width: 1280, Height: 800, DeviceScaleFactor: 1, IsMobile: false, HasTouch: false},
|
||||
},
|
||||
}
|
||||
|
||||
// Run the E2E test suite
|
||||
func TestE2ESuite(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping E2E tests in short mode")
|
||||
}
|
||||
|
||||
// Check if we're in a CI environment or if browser testing is enabled
|
||||
if os.Getenv("ENABLE_E2E_TESTS") != "true" {
|
||||
t.Skip("E2E tests disabled. Set ENABLE_E2E_TESTS=true to enable.")
|
||||
}
|
||||
|
||||
suite.Run(t, new(E2ETestSuite))
|
||||
}
|
||||
Reference in New Issue
Block a user