Compare commits

..

4 Commits

Author SHA1 Message Date
M. Mert Yıldıran
0b7d535a81 Make the scrollable reference snap to the bottom after clicking pause/play buttons (resuming streaming) (#619) 2022-01-11 12:09:10 +03:00
Adam Kol
9d0c2a693e Cypress: new TapRegex test is ready + pageObjects (#611)
* introducing pageObjects

* fixes

* pretty code

Co-authored-by: lirazyehezkel <61656597+lirazyehezkel@users.noreply.github.com>
2022-01-11 10:56:27 +02:00
M. Mert Yıldıran
2b2c7687a1 Fix the CSS issue on tooltip in case of right-pane is scrolled down (#598) 2022-01-11 11:44:16 +03:00
M. Mert Yıldıran
4708998f54 Fix the CSS issue on EntryItem Queryable src.name (#602) 2022-01-11 11:38:13 +03:00
11 changed files with 89 additions and 94 deletions

View File

@@ -6,7 +6,8 @@
"screenshotOnRunFailure": false,
"testFiles":
["tests/GuiPort.js",
"tests/MultipleNamespaces.js"],
"tests/MultipleNamespaces.js",
"tests/Regex.js"],
"env": {
"testUrl": "http://localhost:8899/"
}

View File

@@ -0,0 +1,46 @@
const columns = {podName : 1, namespace : 2, tapping : 3};
const greenStatusImageSrc = '/static/media/success.662997eb.svg';
function getDomPathInStatusBar(line, column) {
return `.expandedStatusBar > :nth-child(2) > > :nth-child(2) > :nth-child(${line}) > :nth-child(${column})`;
}
export function checkLine(line, expectedValues) {
cy.get(getDomPathInStatusBar(line, columns.podName)).invoke('text').then(podValue => {
const podName = getOnlyPodName(podValue);
expect(podName).to.equal(expectedValues.podName);
cy.get(getDomPathInStatusBar(line, columns.namespace)).invoke('text').then(namespaceValue => {
expect(namespaceValue).to.equal(expectedValues.namespace);
cy.get(getDomPathInStatusBar(line, columns.tapping)).children().should('have.attr', 'src', greenStatusImageSrc);
});
});
}
export function findLineAndCheck(expectedValues) {
cy.get('.expandedStatusBar > :nth-child(2) > > :nth-child(2) > > :nth-child(1)').then(pods => {
cy.get('.expandedStatusBar > :nth-child(2) > > :nth-child(2) > > :nth-child(2)').then(namespaces => {
// organizing namespaces array
const podObjectsArray = Object.values(pods ?? {});
const namespacesObjectsArray = Object.values(namespaces ?? {});
let lineNumber = -1;
namespacesObjectsArray.forEach((namespaceObj, index) => {
const currentLine = index + 1;
lineNumber = (namespaceObj.getAttribute && namespaceObj.innerHTML === expectedValues.namespace && (getOnlyPodName(podObjectsArray[index].innerHTML)) === expectedValues.podName) ? currentLine : lineNumber;
});
lineNumber === -1 ? throwError(expectedValues) : checkLine(lineNumber, expectedValues);
});
});
}
function throwError(expectedValues) {
throw new Error(`The pod named ${expectedValues.podName} doesn't match any namespace named ${expectedValues.namespace}`);
}
export function getExpectedDetailsDict(podName, namespace) {
return {podName : podName, namespace : namespace};
}
function getOnlyPodName(podElementFullStr) {
return podElementFullStr.substring(0, podElementFullStr.indexOf('-'));
}

View File

@@ -1,8 +1,8 @@
it('check', function () {
cy.visit(`http://localhost:${Cypress.env('port')}/`)
cy.visit(`http://localhost:${Cypress.env('port')}/`);
cy.get('.header').should('be.visible')
cy.get('.TrafficPageHeader').should('be.visible')
cy.get('.TrafficPage-ListContainer').should('be.visible')
cy.get('.TrafficPage-Container').should('be.visible')
})
cy.get('.header').should('be.visible');
cy.get('.TrafficPageHeader').should('be.visible');
cy.get('.TrafficPage-ListContainer').should('be.visible');
cy.get('.TrafficPage-Container').should('be.visible');
});

View File

@@ -1,67 +1,18 @@
const columns = {"podName" : 1, "namespace" : 2, "tapping" : 3}
const greenStatusImageSrc = "/static/media/success.662997eb.svg"
import {findLineAndCheck, getExpectedDetailsDict} from '../page_objects/StatusBar';
it('opening', function () {
cy.visit(Cypress.env('testUrl'))
cy.get('.podsCount').trigger('mouseover')
cy.visit(Cypress.env('testUrl'));
cy.get('.podsCount').trigger('mouseover');
});
[1, 2, 3].map(doItFunc)
[1, 2, 3].map(doItFunc);
function doItFunc(number) {
const podName = Cypress.env(`name${number}`)
const namespace = Cypress.env(`namespace${number}`)
const podName = Cypress.env(`name${number}`);
const namespace = Cypress.env(`namespace${number}`);
it(`verifying the pod (${podName}, ${namespace})`, function () {
findLineAndCheck({"podName" : podName, "namespace" : namespace})
})
findLineAndCheck(getExpectedDetailsDict(podName, namespace));
});
}
function getDomPathInStatusBar(line, column) {
return `.expandedStatusBar > :nth-child(2) > > :nth-child(2) > :nth-child(${line}) > :nth-child(${column})`
}
function checkLine(line, expectedValues) {
cy.get(getDomPathInStatusBar(line, columns.podName)).invoke('text').then(podValue => {
const podName = podValue.substring(0, podValue.indexOf('-'))
expect(podName).to.equal(expectedValues.podName)
cy.get(getDomPathInStatusBar(line, columns.namespace)).invoke('text').then(namespaceValue => {
expect(namespaceValue).to.equal(expectedValues.namespace)
cy.get(getDomPathInStatusBar(line, columns.tapping)).children().should('have.attr', 'src', greenStatusImageSrc)
})
})
}
function findLineAndCheck(expectedValues) {
cy.get('.expandedStatusBar > :nth-child(2) > > :nth-child(2) > > :nth-child(1)').then(pods => {
cy.get('.expandedStatusBar > :nth-child(2) > > :nth-child(2) > > :nth-child(2)').then(namespaces => {
// organizing namespaces array
const namespacesObjectsArray = Object.values(namespaces)
let namespacesArray = []
namespacesObjectsArray.forEach(line => {
line.getAttribute ? namespacesArray.push(line.innerHTML) : null
})
// organizing pods array
const podObjectsArray = Object.values(pods)
let podsArray = []
podObjectsArray.forEach(line => {
line.getAttribute ? podsArray.push(line.innerHTML.substring(0, line.innerHTML.indexOf('-'))) : null
})
let rightIndex = -1
podsArray.forEach((element, index) => {
if (element === expectedValues.podName && namespacesArray[index] === expectedValues.namespace) {
rightIndex = index + 1
}
})
rightIndex === -1 ? throwError(expectedValues.podName, expectedValues.namespace) : checkLine(rightIndex, expectedValues)
})
})
}
function throwError(pod, namespace) {
throw new Error(`The pod named ${pod} doesn't match any namespace named ${namespace}`)
}

