Skip to content

Commit 8d18b89

Browse files
authored
Merge branch 'main' into danshalev7-patch-1
2 parents 85189ad + e67aeaf commit 8d18b89

File tree

11 files changed

+267
-168
lines changed

11 files changed

+267
-168
lines changed

.github/workflows/playwright.yml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ jobs:
88
test:
99
timeout-minutes: 60
1010
runs-on: ubuntu-latest
11+
strategy:
12+
fail-fast: false
13+
matrix:
14+
shard: [1, 2]
1115
services:
1216
falkordb:
1317
image: falkordb/falkordb:latest
@@ -32,10 +36,17 @@ jobs:
3236
run: |
3337
npm install
3438
npm run build
35-
NEXTAUTH_SECRET=SECRET npm start & npx playwright test --reporter=dot,list
39+
NEXTAUTH_SECRET=SECRET npm start &
40+
npx playwright test --shard=${{ matrix.shard }}/2 --reporter=dot,list
3641
- uses: actions/upload-artifact@v4
3742
if: ${{ !cancelled() }}
3843
with:
39-
name: playwright-report
44+
name: playwright-report-shard-${{ matrix.shard }}
4045
path: playwright-report/
4146
retention-days: 30
47+
- uses: actions/upload-artifact@v4
48+
if: ${{ !cancelled() }}
49+
with:
50+
name: test-results-shard-${{ matrix.shard }}
51+
path: test-results/
52+
retention-days: 30

