een-api-toolkit 0.3.14 → 0.3.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +10 -40
  2. package/README.md +1 -0
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +825 -0
  6. package/dist/index.js +489 -254
  7. package/dist/index.js.map +1 -1
  8. package/docs/AI-CONTEXT.md +314 -2
  9. package/examples/vue-alerts-metrics/README.md +136 -0
  10. package/examples/vue-alerts-metrics/e2e/app.spec.ts +74 -0
  11. package/examples/vue-alerts-metrics/e2e/auth.spec.ts +561 -0
  12. package/examples/vue-alerts-metrics/index.html +13 -0
  13. package/examples/vue-alerts-metrics/package-lock.json +1756 -0
  14. package/examples/vue-alerts-metrics/package.json +31 -0
  15. package/examples/vue-alerts-metrics/playwright.config.ts +46 -0
  16. package/examples/vue-alerts-metrics/src/App.vue +108 -0
  17. package/examples/vue-alerts-metrics/src/components/AlertsList.vue +881 -0
  18. package/examples/vue-alerts-metrics/src/components/CameraSelector.vue +106 -0
  19. package/examples/vue-alerts-metrics/src/components/MetricsChart.vue +336 -0
  20. package/examples/vue-alerts-metrics/src/components/NotificationsList.vue +825 -0
  21. package/examples/vue-alerts-metrics/src/components/TimeRangeSelector.vue +259 -0
  22. package/examples/vue-alerts-metrics/src/composables/useHlsPlayer.ts +285 -0
  23. package/examples/vue-alerts-metrics/src/main.ts +23 -0
  24. package/examples/vue-alerts-metrics/src/router/index.ts +61 -0
  25. package/examples/vue-alerts-metrics/src/views/Callback.vue +76 -0
  26. package/examples/vue-alerts-metrics/src/views/Dashboard.vue +174 -0
  27. package/examples/vue-alerts-metrics/src/views/Home.vue +216 -0
  28. package/examples/vue-alerts-metrics/src/views/Login.vue +33 -0
  29. package/examples/vue-alerts-metrics/src/views/Logout.vue +66 -0
  30. package/examples/vue-alerts-metrics/src/vite-env.d.ts +12 -0
  31. package/examples/vue-alerts-metrics/tsconfig.json +21 -0
  32. package/examples/vue-alerts-metrics/tsconfig.node.json +10 -0
  33. package/examples/vue-alerts-metrics/vite.config.ts +12 -0
  34. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  # EEN API Toolkit - AI Reference
2
2
 
3
- > **Version:** 0.3.14
3
+ > **Version:** 0.3.16
4
4
  >
5
5
  > This file is optimized for AI assistants. It contains all API signatures,
6
6
  > types, and usage patterns in a single, parseable document.
@@ -10,9 +10,10 @@
10
10
 
11
11
  > **Working Examples:** The installed package includes complete Vue 3 example applications
12
12
  > at `./node_modules/een-api-toolkit/examples/`. These demonstrate OAuth authentication,
13
- > user management, camera listing, live/recorded media, video feeds, and events.
13
+ > user management, camera listing, live/recorded media, video feeds, events, and metrics.
14
14
  > For Live Main Video streaming, see `vue-feeds/src/views/Feeds.vue`.
15
15
  > For Events API with thumbnails, see `vue-events/src/components/EventsModal.vue`.
16
+ > For Event Metrics with Chart.js visualization, see `vue-alerts-metrics/src/components/MetricsChart.vue`.
16
17
 
17
18
  ---
18
19
 
@@ -212,6 +213,7 @@ Complete Vue 3 applications demonstrating toolkit features:
212
213
  | [vue-media](../examples/vue-media/) | Live and recorded image viewing | `src/views/LiveCamera.vue`, `RecordedImage.vue`, `HLS.vue` |
213
214
  | [vue-feeds](../examples/vue-feeds/) | Live video streaming (preview and main) | `src/views/Feeds.vue` |
