Skip to content

feat: add Playwright-based E2E test suite for ArcadeDB Studio frontend#2289

Closed
robfrank wants to merge 4 commits intomainfrom
feat/0000-playwright
Closed

feat: add Playwright-based E2E test suite for ArcadeDB Studio frontend#2289
robfrank wants to merge 4 commits intomainfrom
feat/0000-playwright

Conversation

@robfrank
Copy link
Copy Markdown
Collaborator

  • Introduce e2e-studio module with Playwright configuration, package scripts, and dependencies
  • Add comprehensive test suites covering authentication, navigation, UI components, database operations, and API integration
  • Implement robust authentication helper for multi-modal login/logout handling
  • Provide CI integration via GitHub Actions workflow update for studio E2E tests
  • Include documentation: README, module overview, and test results analysis
  • Add .gitignore for Node, Playwright, and IDE artifacts

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @robfrank, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a new, comprehensive Playwright-based End-to-End (E2E) testing suite for the ArcadeDB Studio frontend. It establishes a dedicated module (e2e-studio) with robust test coverage across key functionalities like authentication, UI interactions, database operations, and API integration. The suite includes an advanced authentication helper, automated Docker-based server management for easy setup, and detailed documentation, making it production-ready for continuous integration and improving the overall quality assurance process for ArcadeDB Studio.

Highlights

  • New E2E Test Suite: Introduced a dedicated e2e-studio module for comprehensive end-to-end testing of the ArcadeDB Studio frontend using Playwright.
  • Extensive Test Coverage: Implemented 7 distinct test suites covering critical areas like authentication, navigation, UI components, database operations, API integration, query execution, and graph visualization.
  • Robust Authentication Helper: Developed a versatile auth-helper.js to manage multi-modal login/logout, ensuring reliable test execution across different authentication scenarios.
  • Automated Server Management: Integrated Docker commands within package.json scripts to automatically start and stop a pre-configured ArcadeDB server for test execution, simplifying setup.
  • Comprehensive Documentation: Added detailed README.md and MODULE_OVERVIEW.md files, providing clear instructions for installation, usage, development, and insights into the module's architecture and current test results.
  • CI/CD Readiness: Configured Playwright for CI environments, including HTML and JUnit XML reporting, screenshot/video capture on failure, and optimized worker settings.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Comment on lines +232 to +269
runs-on: ubuntu-latest
needs: build-and-package
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Set up Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "22"
cache: "npm"
cache-dependency-path: "e2e-studio/package-lock.json"

- name: Restore Docker image
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: /tmp/arcadedb-image.tar
key: docker-image-${{ github.run_id }}-${{ github.run_attempt }}

- name: Load Docker image
run: docker load < /tmp/arcadedb-image.tar

- name: Install Playwright Browsers
working-directory: e2e-studio
run: |
npm install
npm run install-browsers

- name: E2E Studio Tests
working-directory: e2e-studio
run: npm test
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ARCADEDB_DOCKER_IMAGE: ${{ needs.build-and-package.outputs.image-tag }}

- name: Studio E2E Tests Reporter
uses: dorny/test-reporter@890a17cecf52a379fc869ab770a71657660be727 # v2.1.0
if: success() || failure()

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI 11 months ago

To fix the issue, we need to add a permissions block to the workflow file. This block should specify the minimal permissions required for the workflow to function correctly. Since the workflow primarily involves testing and artifact uploads, the contents: read permission is sufficient for most jobs. For jobs that require additional permissions (e.g., uploading artifacts), we can specify those permissions explicitly.

The permissions block can be added at the root level of the workflow to apply to all jobs, or it can be added to individual jobs if different jobs require different permissions.

Suggested changeset 1
.github/workflows/mvn-test.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/mvn-test.yml b/.github/workflows/mvn-test.yml
--- a/.github/workflows/mvn-test.yml
+++ b/.github/workflows/mvn-test.yml
@@ -11,2 +11,5 @@
 
+permissions:
+  contents: read
+
 jobs:
@@ -278,2 +281,5 @@
         if: success() || failure()
+        permissions:
+          contents: read
+          actions: write
         uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
EOF
@@ -11,2 +11,5 @@

permissions:
contents: read

jobs:
@@ -278,2 +281,5 @@
if: success() || failure()
permissions:
contents: read
actions: write
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
Copilot is powered by AI and may make mistakes. Always verify output.
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive E2E test suite for ArcadeDB Studio. Key suggestions focus on replacing fixed timeouts with condition-based waits for improved test reliability.