View File

@@ -0,0 +1,11 @@
import {getExpectedDetailsDict, checkLine} from '../page_objects/StatusBar';
it('opening', function () {
cy.visit(Cypress.env('testUrl'));
cy.get('.podsCount').trigger('mouseover');
cy.get('.expandedStatusBar > :nth-child(2) > > :nth-child(2) >').should('have.length', 1); // one line
checkLine(1, getExpectedDetailsDict(Cypress.env('name'), Cypress.env('namespace')));
});

View File

@@ -280,30 +280,8 @@ func TestTapRegex(t *testing.T) {
return
}
podsUrl := fmt.Sprintf("%v/status/tap", apiServerUrl)
requestResult, requestErr := executeHttpGetRequest(podsUrl)
if requestErr != nil {
t.Errorf("failed to get tap status, err: %v", requestErr)
return
}
pods, err := getPods(requestResult)
if err != nil {
t.Errorf("failed to get pods, err: %v", err)
return
}
if len(expectedPods) != len(pods) {
t.Errorf("unexpected result - expected pods length: %v, actual pods length: %v", len(expectedPods), len(pods))
return
}
for _, expectedPod := range expectedPods {
if !isPodDescriptorInPodArray(pods, expectedPod) {
t.Errorf("unexpected result - expected pod not found, pod namespace: %v, pod name: %v", expectedPod.Namespace, expectedPod.Name)
return
}
}
runCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/integration/tests/Regex.js\" --env name=%v,namespace=%v",
expectedPods[0].Name, expectedPods[0].Namespace))
}
func TestTapDryRun(t *testing.T) {

2
ui/package-lock.json generated
View File

@@ -18684,4 +18684,4 @@
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
}
}
}
}

View File