app/components/elementMenu.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export default function ElementMenu({ obj, objects, setPath, handleRemove, posit
4141
setContainerWidth(ref.clientWidth)
4242
}}
4343
className="absolute z-10 bg-black rounded-lg shadow-lg flex divide-x divide-[#434343]"
44+
id="elementMenu"
4445
style={{
4546
left: Math.max(-34, Math.min(position.x - 33 - containerWidth / 2, (parentRef?.current?.clientWidth || 0) + 32 - containerWidth)),
4647
top: Math.min(position.y - 153, (parentRef?.current?.clientHeight || 0) - 9),

e2e/config/constants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
export const GRAPH_ID = "GraphRAG-SDK";
2-
export const PROJECT_NAME = "GraphRAG-SDK";
1+
export const GRAPHRAG_SDK = "GraphRAG-SDK";
2+
export const FLASK_GRAPH = "flask";
33
export const CHAT_OPTTIONS_COUNT = 1;
44
export const Node_Question = "how many nodes do we have?";
55
export const Edge_Question = "how many edges do we have?";

e2e/config/testData.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export const searchData: { searchInput: string; completedSearchInput?: string; }[] = [
22
{ searchInput: "test"},
33
{ searchInput: "set"},
4-
{ searchInput: "low", completedSearchInput: "lower" },
4+
{ searchInput: "low", completedSearchInput: "lower_items" },
55
{ searchInput: "as", completedSearchInput: "ask"},
66
];
77

e2e/logic/POM/codeGraph.ts

Lines changed: 113 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ export default class CodeGraph extends BasePage {
120120
return this.page.locator("//main[@data-name='main-chat']/*[last()-2]//img[@alt='Waiting for response']")
121121
}
122122

123+
private get waitingForResponseImage(): Locator {
124+
return this.page.locator("//img[@alt='Waiting for response']")
125+
}
126+
123127
private get selectInputForShowPath(): (inputNum: string) => Locator {
124128
return (inputNum: string) => this.page.locator(`(//main[@data-name='main-chat']//input)[${inputNum}]`);
125129
}
@@ -189,6 +193,10 @@ export default class CodeGraph extends BasePage {
189193
private get nodeDetailsPanel(): Locator {
190194
return this.page.locator("//div[@data-name='node-details-panel']");
191195
}
196+
197+
private get elementMenu(): Locator {
198+
return this.page.locator("//div[@id='elementMenu']");
199+
}
192200

193201
private get nodedetailsPanelHeader(): Locator {
194202
return this.page.locator("//div[@data-name='node-details-panel']/header/p");
@@ -277,7 +285,12 @@ export default class CodeGraph extends BasePage {
277285
}
278286

279287
async getTextInLastChatElement(): Promise<string>{
280-
await delay(2500);
288+
// Wait for loading indicator to disappear
289+
await this.waitingForResponseImage.waitFor({ state: 'hidden', timeout: 15000 });
290+
291+
// Short delay to ensure text is fully rendered
292+
await delay(1000);
293+
281294
return (await this.lastElementInChat.textContent())!;
282295
}
283296

@@ -416,8 +429,18 @@ export default class CodeGraph extends BasePage {
416429
}
417430

418431
async nodeClick(x: number, y: number): Promise<void> {
419-
await this.canvasElement.hover({ position: { x, y } });
420-
await this.canvasElement.click({ position: { x, y } });
432+
await this.waitForCanvasAnimationToEnd();
433+
for (let attempt = 1; attempt <= 3; attempt++) {
434+
await this.canvasElement.hover({ position: { x, y } });
435+
await this.page.waitForTimeout(500);
436+
await this.canvasElement.click({ position: { x, y }, button: 'left' });
437+
if (await this.elementMenu.isVisible()) {
438+
return;
439+
}
440+
await this.page.waitForTimeout(1000);
441+
}
442+
443+
throw new Error(`Failed to click, elementMenu not visible after multiple attempts.`);
421444
}
422445

423446
async selectCodeGraphCheckbox(checkbox: string): Promise<void> {
@@ -493,42 +516,39 @@ export default class CodeGraph extends BasePage {
493516
return Promise.all(elements.map(element => element.innerHTML()));
494517
}
495518

496-
async getGraphDetails(): Promise<any> {
497-
await this.canvasElementBeforeGraphSelection.waitFor({ state: 'detached' });
498-
await delay(2000)
499-
await this.page.waitForFunction(() => !!window.graph);
519+
async getGraphNodes(): Promise<any[]> {
520+
await this.waitForCanvasAnimationToEnd();
500521

501522
const graphData = await this.page.evaluate(() => {
502-
return window.graph;
503-
});
504-
505-
return graphData;
506-
}
507-
508-
async transformNodeCoordinates(graphData: any): Promise<any[]> {
509-
const { canvasLeft, canvasTop, canvasWidth, canvasHeight, transform } = await this.canvasElement.evaluate((canvas: HTMLCanvasElement) => {
510-
const rect = canvas.getBoundingClientRect();
511-
const ctx = canvas.getContext('2d');
512-
const transform = ctx?.getTransform()!;
513-
return {
514-
canvasLeft: rect.left,
515-
canvasTop: rect.top,
516-
canvasWidth: rect.width,
517-
canvasHeight: rect.height,
518-
transform,
519-
};
523+
return (window as any).graph;
520524
});
521-
522-
const screenCoordinates = graphData.elements.nodes.map((node: any) => {
523-
const adjustedX = node.x * transform.a + transform.e;
524-
const adjustedY = node.y * transform.d + transform.f;
525-
const screenX = canvasLeft + adjustedX - 35;
526-
const screenY = canvasTop + adjustedY - 190;
527525

528-
return {...node, screenX, screenY,};
529-
});
526+
let transformData: any = null;
527+
for (let attempt = 0; attempt < 3; attempt++) {
528+
await this.page.waitForTimeout(1000);
529+
530+
transformData = await this.canvasElement.evaluate((canvas: HTMLCanvasElement) => {
531+
const rect = canvas.getBoundingClientRect();
532+
const ctx = canvas.getContext('2d');
533+
return {
534+
left: rect.left,
535+
top: rect.top,
536+
transform: ctx?.getTransform() || null,
537+
};
538+
});
530539

531-
return screenCoordinates;
540+
if (transformData.transform) break;
541+
console.warn(`Attempt ${attempt + 1}: Transform data not available, retrying...`);
542+
}
543+
544+
if (!transformData?.transform) throw new Error("Canvas transform data not available!");
545+
546+
const { a, e, d, f } = transformData.transform;
547+
return graphData.elements.nodes.map((node: any) => ({
548+
...node,
549+
screenX: transformData.left + node.x * a + e - 35,
550+
screenY: transformData.top + node.y * d + f - 190,
551+
}));
532552
}
533553

534554
async getCanvasScaling(): Promise<{ scaleX: number; scaleY: number }> {
@@ -543,4 +563,63 @@ export default class CodeGraph extends BasePage {
543563
return { scaleX, scaleY };
544564
}
545565

566+
async getGraphDetails(): Promise<any> {
567+
await this.canvasElementBeforeGraphSelection.waitFor({ state: 'detached' });
568+
await this.waitForCanvasAnimationToEnd();
569+
await this.page.waitForFunction(() => !!window.graph);
570+
571+
const graphData = await this.page.evaluate(() => {
572+
return window.graph;
573+
});
574+
575+
return graphData;
576+
}
577+
578+
async waitForCanvasAnimationToEnd(timeout = 15000, checkInterval = 500): Promise<void> {
579+
const canvasHandle = await this.canvasElement.elementHandle();
580+
581+
if (!canvasHandle) {
582+
throw new Error("Canvas element not found!");
583+
}
584+
585+
await this.page.waitForFunction(
586+
async ({ canvas, checkInterval, timeout }) => {
587+
const ctx = canvas.getContext('2d');
588+
if (!ctx) return false;
589+
590+
const width = canvas.width;
591+
const height = canvas.height;
592+
593+
let previousData = ctx.getImageData(0, 0, width, height).data;
594+
const startTime = Date.now();
595+
596+
return new Promise<boolean>((resolve) => {
597+
const checkCanvas = () => {
598+
if (Date.now() - startTime > timeout) {
599+
resolve(true);
600+
return;
601+
}
602+
603+
setTimeout(() => {
604+
const currentData = ctx.getImageData(0, 0, width, height).data;
605+
if (JSON.stringify(previousData) === JSON.stringify(currentData)) {
606+
resolve(true);
607+
} else {
608+
previousData = currentData;
609+
checkCanvas();
610+
}
611+
}, checkInterval);
612+
};
613+
checkCanvas();
614+
});
615+
},
616+
{
617+
canvas: await canvasHandle.evaluateHandle((el) => el as HTMLCanvasElement),
618+
checkInterval,
619+
timeout
620+
},
621+
{ timeout }
622+
);
623+
}
624+
546625
}

e2e/logic/utils.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,12 @@ export const waitToBeEnabled = async (locator: Locator, timeout: number = 5000):
1717

1818
export function findNodeByName(nodes: { name: string }[], nodeName: string): any {
1919
return nodes.find((node) => node.name === nodeName);
20-
}
20+
}
21+
22+
export function findFirstNodeWithSrc(nodes: { src?: string }[]): any {
23+
return nodes.find((node) => node.src !== undefined);
24+
}
25+
26+
export function findNodeWithSpecificSrc(nodes: { src?: string }[], srcContent: string): any {
27+
return nodes.find((node) => node.src && node.src.includes(srcContent));
28+
}

0 commit comments

Comments
 (0)