Comment thread e2e-studio/package.json
"test:database": "npm run start:server && playwright test --grep=\"Database Interaction\"; npm run stop:server",
"test:query": "npm run start:server && playwright test --grep=\"Query.*Data Visualization\"; npm run stop:server",
"test:graph": "npm run start:server && playwright test --grep=\"Graph Visualization\"; npm run stop:server",
"start:server": "docker run -d --name arcadedb-test --rm -p 2480:2480 -p 2424:2424 -p 6379:6379 -p 5432:5432 -p 8182:8182 --env JAVA_OPTS=\"-Darcadedb.server.rootPassword=playwithdata -Darcadedb.server.defaultDatabases=Beer[root]{import:https://github.com/ArcadeData/arcadedb-datasets/raw/main/orientdb/OpenBeer.gz} -Darcadedb.server.plugins=Redis:com.arcadedb.redis.RedisProtocolPlugin,MongoDB:com.arcadedb.mongo.MongoDBProtocolPlugin,Postgres:com.arcadedb.postgres.PostgresProtocolPlugin,GremlinServer:com.arcadedb.server.gremlin.GremlinServerPlugin\" arcadedata/arcadedb:latest && npm run wait:server",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Pinning the Docker image version in start:server improves test stability. Using arcadedata/arcadedb:latest is risky due to potential breaking changes. Consider using a specific version tag like arcadedata/arcadedb:23.11.1.

Comment on lines +48 to +49
await studioPanel.evaluate(el => el.style.display = 'block');
await page.waitForTimeout(500); // Wait for transitions
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Directly manipulating studioPanel's display style might mask legitimate hiding issues. Instead of page.waitForTimeout(500), wait for a specific condition or element state to ensure transition completion and avoid flakiness.

    // Show the studio panel programmatically if it's hidden and expected to be accessible
    // TODO: Investigate if a user action can make this panel visible instead of direct style manipulation
    await studioPanel.evaluate(el => el.style.display = 'block');
    await expect(studioPanel).toHaveCSS('opacity', '1', { timeout: 1000 }); // Example: wait for a CSS transition

const response = await page.request.get('/api/v1/ready');

// Health check should return appropriate status
expect([200, 204, 503]).toContain(response.status());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Including 503 (Service Unavailable) in the health check assertion expect([200, 204, 503]).toContain(response.status()); might mask actual problems. Clarify if 503 is an expected transient state or indicates a test failure.

await passwordField.fill('invalid_password');
await loginButton.click();

await page.waitForTimeout(3000);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Replace the fixed page.waitForTimeout(3000) after an invalid login attempt with a wait for a specific condition, like an error message becoming visible.

Suggested change
await page.waitForTimeout(3000);
// await page.waitForTimeout(3000); // Avoid fixed timeouts
// Option 1: Wait for a specific error message element to be visible
// await expect(page.locator('.login-error-message-selector')).toBeVisible({ timeout: 5000 });
// Option 2: Or ensure the dialog is still present after a short interaction timeout for the button click processing
await loginButton.click({ timeout: 1000 }); // Click and give a short time for processing
// Then check for error or dialog visibility immediately or after a very short dynamic wait for UI update

const headers = response.headers();

// Check for common security headers
expect(headers['x-frame-options'] || headers['x-content-type-options']).toBeDefined();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The assertion expect(headers['x-frame-options'] || headers['x-content-type-options']).toBeDefined(); only checks if either header is defined. Assert the presence of each critical security header individually.

Suggested change
expect(headers['x-frame-options'] || headers['x-content-type-options']).toBeDefined();
// Check for common security headers individually
expect(headers['x-frame-options'], 'X-Frame-Options header should be defined').toBeDefined();
expect(headers['x-content-type-options'], 'X-Content-Type-Options header should be defined').toBeDefined();
// Add other expected security headers here, e.g., Content-Security-Policy, Strict-Transport-Security