@@ -1,4 +1,4 @@
import React, {useCallback, useEffect, useMemo, useRef, useState} from "react";
import React, {useCallback, useEffect, useMemo, useState} from "react";
import styles from './style/EntriesList.module.sass';
import ScrollableFeedVirtualized from "react-scrollable-feed-virtualized";
import Moment from 'moment';
@@ -33,14 +33,14 @@ interface EntriesListProps {
leftOffBottom: number;
truncatedTimestamp: number;
setTruncatedTimestamp: any;
scrollableRef: any;
}
const api = Api.getInstance();
export const EntriesList: React.FC<EntriesListProps> = ({entries, setEntries, query, listEntryREF, onSnapBrokenEvent, isSnappedToBottom, setIsSnappedToBottom, queriedCurrent, setQueriedCurrent, queriedTotal, setQueriedTotal, startTime, noMoreDataTop, setNoMoreDataTop, focusedEntryId, setFocusedEntryId, updateQuery, leftOffTop, setLeftOffTop, isWebSocketConnectionClosed, ws, openWebSocket, leftOffBottom, truncatedTimestamp, setTruncatedTimestamp}) => {
export const EntriesList: React.FC<EntriesListProps> = ({entries, setEntries, query, listEntryREF, onSnapBrokenEvent, isSnappedToBottom, setIsSnappedToBottom, queriedCurrent, setQueriedCurrent, queriedTotal, setQueriedTotal, startTime, noMoreDataTop, setNoMoreDataTop, focusedEntryId, setFocusedEntryId, updateQuery, leftOffTop, setLeftOffTop, isWebSocketConnectionClosed, ws, openWebSocket, leftOffBottom, truncatedTimestamp, setTruncatedTimestamp, scrollableRef}) => {
const [loadMoreTop, setLoadMoreTop] = useState(false);
const [isLoadingTop, setIsLoadingTop] = useState(false);
const scrollableRef = useRef(null);
useEffect(() => {
const list = document.getElementById('list').firstElementChild;
@@ -92,7 +92,7 @@ export const EntriesList: React.FC<EntriesListProps> = ({entries, setEntries, qu
if (scrollTo) {
scrollableRef.current.scrollToIndex(data.data.length - 1);
}
},[setLoadMoreTop, setIsLoadingTop, entries, setEntries, query, setNoMoreDataTop, leftOffTop, setLeftOffTop, queriedCurrent, setQueriedCurrent, setQueriedTotal, setTruncatedTimestamp]);
},[setLoadMoreTop, setIsLoadingTop, entries, setEntries, query, setNoMoreDataTop, leftOffTop, setLeftOffTop, queriedCurrent, setQueriedCurrent, setQueriedTotal, setTruncatedTimestamp, scrollableRef]);
useEffect(() => {
if(!isWebSocketConnectionClosed || !loadMoreTop || noMoreDataTop) return;

View File

@@ -51,6 +51,7 @@
color: $blue-gray
border-radius: 4px
padding: 10px
position: relative
.bodyHeader
padding: 0 1rem
.endpointURL

View File

@@ -161,7 +161,9 @@ export const EntryItem: React.FC<EntryProps> = ({entry, focusedEntryId, setFocus
displayIconOnMouseOver={true}
flipped={true}
style={{marginTop: "-4px", overflow: "visible"}}
iconStyle={!headingMode ? {marginTop: "4px", left: "68px", position: "absolute"} : {marginTop: "4px", left: "calc(50vw + 41px)", position: "absolute"}}
iconStyle={!headingMode ? {marginTop: "4px", left: "68px", position: "absolute"} :
entry.protocol.name === "http" ? {marginTop: "4px", left: "calc(50vw + 41px)", position: "absolute"} :
{marginTop: "4px", left: "calc(50vw - 9px)", position: "absolute"}}
>
<span
title="Source Name"

View File

@@ -72,6 +72,8 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({onTLSDetected, setAnaly
const [startTime, setStartTime] = useState(0);
const scrollableRef = useRef(null);
const handleQueryChange = useMemo(() => debounce(async (query: string) => {
if (!query) {
setQueryBackgroundColor("#f5f5f5")
@@ -239,6 +241,8 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({onTLSDetected, setAnaly
} else {
openWebSocket(`leftOff(-1)`, true);
}
scrollableRef.current.jumpToBottom();
setIsSnappedToBottom(true);
}
}
@@ -318,6 +322,7 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({onTLSDetected, setAnaly
leftOffBottom={leftOffBottom}
truncatedTimestamp={truncatedTimestamp}
setTruncatedTimestamp={setTruncatedTimestamp}
scrollableRef={scrollableRef}
/>
</div>
</div>