Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/javascript/grid-ui/src/tests/components/Node.test.tsx
2887 views
1
// Licensed to the Software Freedom Conservancy (SFC) under one
2
// or more contributor license agreements. See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership. The SFC licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License. You may obtain a copy of the License at
8
//
9
// http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied. See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
import * as React from 'react'
19
import Node from '../../components/Node/Node'
20
import NodeInfo from '../../models/node-info'
21
import OsInfo from '../../models/os-info'
22
import StereotypeInfo from '../../models/stereotype-info'
23
import { render, screen, within } from '@testing-library/react'
24
import userEvent from '@testing-library/user-event'
25
import '@testing-library/jest-dom'
26
27
jest.mock('../../components/LiveView/LiveView', () => {
28
return {
29
__esModule: true,
30
default: React.forwardRef((props: { url: string, scaleViewport?: boolean, onClose?: () => void }, ref) => {
31
React.useImperativeHandle(ref, () => ({
32
disconnect: jest.fn()
33
}))
34
return <div data-testid="mock-live-view" data-url={props.url}>LiveView Mock</div>
35
})
36
}
37
})
38
39
const osInfo: OsInfo = {
40
name: 'Mac OS X',
41
version: '10.16',
42
arch: 'x86_64'
43
}
44
45
const slotStereotype: StereotypeInfo = {
46
browserName: 'chrome',
47
browserVersion: 'v. 88',
48
slotCount: 12,
49
rawData: ['stereotype: {"browserName": "chrome"}'],
50
platformName: 'macos'
51
}
52
53
const node: NodeInfo = {
54
uri: 'http://192.168.1.7:4444',
55
id: '9e92a45a-0de3-4424-824a-ff7b6aa57b16',
56
status: 'UP',
57
maxSession: 12,
58
slotCount: 50,
59
version: '4.0.0-beta-1',
60
osInfo: osInfo,
61
sessionCount: 2,
62
slotStereotypes: [slotStereotype]
63
}
64
65
const sessionWithVnc = {
66
id: 'session-with-vnc',
67
capabilities: JSON.stringify({
68
'browserName': 'chrome',
69
'browserVersion': '88.0',
70
'se:vnc': 'ws://172.17.0.2:4444/session/4d31d065-6cb9-4545-ac8d-d70ed5f5168b/se/vnc'
71
}),
72
nodeId: node.id
73
}
74
75
const sessionWithoutVnc = {
76
id: 'session-without-vnc',
77
capabilities: JSON.stringify({
78
'browserName': 'chrome',
79
'browserVersion': '88.0'
80
}),
81
nodeId: node.id
82
}
83
84
describe('Node component', () => {
85
it('renders basic node information', () => {
86
render(<Node node={node} />)
87
expect(screen.getByText(node.uri)).toBeInTheDocument()
88
expect(
89
screen.getByText(`Sessions: ${node.sessionCount}`)).toBeInTheDocument()
90
expect(screen.getByText(
91
`Max. Concurrency: ${node.maxSession}`)).toBeInTheDocument()
92
})
93
94
it('renders detailed node information', async () => {
95
render(<Node node={node}/>)
96
const user = userEvent.setup()
97
await user.click(screen.getByRole('button'))
98
expect(screen.getByText(`Node Id: ${node.id}`)).toBeInTheDocument()
99
expect(
100
screen.getByText(`Total slots: ${node.slotCount}`)).toBeInTheDocument()
101
expect(screen.getByText(`OS Arch: ${node.osInfo.arch}`)).toBeInTheDocument()
102
expect(screen.getByText(`OS Name: ${node.osInfo.name}`)).toBeInTheDocument()
103
expect(
104
screen.getByText(`OS Version: ${node.osInfo.version}`)).toBeInTheDocument()
105
})
106
107
it('does not render live view icon when no VNC session is available', () => {
108
render(<Node node={node} sessions={[sessionWithoutVnc]} origin="http://localhost:4444" />)
109
expect(screen.queryByTestId('VideocamIcon')).not.toBeInTheDocument()
110
})
111
112
it('renders live view icon when VNC session is available', () => {
113
render(<Node node={node} sessions={[sessionWithVnc]} origin="http://localhost:4444" />)
114
expect(screen.getByTestId('VideocamIcon')).toBeInTheDocument()
115
})
116
117
it('opens live view dialog when camera icon is clicked', async () => {
118
render(<Node node={node} sessions={[sessionWithVnc]} origin="http://localhost:4444" />)
119
120
const user = userEvent.setup()
121
await user.click(screen.getByTestId('VideocamIcon'))
122
123
expect(screen.getByText('Node Session Live View')).toBeInTheDocument()
124
const dialogTitle = screen.getByText('Node Session Live View')
125
const dialog = dialogTitle.closest('.MuiDialog-root')
126
expect(dialog).not.toBeNull()
127
if (dialog) {
128
expect(within(dialog as HTMLElement).getAllByText(node.uri).length).toBeGreaterThan(0)
129
}
130
expect(screen.getByTestId('mock-live-view')).toBeInTheDocument()
131
})
132
133
it('closes live view dialog when close button is clicked', async () => {
134
render(<Node node={node} sessions={[sessionWithVnc]} origin="http://localhost:4444" />)
135
136
const user = userEvent.setup()
137
await user.click(screen.getByTestId('VideocamIcon'))
138
139
expect(screen.getByText('Node Session Live View')).toBeInTheDocument()
140
141
await user.click(screen.getByRole('button', { name: /close/i }))
142
143
expect(screen.queryByText('Node Session Live View')).not.toBeInTheDocument()
144
})
145
146
it('correctly transforms VNC URL for WebSocket connection', async () => {
147
const origin = 'https://grid.example.com'
148
render(<Node node={node} sessions={[sessionWithVnc]} origin={origin} />)
149
150
const user = userEvent.setup()
151
await user.click(screen.getByTestId('VideocamIcon'))
152
153
const liveView = screen.getByTestId('mock-live-view')
154
const url = liveView.getAttribute('data-url')
155
156
expect(url).toBe('wss://grid.example.com/session/4d31d065-6cb9-4545-ac8d-d70ed5f5168b/se/vnc')
157
})
158
159
it('handles HTTP to WS protocol conversion correctly', async () => {
160
const httpOrigin = 'http://grid.example.com'
161
render(<Node node={node} sessions={[sessionWithVnc]} origin={httpOrigin} />)
162
163
const user = userEvent.setup()
164
await user.click(screen.getByTestId('VideocamIcon'))
165
166
const liveView = screen.getByTestId('mock-live-view')
167
const url = liveView.getAttribute('data-url')
168
169
expect(url).toContain('ws:')
170
expect(url).not.toContain('wss:')
171
})
172
173
it('handles invalid VNC URLs gracefully', async () => {
174
const invalidVncSession = {
175
id: 'session-invalid-vnc',
176
capabilities: JSON.stringify({
177
'browserName': 'chrome',
178
'browserVersion': '88.0',
179
'se:vnc': 'invalid-url'
180
}),
181
nodeId: node.id
182
}
183
184
render(<Node node={node} sessions={[invalidVncSession]} origin="http://localhost:4444" />)
185
186
const user = userEvent.setup()
187
await user.click(screen.getByTestId('VideocamIcon'))
188
189
const liveView = screen.getByTestId('mock-live-view')
190
const url = liveView.getAttribute('data-url')
191
192
expect(url).toBe('')
193
})
194
})
195
196