214
215
  | [vue-events](../examples/vue-events/) | Events with bounding box overlays | `src/components/EventsModal.vue` |
216
+ | [vue-alerts-metrics](../examples/vue-alerts-metrics/) | Event metrics, alerts, and notifications | `src/components/MetricsChart.vue`, `AlertsList.vue` |
215
217
 
216
218
  ### Configuration
217
219
 
@@ -270,6 +272,33 @@ Complete Vue 3 applications demonstrating toolkit features:
270
272
  | `listEventTypes(params?)` | List all available event types | `Result<PaginatedResult<EventType>>` |
271
273
  | `listEventFieldValues(params)` | Get available event types for a device | `Result<EventFieldValues>` |
272
274
 
275
+ ### Event Metrics Functions
276
+
277
+ | Function | Purpose | Returns |
278
+ |----------|---------|---------|
279
+ | `getEventMetrics(params)` | Get event count metrics over time | `Result<EventMetric[]>` |
280
+
281
+ ### Alerts Functions
282
+
283
+ | Function | Purpose | Returns |
284
+ |----------|---------|---------|
285
+ | `listAlerts(params?)` | List alerts with filters | `Result<PaginatedResult<Alert>>` |
286
+ | `getAlert(id, params?)` | Get a specific alert by ID | `Result<Alert>` |
287
+ | `listAlertTypes(params?)` | List all available alert types | `Result<PaginatedResult<AlertType>>` |
288
+
289
+ ### Notifications Functions
290
+
291
+ | Function | Purpose | Returns |
292
+ |----------|---------|---------|
293
+ | `listNotifications(params?)` | List notifications with filters | `Result<PaginatedResult<Notification>>` |
294
+ | `getNotification(id)` | Get a specific notification by ID | `Result<Notification>` |
295
+
296
+ ### Utility Functions
297
+
298
+ | Function | Purpose | Returns |
299
+ |----------|---------|---------|
300
+ | `formatTimestamp(timestamp)` | Convert ISO timestamp from Z to +00:00 format (required by EEN API) | `string` |
301
+
273
302
  ---
274
303
 
275
304
  ## Core Types
@@ -741,6 +770,163 @@ interface ListEventFieldValuesParams {
741
770
  }