const options = dbSelector.first().locator('option');
if (await options.count() > 1) {
await dbSelector.first().selectOption({ index: 1 });
await page.waitForTimeout(1000);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Replace page.waitForTimeout(1000) after database selection with a wait for a specific UI change indicating the selection has been processed.

        await dbSelector.first().selectOption({ index: 1 });
        // await page.waitForTimeout(1000); // Replace with a more specific wait
        await page.waitForLoadState('networkidle', { timeout: 5000 }); // Or wait for a specific element change

const executeButton = page.locator('button:has-text("Execute"), button:has-text("Load"), .load-btn');
if (await executeButton.count() > 0) {
await executeButton.first().click();
await page.waitForTimeout(3000);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Replace page.waitForTimeout(3000) after executing a graph query with a wait for graph nodes to be visible.

Suggested change
await page.waitForTimeout(3000);
await executeButton.first().click();
// await page.waitForTimeout(3000); // Avoid fixed timeout
await page.waitForSelector('.node, .vertex, [data-id]', { timeout: 5000 }); // Wait for nodes to appear

await executeButton.first().click();

// Wait for results
await page.waitForTimeout(2000);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Replace page.waitForTimeout(2000) for query results with a wait for the results table to become visible.

Suggested change
await page.waitForTimeout(2000);
// Wait for results table to be visible and contain rows
const resultsTable = page.locator('.results, .query-results, table').first();
await expect(resultsTable).toBeVisible({ timeout: 10000 });
await expect(resultsTable.locator('tr')).toHaveCount(count => count > 1, { timeout: 5000 });

await themeToggle.click();

// Wait for theme change
await page.waitForTimeout(500);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Replace the fixed page.waitForTimeout(500) after toggling the theme with a wait for a CSS class to be applied to the body.

Suggested change
await page.waitForTimeout(500);
// Wait for theme change by checking a specific attribute or class
// await page.waitForTimeout(500);
await expect(page.locator('body')).toHaveAttribute('data-theme', /dark|light/, { timeout: 2000 }); // Example

@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented Jun 18, 2025

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
-0.22%
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (b997918) 70259 45155 64.27%
Head commit (c03e902) 70259 (+0) 45003 (-152) 64.05% (-0.22%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#2289) 0 0 ∅ (not applicable)

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

robfrank added 4 commits June 20, 2025 10:50
- Introduce e2e-studio module with Playwright configuration, package scripts, and dependencies
- Add comprehensive test suites covering authentication, navigation, UI components, database operations, and API integration
- Implement robust authentication helper for multi-modal login/logout handling
- Provide CI integration via GitHub Actions workflow update for studio E2E tests
- Include documentation: README, module overview, and test results analysis
- Add .gitignore for Node, Playwright, and IDE artifacts
@robfrank robfrank force-pushed the feat/0000-playwright branch from 184d7d6 to c03e902 Compare June 20, 2025 08:51
Comment thread e2e-studio/package.json
@@ -0,0 +1,46 @@
{

Check notice

Code scanning / Meterian

[stability] @playwright/test@1.53.0 is outdated Low

This file introduces @playwright/test@1.53.0 which is outdated
@robfrank robfrank closed this Jun 23, 2025
@robfrank robfrank deleted the feat/0000-playwright branch January 14, 2026 16:07
mergify Bot added a commit that referenced this pull request Mar 13, 2026
… to 2.1.39 [skip ci]

[//]: # (dependabot-start)
⚠️ \*\*Dependabot is rebasing this PR\*\* ⚠️
Rebasing might not happen immediately, so don't worry if this takes some time.
Note: if you make any changes to this PR yourself, they will take precedence over the rebase.
---
[//]: # (dependabot-end)
Bumps [io.swagger.parser.v3:swagger-parser](https://github.com/swagger-api/swagger-parser) from 2.1.38 to 2.1.39.
Release notes

*Sourced from [io.swagger.parser.v3:swagger-parser's releases](https://github.com/swagger-api/swagger-parser/releases).*

> Swagger-parser 2.1.39 released!
> -------------------------------
>
> * chore: bump core version to 2.2.45 ([#2288](https://redirect.github.com/swagger-api/swagger-parser/issues/2288))
> * fix: distinguish between default and example set to null and not set at all [#2050](https://redirect.github.com/swagger-api/swagger-parser/issues/2050) ([#2286](https://redirect.github.com/swagger-api/swagger-parser/issues/2286))
> * chore: upgrade jackson from 2.19.0 to 2.21.1 ([#2285](https://redirect.github.com/swagger-api/swagger-parser/issues/2285))


Commits

* [`50ce9c6`](swagger-api/swagger-parser@50ce9c6) prepare release 2.1.39 ([#2289](https://redirect.github.com/swagger-api/swagger-parser/issues/2289))
* [`89ebc8f`](swagger-api/swagger-parser@89ebc8f) chore: bump core version to 2.2.45 ([#2288](https://redirect.github.com/swagger-api/swagger-parser/issues/2288))
* [`9b591a5`](swagger-api/swagger-parser@9b591a5) fix: distinguish between default and example set to null and not set at all #...
* [`df3b779`](swagger-api/swagger-parser@df3b779) chore: upgrade jackson from 2.19.0 to 2.21.1 ([#2285](https://redirect.github.com/swagger-api/swagger-parser/issues/2285))
* [`1883073`](swagger-api/swagger-parser@1883073) bump snapshot 2.1.39-SNAPSHOT
* See full diff in [compare view](swagger-api/swagger-parser@v2.1.38...v2.1.39)
  
[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility\_score?dependency-name=io.swagger.parser.v3:swagger-parser&package-manager=maven&previous-version=2.1.38&new-version=2.1.39)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
  
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot show  ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants