From 84195988a0b72b222621aadee60605ba1211c530 Mon Sep 17 00:00:00 2001 From: tplevko Date: Fri, 20 Oct 2023 13:41:28 +0200 Subject: [PATCH] chore: add e2e PR hook --- .github/workflows/e2e-tests.yml | 236 ++++++++++++++++++ packages/ui-tests/cypress/e2e/beans.cy.ts | 44 ++-- packages/ui-tests/cypress/e2e/catalog.cy.ts | 19 +- packages/ui-tests/cypress/e2e/designer.cy.ts | 19 ++ packages/ui-tests/cypress/e2e/metadata.cy.ts | 147 +++++++++++ .../cypress/fixtures/flows/CamelRoute.yaml | 4 +- .../cypress/fixtures/flows/MetadataPipe.yaml | 56 +++++ .../ui-tests/cypress/support/cypress.d.ts | 10 + packages/ui-tests/cypress/support/e2e.ts | 1 + .../cypress/support/next-commands/default.ts | 19 +- .../cypress/support/next-commands/design.ts | 14 +- .../cypress/support/next-commands/metadata.ts | 50 ++++ .../support/next-commands/sourceCode.ts | 6 + .../Visualization/Canvas/CanvasSideBar.tsx | 2 +- .../ui/src/providers/catalog.provider.tsx | 4 +- .../ui/src/providers/schemas.provider.tsx | 4 +- 16 files changed, 599 insertions(+), 36 deletions(-) create mode 100644 .github/workflows/e2e-tests.yml create mode 100644 packages/ui-tests/cypress/e2e/metadata.cy.ts create mode 100644 packages/ui-tests/cypress/fixtures/flows/MetadataPipe.yaml create mode 100644 packages/ui-tests/cypress/support/next-commands/metadata.ts diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml new file mode 100644 index 000000000..681ad0ad5 --- /dev/null +++ b/.github/workflows/e2e-tests.yml @@ -0,0 +1,236 @@ +name: 🏗️ E2E Tests (Cypress) + +on: + push: + branches: + - main + pull_request: + types: [ opened, synchronize, reopened ] + +jobs: + install: + runs-on: ubuntu-latest + + container: + image: cypress/browsers:node-18.16.0-chrome-112.0.5615.121-1-ff-112.0.1-edge-112.0.1722.48-1 + options: --user 1001 + + steps: + - name: 👷‍♀️ Checkout + uses: actions/checkout@v4 + + - uses: actions/cache@v3 + with: + path: | + **/node_modules + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - uses: actions/cache@v3 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17' + + # Install dependencies + - run: yarn install --immutable + + # Build packages excluding @kaoto-next/camel-catalog since it was build during installing dependencies + - name: Build packages + run: yarn workspaces foreach --verbose --topological-dev --exclude @kaoto-next/camel-catalog run build + + # Build lib + - name: Build @kaoto-next/ui package in lib mode + run: yarn workspace @kaoto-next/ui run build:lib + + - name: 💾 Save build folder + uses: actions/upload-artifact@v3 + with: + name: ui-dist + if-no-files-found: error + path: packages/ui/dist + + - name: 💾 Save catalog build folder + uses: actions/upload-artifact@v3 + with: + name: catalog-dist + if-no-files-found: error + path: packages/camel-catalog/dist + + test-on-firefox: + needs: install + runs-on: ubuntu-latest + container: + image: cypress/browsers:node-18.16.0-chrome-112.0.5615.121-1-ff-112.0.1-edge-112.0.1722.48-1 + options: --user 1001 + + steps: + - name: 👷‍♀️ Checkout + uses: actions/checkout@v4 + + - uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17' + + - name: 🗄️ Download the UI build folder + uses: actions/download-artifact@v3 + with: + name: ui-dist + path: packages/ui/dist + + - name: 🗄️ Download the catalog build folder + uses: actions/download-artifact@v3 + with: + name: catalog-dist + path: packages/camel-catalog/dist + + - name: 🔨 Cypress run + uses: cypress-io/github-action@v6.5.0 + with: + browser: firefox + # we have already installed all dependencies above + # install: false + start: yarn workspace @kaoto-next/ui run start + working-directory: packages/ui-tests + wait-on: 'http://localhost:5173' + wait-on-timeout: 120 + env: + CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }} + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: 💾 Save videos + if: always() + uses: actions/upload-artifact@v3 + with: + name: videos-firefox + path: packages/ui-tests/cypress/videos + + - name: 💾 Save screenshots + if: always() + uses: actions/upload-artifact@v3 + with: + name: screenshots-firefox + path: packages/ui-tests/cypress/screenshots + + test-on-chrome: + needs: install + runs-on: ubuntu-latest + container: + image: cypress/browsers:node-18.16.0-chrome-112.0.5615.121-1-ff-112.0.1-edge-112.0.1722.48-1 + options: --user 1001 + + steps: + - name: 👷‍♀️ Checkout + uses: actions/checkout@v4 + + - uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17' + + - name: 🗄️ Download the UI build folder + uses: actions/download-artifact@v3 + with: + name: ui-dist + path: packages/ui/dist + + - name: 🗄️ Download the catalog build folder + uses: actions/download-artifact@v3 + with: + name: catalog-dist + path: packages/camel-catalog/dist + + - name: 🔨 Cypress run + uses: cypress-io/github-action@v6.5.0 + with: + browser: chrome + # we have already installed all dependencies above + # install: false + start: yarn workspace @kaoto-next/ui run start + working-directory: packages/ui-tests + wait-on: 'http://localhost:5173' + wait-on-timeout: 120 + env: + CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }} + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: 💾 Save videos + if: always() + uses: actions/upload-artifact@v3 + with: + name: videos-chrome + path: packages/ui-tests/cypress/videos + + - name: 💾 Save screenshots + if: always() + uses: actions/upload-artifact@v3 + with: + name: screenshots-chrome + path: packages/ui-tests/cypress/screenshots + + test-on-edge: + needs: install + runs-on: ubuntu-latest + container: + image: cypress/browsers:node-18.16.0-chrome-112.0.5615.121-1-ff-112.0.1-edge-112.0.1722.48-1 + options: --user 1001 + + steps: + - name: 👷‍♀️ Checkout + uses: actions/checkout@v4 + + - uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17' + + - name: 🗄️ Download the UI build folder + uses: actions/download-artifact@v3 + with: + name: ui-dist + path: packages/ui/dist + + - name: 🗄️ Download the catalog build folder + uses: actions/download-artifact@v3 + with: + name: catalog-dist + path: packages/camel-catalog/dist + + - name: 🔨 Cypress run + uses: cypress-io/github-action@v6.5.0 + with: + browser: edge + # we have already installed all dependencies above + # install: false + start: yarn workspace @kaoto-next/ui run start + working-directory: packages/ui-tests + wait-on: 'http://localhost:5173' + wait-on-timeout: 120 + env: + CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }} + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: 💾 Save videos + if: always() + uses: actions/upload-artifact@v3 + with: + name: videos-edge + path: packages/ui-tests/cypress/videos + + - name: 💾 Save screenshots + if: always() + uses: actions/upload-artifact@v3 + with: + name: screenshots-edge + path: packages/ui-tests/cypress/screenshots diff --git a/packages/ui-tests/cypress/e2e/beans.cy.ts b/packages/ui-tests/cypress/e2e/beans.cy.ts index 1aa790777..3a04f1deb 100644 --- a/packages/ui-tests/cypress/e2e/beans.cy.ts +++ b/packages/ui-tests/cypress/e2e/beans.cy.ts @@ -3,24 +3,31 @@ describe('Test for Bean support', () => { cy.openHomePage(); }); - it('Beans - create a new bean using the bean editor', () => { + it('Beans - create a new bean using bean editor', () => { cy.uploadFixture('flows/CamelRoute.yaml'); cy.openBeans(); cy.get('[data-testid="metadata-add-Beans-btn"]').eq(0).click(); - cy.get(`input[name="name"]`).type('test'); - cy.get(`input[name="type"]`).type('org.acme'); + cy.get(`input[name="name"]`).clear().type('test'); + cy.get(`input[name="type"]`).clear().type('org.acme'); - cy.get('[data-testid="expandable-section-properties"]').within(() => { - cy.get('.pf-v5-c-expandable-section__toggle').click(); - }); + cy.openSourceCode(); + cy.checkCodeSpanLine('- beans:'); + cy.checkCodeSpanLine('- name: test'); + cy.checkCodeSpanLine('type: org.acme'); + + cy.openBeans(); + cy.forceSelectMetadataRow(0); + cy.expandWrappedSection('properties'); cy.get('[data-testid="properties-add-string-property--btn"]').not(':hidden').first().click({ force: true }); - cy.get('[data-testid="properties--placeholder-name-input"]').click(); + cy.get('[data-testid="properties--placeholder-name-input"]').should('not.be.disabled'); + cy.get('[data-testid="properties--placeholder-name-input"]').click({ force: true }); cy.get('[data-testid="properties--placeholder-name-input"]').clear().type('test'); - cy.get('[data-testid="properties--placeholder-value-input"]').click(); + cy.get('[data-testid="properties--placeholder-value-input"]').should('not.be.disabled'); + cy.get('[data-testid="properties--placeholder-value-input"]').click({ force: true }); cy.get('[data-testid="properties--placeholder-value-input"]').clear().type('value'); - cy.get('[data-testid="properties--placeholder-property-edit-confirm--btn"]').click(); + cy.get('[data-testid="properties--placeholder-property-edit-confirm--btn"]').click({ force: true }); cy.openSourceCode(); // CHECK the bean was created in the code editor @@ -42,10 +49,7 @@ describe('Test for Bean support', () => { cy.get('@row').find('td').eq(1).should('contain', 'org.acme'); cy.get('@row').click(); - cy.get('[data-testid="expandable-section-properties"]').within(() => { - cy.get('.pf-v5-c-expandable-section__toggle').click(); - }); - + cy.expandWrappedSection('properties'); cy.get('[data-testid="properties-property-name-label"]').should('exist'); cy.get('[data-testid="properties-property-value-label"]').should('exist'); @@ -73,9 +77,7 @@ describe('Test for Bean support', () => { cy.openBeans(); cy.get('[data-testid="metadata-row-0"]').click(); - cy.get('[data-testid="expandable-section-properties"]').within(() => { - cy.get('.pf-v5-c-expandable-section__toggle').click(); - }); + cy.expandWrappedSection('properties'); cy.get('[data-testid="properties-property-name-label"]').should('exist'); cy.get('[data-testid="properties-property-value-label"]').should('exist'); cy.get('[data-testid="properties-property-delete-property-btn"]').click(); @@ -93,9 +95,17 @@ describe('Test for Bean support', () => { cy.get('[data-testid="metadata-delete-1-btn"]').click(); cy.get('[data-testid="metadata-row-1"]').should('not.exist'); - // CHECK the bean was deleted in the code editor + // CHECK the first bean was deleted in the code editor cy.openSourceCode(); cy.checkCodeSpanLine('- name: test2', 0); cy.checkCodeSpanLine('value: value', 0); + // blocked ATM by - https://github.com/KaotoIO/kaoto-next/issues/245 + // cy.openBeans(); + // cy.get('[data-testid="metadata-delete-0-btn"]').click(); + // cy.get('[data-testid="metadata-row-0"]').should('not.exist'); + // // CHECK the second bean was deleted in the code editor + // cy.openSourceCode(); + // cy.checkCodeSpanLine('- name: test', 0); + // cy.checkCodeSpanLine('type: org.acme', 0); }); }); diff --git a/packages/ui-tests/cypress/e2e/catalog.cy.ts b/packages/ui-tests/cypress/e2e/catalog.cy.ts index bdccdcb2c..b0902fb2b 100644 --- a/packages/ui-tests/cypress/e2e/catalog.cy.ts +++ b/packages/ui-tests/cypress/e2e/catalog.cy.ts @@ -5,25 +5,25 @@ describe('Catalog related tests', () => { it('Catalog search', () => { cy.openCatalog(); - cy.get('[data-testid="Component-catalog-tab"]').click(); + cy.get('[data-testid="component-catalog-tab"]').click(); cy.get('.pf-v5-c-text-input-group__text-input').click(); cy.get('.pf-v5-c-text-input-group__text-input').type('timer'); cy.get('div[id="timer"]').should('be.visible'); cy.get('button[aria-label="Reset"]').click(); - cy.get('[data-testid="Processor-catalog-tab"]').click(); + cy.get('[data-testid="model-catalog-tab"]').click(); cy.get('.pf-v5-c-text-input-group__text-input').type('choice'); cy.get('div[id="choice"]').should('be.visible'); cy.get('button[aria-label="Reset"]').click(); - cy.get('[data-testid="Kamelet-catalog-tab"]').click(); + cy.get('[data-testid="kamelet-catalog-tab"]').click(); cy.get('.pf-v5-c-text-input-group__text-input').type('google'); cy.get('div[id="google-storage-source"]').should('be.visible'); }); it('Catalog filtering usign tags', () => { cy.openCatalog(); - cy.get('[data-testid="Component-catalog-tab"]').click(); + cy.get('[data-testid="component-catalog-tab"]').click(); cy.get('[data-testid="tag-cloud"]').first().click(); cy.get('[data-testid="tag-database"]').first().click(); cy.get('[data-testid="tag-serverless"]').first().click(); @@ -39,14 +39,13 @@ describe('Catalog related tests', () => { it('Catalog list view switch check', () => { cy.openCatalog(); cy.get('#toggle-layout-button-List').click(); - cy.get('[data-testid="Kamelet-catalog-tab"]').click(); + cy.get('[data-testid="kamelet-catalog-tab"]').click(); + cy.get('#toggle-layout-button-Gallery').should('have.attr', 'aria-pressed', 'false'); + cy.openSourceCode(); + cy.openCatalog(); cy.get('#toggle-layout-button-Gallery').should('have.attr', 'aria-pressed', 'false'); - // This does not work ATM - relates to https://github.com/KaotoIO/kaoto-next/issues/184 - // cy.openSourceCode(); - // cy.openCatalog(); - // cy.get('#toggle-layout-button-Gallery').should('have.attr', 'aria-pressed', 'false'); cy.get('#toggle-layout-button-Gallery').click(); - cy.get('[data-testid="Component-catalog-tab"]').click(); + cy.get('[data-testid="component-catalog-tab"]').click(); cy.get('#toggle-layout-button-Gallery').should('have.attr', 'aria-pressed', 'true'); }); }); diff --git a/packages/ui-tests/cypress/e2e/designer.cy.ts b/packages/ui-tests/cypress/e2e/designer.cy.ts index 5dcd9ec7c..d75d01e82 100644 --- a/packages/ui-tests/cypress/e2e/designer.cy.ts +++ b/packages/ui-tests/cypress/e2e/designer.cy.ts @@ -30,4 +30,23 @@ describe('Tests for Design page', () => { cy.checkCodeSpanLine('user: user'); cy.checkCodeSpanLine('password: password'); }); + + it('Design - remove steps from CamelRoute', () => { + cy.uploadFixture('flows/CamelRoute.yaml'); + cy.openDesignPage(); + cy.removeElementByName('setHeader'); + cy.removeElementByName('log:test'); + cy.removeElementByName('timer:test'); + cy.openSourceCode(); + cy.checkCodeSpanLine('uri: timer:test', 0); + cy.checkCodeSpanLine('setHeader', 0); + cy.checkCodeSpanLine('constant: test', 0); + cy.checkCodeSpanLine('name: test', 0); + cy.checkCodeSpanLine('uri: log:test', 0); + }); + + // Blocked by - https://github.com/KaotoIO/kaoto-next/issues/253 + // it('Design - remove steps from Pipe/KB', () => { + // cy.uploadFixture('flows/TimerKafkaKB.yaml'); + // }); }); diff --git a/packages/ui-tests/cypress/e2e/metadata.cy.ts b/packages/ui-tests/cypress/e2e/metadata.cy.ts new file mode 100644 index 000000000..32e59350d --- /dev/null +++ b/packages/ui-tests/cypress/e2e/metadata.cy.ts @@ -0,0 +1,147 @@ +describe('Test for Metadata Editor support', () => { + beforeEach(() => { + cy.openHomePage(); + }); + + it('Metadata Editor - edit metadata using metadata editor', () => { + cy.uploadFixture('flows/KafkaSourceSinkKB.yaml'); + cy.openMetadata(); + + cy.expandWrappedSection('annotations'); + cy.get('[data-testid="properties-add-string-property--btn"]').not(':hidden').first().click({ force: true }); + cy.get('[data-testid="annotations--placeholder-name-input"]').click({ force: true }); + cy.get('[data-testid="annotations--placeholder-name-input"]').clear().type('test-annotations'); + cy.get('[data-testid="annotations--placeholder-value-input"]').click({ force: true }); + cy.get('[data-testid="annotations--placeholder-value-input"]').clear().type('value-annotations'); + cy.get('[data-testid="annotations--placeholder-property-edit-confirm--btn"]').click({ force: true }); + cy.closeWrappedSection('annotations'); + cy.expandWrappedSection('labels'); + cy.get('[data-testid="properties-add-string-property--btn"]').not(':hidden').first().click({ force: true }); + cy.get('[data-testid="labels--placeholder-name-input"]').click({ force: true }); + cy.get('[data-testid="labels--placeholder-name-input"]').clear().type('test-labels'); + cy.get('[data-testid="labels--placeholder-value-input"]').click({ force: true }); + cy.get('[data-testid="labels--placeholder-value-input"]').clear().type('value-labels'); + cy.get('[data-testid="labels--placeholder-property-edit-confirm--btn"]').click({ force: true }); + cy.closeWrappedSection('labels'); + + cy.get(`input[name="creationTimestamp"]`).clear().type('testCreationTimestamp'); + cy.get(`input[name="deletionGracePeriodSeconds"]`).clear().type('1000'); + cy.get(`input[name="deletionTimestamp"]`).clear().type('testDeletionTimestamp'); + cy.get(`input[name="generateName"]`).clear().type('testGenerateName'); + cy.get(`input[name="generation"]`).clear().type('10'); + cy.get(`input[name="name"]`).clear().type('testName'); + cy.get(`input[name="namespace"]`).clear().type('testNamespace'); + cy.get(`input[name="resourceVersion"]`).clear().type('testResourceVersion'); + cy.get(`input[name="selfLink"]`).clear().type('testSelfLink'); + cy.get(`input[name="uid"]`).clear().type('testUid'); + cy.addMetadataField('Finalizers'); + cy.get(`input[name="finalizers.0"]`).clear().type('finalizers-testFinalizer'); + + cy.addMetadataField('Managed fields'); + cy.get(`input[name="managedFields.0.apiVersion"]`).clear().type('managedFields-apiVersion'); + cy.get(`input[name="managedFields.0.fieldsType"]`).clear().type('managedFields-fieldsType'); + cy.get(`input[name="managedFields.0.manager"]`).clear().type('managedFields-manager'); + cy.get(`input[name="managedFields.0.operation"]`).clear().type('managedFields-operation'); + cy.get(`input[name="managedFields.0.subresource"]`).clear().type('managedFields-subresource'); + cy.get(`input[name="managedFields.0.time"]`).clear().type('managedFields-time'); + + cy.addMetadataField('Owner references'); + cy.get(`input[name="ownerReferences.0.apiVersion"]`).clear().type('ownerReferences-apiVersion'); + cy.get(`input[name="ownerReferences.0.blockOwnerDeletion"]`).check(); + cy.get(`input[name="ownerReferences.0.controller"]`).check(); + cy.get(`input[name="ownerReferences.0.kind"]`).clear().type('ownerReferences-kind'); + cy.get(`input[name="ownerReferences.0.name"]`).clear().type('ownerReferences-name'); + cy.get(`input[name="ownerReferences.0.uid"]`).clear().type('ownerReferences-uid'); + cy.openSourceCode(); + cy.editorScrollToTop(); + + cy.checkCodeSpanLine('annotations:'); + cy.checkCodeSpanLine('test-annotations: value-annotations'); + cy.checkCodeSpanLine('labels:'); + cy.checkCodeSpanLine('test-labels: value-labels'); + cy.checkCodeSpanLine('name: testName'); + cy.checkCodeSpanLine('creationTimestamp: testCreationTimestamp'); + cy.checkCodeSpanLine('deletionTimestamp: testDeletionTimestamp'); + cy.checkCodeSpanLine('generateName: testGenerateName'); + cy.checkCodeSpanLine('generation: 10'); + cy.checkCodeSpanLine('deletionGracePeriodSeconds: 1000'); + cy.checkCodeSpanLine('namespace: testNamespace'); + cy.checkCodeSpanLine('resourceVersion: testResourceVersion'); + cy.checkCodeSpanLine('selfLink: testSelfLink'); + cy.checkCodeSpanLine('uid: testUid'); + + cy.checkCodeSpanLine('finalizers:'); + cy.checkCodeSpanLine('- finalizers-testFinalizer'); + cy.checkCodeSpanLine('managedFields:'); + cy.checkCodeSpanLine('- apiVersion: managedFields-apiVersion'); + cy.checkCodeSpanLine('fieldsType: managedFields-fieldsType'); + cy.checkCodeSpanLine('manager: managedFields-manager'); + cy.checkCodeSpanLine('operation: managedFields-operation'); + cy.checkCodeSpanLine('subresource: managedFields-subresource'); + cy.checkCodeSpanLine('time: managedFields-time'); + cy.checkCodeSpanLine('ownerReferences:'); + cy.checkCodeSpanLine('- apiVersion: ownerReferences-apiVersion'); + cy.checkCodeSpanLine('kind: ownerReferences-kind'); + cy.checkCodeSpanLine('name: ownerReferences-name'); + cy.checkCodeSpanLine('uid: ownerReferences-uid'); + cy.checkCodeSpanLine('blockOwnerDeletion: true'); + cy.checkCodeSpanLine('controller: true'); + }); + + it('Metadata Editor - create a new bean using editor and edit in bean editor', () => { + cy.openSourceCode(); + cy.uploadFixture('flows/MetadataPipe.yaml'); + cy.openMetadata(); + + cy.get(`input[name="creationTimestamp"]`).clear().type('updatedCreationTimestamp'); + cy.get(`input[name="deletionGracePeriodSeconds"]`).clear().type('2000'); + cy.get(`input[name="deletionTimestamp"]`).clear().type('updatedDeletionTimestamp'); + cy.get(`input[name="generateName"]`).clear().type('updatedGenerateName'); + cy.get(`input[name="generation"]`).clear().type('20'); + cy.get(`input[name="name"]`).clear().type('updatedName'); + cy.get(`input[name="namespace"]`).clear().type('updatedNamespace'); + cy.get(`input[name="resourceVersion"]`).clear().type('updatedResourceVersion'); + cy.get(`input[name="selfLink"]`).clear().type('updatedSelfLink'); + cy.get(`input[name="uid"]`).clear().type('updatedUid'); + + cy.openSourceCode(); + cy.editorScrollToTop(); + // CHECK the bean update was reflected in the code editor + cy.checkCodeSpanLine('name: updatedName'); + cy.checkCodeSpanLine('creationTimestamp: updatedCreationTimestamp'); + cy.checkCodeSpanLine('deletionTimestamp: updatedDeletionTimestamp'); + cy.checkCodeSpanLine('generateName: updatedGenerateName'); + cy.checkCodeSpanLine('generation: 20'); + cy.checkCodeSpanLine('deletionGracePeriodSeconds: 2000'); + cy.checkCodeSpanLine('namespace: updatedNamespace'); + cy.checkCodeSpanLine('resourceVersion: updatedResourceVersion'); + cy.checkCodeSpanLine('selfLink: updatedSelfLink'); + cy.checkCodeSpanLine('uid: updatedUid'); + }); + + it('Metadata Editor - delete bean properties using the bean editor', () => { + cy.openSourceCode(); + cy.uploadFixture('flows/MetadataPipe.yaml'); + cy.openMetadata(); + + cy.expandWrappedSection('annotations'); + cy.get('[data-testid="annotations-annotation-name-name-label"]').should('exist'); + cy.get('[data-testid="annotations-annotation-name-value-label"]').should('exist'); + cy.get('[data-testid="annotations-annotation-name-delete-annotation-name-btn"]').click(); + cy.closeWrappedSection('labels'); + + cy.expandWrappedSection('labels'); + cy.get('[data-testid="labels-label-name-name-label"]').should('exist'); + cy.get('[data-testid="labels-label-name-value-label"]').should('exist'); + cy.get('[data-testid="labels-label-name-delete-label-name-btn"]').click(); + cy.closeWrappedSection('labels'); + + // CHECK the bean was edited in the code editor + cy.openSourceCode(); + cy.editorScrollToTop(); + cy.checkCodeSpanLine('test-annotations: value-annotations', 0); + cy.checkCodeSpanLine('test-labels: label-value', 0); + cy.checkCodeSpanLine('annotations: {}'); + cy.checkCodeSpanLine('labels: {}'); + }); +}); diff --git a/packages/ui-tests/cypress/fixtures/flows/CamelRoute.yaml b/packages/ui-tests/cypress/fixtures/flows/CamelRoute.yaml index 66006854a..81a344915 100644 --- a/packages/ui-tests/cypress/fixtures/flows/CamelRoute.yaml +++ b/packages/ui-tests/cypress/fixtures/flows/CamelRoute.yaml @@ -1,9 +1,9 @@ - route: - id: camel route 1 + id: Camel Route from: uri: timer:test steps: - - set-header: + - setHeader: constant: test name: test - to: diff --git a/packages/ui-tests/cypress/fixtures/flows/MetadataPipe.yaml b/packages/ui-tests/cypress/fixtures/flows/MetadataPipe.yaml new file mode 100644 index 000000000..0ad648536 --- /dev/null +++ b/packages/ui-tests/cypress/fixtures/flows/MetadataPipe.yaml @@ -0,0 +1,56 @@ +apiVersion: camel.apache.org/v1 +kind: Pipe +metadata: + name: webhook-binding + annotations: + annotation-name: annotation-value + labels: + label-name: label-value + namespace: testNamespace + resourceVersion: 1.0.0-SNAPSHOT + selfLink: testLink + uid: testUid + finalizers: + - finalizers-testFinalizer + managedFields: + - apiVersion: managedFields-apiVersion + fieldsType: managedFields-fieldsType + manager: managedFields-manager + operation: managedFields-operation + subresource: managedFields-subresource + time: managedFields-time + ownerReferences: + - apiVersion: ownerReferences-apiVersion + kind: ownerReferences-kind + name: ownerReferences-name + uid: ownerReferences-uid + blockOwnerDeletion: true + controller: true + plural: kameletbindings + scope: Namespaced + served: true + singular: kameletbinding + creationTimestamp: testCreationTimestamp + deletionGracePeriodSeconds: 1000 + deletionTimestamp: testDeletionTimestamp + generateName: testGenerateName + generation: 10 +spec: + source: + ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: webhook-source + steps: + - ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: delay-action + sink: + ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: log-sink + + + diff --git a/packages/ui-tests/cypress/support/cypress.d.ts b/packages/ui-tests/cypress/support/cypress.d.ts index 944875418..7f5fb095b 100644 --- a/packages/ui-tests/cypress/support/cypress.d.ts +++ b/packages/ui-tests/cypress/support/cypress.d.ts @@ -13,6 +13,8 @@ declare global { openDesignPage(): Chainable>; openSourceCode(): Chainable>; openBeans(): Chainable>; + openMetadata(): Chainable>; + openPipeErrorHandler(): Chainable>; openCatalog(): Chainable>; // design openStepConfigurationTab(step: string, stepIndex: number | undefined): Chainable>; @@ -20,7 +22,15 @@ declare global { interactWithConfigInputObject(inputName: string, value: string): Chainable>; fitToScreen(): Chainable>; closeStepConfigurationTab(): Chainable>; + removeElementByName(inputName: string): Chainable>; + // metadata + expandWrappedSection(sectionName: string): Chainable>; + closeWrappedSection(sectionName: string): Chainable>; + switchWrappedSection(sectionName: string, wrapped: boolean): Chainable>; + forceSelectMetadataRow(rowIndex: number): Chainable>; + addMetadataField(fieldName: string): Chainable>; // sourceCode + editorScrollToTop(): Chainable>; editorAddText(line: number, text: string): Chainable>; uploadFixture(fixture: string): Chainable>; editorDeleteLine(line: number, repeatCount: number): Chainable>; diff --git a/packages/ui-tests/cypress/support/e2e.ts b/packages/ui-tests/cypress/support/e2e.ts index 28f34efd6..ab7af9a4d 100644 --- a/packages/ui-tests/cypress/support/e2e.ts +++ b/packages/ui-tests/cypress/support/e2e.ts @@ -17,6 +17,7 @@ import './next-commands/default'; import './next-commands/sourceCode'; import './next-commands/design'; +import './next-commands/metadata'; Cypress.on('uncaught:exception', (_err, _runnable) => { // returning false here prevents Cypress from diff --git a/packages/ui-tests/cypress/support/next-commands/default.ts b/packages/ui-tests/cypress/support/next-commands/default.ts index 5afb8db64..a4d963250 100644 --- a/packages/ui-tests/cypress/support/next-commands/default.ts +++ b/packages/ui-tests/cypress/support/next-commands/default.ts @@ -1,6 +1,13 @@ Cypress.Commands.add('openHomePage', () => { const url = Cypress.config().baseUrl; cy.visit(url!); + // Wait for the loading schemas to disappear + cy.get('[data-testid="loading-schemas"]').should('be.visible'); + cy.get('[data-testid="loading-schemas"]').should('not.exist'); + // Wait for the loading connectors to disappear + cy.get('[data-testid="loading-catalogs"]').should('be.visible'); + cy.get('[data-testid="loading-catalogs"]').should('not.exist'); + cy.get('[data-kind="graph"]').should('exist'); // Wait for the element to become visible cy.get('[data-kind="graph"]').should('be.visible'); @@ -32,7 +39,17 @@ Cypress.Commands.add('openBeans', () => { cy.get('.metadata-editor-modal-details-view').should('be.visible'); }); +Cypress.Commands.add('openMetadata', () => { + cy.get('[data-testid="Metadata"]').click(); + cy.get('[data-testid="metadata-editor-form-Metadata"]').should('be.visible'); +}); + +Cypress.Commands.add('openPipeErrorHandler', () => { + cy.get('[data-testid="Pipe ErrorHandler"]').click(); + cy.get('[data-testid="metadata-editor-form-ErrorHandler"]').should('be.visible'); +}); + Cypress.Commands.add('openCatalog', () => { cy.get('[data-testid="Catalog"]').click(); - cy.get('[data-testid="Component-catalog-tab"]').should('be.visible'); + cy.get('[data-testid="component-catalog-tab"]').should('be.visible'); }); diff --git a/packages/ui-tests/cypress/support/next-commands/design.ts b/packages/ui-tests/cypress/support/next-commands/design.ts index 655650eac..d96fb952c 100644 --- a/packages/ui-tests/cypress/support/next-commands/design.ts +++ b/packages/ui-tests/cypress/support/next-commands/design.ts @@ -8,9 +8,7 @@ Cypress.Commands.add('openStepConfigurationTab', (step, stepIndex) => { }); Cypress.Commands.add('closeStepConfigurationTab', () => { - cy.get('.pf-topology-side-bar').within(() => { - cy.get('.pf-v5-c-card__title-text > .pf-v5-c-button').click(); - }); + cy.get('[data-testid="close-side-bar"]').click(); cy.get('.pf-topology-side-bar').should('be.hidden'); }); @@ -21,3 +19,13 @@ Cypress.Commands.add('interactWithConfigInputObject', (inputName, value) => { cy.get(`input[name="${inputName}"]`).click(); } }); + +Cypress.Commands.add('removeElementByName', (inputName: string) => { + cy.get('g.pf-topology__node__label') + .contains('text', inputName) + .parent() + .find('g.pf-topology__node__action-icon > rect') + .click({ force: true }); + cy.get('.pf-v5-c-dropdown__menu-item').click(); + cy.contains(inputName).should('not.exist'); +}); diff --git a/packages/ui-tests/cypress/support/next-commands/metadata.ts b/packages/ui-tests/cypress/support/next-commands/metadata.ts new file mode 100644 index 000000000..5b1d85f4a --- /dev/null +++ b/packages/ui-tests/cypress/support/next-commands/metadata.ts @@ -0,0 +1,50 @@ +import 'cypress-file-upload'; + +Cypress.Commands.add('expandWrappedSection', (sectionName: string) => { + cy.switchWrappedSection(sectionName, false); +}); + +Cypress.Commands.add('closeWrappedSection', (sectionName: string) => { + cy.switchWrappedSection(sectionName, true); +}); + +Cypress.Commands.add('switchWrappedSection', (sectionName: string, wrapped: boolean) => { + cy.get(`[data-testid="expandable-section-${sectionName}"]`).within(() => { + cy.get('.pf-v5-c-expandable-section__toggle').each(($button) => { + if ($button.attr('aria-expanded') === String(wrapped)) { + cy.wrap($button).click(); + cy.wrap($button).should('have.attr', 'aria-expanded', String(!wrapped)); + } + }); + }); +}); + +Cypress.Commands.add('forceSelectMetadataRow', (rowIndex: number) => { + cy.get('input[name="name"]').then(($input) => { + // Check if the input field is disabled + if ($input.is(':disabled')) { + cy.get(`[data-testid="metadata-row-${rowIndex}"]`).click(); + cy.get('input[name="name"]').then(($element) => { + const attributeValue = $element.attr('disabled'); + if (attributeValue !== undefined) { + let retryCount = 0; + if (retryCount < 5) { + retryCount++; + cy.forceSelectMetadataRow(rowIndex); + } else { + return; + } + } + }); + } + }); +}); + +Cypress.Commands.add('addMetadataField', (fieldName: string) => { + cy.contains('label', fieldName) + .parent() + .parent() + .within(() => { + cy.get('[data-testid="list-add-field"]').click(); + }); +}); diff --git a/packages/ui-tests/cypress/support/next-commands/sourceCode.ts b/packages/ui-tests/cypress/support/next-commands/sourceCode.ts index fe71d9639..1bfb0cb44 100644 --- a/packages/ui-tests/cypress/support/next-commands/sourceCode.ts +++ b/packages/ui-tests/cypress/support/next-commands/sourceCode.ts @@ -43,3 +43,9 @@ Cypress.Commands.add('checkCodeSpanLine', (spanText, linesCount) => { cy.get('span:only-child').contains(spanText).should('have.length', linesCount); }); }); + +Cypress.Commands.add('editorScrollToTop', () => { + cy.get('.pf-v5-c-code-editor').click().type('{pageUp}{pageUp}{pageUp}{pageUp}', { + delay: 1, + }); +}); diff --git a/packages/ui/src/components/Visualization/Canvas/CanvasSideBar.tsx b/packages/ui/src/components/Visualization/Canvas/CanvasSideBar.tsx index 008e20206..96314e3d5 100644 --- a/packages/ui/src/components/Visualization/Canvas/CanvasSideBar.tsx +++ b/packages/ui/src/components/Visualization/Canvas/CanvasSideBar.tsx @@ -33,7 +33,7 @@ export const CanvasSideBar: FunctionComponent = (props) => { {props.selectedNode?.label} -