Skip to content

Commit 7e4bb86

Browse files
AaronPlaveJosephVolosin
authored andcommitted
Add API integration test mode to aerie-action-demo (#1909)
* Add API integration test mode to aerie-action-demo. Update aerie-action library. * Refactor * Enhance env test * Aria label and test ids * Additional e2e test that checks that an action actually wrote a file. Collect and surface action run errors in e2e tests.
1 parent aef0026 commit 7e4bb86

9 files changed

Lines changed: 439 additions & 14 deletions

File tree

e2e-tests/data/aerie-action-demo.js

Lines changed: 377 additions & 3 deletions
Large diffs are not rendered by default.

e2e-tests/fixtures/Action.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,25 +74,53 @@ export class Action {
7474
await expect(this.page.getByRole('tab', { name: 'Code' })).toBeVisible();
7575
}
7676

77-
async runAction(): Promise<void> {
77+
async runAction(options?: { expectedStatus?: 'Complete' | 'Failed'; mode?: string }): Promise<void> {
78+
const { expectedStatus, mode } = options ?? {};
79+
7880
// Click "Run Action" button in the detail view header
7981
await this.page.getByRole('button', { name: 'Run Action' }).click();
8082
// Wait for the run modal to appear
8183
const runModal = this.page.locator('#modal-container');
8284
await expect(runModal).toBeVisible();
85+
86+
// If a mode is specified, select it in the variant dropdown
87+
if (mode) {
88+
await runModal.getByRole('combobox', { name: 'mode' }).selectOption(mode);
89+
}
90+
8391
// Click the Run button in the modal footer
8492
await runModal.getByRole('button', { exact: true, name: 'Run' }).click();
8593
// Verify we navigated to the run detail view
8694
await expect(this.page.getByRole('heading', { name: /Run #\d+/ })).toBeVisible({ timeout: 15000 });
95+
8796
// Wait for a terminal status (Complete or Failed) in the main content area
8897
await expect(
8998
this.page
9099
.getByRole('tabpanel')
91100
.getByRole('button', { name: `Complete ${this.actionName}` })
92101
.or(this.page.getByRole('tabpanel').getByRole('button', { name: `Failed ${this.actionName}` })),
93-
).toBeVisible({
94-
timeout: 30000,
95-
});
102+
).toBeVisible({ timeout: 30000 });
103+
104+
if (expectedStatus) {
105+
const statusMatched = await this.page
106+
.getByRole('tabpanel')
107+
.getByRole('button', { name: `${expectedStatus} ${this.actionName}` });
108+
109+
if (!(await statusMatched.isVisible())) {
110+
if (expectedStatus === 'Complete') {
111+
// If we expect success but see failure, collect and throw the error message from the UI
112+
const errorMessage = await this.page.getByTestId('action-run-error-log').innerText();
113+
throw new Error(
114+
`Expected action run to have status "${expectedStatus}" but it did not. Error message: ${errorMessage}`,
115+
);
116+
} else {
117+
const results = await this.page.getByTestId('action-run-results').innerText();
118+
throw new Error(
119+
`Expected action run to have status "${expectedStatus}" but it did not. Run details: ${results}`,
120+
);
121+
}
122+
}
123+
}
96124
}
97125

98126
async selectActionInSidebar(): Promise<void> {

e2e-tests/fixtures/Workspace.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export class Workspace {
3232
workspaceFileContextMenu!: Locator;
3333
workspaceFileGrid!: Locator;
3434
workspaceHeaderMenu!: Locator;
35+
workspaceRefreshButton!: Locator;
3536
workspaceSettingsButton!: Locator;
3637
workspaceSidebar!: Locator;
3738

@@ -296,6 +297,7 @@ export class Workspace {
296297
this.workspaceHeaderMenu = page.getByTestId('workspace-header-menu');
297298
this.workspaceSidebar = page.locator('[data-slot="sidebar-wrapper"]').first();
298299
this.workspaceContextMenuButton = page.getByRole('button', { name: 'New Workspace Item' });
300+
this.workspaceRefreshButton = page.getByRole('button', { name: 'Refresh Workspace' });
299301
this.workspaceSettingsButton = page.getByRole('button', { name: 'Settings' });
300302
this.workspaceFileBrowserButton = page.getByRole('button', { name: 'Files' });
301303
this.workspaceCollaboratorInput = page.getByPlaceholder('Search collaborators or workspaces');

e2e-tests/tests/actions.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,24 @@ test.describe.serial('Actions', () => {
6666
await action.runAction();
6767
});
6868

69+
test('Run API integration tests', async () => {
70+
await action.selectActionInSidebar();
71+
await action.runAction({ expectedStatus: 'Complete', mode: 'api-test' });
72+
});
73+
74+
test('Action writes a file visible in workspace file browser', async () => {
75+
await action.selectActionInSidebar();
76+
await action.runAction({ expectedStatus: 'Complete', mode: 'write' });
77+
78+
// Switch to file browser and verify the written file appears
79+
await workspace.workspaceFileBrowserButton.click();
80+
await workspace.workspaceRefreshButton.click();
81+
await workspace.searchForFileAndWait('action_output.txt');
82+
83+
// Go back to the actions tab
84+
await action.switchToActionsTab();
85+
});
86+
6987
test('Archive an action prevents running', async () => {
7088
// Go back to the action detail view by clicking action name in sidebar
7189
await action.selectActionInSidebar();

package-lock.json

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"@lezer/generator": "^1.7.3",
5050
"@lezer/highlight": "^1.2.1",
5151
"@lezer/lr": "^1.4.2",
52-
"@nasa-jpl/aerie-actions": "1.1.0",
52+
"@nasa-jpl/aerie-actions": "1.2.4",
5353
"@nasa-jpl/aerie-ampcs": "^1.0.5",
5454
"@nasa-jpl/aerie-sequence-languages": "1.0.2",
5555
"@nasa-jpl/seq-json-schema": "^1.3.1",

src/components/parameters/ParameterBaseVariant.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<ParameterName {formParameter} />
3232
<div class="parameter-base-variant-content">
3333
<select
34+
aria-label={formParameter.name}
3435
bind:value={formParameter.value}
3536
class="st-select w-full"
3637
class:error={formParameter.errors !== null}

src/components/sequencing/actions/ActionRunDetailView.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@
295295
}}
296296
<div class="flex flex-col gap-3 rounded border border-destructive/30 bg-destructive/5 p-4">
297297
<h3 class="text-sm font-medium text-destructive">Error</h3>
298-
<div class="overflow-auto rounded bg-muted py-2 font-mono text-xs">
298+
<div class="overflow-auto rounded bg-muted py-2 font-mono text-xs" data-testid="action-run-error-log">
299299
<ConsoleLog log={errorLog} showType={false} showLongTimestamp={false} />
300300
</div>
301301
</div>
@@ -304,6 +304,7 @@
304304
<h3 class="text-sm font-medium">Results</h3>
305305
{#if actionRun.results?.data}
306306
<pre
307+
data-testid="action-run-results"
307308
class="max-h-[600px] overflow-auto whitespace-pre-wrap rounded bg-muted p-3 font-mono text-xs">{JSON.stringify(
308309
actionRun.results.data,
309310
undefined,

src/components/workspace/WorkspaceTabHeader.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
<Check size={16} />
4949
</Button>
5050
{:else}
51-
<Button variant="outline" size="icon" on:click={onRefreshWorkspace}>
51+
<Button variant="outline" size="icon" on:click={onRefreshWorkspace} aria-label="Refresh Workspace">
5252
<RefreshCw size={16} />
5353
</Button>
5454
{/if}

0 commit comments

Comments
 (0)