Path: blob/trunk/javascript/grid-ui/src/tests/components/Node.test.tsx
2887 views
// Licensed to the Software Freedom Conservancy (SFC) under one1// or more contributor license agreements. See the NOTICE file2// distributed with this work for additional information3// regarding copyright ownership. The SFC licenses this file4// to you under the Apache License, Version 2.0 (the5// "License"); you may not use this file except in compliance6// with the License. You may obtain a copy of the License at7//8// http://www.apache.org/licenses/LICENSE-2.09//10// Unless required by applicable law or agreed to in writing,11// software distributed under the License is distributed on an12// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY13// KIND, either express or implied. See the License for the14// specific language governing permissions and limitations15// under the License.1617import * as React from 'react'18import Node from '../../components/Node/Node'19import NodeInfo from '../../models/node-info'20import OsInfo from '../../models/os-info'21import StereotypeInfo from '../../models/stereotype-info'22import { render, screen, within } from '@testing-library/react'23import userEvent from '@testing-library/user-event'24import '@testing-library/jest-dom'2526jest.mock('../../components/LiveView/LiveView', () => {27return {28__esModule: true,29default: React.forwardRef((props: { url: string, scaleViewport?: boolean, onClose?: () => void }, ref) => {30React.useImperativeHandle(ref, () => ({31disconnect: jest.fn()32}))33return <div data-testid="mock-live-view" data-url={props.url}>LiveView Mock</div>34})35}36})3738const osInfo: OsInfo = {39name: 'Mac OS X',40version: '10.16',41arch: 'x86_64'42}4344const slotStereotype: StereotypeInfo = {45browserName: 'chrome',46browserVersion: 'v. 88',47slotCount: 12,48rawData: ['stereotype: {"browserName": "chrome"}'],49platformName: 'macos'50}5152const node: NodeInfo = {53uri: 'http://192.168.1.7:4444',54id: '9e92a45a-0de3-4424-824a-ff7b6aa57b16',55status: 'UP',56maxSession: 12,57slotCount: 50,58version: '4.0.0-beta-1',59osInfo: osInfo,60sessionCount: 2,61slotStereotypes: [slotStereotype]62}6364const sessionWithVnc = {65id: 'session-with-vnc',66capabilities: JSON.stringify({67'browserName': 'chrome',68'browserVersion': '88.0',69'se:vnc': 'ws://172.17.0.2:4444/session/4d31d065-6cb9-4545-ac8d-d70ed5f5168b/se/vnc'70}),71nodeId: node.id72}7374const sessionWithoutVnc = {75id: 'session-without-vnc',76capabilities: JSON.stringify({77'browserName': 'chrome',78'browserVersion': '88.0'79}),80nodeId: node.id81}8283describe('Node component', () => {84it('renders basic node information', () => {85render(<Node node={node} />)86expect(screen.getByText(node.uri)).toBeInTheDocument()87expect(88screen.getByText(`Sessions: ${node.sessionCount}`)).toBeInTheDocument()89expect(screen.getByText(90`Max. Concurrency: ${node.maxSession}`)).toBeInTheDocument()91})9293it('renders detailed node information', async () => {94render(<Node node={node}/>)95const user = userEvent.setup()96await user.click(screen.getByRole('button'))97expect(screen.getByText(`Node Id: ${node.id}`)).toBeInTheDocument()98expect(99screen.getByText(`Total slots: ${node.slotCount}`)).toBeInTheDocument()100expect(screen.getByText(`OS Arch: ${node.osInfo.arch}`)).toBeInTheDocument()101expect(screen.getByText(`OS Name: ${node.osInfo.name}`)).toBeInTheDocument()102expect(103screen.getByText(`OS Version: ${node.osInfo.version}`)).toBeInTheDocument()104})105106it('does not render live view icon when no VNC session is available', () => {107render(<Node node={node} sessions={[sessionWithoutVnc]} origin="http://localhost:4444" />)108expect(screen.queryByTestId('VideocamIcon')).not.toBeInTheDocument()109})110111it('renders live view icon when VNC session is available', () => {112render(<Node node={node} sessions={[sessionWithVnc]} origin="http://localhost:4444" />)113expect(screen.getByTestId('VideocamIcon')).toBeInTheDocument()114})115116it('opens live view dialog when camera icon is clicked', async () => {117render(<Node node={node} sessions={[sessionWithVnc]} origin="http://localhost:4444" />)118119const user = userEvent.setup()120await user.click(screen.getByTestId('VideocamIcon'))121122expect(screen.getByText('Node Session Live View')).toBeInTheDocument()123const dialogTitle = screen.getByText('Node Session Live View')124const dialog = dialogTitle.closest('.MuiDialog-root')125expect(dialog).not.toBeNull()126if (dialog) {127expect(within(dialog as HTMLElement).getAllByText(node.uri).length).toBeGreaterThan(0)128}129expect(screen.getByTestId('mock-live-view')).toBeInTheDocument()130})131132it('closes live view dialog when close button is clicked', async () => {133render(<Node node={node} sessions={[sessionWithVnc]} origin="http://localhost:4444" />)134135const user = userEvent.setup()136await user.click(screen.getByTestId('VideocamIcon'))137138expect(screen.getByText('Node Session Live View')).toBeInTheDocument()139140await user.click(screen.getByRole('button', { name: /close/i }))141142expect(screen.queryByText('Node Session Live View')).not.toBeInTheDocument()143})144145it('correctly transforms VNC URL for WebSocket connection', async () => {146const origin = 'https://grid.example.com'147render(<Node node={node} sessions={[sessionWithVnc]} origin={origin} />)148149const user = userEvent.setup()150await user.click(screen.getByTestId('VideocamIcon'))151152const liveView = screen.getByTestId('mock-live-view')153const url = liveView.getAttribute('data-url')154155expect(url).toBe('wss://grid.example.com/session/4d31d065-6cb9-4545-ac8d-d70ed5f5168b/se/vnc')156})157158it('handles HTTP to WS protocol conversion correctly', async () => {159const httpOrigin = 'http://grid.example.com'160render(<Node node={node} sessions={[sessionWithVnc]} origin={httpOrigin} />)161162const user = userEvent.setup()163await user.click(screen.getByTestId('VideocamIcon'))164165const liveView = screen.getByTestId('mock-live-view')166const url = liveView.getAttribute('data-url')167168expect(url).toContain('ws:')169expect(url).not.toContain('wss:')170})171172it('handles invalid VNC URLs gracefully', async () => {173const invalidVncSession = {174id: 'session-invalid-vnc',175capabilities: JSON.stringify({176'browserName': 'chrome',177'browserVersion': '88.0',178'se:vnc': 'invalid-url'179}),180nodeId: node.id181}182183render(<Node node={node} sessions={[invalidVncSession]} origin="http://localhost:4444" />)184185const user = userEvent.setup()186await user.click(screen.getByTestId('VideocamIcon'))187188const liveView = screen.getByTestId('mock-live-view')189const url = liveView.getAttribute('data-url')190191expect(url).toBe('')192})193})194195196