742
771
  ```
743
772
 
773
+ ### Event Metrics Types
774
+
775
+ ```typescript
776
+ type MetricActorType = 'bridge' | 'camera' | 'speaker' | 'account' | 'user' | 'layout' | 'job'
777
+
778
+ // Data point: [timestamp_ms, value]
779
+ type MetricDataPoint = [number, number]
780
+
781
+ interface EventMetric {
782
+ eventType: string
783
+ actorId: string
784
+ actorType: MetricActorType
785
+ target: string // e.g., 'count'
786
+ dataPoints: MetricDataPoint[]
787
+ [key: string]: unknown // Additional properties
788
+ }
789
+
790
+ interface GetEventMetricsParams {
791
+ actor: string // Required: 'camera:{id}' format
792
+ eventType: string // Required: e.g., 'een.motionDetectionEvent.v1'
793
+ timestamp__gte?: string // Optional: defaults to 7 days ago
794
+ timestamp__lte?: string // Optional: defaults to now
795
+ aggregateByMinutes?: number // Optional: default 60, minimum 60
796
+ }
797
+ ```
798
+
799
+ ### Alert Types
800
+
801
+ ```typescript
802
+ interface AlertAction {
803
+ name: string
804
+ type: string
805
+ success: boolean
806
+ timestamp: string
807
+ status?: 'fired' | 'success' | 'partialSuccess' | 'silenced' | 'failed' | 'internalError'
808
+ }
809
+
810
+ interface Alert {
811
+ id: string
812
+ timestamp: string
813
+ createTimestamp: string
814
+ creatorId: string
815
+ alertType: string
816
+ alertName?: string
817
+ category?: string
818
+ serviceRuleId?: string
819
+ eventType?: string
820
+ actorId: string
821
+ actorType: string
822
+ actorAccountId: string
823
+ actorName?: string
824
+ ruleId?: string
825
+ eventId?: string
826
+ locationId?: string
827
+ locationName?: string
828
+ priority?: number // 0-20
829
+ dataSchemas?: string[]
830
+ data?: Record<string, unknown>
831
+ actions?: Record<string, AlertAction>
832
+ description?: string
833
+ }
834
+
835
+ interface AlertType {
836
+ type: string
837
+ description: string
838
+ }
839
+
840
+ type AlertInclude = 'data' | 'actions' | 'dataSchemas' | 'description'
841
+ type AlertSort = '+timestamp' | '-timestamp'
842
+ type AlertActionStatus = 'fired' | 'success' | 'partialSuccess' | 'silenced' | 'failed' | 'internalError'
843
+
844
+ interface ListAlertsParams {
845
+ pageSize?: number
846
+ pageToken?: string
847
+ timestamp__lte?: string
848
+ timestamp__gte?: string
849
+ creatorId?: string
850
+ alertType__in?: string[]
851
+ actorId__in?: string[]
852
+ actorType__in?: string[]
853
+ actorAccountId?: string
854
+ ruleId?: string
855
+ ruleId__in?: string[]
856
+ eventId?: string
857
+ locationId__in?: string[]
858
+ priority__gte?: number
859
+ priority__lte?: number
860
+ showInvalidAlerts?: boolean
861
+ alertActionId__in?: string[]
862
+ alertActionStatus__in?: AlertActionStatus[]
863
+ include?: AlertInclude[]
864
+ sort?: AlertSort[]
865
+ language?: string
866
+ }
867
+
868
+ interface GetAlertParams {
869
+ include?: AlertInclude[]
870
+ }
871
+
872
+ interface ListAlertTypesParams {
873
+ pageSize?: number
874
+ pageToken?: string
875
+ }
876
+ ```
877
+
878
+ ### Notification Types
879
+
880
+ ```typescript
881
+ type NotificationCategory = 'health' | 'video' | 'operational' | 'audit' | 'job' | 'security' | 'sharing'
882
+
883
+ type NotificationStatus =
884
+ | 'pending' | 'bounced' | 'dropped' | 'deferred' | 'delivered' | 'sent'
885
+ | 'outsideUsersSchedule' | 'notificationsDisabled' | 'noNotificationActions'
886
+ | 'sendingFailed' | 'throttled' | 'unableToGetSettings'
887
+
888
+ interface Notification {
889
+ id: string
890
+ timestamp: string
891
+ createTimestamp: string
892
+ sentTimestamp?: string
893
+ alertId?: string | null
894
+ alertType?: string
895
+ actorId: string
896
+ actorName?: string
897
+ actorType: string
898
+ actorAccountId: string
899
+ userId: string
900
+ accountId: string
901
+ read: boolean
902
+ status: NotificationStatus
903
+ category: NotificationCategory
904
+ description?: string
905
+ notificationActions: string[]
906
+ dataSchemas: string[]
907
+ data: Record<string, unknown>
908
+ }
909
+
910
+ interface ListNotificationsParams {
911
+ pageSize?: number
912
+ pageToken?: string
913
+ timestamp__lte?: string
914
+ timestamp__gte?: string
915
+ alertId?: string
916
+ alertType?: string
917
+ actorId?: string
918
+ actorType?: string
919
+ actorAccountId?: string
920
+ category?: NotificationCategory
921
+ userId?: string
922
+ read?: boolean
923
+ status?: NotificationStatus
924
+ includeV1Notifications?: boolean
925
+ sort?: ('+timestamp' | '-timestamp')[]
926
+ language?: string
927
+ }
928
+ ```
929
+
744
930
  ---
745
931
 
746
932
  ## API Reference
@@ -1095,6 +1281,40 @@ console.log('Session URL:', data.url)
1095
1281
 
1096
1282
  ---
1097
1283
 
1284
+ ## Utilities
1285
+
1286
+ ### formatTimestamp
1287
+
1288
+ Converts ISO 8601 timestamps from `Z` (Zulu/UTC) format to `+00:00` format, as required by the EEN API.
1289
+
1290
+ **Why this is needed:** JavaScript's `Date.toISOString()` returns timestamps with a `Z` suffix (e.g., `2025-01-15T22:30:00.000Z`), but the EEN API requires the `+00:00` format (e.g., `2025-01-15T22:30:00.000+00:00`).
1291
+
1292
+ ```typescript
1293
+ import { formatTimestamp } from 'een-api-toolkit'
1294
+
1295
+ // Convert Z format to +00:00 format
1296
+ formatTimestamp('2025-01-15T22:30:00.000Z')
1297
+ // Returns: '2025-01-15T22:30:00.000+00:00'
1298
+
1299
+ // Already in +00:00 format - returns unchanged
1300
+ formatTimestamp('2025-01-15T22:30:00.000+00:00')
1301
+ // Returns: '2025-01-15T22:30:00.000+00:00'
1302
+
1303
+ // Common usage with Date objects
1304
+ const now = new Date()
1305
+ const apiTimestamp = formatTimestamp(now.toISOString())
1306
+ // Returns timestamp in EEN API format
1307
+ ```
1308
+
1309
+ **When to use:**
1310
+ - When displaying timestamps that match the exact format used in API calls (e.g., for debugging)
1311
+ - When making direct API calls outside of the toolkit
1312
+ - When building custom timestamp display components
1313
+
1314
+ **Note:** The toolkit's API functions (`listAlerts`, `getEventMetrics`, `listNotifications`, `listEvents`, etc.) automatically apply `formatTimestamp` internally, so you don't need to pre-format timestamps when using these functions.
1315
+
1316
+ ---
1317
+
1098
1318
  ## Live Video Streaming
1099
1319
 
1100
1320
  The EEN API Toolkit supports two methods for displaying live video from cameras:
@@ -1345,6 +1565,98 @@ video {
1345
1565
 
1346
1566
  ---
1347
1567
 
1568
+ ## HLS Video Playback Troubleshooting
1569
+
1570
+ For detailed troubleshooting, see the [HLS Video Troubleshooting Guide](./guides/HLS-VIDEO-TROUBLESHOOTING.md).
1571
+
1572
+ ### Overview
1573
+
1574
+ HLS video playback from the EEN API requires:
1575
+
1576
+ 1. **Initialize media session** - `initMediaSession()`
1577
+ 2. **Find recording intervals** - `listMedia()` with `include: ['hlsUrl']`
1578
+ 3. **Extract HLS URL** - From interval containing target timestamp
1579
+ 4. **Configure HLS.js with auth** - Bearer token in Authorization header
1580
+
1581
+ ### Key Requirements
1582
+
1583
+ | Requirement | Details |
1584
+ |-------------|---------|
1585
+ | Feed Type | HLS only available for `main` feeds, not `preview` |
1586
+ | Timestamp Format | Use `formatTimestamp()` to convert `Z` to `+00:00` |
1587
+ | Authentication | HLS.js requires `xhr.setRequestHeader('Authorization', `Bearer ${token}`)` |
1588
+ | Recording Coverage | Target timestamp must fall within a recording interval |
1589
+
1590
+ ### Common Issues
1591
+
1592
+ #### 401 Unauthorized
1593
+
1594
+ **Cause:** Using `withCredentials: true` instead of Authorization header.
1595
+
1596
+ ```typescript
1597
+ // WRONG
1598
+ const hls = new Hls({
1599
+ xhrSetup: (xhr) => { xhr.withCredentials = true }
1600
+ })
1601
+
1602
+ // CORRECT
1603
+ import { useAuthStore } from 'een-api-toolkit'
1604
+ const authStore = useAuthStore()
1605
+
1606
+ const hls = new Hls({
1607
+ xhrSetup: (xhr) => {
1608
+ xhr.setRequestHeader('Authorization', `Bearer ${authStore.token}`)
1609
+ }
1610
+ })
1611
+ ```
1612
+
1613
+ #### No Video Available for Timestamp
1614
+
1615
+ **Cause:** Search range too narrow or using wrong feed type.
1616
+
1617
+ ```typescript
1618
+ import { listMedia, formatTimestamp } from 'een-api-toolkit'
1619
+
1620
+ const targetTime = new Date(alertTimestamp)
1621
+ const searchStart = new Date(targetTime.getTime() - 60 * 60 * 1000) // 1 hour before
1622
+ const searchEnd = new Date(targetTime.getTime() + 60 * 60 * 1000) // 1 hour after
1623
+
1624
+ const result = await listMedia({
1625
+ deviceId: cameraId,
1626
+ type: 'main', // MUST be 'main' for HLS
1627
+ mediaType: 'video',
1628
+ startTimestamp: formatTimestamp(searchStart.toISOString()),
1629
+ endTimestamp: formatTimestamp(searchEnd.toISOString()),
1630
+ include: ['hlsUrl'] // MUST include 'hlsUrl'
1631
+ })
1632
+
1633
+ // Find interval containing target timestamp
1634
+ const intervals = result.data?.results ?? []
1635
+ const targetTimeMs = targetTime.getTime()
1636
+
1637
+ const matchingInterval = intervals.find(i => {
1638
+ if (!i.hlsUrl) return false
1639
+ const start = new Date(i.startTimestamp).getTime()
1640
+ const end = new Date(i.endTimestamp).getTime()
1641
+ return targetTimeMs >= start && targetTimeMs <= end
1642
+ })
1643
+ ```
1644
+
1645
+ #### Timestamp Format Error
1646
+
1647
+ **Cause:** Using `Z` suffix instead of `+00:00`.
1648
+
1649
+ ```typescript
1650
+ // WRONG
1651
+ const timestamp = new Date().toISOString() // "2025-01-15T22:30:00.000Z"
1652
+
1653
+ // CORRECT
1654
+ import { formatTimestamp } from 'een-api-toolkit'
1655
+ const timestamp = formatTimestamp(new Date().toISOString()) // "2025-01-15T22:30:00.000+00:00"
1656
+ ```
1657
+
1658
+ ---
1659
+
1348
1660
  ## Common Patterns
1349
1661
 
1350
1662
  ### Error Handling
@@ -0,0 +1,136 @@
1
+ # vue-alerts-metrics
2
+
3
+ A Vue 3 example application demonstrating the Event Metrics, Alerts, and Notifications APIs from the `een-api-toolkit`.
4
+
5
+ ## Status
6
+
7
+ | Feature | Status |
8
+ |---------|--------|
9
+ | Event Metrics | Supported |
10
+ | Alerts | Work in Progress |
11
+ | Notifications | Work in Progress |
12
+
13
+ > **Note:** The Event Metrics feature is fully functional. Alerts and Notifications UI components are present but the underlying API integration may have limitations.
14
+
15
+ ## Features
16
+
17
+ - **OAuth Authentication** - Secure login via Eagle Eye Networks
18
+ - **Camera Selection** - Browse and select cameras from your account
19
+ - **Time Range Selection** - View data for 1h, 6h, 24h, or 7 days
20
+ - **Event Metrics Chart** - Line chart visualization of event counts over time
21
+ - **Event Type Selection** - Filter metrics by specific event types
22
+ - **Alert Type Filtering** - Filter alerts by type (work in progress)
23
+ - **Notifications List** - View notifications for selected camera (work in progress)
24
+
25
+ ## Prerequisites
26
+
27
+ 1. **OAuth Proxy** - Running instance of [een-oauth-proxy](https://github.com/klaushofrichter/een-oauth-proxy)
28
+ 2. **EEN Account** - Valid Eagle Eye Networks account with API access
29
+ 3. **Node.js** - Version 20 or higher
30
+
31
+ ## Setup
32
+
33
+ 1. Install dependencies:
34
+ ```bash
35
+ npm install
36
+ ```
37
+
38
+ 2. Create a `.env` file (or copy from parent):
39
+ ```bash
40
+ VITE_PROXY_URL=http://127.0.0.1:8787
41
+ VITE_EEN_CLIENT_ID=your-client-id
42
+ VITE_REDIRECT_URI=http://127.0.0.1:3333
43
+ ```
44
+
45
+ 3. Start the development server:
46
+ ```bash
47
+ npm run dev
48
+ ```
49
+
50
+ 4. Open http://127.0.0.1:3333 in your browser
51
+
52
+ ## Usage
53
+
54
+ 1. Click **Login** to authenticate with Eagle Eye Networks
55
+ 2. After login, you'll be redirected to the Dashboard
56
+ 3. Select a **Camera** from the dropdown
57
+ 4. Select an **Event Type** to view metrics in the chart
58
+ 5. Use the **Time Range** buttons to change the data window
59
+ 6. View Alerts and Notifications in the panels below (work in progress)
60
+
61
+ ## Project Structure
62
+
63
+ ```
64
+ vue-alerts-metrics/
65
+ ├── src/
66
+ │ ├── components/
67
+ │ │ ├── AlertsList.vue # Alerts display with type filter
68
+ │ │ ├── CameraSelector.vue # Camera dropdown
69
+ │ │ ├── MetricsChart.vue # Chart.js line chart
70
+ │ │ ├── NotificationsList.vue # Notifications display
71
+ │ │ └── TimeRangeSelector.vue # Time range buttons
72
+ │ ├── views/
73
+ │ │ ├── Callback.vue # OAuth callback handler
74
+ │ │ ├── Dashboard.vue # Main dashboard view
75
+ │ │ ├── Home.vue # Landing page
76
+ │ │ ├── Login.vue # Login page
77
+ │ │ └── Logout.vue # Logout handler
78
+ │ ├── router/
79
+ │ │ └── index.ts # Vue Router config
80
+ │ ├── App.vue # Root component
81
+ │ └── main.ts # App entry point
82
+ ├── e2e/
83
+ │ ├── app.spec.ts # Basic navigation tests
84
+ │ └── auth.spec.ts # OAuth flow tests
85
+ ├── playwright.config.ts # Playwright configuration
86
+ └── package.json
87
+ ```
88
+
89
+ ## Scripts
90
+
91
+ | Command | Description |
92
+ |---------|-------------|
93
+ | `npm run dev` | Start development server |
94
+ | `npm run build` | Build for production |
95
+ | `npm run preview` | Preview production build |
96
+ | `npm run test:e2e` | Run Playwright E2E tests |
97
+
98
+ ## E2E Testing
99
+
100
+ The example includes Playwright E2E tests that verify:
101
+ - Basic navigation and page rendering
102
+ - OAuth login flow
103
+ - Dashboard functionality
104
+ - Camera and event type selection
105
+ - Alerts and notifications loading
106
+
107
+ To run E2E tests:
108
+ ```bash
109
+ # Ensure OAuth proxy is running
110
+ npm run test:e2e
111
+ ```
112
+
113
+ Required environment variables for E2E tests:
114
+ - `TEST_USER` - Test account email
115
+ - `TEST_PASSWORD` - Test account password
116
+
117
+ ## API Functions Used
118
+
119
+ This example demonstrates the following `een-api-toolkit` functions:
120
+
121
+ - `initEenToolkit()` - Initialize the toolkit
122
+ - `getAuthUrl()` - Get OAuth authorization URL
123
+ - `handleAuthCallback()` - Handle OAuth callback
124
+ - `useAuthStore()` - Access authentication state
125
+ - `getCameras()` - List available cameras
126
+ - `listEventFieldValues()` - Get available event types for a camera
127
+ - `getEventMetrics()` - Fetch event metrics time-series data
128
+ - `listAlertTypes()` - Get available alert types
129
+ - `listAlerts()` - Fetch alerts for a camera
130
+ - `listNotifications()` - Fetch notifications for a camera
131
+
132
+ ## Known Limitations
133
+
134
+ - **Event Metrics aggregation** - The EEN API requires a minimum 60-minute aggregation period. Shorter time ranges (1h, 6h) will have fewer data points.
135
+ - **Alerts API** - Alert type filtering is functional, but some alert types may not have data.
136
+ - **Notifications API** - Notification display is implemented but may have limited data depending on account configuration.
@@ -0,0 +1,74 @@
1
+ import { test, expect } from '@playwright/test'
2
+
3
+ test.describe('Alerts & Metrics Example App', () => {
4
+ test('should display the home page', async ({ page }) => {
5
+ await page.goto('/')
6
+
7
+ // Check title
8
+ await expect(page).toHaveTitle('EEN Alerts & Metrics Example')
9
+
10
+ // Check header
11
+ await expect(page.locator('h1')).toContainText('EEN Alerts & Metrics Example')
12
+
13
+ // Check navigation links
14
+ await expect(page.locator('nav')).toContainText('Home')
15
+ await expect(page.locator('nav')).toContainText('Login')
16
+ })
17
+
18
+ test('should show welcome message on home page', async ({ page }) => {
19
+ await page.goto('/')
20
+
21
+ await expect(page.locator('h2')).toContainText('Welcome to the EEN Alerts & Metrics Example')
22
+ })
23
+
24
+ test('should display login prompt when not authenticated', async ({ page }) => {
25
+ await page.goto('/')
26
+
27
+ // Should show login prompt
28
+ await expect(page.locator('.login-prompt')).toBeVisible()
29
+ await expect(page.locator('.login-prompt')).toContainText('Please log in to view alerts, notifications, and metrics')
30
+ })
31
+
32
+ test('should navigate to login page', async ({ page }) => {
33
+ await page.goto('/')
34
+
35
+ // Click login in nav
36
+ await page.locator('nav a:has-text("Login")').click()
37
+
38
+ // Should be on login page
39
+ await expect(page.locator('h2')).toContainText('Login')
40
+ await expect(page.locator('button')).toContainText('Login with Eagle Eye Networks')
41
+ })
42
+
43
+ test('should redirect to login when accessing dashboard without auth', async ({ page }) => {
44
+ // Try to access dashboard directly
45
+ await page.goto('/dashboard')
46
+
47
+ // Should be redirected to login
48
+ await expect(page.locator('h2')).toContainText('Login')
49
+ })
50
+
51
+ test('should show about section on home page', async ({ page }) => {
52
+ await page.goto('/')
53
+
54
+ // Check the about section
55
+ await expect(page.locator('.description h3')).toContainText('About This Example')
56
+ await expect(page.locator('.description')).toContainText('getEventMetrics')
57
+ await expect(page.locator('.description')).toContainText('listAlerts')
58
+ await expect(page.locator('.description')).toContainText('listNotifications')
59
+ })
60
+
61
+ test('should have correct navigation structure', async ({ page }) => {
62
+ await page.goto('/')
63
+
64
+ // Check all expected nav links for unauthenticated state
65
+ const navLinks = page.locator('nav a')
66
+ await expect(navLinks).toHaveCount(2) // Home, Login
67
+
68
+ // Verify Home link
69
+ await expect(navLinks.nth(0)).toHaveAttribute('href', '/')
70
+
71
+ // Verify Login link
72
+ await expect(navLinks.nth(1)).toHaveAttribute('href', '/login')
73
+ })
74
+ })