From 0004dc7ee8718eedcddd3b4054d55eea6a07111a Mon Sep 17 00:00:00 2001 From: OlegIvaniv Date: Thu, 2 Mar 2023 16:50:21 +0100 Subject: [PATCH] ci(editor): Run e2e tests in parallel and improve build caching (#5445) * WIP: Cypress parallel CI run test * Trigger action on branch push * Change build artifacts path * Make sure to checkout the repo for testing job * Use Cypress action for installing * Lock cypress action userd version * Skip node install step since we're using cypress node16 container * Let Cypress handle pnpm install * Use setup-node action for caching pnpm * Set CYPRESS_CACHE_FOLDER * Set CYPRESS_CACHE_FOLDER * Manually cache pnpm store * Dont fix pnpm version * Use caching action also in testing job * Zip packages dist before uploading the artifacts and change caching key * Use absolute build paths for zipping job * Use zip command in action * Use tar for zipping packages * Debuggin directory ls * Debugging caching of modules * Attempt to fix permissions issue * Porivde Cypress executable via `CYPRESS_RUN_BINARY` * Cache /github/home * Adjust caching keys * Debug: search for cypress exec * Debugging: List dirs * Use pnpm install action to install node_modules * Do not log /home/runner * Use node_modules/.bin Cypress binary * Use absolute path to nodue modules * Run Cypress via custom command * Try with patched cypress action * Revert logging * Manually specify cypress config file * Use absolute paths * Fix cypress config name * Debug print cypress config * Remove debugging, increase to 4 containers * Increase amount of containers * Add env-version matrix * Replace node14 with node18 in testing matrix * Remove debugging and add node 14 * Use just node14 * Use cypress:base and remove browser req * Give more general timeouts * Try with node16 * Change cache directive position * Replace zip artifact upload with cache * Cache full packages not just dist * Test with variable inputs * Add commit info message * Remove wrongly commited code * Allow WF API dispatch * Try Chrome browser again for comparison * Include Monaco in the build * Make e2e workflow re-usable * Comment out invalid reusable workflow args * Use electron and add node 14 run * Fix env arg * Provide custom ci-build-id * Refactor remaining e2e workflow to use reusable action * Remove single matrix directive * Refactor ci-pull-req * Make lint job dependant on test jobs * Disable debugging job * Make containers dynamic * Cleanup & install git for linting action * Use regular buntu image for PR linting * Debugging failing tests * Remove fixed spec name * Debug e2e env var * Do not use realkeypress which crashes electron runner * Debugging * chore: remove console * chore: remove console * test: remove node 14 tests * test: replace test branch with master * test: use tests in current branch * test: use relative path * chore: clean up * test: only trigger on approval * ci: update test PR * ci: use curr branch * ci: only run 14 on schedule, not for slack command * ci: only run test on approval * ci: clean up branch, rename step * ci: rename steps * ci: clean up cancel * ci: clean up env var * ci: set var * ci: use chromef * ci: use electron * chore: add console log * chore: add console log * ci: update to string * ci: set all env options * test: build * ci: fix step issue * Fix failing tests & upgrade to Cypress 12 * Allow WF dispatch of e2e reusable * Fix wrong naming in e2e-tests workflow * Redeploy * Fix tests * Fix NDV tests and remove skipping of webhooks execution tests * Fix clipboard read command * Fix execution failing tests * Reset before each 15 and 3 * Fix flaky tests * Cleanup and log envs * Test fixes * Default owner spec fixes * Get rid of CYPRESS_RUN_ENV * Increase amount of containers, cleanup and add mock for credentials test call * Cleanup & fix PR tests unit tests * Wait for WF to loade in sharing spec * Do linting and unit tests first * Use frozen lockfile * Revert back ci pull request jobs order * Refine credential input selector and move cy.waitForLoad to correct position in 15-scheduler spec * test: build * Wait for WF execution instead of arbitraty timeout in WF execution spec, change order of jobs for ci pull request * Fix flaky 3-default owner spec and wait for execution list to load in 20-workflow-executions * Use setup node action * Remove caching for lint/unit tests * Experiment with parallel test & lint on ci * Provide cache key dynamically * Run e2e in parallel on pr * Only run node14 e2e on daily schedule * Make sure to generate generate new ci-build-id on re-runs * Remove debugging prints * Address PR comments * Rename custom onBeforeUnload handler * Make sure 19-execution spec waits for wf to load properly before import fixtures --------- Co-authored-by: Mutasem --- .github/workflows/ci-pull-requests.yml | 105 +++++++++-- .github/workflows/e2e-reusable.yml | 150 ++++++++++++++++ .github/workflows/e2e-tests-pr.yml | 71 +++----- .github/workflows/e2e-tests.yml | 72 ++++---- cypress.config.js | 28 ++- cypress/e2e/10-settings-log-streaming.cy.ts | 15 +- cypress/e2e/11-inline-expression-editor.cy.ts | 2 + .../14-data-transformation-expressions.cy.ts | 14 +- cypress/e2e/14-mapping.cy.ts | 2 +- cypress/e2e/15-scheduler-node.cy.ts | 9 +- cypress/e2e/16-webhook-node.cy.ts | 2 +- cypress/e2e/17-sharing.cy.ts | 1 + cypress/e2e/17-workflow-tags.cy.ts | 5 +- cypress/e2e/19-execution.cy.ts | 56 +++--- cypress/e2e/2-credentials.cy.ts | 11 +- cypress/e2e/20-workflow-executions.cy.ts | 10 +- cypress/e2e/3-default-owner.cy.ts | 18 +- cypress/e2e/4-node-creator.cy.ts | 86 ++++----- cypress/e2e/5-ndv.cy.ts | 16 +- cypress/e2e/7-workflow-actions.cy.ts | 3 + cypress/pages/credentials.ts | 2 +- cypress/pages/modals/credentials-modal.ts | 8 +- cypress/pages/workflow-executions-tab.ts | 3 +- cypress/pages/workflow.ts | 6 +- cypress/pages/workflows.ts | 2 +- cypress/support/commands.ts | 5 +- package.json | 2 +- packages/cli/src/constants.ts | 1 + .../ResourceLocator/ResourceLocator.vue | 5 +- packages/editor-ui/src/views/NodeView.vue | 4 +- pnpm-lock.yaml | 170 +++++++++--------- 31 files changed, 528 insertions(+), 356 deletions(-) create mode 100644 .github/workflows/e2e-reusable.yml diff --git a/.github/workflows/ci-pull-requests.yml b/.github/workflows/ci-pull-requests.yml index 130e1753bd..c567d1baea 100644 --- a/.github/workflows/ci-pull-requests.yml +++ b/.github/workflows/ci-pull-requests.yml @@ -1,27 +1,24 @@ -name: Test Pull Requests +name: Build, unit/smoke test and lint branch on: [pull_request] jobs: - build: + install: + name: Install & Build runs-on: ubuntu-latest - - timeout-minutes: 30 - - strategy: - matrix: - node-version: [14.x, 16.x] - steps: - uses: actions/checkout@v3 + with: + repository: n8n-io/n8n + ref: ${{ inputs.branch }} - uses: pnpm/action-setup@v2.2.4 - - name: Use Node.js ${{ matrix.node-version }} + - name: Use Node.js 16 uses: actions/setup-node@v3 with: - node-version: ${{ matrix.node-version }} - cache: 'pnpm' + node-version: 16.x + cache: pnpm - name: Install dependencies run: pnpm install --frozen-lockfile @@ -29,13 +26,74 @@ jobs: - name: Build run: pnpm build + - name: Cache build artifacts + uses: actions/cache@v3 + with: + path: | + /github/home/.cache + /github/home/.pnpm-store + ./node_modules + ./packages + key: ${{ github.sha }}-base:16.18.1-test-lint + + unit-test: + name: Unit tests + runs-on: ubuntu-latest + needs: install + steps: + - uses: actions/checkout@v3 + with: + repository: n8n-io/n8n + ref: ${{ inputs.branch }} + + - name: Restore cached build artifacts + uses: actions/cache@v3 + with: + path: | + /github/home/.cache + /github/home/.pnpm-store + ./node_modules + ./packages + key: ${{ github.sha }}-base:16.18.1-test-lint + + - uses: pnpm/action-setup@v2.2.4 + + - name: Use Node.js 16 + uses: actions/setup-node@v3 + with: + node-version: 16.x + cache: pnpm + - name: Test run: pnpm test - - name: Test E2E - run: | - pnpm cypress:install - pnpm test:e2e:smoke + lint: + name: Lint changes + runs-on: ubuntu-latest + needs: install + steps: + - uses: actions/checkout@v3 + with: + repository: n8n-io/n8n + ref: ${{ inputs.branch }} + + - name: Restore cached build artifacts + uses: actions/cache@v3 + with: + path: | + /github/home/.cache + /github/home/.pnpm-store + ./node_modules + ./packages + key: ${{ github.sha }}-base:16.18.1-test-lint + + - uses: pnpm/action-setup@v2.2.4 + + - name: Use Node.js 16 + uses: actions/setup-node@v3 + with: + node-version: 16.x + cache: pnpm - name: Fetch base branch for `git diff` run: git fetch origin ${{ github.event.pull_request.base.ref }}:${{ github.event.pull_request.base.ref }} @@ -44,3 +102,18 @@ jobs: env: ESLINT_PLUGIN_DIFF_COMMIT: ${{ github.event.pull_request.base.ref }} run: pnpm lint + + smoke-test: + name: E2E [Electron/Node 16] + uses: ./.github/workflows/e2e-reusable.yml + if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-e2e') }} + with: + branch: ${{ github.event.pull_request.base.ref }} + user: ${{ github.event.inputs.user || 'PR User' }} + spec: ${{ github.event.inputs.spec || 'e2e/0-smoke.cy.ts' }} + run-env: base:16.18.1 + record: false + parallel: false + containers: '[1]' + secrets: + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} diff --git a/.github/workflows/e2e-reusable.yml b/.github/workflows/e2e-reusable.yml new file mode 100644 index 0000000000..c982d84e1f --- /dev/null +++ b/.github/workflows/e2e-reusable.yml @@ -0,0 +1,150 @@ +name: Reusable e2e workflow + +on: + workflow_call: + inputs: + branch: + description: 'GitHub branch to test.' + required: false + type: string + default: 'master' + user: + description: 'User who kicked this off.' + required: false + type: string + default: 'schedule' + spec: + description: 'Specify specs.' + required: false + default: 'e2e/*' + type: string + run-env: + description: 'Node env version to run tests with.' + required: false + default: 'browsers:node16.18.0-chrome90-ff88' + type: string + cache-key: + description: 'Cache key for modules and build artifacts.' + required: false + default: ${{ github.sha }}-${{ inputs.run-env }}-e2e-modules + type: string + record: + description: 'Record test run.' + required: false + default: true + type: boolean + parallel: + description: 'Run tests in parallel.' + required: false + default: true + type: boolean + containers: + description: 'Number of containers to run tests in.' + required: false + default: '[1, 2, 3, 4, 5, 6, 7, 8]' + type: string + secrets: + CYPRESS_RECORD_KEY: + description: 'Cypress record key.' + required: true + +jobs: + # single job that generates and outputs a common id + prepare: + runs-on: ubuntu-latest + outputs: + uuid: ${{ steps.uuid.outputs.value }} + steps: + - name: Generate unique ID 💎 + id: uuid + # take the current commit + timestamp together + # the typical value would be something like + # "sha-5d3fe...35d3-time-1620841214" + run: echo "value=sha-$GITHUB_SHA-time-$(date +"%s")" >> $GITHUB_OUTPUT + + install: + runs-on: ubuntu-latest + needs: ['prepare'] + container: + image: cypress/${{ inputs.run-env }} + options: --user 1001 + steps: + - uses: actions/checkout@v3 + with: + repository: n8n-io/n8n + ref: ${{ inputs.branch }} + + - name: Setup pnpm + uses: pnpm/action-setup@v2.2.4 + with: + run_install: true + + - name: Cache pnpm modules + uses: actions/cache@v3 + with: + path: | + /github/home/.cache + /github/home/.pnpm-store + ./node_modules + ./packages + key: ${{ inputs.cache-key }} + + - name: Cypress build + uses: cypress-io/github-action@v5 + with: + # Disable running of tests within install job + runTests: false + install: false + build: pnpm build + + - name: Cypress install + run: pnpm cypress:install + + testing: + runs-on: ubuntu-latest + container: + image: cypress/${{ inputs.run-env }} + options: --user 1001 + needs: ['prepare', 'install'] + strategy: + fail-fast: false + matrix: + containers: ${{ fromJSON(inputs.containers) }} + steps: + - uses: actions/checkout@v3 + with: + repository: n8n-io/n8n + ref: ${{ inputs.branch }} + + - name: Setup pnpm + uses: pnpm/action-setup@v2.2.4 + + - name: Restore cached pnpm modules + uses: actions/cache@v3 + with: + path: | + /github/home/.cache + /github/home/.pnpm-store + ./node_modules + ./packages + key: ${{ inputs.cache-key }} + + - name: Cypress run + uses: cypress-io/github-action@v5 + with: + install: false + start: pnpm start + wait-on: 'http://localhost:5678' + wait-on-timeout: 120 # + record: ${{ inputs.record }} + parallel: ${{ inputs.parallel }} + # We have to provide custom ci-build-id key to make sure that this workflow could be run multiple times + # in the same parent workflow + ci-build-id: ${{ needs.prepare.outputs.uuid }} + spec: "/__w/n8n/n8n/cypress/${{ inputs.spec }}" + config-file: /__w/n8n/n8n/cypress.config.js + env: + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + E2E_TESTS: true + COMMIT_INFO_MESSAGE: 🌳 ${{ inputs.branch }} 🖥️ ${{ inputs.run-env }} 🤖 ${{ inputs.user }} 🗃️ ${{ inputs.spec }} diff --git a/.github/workflows/e2e-tests-pr.yml b/.github/workflows/e2e-tests-pr.yml index ad21fa7706..e23df4429f 100644 --- a/.github/workflows/e2e-tests-pr.yml +++ b/.github/workflows/e2e-tests-pr.yml @@ -7,53 +7,28 @@ on: - 'master' jobs: - runTests: - name: 'Run E2E tests' - runs-on: ubuntu-latest - if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-e2e') }} + # We disable this for now because cancelling runs makes the Cypress Cloud tests to hang. + # cancel-previous-runs: + # runs-on: ubuntu-latest + # name: 'Cancel previous e2e test runs' + # strategy: + # matrix: + # node-version: [16.x] - timeout-minutes: 30 + # steps: + # - name: 'Cancel previous runs' + # uses: styfle/cancel-workflow-action@0.9.0 + # with: + # access_token: ${{ github.token }} - strategy: - matrix: - node-version: [16.x] - - steps: - - name: 'Cancel previous runs' - uses: styfle/cancel-workflow-action@0.9.0 - with: - access_token: ${{ github.token }} - - - name: 'Cancel if PR is not approved' - if: github.event.review.state != 'approved' - uses: andymckay/cancel-action@0.2 - - - uses: actions/checkout@v3 - - - uses: pnpm/action-setup@v2.2.4 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'pnpm' - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Build - run: pnpm build - - - name: Test E2E - run: | - pnpm cypress:install - pnpm test:e2e:all - - - name: Upload artifacts - uses: actions/upload-artifact@v3 - if: failure() - with: - name: cypress-screenshots - path: | - cypress/screenshots - retention-days: 1 + run-e2e-tests: + name: E2E [Electron/Node 16] + uses: ./.github/workflows/e2e-reusable.yml + if: ${{ github.event.review.state == 'approved' && !contains(github.event.pull_request.labels.*.name, 'skip-e2e') }} + with: + branch: ${{ github.event.pull_request.head.ref }} + user: ${{ github.event.pull_request.user.login || 'PR User' }} + spec: 'e2e/*' + run-env: base:16.18.1 + secrets: + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 232d0f508b..3e9f44eb6e 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -24,54 +24,46 @@ on: default: '' jobs: - build: + calls-start-url: + name: Calls start URL runs-on: ubuntu-latest - - timeout-minutes: 30 - - strategy: - matrix: - node-version: [14.x, 16.x] - + if: ${{ github.event.inputs.start-url != '' }} steps: - - name: Call Start URL - optionally + - name: Calls start URL run: | [[ "${{github.event.inputs.start-url}}" != "" ]] && curl -v -X POST -d 'url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}' ${{github.event.inputs.start-url}} || echo "" shell: bash - - uses: actions/checkout@v3 - with: - repository: ${{ github.event.inputs.repository || 'n8n-io/n8n' }} - ref: ${{ github.event.inputs.branch || 'master' }} + run-e2e-tests: + name: E2E [Electron/Node 16] + uses: ./.github/workflows/e2e-reusable.yml + if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-e2e') }} + with: + branch: ${{ github.event.inputs.branch || 'master' }} + user: ${{ github.event.inputs.user || 'PR User' }} + spec: ${{ github.event.inputs.spec || 'e2e/*' }} + run-env: base:16.18.1 + secrets: + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} - - uses: pnpm/action-setup@v2.2.4 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'pnpm' - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Build - run: pnpm build - - - name: Test E2E - run: | - pnpm cypress:install - pnpm test:e2e:all - - - name: Upload artifacts - uses: actions/upload-artifact@v3 - if: failure() - with: - name: cypress-screenshots - path: | - cypress/screenshots - retention-days: 1 + run-e2e-tests-node-14: + name: E2E [Electron/Node 14] + uses: ./.github/workflows/e2e-reusable.yml + if: ${{ github.event_name == 'schedule' }} + with: + branch: ${{ github.event.inputs.branch || 'master' }} + user: ${{ github.event.inputs.user || 'schedule' }} + spec: ${{ github.event.inputs.spec || 'e2e/*' }} + run-env: base:14.21.1 + secrets: + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} + calls-success-url-notify: + name: Calls success URL and notifies + runs-on: ubuntu-latest + needs: [run-e2e-tests, run-e2e-tests-node-14] + if: ${{ github.event.inputs.success-url != '' }} + steps: - name: Notify Slack on failure uses: act10ns/slack@v2.0.0 if: failure() diff --git a/cypress.config.js b/cypress.config.js index 357875df43..c38bcbc111 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -4,29 +4,39 @@ const { defineConfig } = require('cypress'); const BASE_URL = 'http://localhost:5678'; module.exports = defineConfig({ + projectId: "5hbsdn", retries: { openMode: 0, - runMode: 3, + runMode: 2, }, + defaultCommandTimeout: 10000, + requestTimeout: 12000, e2e: { baseUrl: BASE_URL, - video: false, + video: true, screenshotOnRunFailure: true, - experimentalSessionAndOrigin: true, experimentalInteractiveRunEvents: true, + experimentalSessionAndOrigin: true, setupNodeEvents(on, config) { on('task', { reset: () => fetch(BASE_URL + '/e2e/db/reset', { method: 'POST' }), - 'setup-owner': (payload) => - fetch(BASE_URL + '/e2e/db/setup-owner', { - method: 'POST', - body: JSON.stringify(payload), - headers: { 'Content-Type': 'application/json' }, - }), + 'setup-owner': (payload) => { + try { + return fetch(BASE_URL + '/e2e/db/setup-owner', { + method: 'POST', + body: JSON.stringify(payload), + headers: { 'Content-Type': 'application/json' }, + }) + } catch (error) { + console.error("setup-owner failed with: ", error) + return null + } + }, 'enable-feature': (feature) => fetch(BASE_URL + `/e2e/enable-feature/${feature}`, { method: 'POST' }), }); }, }, }); + diff --git a/cypress/e2e/10-settings-log-streaming.cy.ts b/cypress/e2e/10-settings-log-streaming.cy.ts index 00a08c804b..e67f47045d 100644 --- a/cypress/e2e/10-settings-log-streaming.cy.ts +++ b/cypress/e2e/10-settings-log-streaming.cy.ts @@ -63,11 +63,9 @@ describe('Log Streaming Settings', () => { settingsLogStreamingPage.getters.getSelectDestinationType().click(); settingsLogStreamingPage.getters.getSelectDestinationTypeItems().eq(0).click(); settingsLogStreamingPage.getters.getSelectDestinationButton().click(); - settingsLogStreamingPage.getters - .getDestinationNameInput() - .click() - .clear() - .type('Destination 0'); + settingsLogStreamingPage.getters.getDestinationNameInput().click() + + settingsLogStreamingPage.getters.getDestinationNameInput().find('input').clear().type('Destination 0'); settingsLogStreamingPage.getters.getDestinationSaveButton().click(); cy.wait(100); settingsLogStreamingPage.getters.getDestinationModal().click(1, 1); @@ -88,11 +86,8 @@ describe('Log Streaming Settings', () => { settingsLogStreamingPage.getters.getSelectDestinationType().click(); settingsLogStreamingPage.getters.getSelectDestinationTypeItems().eq(0).click(); settingsLogStreamingPage.getters.getSelectDestinationButton().click(); - settingsLogStreamingPage.getters - .getDestinationNameInput() - .click() - .clear() - .type('Destination 1'); + settingsLogStreamingPage.getters.getDestinationNameInput().click() + settingsLogStreamingPage.getters.getDestinationNameInput().find('input').clear().type('Destination 1'); settingsLogStreamingPage.getters.getDestinationSaveButton().should('not.have.attr', 'disabled'); settingsLogStreamingPage.getters.getDestinationSaveButton().click(); cy.wait(100); diff --git a/cypress/e2e/11-inline-expression-editor.cy.ts b/cypress/e2e/11-inline-expression-editor.cy.ts index 10bc16fde8..de5594a4f4 100644 --- a/cypress/e2e/11-inline-expression-editor.cy.ts +++ b/cypress/e2e/11-inline-expression-editor.cy.ts @@ -17,6 +17,7 @@ describe('Inline expression editor', () => { }); it('should resolve primitive resolvables', () => { + WorkflowPage.getters.inlineExpressionEditorInput().clear(); WorkflowPage.getters.inlineExpressionEditorInput().type('{{'); WorkflowPage.getters.inlineExpressionEditorInput().type('1 + 2'); WorkflowPage.getters.inlineExpressionEditorOutput().contains(/^3$/); @@ -35,6 +36,7 @@ describe('Inline expression editor', () => { }); it('should resolve object resolvables', () => { + WorkflowPage.getters.inlineExpressionEditorInput().clear(); WorkflowPage.getters.inlineExpressionEditorInput().type('{{'); WorkflowPage.getters .inlineExpressionEditorInput() diff --git a/cypress/e2e/14-data-transformation-expressions.cy.ts b/cypress/e2e/14-data-transformation-expressions.cy.ts index 1082765393..161f02fe1f 100644 --- a/cypress/e2e/14-data-transformation-expressions.cy.ts +++ b/cypress/e2e/14-data-transformation-expressions.cy.ts @@ -16,7 +16,7 @@ describe('Data transformation expressions', () => { cy.window() // @ts-ignore .then( - (win) => win.onBeforeUnload && win.removeEventListener('beforeunload', win.onBeforeUnload), + (win) => win.onBeforeUnloadNodeView && win.removeEventListener('beforeunload', win.onBeforeUnloadNodeView), ); }); @@ -80,19 +80,18 @@ describe('Data transformation expressions', () => { ndv.getters.outputDataContainer().contains(output); }); - it('$json + native array methods', () => { + it('$json + native array access', () => { wf.actions.addInitialNodeToCanvas('Schedule Trigger', { keepNdvOpen: true }); ndv.actions.setPinnedData([{ myArr: [1, 2, 3] }]); ndv.actions.close(); addSet(); - - const input = '{{$json.myArr.includes(1) + " " + $json.myArr.at(2)'; + const input = '{{$json.myArr.includes(1) + " " + $json.myArr[2]'; const output = 'true 3'; ndv.getters.inlineExpressionEditorInput().clear().type(input); ndv.actions.execute(); - ndv.getters.outputDataContainer().should('be.visible'); - ndv.getters.outputDataContainer().contains(output); + ndv.getters.outputDataContainer().find('[class*=value_]').should('exist') + ndv.getters.outputDataContainer().find('[class*=value_]').should('contain', output); }); it('$json + n8n array methods', () => { @@ -106,7 +105,8 @@ describe('Data transformation expressions', () => { ndv.getters.inlineExpressionEditorInput().clear().type(input); ndv.actions.execute(); - ndv.getters.outputDataContainer().should('be.visible').contains(output); + ndv.getters.outputDataContainer().find('[class*=value_]').should('exist') + ndv.getters.outputDataContainer().find('[class*=value_]').should('contain', output); }); }); diff --git a/cypress/e2e/14-mapping.cy.ts b/cypress/e2e/14-mapping.cy.ts index c30f2d0521..6b8cd6282a 100644 --- a/cypress/e2e/14-mapping.cy.ts +++ b/cypress/e2e/14-mapping.cy.ts @@ -21,7 +21,7 @@ describe('Data mapping', () => { cy.window() // @ts-ignore .then( - (win) => win.onBeforeUnload && win.removeEventListener('beforeunload', win.onBeforeUnload), + (win) => win.onBeforeUnloadNodeView && win.removeEventListener('beforeunload', win.onBeforeUnloadNodeView), ); }); diff --git a/cypress/e2e/15-scheduler-node.cy.ts b/cypress/e2e/15-scheduler-node.cy.ts index 922972263a..7ba5acec3e 100644 --- a/cypress/e2e/15-scheduler-node.cy.ts +++ b/cypress/e2e/15-scheduler-node.cy.ts @@ -5,15 +5,15 @@ const workflowPage = new WorkflowPage(); const ndv = new NDV(); describe('Schedule Trigger node', async () => { - before(() => { + beforeEach(() => { cy.resetAll(); cy.skipSetup(); + cy.visit(workflowsPage.url); }); it('should execute and return the execution timestamp', () => { - cy.visit(workflowsPage.url); - workflowsPage.actions.createWorkflowFromCard(); + cy.waitForLoad(); workflowPage.actions.addInitialNodeToCanvas('Schedule Trigger'); workflowPage.actions.openNode('Schedule Trigger'); ndv.actions.execute(); @@ -22,9 +22,8 @@ describe('Schedule Trigger node', async () => { }); it('should execute once per second when activated', () => { - cy.visit(workflowsPage.url); - workflowsPage.actions.createWorkflowFromCard(); + cy.waitForLoad(); workflowPage.actions.renameWorkflow('Schedule Trigger Workflow'); workflowPage.actions.addInitialNodeToCanvas('Schedule Trigger'); workflowPage.actions.openNode('Schedule Trigger'); diff --git a/cypress/e2e/16-webhook-node.cy.ts b/cypress/e2e/16-webhook-node.cy.ts index 3ed3c342cf..83c99cb982 100644 --- a/cypress/e2e/16-webhook-node.cy.ts +++ b/cypress/e2e/16-webhook-node.cy.ts @@ -103,7 +103,7 @@ describe('Webhook Trigger node', async () => { cy.window() // @ts-ignore .then( - (win) => win.onBeforeUnload && win.removeEventListener('beforeunload', win.onBeforeUnload), + (win) => win.onBeforeUnloadNodeView && win.removeEventListener('beforeunload', win.onBeforeUnloadNodeView), ); }); diff --git a/cypress/e2e/17-sharing.cy.ts b/cypress/e2e/17-sharing.cy.ts index 9bb11293f4..ff3456f7dc 100644 --- a/cypress/e2e/17-sharing.cy.ts +++ b/cypress/e2e/17-sharing.cy.ts @@ -82,6 +82,7 @@ describe('Sharing', () => { cy.visit(workflowsPage.url); workflowsPage.getters.newWorkflowButtonCard().click(); + cy.waitForLoad(); workflowPage.actions.setWorkflowName('Workflow W1'); workflowPage.actions.addInitialNodeToCanvas('Manual Trigger'); workflowPage.actions.addNodeToCanvas('Notion', true, true); diff --git a/cypress/e2e/17-workflow-tags.cy.ts b/cypress/e2e/17-workflow-tags.cy.ts index 27c3e0b0b5..87926bf0f2 100644 --- a/cypress/e2e/17-workflow-tags.cy.ts +++ b/cypress/e2e/17-workflow-tags.cy.ts @@ -5,12 +5,9 @@ const wf = new WorkflowPage(); const TEST_TAGS = ['Tag 1', 'Tag 2', 'Tag 3']; describe('Workflow tags', () => { - before(() => { + beforeEach(() => { cy.resetAll(); cy.skipSetup(); - }); - - beforeEach(() => { wf.actions.visit(); cy.waitForLoad(); }); diff --git a/cypress/e2e/19-execution.cy.ts b/cypress/e2e/19-execution.cy.ts index 79b60d9dc6..9fcf27d91a 100644 --- a/cypress/e2e/19-execution.cy.ts +++ b/cypress/e2e/19-execution.cy.ts @@ -6,18 +6,15 @@ const workflowPage = new WorkflowPageClass(); const ndv = new NDV(); describe('Execution', () => { - before(() => { + beforeEach(() => { cy.resetAll(); cy.skipSetup(); - }); - - beforeEach(() => { - cy.visit('/'); + // Import workflow + workflowsPage.getters.newWorkflowButtonCard().click(); + cy.waitForLoad(); }); it('should test manual workflow', () => { - // Import workflow - workflowsPage.getters.newWorkflowButtonCard().click(); cy.createFixtureWorkflow('Manual_wait_set.json', `Manual wait set ${uuid()}`); // Check workflow buttons @@ -40,14 +37,14 @@ describe('Execution', () => { workflowPage.getters .canvasNodeByName('Manual') .within(() => cy.get('.fa-check')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Wait') .within(() => cy.get('.fa-check').should('not.exist')); workflowPage.getters .canvasNodeByName('Wait') .within(() => cy.get('.fa-sync-alt')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Set') .within(() => cy.get('.fa-check').should('not.exist')); @@ -58,15 +55,15 @@ describe('Execution', () => { workflowPage.getters .canvasNodeByName('Manual') .within(() => cy.get('.fa-check')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Wait') .within(() => cy.get('.fa-check')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Set') .within(() => cy.get('.fa-check')) - .should('be.visible'); + .should('exist'); // Clear execution data workflowPage.getters.clearExecutionDataButton().should('be.visible'); @@ -78,8 +75,6 @@ describe('Execution', () => { }); it('should test manual workflow stop', () => { - // Import workflow - workflowsPage.getters.newWorkflowButtonCard().click(); cy.createFixtureWorkflow('Manual_wait_set.json', `Manual wait set ${uuid()}`); // Check workflow buttons @@ -102,14 +97,14 @@ describe('Execution', () => { workflowPage.getters .canvasNodeByName('Manual') .within(() => cy.get('.fa-check')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Wait') .within(() => cy.get('.fa-check').should('not.exist')); workflowPage.getters .canvasNodeByName('Wait') .within(() => cy.get('.fa-sync-alt')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Set') .within(() => cy.get('.fa-check').should('not.exist')); @@ -121,11 +116,11 @@ describe('Execution', () => { workflowPage.getters .canvasNodeByName('Manual') .within(() => cy.get('.fa-check')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Wait') .within(() => cy.get('.fa-check')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Wait') .within(() => cy.get('.fa-sync-alt').should('not.visible')); @@ -143,8 +138,6 @@ describe('Execution', () => { }); it('should test webhook workflow', () => { - // Import workflow - workflowsPage.getters.newWorkflowButtonCard().click(); cy.createFixtureWorkflow('Webhook_wait_set.json', `Webhook wait set ${uuid()}`); // Check workflow buttons @@ -184,14 +177,14 @@ describe('Execution', () => { workflowPage.getters .canvasNodeByName('Webhook') .within(() => cy.get('.fa-check')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Wait') .within(() => cy.get('.fa-check').should('not.exist')); workflowPage.getters .canvasNodeByName('Wait') .within(() => cy.get('.fa-sync-alt')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Set') .within(() => cy.get('.fa-check').should('not.exist')); @@ -202,15 +195,15 @@ describe('Execution', () => { workflowPage.getters .canvasNodeByName('Webhook') .within(() => cy.get('.fa-check')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Wait') .within(() => cy.get('.fa-check')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Set') .within(() => cy.get('.fa-check')) - .should('be.visible'); + .should('exist'); // Clear execution data workflowPage.getters.clearExecutionDataButton().should('be.visible'); @@ -222,8 +215,6 @@ describe('Execution', () => { }); it('should test webhook workflow stop', () => { - // Import workflow - workflowsPage.getters.newWorkflowButtonCard().click(); cy.createFixtureWorkflow('Webhook_wait_set.json', `Webhook wait set ${uuid()}`); // Check workflow buttons @@ -259,34 +250,33 @@ describe('Execution', () => { }); }); + workflowPage.getters.stopExecutionButton().click(); // Check canvas nodes after 1st step (workflow passed the manual trigger node workflowPage.getters .canvasNodeByName('Webhook') .within(() => cy.get('.fa-check')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Wait') .within(() => cy.get('.fa-check').should('not.exist')); workflowPage.getters .canvasNodeByName('Wait') .within(() => cy.get('.fa-sync-alt')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Set') .within(() => cy.get('.fa-check').should('not.exist')); - cy.wait(1000); - workflowPage.getters.stopExecutionWaitingForWebhookButton().click(); // Check canvas nodes after workflow stopped workflowPage.getters .canvasNodeByName('Webhook') .within(() => cy.get('.fa-check')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Wait') .within(() => cy.get('.fa-check')) - .should('be.visible'); + .should('exist'); workflowPage.getters .canvasNodeByName('Wait') .within(() => cy.get('.fa-sync-alt').should('not.visible')); diff --git a/cypress/e2e/2-credentials.cy.ts b/cypress/e2e/2-credentials.cy.ts index 82cfa427a3..3fe9dd1968 100644 --- a/cypress/e2e/2-credentials.cy.ts +++ b/cypress/e2e/2-credentials.cy.ts @@ -32,6 +32,14 @@ describe('Credentials', () => { before(() => { cy.resetAll(); cy.setup({ email, firstName, lastName, password }); + + // Always intercept the request to test credentials and return a success + cy.intercept('POST', '/rest/credentials/test', { + statusCode: 200, + body: { + data: { status: 'success', message: 'Tested successfully' }, + } + }); }); beforeEach(() => { @@ -53,7 +61,6 @@ describe('Credentials', () => { credentialsModal.getters.newCredentialTypeOption('Notion API').click(); credentialsModal.getters.newCredentialTypeButton().click(); - credentialsModal.getters.connectionParameter('API Key').type('1234567890'); credentialsModal.actions.setName('My awesome Notion account'); @@ -71,7 +78,7 @@ describe('Credentials', () => { credentialsModal.getters.newCredentialTypeOption('Airtable API').click(); credentialsModal.getters.newCredentialTypeButton().click(); - + credentialsModal.getters.editCredentialModal().should('be.visible'); credentialsModal.getters.connectionParameter('API Key').type('1234567890'); credentialsModal.actions.setName('Airtable Account'); diff --git a/cypress/e2e/20-workflow-executions.cy.ts b/cypress/e2e/20-workflow-executions.cy.ts index b40f26be91..d619659ac3 100644 --- a/cypress/e2e/20-workflow-executions.cy.ts +++ b/cypress/e2e/20-workflow-executions.cy.ts @@ -19,7 +19,13 @@ describe('Current Workflow Executions', () => { }); it('should render executions tab correctly', () => { - cy.waitForLoad(); + cy.intercept('GET', '/rest/executions?filter=*').as('getExecutions'); + cy.intercept('GET', '/rest/executions-current?filter=*').as('getCurrentExecutions'); + + executionsTab.actions.switchToExecutionsTab(); + + cy.wait(['@getExecutions', '@getCurrentExecutions']); + executionsTab.getters.executionListItems().should('have.length', 11); executionsTab.getters.successfulExecutionListItems().should('have.length', 9); executionsTab.getters.failedExecutionListItems().should('have.length', 2); @@ -40,6 +46,4 @@ const createMockExecutions = () => { // Then add some more successful ones executionsTab.actions.toggleNodeEnabled('Error'); executionsTab.actions.createManualExecutions(4); - executionsTab.actions.switchToExecutionsTab(); - cy.waitForLoad(); }; diff --git a/cypress/e2e/3-default-owner.cy.ts b/cypress/e2e/3-default-owner.cy.ts index 0ba2f9f44a..95b83b043f 100644 --- a/cypress/e2e/3-default-owner.cy.ts +++ b/cypress/e2e/3-default-owner.cy.ts @@ -34,26 +34,19 @@ const firstName = randFirstName(); const lastName = randLastName(); describe('Default owner', () => { - before(() => { - cy.resetAll(); - }); - beforeEach(() => { - cy.visit('/'); - }); - - it('should skip owner setup', () => { - cy.skipSetup(); - }); - it('should be able to create workflows', () => { + cy.resetAll(); + cy.skipSetup(); + cy.visit('/'); workflowsPage.getters.newWorkflowButtonCard().should('be.visible'); workflowsPage.getters.newWorkflowButtonCard().click(); + cy.waitForLoad(); cy.createFixtureWorkflow('Test_workflow_1.json', `Test workflow`); // reload page, ensure owner still has access cy.reload(); - + cy.waitForLoad(); workflowPage.getters.workflowNameInput().should('contain.value', 'Test workflow'); }); @@ -82,6 +75,7 @@ describe('Default owner', () => { }); it('should be able to setup UM from settings', () => { + cy.visit('/'); mainSidebar.getters.settings().should('be.visible'); mainSidebar.actions.goToSettings(); cy.url().should('include', settingsUsagePage.url); diff --git a/cypress/e2e/4-node-creator.cy.ts b/cypress/e2e/4-node-creator.cy.ts index 9850ab14c1..a6e986c645 100644 --- a/cypress/e2e/4-node-creator.cy.ts +++ b/cypress/e2e/4-node-creator.cy.ts @@ -1,13 +1,7 @@ import { NodeCreator } from '../pages/features/node-creator'; -import { DEFAULT_USER_EMAIL, DEFAULT_USER_PASSWORD } from '../constants'; -import { randFirstName, randLastName } from '@ngneat/falso'; import { WorkflowPage as WorkflowPageClass } from '../pages/workflow'; import { NDV } from '../pages/ndv'; -const email = DEFAULT_USER_EMAIL; -const password = DEFAULT_USER_PASSWORD; -const firstName = randFirstName(); -const lastName = randLastName(); const nodeCreatorFeature = new NodeCreator(); const WorkflowPage = new WorkflowPageClass(); const NDVModal = new NDV(); @@ -15,12 +9,10 @@ const NDVModal = new NDV(); describe('Node Creator', () => { before(() => { cy.resetAll(); - cy.setup({ email, firstName, lastName, password }); + cy.skipSetup(); }); beforeEach(() => { - cy.signin({ email, password }); - cy.visit(nodeCreatorFeature.url); cy.waitForLoad(); }); @@ -105,58 +97,52 @@ describe('Node Creator', () => { it('should search through actions and confirm added action', () => { nodeCreatorFeature.actions.openNodeCreator(); nodeCreatorFeature.getters.searchBar().find('input').clear().type('ftp'); - nodeCreatorFeature.getters.searchBar().find('input').realPress('{rightarrow}'); + nodeCreatorFeature.getters.searchBar().find('input').type('{rightarrow}'); nodeCreatorFeature.getters.activeSubcategory().should('have.text', 'FTP'); nodeCreatorFeature.getters.searchBar().find('input').clear().type('file'); // Navigate to rename action which should be the 4th item - nodeCreatorFeature.getters.searchBar().find('input').realPress('{downarrow}'); - nodeCreatorFeature.getters.searchBar().find('input').realPress('{downarrow}'); - nodeCreatorFeature.getters.searchBar().find('input').realPress('{downarrow}'); - nodeCreatorFeature.getters.searchBar().find('input').realPress('{rightarrow}'); + nodeCreatorFeature.getters.searchBar().find('input').type('{downarrow} {downarrow} {downarrow} {rightarrow}'); NDVModal.getters.parameterInput('operation').should('contain.text', 'Rename'); }) it('should render and select community node', () => { - cy.intercept('GET', '/types/nodes.json').as('nodesIntercept'); - cy.wait('@nodesIntercept').then(() => { - const customNode = 'E2E Node'; + const customNode = 'E2E Node'; - nodeCreatorFeature.actions.openNodeCreator(); - nodeCreatorFeature.getters.searchBar().find('input').clear().type(customNode); + nodeCreatorFeature.actions.openNodeCreator(); + nodeCreatorFeature.getters.searchBar().find('input').clear().type(customNode); - nodeCreatorFeature.getters - .getCreatorItem(customNode) - .findChildByTestId('node-creator-item-tooltip') - .should('exist'); - nodeCreatorFeature.actions.selectNode(customNode); + nodeCreatorFeature.getters + .getCreatorItem(customNode) + .findChildByTestId('node-creator-item-tooltip') + .should('exist'); + nodeCreatorFeature.actions.selectNode(customNode); - // TODO: Replace once we have canvas feature utils - cy.get('.data-display .node-name').contains(customNode).should('exist'); + // TODO: Replace once we have canvas feature utils + cy.get('.data-display .node-name').contains(customNode).should('exist'); - const nodeParameters = () => cy.getByTestId('node-parameters'); - const firstParameter = () => nodeParameters().find('.parameter-item').eq(0); - const secondParameter = () => nodeParameters().find('.parameter-item').eq(1); + const nodeParameters = () => cy.getByTestId('node-parameters'); + const firstParameter = () => nodeParameters().find('.parameter-item').eq(0); + const secondParameter = () => nodeParameters().find('.parameter-item').eq(1); - // Check correct fields are rendered - nodeParameters().should('exist'); - // Test property text input - firstParameter().contains('Test property').should('exist'); - firstParameter().find('input.el-input__inner').should('have.value', 'Some default'); - // Resource select input - secondParameter().find('label').contains('Resource').should('exist'); - secondParameter().find('input.el-input__inner').should('have.value', 'option2'); - secondParameter().find('.el-select').click(); - secondParameter().find('.el-select-dropdown__list').should('exist'); - // Check if all options are rendered and select the fourth one - secondParameter().find('.el-select-dropdown__list').children().should('have.length', 4); - secondParameter() - .find('.el-select-dropdown__list') - .children() - .eq(3) - .contains('option4') - .should('exist') - .click(); - secondParameter().find('input.el-input__inner').should('have.value', 'option4'); - }); + // Check correct fields are rendered + nodeParameters().should('exist'); + // Test property text input + firstParameter().contains('Test property').should('exist'); + firstParameter().find('input.el-input__inner').should('have.value', 'Some default'); + // Resource select input + secondParameter().find('label').contains('Resource').should('exist'); + secondParameter().find('input.el-input__inner').should('have.value', 'option2'); + secondParameter().find('.el-select').click(); + secondParameter().find('.el-select-dropdown__list').should('exist'); + // Check if all options are rendered and select the fourth one + secondParameter().find('.el-select-dropdown__list').children().should('have.length', 4); + secondParameter() + .find('.el-select-dropdown__list') + .children() + .eq(3) + .contains('option4') + .should('exist') + .click(); + secondParameter().find('input.el-input__inner').should('have.value', 'option4'); }); }); diff --git a/cypress/e2e/5-ndv.cy.ts b/cypress/e2e/5-ndv.cy.ts index 9025725e55..3a57d51bcf 100644 --- a/cypress/e2e/5-ndv.cy.ts +++ b/cypress/e2e/5-ndv.cy.ts @@ -1,22 +1,19 @@ -import { WorkflowsPage, WorkflowPage, NDV } from '../pages'; +import { WorkflowPage, NDV } from '../pages'; import { v4 as uuid } from 'uuid'; -const workflowsPage = new WorkflowsPage(); const workflowPage = new WorkflowPage(); const ndv = new NDV(); describe('NDV', () => { - before(() => { - cy.resetAll(); - cy.skipSetup(); - }); beforeEach(() => { - workflowsPage.actions.createWorkflowFromCard(); + cy.resetAll(); + cy.skipSetup(); + cy.visit(workflowPage.url) + cy.waitForLoad(); workflowPage.actions.renameWorkflow(uuid()); workflowPage.actions.saveWorkflowOnButtonClick(); }); - it('should show up when double clicked on a node and close when Back to canvas clicked', () => { workflowPage.actions.addInitialNodeToCanvas('Manual'); workflowPage.getters.canvasNodes().first().dblclick(); @@ -52,11 +49,12 @@ describe('NDV', () => { workflowPage.getters.canvasNodes().last().dblclick(); ndv.getters.inputSelect().click(); ndv.getters.inputOption().last().click(); + ndv.getters.inputDataContainer().find('[class*=schema_]').should('exist') ndv.getters.inputDataContainer().should('contain', 'start'); }); it('should show correct validation state for resource locator params', () => { - workflowPage.actions.addNodeToCanvas('Typeform', true, false); + workflowPage.actions.addNodeToCanvas('Typeform', true, true); ndv.getters.container().should('be.visible'); cy.get('.has-issues').should('have.length', 0); cy.get('[class*=hasIssues]').should('have.length', 0); diff --git a/cypress/e2e/7-workflow-actions.cy.ts b/cypress/e2e/7-workflow-actions.cy.ts index 4742bb3cbc..8896953c3b 100644 --- a/cypress/e2e/7-workflow-actions.cy.ts +++ b/cypress/e2e/7-workflow-actions.cy.ts @@ -112,6 +112,9 @@ describe('Workflow Actions', () => { }); it('should update workflow settings', () => { + cy.resetAll(); + cy.skipSetup(); + WorkflowPage.actions.visit(); // Open settings dialog WorkflowPage.actions.saveWorkflowOnButtonClick(); WorkflowPage.getters.workflowMenu().should('be.visible'); diff --git a/cypress/pages/credentials.ts b/cypress/pages/credentials.ts index 47f8cdcc9a..7d3bf7ac98 100644 --- a/cypress/pages/credentials.ts +++ b/cypress/pages/credentials.ts @@ -5,7 +5,7 @@ export class CredentialsPage extends BasePage { getters = { emptyListCreateCredentialButton: () => cy.getByTestId('empty-resources-list').find('button'), createCredentialButton: () => cy.getByTestId('resources-list-add'), - searchInput: () => cy.getByTestId('resources-list-search'), + searchInput: () => cy.getByTestId('resources-list-search').find('input'), emptyList: () => cy.getByTestId('resources-list-empty'), credentialCards: () => cy.getByTestId('resources-list-item'), credentialCard: (credentialName: string) => diff --git a/cypress/pages/modals/credentials-modal.ts b/cypress/pages/modals/credentials-modal.ts index 02b267bf9f..2f5fd298aa 100644 --- a/cypress/pages/modals/credentials-modal.ts +++ b/cypress/pages/modals/credentials-modal.ts @@ -12,9 +12,7 @@ export class CredentialsModal extends BasePage { connectionParameter: (fieldName: string) => this.getters .connectionParameters() - .contains(fieldName) - .parents('[data-test-id="credential-connection-parameter"]') - .find('.n8n-input input'), + .find(`:contains('${fieldName}') .n8n-input input`), name: () => cy.getByTestId('credential-name'), nameInput: () => cy.getByTestId('credential-name').find('input'), // Saving of the credentials takes a while on the CI so we need to increase the timeout @@ -45,10 +43,6 @@ export class CredentialsModal extends BasePage { }, save: (test = false) => { cy.intercept('POST', '/rest/credentials').as('saveCredential'); - if (test) { - cy.intercept('POST', '/rest/credentials/test').as('testCredential'); - } - this.getters.saveButton().click(); cy.wait('@saveCredential'); diff --git a/cypress/pages/workflow-executions-tab.ts b/cypress/pages/workflow-executions-tab.ts index ea6c8b4fd5..4e641ae69a 100644 --- a/cypress/pages/workflow-executions-tab.ts +++ b/cypress/pages/workflow-executions-tab.ts @@ -26,8 +26,9 @@ export class WorkflowExecutionsTab extends BasePage { }, createManualExecutions: (count: number) => { for (let i=0; i { diff --git a/cypress/pages/workflow.ts b/cypress/pages/workflow.ts index 2094726db8..f5167e01cb 100644 --- a/cypress/pages/workflow.ts +++ b/cypress/pages/workflow.ts @@ -44,7 +44,7 @@ export class WorkflowPage extends BasePage { firstStepButton: () => cy.getByTestId('canvas-add-button'), isWorkflowSaved: () => this.getters.saveButton().should('match', 'span'), // In Element UI, disabled button turn into spans 🤷‍♂️ isWorkflowActivated: () => this.getters.activatorSwitch().should('have.class', 'is-checked'), - expressionModalInput: () => cy.getByTestId('expression-modal-input'), + expressionModalInput: () => cy.getByTestId('expression-modal-input').find('[role=textbox]'), expressionModalOutput: () => cy.getByTestId('expression-modal-output'), nodeViewRoot: () => cy.getByTestId('node-view-root'), @@ -84,7 +84,7 @@ export class WorkflowPage extends BasePage { duplicateWorkflowModal: () => cy.getByTestId('duplicate-modal'), nodeViewBackground: () => cy.getByTestId('node-view-background'), nodeView: () => cy.getByTestId('node-view'), - inlineExpressionEditorInput: () => cy.getByTestId('inline-expression-editor-input'), + inlineExpressionEditorInput: () => cy.getByTestId('inline-expression-editor-input').find('[role=textbox]'), inlineExpressionEditorOutput: () => cy.getByTestId('inline-expression-editor-output'), zoomInButton: () => cy.getByTestId('zoom-in-button'), zoomOutButton: () => cy.getByTestId('zoom-out-button'), @@ -181,8 +181,10 @@ export class WorkflowPage extends BasePage { this.getters.workflowNameInput().clear().type(name).type('{enter}'); }, activateWorkflow: () => { + cy.intercept('PATCH', '/rest/workflows/*').as('activateWorkflow'); this.getters.activatorSwitch().find('input').first().should('be.enabled'); this.getters.activatorSwitch().click(); + cy.wait('@activateWorkflow'); cy.get('body').type('{esc}'); }, renameWorkflow: (newName: string) => { diff --git a/cypress/pages/workflows.ts b/cypress/pages/workflows.ts index de2a38a101..4a30b92ecb 100644 --- a/cypress/pages/workflows.ts +++ b/cypress/pages/workflows.ts @@ -5,7 +5,7 @@ export class WorkflowsPage extends BasePage { getters = { newWorkflowButtonCard: () => cy.getByTestId('new-workflow-card'), newWorkflowTemplateCard: () => cy.getByTestId('new-workflow-template-card'), - searchBar: () => cy.getByTestId('resources-list-search'), + searchBar: () => cy.getByTestId('resources-list-search').find('input'), createWorkflowButton: () => cy.getByTestId('resources-list-add'), workflowCards: () => cy.getByTestId('resources-list-item'), workflowCard: (workflowName: string) => diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 445645975c..2497b3abec 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -206,9 +206,8 @@ Cypress.Commands.add('grantBrowserPermissions', (...permissions: string[]) => { ); } }); -Cypress.Commands.add('readClipboard', () => - cy.window().its('navigator.clipboard').invoke('readText'), -); + +Cypress.Commands.add('readClipboard', () => cy.window().then(win => win.navigator.clipboard.readText())) Cypress.Commands.add('paste', { prevSubject: true }, (selector, pastePayload) => { // https://developer.mozilla.org/en-US/docs/Web/API/Element/paste_event diff --git a/package.json b/package.json index 0ad9b44fa7..5f272f06c4 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@types/jest": "^29.2.2", "@types/supertest": "^2.0.12", "cross-env": "^7.0.3", - "cypress": "^10.0.3", + "cypress": "^12.7.0", "cypress-real-events": "^1.7.6", "jest": "^29.4.2", "jest-environment-jsdom": "^29.4.2", diff --git a/packages/cli/src/constants.ts b/packages/cli/src/constants.ts index 0a50fe9081..bcca817b40 100644 --- a/packages/cli/src/constants.ts +++ b/packages/cli/src/constants.ts @@ -12,6 +12,7 @@ export const inProduction = NODE_ENV === 'production'; export const inDevelopment = !NODE_ENV || NODE_ENV === 'development'; export const inTest = NODE_ENV === 'test'; export const inE2ETests = E2E_TESTS === 'true'; + export const CUSTOM_API_CALL_NAME = 'Custom API Call'; export const CUSTOM_API_CALL_KEY = '__CUSTOM_API_CALL__'; diff --git a/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue b/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue index 1d892ca04f..0669617f9e 100644 --- a/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue +++ b/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue @@ -447,7 +447,10 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({ }, methods: { setWidth() { - this.width = (this.$refs.container as HTMLElement).offsetWidth; + const containerRef = this.$refs.container as HTMLElement; + if (containerRef) { + this.width = containerRef?.offsetWidth; + } }, getLinkAlt(entity: string) { if (this.selectedMode === 'list' && entity) { diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index f8b8dbb359..eb3c2ea626 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -2594,7 +2594,7 @@ export default mixins( // allow to be overriden in e2e tests // @ts-ignore - window.onBeforeUnload = (e) => { + window.onBeforeUnloadNodeView = (e) => { if (this.isDemo) { return; } else if (this.uiStore.stateIsDirty) { @@ -2608,7 +2608,7 @@ export default mixins( return; } }; - window.addEventListener('beforeunload', window.onBeforeUnload); + window.addEventListener('beforeunload', window.onBeforeUnloadNodeView); }, getOutputEndpointUUID(nodeName: string, index: number): string | null { const node = this.workflowsStore.getNodeByName(nodeName); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6375d3ca6d..770e2251b4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,7 +34,7 @@ importers: '@types/jest': ^29.2.2 '@types/supertest': ^2.0.12 cross-env: ^7.0.3 - cypress: ^10.0.3 + cypress: ^12.7.0 cypress-real-events: ^1.7.6 jest: ^29.4.2 jest-environment-jsdom: ^29.4.2 @@ -60,12 +60,12 @@ importers: '@types/jest': 29.2.2 '@types/supertest': 2.0.12 cross-env: 7.0.3 - cypress: 10.11.0 - cypress-real-events: 1.7.6_cypress@10.11.0 + cypress: 12.7.0 + cypress-real-events: 1.7.6_cypress@12.7.0 jest: 29.4.2 jest-environment-jsdom: 29.4.2 jest-mock: 29.4.2 - jest-mock-extended: 3.0.1_47mstovy2thvxzoe7ouhdvjexm + jest-mock-extended: 3.0.1_gelezmms3va3pnkofxaadhcvma nock: 13.2.9 node-fetch: 2.6.7 p-limit: 3.1.0 @@ -74,8 +74,8 @@ importers: run-script-os: 1.1.6 start-server-and-test: 1.14.0 supertest: 6.3.3 - ts-jest: 29.0.5_pa4ebk5usulsg7iw3zwjv5figy - tsc-watch: 6.0.0_typescript@4.9.4 + ts-jest: 29.0.5_zgilbyuumz7xbrerspmrtjuxsi + tsc-watch: 6.0.0_typescript@4.9.5 turbo: 1.7.4 packages/@n8n_io/eslint-config: @@ -95,9 +95,9 @@ importers: eslint-plugin-vue: ~7.17 devDependencies: '@types/eslint': 8.4.6 - '@typescript-eslint/eslint-plugin': 5.45.0_wke4plxjew2ogjxrdwvzd2srfq - '@typescript-eslint/parser': 5.45.0_wy4udjehnvkneqnogzx5kughki - '@vue/eslint-config-typescript': 8.0.0_foaxzhaputljbcoeiwudem25oq + '@typescript-eslint/eslint-plugin': 5.45.0_nasf2kpz3oxiofoztaiw65ixem + '@typescript-eslint/parser': 5.45.0_pku7h6lsbnh7tcsfjudlqd5qce + '@vue/eslint-config-typescript': 8.0.0_tzuopv2z7r6hmaghrrdryxy3qq eslint: 8.28.0 eslint-config-airbnb-typescript: 17.0.0_twozqnrpw2n42bn4rzkw5rgv4m eslint-config-prettier: 8.5.0_eslint@8.28.0 @@ -337,7 +337,7 @@ importers: sse-channel: 4.0.0 swagger-ui-express: 4.5.0_express@4.18.2 syslog-client: 1.1.1 - typedi: 0.10.0 + typedi: 0.10.0_syy565ld7euwcedfbmx53j2qc4 typeorm: 0.3.12_pgelcv6ef3switkrteavpif3pq uuid: 8.3.2 validator: 13.7.0 @@ -391,7 +391,7 @@ importers: mock-jwks: 1.0.9_nock@13.2.9 nodemon: 2.0.20 run-script-os: 1.1.6 - ts-essentials: 7.0.3_typescript@4.9.4 + ts-essentials: 7.0.3_typescript@4.9.5 tsc-alias: 1.8.2 tsconfig-paths: 4.1.2 @@ -520,7 +520,7 @@ importers: '@storybook/addon-links': 7.0.0-beta.46_6l5554ty5ajsajah6yazvrjhoe '@storybook/addon-postcss': 3.0.0-alpha.1_webpack@5.75.0 '@storybook/vue': 7.0.0-beta.46_wp7tvu3eu4pbkovl2pyk3t6dzu - '@storybook/vue-webpack5': 7.0.0-beta.46_kqbjeyqrxfaciuxblodnlqbkgm + '@storybook/vue-webpack5': 7.0.0-beta.46_6qmhhfx7j6nt5tk6ratxcrskc4 '@testing-library/jest-dom': 5.16.5 '@testing-library/vue': 5.8.3_rhqkolmkwunxzlyyxxsuwaiuri '@types/markdown-it': 12.2.3 @@ -545,7 +545,7 @@ importers: vue-loader: 15.10.1_eo5mtzohqv75mh6aooqyrh42dy vue-property-decorator: 9.1.2_jtyyyychrtcflhl7vfprhmeb3y vue-template-compiler: 2.7.14 - vue-tsc: 1.0.24_typescript@4.9.4 + vue-tsc: 1.0.24_typescript@4.9.5 packages/editor-ui: specifiers: @@ -664,7 +664,7 @@ importers: n8n-design-system: link:../design-system n8n-workflow: link:../workflow normalize-wheel: 1.0.1 - pinia: 2.0.23_vj744rb3neneiaeb3oalctaenu + pinia: 2.0.23_hwpzsh6pnvsm3pjf2zi526hnzq prettier: 2.8.3 prismjs: 1.29.0 stream-browserify: 3.0.0 @@ -710,7 +710,7 @@ importers: vite: 4.0.4_sass@1.55.0+terser@5.16.1 vite-plugin-monaco-editor: 1.1.0_monaco-editor@0.33.0 vitest: 0.28.4_sass@1.55.0+terser@5.16.1 - vue-tsc: 1.0.24_typescript@4.9.4 + vue-tsc: 1.0.24_typescript@4.9.5 packages/node-dev: specifiers: @@ -1082,7 +1082,7 @@ importers: '@types/tmp': 0.2.3 '@types/uuid': 8.3.4 '@types/xml2js': 0.4.11 - eslint-plugin-n8n-nodes-base: 1.12.0_wy4udjehnvkneqnogzx5kughki + eslint-plugin-n8n-nodes-base: 1.12.0_pku7h6lsbnh7tcsfjudlqd5qce gulp: 4.0.2 n8n-workflow: link:../workflow @@ -3983,7 +3983,7 @@ packages: peerDependencies: pinia: '>=2.0.19' dependencies: - pinia: 2.0.23_vj744rb3neneiaeb3oalctaenu + pinia: 2.0.23_hwpzsh6pnvsm3pjf2zi526hnzq vue-demi: 0.13.11_vue@2.7.14 transitivePeerDependencies: - '@vue/composition-api' @@ -4557,7 +4557,7 @@ packages: - supports-color dev: true - /@storybook/builder-webpack5/7.0.0-beta.46_vsjsuvw2laeoxumlaes6yduxsu: + /@storybook/builder-webpack5/7.0.0-beta.46_lyfnfac7rmzfleuimsdvcn3dv4: resolution: {integrity: sha512-1pvo9IDlz836hiDFmALVttQxw4ehSd3UEhE6Yz0B+TMl4cAQuSRWze8w2sI474tiHtGeKGRoIIWmH5hSVQvFrQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4595,7 +4595,7 @@ packages: case-sensitive-paths-webpack-plugin: 2.4.0 css-loader: 6.7.3_webpack@5.75.0 express: 4.18.2 - fork-ts-checker-webpack-plugin: 6.5.2_oidmngyddw6azfqg3taanyywde + fork-ts-checker-webpack-plugin: 6.5.2_3vu26w62dupooczhvlkrwvyfsa fs-extra: 11.1.0 html-webpack-plugin: 5.5.0_webpack@5.75.0 path-browserify: 1.0.1 @@ -4607,7 +4607,7 @@ packages: style-loader: 3.3.1_webpack@5.75.0 terser-webpack-plugin: 5.3.6_htvmhiqynazf46fjrszipnqp7a ts-dedent: 2.2.0 - typescript: 4.9.4 + typescript: 4.9.5 util: 0.12.5 util-deprecate: 1.0.2 webpack: 5.75.0_esbuild@0.16.17 @@ -5012,7 +5012,7 @@ packages: resolution: {integrity: sha512-tQ6hv57SPVxyOYPQzhlrhkuKs3Nk4Efa1DN9bzYg5jEzXbeZ9uK4jmV9TDQdWv0QeAvK81SD1YNI2OtzbLPVgA==} dev: true - /@storybook/preset-vue-webpack/7.0.0-beta.46_saukmnhi62725vq7wtdfif6krm: + /@storybook/preset-vue-webpack/7.0.0-beta.46_hp247ej5z4ok6lxqqu3v2d7xta: resolution: {integrity: sha512-X40UKuFlXV5lQuVrdP4jBEkPwf+9whXqJwNnBMlQICU/SEwC5oE2sqi7cFU5sZ8DBVzqDunxCE0rfYETeliyyw==} engines: {node: '>=16.0.0'} peerDependencies: @@ -5029,7 +5029,7 @@ packages: '@types/node': 16.18.12 babel-loader: 9.1.2_la66t7xldg4uecmyawueag5wkm css-loader: 6.7.3_webpack@5.75.0 - ts-loader: 9.4.2_3fkjkrd3audxnith3e7fo4fnxi + ts-loader: 9.4.2_hhrrucqyg4eysmfpujvov2ym5u vue: 2.7.14 vue-docgen-api: 4.56.4_vue@2.7.14 vue-docgen-loader: 1.5.1_yl6fzifju7igosbqtgzpjuylxi @@ -5177,7 +5177,7 @@ packages: - supports-color dev: true - /@storybook/vue-webpack5/7.0.0-beta.46_kqbjeyqrxfaciuxblodnlqbkgm: + /@storybook/vue-webpack5/7.0.0-beta.46_6qmhhfx7j6nt5tk6ratxcrskc4: resolution: {integrity: sha512-PJJo/NGiWL1raOfHpJTb3X6LmLAC2TgI3EV2nDlkPigxj29O+zeMkyvfDky7eWpgOIbVqqtNVUYGH1GwbL7jqw==} engines: {node: '>=16.0.0'} peerDependencies: @@ -5191,9 +5191,9 @@ packages: vue-template-compiler: ^2.6.8 dependencies: '@babel/core': 7.20.12 - '@storybook/builder-webpack5': 7.0.0-beta.46_vsjsuvw2laeoxumlaes6yduxsu + '@storybook/builder-webpack5': 7.0.0-beta.46_lyfnfac7rmzfleuimsdvcn3dv4 '@storybook/core-common': 7.0.0-beta.46 - '@storybook/preset-vue-webpack': 7.0.0-beta.46_saukmnhi62725vq7wtdfif6krm + '@storybook/preset-vue-webpack': 7.0.0-beta.46_hp247ej5z4ok6lxqqu3v2d7xta '@storybook/vue': 7.0.0-beta.46_wp7tvu3eu4pbkovl2pyk3t6dzu '@types/node': 16.18.12 babel-loader: 9.1.2_la66t7xldg4uecmyawueag5wkm @@ -6391,7 +6391,7 @@ packages: dev: true optional: true - /@typescript-eslint/eslint-plugin/5.45.0_wke4plxjew2ogjxrdwvzd2srfq: + /@typescript-eslint/eslint-plugin/5.45.0_nasf2kpz3oxiofoztaiw65ixem: resolution: {integrity: sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -6402,23 +6402,23 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.45.0_wy4udjehnvkneqnogzx5kughki + '@typescript-eslint/parser': 5.45.0_pku7h6lsbnh7tcsfjudlqd5qce '@typescript-eslint/scope-manager': 5.45.0 - '@typescript-eslint/type-utils': 5.45.0_wy4udjehnvkneqnogzx5kughki - '@typescript-eslint/utils': 5.45.0_wy4udjehnvkneqnogzx5kughki + '@typescript-eslint/type-utils': 5.45.0_pku7h6lsbnh7tcsfjudlqd5qce + '@typescript-eslint/utils': 5.45.0_pku7h6lsbnh7tcsfjudlqd5qce debug: 4.3.4 eslint: 8.28.0 ignore: 5.2.0 natural-compare-lite: 1.4.0 regexpp: 3.2.0 semver: 7.3.8 - tsutils: 3.21.0_typescript@4.9.4 - typescript: 4.9.4 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser/5.45.0_wy4udjehnvkneqnogzx5kughki: + /@typescript-eslint/parser/5.45.0_pku7h6lsbnh7tcsfjudlqd5qce: resolution: {integrity: sha512-brvs/WSM4fKUmF5Ot/gEve6qYiCMjm6w4HkHPfS6ZNmxTS0m0iNN4yOChImaCkqc1hRwFGqUyanMXuGal6oyyQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -6430,10 +6430,10 @@ packages: dependencies: '@typescript-eslint/scope-manager': 5.45.0 '@typescript-eslint/types': 5.45.0 - '@typescript-eslint/typescript-estree': 5.45.0_typescript@4.9.4 + '@typescript-eslint/typescript-estree': 5.45.0_typescript@4.9.5 debug: 4.3.4 eslint: 8.28.0 - typescript: 4.9.4 + typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true @@ -6446,7 +6446,7 @@ packages: '@typescript-eslint/visitor-keys': 5.45.0 dev: true - /@typescript-eslint/type-utils/5.45.0_wy4udjehnvkneqnogzx5kughki: + /@typescript-eslint/type-utils/5.45.0_pku7h6lsbnh7tcsfjudlqd5qce: resolution: {integrity: sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -6456,12 +6456,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.45.0_typescript@4.9.4 - '@typescript-eslint/utils': 5.45.0_wy4udjehnvkneqnogzx5kughki + '@typescript-eslint/typescript-estree': 5.45.0_typescript@4.9.5 + '@typescript-eslint/utils': 5.45.0_pku7h6lsbnh7tcsfjudlqd5qce debug: 4.3.4 eslint: 8.28.0 - tsutils: 3.21.0_typescript@4.9.4 - typescript: 4.9.4 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true @@ -6471,7 +6471,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree/5.45.0_typescript@4.9.4: + /@typescript-eslint/typescript-estree/5.45.0_typescript@4.9.5: resolution: {integrity: sha512-maRhLGSzqUpFcZgXxg1qc/+H0bT36lHK4APhp0AEUVrpSwXiRAomm/JGjSG+kNUio5kAa3uekCYu/47cnGn5EQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -6486,13 +6486,13 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.3.8 - tsutils: 3.21.0_typescript@4.9.4 - typescript: 4.9.4 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils/5.45.0_wy4udjehnvkneqnogzx5kughki: + /@typescript-eslint/utils/5.45.0_pku7h6lsbnh7tcsfjudlqd5qce: resolution: {integrity: sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -6502,7 +6502,7 @@ packages: '@types/semver': 7.3.13 '@typescript-eslint/scope-manager': 5.45.0 '@typescript-eslint/types': 5.45.0 - '@typescript-eslint/typescript-estree': 5.45.0_typescript@4.9.4 + '@typescript-eslint/typescript-estree': 5.45.0_typescript@4.9.5 eslint: 8.28.0 eslint-scope: 5.1.1 eslint-utils: 3.0.0_eslint@8.28.0 @@ -6735,7 +6735,7 @@ packages: /@vue/devtools-api/6.4.5: resolution: {integrity: sha512-JD5fcdIuFxU4fQyXUu3w2KpAJHzTVdN+p4iOX2lMWSHMOoQdMAcpFLZzm9Z/2nmsoZ1a96QEhZ26e50xLBsgOQ==} - /@vue/eslint-config-typescript/8.0.0_foaxzhaputljbcoeiwudem25oq: + /@vue/eslint-config-typescript/8.0.0_tzuopv2z7r6hmaghrrdryxy3qq: resolution: {integrity: sha512-8u8Qpg4qfjJoNeRMdHlxif9BcGy4iYSSK4YYW5AFPPRtkBJiCqtoyT72l4F3ZeZII09ax2N6yQeHbQ0CXQi1bA==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -6748,11 +6748,11 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 5.45.0_wke4plxjew2ogjxrdwvzd2srfq - '@typescript-eslint/parser': 5.45.0_wy4udjehnvkneqnogzx5kughki + '@typescript-eslint/eslint-plugin': 5.45.0_nasf2kpz3oxiofoztaiw65ixem + '@typescript-eslint/parser': 5.45.0_pku7h6lsbnh7tcsfjudlqd5qce eslint: 8.28.0 eslint-plugin-vue: 7.17.0_eslint@8.28.0 - typescript: 4.9.4 + typescript: 4.9.5 vue-eslint-parser: 7.11.0_eslint@8.28.0 transitivePeerDependencies: - supports-color @@ -9436,17 +9436,17 @@ packages: nub: 0.0.0 dev: false - /cypress-real-events/1.7.6_cypress@10.11.0: + /cypress-real-events/1.7.6_cypress@12.7.0: resolution: {integrity: sha512-yP6GnRrbm6HK5q4DH6Nnupz37nOfZu/xn1xFYqsE2o4G73giPWQOdu6375QYpwfU1cvHNCgyD2bQ2hPH9D7NMw==} peerDependencies: cypress: ^4.x || ^5.x || ^6.x || ^7.x || ^8.x || ^9.x || ^10.x || ^11.x || ^12.x dependencies: - cypress: 10.11.0 + cypress: 12.7.0 dev: true - /cypress/10.11.0: - resolution: {integrity: sha512-lsaE7dprw5DoXM00skni6W5ElVVLGAdRUUdZjX2dYsGjbY/QnpzWZ95Zom1mkGg0hAaO/QVTZoFVS7Jgr/GUPA==} - engines: {node: '>=12.0.0'} + /cypress/12.7.0: + resolution: {integrity: sha512-7rq+nmhzz0u6yabCFyPtADU2OOrYt6pvUau9qV7xyifJ/hnsaw/vkr0tnLlcuuQKUAOC1v1M1e4Z0zG7S0IAvA==} + engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} hasBin: true dependencies: '@cypress/request': 2.88.10 @@ -10488,8 +10488,8 @@ packages: eslint: ^7.32.0 || ^8.2.0 eslint-plugin-import: ^2.25.3 dependencies: - '@typescript-eslint/eslint-plugin': 5.45.0_wke4plxjew2ogjxrdwvzd2srfq - '@typescript-eslint/parser': 5.45.0_wy4udjehnvkneqnogzx5kughki + '@typescript-eslint/eslint-plugin': 5.45.0_nasf2kpz3oxiofoztaiw65ixem + '@typescript-eslint/parser': 5.45.0_pku7h6lsbnh7tcsfjudlqd5qce eslint: 8.28.0 eslint-config-airbnb-base: 15.0.0_ktrec6dplf4now6nlbc6d67jee eslint-plugin-import: 2.26.0_xmouedd5rhgbah4737x2hltudq @@ -10558,7 +10558,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.45.0_wy4udjehnvkneqnogzx5kughki + '@typescript-eslint/parser': 5.45.0_pku7h6lsbnh7tcsfjudlqd5qce debug: 3.2.7 eslint: 8.28.0 eslint-import-resolver-node: 0.3.6 @@ -10586,7 +10586,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.45.0_wy4udjehnvkneqnogzx5kughki + '@typescript-eslint/parser': 5.45.0_pku7h6lsbnh7tcsfjudlqd5qce array-includes: 3.1.5 array.prototype.flat: 1.3.0 debug: 2.6.9 @@ -10611,10 +10611,10 @@ packages: resolution: {integrity: sha512-qe6sVFDP1Vj5eXlqZxYZpIjwYvhuqXlI0P8OfPyhiPOhMkFtr0TpFphD8/6WCzkm7LJCvG1eJEzURCtMIsFTAg==} dev: true - /eslint-plugin-n8n-nodes-base/1.12.0_wy4udjehnvkneqnogzx5kughki: + /eslint-plugin-n8n-nodes-base/1.12.0_pku7h6lsbnh7tcsfjudlqd5qce: resolution: {integrity: sha512-AotXR6IsxLNnxp4OxhD33xcmRFwVq7ZImBd0mTgpirV3VX8pCJDdiDlI2zCAICcICZxtOdbVtHOMhhnMjTh71A==} dependencies: - '@typescript-eslint/utils': 5.45.0_wy4udjehnvkneqnogzx5kughki + '@typescript-eslint/utils': 5.45.0_pku7h6lsbnh7tcsfjudlqd5qce camel-case: 4.1.2 indefinite: 2.4.1 pascal-case: 3.1.2 @@ -11451,7 +11451,7 @@ packages: /forever-agent/0.6.1: resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} - /fork-ts-checker-webpack-plugin/6.5.2_oidmngyddw6azfqg3taanyywde: + /fork-ts-checker-webpack-plugin/6.5.2_3vu26w62dupooczhvlkrwvyfsa: resolution: {integrity: sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==} engines: {node: '>=10', yarn: '>=1.0.0'} peerDependencies: @@ -11478,7 +11478,7 @@ packages: schema-utils: 2.7.0 semver: 7.3.8 tapable: 1.1.3 - typescript: 4.9.4 + typescript: 4.9.5 vue-template-compiler: 2.7.14 webpack: 5.75.0_esbuild@0.16.17 dev: true @@ -13447,15 +13447,15 @@ packages: stack-utils: 2.0.6 dev: true - /jest-mock-extended/3.0.1_47mstovy2thvxzoe7ouhdvjexm: + /jest-mock-extended/3.0.1_gelezmms3va3pnkofxaadhcvma: resolution: {integrity: sha512-RF4Ow8pXvbRuEcCTj56oYHmig5311BSFvbEGxPNYL51wGKGu93MvVQgx0UpFmjqyBXIcElkZo2Rke88kR1iSKQ==} peerDependencies: jest: ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0 typescript: ^3.0.0 || ^4.0.0 dependencies: jest: 29.4.2 - ts-essentials: 7.0.3_typescript@4.9.4 - typescript: 4.9.4 + ts-essentials: 7.0.3_typescript@4.9.5 + typescript: 4.9.5 dev: true /jest-mock/29.4.2: @@ -16509,7 +16509,7 @@ packages: engines: {node: '>=6'} dev: true - /pinia/2.0.23_vj744rb3neneiaeb3oalctaenu: + /pinia/2.0.23_hwpzsh6pnvsm3pjf2zi526hnzq: resolution: {integrity: sha512-N15hFf4o5STrxpNrib1IEb1GOArvPYf1zPvQVRGOO1G1d74Ak0J0lVyalX/SmrzdT4Q0nlEFjbURsmBmIGUR5Q==} peerDependencies: '@vue/composition-api': ^1.4.0 @@ -16522,7 +16522,7 @@ packages: optional: true dependencies: '@vue/devtools-api': 6.4.5 - typescript: 4.9.4 + typescript: 4.9.5 vue: 2.7.14 vue-demi: 0.13.11_vue@2.7.14 @@ -17165,11 +17165,6 @@ packages: resolution: {integrity: sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==} dev: false - /punycode/2.1.1: - resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} - engines: {node: '>=6'} - dev: false - /punycode/2.2.0: resolution: {integrity: sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==} engines: {node: '>=6'} @@ -19643,7 +19638,7 @@ packages: dependencies: ip-regex: 2.1.0 psl: 1.9.0 - punycode: 2.1.1 + punycode: 2.2.0 dev: false /tough-cookie/4.1.2: @@ -19690,19 +19685,19 @@ packages: engines: {node: '>=6.10'} dev: true - /ts-essentials/7.0.3_typescript@4.9.4: + /ts-essentials/7.0.3_typescript@4.9.5: resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==} peerDependencies: typescript: '>=3.7.0' dependencies: - typescript: 4.9.4 + typescript: 4.9.5 dev: true /ts-expect/1.3.0: resolution: {integrity: sha512-e4g0EJtAjk64xgnFPD6kTBUtpnMVzDrMb12N1YZV0VvSlhnVT3SGxiYTLdGy8Q5cYHOIC/FAHmZ10eGrAguicQ==} dev: false - /ts-jest/29.0.5_pa4ebk5usulsg7iw3zwjv5figy: + /ts-jest/29.0.5_zgilbyuumz7xbrerspmrtjuxsi: resolution: {integrity: sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -19732,11 +19727,11 @@ packages: lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.3.8 - typescript: 4.9.4 + typescript: 4.9.5 yargs-parser: 21.1.1 dev: true - /ts-loader/9.4.2_3fkjkrd3audxnith3e7fo4fnxi: + /ts-loader/9.4.2_hhrrucqyg4eysmfpujvov2ym5u: resolution: {integrity: sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==} engines: {node: '>=12.0.0'} peerDependencies: @@ -19747,7 +19742,7 @@ packages: enhanced-resolve: 5.10.0 micromatch: 4.0.5 semver: 7.3.8 - typescript: 4.9.4 + typescript: 4.9.5 webpack: 5.75.0_esbuild@0.16.17 dev: true @@ -19767,7 +19762,7 @@ packages: plimit-lit: 1.4.1 dev: true - /tsc-watch/6.0.0_typescript@4.9.4: + /tsc-watch/6.0.0_typescript@4.9.5: resolution: {integrity: sha512-zgpju+/z5z29/kK5V28Nz16CMkX2voFOUxkTlCim/R25hxzbyUqu2NfTnmJBQfESBSPbEQUGqDdB9A8opAcB4A==} engines: {node: '>=12.12.0'} hasBin: true @@ -19778,7 +19773,7 @@ packages: node-cleanup: 2.1.2 ps-tree: 1.2.0 string-argv: 0.3.1 - typescript: 4.9.4 + typescript: 4.9.5 dev: true /tsconfig-paths/3.14.1: @@ -19816,14 +19811,14 @@ packages: engines: {node: '>=0.6.x'} dev: false - /tsutils/3.21.0_typescript@4.9.4: + /tsutils/3.21.0_typescript@4.9.5: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.9.4 + typescript: 4.9.5 dev: true /tunnel-agent/0.6.0: @@ -19971,9 +19966,10 @@ packages: /typedarray/0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - /typedi/0.10.0: + /typedi/0.10.0_syy565ld7euwcedfbmx53j2qc4: resolution: {integrity: sha512-v3UJF8xm68BBj6AF4oQML3ikrfK2c9EmZUyLOfShpJuItAqVBHWP/KtpGinkSsIiP6EZyyb6Z3NXyW9dgS9X1w==} dev: false + patched: true /typeorm/0.3.12_pgelcv6ef3switkrteavpif3pq: resolution: {integrity: sha512-sYSxBmCf1nJLLTcYtwqZ+lQIRtLPyUoO93rHTOKk9vJCyT4UfRtU7oRsJvfvKP3nnZTD1hzz2SEy2zwPEN6OyA==} @@ -20058,8 +20054,8 @@ packages: - supports-color dev: false - /typescript/4.9.4: - resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==} + /typescript/4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} engines: {node: '>=4.2.0'} hasBin: true @@ -21112,7 +21108,7 @@ packages: resolution: {integrity: sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==} dev: true - /vue-tsc/1.0.24_typescript@4.9.4: + /vue-tsc/1.0.24_typescript@4.9.5: resolution: {integrity: sha512-mmU1s5SAqE1nByQAiQnao9oU4vX+mSdsgI8H57SfKH6UVzq/jP9+Dbi2GaV+0b4Cn361d2ln8m6xeU60ApiEXg==} hasBin: true peerDependencies: @@ -21120,7 +21116,7 @@ packages: dependencies: '@volar/vue-language-core': 1.0.24 '@volar/vue-typescript': 1.0.24 - typescript: 4.9.4 + typescript: 4.9.5 dev: true /vue-typed-mixins/0.2.0: