Implements real-time wireless client monitoring with historical tracking, LiveView UI, proactive alerting, and cross-browser e2e tests. Phase 1: Historical Tracking - Add TimescaleDB hypertable for wireless_client_readings - Batch insert client metrics every 60 seconds from DevicePollerWorker - 90-day retention with compression after 7 days - Continuous aggregates for hourly (1 year) and daily (5 years) rollups Phase 2: LiveView UI - Add wireless tab to device detail page - Real-time client list with PubSub updates - Signal strength and SNR badges with 5-level thresholds - Display MAC, IP, subscriber, TX/RX rates, distance, uptime - Subscriber matching via device_subscriber_links - Empty state handling Phase 3: Proactive Alerting - WirelessInsightWorker runs every 5 minutes via Oban cron - 4 insight types with auto-resolution: * wireless_signal_weak: < -75 dBm (warning), < -85 dBm (critical) * wireless_snr_low: < 15 dB (warning), < 10 dB (critical) * wireless_ap_overloaded: > 50 clients (warning), > 75 clients (critical) * wireless_client_missing: expected subscribers not connecting - Hysteresis thresholds prevent alert flapping - Multi-organization isolation with proper deduplication Code Quality: - Refactored reload_current_tab_data to reduce cyclomatic complexity - Combined double Enum.filter into single pass for efficiency - Fixed length/1 comparison to use empty list check - All Credo checks passing Testing: - 28 unit tests (ExUnit) - 100% passing - 15 e2e tests (Playwright) - 100% passing across chromium/firefox/webkit - Total: 73 tests, all passing Files changed: - lib/towerops/workers/wireless_insight_worker.ex (NEW) - lib/towerops_web/live/device_live/show.ex (wireless tab + refactoring) - lib/towerops_web/live/device_live/show.html.heex (wireless template) - lib/towerops/snmp.ex (5 new query functions) - lib/towerops/gaiia.ex (list_missing_subscribers) - lib/towerops/preseem/insight.ex (5 new insight types) - config/runtime.exs (Oban cron schedule) - test/support/fixtures/snmp_fixtures.ex (NEW) - test/towerops/workers/wireless_insight_worker_test.exs (NEW) - test/towerops_web/live/device_live/show_test.exs (9 new tests) - e2e/tests/wireless-clients.spec.ts (NEW - 15 cross-browser tests) |
||
|---|---|---|
| .. | ||
| scripts | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.ts | ||
| README.md | ||
| setup.sh | ||
| TOTP_SETUP.md | ||
| tsconfig.json | ||
Towerops E2E Tests
End-to-end tests using Playwright for testing the Towerops application against local development or staging environments.
Setup
1. Install Dependencies
cd e2e
npm install
npx playwright install
2. Create Test User
You need a test user with TOTP enabled.
Quick Setup (Recommended):
# From the Phoenix app directory
cd ..
mix run e2e/scripts/create_test_user.exs
This creates a test user with known credentials and outputs the configuration for your .env file.
For detailed TOTP setup instructions, see TOTP_SETUP.md
3. Configure Environment
cp .env.example .env
Edit .env and set:
TEST_USER_EMAIL- Your test user emailTEST_USER_PASSWORD- Your test user passwordTEST_USER_TOTP_SECRET- TOTP secret from step 2
Running Tests
Local Development
Make sure Phoenix is running first:
cd ..
mix phx.server
Then run tests:
cd e2e
npm test
Against Staging
npm run test:staging
Other Commands
# Run tests with UI (interactive mode)
npm run test:ui
# Run tests with browser visible
npm run test:headed
# Debug a specific test
npm run test:debug -- tests/devices.spec.ts
# Generate tests by recording actions
npm run codegen
# View last test report
npm run report
Test Organization
tests/auth.setup.ts
Authentication setup that runs before all other tests. Logs in once and saves the session state so other tests don't need to authenticate.
Test Files
organizations.spec.ts- Organization listing and switchingdevices.spec.ts- Device listing, details, search/filteralerts.spec.ts- Alert viewing, filtering, resolution
Adding New Tests
- Create a new
.spec.tsfile intests/ - Import test utilities:
import { test, expect } from '@playwright/test'; - Write tests using Playwright's API
Example:
import { test, expect } from '@playwright/test';
test.describe('My Feature', () => {
test('can do something', async ({ page }) => {
await page.goto('/my-page');
await expect(page.getByRole('heading')).toBeVisible();
});
});
Configuration
Environment Variables
BASE_URL- Base URL of the application (default: http://localhost:4000)TEST_USER_EMAIL- Test user emailTEST_USER_PASSWORD- Test user passwordTEST_USER_TOTP_SECRET- TOTP secret for test user
Playwright Config
Edit playwright.config.ts to:
- Add/remove browsers
- Change timeout settings
- Configure reporters
- Add mobile viewports
- Enable video recording
Best Practices
1. Use Data Test Attributes
Add data-test attributes to important elements in your templates:
<div data-test="device-card">
<h3 data-test="device-name"><%= @device.name %></h3>
</div>
Then in tests:
await page.locator('[data-test="device-card"]').first().click();
2. Wait for Network Idle
For LiveView pages with dynamic content:
await page.waitForLoadState('networkidle');
3. Use Semantic Selectors
Prefer role-based selectors when possible:
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByRole('heading', { name: 'Devices' }).toBeVisible();
4. Handle Optional Elements
Check if elements exist before interacting:
if (await page.getByText('No results').count() > 0) {
// Handle empty state
}
5. Avoid Hard Timeouts
Use waitFor methods instead of waitForTimeout:
// Good
await page.getByText('Success').waitFor();
// Bad
await page.waitForTimeout(3000);
CI/CD Integration
GitHub Actions / GitLab CI
e2e-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: |
cd e2e
npm ci
npx playwright install --with-deps
- name: Run tests
run: |
cd e2e
BASE_URL=${{ secrets.STAGING_URL }} npm test
env:
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
TEST_USER_TOTP_SECRET: ${{ secrets.TEST_USER_TOTP_SECRET }}
- name: Upload test results
if: always()
uses: actions/upload-artifact@v3
with:
name: playwright-report
path: e2e/playwright-report/
Debugging
Visual Debugging
# Open test in UI mode
npm run test:ui
# Run specific test with browser visible
npm run test:headed -- tests/devices.spec.ts
Debug Mode
# Opens Playwright Inspector
npm run test:debug -- tests/devices.spec.ts
Screenshots and Videos
Failed tests automatically capture:
- Screenshots (in
test-results/) - Videos (in
test-results/) - Traces (view with
npx playwright show-trace <trace-file>)
Console Logs
Add console logging in tests:
test('debug test', async ({ page }) => {
page.on('console', msg => console.log('Browser:', msg.text()));
await page.goto('/devices');
});
Troubleshooting
"Authentication failed" or TOTP errors
- Verify TOTP secret is correct in
.env - Check test user exists and has TOTP enabled
- Ensure test user has access to at least one organization
Tests timing out
- Increase timeout in
playwright.config.ts - Check Phoenix server is running
- Verify BASE_URL is correct
- Check network connectivity to staging
"Element not found" errors
- Add
data-testattributes to elements - Use
page.waitForLoadState('networkidle')before assertions - Check if LiveView is fully mounted before interacting
Browser not launching
# Reinstall browsers
npx playwright install --with-deps