diff --git a/.deploy/dependencies/e2e/Dockerfile b/.deploy/dependencies/e2e/Dockerfile new file mode 100644 index 00000000000..47d0f814c7e --- /dev/null +++ b/.deploy/dependencies/e2e/Dockerfile @@ -0,0 +1,28 @@ +# DSpot ERP E2E dependencies image + +FROM node:20.11.1-alpine3.19 AS builder + +# Set Python interpreter for `node-gyp` to use +ENV PYTHON=/usr/bin/python + +RUN apk --update add bash \ + && apk add --no-cache build-base postgresql postgresql-contrib \ + && npm i -g npm@9 node-gyp@10.2.0 yarn --force \ + && mkdir /srv/gauzy \ + && chown -R node:node /srv/gauzy \ + && rm -rf /var/cache/apk/* + +USER node:node +WORKDIR /srv/gauzy + +# Copy related project files and configuration files +COPY --chown=node:node . . + +# Install ALL dependencies needed for e2e testing +RUN NODE_ENV=development yarn install \ + --network-timeout 1000000 \ + --frozen-lockfile \ + --ignore-scripts \ + --link-duplicates \ + && NODE_ENV=development yarn postinstall.manual \ + && yarn cache clean diff --git a/.deploy/dependencies/e2e/Dockerfile.dockerignore b/.deploy/dependencies/e2e/Dockerfile.dockerignore new file mode 100644 index 00000000000..18987a2351a --- /dev/null +++ b/.deploy/dependencies/e2e/Dockerfile.dockerignore @@ -0,0 +1,93 @@ +# Docker-related files and directories +docker +**/tmp +**/.dockerignore +docker-compose*.yml + +# Git-related files and directories +.git/ +**/.gitignore +.github +.gitmodules +.gitattributes +.gitpod.yml + +# Cache and other project directories +.angular +.cache +.circle +.circleci +.do +.fly +.husky +.nx +.render +.sonarlint +.verdaccio +.npmrc +.travis.yml +greenkeeper.json +**/*.md +**/*.cmd +**/*.log +Jenkinsfile +.yarn +render.yml +export +tools +.env* +.prettier* +.snyk +.czrc +.* + +# Scripts and deployment entrypoint scripts +!.scripts +.deploy +!.deploy/api/entrypoint.compose.sh +!.deploy/api/entrypoint.prod.sh + +.nvmrc +**/node_modules +**/npm-debug.log + +# IDEs and editors +.idea +.vscode +.project +.classpath +*.launch +*.code-workspace +.settings/ +.editorconfig + +#System Files +**/.DS_Store +**/Thumbs.db + +# Build and compilation output +**/dist +**/build + +# API apps and packages +apps +!apps/api +apps/api/public +!apps/api/public/.gitkeep +!apps/api/public/**/.gitkeep +!apps/api/public/ever-icons +!apps/api/public/features +!apps/api/public/integrations +!apps/api/public/reports +apps/api/report.*.json + +# Gauzy apps and packages +!apps/gauzy +packages +!packages/contracts +!packages/constants +!packages/ui-* +!packages/plugins/*-ui + +# e2e apps and packages +!apps/gauzy-e2e diff --git a/.github/workflows/e2e-dependencies.yml b/.github/workflows/e2e-dependencies.yml new file mode 100644 index 00000000000..046433989a6 --- /dev/null +++ b/.github/workflows/e2e-dependencies.yml @@ -0,0 +1,104 @@ +name: Generate E2E Test Environment Image + +on: + workflow_call: + inputs: + ref: + description: 'The branch, tag or SHA to checkout' + required: false + type: string + default: '' + +jobs: + check-e2e-changes: + name: Check for dependency changes + runs-on: ubuntu-latest + outputs: + changes_detected: ${{ steps.check-e2e-changes.outputs.changes_detected }} + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + with: + ref: ${{ inputs.ref || github.ref }} + fetch-depth: 2 + + - name: Check for changes in dependency files + id: check-e2e-changes + run: | + # For manual triggers or workflow calls, check if files have changed in the last commit + CHANGED_FILES=$(git diff --name-only HEAD^ HEAD) + + # Define patterns for all dependency-related files + # API Dependencies + DEPENDENCY_PATTERN="^package\.json$|^yarn\.lock$|^apps\/api\/package\.json$" + DEPENDENCY_PATTERN="$DEPENDENCY_PATTERN|^packages\/(auth|common|config|contracts|core|plugin|utils)\/.*package\.json$" + DEPENDENCY_PATTERN="$DEPENDENCY_PATTERN|^packages\/plugins\/[a-z\-]+[^u][^i]\/.*package\.json$" + + # WebApp Dependencies + DEPENDENCY_PATTERN="$DEPENDENCY_PATTERN|^apps\/gauzy\/package\.json$" + DEPENDENCY_PATTERN="$DEPENDENCY_PATTERN|^packages\/(contracts|ui-auth|ui-config|ui-core)\/.*package\.json$" + DEPENDENCY_PATTERN="$DEPENDENCY_PATTERN|^packages\/plugins\/[a-z\-]+(-ui)\/.*package\.json$" + + # Infrastructure and E2E specific files + DEPENDENCY_PATTERN="$DEPENDENCY_PATTERN|^\.deploy\/dependencies\/(api|webapp|e2e)\/|^docker-compose\.infra\.yml$" + DEPENDENCY_PATTERN="$DEPENDENCY_PATTERN|^\.github\/workflows\/(api|webapp|e2e)-dependencies\.yml$" + + if echo "$CHANGED_FILES" | grep -q -E "$DEPENDENCY_PATTERN"; then + echo "changes_detected=true" >> $GITHUB_OUTPUT + echo "Dependency changes detected" + else + echo "changes_detected=false" >> $GITHUB_OUTPUT + echo "No dependency changes detected" + fi + + handle-no-changes: + name: Handle no changes + needs: check-e2e-changes + if: needs.check-e2e-changes.outputs.changes_detected != 'true' + runs-on: ubuntu-latest + steps: + - name: No changes required + run: | + echo "No dependency changes detected. No rebuild required." + exit 0 + + generate-e2e-image: + name: Generate E2E environment image + needs: check-e2e-changes + if: needs.check-e2e-changes.outputs.changes_detected == 'true' + runs-on: ubuntu-latest + environment: ${{ startsWith(github.ref, 'refs/tags/v') && 'production' || 'staging' }} + permissions: + contents: read + id-token: write + env: + AWS_REGION: ${{ vars.AWS_REGION }} + ECR_REGISTRY: ${{ vars.ECR_REGISTRY }} + ECR_REPOSITORY_DEPENDENCIES: ${{ vars.ECR_REPOSITORY_DEPENDENCIES }} + + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + role-to-assume: ${{ secrets.AWS_ROLE_ARN }} + aws-region: ${{ env.AWS_REGION }} + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + - name: Build E2E environment image + run: | + docker build \ + -t ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY_DEPENDENCIES }}:latest-e2e \ + -f .deploy/dependencies/e2e/Dockerfile \ + . + + - name: Push image to Amazon ECR + run: | + docker push ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY_DEPENDENCIES }}:latest-e2e diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml new file mode 100644 index 00000000000..c72bb7a99bc --- /dev/null +++ b/.github/workflows/e2e-tests.yml @@ -0,0 +1,125 @@ +name: E2E Tests + +on: + pull_request: + branches: [dev-dspot] + paths: + - 'apps/**' + - 'packages/**' + - 'docker/**' + +jobs: + + check-e2e-dependencies: + name: Check and Build E2E Dependencies + if: ${{ !contains(github.event.pull_request.labels.*.name, 'dependencies-built') }} + uses: ./.github/workflows/e2e-dependencies.yml + secrets: inherit + + e2e-environment: + name: Setup E2E Environment + needs: [check-e2e-dependencies] + if: ${{ always() && (needs.check-e2e-dependencies.result == 'success' || needs.check-e2e-dependencies.result == 'skipped') }} + runs-on: ubuntu-latest + environment: staging + permissions: + contents: read + id-token: write + env: + ECR_REGISTRY: ${{ vars.ECR_REGISTRY }} + ECR_REPOSITORY_DEPENDENCIES: ${{ vars.ECR_REPOSITORY_DEPENDENCIES }} + AWS_REGION: ${{ vars.AWS_REGION }} + DB_NAME: gauzy + DB_USER: postgres + DB_PASS: gauzy_password + DB_PORT: 5432 + DB_HOST: localhost + API_HOST: 0.0.0.0 + API_PORT: 3000 + API_BASE_URL: http://localhost:3000 + WEBAPP_URL: http://localhost:4200 + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + role-to-assume: ${{ secrets.AWS_ROLE_ARN }} + aws-region: ${{ env.AWS_REGION }} + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + - name: Start E2E Environment + run: | + # Pull the latest e2e image + docker pull ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY_DEPENDENCIES }}:latest-e2e + + # Start the e2e container with all services + docker run -d \ + --name e2e-env \ + -p 3000:3000 \ + -p 4200:4200 \ + -p 5432:5432 \ + -e NODE_ENV=production \ + -e DB_HOST=${{ env.DB_HOST }} \ + -e DB_PORT=${{ env.DB_PORT }} \ + -e DB_NAME=${{ env.DB_NAME }} \ + -e DB_USER=${{ env.DB_USER }} \ + -e DB_PASS=${{ env.DB_PASS }} \ + -e API_HOST=${{ env.API_HOST }} \ + -e API_PORT=${{ env.API_PORT }} \ + -e API_BASE_URL=${{ env.API_BASE_URL }} \ + ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY_DEPENDENCIES }}:latest-e2e + + - name: Set up Docker Compose infra + run: docker-compose -f docker-compose.infra.yml up -d + + - name: Wait for Services + run: | + echo "Waiting for PostgreSQL..." + timeout 30s bash -c 'until pg_isready -h localhost -p 5432; do sleep 2; done' + + echo "Waiting for API..." + timeout 30s bash -c 'until curl -s http://localhost:3000/api; do sleep 2; done' + + echo "Waiting for WebApp..." + timeout 30s bash -c 'until curl -s http://localhost:4200; do sleep 2; done' + + - name: Clean and Seed Database + run: | + # The seed:all command will: + # 1. Clean the database (TRUNCATE all tables) + # 2. Reset sequences + # 3. Seed fresh test data + docker exec e2e-env yarn --cwd /app/apps/api seed:all + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.11.1' + cache: 'yarn' + + - name: Install Dependencies + run: | + yarn config set network-timeout 300000 + yarn install --frozen-lockfile --cache-folder ~/.cache/yarn + + - name: Run E2E Tests + run: yarn e2e:ci + + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v4 + with: + name: e2e-test-results + path: | + dist/cypress + cypress/screenshots + cypress/videos + + - name: Cleanup + if: always() + run: docker rm -f e2e-env diff --git a/apps/gauzy-e2e/cypress.config.js b/apps/gauzy-e2e/cypress.config.js index 1e6323b14a3..760166854ed 100644 --- a/apps/gauzy-e2e/cypress.config.js +++ b/apps/gauzy-e2e/cypress.config.js @@ -28,10 +28,15 @@ module.exports = defineConfig({ } }, e2e: { - baseUrl: "http://localhost:4200", + // Use environment variable for baseUrl, fallback to localhost for local development + baseUrl: process.env.WEBAPP_URL || "http://localhost:4200", specPattern: "./src/e2e/**/*.{ts,tsx}", supportFile: "./src/support/index.ts", setupNodeEvents(on, config) { + // Update baseUrl from environment variable if present + if (process.env.WEBAPP_URL) { + config.baseUrl = process.env.WEBAPP_URL; + } return require('./src/plugins/index')(on, config); } } diff --git a/apps/gauzy-e2e/src/e2e/AddEmployeeLevelTest.ts b/apps/gauzy-e2e/src/e2e/AddEmployeeLevelTest.ts index 29a3f09b9c8..0297c764377 100644 --- a/apps/gauzy-e2e/src/e2e/AddEmployeeLevelTest.ts +++ b/apps/gauzy-e2e/src/e2e/AddEmployeeLevelTest.ts @@ -7,7 +7,7 @@ import { OrganizationTagsPageData } from '../support/Base/pagedata/OrganizationT import * as dashboardPage from '../support/Base/pages/Dashboard.po'; import { CustomCommands } from '../support/commands'; -// OK +// OK (no issues detected) describe('Add employee level test', () => { beforeEach(() => { cy.session('login', () => { diff --git a/package.json b/package.json index 6cd8f225794..293c6a61900 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "test": "yarn run postinstall.web && yarn run config:dev && yarn ng test", "lint": "yarn run config:dev && yarn ng lint && yarn ng lint", "e2e": "yarn run postinstall.web && yarn run config:dev && yarn ng e2e --browser chrome", - "e2e:ci": "yarn run postinstall.web && yarn run config:prod && yarn --frozen-lockfile --cache-folder ~/.cache/yarn ng:ci e2e -c=production --prod --headless", + "e2e:ci": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=12288 yarn run postinstall.web && yarn run config:prod && yarn --frozen-lockfile --cache-folder ~/.cache/yarn ng:ci e2e gauzy-e2e -c=production --prod --headless --browser chrome", "affected:apps": "yarn nx affected:apps", "affected:libs": "yarn nx affected:libs", "affected:build": "yarn nx affected:build",