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
15 changes: 14 additions & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -327,12 +327,25 @@ tasks:

test:e2e:
dir: test/e2e
desc: Test tool using end-to-end tests using Playwright
desc: Test tool using end-to-end tests
cmd: |
set -e
sh nw npm install
sh nw npx playwright {{.CLI_ARGS | default "test"}}

test:e2e:codegen:
dir: test/e2e
desc: Generate end-to-end test code from recording
cmd: |
sh nw npm install
sh nw npx playwright codegen --target=ts {{.AEM_AUTHOR_HTTP_URL}}

test:e2e:report:
dir: test/e2e
desc: Show end-to-end test report
cmd: |
sh nw npx playwright show-report

rde:setup:
desc: setup access to RDE
cmds:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ public void onEvent(Event event) {

public void bootOnDemand() {
LOG.info("Automatic scripts booting on demand - job scheduling");
bootedScripts.clear();
unscheduleBoot();
scheduleBoot();
LOG.info("Automatic scripts booting on demand - job scheduled");
Expand Down Expand Up @@ -319,8 +320,10 @@ private void queueBootScript(Script script, ResourceResolver resourceResolver) {
bootedScripts.put(script.getId(), checksum);
LOG.info("Boot script '{}' queued", script.getId());
} else {
LOG.info("Boot script '{}' not eligible for queueing!", script.getId());
LOG.info("Boot script '{}' not queued - check failed", script.getId());
}
} else {
LOG.info("Boot script '{}' not queued - checksum unchanged", script.getId());
}
}

Expand Down
26 changes: 23 additions & 3 deletions test/e2e/001-general.spec.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,44 @@
import { test, expect } from '@playwright/test';
import { expectCodeExecutorStatus, expectHealthyStatus } from './utils/expect';
import { testOnEnv, apiHeaders } from './utils/env';
import { attachScreenshot } from './utils/page';

