Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isP
</button>
<form className="grow flex items-center border rounded-md px-2" onSubmit={sendQuery}>
<DropdownMenuTrigger asChild>
<button className="bg-gray-200 p-2 rounded-md hover:bg-gray-300">
<button data-name="questionOptionsMenu" className="bg-gray-200 p-2 rounded-md hover:bg-gray-300">
<ArrowDown color="white" />
</button>
</DropdownMenuTrigger>
Expand Down
4 changes: 2 additions & 2 deletions app/components/code-graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -435,8 +435,8 @@ export function CodeGraph({
</button>
}
</div>
<div className="w-full absolute bottom-0 left-0 flex justify-between items-center p-4 z-10 pointer-events-none">
<div className="flex gap-4 text-gray-500">
<div data-name="canvas-info-panel" className="w-full absolute bottom-0 left-0 flex justify-between items-center p-4 z-10 pointer-events-none">
<div data-name="metrics-panel" className="flex gap-4 text-gray-500">
<p>{nodesCount} Nodes</p>
<p>{edgesCount} Edges</p>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/components/dataPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default function DataPanel({ obj, setObj, url }: Props) {
const object = Object.entries(obj).filter(([k]) => !excludedProperties.includes(k))

return (
<div className="z-20 absolute -top-10 left-20 bg-[#343434] text-white shadow-lg rounded-lg flex flex-col max-h-[88%] max-w-[56%] overflow-hidden" >
<div data-name="node-details-panel" className="z-20 absolute -top-10 left-20 bg-[#343434] text-white shadow-lg rounded-lg flex flex-col max-h-[88%] max-w-[56%] overflow-hidden" >
<header className="bg-[#191919] flex items-center gap-8 justify-between p-8">
<p title={label} className="truncate font-bold">{label.toUpperCase()}</p>
<button onClick={() => setObj(undefined)}>
Expand Down
2 changes: 1 addition & 1 deletion e2e/config/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const GRAPH_ID = "1";
export const GRAPH_ID = "GraphRAG-SDK";
export const PROJECT_NAME = "GraphRAG-SDK";
export const CHAT_OPTTIONS_COUNT = 1;
export const Node_Question = "how many nodes do we have?";
Expand Down
5 changes: 5 additions & 0 deletions e2e/config/testData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@ export const specialCharacters: { character: string; expectedRes: boolean }[] =
...categorizeCharacters(['%', '*', '(', ')', '-', '[', ']', '{', '}', ';', ':', '"', '|', '~'], false),
...categorizeCharacters(['!', '@', '$', '^', '_', '=', '+', "'", ',', '.', '<', '>', '/', '?', '\\', '`', '&', '#'], true)
];

export const nodesPath: { firstNode: string; secondNode: string }[] = [
{ firstNode: "import_data", secondNode: "add_edge" },
{ firstNode: "test_kg_delete", secondNode: "list_graphs" },
];
6 changes: 3 additions & 3 deletions e2e/infra/ui/browserWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ export default class BrowserWrapper {
if (!this.browser) {
this.browser = await chromium.launch();
}
if (!this.context) {
this.context = await this.browser.newContext();
}
this.context = await this.browser.newContext({
permissions: ['clipboard-read', 'clipboard-write'],
});
if (!this.page) {
this.page = await this.context.newPage();
}
Expand Down
189 changes: 171 additions & 18 deletions e2e/logic/POM/codeGraph.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Locator, Page } from "playwright";
import BasePage from "../../infra/ui/basePage";
import { delay, waitToBeEnabled } from "../utils";
import { analyzeCanvasWithLocator, CanvasAnalysisResult } from "../canvasAnalysis";
import { analyzeCanvasNodes, CanvasAnalysisResult } from "../canvasAnalysis";

export default class CodeGraph extends BasePage {
/* NavBar Locators*/
Expand All @@ -21,17 +21,33 @@ export default class CodeGraph extends BasePage {
return this.page.locator("//div[@role='dialog']")
}

private get tipBtn(): Locator {
return this.page.locator("//button[@title='Tip']")
}

private get genericMenu(): Locator {
return this.page.locator("//div[contains(@role, 'menu')]")
}

private get tipMenuCloseBtn(): Locator {
return this.page.locator("//div[@role='menu']//button[@title='Close']")
}

/* CodeGraph Locators*/
private get comboBoxbtn(): Locator {
return this.page.locator("//button[@role='combobox']")
}

private get selectGraphInComboBox(): (graph: string) => Locator {
return (graph: string) => this.page.locator(`//div[@role='presentation']//div[@role='option'][${graph}]`);
private get selectGraphInComboBoxByName(): (graph: string) => Locator {
return (graph: string) => this.page.locator(`//div[@role='presentation']//div//span[contains(text(), '${graph}')]`);
}

private get selectGraphInComboBoxById(): (graph: string) => Locator {
return (graph: string) => this.page.locator(`//div[@role='presentation']//div[${graph}]`);
}

private get lastElementInChat(): Locator {
return this.page.locator("//main[@data-name='main-chat']/*[last()]/p");
return this.page.locator("//main[@data-name='main-chat']/*[last()]/span");
}

private get typeUrlInput(): Locator {
Expand Down Expand Up @@ -115,6 +131,22 @@ export default class CodeGraph extends BasePage {
return this.page.locator("//div[@role='region']//ol//li");
}

private get notificationErrorCloseBtn(): Locator {
return this.page.locator("//div[@role='region']//ol//li/button");
}

private get questionOptionsMenu(): Locator {
return this.page.locator("//button[@data-name='questionOptionsMenu']");
}

private get selectQuestionInMenu(): (questionNumber: string) => Locator {
return (questionNumber: string) => this.page.locator(`//div[contains(@role, 'menu')]/button[${questionNumber}]`);
}

private get lastQuestionInChat(): Locator {
return this.page.locator("//main[@data-name='main-chat']/*[last()-1]/p");
}

/* Canvas Locators*/

private get canvasElement(): Locator {
Expand All @@ -133,10 +165,37 @@ export default class CodeGraph extends BasePage {
return this.page.locator("//button[@title='Center']");
}

private get removeNodeViaElementMenu(): Locator {
return this.page.locator("//button[@title='Remove']");
private get codeGraphCheckbox(): (checkbox: string) => Locator {
return (checkbox: string) => this.page.locator(`(//button[@role='checkbox'])[${checkbox}]`);
}

private get clearGraphBtn(): Locator {
return this.page.locator("//button[p[text()='Clear Graph']]");
}

private get elementMenuButton(): (buttonID: string) => Locator {
return (buttonID: string) => this.page.locator(`//button[@title='${buttonID}']`);
}

private get nodedetailsPanelHeader(): Locator {
return this.page.locator("//div[@data-name='node-details-panel']/header/p");
}

private get nodedetailsPanelcloseBtn(): Locator {
return this.page.locator("//div[@data-name='node-details-panel']/header/button");
}
private get canvasMetricsPanel(): (itemId: string) => Locator {
return (itemId: string) => this.page.locator(`//div[@data-name='metrics-panel']/p[${itemId}]`);
}

private get nodedetailsPanelID(): Locator {
return this.page.locator("//div[@data-name='node-details-panel']/main/div[1]/p[2]");
}

private get nodedetailsPanelElements(): Locator {
return this.page.locator("//div[@data-name='node-details-panel']/main/div/p[1]");
}

/* NavBar functionality */
async clickOnFalkorDbLogo(): Promise<Page> {
await this.page.waitForLoadState('networkidle');
Expand Down Expand Up @@ -164,6 +223,19 @@ export default class CodeGraph extends BasePage {
return await this.createNewProjectDialog.isVisible();
}

async clickonTipBtn(): Promise<void> {
await this.tipBtn.click();
}

async isTipMenuVisible(): Promise<boolean> {
await delay(500);
return await this.genericMenu.isVisible();
}

async clickonTipMenuCloseBtn(): Promise<void> {
await this.tipMenuCloseBtn.click();
}

/* Chat functionality */
async clickOnshowPathBtn(): Promise<void> {
await this.showPathBtn.click();
Expand All @@ -183,8 +255,9 @@ export default class CodeGraph extends BasePage {
await this.lightbulbBtn.click();
}

async getTextInLastChatElement(): Promise<string | null>{
return await this.lastElementInChat.textContent();
async getTextInLastChatElement(): Promise<string>{
await delay(2500);
return (await this.lastElementInChat.textContent())!;
}

async getLastChatElementButtonCount(): Promise<number | null>{
Expand Down Expand Up @@ -224,14 +297,37 @@ export default class CodeGraph extends BasePage {
}

async isNotificationError(): Promise<boolean> {
await delay(500);
return await this.notificationError.isVisible();
}

async clickOnNotificationErrorCloseBtn(): Promise<void> {
await this.notificationErrorCloseBtn.click();
}

async clickOnQuestionOptionsMenu(): Promise<void> {
await this.questionOptionsMenu.click();
}

async selectAndGetQuestionInOptionsMenu(questionNumber: string): Promise<string> {
await this.selectQuestionInMenu(questionNumber).click();
return await this.selectQuestionInMenu(questionNumber).innerHTML();
}

async getLastQuestionInChat(): Promise<string> {
return await this.lastQuestionInChat.innerText();
}

/* CodeGraph functionality */
async selectGraph(graph: string): Promise<void> {
async selectGraph(graph: string | number): Promise<void> {
await this.comboBoxbtn.click();
await this.selectGraphInComboBox(graph).waitFor({ state : 'visible'})
await this.selectGraphInComboBox(graph).click();
if(typeof graph === 'number'){
await this.selectGraphInComboBoxById(graph.toString()).waitFor({ state : 'visible'})
await this.selectGraphInComboBoxById(graph.toString()).click();
} else {
await this.selectGraphInComboBoxByName(graph).waitFor({ state : 'visible'})
await this.selectGraphInComboBoxByName(graph).click();
}
}

async createProject(url : string): Promise<void> {
Expand All @@ -251,6 +347,7 @@ export default class CodeGraph extends BasePage {
}

async getSearchAutoCompleteCount(): Promise<number> {
await this.searchBarAutoCompleteOptions.first().waitFor({ state: 'visible' });
return await this.searchBarAutoCompleteOptions.count();
}

Expand All @@ -259,14 +356,14 @@ export default class CodeGraph extends BasePage {
}

async selectSearchBarOptionBtn(buttonNum: string): Promise<void> {
await delay(1000);
await this.searchBarOptionBtn(buttonNum).click();
}

async getSearchBarInputValue(): Promise<string> {
return await this.searchBarInput.inputValue();
}


async scrollToBottomInSearchBarList(): Promise<void> {
await this.searchBarList.evaluate((element) => {
element.scrollTop = element.scrollHeight;
Expand All @@ -279,10 +376,10 @@ export default class CodeGraph extends BasePage {
}

/* Canvas functionality */

async getCanvasAnalysis(): Promise<CanvasAnalysisResult> {
await delay(2000);
return await analyzeCanvasWithLocator(this.canvasElement);
return await analyzeCanvasNodes(this.canvasElement);
}

async clickZoomIn(): Promise<void> {
Expand All @@ -298,14 +395,70 @@ export default class CodeGraph extends BasePage {
}

async clickOnRemoveNodeViaElementMenu(): Promise<void> {
await this.removeNodeViaElementMenu.click();
await this.elementMenuButton("Remove").click();
}

async rightClickOnNode(x : number, y: number): Promise<void> {
async rightClickOnNode(x: number, y: number): Promise<void> {
const boundingBox = (await this.canvasElement.boundingBox())!;
const adjustedX = boundingBox.x + Math.round(x);
const adjustedY = boundingBox.y + Math.round(y);
const devicePixelRatio = await this.page.evaluate(() => window.devicePixelRatio || 1);
const adjustedX = boundingBox.x + Math.round(x * devicePixelRatio);
const adjustedY = boundingBox.y + Math.round(y * devicePixelRatio);
await this.page.mouse.click(adjustedX, adjustedY, { button: 'right' });
}


async selectCodeGraphCheckbox(checkbox: string): Promise<void> {
await this.codeGraphCheckbox(checkbox).click();
}

async clickOnClearGraphBtn(): Promise<void> {
await this.clearGraphBtn.click();
}
Comment on lines +410 to +416
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add wait states for improved test reliability

Consider adding wait states similar to other methods in the class to ensure reliable test execution.

 async selectCodeGraphCheckbox(checkbox: string): Promise<void> {
+    await this.page.waitForLoadState('networkidle');
     await this.codeGraphCheckbox(checkbox).click();
 }

 async clickOnClearGraphBtn(): Promise<void> {
+    await this.page.waitForLoadState('networkidle');
     await this.clearGraphBtn.click();
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async selectCodeGraphCheckbox(checkbox: string): Promise<void> {
await this.codeGraphCheckbox(checkbox).click();
}
async clickOnClearGraphBtn(): Promise<void> {
await this.clearGraphBtn.click();
}
async selectCodeGraphCheckbox(checkbox: string): Promise<void> {
await this.page.waitForLoadState('networkidle');
await this.codeGraphCheckbox(checkbox).click();
}
async clickOnClearGraphBtn(): Promise<void> {
await this.page.waitForLoadState('networkidle');
await this.clearGraphBtn.click();
}


async changeNodePosition(x: number, y: number): Promise<void> {
const box = (await this.canvasElement.boundingBox())!;
const targetX = x + 100;
const targetY = y + 50;
const absStartX = box.x + x;
const absStartY = box.y + y;
const absEndX = box.x + targetX;
const absEndY = box.y + targetY;
await this.page.mouse.move(absStartX, absStartY);
await this.page.mouse.down();
await this.page.mouse.move(absEndX, absEndY);
await this.page.mouse.up();
}

async getNodeDetailsHeader(): Promise<string> {
await this.elementMenuButton("View Node").click();
const text = await this.nodedetailsPanelHeader.innerHTML();
return text;
}

async clickOnNodeDetailsCloseBtn(): Promise<void>{
await this.nodedetailsPanelcloseBtn.click();
}

async getMetricsPanelInfo(): Promise<{nodes: string, edges: string}> {
const nodes = await this.canvasMetricsPanel("1").innerHTML();
const edges = await this.canvasMetricsPanel("2").innerHTML();
return { nodes, edges }
}

async clickOnCopySrcOnNode(): Promise<string> {
await this.elementMenuButton("Copy src to clipboard").click();
await delay(1000)
return await this.page.evaluate(() => navigator.clipboard.readText());
}

async getNodedetailsPanelID(): Promise<string> {
return await this.nodedetailsPanelID.innerHTML();
}

async getNodeDetailsPanelElements(): Promise<string[]> {
await this.elementMenuButton("View Node").click();
await delay(500)
const elements = await this.nodedetailsPanelElements.all();
return Promise.all(elements.map(element => element.innerHTML()));
}
}
4 changes: 2 additions & 2 deletions e2e/logic/api/apiCalls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export class ApiCalls {
return await result.json();
}

async fetchLatestRepoInfo(projectName: string): Promise<fetchLatestRepoInfo>{
const result = await postRequest(urls.baseUrl + "api/repo/" + projectName);
async projectInfo(projectName: string): Promise<fetchLatestRepoInfo>{
const result = await getRequest(urls.baseUrl + "api/repo/" + projectName + "/info");
return await result.json();
}

Expand Down
1 change: 1 addition & 0 deletions e2e/logic/api/apiResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface getProjectResponse {
ext?: string;
name: string;
path: string;
src: string;
doc?: string;
src_end?: number;
src_start?: number;
Expand Down
Loading
Loading