Skip to content

Commit 043d959

Browse files
WiP
1 parent a80929a commit 043d959

File tree

12 files changed

+107
-40
lines changed

12 files changed

+107
-40
lines changed

test/e2e/002-console.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ test.describe('Console', () => {
2525
await page.getByRole('tab', { name: 'Output' }).click();
2626
await expectExecutionProgressBarSucceeded(page);
2727

28-
const output = await readFromCodeEditor(page);
28+
const output = await readFromCodeEditor(page, 'Console Output');
2929
expectToHaveMultilineText(output, `
3030
Hello World!
3131
`);

test/e2e/003-tool-access.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ test.describe('Tool Access', () => {
6363
await page.getByRole('tab', { name: 'Output' }).click();
6464
await expectExecutionProgressBarSucceeded(page);
6565

66-
const output = await readFromCodeEditor(page);
66+
const output = await readFromCodeEditor(page, 'Console Output');
6767
expect(output).toContain('Setup complete!');
6868

6969
await newAemContext(browser, 'acm-test-user', 'test1234', async (testUserPage) => {

test/e2e/004-history.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ test.describe('History', () => {
1717
await expect(firstRow.locator('[role="rowheader"]')).toContainText('Console');
1818
await firstRow.click();
1919
await page.getByRole('tab', { name: 'Output' }).click();
20-
const firstOutput = await readFromCodeEditor(page);
20+
const firstOutput = await readFromCodeEditor(page, 'Execution Output');
2121
expect(firstOutput).toContain('Setup complete!');
2222

2323
await page.goto('/acm#/history');
@@ -27,7 +27,7 @@ test.describe('History', () => {
2727
await expect(secondRow.locator('[role="rowheader"]')).toContainText('Console');
2828
await secondRow.click();
2929
await page.getByRole('tab', { name: 'Output' }).click();
30-
const secondOutput = await readFromCodeEditor(page);
30+
const secondOutput = await readFromCodeEditor(page, 'Execution Output');
3131
expect(secondOutput).toContain('Hello World!');
3232
});
3333
});

test/e2e/005-manual-scripts.spec.ts

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { test, expect } from '@playwright/test';
2-
import { expectExecutionProgressBarSucceeded } from './utils/expect';
3-
import { readFromCodeEditor } from './utils/editor';
2+
import { expectExecutionProgressBarSucceeded, expectToMatchTimestamp } from './utils/expect';
3+
import { readFromCodeEditor, readFromCodeEditorAsJson } from './utils/editor';
4+
import { getLabeledValueText } from './utils/labeledValue';
45

56
test.describe('Manual Scripts', () => {
67
test('Execute CSV Generation With I/O', async ({ page }) => {
@@ -16,7 +17,7 @@ test.describe('Manual Scripts', () => {
1617
await page.getByRole('button', { name: 'Start' }).click();
1718
await expectExecutionProgressBarSucceeded(page);
1819

19-
const output = await readFromCodeEditor(page);
20+
const output = await readFromCodeEditor(page, 'Execution Output');
2021
expect(output).toContain('[SUCCESS] Users CSV report generation ended successfully');
2122

2223
await page.getByRole('button', { name: 'Review' }).click();
@@ -41,5 +42,48 @@ test.describe('Manual Scripts', () => {
4142
await page.getByRole('button', { name: 'Download Report' }).click();
4243
const downloadReport = await downloadReportPromise;
4344
expect(downloadReport.suggestedFilename()).toMatch(/\.csv$/);
45+
46+
47+
await page.getByRole('tab', { name: 'Details' }).click();
48+
49+
const executionStatus = page.locator('#execution-status');
50+
const executionId = await getLabeledValueText(page, 'ID', executionStatus);
51+
expect(executionId).toMatch(/^2025\/\d+\/\d+\/\d+\/\d+\//);
52+
53+
await expect(page.getByText('admin')).toBeVisible();
54+
await expect(page.getByText('succeeded', { exact: false })).toBeVisible();
55+
56+
const executionTiming = page.locator('#execution-timing');
57+
const startedAt = await getLabeledValueText(page, 'Started At', executionTiming);
58+
expectToMatchTimestamp(startedAt);
59+
60+
const duration = await getLabeledValueText(page, 'Duration', executionTiming);
61+
expect(duration).toMatch(/\d+ ms \(\d+ seconds?\)/);
62+
63+
const endedAt = await getLabeledValueText(page, 'Ended At', executionTiming);
64+
expectToMatchTimestamp(endedAt);
65+
66+
const inputs = await readFromCodeEditorAsJson<Record<string, any>>(page, 'Execution Inputs JSON');
67+
expect(inputs).toEqual({
68+
count: 5000,
69+
firstNames: 'John\nJane\nJack\nAlice\nBob\nRobert',
70+
lastNames: 'Doe\nSmith\nBrown\nJohnson\nWhite\nJordan',
71+
});
72+
73+
const outputs = await readFromCodeEditorAsJson<Array<any>>(page, 'Execution Outputs JSON');
74+
expect(outputs).toHaveLength(2);
75+
expect(outputs[0]).toMatchObject({
76+
type: 'FILE',
77+
name: 'report',
78+
label: 'Report',
79+
downloadName: 'report.csv',
80+
});
81+
expect(outputs[1]).toMatchObject({
82+
type: 'TEXT',
83+
name: 'summary',
84+
value: 'Processed 5000 user(s)',
85+
});
86+
87+
await page.getByRole('button', { name: 'Close' }).click();
4488
});
4589
});

test/e2e/utils/editor.ts

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,32 @@ export async function writeToCodeEditor(page: Page, code: string, editorIndex: n
2222
}, { editorIndex, codeClean });
2323
}
2424

25-
export async function readFromCodeEditor(page: Page, editorIndex: number = 0): Promise<string> {
26-
await page.waitForFunction((data: { editorIndex: number }) => {
25+
export async function readFromCodeEditor(page: Page, ariaLabel: string): Promise<string> {
26+
await page.waitForFunction((label: string) => {
2727
const editors = (window as any).monaco?.editor?.getEditors?.() || [];
28-
if (editors.length <= data.editorIndex) {
29-
return false;
30-
}
31-
32-
const editor = editors[data.editorIndex];
33-
const model = editor.getModel();
34-
const value = model ? model.getValue() : '';
35-
36-
return value.trim().length > 0;
37-
}, { editorIndex }, { timeout: 10000 });
28+
return editors.some((editor: any) => {
29+
const domNode = editor.getDomNode();
30+
const textarea = domNode?.querySelector('textarea');
31+
return textarea?.getAttribute('aria-label') === label;
32+
});
33+
}, ariaLabel, { timeout: 10000 });
3834

39-
return await page.evaluate((data: { editorIndex: number }) => {
35+
return await page.evaluate((label: string) => {
4036
const editors = (window as any).monaco?.editor?.getEditors?.() || [];
41-
const editor = editors[data.editorIndex];
42-
const model = editor.getModel();
37+
const editor = editors.find((e: any) => {
38+
const domNode = e.getDomNode();
39+
const textarea = domNode?.querySelector('textarea');
40+
return textarea?.getAttribute('aria-label') === label;
41+
});
42+
const model = editor?.getModel();
4343
return model ? model.getValue() : '';
44-
}, { editorIndex });
44+
}, ariaLabel);
45+
}
46+
47+
export async function readFromCodeEditorAsJson<T = any>(
48+
page: Page,
49+
ariaLabel: string
50+
): Promise<T> {
51+
const content = await readFromCodeEditor(page, ariaLabel);
52+
return JSON.parse(content);
4553
}

test/e2e/utils/expect.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,8 @@ export function expectToHaveMultilineText(actual: string, expected: string) {
2828
for (const line of lines) {
2929
expect(actual).toContain(line);
3030
}
31+
}
32+
33+
export function expectToMatchTimestamp(actual: string) {
34+
expect(actual).toMatch(/\d+ \w+ \d{4} at \d+:\d+( \(.+\))?/);
3135
}

test/e2e/utils/labeledValue.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Locator, Page } from '@playwright/test';
2+
3+
/**
4+
* Gets the value text from a LabeledValue by its label
5+
*/
6+
export async function getLabeledValueText(page: Page, label: string, scope?: Locator): Promise<string> {
7+
const container = scope || page;
8+
const labeledValue = container.locator('div[class*="LabeledValue"]').filter({
9+
has: container.locator('span[class*="FieldLabel"]:text-is("' + label + '")')
10+
});
11+
const valueSpan = labeledValue.locator('span[class*="Field-field"]').first();
12+
return await valueSpan.textContent() || '';
13+
}

ui.frontend/src/components/ExecutionInputs.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const ExecutionInputs: React.FC<ExecutionInputsProps> = ({ inputs }) => {
5858
</ContextualHelp>
5959
</Flex>
6060
) : (
61-
<CodeTextarea language="json" value={JSON.stringify(inputs, null, 2)} options={{ readOnly: true }} />
61+
<CodeTextarea language="json" value={JSON.stringify(inputs, null, 2)} options={{ readOnly: true, ariaLabel: 'Execution Inputs JSON' }} />
6262
)}
6363
</div>
6464
</Field>

ui.frontend/src/components/ExecutionOutputs.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const ExecutionOutputs: React.FC<ExecutionOutputsProps> = ({ outputs }) => {
5858
</ContextualHelp>
5959
</Flex>
6060
) : (
61-
<CodeTextarea language="json" value={JSON.stringify(outputs, null, 2)} options={{ readOnly: true }} />
61+
<CodeTextarea language="json" value={JSON.stringify(outputs, null, 2)} options={{ readOnly: true, ariaLabel: 'Execution Outputs JSON' }} />
6262
)}
6363
</div>
6464
</Field>

ui.frontend/src/components/InfoCard.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ import { ReactNode } from 'react';
33

44
type InfoCardProps = {
55
children: ReactNode;
6+
id?: string;
67
};
78

8-
const InfoCard = ({ children }: InfoCardProps) => {
9+
const InfoCard = ({ children, id }: InfoCardProps) => {
910
return (
10-
<View backgroundColor="static-white" padding="size-200" borderRadius="medium" borderColor="dark" borderWidth="thin" flex="1">
11+
<View id={id} backgroundColor="static-white" padding="size-200" borderRadius="medium" borderColor="dark" borderWidth="thin" flex="1">
1112
<Flex direction="column" gap="size-200">
1213
{children}
1314
</Flex>

0 commit comments

Comments
 (0)