test.describe('General', () => {
test('Tool is accessible', async ({ page }) => {
test('Tool is accessible', async ({ page }, testInfo) => {
await page.goto('/acm');

const title = page.locator('.granite-title', { hasText: 'Content Manager' });
await expect(title).toBeVisible();

await attachScreenshot(page, testInfo, 'Dashboard Page');
});

testOnEnv('local')('Tool state is reset', async ({ page }) => {
const clearResponse = await page.request.post('/apps/acm/api/event.json?name=HISTORY_CLEAR', { headers: await apiHeaders(page) });
expect(clearResponse.ok()).toBeTruthy();
const clearJson = await clearResponse.json();
expect(clearJson).toEqual({ status: 200, message: "Event 'HISTORY_CLEAR' dispatched successfully!", data: null });
await page.waitForTimeout(3000);

const bootResponse = await page.request.post('/apps/acm/api/event.json?name=SCRIPT_SCHEDULER_BOOT', { headers: await apiHeaders(page) });
expect(bootResponse.ok()).toBeTruthy();
const bootJson = await bootResponse.json();
expect(bootJson).toEqual({ status: 200, message: "Event 'SCRIPT_SCHEDULER_BOOT' dispatched successfully!", data: null });
await page.waitForTimeout(10000);
});

test('System is healthy', async ({ page }) => {
test('System is healthy', async ({ page }, testInfo) => {
await page.goto('/acm#/maintenance?tab=health-checker');

await expectHealthyStatus(page);
await attachScreenshot(page, testInfo, 'Health Checker');
});

test('Code executor is idle', async ({ page }) => {
test('Code executor is idle', async ({ page }, testInfo) => {
await page.goto('/acm#/maintenance?tab=code-executor');

await expectCodeExecutorStatus(page);
await attachScreenshot(page, testInfo, 'Code Executor');
});

});
6 changes: 4 additions & 2 deletions test/e2e/002-console.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { test, expect } from '@playwright/test';
import { expectCompilationSucceeded, expectExecutionProgressBarSucceeded, expectToHaveMultilineText } from './utils/expect'
import { readFromCodeEditor, writeToCodeEditor } from './utils/editor';
import { attachScreenshot } from './utils/page';

test.describe('Console', () => {
test('Executes script', async ({ page }) => {
test('Executes script', async ({ page }, testInfo) => {
await page.goto('/acm#/console');

await expectCompilationSucceeded(page);
Expand All @@ -22,13 +23,14 @@ test.describe('Console', () => {
await expect(page.getByRole('button', { name: 'Execute' })).toBeEnabled();
await page.getByRole('button', { name: 'Execute' }).click();

await page.getByRole('tab', { name: 'Output' }).click();
await expect(page.getByRole('tab', { name: 'Output' })).toHaveAttribute('aria-selected', 'true');
await expectExecutionProgressBarSucceeded(page);

const output = await readFromCodeEditor(page, 'Console Output');
expectToHaveMultilineText(output, `
Hello World!
`);
await attachScreenshot(page, testInfo, 'Console Output');
});
});

15 changes: 11 additions & 4 deletions test/e2e/003-tool-access.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { test, expect } from '@playwright/test';
import { expectCompilationSucceeded, expectExecutionProgressBarSucceeded } from './utils/expect';
import { readFromCodeEditor, writeToCodeEditor } from './utils/editor';
import { newAemContext } from './utils/context';
import { attachScreenshot } from './utils/page';

test.describe('Tool Access', () => {
test('Admin user has full access', async ({ page }) => {
test('Admin user has full access', async ({ page }, testInfo) => {
await page.goto('/acm');

await expect(page.getByRole('button', { name: 'Console' })).toBeVisible();
Expand All @@ -18,9 +19,11 @@ test.describe('Tool Access', () => {
await page.goto('/acm#/console');
await expectCompilationSucceeded(page);
await expect(page.getByRole('button', { name: 'Execute' })).toBeEnabled();

await attachScreenshot(page, testInfo, 'Admin Full Access');
});

test('Setup test user and verify limited access', async ({ page, browser }) => {
test('Setup test user and verify limited access', async ({ page, browser }, testInfo) => {
await page.goto('/acm#/console');

await expectCompilationSucceeded(page);
Expand Down Expand Up @@ -59,8 +62,7 @@ test.describe('Tool Access', () => {

await expect(page.getByRole('button', { name: 'Execute' })).toBeEnabled();
await page.getByRole('button', { name: 'Execute' }).click();

await page.getByRole('tab', { name: 'Output' }).click();
await expect(page.getByRole('tab', { name: 'Output' })).toHaveAttribute('aria-selected', 'true');
await expectExecutionProgressBarSucceeded(page);

const output = await readFromCodeEditor(page, 'Console Output');
Expand All @@ -77,6 +79,8 @@ test.describe('Tool Access', () => {
await expect(testUserPage.getByRole('button', { name: 'Snippets' })).not.toBeVisible();
await expect(testUserPage.getByRole('button', { name: 'History' })).not.toBeVisible();
await expect(testUserPage.getByRole('button', { name: 'Maintenance' })).not.toBeVisible();

await attachScreenshot(testUserPage, testInfo, 'Test User Access - Dashboard');

await testUserPage.getByRole('button', { name: 'Scripts' }).click();
await expect(testUserPage).toHaveURL(/\/acm#\/scripts/);
Expand All @@ -90,6 +94,9 @@ test.describe('Tool Access', () => {
const scriptRow = rows.nth(1);
await expect(scriptRow.locator('[role="rowheader"]')).toContainText('example/ACME-200_hello-world');

await attachScreenshot(testUserPage, testInfo, 'Test User Access - Script List');

// Check if routing blocks access to other tools
await testUserPage.goto('/acm#/console');
await expect(testUserPage.getByRole('button', { name: 'Console' })).not.toBeVisible();

Expand Down
24 changes: 24 additions & 0 deletions test/e2e/004-automatic-scripts.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { test, expect } from '@playwright/test';
import { attachScreenshot } from './utils/page';

test.describe('Automatic Scripts', () => {

test('Executions saved in history', async ({ page }, testInfo) => {
await page.goto('/acm');
await page.getByRole('button', { name: 'History' }).click();

const grid = page.locator('[role="grid"][aria-label="Executions table"]');
await expect(grid).toBeVisible();
const rows = grid.locator('[role="row"]');

await page.getByRole('searchbox', { name: 'Executable' }).fill('example/ACME-20_once');
await expect(rows.nth(1)).toContainText('Script \'example/ACME-20_once\'');
await expect(rows.nth(1)).toContainText('succeeded');
await attachScreenshot(page, testInfo, `Script List filtered by 'ACME-20_once'`);

await page.getByRole('searchbox', { name: 'Executable' }).fill('example/ACME-21_changed');
await expect(rows.nth(1)).toContainText('Script \'example/ACME-21_changed\'');
await expect(rows.nth(1)).toContainText('succeeded');
await attachScreenshot(page, testInfo, `Script List filtered by 'ACME-21_changed'`);
});
});
50 changes: 0 additions & 50 deletions test/e2e/004-history.spec.ts

This file was deleted.

18 changes: 15 additions & 3 deletions test/e2e/005-manual-scripts.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,38 @@ import {
expectOutputFileDownload,
} from './utils/expect';
import { readFromCodeEditor } from './utils/editor';
import { attachScreenshot } from './utils/page';

test.describe('Manual Scripts', () => {
test('Execute CSV Generation With I/O', async ({ page }) => {
test('Execute CSV Generation', async ({ page }, testInfo) => {
await page.goto('/acm');
await page.getByRole('button', { name: 'Scripts' }).click();
await expect(page.locator('[role="grid"][aria-label="Script list (manual)"]')).toBeVisible();

await page.getByText('example/ACME-203_output-csv').click();
await expect(page).toHaveURL(/\/acm#\/scripts\/view\/%2Fconf%2Facm%2Fsettings%2Fscript%2Fmanual%2Fexample%2FACME-203_output-csv\.groovy/);
await page.waitForTimeout(1000);
await attachScreenshot(page, testInfo, 'Script Details');

await page.getByRole('button', { name: 'Execute' }).click();

await page.getByRole('textbox', { name: 'Users to' }).fill('5000');
await page.getByRole('textbox', { name: 'First names' }).fill('John\nJane\nJack\nAlice\nBob\nRobert');
await page.getByRole('textbox', { name: 'Last names' }).fill('Doe\nSmith\nBrown\nJohnson\nWhite\nJordan');

// TODO await attachScreenshot(page, testInfo, 'Inputs Dialog');

await page.getByRole('button', { name: 'Start' }).click();
await expectExecutionProgressBarSucceeded(page);

const output = await readFromCodeEditor(page, 'Execution Output');
expect(output).toContain('[SUCCESS] Users CSV report generation ended successfully');
await attachScreenshot(page, testInfo, 'Execution Console Output');

await page.getByRole('tab', { name: 'Details' }).click();

await page.waitForTimeout(1000);
await page.screenshot();
await attachScreenshot(page, testInfo, 'Execution Details');

await expectExecutionDetails(page);
await expectExecutionTimings(page);
Expand All @@ -56,14 +66,16 @@ test.describe('Manual Scripts', () => {
]);

await page.getByRole('tab', { name: 'Output' }).click();

await page.getByRole('button', { name: 'Review' }).click();

await page.getByRole('tab', { name: 'Texts' }).click();
await expectOutputTexts(page, ['Processed 5000 user(s)']);
// TODO await attachScreenshot(page, testInfo, 'Outputs Review - Texts');
await page.getByTestId('modal').getByRole('button', { name: 'Close' }).click();

await page.getByRole('button', { name: 'Review' }).click();
await page.getByRole('tab', { name: 'Files' }).click();
// TODO await attachScreenshot(page, testInfo, 'Outputs Review - Files');
await expectOutputFileDownload(page, 'Download Archive', /\.(zip)$/);

await page.getByRole('button', { name: 'Review' }).click();
Expand Down
10 changes: 6 additions & 4 deletions test/e2e/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { defineConfig, devices } from '@playwright/test';
import { authHeader, BASE_URL } from './utils/env';

/**
* Read environment variables from file.
Expand Down Expand Up @@ -26,21 +27,22 @@ export default defineConfig({
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('')`. */
baseURL: 'http://localhost:5502',
baseURL: BASE_URL,

/* Action timeout (e.g. toBeEnabled, toBeVisible) */
actionTimeout: 10000,

/* Basic Auth for AEM */
extraHTTPHeaders: {
'Authorization': 'Basic ' + Buffer.from('admin:admin').toString('base64'),
...authHeader(),
'Origin': BASE_URL,
},

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',

/* Screenshots on failure */
screenshot: 'on',
/* Screenshots only on failure (manual screenshots still work) */
screenshot: 'only-on-failure',

/* Videos on failure */
video: 'retain-on-failure',
Expand Down
7 changes: 3 additions & 4 deletions test/e2e/utils/context.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Browser, Page } from '@playwright/test';
import { authHeader, BASE_URL } from './env';

export async function newAemContext(
browser: Browser,
Expand All @@ -7,10 +8,8 @@ export async function newAemContext(
callback: (page: Page) => Promise<void>
): Promise<void> {
const context = await browser.newContext({
baseURL: 'http://localhost:5502',
extraHTTPHeaders: {
'Authorization': 'Basic ' + btoa(`${user}:${password}`),
},
baseURL: BASE_URL,
extraHTTPHeaders: authHeader(user, password),
});

const page = await context.newPage();
Expand Down
Loading