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
380 changes: 377 additions & 3 deletions e2e-tests/data/aerie-action-demo.js

Large diffs are not rendered by default.

36 changes: 32 additions & 4 deletions e2e-tests/fixtures/Action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,25 +74,53 @@ export class Action {
await expect(this.page.getByRole('tab', { name: 'Code' })).toBeVisible();
}

async runAction(): Promise<void> {
async runAction(options?: { expectedStatus?: 'Complete' | 'Failed'; mode?: string }): Promise<void> {
const { expectedStatus, mode } = options ?? {};

// Click "Run Action" button in the detail view header
await this.page.getByRole('button', { name: 'Run Action' }).click();
// Wait for the run modal to appear
const runModal = this.page.locator('#modal-container');
await expect(runModal).toBeVisible();

// If a mode is specified, select it in the variant dropdown
if (mode) {
await runModal.getByRole('combobox', { name: 'mode' }).selectOption(mode);
}

// Click the Run button in the modal footer
await runModal.getByRole('button', { exact: true, name: 'Run' }).click();
// Verify we navigated to the run detail view
await expect(this.page.getByRole('heading', { name: /Run #\d+/ })).toBeVisible({ timeout: 15000 });

// Wait for a terminal status (Complete or Failed) in the main content area
await expect(
this.page
.getByRole('tabpanel')
.getByRole('button', { name: `Complete ${this.actionName}` })
.or(this.page.getByRole('tabpanel').getByRole('button', { name: `Failed ${this.actionName}` })),
).toBeVisible({
timeout: 30000,
});
).toBeVisible({ timeout: 30000 });

if (expectedStatus) {
const statusMatched = await this.page
.getByRole('tabpanel')
.getByRole('button', { name: `${expectedStatus} ${this.actionName}` });

if (!(await statusMatched.isVisible())) {
if (expectedStatus === 'Complete') {
// If we expect success but see failure, collect and throw the error message from the UI
const errorMessage = await this.page.getByTestId('action-run-error-log').innerText();
throw new Error(
`Expected action run to have status "${expectedStatus}" but it did not. Error message: ${errorMessage}`,
);
} else {
const results = await this.page.getByTestId('action-run-results').innerText();
throw new Error(
`Expected action run to have status "${expectedStatus}" but it did not. Run details: ${results}`,
);
}
}
}
}

async selectActionInSidebar(): Promise<void> {
Expand Down
2 changes: 2 additions & 0 deletions e2e-tests/fixtures/Workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export class Workspace {
workspaceFileContextMenu!: Locator;
workspaceFileGrid!: Locator;
workspaceHeaderMenu!: Locator;
workspaceRefreshButton!: Locator;
workspaceSettingsButton!: Locator;
workspaceSidebar!: Locator;

Expand Down Expand Up @@ -296,6 +297,7 @@ export class Workspace {
this.workspaceHeaderMenu = page.getByTestId('workspace-header-menu');
this.workspaceSidebar = page.locator('[data-slot="sidebar-wrapper"]').first();
this.workspaceContextMenuButton = page.getByRole('button', { name: 'New Workspace Item' });
this.workspaceRefreshButton = page.getByRole('button', { name: 'Refresh Workspace' });
this.workspaceSettingsButton = page.getByRole('button', { name: 'Settings' });
this.workspaceFileBrowserButton = page.getByRole('button', { name: 'Files' });
this.workspaceCollaboratorInput = page.getByPlaceholder('Search collaborators or workspaces');
Expand Down
18 changes: 18 additions & 0 deletions e2e-tests/tests/actions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,24 @@ test.describe.serial('Actions', () => {
await action.runAction();
});

test('Run API integration tests', async () => {
await action.selectActionInSidebar();
await action.runAction({ expectedStatus: 'Complete', mode: 'api-test' });
});

test('Action writes a file visible in workspace file browser', async () => {
await action.selectActionInSidebar();
await action.runAction({ expectedStatus: 'Complete', mode: 'write' });

// Switch to file browser and verify the written file appears
await workspace.workspaceFileBrowserButton.click();
await workspace.workspaceRefreshButton.click();
await workspace.searchForFileAndWait('action_output.txt');

// Go back to the actions tab
await action.switchToActionsTab();
});

test('Archive an action prevents running', async () => {
// Go back to the action detail view by clicking action name in sidebar
await action.selectActionInSidebar();
Expand Down
9 changes: 5 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"@lezer/generator": "^1.7.3",
"@lezer/highlight": "^1.2.1",
"@lezer/lr": "^1.4.2",
"@nasa-jpl/aerie-actions": "1.1.0",
"@nasa-jpl/aerie-actions": "1.2.4",
"@nasa-jpl/aerie-ampcs": "^1.0.5",
"@nasa-jpl/aerie-sequence-languages": "1.0.2",
"@nasa-jpl/seq-json-schema": "^1.3.1",
Expand Down
1 change: 1 addition & 0 deletions src/components/parameters/ParameterBaseVariant.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<ParameterName {formParameter} />
<div class="parameter-base-variant-content">
<select
aria-label={formParameter.name}
bind:value={formParameter.value}
class="st-select w-full"
class:error={formParameter.errors !== null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@
}}
<div class="flex flex-col gap-3 rounded border border-destructive/30 bg-destructive/5 p-4">
<h3 class="text-sm font-medium text-destructive">Error</h3>
<div class="overflow-auto rounded bg-muted py-2 font-mono text-xs">
<div class="overflow-auto rounded bg-muted py-2 font-mono text-xs" data-testid="action-run-error-log">
<ConsoleLog log={errorLog} showType={false} showLongTimestamp={false} />
</div>
</div>
Expand All @@ -304,6 +304,7 @@
<h3 class="text-sm font-medium">Results</h3>
{#if actionRun.results?.data}
<pre
data-testid="action-run-results"
class="max-h-[600px] overflow-auto whitespace-pre-wrap rounded bg-muted p-3 font-mono text-xs">{JSON.stringify(
actionRun.results.data,
undefined,
Expand Down
2 changes: 1 addition & 1 deletion src/components/workspace/WorkspaceTabHeader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
<Check size={16} />
</Button>
{:else}
<Button variant="outline" size="icon" on:click={onRefreshWorkspace}>
<Button variant="outline" size="icon" on:click={onRefreshWorkspace} aria-label="Refresh Workspace">
<RefreshCw size={16} />
</Button>
{/if}
Expand Down
Loading