├── .DS_Store ├── .env.template ├── .eslintrc ├── .github ├── pull_request_template.md └── workflows │ ├── internal-playwright.yml │ ├── internal.yml │ ├── internal_postgres.yml │ ├── on_demand.yml │ ├── tyk-demo-ui.yml │ └── ui_test.yml ├── .gitignore ├── .gitmodules ├── Dockerfile ├── Makefile ├── README.md ├── babel.config.js ├── ci ├── Dashboard │ ├── Dockerfile │ └── entrypoint.sh ├── GW │ ├── Dockerfile │ └── entrypoint.sh ├── ci_testing_env.yml ├── conf │ ├── pump.conf │ ├── tyk.conf │ ├── tyk_analytics.conf │ ├── tyk_analytics_postgres.conf │ └── tyk_pro.conf ├── testing_env.yml ├── testing_env_images.yml └── testing_env_postgres.yml ├── config_variables.js ├── coverage.md ├── lib ├── pom │ ├── Apis_page.js │ ├── Catalogue_page.js │ ├── Endpoints_page.js │ ├── Graphql_page.js │ ├── Keys_page.js │ ├── Login_page.js │ ├── Main_page.js │ ├── Page.js │ ├── Policies_page.js │ ├── Tib_page.js │ ├── Users_page.js │ ├── Webhooks_page.js │ └── portal │ │ └── Admin_settings_page.js └── utils │ ├── API_object_designer.js │ ├── Policy_object_designer.js │ ├── api_connections │ ├── API_connection.js │ ├── Dashboard_admin_connection.js │ └── Dashboard_connection.js │ ├── api_object.json │ ├── federation_example.js │ ├── policy_object.json │ ├── prerequisites.js │ └── utils.js ├── package-lock.json ├── package.json ├── playwright ├── .eslintrc.js ├── .gitignore ├── README.md ├── config_variables.ts ├── coverage.md ├── lib │ ├── pom │ │ ├── Apis_page.ts │ │ ├── Catalogue_page.ts │ │ ├── Endpoints_page.ts │ │ ├── Graphql_page.ts │ │ ├── Keys_page.ts │ │ ├── Login_page.ts │ │ ├── Main_page.ts │ │ ├── Policies_page.ts │ │ ├── Template_Page.ts │ │ ├── Tib_page.ts │ │ ├── Users_page.ts │ │ ├── Webhooks_page.ts │ │ └── portal │ │ │ └── Admin_settings_page.ts │ └── utils │ │ ├── API_object_designer.ts │ │ ├── Policy_object_designer.ts │ │ ├── api_connections │ │ ├── Dashboard_admin_connection.ts │ │ └── Dashboard_connection.ts │ │ ├── api_object.json │ │ ├── federation_example.ts │ │ ├── fixtures.ts │ │ ├── policy_object.json │ │ ├── prerequisites.ts │ │ └── utils.ts ├── package-lock.json ├── package.json ├── playwright.config.ts ├── slack_notify.js ├── tests │ └── specs │ │ ├── api_designer │ │ ├── authentication_tests │ │ │ ├── oas_api_authtoken_test.js │ │ │ ├── oas_api_basicauth_test.js │ │ │ ├── oas_api_custom_auth_test.js │ │ │ ├── oas_api_hmac_test.js │ │ │ ├── oas_api_multiauth_test.js │ │ │ ├── oas_api_oauth_test.js │ │ │ └── oas_api_oidc_test.js │ │ ├── create_api.spec.ts │ │ ├── oas_api_cache.spec.ts │ │ ├── oas_api_cors.spec.ts │ │ ├── oas_api_endpoints_test.ts │ │ ├── oas_api_page_search_test.ts │ │ ├── oas_api_service_discovery_test.ts │ │ ├── oas_fields_validation_test.ts │ │ └── oas_middleware_tests │ │ │ ├── oas_api_allow_plugin_test.js │ │ │ ├── oas_api_block_plugin_test.js │ │ │ └── oas_api_ignore_plugin_test.js │ │ ├── catalogue │ │ └── catalogue_crud.spec.ts │ │ ├── graphql │ │ ├── crud_federation.spec.ts │ │ ├── crud_graphql_proxy.spec.ts │ │ ├── crud_udg.spec.ts │ │ ├── federation_frontend.spec.ts │ │ ├── udg-schema.gql │ │ ├── udg_fe_internal_sources.spec.ts │ │ └── udg_frontend.spec.ts │ │ ├── keys │ │ ├── key_id_crud_test.spec.ts │ │ └── keys_hash_crud_test.spec.ts │ │ ├── login_test │ │ └── empty_username_test.spec.ts │ │ ├── policies │ │ ├── multiple_apis_policy_test.spec.ts │ │ ├── policy_api_search.spec.ts │ │ ├── policy_crud.spec.ts │ │ ├── policy_mainpage_search.spec.ts │ │ ├── policy_mandatory_fields.spec.ts │ │ ├── policy_metadata.spec.ts │ │ ├── policy_settings.spec.ts │ │ └── policy_tags.spec.ts │ │ ├── portal_settings │ │ ├── admin_settings.spec.ts │ │ ├── api_access_settings.spec.ts │ │ ├── dcr_settings.spec.ts │ │ └── emails_settings.spec.ts │ │ ├── test.spec.ts │ │ ├── tib │ │ ├── add_tib_profiles.spec.ts │ │ └── public_key.pem │ │ ├── users │ │ ├── users_creation.spec.ts │ │ └── users_crud.spec.ts │ │ └── webhooks │ │ └── webhooks_crud.spec.ts ├── tsconfig.json └── update_xray.sh ├── template_test.js ├── test └── specs │ ├── api_designer │ ├── authentication_tests │ │ ├── oas_api_authtoken_test.js │ │ ├── oas_api_basicauth_test.js │ │ ├── oas_api_custom_auth_test.js │ │ ├── oas_api_hmac_test.js │ │ ├── oas_api_multiauth_test.js │ │ ├── oas_api_oauth_test.js │ │ └── oas_api_oidc_test.js │ ├── create_api_test.js │ ├── oas_api_cache_test.js │ ├── oas_api_cors_test.js │ ├── oas_api_endpoints_test.js │ ├── oas_api_page_search_test.js │ ├── oas_api_service_discovery_test.js │ ├── oas_fields_validation_test.js │ └── oas_middleware_tests │ │ ├── oas_api_allow_plugin_test.js │ │ ├── oas_api_block_plugin_test.js │ │ └── oas_api_ignore_plugin_test.js │ ├── catalogue │ └── catalogue_crud_test.js │ ├── graphql │ ├── crud_federation_test.js │ ├── crud_graphql_proxy_test.js │ ├── crud_udg_test.js │ ├── federation_frontend_test.js │ ├── udg-schema.gql │ ├── udg_fe_internal_sources_test.js │ └── udg_frontend_test.js │ ├── keys │ ├── key_id_crud_test.js │ └── keys_hash_crud_test.js │ ├── login_test │ └── empty_username_test.js │ ├── policies │ ├── multiple_apis_policy_test.js │ ├── policy_api_search_test.js │ ├── policy_crud_test.js │ ├── policy_mainpage_search_test.js │ ├── policy_mandatory_fields_test.js │ ├── policy_metadata_test.js │ ├── policy_settings_test.js │ └── policy_tags_test.js │ ├── portal_settings │ ├── admin_settings_test.js │ ├── api_access_settings_test.js │ ├── dcr_settings_test.js │ └── emails_settings_test.js │ ├── tib │ ├── add_tib_profiles_test.js │ └── public_key.pem │ ├── users │ ├── users_creation_test.js │ └── users_crud_test.js │ └── webhooks │ └── webhooks_crud_test.js ├── update_xray.sh └── wdio.conf.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-analytics-tests/e1d6971a782f1fe4ec3877c73a659df6e9cb6ebb/.DS_Store -------------------------------------------------------------------------------- /.env.template: -------------------------------------------------------------------------------- 1 | TOKEN=%github_personal_token% 2 | TYK_DB_LICENSEKEY=%dash_license_key% 3 | 4 | GOPATH=/Users/konrad/go 5 | DASH_REPO_PATH=/Users/konrad/go/src/github.com/TykTechnologies/tyk-analytics 6 | GW_REPO_PATH=/Users/konrad/go/src/github.com/TykTechnologies/tyk 7 | MDCB_REPO_PATH=/Users/konrad/go/src/github.com/TykTechnologies/tyk-sink 8 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "es6": true 5 | }, 6 | "rules": { 7 | "semi": 2, 8 | "strict": 2, 9 | "block-scoped-var": 2, 10 | "complexity": 1, 11 | "consistent-return": 2, 12 | "curly": 2, 13 | "default-case": 2, 14 | "dot-notation": 2, 15 | "eqeqeq": 2, 16 | "guard-for-in": 2, 17 | "no-else-return": 2, 18 | "no-labels": 2, 19 | "no-eq-null": 2, 20 | "no-eval": 2, 21 | "no-implied-eval": 2, 22 | "no-lone-blocks": 2, 23 | "no-loop-func": 2, 24 | "no-multi-spaces": 2, 25 | "no-native-reassign": 2, 26 | "no-new": 2, 27 | "no-octal": 0, 28 | "no-process-env": 0, 29 | "no-proto": 2, 30 | "no-redeclare": 2, 31 | "no-with": 2, 32 | "radix": 2, 33 | "vars-on-top": 2, 34 | "wrap-iife": 2, 35 | "yoda": 2 36 | } 37 | } -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | ## Description 3 | 4 | 5 | 6 | ## Checklist 7 | 8 | - [ ] Make sure that tests are passing in githubaction 9 | - [ ] Check if change should be populated to other branches (master, release-3-lts, release-4.0) 10 | - [ ] Tests are stable 11 | -------------------------------------------------------------------------------- /.github/workflows/tyk-demo-ui.yml: -------------------------------------------------------------------------------- 1 | name: UI Tests 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | deployement_type: 7 | default: "on-premises" 8 | description: "deployment type, for example: on-premises. Other type - WIP" 9 | required: true 10 | dashboard_image_tag: 11 | default: "v5.0" 12 | description: "dashboard image tag, for example:v5.0. WIP: ID from ECR (maybe PR number)" 13 | required: true 14 | gateway_image_tag: 15 | default: "v5.0" 16 | description: "gateway image tag, for example:v5.0" 17 | required: true 18 | 19 | env: 20 | GOPRIVATE: github.com/TykTechnologies 21 | 22 | jobs: 23 | test: 24 | if: github.event.pull_request.draft == false 25 | strategy: 26 | matrix: 27 | go-version: [1.19.x] 28 | platform: [ubuntu-latest] 29 | arch: [amd64] 30 | node-version: [15.x] 31 | runs-on: ${{ matrix.platform }} 32 | 33 | steps: 34 | - name: Install Node.js ${{ matrix.node-version }} 35 | uses: actions/setup-node@v2.4.1 36 | with: 37 | node-version: ${{ matrix.node-version }} 38 | 39 | - name: Fix private module deps 40 | env: 41 | TOKEN: '${{ secrets.ORG_GH_TOKEN }}' 42 | run: > 43 | git config --global url."https://${TOKEN}@github.com".insteadOf "https://github.com" 44 | 45 | - name: Checkout test repo repostory 46 | uses: actions/checkout@v2 47 | 48 | - name: Checkout Dash repository 49 | uses: actions/checkout@v2 50 | with: 51 | repository: TykTechnologies/tyk-analytics 52 | path: tyk-analytics 53 | 54 | 55 | - name: Update Hosts 56 | run: sudo ./scripts/update-hosts.sh 57 | 58 | - name: start tyk demo 59 | run: ./up.sh 60 | env: 61 | DASHBOARD_VERSION: ${{ github.event.inputs.dashboard_image_tag }} 62 | GATEWAY_VERSION: ${{ github.event.inputs.gateway_image_tag }} 63 | 64 | - name: Install test dependecies 65 | run: | 66 | npm ci 67 | working-directory: tyk-analytics-tests/playwright 68 | 69 | - name: Install Playwright Browsers 70 | run: npx playwright install --with-deps 71 | working-directory: tyk-analytics-tests/playwright 72 | 73 | # - name: Waiting for dashboard 74 | # run: | 75 | # while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:3000/hello/)" != "200" ]]; do sleep 60 && echo "waiting for dashboard '$(date +"%T")'"; done 76 | # timeout-minutes: 15 77 | 78 | - name: Execute UI tests 79 | id: test_execution 80 | run: | 81 | npm run test 82 | env: 83 | URL: "http://tyk-dashboard.localhost:3000/" 84 | working-directory: tyk-analytics-tests/playwright 85 | 86 | - uses: actions/upload-artifact@v3 87 | if: always() 88 | with: 89 | name: playwright-report 90 | path: tyk-analytics-tests/playwright/playwright-report/ 91 | retention-days: 30 -------------------------------------------------------------------------------- /.github/workflows/ui_test.yml: -------------------------------------------------------------------------------- 1 | # Run UI test automation 2 | 3 | name: Dashboard UI test run 4 | 5 | on: 6 | schedule: 7 | - cron: "0 */12 * * *" # every 12 hours 8 | workflow_dispatch: 9 | inputs: 10 | url: 11 | default: "http://tyk-analytics.master.dev.tyk.technology:3000/" 12 | description: "Environment URL run against; like http://tyk-analytics.BRANCH_NAME.dev.tyk.technology:3000/" 13 | required: false 14 | push: 15 | branches: 16 | - master 17 | pull_request: 18 | branches: 19 | - master 20 | 21 | env: 22 | URL: ${{ github.event.inputs.url }} 23 | 24 | defaults: 25 | run: 26 | shell: bash 27 | 28 | jobs: 29 | test: 30 | name: test run 31 | 32 | strategy: 33 | matrix: 34 | arch: [amd64] 35 | node-version: [12.x] # stick to latest LTS 36 | 37 | runs-on: ubuntu-latest 38 | 39 | steps: 40 | - name: Checkout ${{ github.repository }} 41 | uses: actions/checkout@v2 42 | 43 | - name: Use Node.js ${{ matrix.node-version }} 44 | uses: actions/setup-node@v1 45 | with: 46 | node-version: ${{ matrix.node-version }} 47 | 48 | # https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable 49 | - run: npm ci 50 | 51 | - name: executeTests 52 | run: | 53 | if [[ "${{ env.URL }}" == "" ]]; then 54 | URL='http://tyk-analytics.master.dev.tyk.technology:3000/' npm run headless-test 55 | else 56 | npm run headless-test 57 | fi 58 | env: 59 | URL: ${{ env.URL}} 60 | 61 | - name: Archive UI test report 62 | if: ${{ always() }} 63 | uses: actions/upload-artifact@v2 64 | with: 65 | name: ui-test-report 66 | path: ./results/report/index.html 67 | 68 | - name: Slack notify 69 | if: ${{ always() }} 70 | run: | 71 | if [[ "${{ env.URL }}" == "" ]]; then 72 | WDIO_TEST_ENV='http://tyk-analytics.master.dev.tyk.technology:3000/' npm run notify-slack 73 | else 74 | npm run notify-slack 75 | fi 76 | env: 77 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 78 | WDIO_TEST_ENV: ${{ env.URL }} 79 | FRAMEWORK_REPO: ${{ github.repository }} 80 | EVENT_TRIGGER: ${{ github.event_name }} 81 | JOB_RUN_ID: ${{ github.run_id }} 82 | JOB_NAME: ${{ github.job }} 83 | GIT_BRANCH: ${{ github.ref }} 84 | 85 | - name: Getting dashboard logs on failure 86 | if: ${{ failure() }} 87 | run: docker logs tyk-dashboard 88 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node 2 | node_modules/ 3 | 4 | # Don't keep recordings from test runs 5 | results/ 6 | *.log 7 | # Local files 8 | .DS_Store 9 | 10 | # Env files 11 | .env 12 | 13 | # IDE settings 14 | .idea/ 15 | .vscode/* 16 | 17 | # Playwright test reports 18 | playwright/playwright-report/ 19 | playwright/test-results/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-analytics-tests/e1d6971a782f1fe4ec3877c73a659df6e9cb6ebb/.gitmodules -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14 2 | 3 | RUN apt-get update 4 | RUN apt-get install -y libnss3-dev 5 | 6 | RUN apt-get update -y && \ 7 | apt-get install -y gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 \ 8 | libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 \ 9 | libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \ 10 | libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 \ 11 | libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 \ 12 | libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \ 13 | ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release \ 14 | net-tools xdg-utils wget xvfb ifupdown libgbm-dev 15 | RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb 16 | RUN apt-get -y install ./google-chrome-stable_current_amd64.deb 17 | WORKDIR /app 18 | COPY package.json /app 19 | RUN npm install 20 | COPY . /app 21 | 22 | CMD DOCKER_IP=$(/sbin/ip route|awk '/default/ { print $3 }') npm run headless-test; 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | start-env: 2 | $(info Make: Starting Tyk dashboard and dependecies) 3 | docker-compose --env-file .env -f ci/testing_env.yml up 4 | start-env-images: 5 | $(info Make: Starting Tyk dashboard and dependecies with official images) 6 | docker-compose --env-file .env -f ci/testing_env_images.yml up 7 | build-env: 8 | $(info Make: Building Tyk dashboard and dependecies) 9 | docker-compose --env-file .env -f ci/testing_env.yml build 10 | stop-env: 11 | $(info Make: Stopping Tyk dashboard and dependecies) 12 | docker-compose --env-file .env -f ci/testing_env.yml down -v --remove-orphans -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # !!WARNING!! 2 | Code from this repository was moved to tyk-analytics repo. 3 | Any changes in the Playwright framework should be introduced as PR in tyk-analytics repo. 4 | 5 | # UI Automated Tests 6 | 7 | [Test coverage](coverage.md) 8 | 9 | ## Dashboard UI automation test suite based on: 10 | 11 | 1. Node.js 12 | 2. [Webdriverio](https://webdriver.io/) 13 | 3. [Timeline reporter](https://github.com/QualityOps/wdio-timeline-reporter) for reporting 14 | 15 | ## How to run tests 16 | 1. Clone repository 17 | 2. Install Dependencies 18 | ``` 19 | 'npm install' 20 | ``` 21 | 4. Execute tests using ```npm test``` or ```npm headless-test``` 22 | 5. Report will be generated in results/report 23 | 24 | ## Configuration 25 | We can execute test with following variables [default values]: 26 | - URL [http://localhost:3000/] - dashboard UI url 27 | - ADMIN_SECRET [12345] - admin secrted on environment 28 | - CLEAN_TEST [true] - decide if test should be run on new Org and user 29 | 30 | Below variables will be used only if __CLEAN_TEST__ set to **false** 31 | - USER_SECRET - user_secret to be used for API calls 32 | - USER_EMAIL - email to be used for log-in 33 | - USER_PASSWORD - password to be used for log-in 34 | 35 | ## Test template 36 | For creating new tests please copy and rename **template_test.js** file into test/specs/ 37 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['@babel/preset-env', { 4 | targets: { 5 | node: 'current' 6 | } 7 | }] 8 | ] 9 | }; -------------------------------------------------------------------------------- /ci/Dashboard/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | ARG GO_VERSION=1.19.8 4 | 5 | SHELL [ "/bin/bash", "-o", "pipefail", "-c" ] 6 | 7 | RUN apt-get update --assume-yes \ 8 | && apt-get install --assume-yes --no-install-recommends \ 9 | ca-certificates \ 10 | curl \ 11 | && apt-get clean \ 12 | && rm --force --recursive /var/lib/apt/lists/* 13 | 14 | RUN curl --location --silent https://deb.nodesource.com/setup_10.x | bash - 15 | 16 | RUN apt-get update --assume-yes \ 17 | && apt-get install --assume-yes --no-install-recommends \ 18 | build-essential \ 19 | bzip2 \ 20 | git \ 21 | libluajit-5.1-2 \ 22 | libpython3.5 \ 23 | luarocks \ 24 | nodejs \ 25 | python3-dev \ 26 | python3-pip \ 27 | python3-setuptools \ 28 | python3 \ 29 | vim \ 30 | wget \ 31 | && apt-get clean \ 32 | && rm --force --recursive /var/lib/apt/lists/* 33 | 34 | RUN wget --progress=dot:giga https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz 35 | RUN tar --directory=/usr/local --extract --gzip --file=go${GO_VERSION}.linux-amd64.tar.gz 36 | 37 | RUN mkdir --parents \ 38 | /develop/confs \ 39 | /develop/go \ 40 | /develop/start 41 | COPY /entrypoint.sh /develop/start/entrypoint.sh 42 | RUN chmod +x /develop/start/entrypoint.sh 43 | 44 | ENV PATH=$PATH:/usr/local/go/bin 45 | ENV GOPATH=/develop/go 46 | 47 | VOLUME [ "/develop/go/src", "/opt/tyk-dashboard/tyk_analytics.conf" ] 48 | 49 | CMD [ "/develop/start/entrypoint.sh" ] 50 | EXPOSE 8080 443 -------------------------------------------------------------------------------- /ci/Dashboard/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | echo "Tyk log level: '${TYK_LOGLEVEL:-}'" 5 | 6 | src_dir=/develop/go/src 7 | cd "$src_dir" 8 | 9 | echo "Installing Tyk Dashboard..." 10 | git config --global --add safe.directory $src_dir 11 | git config --global url."https://${TOKEN}@github.com".insteadOf "https://github.com" 12 | go install 13 | 14 | dashboard_args=("--conf=/opt/tyk-dashboard/tyk_analytics.conf") 15 | 16 | # Required to work around the kingpin CLI parser used in tyk-analytics: 17 | # https://github.com/TykTechnologies/tyk-analytics/blob/e554af201b/cli/cli.go#L49 18 | if test -n "${TYK_ARG:-}"; then 19 | dashboard_args+=("$TYK_ARG") 20 | fi 21 | 22 | echo "Running Tyk Dashboard with following arguments:" 23 | echo "${dashboard_args[@]}" 24 | 25 | "${GOPATH}/bin/tyk-analytics" "${dashboard_args[@]}" -------------------------------------------------------------------------------- /ci/GW/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | ARG GO_VERSION=1.19.8 4 | 5 | RUN apt-get update \ 6 | && apt-get install --assume-yes --no-install-recommends \ 7 | build-essential \ 8 | ca-certificates \ 9 | jq \ 10 | git \ 11 | libluajit-5.1-2 \ 12 | lua-cjson \ 13 | lua-cjson-dev \ 14 | luarocks \ 15 | python3-dev \ 16 | python3-pip \ 17 | python3-setuptools \ 18 | python3 \ 19 | wget \ 20 | && apt-get clean \ 21 | && rm --force --recursive /var/lib/apt/lists/* 22 | 23 | # Build protobuf from source 24 | #RUN wget --progress=dot:giga https://github.com/google/protobuf/releases/download/v3.1.0/protobuf-python-3.1.0.tar.gz 25 | #RUN tar -xvzf protobuf-python-3.1.0.tar.gz 26 | #RUN cd protobuf-3.1.0/ && ./configure -prefix=/usr && make && make install 27 | #RUN cd protobuf-3.1.0/python && python3 setup.py build --cpp_implementation && python3 setup.py install --cpp_implementation 28 | 29 | # Sphinx 1.5.2 breaks grpcio 30 | RUN pip3 install -U pip 31 | RUN pip3 install Sphinx==1.5.1 32 | RUN pip3 install grpcio 33 | RUN pip3 install protobuf 34 | RUN python3 -m pip install grpcio 35 | RUN python3 -m pip install protobuf 36 | 37 | # Go install 38 | RUN wget --progress=dot:giga https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz 39 | RUN tar --directory=/usr/local --extract --gzip --file=go${GO_VERSION}.linux-amd64.tar.gz 40 | 41 | RUN mkdir --parents \ 42 | /develop/confs \ 43 | /develop/go \ 44 | /develop/start 45 | COPY /entrypoint.sh /develop/start/entrypoint.sh 46 | RUN chmod +x /develop/start/entrypoint.sh 47 | 48 | ENV PATH=$PATH:/usr/local/go/bin 49 | ENV GOPATH=/develop/go/ 50 | 51 | VOLUME [ "/develop/go", "/opt/tyk-gateway/tyk.conf", "/opt/tyk-gateway" ] 52 | 53 | CMD [ "/develop/start/entrypoint.sh"] 54 | EXPOSE 8080 443 55 | -------------------------------------------------------------------------------- /ci/GW/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | tyk_args=(--debug --httpprofile) 5 | 6 | tyk_args+=("--conf=/opt/tyk-gateway/tyk.conf") 7 | 8 | echo "Installing Tyk..." 9 | cd /opt/tyk-gateway 10 | ls 11 | 12 | git config --global --add safe.directory /opt/tyk-gateway 13 | go install 14 | 15 | echo "Running Tyk with following arguments:" 16 | echo "${tyk_args[@]}" 17 | 18 | "${GOPATH:-}/bin/tyk" "${tyk_args[@]}" -------------------------------------------------------------------------------- /ci/ci_testing_env.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | services: 3 | tyk-dashboard: 4 | build: ./Dashboard 5 | ports: 6 | - "3000:3000" 7 | - "5000:5000" 8 | - "1026:1025" 9 | environment: 10 | - "TYK_DB_LICENSEKEY=${TYK_DB_LICENSEKEY}" 11 | - TYK_LOGLEVEL=${TYK_LOGLEVEL:-debug} 12 | - TOKEN=${TOKEN} 13 | - GOPRIVATE=${GOPRIVATE} 14 | volumes: 15 | - ${DASH_REPO_PATH}:/develop/go/src 16 | - ./conf/tyk_analytics.conf:/opt/tyk-dashboard/tyk_analytics.conf 17 | depends_on: 18 | - tyk-redis 19 | - tyk-mongo 20 | - tyk-gateway 21 | tyk-gateway: 22 | build: ./GW 23 | ports: 24 | - "6000:6000" 25 | - "8003:8003" 26 | - "8080:8080" 27 | volumes: 28 | - ${GOPATH}:/develop/go 29 | - ${GW_REPO_PATH}:/opt/tyk-gateway 30 | - ./conf/tyk.conf:/opt/tyk-gateway/tyk.conf 31 | - ./conf/tyk.conf:/develop/confs/tyk.conf 32 | - ./conf/cert.pem:/etc/ssl/certs/cert.pem 33 | - ./conf/key.pem:/etc/ssl/certs/key.pem 34 | - ./apps:/opt/tyk-gateway/apps 35 | - ./middleware:/opt/tyk-gateway/middleware 36 | environment: 37 | - TOKEN=${TOKEN} 38 | - TYK_LOGLEVEL=info 39 | depends_on: 40 | - tyk-redis 41 | tyk-redis: 42 | image: redis:6.2 43 | ports: 44 | - "6379:6379" 45 | tyk-mongo: 46 | image: mongo:4.1 47 | ports: 48 | - "27017:27017" 49 | federation: 50 | container_name: federation 51 | image: agatawitkowska/federation-example 52 | ports: 53 | - "4000:4000" 54 | - "4001:4001" 55 | - "4002:4002" 56 | - "4003:4003" -------------------------------------------------------------------------------- /ci/conf/pump.conf: -------------------------------------------------------------------------------- 1 | { 2 | "analytics_storage_type": "redis", 3 | "analytics_storage_config": { 4 | "type": "redis", 5 | "host": "tyk-redis", 6 | "port": 6379, 7 | "hosts": null, 8 | "username": "", 9 | "password": "", 10 | "database": 0, 11 | "optimisation_max_idle": 100, 12 | "optimisation_max_active": 0, 13 | "enable_cluster": false 14 | }, 15 | "purge_delay": 1, 16 | "pumps": { 17 | "mongo": { 18 | "name": "mongo", 19 | "meta": { 20 | "collection_name": "tyk_analytics", 21 | "mongo_url": "mongodb://tyk-mongo:27017/tyk_analytics", 22 | "max_insert_batch_size_bytes": 80000, 23 | "max_document_size_bytes": 20112 24 | } 25 | }, 26 | "mongo-pump-aggregate": { 27 | "name": "mongo-pump-aggregate", 28 | "meta": { 29 | "mongo_url": "mongodb://tyk-mongo:27017/tyk_analytics", 30 | "use_mixed_collection": true, 31 | "track_all_paths" : true 32 | } 33 | }, 34 | "mongo-pump-selective": { 35 | "name": "mongo-pump-selective", 36 | "meta": { 37 | "mongo_url": "mongodb://tyk-mongo:27017/tyk_analytics", 38 | "use_mixed_collection": true, 39 | "track_all_paths" : true 40 | } 41 | } 42 | }, 43 | "uptime_pump_config": { 44 | "collection_name": "tyk_uptime_analytics", 45 | "mongo_url": "mongodb://tyk-mongo:27017/tyk_analytics", 46 | "max_insert_batch_size_bytes": 500000, 47 | "max_document_size_bytes": 200000 48 | }, 49 | "dont_purge_uptime_data": false 50 | } 51 | -------------------------------------------------------------------------------- /ci/testing_env.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | services: 3 | tyk-dashboard: 4 | build: ./Dashboard 5 | # image: tykio/tyk-dashboard:v5.0.2 6 | container_name: tyk-dashboard 7 | ports: 8 | - "3000:3000" 9 | - "5000:5000" 10 | - "1026:1025" 11 | environment: 12 | - "TYK_DB_LICENSEKEY=${TYK_DB_LICENSEKEY}" 13 | - TYK_LOGLEVEL=${TYK_LOGLEVEL:-debug} 14 | - TOKEN=${TOKEN} 15 | - GOPRIVATE=${GOPRIVATE} 16 | - GO_VERSION=${GO_VERSION} 17 | volumes: 18 | - ${DASH_REPO_PATH}:/develop/go/src 19 | - ./conf/tyk_analytics.conf:/opt/tyk-dashboard/tyk_analytics.conf 20 | depends_on: 21 | - tyk-redis 22 | - tyk-mongo 23 | - tyk-gateway 24 | tyk-gateway: 25 | build: ./GW 26 | container_name: tyk-gateway 27 | ports: 28 | - "6000:6000" 29 | - "8003:8003" 30 | - "8080:8080" 31 | volumes: 32 | - ${GOPATH}:/develop/go 33 | - ${GW_REPO_PATH}:/opt/tyk-gateway 34 | - ./conf/tyk.conf:/opt/tyk-gateway/tyk.conf 35 | - ./conf/tyk.conf:/develop/confs/tyk.conf 36 | - ./conf/cert.pem:/etc/ssl/certs/cert.pem 37 | - ./conf/key.pem:/etc/ssl/certs/key.pem 38 | - ./apps:/opt/tyk-gateway/apps 39 | - ./middleware:/opt/tyk-gateway/middleware 40 | environment: 41 | - TOKEN=${TOKEN} 42 | - TYK_LOGLEVEL=info 43 | - GO_VERSION=${GO_VERSION} 44 | depends_on: 45 | - tyk-redis 46 | tyk-redis: 47 | image: redis:6.2 48 | ports: 49 | - "6379:6379" 50 | tyk-mongo: 51 | image: mongo:4.1 52 | ports: 53 | - "27017:27017" 54 | federation: 55 | container_name: federation 56 | image: agatawitkowska/federation-example 57 | ports: 58 | - "4000:4000" 59 | - "4001:4001" 60 | - "4002:4002" 61 | - "4003:4003" 62 | -------------------------------------------------------------------------------- /ci/testing_env_images.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | services: 3 | tyk-dashboard: 4 | image: tykio/tyk-dashboard:v5.2rc2 5 | container_name: tyk-dashboard 6 | ports: 7 | - "3000:3000" 8 | - "5000:5000" 9 | - "1026:1025" 10 | environment: 11 | - "TYK_DB_LICENSEKEY=${TYK_DB_LICENSEKEY}" 12 | - TYK_LOGLEVEL=${TYK_LOGLEVEL:-debug} 13 | volumes: 14 | - ./conf/tyk_analytics.conf:/opt/tyk-dashboard/tyk_analytics.conf 15 | - ./conf/tyk_analytics.conf:/develop/confs/tyk_analytics.conf 16 | depends_on: 17 | - tyk-redis 18 | - tyk-mongo 19 | - tyk-gateway 20 | tyk-gateway: 21 | image: tykio/tyk-gateway:v5.2rc2 22 | container_name: tyk-gateway 23 | ports: 24 | - "6000:6000" 25 | - "8003:8003" 26 | - "8080:8080" 27 | volumes: 28 | - ./conf/tyk.conf:/opt/tyk-gateway/tyk.conf 29 | - ./conf/tyk.conf:/develop/confs/tyk.conf 30 | - ./conf/cert.pem:/etc/ssl/certs/cert.pem 31 | - ./conf/key.pem:/etc/ssl/certs/key.pem 32 | - ./apps:/opt/tyk-gateway/apps 33 | - ./middleware:/opt/tyk-gateway/middleware 34 | environment: 35 | - TYK_LOGLEVEL=info 36 | depends_on: 37 | - tyk-redis 38 | tyk-redis: 39 | image: redis:6.2 40 | ports: 41 | - "6379:6379" 42 | tyk-mongo: 43 | image: mongo:4.1 44 | ports: 45 | - "27017:27017" 46 | federation: 47 | container_name: federation 48 | image: agatawitkowska/federation-example 49 | ports: 50 | - "4000:4000" 51 | - "4001:4001" 52 | - "4002:4002" 53 | - "4003:4003" 54 | -------------------------------------------------------------------------------- /ci/testing_env_postgres.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | services: 3 | tyk-dashboard: 4 | build: ./Dashboard 5 | container_name: tyk-dashboard 6 | ports: 7 | - "3000:3000" 8 | - "5000:5000" 9 | - "1026:1025" 10 | environment: 11 | - "TYK_DB_LICENSEKEY=${TYK_DB_LICENSEKEY}" 12 | - TYK_LOGLEVEL=${TYK_LOGLEVEL:-debug} 13 | - TOKEN=${TOKEN} 14 | - GOPRIVATE=${GOPRIVATE} 15 | - GO_VERSION=${GO_VERSION} 16 | volumes: 17 | - ${DASH_REPO_PATH}:/develop/go/src 18 | - ./conf/tyk_analytics_postgres.conf:/opt/tyk-dashboard/tyk_analytics.conf 19 | depends_on: 20 | - tyk-redis 21 | - tyk-postgres 22 | - tyk-gateway 23 | tyk-gateway: 24 | build: ./GW 25 | container_name: tyk-gateway 26 | ports: 27 | - "6000:6000" 28 | - "8003:8003" 29 | - "8080:8080" 30 | volumes: 31 | - ${GOPATH}:/develop/go 32 | - ${GW_REPO_PATH}:/opt/tyk-gateway 33 | - ./conf/tyk.conf:/opt/tyk-gateway/tyk.conf 34 | - ./conf/tyk.conf:/develop/confs/tyk.conf 35 | - ./conf/cert.pem:/etc/ssl/certs/cert.pem 36 | - ./conf/key.pem:/etc/ssl/certs/key.pem 37 | - ./apps:/opt/tyk-gateway/apps 38 | - ./middleware:/opt/tyk-gateway/middleware 39 | environment: 40 | - TOKEN=${TOKEN} 41 | - TYK_LOGLEVEL=info 42 | - GO_VERSION=${GO_VERSION} 43 | depends_on: 44 | - tyk-redis 45 | tyk-redis: 46 | image: redis:6.2 47 | ports: 48 | - "6379:6379" 49 | tyk-postgres: 50 | container_name: tyk-postgres 51 | image: postgres:13.5-alpine 52 | ports: 53 | - "5432:5432" 54 | environment: 55 | - POSTGRES_USER=tyk 56 | - POSTGRES_PASSWORD=tyk 57 | - POSTGRES_DB=tyk 58 | federation: 59 | container_name: federation 60 | image: agatawitkowska/federation-example 61 | ports: 62 | - "4000:4000" 63 | - "4001:4001" 64 | - "4002:4002" 65 | - "4003:4003" 66 | -------------------------------------------------------------------------------- /config_variables.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | 3 | const URL = process.env.URL || "http://localhost:3000/"; 4 | const FEDERATION_UPSTREAM_HOST = (process.env.CI) ? "federation" : "localhost"; 5 | 6 | module.exports = { 7 | CLEAN_TEST: process.env.CLEAN_TEST || true, 8 | 9 | URL: URL, 10 | DASHBOARD_API: URL + 'api/', 11 | DASHBOARD_ADMIN_API: URL + 'admin/', 12 | 13 | USER_EMAIL: process.env.USER_EMAIL, 14 | USER_SECRET: process.env.USER_SECRET, 15 | USER_PASSWORD: process.env.USER_PASSWORD || "test123", 16 | 17 | ORG_NAME: process.env.ORG_NAME || "Auto-test-org", 18 | ADMIN_SECRET: process.env.ADMIN_SECRET || "12345", 19 | 20 | ORG_API_PATH: "organisations/", 21 | USERS_API_PATH: "users/", 22 | 23 | LOGOUT_PATH: "logout/", 24 | HELLO_PATH: "hello/", 25 | 26 | FEDERATION_UPSTREAM_HOST: FEDERATION_UPSTREAM_HOST 27 | }; -------------------------------------------------------------------------------- /lib/pom/Catalogue_page.js: -------------------------------------------------------------------------------- 1 | var Page = require('./Page'); 2 | var Button_object = require('ui_test_automation/wrappers/Button_object'); 3 | var DropDown_object = require('ui_test_automation/wrappers/DropDown_object'); 4 | var Input_object = require('ui_test_automation/wrappers/Input_object'); 5 | var Checkbox_object = require('ui_test_automation/wrappers/Checkbox_object'); 6 | var Table_object = require('ui_test_automation/wrappers/Table_object'); 7 | 8 | class Catalogue_page extends Page { 9 | //API Details tab 10 | get API_DETAILS_TAB() { return new Button_object('button*=API details');} 11 | get ADD_NEW_API_BUTTON() {return new Button_object('span*=Add new API');} 12 | get PUBLIC_API_NAME_INPUT() {return new Input_object('input[name="name"]');} 13 | get SELECT_POLICY_DROPDOWN() {return new DropDown_object('.tyk-combobox2__text-value');} 14 | get DESCRIBE_THIS_API_INPUT() {return new Input_object('[placeholder="A really cool API that provides badger widgets"]');} 15 | get CATALOGUE_OWNER_EMAIL_INPUT() {return new Input_object('input[name="config.email"]');} 16 | get UPDATE_BUTTON() {return new Button_object('span*=Update');} 17 | get SAVE_BUTTON() {return new Button_object('span*=Save');} 18 | 19 | get DELETE_BUTTON() {return new Button_object('span*=Delete');} 20 | get DELETE_KEY_MODAL() {return $('.tyk-modal__content');} 21 | get DELETE_KEY_CONFIRMATION_BUTTON() {return new Button_object('//div[contains(@class,"opened")]//div[@class="tyk-modal__content"]//button//span[text()="Delete"]');} 22 | get NO_APIS_REGISTERED_MESSAGE() {return $('.tyk-message--info');} 23 | 24 | //Settings tab 25 | get OVERRIDE_GLOBAL_SETTINGS() {return new Checkbox_object('input[name="config.override"]');} 26 | get REQUIRE_KEY_APPROVAL() {return new Checkbox_object('input[name="config.require_key_approval"]');} 27 | get REDIRECT_KEY_REQUEST_CHECKBOX() {return new Checkbox_object('input[name="config.redirect_on_key_request"]');} 28 | get SETTINGS_TAB_BUTTON() {return new Button_object('button*=Settings');} 29 | get DEVELOPER_REQUEST_FORM_CUSTOMISATION() {return new Button_object('input[name="fieldName"]');} 30 | 31 | 32 | //Custom fields section 33 | get FIELD_NAME_INPUT() {return new Input_object('input[name="field_name"]');} 34 | get FIELD_VALUE_INPUT() {return new Input_object('input[name="field_value"]');} 35 | get ADD_BUTTON() {return new Button_object('span*=ADD');} 36 | 37 | 38 | //Table 39 | get CATALOGUE_TABLE() {return new Table_object('.tyk-table');} 40 | 41 | 42 | } 43 | 44 | export const catalogue_page = new Catalogue_page(); 45 | -------------------------------------------------------------------------------- /lib/pom/Keys_page.js: -------------------------------------------------------------------------------- 1 | var Page = require('./Page'); 2 | var Button_object = require('ui_test_automation/wrappers/Button_object'); 3 | var Table_object = require('ui_test_automation/wrappers/Table_object'); 4 | var DropDown_object = require('ui_test_automation/wrappers/DropDown_object'); 5 | var Input_object = require('ui_test_automation/wrappers/Input_object'); 6 | var Checkbox_object = require('ui_test_automation/wrappers/Checkbox_object'); 7 | 8 | 9 | 10 | class Keys_page extends Page { 11 | 12 | get ADD_KEY_BUTTON() {return new Button_object('span*=Add Key');} 13 | get CHOOSE_API_TOGGLE() {return new Button_object('span*=Choose api');} 14 | get CHOOSE_API_TABLE() {return new Table_object('.tyk-table');} 15 | get LOOKUP_KEY_BUTTON() {return new Button_object('span*=Lookup Key');} 16 | get KEY_SEARCH_FIELD() {return new Input_object('input[name="key"]');} 17 | get UPDATE_BUTTON() {return new Button_object('span*=Update');} 18 | get UPDATE_WITHOUT_QUOTA_RESET_BUTTON() {return new Button_object('span*=Update without quota reset');} 19 | get DELETE_BUTTON() {return new Button_object('span*=Delete');} 20 | 21 | //Configurations tab/page 22 | get CONFIGURATIONS_TAB_BUTTON() {return new Button_object('button*=2. Configurations');} 23 | get KEY_EXPIRE_DROPDOWN() {return new DropDown_object('.tyk-combobox2__text-value');} 24 | get ALIAS_INPUT_FIELD() {return new Input_object("//input[@name='alias']");} 25 | get ENABLE_DETAILED_LOGGING_BUTTON() {return new Checkbox_object('.tyk-toggle__item');} 26 | get CREATE_KEY_BUTTON() {return new Button_object('span*=Create Key');} 27 | get METADATA_KEY_INPUT() {return new Input_object('input[name=metaDataKey]');} 28 | get METADATA_VALUE_INPUT() {return new Input_object('input[name=metaDataValue]');} 29 | get METADATA_ADD_BUTTON() {return new Button_object('span*=ADD');} 30 | get KEY_HASH_VALUE() {return $('//span[@class="font-family-medium"]//span[text()="Key hash"]//following::button[1]');} 31 | get KEY_ID_VALUE() {return $('//span[@class="font-family-medium"]//span[text()="Key ID"]//following::button[1]');} 32 | 33 | //Basic Authentication section 34 | get AUTHENTICATION_BUTTON() {return new Button_object('button*=3. Authentication');} 35 | get AUTH_USERNAME() {return new Input_object('input[name="authentication.username"]');} 36 | get AUTH_PASSWORD() {return new Input_object('input[name="authentication.password"]');} 37 | get CREATE_NEW_PASSWORD_CHECKBOX() {return new Checkbox_object('.tyk-checkbox');} 38 | 39 | //Key Successfully Generated modal 40 | get MODAL() {return $('.opened .tyk-modal__content');} 41 | //Copy icons inside Key sucessfully generated modal 42 | get COPY_KEY_HASH_BUTTON() {return new Button_object('//span/strong[text()="Key Hash "]//following::button[1]');}; 43 | get KEY_ID_BUTTON() {return new Button_object('//span/strong[text()="Key ID "]//following::button[1]');}; 44 | get COPY_KEY_ID_BUTTON() {return $$('.tyk-button--no-style')[1];} 45 | get OK_BUTTON() {return new Button_object('span*=OK');} 46 | 47 | 48 | //Update Key modal 49 | get UPDATE_KEY_MODAL() {return $('.opened .tyk-modal__content');} 50 | get CONFIRM_BUTTON() {return new Button_object('//div[@class="tyk-modal__content"]//button//span[text()="Confirm"]');} 51 | get CANCEL_BUTTON() {return new Button_object('//div[@class="tyk-modal__content"]//button//span[text()="Cancel"]');} 52 | get DELETE_KEY_MODAL() {return $('.tyk-modal__content');} 53 | get DELETE_KEY_CONFIRMATION_BUTTON() {return new Button_object('//div[contains(@class,"opened")]//div[@class="tyk-modal__content"]//button//span[text()="Confirm"]');} 54 | 55 | 56 | get key_updated_expected_message() {return 'Key has been successfully updated';} 57 | get key_deleted_expected_message() {return 'Key has been successfully deleted';} 58 | get key_created_expected_message() {return 'Key has been successfully created';} 59 | get key_not_retrive_detail_message() {return 'Could not retrieve key detail';} 60 | 61 | isKeyUpdatedPopUpDisplayed() {return this.isSuccessPopupDisplayedWithText(this.key_updated_expected_message);} 62 | isKeyDeletedPopUpDisplayed() {return this.isSuccessPopupDisplayedWithText(this.key_deleted_expected_message);} 63 | isKeyCreatedPopUpDisplayed() {return this.isSuccessPopupDisplayedWithText(this.key_created_expected_message);} 64 | isCouldNotRetrieveKeyDisplayed() {return this.isErrorPopupDisplayedWithText(this.key_not_retrive_detail_message);} 65 | } 66 | export const keys_page = new Keys_page(); 67 | 68 | -------------------------------------------------------------------------------- /lib/pom/Login_page.js: -------------------------------------------------------------------------------- 1 | var Page = require('./Page'); 2 | import { URL, USER_EMAIL, USER_PASSWORD } from './../../config_variables'; 3 | 4 | class Login_page extends Page { 5 | get USERNAME_INPUT() {return $('input[name="username"]');} 6 | get PASSWORD_INPUT() {return $('input[name="password"]');} 7 | get LOGIN_BUTTON() {return $('button[type="submit"]');} 8 | 9 | open() { 10 | super.open(URL); 11 | } 12 | 13 | login(userName = USER_EMAIL, password = USER_PASSWORD) { 14 | console.debug(`Login as ${userName} and pass: ${password}`); 15 | this.USERNAME_INPUT.setValue(userName); 16 | this.PASSWORD_INPUT.setValue(password); 17 | 18 | this.LOGIN_BUTTON.click(); 19 | } 20 | 21 | waitUntilPageLoaded() { 22 | super.waitUntilPageLoaded(this.EMAIL_INPUT); 23 | } 24 | } 25 | export const login_page = new Login_page(); 26 | -------------------------------------------------------------------------------- /lib/pom/Main_page.js: -------------------------------------------------------------------------------- 1 | var Page = require('./Page'); 2 | var Button_object = require('ui_test_automation/wrappers/Button_object'); 3 | import { URL, LOGOUT_PATH } from './../../config_variables'; 4 | 5 | class Main_page extends Page { 6 | get PAGE_H1() {return $('h1*=API Activity Dashboard');} 7 | 8 | //NAVIGATION 9 | get APIs_NAVIAGTION_BUTTON() {return new Button_object('a[href="/apis"]');} 10 | get KEYS_NAVIAGTION_BUTTON() {return new Button_object('a[href="/keys"]');} 11 | get POLICIES_NAVIAGTION_BUTTON() {return new Button_object('a[href="/policies"]');} 12 | get USERS_NAVIAGTION_BUTTON() {return new Button_object('a[href="/users"]');} 13 | get SETTINGS_NAVIAGTION_BUTTON() {return new Button_object('a[href="/portal-configuration"]');} 14 | get TIB_NAVIGATION_BUTTON() {return new Button_object('a[href="/tib/profiles"]');} 15 | get WEBHOOKS_NAVIGATION_BUTTON() {return new Button_object('a[href="/webhooks"]');} 16 | get CATALOGUE_NAVIGATION_BUTTON() {return new Button_object('a[href="/portal-catalogue"]');} 17 | 18 | 19 | openAPIs() { 20 | this.APIs_NAVIAGTION_BUTTON.click(); 21 | } 22 | 23 | openKeys() { 24 | this.KEYS_NAVIAGTION_BUTTON.click(); 25 | } 26 | 27 | openPolicies() { 28 | this.POLICIES_NAVIAGTION_BUTTON.click(); 29 | } 30 | 31 | openUsers() { 32 | this.USERS_NAVIAGTION_BUTTON.click(); 33 | } 34 | 35 | openPortalSettings() { 36 | this.SETTINGS_NAVIAGTION_BUTTON.click(); 37 | } 38 | 39 | openIdentityManagement() { 40 | this.TIB_NAVIGATION_BUTTON.click(); 41 | } 42 | 43 | waitUntilPageLoaded() { 44 | return super.waitUntilPageLoaded(this.PAGE_H1); 45 | } 46 | 47 | logOut() { 48 | browser.url(URL + LOGOUT_PATH); 49 | } 50 | 51 | openWebhooks() { 52 | this.WEBHOOKS_NAVIGATION_BUTTON.click(); 53 | } 54 | 55 | openCatalogue(){ 56 | this.CATALOGUE_NAVIGATION_BUTTON.click(); 57 | } 58 | 59 | } 60 | export const main_page = new Main_page(); -------------------------------------------------------------------------------- /lib/pom/Page.js: -------------------------------------------------------------------------------- 1 | class Page { 2 | get SUCCESS_POP_UPS_LIST() {return $$('.tyk-message--success');} 3 | get ERROR_POP_UPS_LIST() {return $$('.tyk-message--danger');} 4 | 5 | constructor() { 6 | console.log('Creating new page object model'); 7 | } 8 | 9 | open(path) { 10 | console.log('>> Opening page ' + path); 11 | browser.url(path); 12 | } 13 | 14 | waitUntilPageLoaded(webElementOnPage, timeout) { 15 | return webElementOnPage.waitForExist({ timeout: timeout, timeoutMsg: 'Page not loaded! Element not visible!'}); 16 | } 17 | 18 | isSuccessPopupDisplayedWithText(text) { 19 | console.debug(`>>> Looking for popup with text ${text}`); 20 | try { 21 | browser.waitUntil( () => 22 | this.SUCCESS_POP_UPS_LIST.filter(popup => popup.getText() === text).length > 0 23 | ); 24 | } 25 | catch(e) { 26 | console.debug(`Popup with text ${text} was not displayed`); 27 | return false; 28 | } 29 | return true; 30 | } 31 | 32 | isErrorPopupDisplayedWithText(text) { 33 | console.debug(`>>> Looking for error popup with text ${text}`); 34 | wdioExpect(this.ERROR_POP_UPS_LIST).toBeElementsArrayOfSize({ gte: 1 }); //checking if at least one pop up is displayed 35 | console.debug(`>>> Count of displayed error popups: ${this.ERROR_POP_UPS_LIST.length}`); 36 | const popUpsWithExpectedText = this.ERROR_POP_UPS_LIST.filter(popup => { 37 | console.log(`>>> error popup text: ${popup.getText()}`); 38 | return popup.getText() === text; 39 | } 40 | ); 41 | return popUpsWithExpectedText.length >= 1; 42 | } 43 | 44 | isErrorPopUpDisplayed() { 45 | try { 46 | browser.waitUntil( () => this.ERROR_POP_UPS_LIST.length > 0); 47 | return true; 48 | } catch(e) { 49 | return false;} 50 | } 51 | 52 | getErrorPopUpText() { 53 | return this.ERROR_POP_UPS_LIST.map(popup => popup.getText()); 54 | } 55 | } 56 | 57 | module.exports = Page; -------------------------------------------------------------------------------- /lib/pom/Tib_page.js: -------------------------------------------------------------------------------- 1 | var Page = require('./Page'); 2 | var Button_object = require('ui_test_automation/wrappers/Button_object'); 3 | var DropDown_object = require('ui_test_automation/wrappers/DropDown_object'); 4 | var Input_object = require('ui_test_automation/wrappers/Input_object'); 5 | 6 | class Tib_page extends Page { 7 | get CREATE_PROFILE_BUTTON() {return new Button_object('span*=Create Profile');} 8 | get PROFILE_NAME_INPUT() {return new Input_object('input[label="Name"]');} 9 | get PROFILE_NEXT_BUTTON() {return new Button_object('(//span[text()="Next"])[1]');} 10 | get PROVIDER_NEXT_BUTTON() {return new Button_object('(//span[text()="Next"])[2]');} 11 | get SAML_CERTIFICATE_DROPDOWN() {return new DropDown_object('span=Select a certificate');} 12 | get SAML_URL_INPUT() {return new Input_object('input[name="ProviderConfig.IDPMetaDataURL"]');} 13 | get LDAP_SERVER_INPUT() {return new Input_object('input[name="ProviderConfig.LDAPServer"]');} 14 | get LDAP_PORT_INPUT() {return new Input_object('input[name="ProviderConfig.LDAPPort"]');} 15 | get LDAP_USERDN_INPUT() {return new Input_object('input[name="ProviderConfig.LDAPUserDN"]');} 16 | get OICD_CLIENT_ID_INPUT() {return new Input_object('input[name="ProviderConfig.UseProviders[0].Key"]');} 17 | get OICD_CLIENT_SECRET_INPUT() {return new Input_object('input[name="ProviderConfig.UseProviders[0].Secret"]');} 18 | get OICD_DISCOVER_URL_INPUT() {return new Input_object('input[name="ProviderConfig.UseProviders[0].DiscoverURL"]');} 19 | get SOCIAL_POLICY_DROPDOWN() {return $('span=Select policy');} 20 | get SOCIAL_PROVIDER_DROPDOWN() {return new DropDown_object('span=Select a provider');} 21 | get SOCIAL_CLIENT_ID_INPUT() {return new Input_object('input[name="ProviderConfig.UseProviders[0].Key"]');} 22 | get SOCIAL_CLIENT_SECRET_INPUT() {return new Input_object('input[name="ProviderConfig.UseProviders[0].Secret"]');} 23 | 24 | selectProviderByName(name) { 25 | $(`//label[text()="${name}"]`).click(); 26 | } 27 | 28 | selectFirstPolicyFromDropdown() { 29 | $('.tyk-combobox2__combobox-list').$$('li')[0].click(); 30 | } 31 | 32 | get profile_created_expected_mesage() {return 'Profile created successfully';} 33 | isProfileCreatedPopUpDisplayed() {return this.isSuccessPopupDisplayedWithText(this.profile_created_expected_mesage);} 34 | } 35 | export const tib_page = new Tib_page(); -------------------------------------------------------------------------------- /lib/pom/Users_page.js: -------------------------------------------------------------------------------- 1 | var Page = require('./Page'); 2 | var Button_object = require('ui_test_automation/wrappers/Button_object'); 3 | var Checkbox_object = require('ui_test_automation/wrappers/Checkbox_object'); 4 | var Table_object = require('ui_test_automation/wrappers/Table_object'); 5 | var DropDown_object = require('ui_test_automation/wrappers/DropDown_object'); 6 | var Input_object = require('ui_test_automation/wrappers/Input_object'); 7 | 8 | class Users_page extends Page { 9 | //MAIN PAGE 10 | get ADD_USER_BUTTON() {return new Button_object('span*= Add user');} 11 | get USERS_TABLE() {return new Table_object('.tyk-table');} 12 | 13 | //ADD/EDIT USER PAGE 14 | get SAVE_BUTTON() {return new Button_object('span=Save');} 15 | get UPDATE_BUTTON() {return new Button_object('span=Update');} 16 | get DELETE_BUTTON() {return new Button_object('span=Delete');} 17 | get FIRST_NAME_INPUT() {return new Input_object('input[name="first_name"]');} 18 | get LAST_NAME_INPUT() {return new Input_object('input[name="last_name"]');} 19 | get EMAIL_ADRESS_INPUT() {return new Input_object('input[name="email_address"]');} 20 | get PASSWORD_INPUT() {return new Input_object('input[name="password"]');} 21 | get ACCOUNT_IS_ACTIVE_CHECKBOX() {return new Checkbox_object('input[name=active]');} 22 | get ACCOUNT_IS_ADMIN_CHECKBOX() {return new Checkbox_object('input[name=admin]');} 23 | get USER_GROUP_DROPDOWN() {return new DropDown_object('.tyk-combobox2__text-value');} 24 | 25 | //PERMISSION 26 | get PERMISSIONS_ANALYTICS_ROW() {return $(`input[name="user_permissions.analytics"]`);} 27 | 28 | //MODALS 29 | get MODAL() {return $('.opened .tyk-modal__content');} 30 | get UPDATE_CONFIRMATION_BUTTON() {return $('//div[@class="tyk-modal__content"]//button//span[text()="Update"]');} 31 | get DELETE_CONFIRMATION_BUTTON() {return $('//div[@class="tyk-modal__content"]//button//span[text()="Delete"]');} 32 | get CONFIRM_BUTTON() {return $('//div[contains(@class,"opened")]//div[@class="tyk-modal__content"]//button//span[text()="Confirm"]');} 33 | 34 | get user_created_expected_mesage() {return 'User added successfully';} 35 | get user_updated_expected_mesage() {return 'User updated successfully';} 36 | get user_already_exists_expected_mesage() {return 'User email already exists for this Org';} 37 | 38 | waitUntilPageLoaded() { 39 | return super.waitUntilPageLoaded(this.ADD_POLICY_BUTTON); 40 | } 41 | 42 | isUserCreatedPopUpDisplayed() {return this.isSuccessPopupDisplayedWithText(this.user_created_expected_mesage);} 43 | 44 | isUserUpdatedPopUpDisplayed() {return this.isSuccessPopupDisplayedWithText(this.user_updated_expected_mesage);} 45 | 46 | isUserAlreadyExistsPopUpDisplayed() {return this.isErrorPopupDisplayedWithText(this.user_already_exists_expected_mesage);} 47 | 48 | selectReadAccessForPermission(permissionName) { 49 | const $$radioButtons = $$(`input[name="user_permissions.${permissionName}"]`); 50 | wdioExpect($$radioButtons).toBeElementsArrayOfSize({gte: 2}); 51 | $$radioButtons[1].waitForClickable(); 52 | $$radioButtons[1].click(); 53 | browser.pause(1000); 54 | if ($$radioButtons[1].getValue() !== 'read'){ 55 | $$radioButtons[1].click(); 56 | } 57 | wdioExpect($$radioButtons[1]).toHaveValue('read'); 58 | } 59 | } 60 | export const users_page = new Users_page(); -------------------------------------------------------------------------------- /lib/pom/Webhooks_page.js: -------------------------------------------------------------------------------- 1 | var Page = require('./Page'); 2 | var Button_object = require('ui_test_automation/wrappers/Button_object'); 3 | var Table_object = require('ui_test_automation/wrappers/Table_object'); 4 | var DropDown_object = require('ui_test_automation/wrappers/DropDown_object'); 5 | var Input_object = require('ui_test_automation/wrappers/Input_object'); 6 | 7 | class Webhooks_page extends Page { 8 | 9 | get ADD_WEBHOOK() {return new Button_object('span*=Add Webhook');} 10 | get NAME_INPUT() {return new Input_object('input[name="name"]');} 11 | get REQUEST_METHOD_DROPDOWN() {return new DropDown_object('.tyk-select');} 12 | get TARGET_INPUT() {return new Input_object('input[name="target_path"]');} 13 | get HEADER_KEY() {return new Input_object('input[name="key"]');} 14 | get HEADER_VALUE() {return new Input_object('input[name="value"]');} 15 | get ADD_HEADER_BUTTON() {return new Button_object('span*=ADD');} 16 | get SAVE_BUTTON() {return new Button_object('span*=Save');} 17 | get UPDATE_BUTTON() {return new Button_object('span*=Update');} 18 | get DELETE_BUTTON() {return new Button_object('span*=Delete');} 19 | get DELETE_KEY_CONFIRMATION_BUTTON() {return new Button_object('//div[contains(@class,"opened")]//div[@class="tyk-modal__content"]//button//span[text()="Delete"]');} 20 | 21 | //Table 22 | get WEBHOOK_TABLE() {return new Table_object('.tyk-table');} 23 | get NO_DATA_TO_DISPLAY() {return $('.tyk-message--info');} 24 | } 25 | 26 | export const webhook_page = new Webhooks_page(); -------------------------------------------------------------------------------- /lib/utils/API_object_designer.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | export const newAPIdefinitionWithDefaults = (apiDetails) => { 4 | const defaultApiDefinition = new API_object_designer(); 5 | defaultApiDefinition.mergeWithJson(apiDetails); 6 | return defaultApiDefinition.api_object; 7 | }; 8 | 9 | export default class API_object_designer { 10 | 11 | constructor(){ 12 | const json = require('./api_object'); 13 | this.api_object = {...json}; //saving values, not link to a file (no caching) 14 | } 15 | 16 | mergeWithJson(apiDetails) { 17 | this.mergedApiDefinition = {...this.api_object.api_definition, ...apiDetails}; 18 | this.api_object.api_definition = this.mergedApiDefinition; 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /lib/utils/Policy_object_designer.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | export const newPolicyDefinitionWithDefaults = (policyDetails) => { 4 | const defaultPolicyDefinition = new Policy_object_designer(); 5 | defaultPolicyDefinition.mergeWithJson(policyDetails); 6 | return defaultPolicyDefinition.policy_object; 7 | }; 8 | 9 | export default class Policy_object_designer { 10 | 11 | constructor(){ 12 | const json = require('./policy_object'); 13 | this.policy_object = {...json}; //saving values, not link to a file (no caching) 14 | } 15 | 16 | mergeWithJson(policyDetails) { 17 | this.mergedPolicyDefinition = {...this.policy_object, ...policyDetails}; 18 | this.policy_object = this.mergedPolicyDefinition; 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /lib/utils/api_connections/API_connection.js: -------------------------------------------------------------------------------- 1 | const superagent = require('superagent'); 2 | const config_variables = require('../../../config_variables'); 3 | const Promise = require('bluebird'); 4 | 5 | const timeoutMs = 5000; 6 | 7 | export class API_connection { 8 | constructor(url) { 9 | this.url = url; 10 | } 11 | 12 | sendGetRequest(config) { 13 | console.debug(`>>> Sending GET request to ${this.url}${config.path}`); 14 | const response = browser.call(() => this.sendGetRequestPromise(config).timeout(timeoutMs)); 15 | return response; 16 | }; 17 | 18 | sendPostRequest(config) { 19 | console.debug(`>>> Sending POST request to ${this.url}${config.path}, body: ${config.body}`); 20 | const response = browser.call(() => this.sendPostRequestPromise(config).timeout(timeoutMs)); 21 | return response; 22 | }; 23 | 24 | sendPutRequest(config) { 25 | console.debug(`>>> Sending PUT request to ${this.url}${config.path}, body: ${config.body}`); 26 | const response = browser.call(() => this.sendPutRequestPromise(config).timeout(timeoutMs)); 27 | return response; 28 | }; 29 | 30 | sendDeleteRequest(config) { 31 | console.debug(`>>> Sending DELETE request to ${this.url}${config.path}, param: ${config.param}`); 32 | const response = browser.call(() => this.sendDeleteRequestPromise(config).timeout(timeoutMs)); 33 | return response; 34 | }; 35 | 36 | sendGetRequestPromise(config) { 37 | return new Promise( (resolve, reject) => { 38 | console.debug(`>>> Sending request to ${this.url}${config.path}`); 39 | superagent 40 | .get(this.url + config.path) 41 | .set(config.headers) 42 | .disableTLSCerts() 43 | .then((response) => { 44 | console.debug(`>>> response status: ${response.status}`); 45 | resolve(response);}) 46 | .catch( err => {console.log(err); reject;}); 47 | 48 | }); 49 | }; 50 | 51 | sendPostRequestPromise(config) { 52 | if (config.headers === undefined) {config.headers = {};} 53 | return new Promise( (resolve, reject) => { 54 | console.debug(`>>> Sending request to ${this.url}${config.path}`); 55 | superagent 56 | .post(this.url + config.path) 57 | .send(config.body) 58 | .set(config.headers) 59 | .attach('cert', config.file) 60 | .disableTLSCerts() 61 | .then((response) => { 62 | console.debug(`>>> response status: ${response.status}`); 63 | resolve(response);}) 64 | .catch( err => {console.log(err);}); 65 | 66 | }); 67 | }; 68 | 69 | sendPutRequestPromise(config) { 70 | if (config.headers === undefined) {config.headers = {};} 71 | return new Promise( (resolve, reject) => { 72 | console.debug(`>>> Sending PUT request to ${this.url}${config.path}`); 73 | superagent 74 | .put(this.url + config.path) 75 | .send(config.body) 76 | .set(config.headers) 77 | .disableTLSCerts() 78 | .then((response) => { 79 | console.debug(`>>> response status: ${response.status}`); 80 | resolve(response);}) 81 | .catch( err => {console.log(err);}); 82 | 83 | }); 84 | }; 85 | 86 | sendDeleteRequestPromise(config) { 87 | if (config.headers === undefined) {config.headers = {};} 88 | return new Promise( (resolve, reject) => { 89 | console.debug(`>>> Sending request to ${this.url}${config.path}`); 90 | superagent 91 | .del(this.url + config.path) 92 | .send(config.param) 93 | .set(config.headers) 94 | .disableTLSCerts() 95 | .then((response) => { 96 | console.debug(`>>> response status: ${response.status}`); 97 | resolve(response);}) 98 | .catch( err => {console.log(err);}); 99 | }); 100 | }; 101 | }; -------------------------------------------------------------------------------- /lib/utils/api_connections/Dashboard_admin_connection.js: -------------------------------------------------------------------------------- 1 | var { API_connection } = require('./API_connection'); 2 | const config_variables = require('../../../config_variables'); 3 | 4 | export class Dashboard_admin_connection extends API_connection { 5 | constructor(){ 6 | super(config_variables.DASHBOARD_ADMIN_API); 7 | } 8 | 9 | createOrg(body, headers) { 10 | const response = this.sendPostRequest({path: config_variables.ORG_API_PATH, body, headers}); 11 | expect(response.status).to.equal(200, 'Organisation was not created!'); 12 | console.debug(`New organization was created: ${response.body}`); 13 | return response.body.Meta; 14 | } 15 | 16 | getStatus(headers) { 17 | console.log(">>> Checking is dashboard is up"); 18 | const response = this.sendGetRequest({path: config_variables.HELLO_PATH, headers}); 19 | return response; 20 | } 21 | 22 | // getOrgsWithName(orgName = config_variables.ORG_NAME) { 23 | // const response = this.sendGetRequest({path: this.ORG_PREFIX}); 24 | // const orgList = response.body.organisations; 25 | // console.debug(`>>> Number of created Organisations: ${orgList.length}`); 26 | // return orgList.filter((org) => org.cname === orgName); 27 | // }; 28 | 29 | // prepareConfig(config) { 30 | // if (config.headers === undefined) {config.headers = {};} 31 | // if (config.headers["admin-auth"] === undefined) { 32 | // config.headers["admin-auth"] = config_variables.ADMIN_SECRET; 33 | // }; 34 | // return config; 35 | // } 36 | } 37 | -------------------------------------------------------------------------------- /lib/utils/api_connections/Dashboard_connection.js: -------------------------------------------------------------------------------- 1 | var { API_connection } = require('./API_connection'); 2 | const config_variables = require('../../../config_variables'); 3 | const fs = require('fs'); 4 | 5 | export class Dashboard_connection extends API_connection { 6 | constructor(){ 7 | super(config_variables.DASHBOARD_API); 8 | } 9 | 10 | getUserWithEmail(userEmail, secret) { 11 | console.debug(`>>> Getting user with email ${userEmail}`); 12 | const response = this.sendGetRequest({path: config_variables.USERS_API_PATH, Authorization: secret}); 13 | const usersList = response.body.users; 14 | console.debug(usersList); 15 | return usersList.filter((user) => user.email_address === userEmail); 16 | } 17 | 18 | createAPI(apiDefinition, userSecret){ 19 | console.log(`>>> Creating API with name: ${apiDefinition.api_definition.name}`); 20 | const config = { 21 | path: "apis/", 22 | body: apiDefinition, 23 | headers: {Authorization: userSecret} 24 | }; 25 | const response = this.sendPostRequest(config); 26 | expect(response.status).to.equal(200, 'Failed to create API definition!'); 27 | console.log(`>>> API created. API definition id: ${response.body.Meta}`); 28 | return response.body.Meta; 29 | } 30 | 31 | getAPI(meta, userSecret){ 32 | console.log(`>>> Get API for meta: ${meta}`); 33 | const config = { 34 | path: "apis/" + meta, 35 | headers: {Authorization: userSecret} 36 | }; 37 | const response = this.sendGetRequest(config); 38 | expect(response.status).to.equal(200, 'Failed to retrieve API details!'); 39 | console.log(`>>> API received. API definition: ${response.body}`); 40 | return response.body.api_definition; 41 | } 42 | 43 | createPolicy(policyDefinition, userSecret){ 44 | console.log(`>>> Creating Policy with name: ${policyDefinition.name}`); 45 | const config = { 46 | path: "portal/policies/", 47 | body: policyDefinition, 48 | headers: {Authorization: userSecret} 49 | }; 50 | const response = this.sendPostRequest(config); 51 | expect(response.status).to.equal(200, 'Failed to create Policy definition!'); 52 | console.log(`>>> Policy created. Policy definition id: ${response.Meta}`); 53 | } 54 | 55 | getPolicyByName(name, userSecret){ 56 | console.log(`>>> Get Policy by name: ${name}`); 57 | const config = { 58 | path: "portal/policies/search/?q=" + name, 59 | headers: {Authorization: userSecret} 60 | }; 61 | const response = this.sendGetRequest(config); 62 | expect(response.status).to.equal(200, 'Failed to retrieve Policy details!'); 63 | console.log(`>>> Policy received. Policy definition: ${response.body}`); 64 | return response.body; 65 | } 66 | 67 | uploadCert(certFile, userSecret){ 68 | console.log('>>> Uploading Certificate'); 69 | const config = { 70 | path: "certs/", 71 | file: certFile, 72 | headers: { Authorization: userSecret } 73 | }; 74 | const response = this.sendPostRequest(config); 75 | expect(response.status).to.equal(200, 'Failed to upload Certificate!'); 76 | console.log(`>>> Certificate added. Cert id: ${response.id}`); 77 | } 78 | 79 | prepareConfig(config) { 80 | if (config.headers === undefined) {config.headers = {};} 81 | config.headers.Authorization = config_variables.USER_SECRET; 82 | return config; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/utils/api_object.json: -------------------------------------------------------------------------------- 1 | { 2 | "api_definition": { 3 | "name": "test1", 4 | "slug": "test1", 5 | "use_keyless": true, 6 | "auth": { 7 | "auth_header_name": "Authorization" 8 | }, 9 | "definition": { 10 | "location": "header", 11 | "key": "x-api-version" 12 | }, 13 | "version_data": { 14 | "not_versioned": true, 15 | "versions": { 16 | "Default": { 17 | "name": "Default", 18 | "use_extended_paths": true} 19 | } 20 | }, 21 | "proxy": { 22 | "listen_path": "", 23 | "target_url": "http://httpbin.org/", 24 | "strip_listen_path": true 25 | }, 26 | "active": true 27 | } 28 | } -------------------------------------------------------------------------------- /lib/utils/federation_example.js: -------------------------------------------------------------------------------- 1 | import { exec } from 'child_process'; 2 | const bashCmdExecutor = require('child_process').exec; 3 | import { API_connection } from './api_connections/API_connection'; 4 | 5 | const federationExampleTestUrl = "http://localhost:4000/"; 6 | const api_connection = new API_connection(federationExampleTestUrl); 7 | const expectedFederationResponse = { data: { me: { id: '1234' } } }; 8 | const federationTestRequestConfig = { 9 | path: "query", 10 | body: `{"query":"query{me{id}}","variables":{}}` 11 | }; 12 | 13 | export const prepareFederationExampleUpstream = () => { 14 | let isUpstreamRunning = waitForFederationUpstream(); 15 | if (isUpstreamRunning) { 16 | return true; 17 | }; 18 | if(!checkIfFederationFilesExists()) { 19 | console.error(`Federation file "start.sh" does NOT exist!`); 20 | return false; 21 | } 22 | 23 | console.log('>>> Running Federation example'); 24 | const logs = bashCmdExecutor('(cd graphql-go-tools/examples/federation ; ./start.sh)').stdout.pipe(process.stdout); 25 | console.log("<<<< logs: " + logs) 26 | return waitForFederationUpstream(20); 27 | }; 28 | 29 | const checkIfFederationFilesExists = () => { 30 | console.log('>>> Checking presence of federation start.sh file'); 31 | exec('ls graphql-go-tools/examples/federation | grep start.sh', (error, stdout, stderr) => { 32 | if(error){ 33 | console.error(`>>> Files in federation folder: ${stdout}`); 34 | console.error('>>> Error: ', error.message); 35 | return false; 36 | } 37 | }); 38 | console.log(`>>> Federation file "start.sh" exists`); 39 | return true; 40 | }; 41 | 42 | const waitForFederationUpstream = (retryMaxCount = 1) => { 43 | let retryNumber = 1; 44 | let isRunning = false; 45 | 46 | while(!isRunning && retryNumber <= retryMaxCount){ 47 | let response; 48 | console.log(`>>> Starting connection try number ${retryNumber}`); 49 | try { 50 | response = api_connection.sendPostRequest({path: federationTestRequestConfig.path, body: federationTestRequestConfig.body}); 51 | if(JSON.stringify(response.body) === JSON.stringify(expectedFederationResponse)) { 52 | console.log('>> Federation upstream works'); 53 | return true; 54 | } 55 | } catch (error) { 56 | console.error('Federation example not running. Trying again. ' + error); 57 | } 58 | retryNumber++; 59 | } 60 | return isRunning; 61 | }; -------------------------------------------------------------------------------- /lib/utils/policy_object.json: -------------------------------------------------------------------------------- 1 | { 2 | "last_updated": "0001-01-01T00:00:00Z", 3 | "rate": 1000, 4 | "per": 60, 5 | "quota_max": -1, 6 | "quota_renews": 1481546970, 7 | "quota_remaining": 0, 8 | "quota_renewal_rate": 60, 9 | "access_rights": { 10 | "35447b1469df4e846894b1e87372f6d7": { 11 | "api_id": "35447b1469df4e846894b1e87372f6d7", 12 | "api_name": "My API", 13 | "versions": ["Default"] 14 | } 15 | }, 16 | "name": "test policy", 17 | "active": true 18 | } -------------------------------------------------------------------------------- /lib/utils/prerequisites.js: -------------------------------------------------------------------------------- 1 | import { Dashboard_admin_connection } from './api_connections/Dashboard_admin_connection'; 2 | import * as config_variables from '../../config_variables'; 3 | import { uuid } from 'uuidv4'; 4 | import { generateRandomEmail } from './utils'; 5 | 6 | export const setUpEnv = () => { 7 | if (!config_variables.CLEAN_TEST) { //returning default values from config 8 | log.debug(`>>> $CLEAN_TEST set to false -> tests will re-use already created org and user`); 9 | return { 10 | userEmail: config_variables.USER_EMAIL, 11 | userPassword: config_variables.USER_PASSWORD, 12 | userSecret: config_variables.USER_SECRET 13 | }; 14 | } 15 | 16 | const dashboard_admin_request = new Dashboard_admin_connection(); 17 | const authorizationHeader = {"admin-auth": config_variables.ADMIN_SECRET}; 18 | const orgCname = config_variables.ORG_NAME + uuid(); 19 | const adminEmail = generateRandomEmail(); 20 | const adminPassword = config_variables.USER_PASSWORD; 21 | 22 | //CHECKING IF ENV IS UP 23 | const statusResponse = dashboard_admin_request.getStatus(authorizationHeader); 24 | expect(statusResponse.status).to.equal(200, "Dashboard is down!"); 25 | //PREPARING ORG 26 | console.debug(`>>> Preparing new ${orgCname} organization`); 27 | const testOrgBody = {"cname": orgCname,"cname_enabled": true,"owner_name": "test-org1","owner_slug": "default"}; 28 | const orgID = dashboard_admin_request.createOrg(testOrgBody, authorizationHeader); 29 | //PREPARING ADMIN USER 30 | const adminUserBody = { 31 | "active": true, 32 | "email_address": adminEmail, 33 | "first_name": "auto", 34 | "last_name": "admin", 35 | "org_id": orgID, 36 | "user_permissions": { "IsAdmin": "admin" } 37 | }; 38 | const adminUserResponse = dashboard_admin_request 39 | .sendPostRequest({path: config_variables.USERS_API_PATH, body: adminUserBody, headers: authorizationHeader}); 40 | const adminUserSecret = adminUserResponse.body.Message; 41 | const adminUserID = adminUserResponse.body.Meta.id; 42 | //UPDATE PASSWORD FOR USER 43 | const adminUserPasswordBody = { 44 | "active": true, 45 | "email_address": adminEmail, 46 | "first_name": "auto", 47 | "last_name": "admin", 48 | "org_id": orgID, 49 | "password": adminPassword, 50 | "user_permissions": { "IsAdmin": "admin" } 51 | }; 52 | const updatePath = `${config_variables.USERS_API_PATH}${adminUserID}`; 53 | dashboard_admin_request.sendPutRequest({path: updatePath, body: adminUserPasswordBody, headers: authorizationHeader}); 54 | 55 | console.log(`User was created: ${adminEmail}, secret: ${adminUserSecret}, organization: ${orgCname}`); 56 | return { userEmail: adminEmail, userPassword: adminPassword, userSecret: adminUserSecret}; 57 | }; 58 | -------------------------------------------------------------------------------- /lib/utils/utils.js: -------------------------------------------------------------------------------- 1 | import { exec } from 'child_process'; 2 | import moment from 'moment'; 3 | const bashCmdExecutor = require('child_process').exec; 4 | import { API_connection } from './api_connections/API_connection'; 5 | const randomEmailGenerator = require('random-email'); 6 | 7 | /** generating random email in format name+11-Feb-9_39_41@example.com 8 | * @function 9 | * @return {string} random email 10 | **/ 11 | export const generateRandomEmail = () => { 12 | const randomEmail = randomEmailGenerator({ domain: 'example.com' }); 13 | return randomEmail.replace('@', `+${moment().format('h_mm_ss')}@`); 14 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dashboard_ui_tests", 3 | "version": "1.0.0", 4 | "description": "Framework for Dashboard UI automated tests", 5 | "main": "index.js", 6 | "scripts": { 7 | "notify-slack": "node ./node_modules/ui_test_automation/utils/SlackNotification.js", 8 | "headless-test": "WDIO_HEADLESS=1 npm test", 9 | "generate-coverage-doc": "PATH_TO_RESULTS=`PWD`/results/json/wdio-merged.json node ./node_modules/ui_test_automation/utils/GenerateCoverageDoc.js", 10 | "test": "npx wdio wdio.conf.js" 11 | }, 12 | "keywords": [], 13 | "author": "Konrad Soltys", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "@babel/core": "^7.16.0", 17 | "@babel/preset-env": "^7.16.4", 18 | "@babel/register": "^7.16.0", 19 | "@wdio/cli": "^6.12.1", 20 | "@wdio/local-runner": "^6.12.1", 21 | "@wdio/mocha-framework": "^6.11.0", 22 | "@wdio/spec-reporter": "^6.11.0", 23 | "@wdio/sync": "^6.11.0", 24 | "chai": "^4.3.4", 25 | "chromedriver": "111.0.0", 26 | "eslint": "^7.32.0", 27 | "eslint-plugin-wdio": "^6.0.12", 28 | "timediff": "^1.1.1", 29 | "ui_test_automation": "git+https://github.com/TykTechnologies/ui_test_automation.git#main", 30 | "wdio-chromedriver-service": "^7.2.2", 31 | "wdio-json-reporter": "^2.0.0", 32 | "wdio-spec-reporter": "^0.1.5" 33 | }, 34 | "dependencies": { 35 | "babel-eslint": "^10.1.0", 36 | "bluebird": "^3.7.2", 37 | "dotenv": "^8.6.0", 38 | "expect": "^26.6.2", 39 | "expect-webdriverio": "^1.4.1", 40 | "moment": "^2.27.0", 41 | "random-email": "^1.0.3", 42 | "superagent": "^6.1.0", 43 | "uuidv4": "^6.2.12", 44 | "wdio-timeline-reporter": "^5.1.3", 45 | "webdriverio": "^7.16.10" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /playwright/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // root: true, 3 | "settings": { 4 | "import/resolver": { 5 | "typescript": {} 6 | }, 7 | }, 8 | env: { 9 | browser: true, 10 | es2021: true 11 | }, 12 | plugins: [ 13 | 'playwright', 14 | "@typescript-eslint", 15 | "import", 16 | ], 17 | extends: [ 18 | `plugin:@typescript-eslint/recommended`, 19 | "eslint:recommended", 20 | "plugin:@typescript-eslint/eslint-recommended", 21 | ], 22 | parser: `@typescript-eslint/parser`, 23 | parserOptions: { 24 | ecmaVersion: 'latest', 25 | sourceType: 'module', 26 | project: './tsconfig.json', 27 | }, 28 | rules: { 29 | semi: [`error`, `always`], 30 | "@typescript-eslint/no-floating-promises": ["error"], 31 | "block-spacing": ["error"], 32 | "space-before-blocks": ["error"], 33 | "object-curly-spacing": ["error", "always", { "objectsInObjects": true }], 34 | "no-multiple-empty-lines": ["error"], 35 | "indent": ["error", 2], 36 | "no-unused-vars": ["error", { "vars": "all", "args": "after-used", "ignoreRestSiblings": false }] 37 | }, 38 | ignorePatterns: ['**/*.js'], 39 | settings: { 40 | "playwright": { 41 | "additionalAssertFunctionNames": ["toBeSelected"] 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /playwright/.gitignore: -------------------------------------------------------------------------------- 1 | # Node 2 | node_modules/ 3 | 4 | # Don't keep recordings from test runs 5 | playwright-report/ 6 | results/ 7 | *.log 8 | # Local files 9 | .DS_Store 10 | 11 | # Env files 12 | .env* 13 | 14 | #IDE settings 15 | .idea/ 16 | .vscode/* -------------------------------------------------------------------------------- /playwright/README.md: -------------------------------------------------------------------------------- 1 | # UI Automated Tests 2 | 3 | [Test coverage](coverage.md) 4 | 5 | ## Dashboard UI automation test suite based on: 6 | 7 | 1. TypeScript 8 | 2. [Playwright](https://playwright.dev/) 9 | 10 | ## How to start env 11 | You can execute tests on any env (each test will create separate org and users in it). 12 | In this repo we have simple docker compose that will build and start all components for you. Just make sure you don't have any dash or GW running on your local and you provided the dash license. 13 | 14 | Provide paths and license in .env file and execute command that will create images from your local repo: 15 | ``` 16 | make start-env 17 | ``` 18 | Or command that will images available in docker hub: 19 | ``` 20 | make start-env-images 21 | ``` 22 | ## How to run tests 23 | 1. Clone repository 24 | 2. Install Dependencies 25 | ``` 26 | npm install 27 | npx playwright install --with-deps 28 | ``` 29 | 4. Execute tests using ```npm run test``` 30 | 5. Report will be generated in playwright-report 31 | 32 | Note: You can also use VS code pluggin or ```npm run gui``` to run tests on local 33 | 34 | ## Configuration 35 | We can execute test with following variables [default values]: 36 | - URL [http://localhost:3000/] - dashboard UI url 37 | - ADMIN_SECRET [12345] - admin secrted on environment 38 | - CLEAN_TEST [true] - decide if test should be run on new Org and user 39 | 40 | Below variables will be used only if __CLEAN_TEST__ set to **false** 41 | - USER_SECRET - user_secret to be used for API calls 42 | - USER_EMAIL - email to be used for log-in 43 | - USER_PASSWORD - password to be used for log-in 44 | 45 | ## Test template 46 | For creating new tests please copy and rename **template_test.js** file into test/specs/ 47 | 48 | ## Wrappers 49 | In all UI frameworks we share the logic that encapsulate the objects on web page - we call it _wrappers_, and we store it in separate repo. 50 | If you want to add/modify _wrapper_ method please follow the instruction [here](https://github.com/TykTechnologies/tyk-test-automation-wrappers#how-to-update-wrappers) -------------------------------------------------------------------------------- /playwright/config_variables.ts: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv'; 2 | dotenv.config(); 3 | 4 | const URL = process.env.URL || "http://localhost:3000/"; 5 | const GW_URL = process.env.GW_URL || "http://localhost:8080/"; 6 | const FEDERATION_UPSTREAM_HOST = (process.env.LOCAL_PROCESS) ? "localhost" : "federation"; 7 | 8 | export const config = { 9 | CLEAN_TEST: process.env.CLEAN_TEST || true, 10 | 11 | URL: URL, 12 | GATEWAY_API: GW_URL, 13 | DASHBOARD_API: URL + 'api/', 14 | DASHBOARD_ADMIN_API: URL + 'admin/', 15 | GW_HELLO_API: GW_URL + 'hello', 16 | 17 | USER_EMAIL: process.env.USER_EMAIL || "test123@tyk.io", 18 | USER_SECRET: process.env.USER_SECRET || "", 19 | USER_PASSWORD: process.env.USER_PASSWORD || "test123", 20 | 21 | ORG_NAME: process.env.ORG_NAME || "Auto-test-org", 22 | ADMIN_SECRET: process.env.ADMIN_SECRET || "12345", 23 | 24 | ORG_API_PATH: "organisations/", 25 | USERS_API_PATH: "users/", 26 | 27 | LOGOUT_PATH: "logout/", 28 | HELLO_PATH: "hello/", 29 | 30 | FEDERATION_UPSTREAM_HOST: FEDERATION_UPSTREAM_HOST 31 | }; -------------------------------------------------------------------------------- /playwright/lib/pom/Catalogue_page.ts: -------------------------------------------------------------------------------- 1 | import { Template_Page } from './Template_Page'; 2 | import { Button_object } from '@wrappers/Button_object'; 3 | import { DropDown_object } from '@wrappers/DropDown_object'; 4 | import { Input_object } from '@wrappers/Input_object'; 5 | import { Checkbox_object } from '@wrappers/CheckBox_object'; 6 | import { Table_object } from '@wrappers/Table_object'; 7 | 8 | export class Catalogue_page extends Template_Page { 9 | //API Details tab 10 | get API_DETAILS_TAB() { return new Button_object('button:text-is("API details")', this.page); } 11 | get ADD_NEW_API_BUTTON() { return new Button_object('span:text-is("Add new API")', this.page); } 12 | get PUBLIC_API_NAME_INPUT() { return new Input_object('input[name="name"]', this.page); } 13 | get SELECT_POLICY_DROPDOWN() { return new DropDown_object('.tyk-combobox2__text-value', this.page); } 14 | get DESCRIBE_THIS_API_INPUT() { return new Input_object('[placeholder="A really cool API that provides badger widgets"]', this.page); } 15 | get CATALOGUE_OWNER_EMAIL_INPUT() { return new Input_object('input[name="config.email"]', this.page); } 16 | get UPDATE_BUTTON() { return new Button_object('span:text-is("Update")', this.page); } 17 | get SAVE_BUTTON() { return new Button_object('span:text-is("Save")', this.page); } 18 | 19 | get DELETE_BUTTON() { return new Button_object('span:text-is("Delete")', this.page); } 20 | get DELETE_KEY_MODAL() { return this.page.locator('.tyk-modal__content'); } 21 | get DELETE_KEY_CONFIRMATION_BUTTON() { return new Button_object('//div[contains(@class,"opened")]//div[@class="tyk-modal__content"]//button//span[text()="Delete"]', this.page); } 22 | get NO_APIS_REGISTERED_MESSAGE() { return this.page.getByText('No APIs registered for the portal.'); } 23 | 24 | //Settings tab 25 | get OVERRIDE_GLOBAL_SETTINGS() { return new Checkbox_object('input[name="config.override"]', this.page); } 26 | get REQUIRE_KEY_APPROVAL() { return new Checkbox_object('input[name="config.require_key_approval"]', this.page); } 27 | get REDIRECT_KEY_REQUEST_CHECKBOX() { return new Checkbox_object('input[name="config.redirect_on_key_request"]', this.page); } 28 | get SETTINGS_TAB_BUTTON() { return new Button_object('button:text-is("Settings")', this.page); } 29 | get DEVELOPER_REQUEST_FORM_CUSTOMISATION() { return new Button_object('input[name="fieldName"]', this.page); } 30 | 31 | 32 | //Custom fields section 33 | get FIELD_NAME_INPUT() { return new Input_object('input[name="field_name"]', this.page); } 34 | get FIELD_VALUE_INPUT() { return new Input_object('input[name="field_value"]', this.page); } 35 | get ADD_BUTTON() { return new Button_object('span:text-is("ADD")', this.page); } 36 | 37 | 38 | //Table 39 | get CATALOGUE_TABLE() { return new Table_object('.tyk-table', this.page); } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /playwright/lib/pom/Login_page.ts: -------------------------------------------------------------------------------- 1 | import { Template_Page } from './Template_Page'; 2 | import { config } from '@variables'; 3 | 4 | export class Login_page extends Template_Page { 5 | get USERNAME_INPUT() { return this.page.locator('input[name="username"]'); } 6 | get PASSWORD_INPUT() { return this.page.locator('input[name="password"]'); } 7 | get LOGIN_BUTTON() { return this.page.locator('button[type="submit"]'); } 8 | 9 | async open() { 10 | await super.open(config.URL); 11 | } 12 | 13 | async login(userName = config.USER_EMAIL, password = config.USER_PASSWORD) { 14 | console.debug(`>>> Login as ${userName} and pass: ${password}`); 15 | await this.USERNAME_INPUT.fill(userName); 16 | await this.PASSWORD_INPUT.fill(password); 17 | 18 | await await this.LOGIN_BUTTON.click(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /playwright/lib/pom/Main_page.ts: -------------------------------------------------------------------------------- 1 | import { Template_Page } from './Template_Page'; 2 | import { Button_object } from '@wrappers/Button_object'; 3 | import { SlowButton_object } from '@wrappers/SlowButton_object'; 4 | import { config } from '@variables'; 5 | 6 | export class Main_page extends Template_Page { 7 | //NAVIGATION 8 | get APIs_NAVIAGTION_BUTTON() { return new SlowButton_object('a[href="/apis"]', this.page); } 9 | get KEYS_NAVIAGTION_BUTTON() { return new Button_object('a[href="/keys"]', this.page); } 10 | get POLICIES_NAVIAGTION_BUTTON() { return new Button_object('a[href="/policies"]', this.page); } 11 | get USERS_NAVIAGTION_BUTTON() { return new Button_object('a[href="/users"]', this.page); } 12 | get SETTINGS_NAVIAGTION_BUTTON() { return new Button_object('a[href="/portal-configuration"]', this.page); } 13 | get TIB_NAVIGATION_BUTTON() { return new Button_object('a[href="/tib/profiles"]', this.page); } 14 | get WEBHOOKS_NAVIGATION_BUTTON() { return new Button_object('a[href="/webhooks"]', this.page); } 15 | get CATALOGUE_NAVIGATION_BUTTON() { return new Button_object('a[href="/portal-catalogue"]', this.page); } 16 | 17 | 18 | async openAPIs() { 19 | await this.APIs_NAVIAGTION_BUTTON.click(); 20 | } 21 | 22 | async openKeys() { 23 | await this.KEYS_NAVIAGTION_BUTTON.click(); 24 | } 25 | 26 | async openPolicies() { 27 | await this.POLICIES_NAVIAGTION_BUTTON.click(); 28 | } 29 | 30 | async openUsers() { 31 | await this.USERS_NAVIAGTION_BUTTON.click(); 32 | } 33 | 34 | async openPortalSettings() { 35 | await this.SETTINGS_NAVIAGTION_BUTTON.click(); 36 | } 37 | 38 | async openIdentityManagement() { 39 | await this.TIB_NAVIGATION_BUTTON.click(); 40 | } 41 | 42 | async waitUntilPageLoaded() { 43 | await super.waitUntilPageLoaded(this.APIs_NAVIAGTION_BUTTON); 44 | } 45 | 46 | async logOut() { 47 | await this.page.goto(config.URL + config.LOGOUT_PATH); 48 | } 49 | 50 | async openWebhooks() { 51 | await this.WEBHOOKS_NAVIGATION_BUTTON.click(); 52 | } 53 | 54 | async openCatalogue() { 55 | await this.CATALOGUE_NAVIGATION_BUTTON.click(); 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /playwright/lib/pom/Template_Page.ts: -------------------------------------------------------------------------------- 1 | import { Locator, Page, expect } from '@playwright/test'; 2 | import { Wrapper } from '@wrappers/Wrapper'; 3 | 4 | export class Template_Page { 5 | readonly page: Page; 6 | 7 | get SUCCESS_POP_UPS_LIST() { return this.page.locator('.tyk-message--success'); } 8 | get ERROR_POP_UPS_LIST() { return this.page.locator('.tyk-message--danger'); } 9 | 10 | constructor(page: Page) { 11 | this.page = page; 12 | } 13 | 14 | async open(path: string) { 15 | console.log('>> Opening page ' + path); 16 | await this.page.goto(path); 17 | } 18 | 19 | async waitUntilPageLoaded(webElementOnPage: Locator | Wrapper, timeout = 10000) { 20 | return await webElementOnPage.waitFor({ timeout: timeout }); 21 | } 22 | 23 | async checkIfSuccessPopupDisplayedWithText(text: string): Promise { 24 | console.debug(`>>> Looking for popup with text ${text}`); 25 | await this.SUCCESS_POP_UPS_LIST.first().waitFor(); 26 | await expect.poll( async () => { 27 | const popUps = await this.SUCCESS_POP_UPS_LIST.all(); 28 | for (const popUp of popUps) { 29 | console.debug(`>>> success popup text: ${await popUp.textContent()}`); 30 | if (await popUp.textContent() === text) { 31 | return true; 32 | } 33 | } 34 | return false; 35 | }).toBeTruthy(); 36 | } 37 | 38 | async isErrorPopupDisplayedWithText(text: string): Promise { 39 | console.debug(`>>> Looking for popup with text ${text}`); 40 | await expect.poll( async () => { 41 | await this.ERROR_POP_UPS_LIST.first().waitFor(); 42 | const popUps = await this.ERROR_POP_UPS_LIST.all(); 43 | for (const popUp of popUps) { 44 | console.debug(`>>> success popup text: ${await popUp.textContent()}`); 45 | if (await popUp.textContent() === text) { 46 | return true; 47 | } 48 | } 49 | return false; 50 | }).toBeTruthy(); 51 | } 52 | 53 | async checkIfErrorPopUpDisplayed() { 54 | await expect.poll( async () => { 55 | if (await this.ERROR_POP_UPS_LIST.count() > 0) { 56 | return true; 57 | } 58 | return false; 59 | }).toBeTruthy(); 60 | } 61 | 62 | async getErrorPopUpText() { 63 | const popUps = await this.ERROR_POP_UPS_LIST.all(); 64 | const errorText = []; 65 | for (const popUp of popUps) { 66 | console.debug(`>>> error popup text: ${await popUp.textContent()}`); 67 | errorText.push(await popUp.textContent()); 68 | } 69 | return errorText; 70 | } 71 | } -------------------------------------------------------------------------------- /playwright/lib/pom/Tib_page.ts: -------------------------------------------------------------------------------- 1 | import { Template_Page } from './Template_Page'; 2 | import { DropDown_object } from '@wrappers/DropDown_object'; 3 | import { Input_object } from '@wrappers/Input_object'; 4 | import { SlowButton_object } from '@wrappers/SlowButton_object'; 5 | 6 | export class Tib_page extends Template_Page { 7 | get CREATE_PROFILE_BUTTON() { return new SlowButton_object('span:text-is("Create Profile")', this.page); } 8 | get PROFILE_NAME_INPUT() { return new Input_object('input[label="Name"]', this.page); } 9 | get PROFILE_NEXT_BUTTON() { return new SlowButton_object('(//span[text()="Next"])[1]', this.page); } 10 | get PROVIDER_NEXT_BUTTON() { return new SlowButton_object('(//span[text()="Next"])[2]', this.page); } 11 | get SAML_CERTIFICATE_DROPDOWN() { return new DropDown_object(this.page.locator('span').filter({ hasText:'Select a certificate' }), this.page); } 12 | get SAML_URL_INPUT() { return new Input_object('input[name="ProviderConfig.IDPMetaDataURL"]', this.page); } 13 | get LDAP_SERVER_INPUT() { return new Input_object('input[name="ProviderConfig.LDAPServer"]', this.page); } 14 | get LDAP_PORT_INPUT() { return new Input_object('input[name="ProviderConfig.LDAPPort"]', this.page); } 15 | get LDAP_USERDN_INPUT() { return new Input_object('input[name="ProviderConfig.LDAPUserDN"]', this.page); } 16 | get OICD_CLIENT_ID_INPUT() { return new Input_object('input[name="ProviderConfig.UseProviders[0].Key"]', this.page); } 17 | get OICD_CLIENT_SECRET_INPUT() { return new Input_object('input[name="ProviderConfig.UseProviders[0].Secret"]', this.page); } 18 | get OICD_DISCOVER_URL_INPUT() { return new Input_object('input[name="ProviderConfig.UseProviders[0].DiscoverURL"]', this.page); } 19 | get SOCIAL_POLICY_DROPDOWN() { return this.page.getByRole('button', { name: 'a', exact: true }).first(); } 20 | get SOCIAL_PROVIDER_DROPDOWN() { return new DropDown_object(this.page.locator('span').filter({ hasText:'Select a provider' }), this.page); } 21 | get SOCIAL_CLIENT_ID_INPUT() { return new Input_object('input[name="ProviderConfig.UseProviders[0].Key"]', this.page); } 22 | get SOCIAL_CLIENT_SECRET_INPUT() { return new Input_object('input[name="ProviderConfig.UseProviders[0].Secret"]', this.page); } 23 | 24 | async selectProviderByName(name: any) { 25 | await this.page.locator(`//label[text()="${name}"]`).click(); 26 | } 27 | 28 | async selectFirstPolicyFromDropdown() { 29 | await this.page.locator('.tyk-combobox2__combobox-list').locator('li').first().click(); 30 | } 31 | 32 | get profile_created_expected_mesage() { return 'Profile created successfully'; } 33 | async isProfileCreatedPopUpDisplayed() { return await this.checkIfSuccessPopupDisplayedWithText(this.profile_created_expected_mesage); } 34 | } -------------------------------------------------------------------------------- /playwright/lib/pom/Users_page.ts: -------------------------------------------------------------------------------- 1 | import { Template_Page } from './Template_Page'; 2 | import { Button_object } from '@wrappers/Button_object'; 3 | import { Checkbox_object } from '@wrappers/CheckBox_object'; 4 | import { Table_object } from '@wrappers/Table_object'; 5 | import { DropDown_object } from '@wrappers/DropDown_object'; 6 | import { Input_object } from '@wrappers/Input_object'; 7 | import { expect } from '@playwright/test'; 8 | import { SlowButton_object } from '@wrappers/SlowButton_object'; 9 | 10 | export class Users_page extends Template_Page { 11 | //MAIN PAGE 12 | get ADD_USER_BUTTON() { return new Button_object('span:text-is(" Add user")', this.page); } 13 | get USERS_TABLE() { return new Table_object('.tyk-table', this.page); } 14 | 15 | //ADD/EDIT USER PAGE 16 | get SAVE_BUTTON() { return new SlowButton_object(this.page.locator('span').filter({ hasText: 'Save' }), this.page); } 17 | get UPDATE_BUTTON() { return new SlowButton_object(this.page.locator('span').filter({ hasText: 'Update' }), this.page); } 18 | get DELETE_BUTTON() { return new Button_object(this.page.locator('span').filter({ hasText: 'Delete' }), this.page); } 19 | get FIRST_NAME_INPUT() { return new Input_object('input[name="first_name"]', this.page); } 20 | get LAST_NAME_INPUT() { return new Input_object('input[name="last_name"]', this.page); } 21 | get EMAIL_ADRESS_INPUT() { return new Input_object('input[name="email_address"]', this.page); } 22 | get PASSWORD_INPUT() { return new Input_object('input[name="password"]', this.page); } 23 | get ACCOUNT_IS_ACTIVE_CHECKBOX() { return new Checkbox_object('input[name=active]', this.page); } 24 | get ACCOUNT_IS_ADMIN_CHECKBOX() { return new Checkbox_object('input[name=admin]', this.page); } 25 | get USER_GROUP_DROPDOWN() { return new DropDown_object('.tyk-combobox2__text-value', this.page); } 26 | 27 | //PERMISSION 28 | get PERMISSIONS_ANALYTICS_ROW() { return this.page.locator(`input[name="user_permissions.analytics"]`).first(); } 29 | 30 | //MODALS 31 | get MODAL() { return this.page.locator('.opened .tyk-modal__content'); } 32 | get UPDATE_CONFIRMATION_BUTTON() { return this.page.locator('//div[@class="tyk-modal__content"]//button//span[text()="Update"]'); } 33 | get DELETE_CONFIRMATION_BUTTON() { return this.page.locator('//div[@class="tyk-modal__content"]//button//span[text()="Delete"]'); } 34 | get CONFIRM_BUTTON() { return this.page.locator('//div[contains(@class,"opened")]//div[@class="tyk-modal__content"]//button//span[text()="Confirm"]'); } 35 | 36 | get user_created_expected_mesage() { return 'User added successfully'; } 37 | get user_updated_expected_mesage() { return 'User updated successfully'; } 38 | get user_already_exists_expected_mesage() { return 'User email already exists for this Org'; } 39 | 40 | waitUntilPageLoaded() { 41 | return super.waitUntilPageLoaded(this.USERS_TABLE); 42 | } 43 | 44 | async checkIfUserCreatedPopUpDisplayed(): Promise { return await this.checkIfSuccessPopupDisplayedWithText(this.user_created_expected_mesage); } 45 | 46 | async checkIfUserUpdatedPopUpDisplayed(): Promise { return await this.checkIfSuccessPopupDisplayedWithText(this.user_updated_expected_mesage); } 47 | 48 | async checkIfUserAlreadyExistsPopUpDisplayed(): Promise { return await this.isErrorPopupDisplayedWithText(this.user_already_exists_expected_mesage); } 49 | 50 | async selectReadAccessForPermission(permissionName: any) { 51 | const $$radioButtons = this.page.locator(`input[name="user_permissions.${permissionName}"]`); 52 | expect(await $$radioButtons.count()).toBeGreaterThan(1); 53 | await $$radioButtons.nth(1).waitFor(); 54 | await $$radioButtons.nth(1).click(); 55 | if (await $$radioButtons.nth(1).textContent() !== 'read') { 56 | await $$radioButtons.nth(1).click(); 57 | } 58 | await expect($$radioButtons.nth(1)).toHaveValue('read'); 59 | } 60 | } -------------------------------------------------------------------------------- /playwright/lib/pom/Webhooks_page.ts: -------------------------------------------------------------------------------- 1 | import { Template_Page } from './Template_Page'; 2 | import { Button_object } from '@wrappers/Button_object'; 3 | import { Table_object } from '@wrappers/Table_object'; 4 | import { Input_object } from '@wrappers/Input_object'; 5 | 6 | export class Webhooks_page extends Template_Page { 7 | 8 | get ADD_WEBHOOK() { return new Button_object('span:text-is("Add Webhook")', this.page); } 9 | get NAME_INPUT() { return new Input_object('input[name="name"]', this.page); } 10 | get REQUEST_METHOD_DROPDOWN() { return this.page.locator('.tyk-select'); } 11 | get TARGET_INPUT() { return new Input_object('input[name="target_path"]', this.page); } 12 | get HEADER_KEY() { return new Input_object('input[name="key"]', this.page); } 13 | get HEADER_VALUE() { return new Input_object('input[name="value"]', this.page); } 14 | get ADD_HEADER_BUTTON() { return new Button_object('span:text-is("ADD")', this.page); } 15 | get SAVE_BUTTON() { return new Button_object('span:text-is("Save")', this.page); } 16 | get UPDATE_BUTTON() { return new Button_object('span:text-is("Update")', this.page); } 17 | get DELETE_BUTTON() { return new Button_object('span:text-is("Delete")', this.page); } 18 | get DELETE_KEY_CONFIRMATION_BUTTON() { return new Button_object('//div[contains(@class,"opened")]//div[@class="tyk-modal__content"]//button//span[text()="Delete"]', this.page); } 19 | 20 | //Table 21 | get WEBHOOK_TABLE() { return new Table_object('.tyk-table', this.page); } 22 | get NO_DATA_TO_DISPLAY() { return this.page.locator('.tyk-message--info'); } 23 | } -------------------------------------------------------------------------------- /playwright/lib/utils/API_object_designer.ts: -------------------------------------------------------------------------------- 1 | import json from './api_object.json'; 2 | 3 | export const newAPIdefinitionWithDefaults = (apiDetails: Record) => { 4 | const defaultApiDefinition = new API_object_designer(); 5 | defaultApiDefinition.mergeWithJson(apiDetails); 6 | return defaultApiDefinition.api_object; 7 | }; 8 | 9 | export default class API_object_designer { 10 | api_object: any; 11 | 12 | constructor() { 13 | this.api_object = { ...json }; //saving values, not link to a file (no caching) 14 | } 15 | 16 | mergeWithJson(apiDetails: any) { 17 | this.api_object.api_definition = { ...this.api_object.api_definition, ...apiDetails }; 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /playwright/lib/utils/Policy_object_designer.ts: -------------------------------------------------------------------------------- 1 | export const newPolicyDefinitionWithDefaults = (policyDetails: JSON) => { 2 | const defaultPolicyDefinition = new Policy_object_designer(); 3 | defaultPolicyDefinition.mergeWithJson(policyDetails); 4 | return defaultPolicyDefinition.policy_object; 5 | }; 6 | 7 | export default class Policy_object_designer { 8 | policy_object: any; 9 | mergedPolicyDefinition: any; 10 | 11 | constructor() { 12 | const json = require('./policy_object.json'); 13 | this.policy_object = { ...json }; //saving values, not link to a file (no caching) 14 | } 15 | 16 | mergeWithJson(policyDetails: JSON) { 17 | this.mergedPolicyDefinition = { ...this.policy_object, ...policyDetails }; 18 | this.policy_object = this.mergedPolicyDefinition; 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /playwright/lib/utils/api_connections/Dashboard_admin_connection.ts: -------------------------------------------------------------------------------- 1 | import { config } from '@variables'; 2 | import { APIRequestContext, request, APIResponse } from '@playwright/test'; 3 | import { assert } from '@fixtures'; 4 | 5 | export class Dashboard_admin_connection { 6 | url: string; 7 | org_prefix: string; 8 | 9 | constructor() { 10 | this.url = config.DASHBOARD_ADMIN_API; 11 | this.org_prefix = config.ORG_API_PATH; 12 | } 13 | 14 | async createOrg(body: { 15 | cname: string; cname_enabled: boolean; owner_name: string; owner_slug: string; 16 | }, headers: { "admin-auth": string; }) { 17 | const context: APIRequestContext = await request.newContext({}); 18 | const response: APIResponse = await context.post(this.url + this.org_prefix, { data: body, headers: headers }); 19 | assert(response.ok()).toBeTruthy(); 20 | const responseBody = await response.json(); 21 | assert(responseBody.Meta !== undefined); 22 | console.debug(`>>> New organization was created: ${responseBody}`); 23 | return responseBody.Meta; 24 | } 25 | 26 | async getStatus(headers: { "admin-auth": any; }): Promise { 27 | console.log(">>> Checking is dashboard is up"); 28 | const context: APIRequestContext = await request.newContext({}); 29 | const response: APIResponse = await context.get(this.url + config.HELLO_PATH, { headers: headers }); 30 | return response; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /playwright/lib/utils/api_object.json: -------------------------------------------------------------------------------- 1 | { 2 | "api_definition": { 3 | "name": "test1", 4 | "slug": "test1", 5 | "use_keyless": true, 6 | "auth": { 7 | "auth_header_name": "Authorization" 8 | }, 9 | "definition": { 10 | "location": "header", 11 | "key": "x-api-version" 12 | }, 13 | "version_data": { 14 | "not_versioned": true, 15 | "versions": { 16 | "Default": { 17 | "name": "Default", 18 | "use_extended_paths": true} 19 | } 20 | }, 21 | "proxy": { 22 | "listen_path": "", 23 | "target_url": "http://httpbin.org/", 24 | "strip_listen_path": true 25 | }, 26 | "active": true 27 | } 28 | } -------------------------------------------------------------------------------- /playwright/lib/utils/federation_example.ts: -------------------------------------------------------------------------------- 1 | import { exec } from 'child_process'; 2 | const bashCmdExecutor = require('child_process').exec; 3 | import { API_connection } from './api_connections/API_connection'; 4 | 5 | const federationExampleTestUrl = "http://localhost:4000/"; 6 | const api_connection = new API_connection(federationExampleTestUrl); 7 | const expectedFederationResponse = { data: { me: { id: '1234' } } }; 8 | const federationTestRequestConfig = { 9 | path: "query", 10 | body: `{"query":"query{me{id}}","variables":{}}` 11 | }; 12 | 13 | export const prepareFederationExampleUpstream = () => { 14 | const isUpstreamRunning = waitForFederationUpstream(); 15 | if (isUpstreamRunning) { 16 | return true; 17 | } 18 | if(!checkIfFederationFilesExists()) { 19 | console.error(`Federation file "start.sh" does NOT exist!`); 20 | return false; 21 | } 22 | 23 | console.log('>>> Running Federation example'); 24 | const logs = bashCmdExecutor('(cd graphql-go-tools/examples/federation ; ./start.sh)').stdout.pipe(process.stdout); 25 | console.log("<<<< logs: " + logs); 26 | return waitForFederationUpstream(20); 27 | }; 28 | 29 | const checkIfFederationFilesExists = () => { 30 | console.log('>>> Checking presence of federation start.sh file'); 31 | exec('ls graphql-go-tools/examples/federation | grep start.sh', (error, stdout) => { 32 | if(error) { 33 | console.error(`>>> Files in federation folder: ${stdout}`); 34 | console.error('>>> Error: ', error.message); 35 | return false; 36 | } 37 | }); 38 | console.log(`>>> Federation file "start.sh" exists`); 39 | return true; 40 | }; 41 | 42 | const waitForFederationUpstream = (retryMaxCount = 1) => { 43 | let retryNumber = 1; 44 | const isRunning = false; 45 | 46 | while(!isRunning && retryNumber <= retryMaxCount) { 47 | let response; 48 | console.log(`>>> Starting connection try number ${retryNumber}`); 49 | try { 50 | response = api_connection.sendPostRequest({ path: federationTestRequestConfig.path, body: federationTestRequestConfig.body }); 51 | if(JSON.stringify(response.body) === JSON.stringify(expectedFederationResponse)) { 52 | console.log('>> Federation upstream works'); 53 | return true; 54 | } 55 | } catch (error) { 56 | console.error('Federation example not running. Trying again. ' + error); 57 | } 58 | retryNumber++; 59 | } 60 | return isRunning; 61 | }; -------------------------------------------------------------------------------- /playwright/lib/utils/fixtures.ts: -------------------------------------------------------------------------------- 1 | import { Locator, test as base, expect } from '@playwright/test'; 2 | import { setUpEnv } from './prerequisites'; 3 | import { Login_page } from '@pom/Login_page'; 4 | import { Main_page } from '@pom/Main_page'; 5 | import { Wrapper } from '@wrappers/Wrapper'; 6 | import { Apis_page } from '@pom/Apis_page'; 7 | import { Catalogue_page } from '@pom/Catalogue_page'; 8 | import { Endpoints_page } from '@pom/Endpoints_page'; 9 | import { Graphql_page } from '@pom/Graphql_page'; 10 | import { Keys_page } from '@pom/Keys_page'; 11 | import { Policies_page } from '@pom/Policies_page'; 12 | import { Tib_page } from '@pom/Tib_page'; 13 | import { Users_page } from '@pom/Users_page'; 14 | import { Webhooks_page } from '@pom/Webhooks_page'; 15 | import { Admin_settings_page } from '@lib/pom/portal/Admin_settings_page'; 16 | 17 | export function assert(wrapper: Wrapper | Locator | any) { 18 | if (wrapper instanceof Wrapper) { 19 | return expect(wrapper.element); 20 | } 21 | return expect(wrapper); 22 | 23 | } 24 | 25 | export const test = base.extend<{ 26 | createUserAndLogin: any, 27 | apis_page: Apis_page 28 | catalogue_page: Catalogue_page, 29 | endpoints_page: Endpoints_page, 30 | graphql_page: Graphql_page, 31 | keys_page: Keys_page, 32 | login_page: Login_page, 33 | main_page: Main_page, 34 | policies_page: Policies_page, 35 | tib_page: Tib_page, 36 | users_page: Users_page, 37 | webhooks_page: Webhooks_page, 38 | admin_settings_page: Admin_settings_page 39 | }>({ 40 | createUserAndLogin: [async ({ page }, use: any) => { 41 | const userDetails = await setUpEnv(); 42 | const login_page = new Login_page(page); 43 | await login_page.open(); 44 | await login_page.login(userDetails.userEmail, userDetails.userPassword); 45 | console.log(`>>> User is logged in! User Email: ${userDetails.userEmail}`); 46 | use(userDetails); 47 | }, { auto: true }], 48 | apis_page: async ({ page }, use) => { 49 | await use(new Apis_page(page)); 50 | }, 51 | catalogue_page: async ({ page }, use) => { 52 | await use(new Catalogue_page(page)); 53 | }, 54 | endpoints_page: async ({ page }, use) => { 55 | await use(new Endpoints_page(page)); 56 | }, 57 | graphql_page: async ({ page }, use) => { 58 | await use(new Graphql_page(page)); 59 | }, 60 | keys_page: async ({ page }, use) => { 61 | await use(new Keys_page(page)); 62 | }, 63 | login_page: async ({ page }, use) => { 64 | await use(new Login_page(page)); 65 | }, 66 | main_page: async ({ page }, use) => { 67 | await use(new Main_page(page)); 68 | }, 69 | policies_page: async ({ page }, use) => { 70 | await use(new Policies_page(page)); 71 | }, 72 | tib_page: async ({ page }, use) => { 73 | await use(new Tib_page(page)); 74 | }, 75 | users_page: async ({ page }, use) => { 76 | await use(new Users_page(page)); 77 | }, 78 | webhooks_page: async ({ page }, use) => { 79 | await use(new Webhooks_page(page)); 80 | }, 81 | admin_settings_page: async ({ page }, use) => { 82 | await use(new Admin_settings_page(page)); 83 | } 84 | }); -------------------------------------------------------------------------------- /playwright/lib/utils/policy_object.json: -------------------------------------------------------------------------------- 1 | { 2 | "last_updated": "0001-01-01T00:00:00Z", 3 | "rate": 1000, 4 | "per": 60, 5 | "quota_max": -1, 6 | "quota_renews": 1481546970, 7 | "quota_remaining": 0, 8 | "quota_renewal_rate": 60, 9 | "access_rights": { 10 | "35447b1469df4e846894b1e87372f6d7": { 11 | "api_id": "35447b1469df4e846894b1e87372f6d7", 12 | "api_name": "My API", 13 | "versions": ["Default"] 14 | } 15 | }, 16 | "name": "test policy", 17 | "active": true 18 | } -------------------------------------------------------------------------------- /playwright/lib/utils/prerequisites.ts: -------------------------------------------------------------------------------- 1 | import { Dashboard_admin_connection } from './api_connections/Dashboard_admin_connection'; 2 | import { v4 as uuid } from 'uuid'; 3 | import { generateRandomEmail } from './utils'; 4 | import { assert } from 'lib/utils/fixtures'; 5 | import { config } from '@variables'; 6 | import { APIRequestContext, expect, request } from '@playwright/test'; 7 | 8 | export const setUpEnv = async () => { 9 | if (!config.CLEAN_TEST) { //returning default values from config 10 | console.debug(`>>> $CLEAN_TEST set to false -> tests will re-use already created org and user`); 11 | return { 12 | userEmail: config.USER_EMAIL, 13 | userPassword: config.USER_PASSWORD, 14 | userSecret: config.USER_SECRET 15 | }; 16 | } 17 | 18 | const dashboard_admin_request = new Dashboard_admin_connection(); 19 | const authorizationHeader = { "admin-auth": config.ADMIN_SECRET }; 20 | const orgCname = config.ORG_NAME + uuid(); 21 | const adminEmail = generateRandomEmail(); 22 | const adminPassword = config.USER_PASSWORD; 23 | 24 | //CHECKING IF ENV IS UP - TODO: move it to before all tests (to execute only once) 25 | const statusResponse = await dashboard_admin_request.getStatus(authorizationHeader); 26 | assert(statusResponse.ok()).toBeTruthy(); 27 | const context: APIRequestContext = await request.newContext({}); 28 | await expect.poll(async () => { 29 | const gwStatusResponse: any = await context.get(config.GW_HELLO_API); 30 | assert(gwStatusResponse.ok()).toBeTruthy(); 31 | const body = await gwStatusResponse.json(); 32 | return body.details.dashboard.status === "pass"; 33 | }).toBeTruthy(); 34 | //PREPARING ORG 35 | console.debug(`>>> Preparing new ${orgCname} organization`); 36 | const testOrgBody = { "cname": orgCname,"cname_enabled": true,"owner_name": "test-org1","owner_slug": "default" }; 37 | const orgID = await dashboard_admin_request.createOrg(testOrgBody, authorizationHeader); 38 | //PREPARING ADMIN USER 39 | const adminUserBody = { 40 | "active": true, 41 | "email_address": adminEmail, 42 | "first_name": "auto", 43 | "last_name": "admin", 44 | "org_id": orgID, 45 | "user_permissions": { "IsAdmin": "admin" } 46 | }; 47 | // const context: APIRequestContext = await request.newContext({}); 48 | const adminUserResponse = await context.post(config.DASHBOARD_ADMIN_API + config.USERS_API_PATH, { data: adminUserBody, headers: authorizationHeader }); 49 | const reposneJson = await adminUserResponse.json(); 50 | console.debug(`>>> Creating user response: ${reposneJson}`); 51 | const adminUserSecret = reposneJson.Message; 52 | const adminUserID = reposneJson.Meta.id; 53 | //UPDATE PASSWORD FOR USER 54 | const adminUserPasswordBody = { 55 | "active": true, 56 | "email_address": adminEmail, 57 | "first_name": "auto", 58 | "last_name": "admin", 59 | "org_id": orgID, 60 | "password": adminPassword, 61 | "user_permissions": { "IsAdmin": "admin" } 62 | }; 63 | const updatePath = `${config.USERS_API_PATH}${adminUserID}`; 64 | const updatePasswordResponse = await context.put(config.DASHBOARD_ADMIN_API + updatePath, { data: adminUserPasswordBody, headers: authorizationHeader }); 65 | assert(updatePasswordResponse.ok()).toBeTruthy(); 66 | console.log(`>>> User was created: ${adminEmail}, secret: ${adminUserSecret}, organization: ${orgCname}`); 67 | return { userEmail: adminEmail, userPassword: adminPassword, userSecret: adminUserSecret }; 68 | }; 69 | -------------------------------------------------------------------------------- /playwright/lib/utils/utils.ts: -------------------------------------------------------------------------------- 1 | import moment from 'moment'; 2 | import randomEmailGenerator from 'random-email'; 3 | 4 | /** generating random email in format name+11-Feb-9_39_41@example.com 5 | * @function 6 | * @return {string} random email 7 | **/ 8 | export const generateRandomEmail = () => { 9 | const randomEmail = randomEmailGenerator({ domain: 'example.com' }); 10 | return randomEmail.replace('@', `+${moment().format('h_mm_ss')}@`); 11 | }; -------------------------------------------------------------------------------- /playwright/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dashboard_ui_tests", 3 | "version": "2.0.0", 4 | "description": "Framework for Dashboard UI automated tests", 5 | "scripts": { 6 | "notify-slack": "node ./slack_notify.js", 7 | "test": "npx playwright test --project='chromium'", 8 | "generate-coverage-doc": "PATH_TO_RESULTS=`PWD`/results/json/wdio-merged.json node ./node_modules/ui_test_automation/utils/GenerateCoverageDoc.js", 9 | "gui": "npx playwright test --project='chromium' --ui", 10 | "upload_report_to_s3": "node ./node_modules/tyk-test-automation-wrappers/lib/utils/uploadReport.js" 11 | }, 12 | "keywords": [], 13 | "author": "Konrad Soltys", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "@babel/core": "^7.16.0", 17 | "@playwright/test": "^1.38.0", 18 | "@types/node": "^20.5.0", 19 | "@typescript-eslint/eslint-plugin": "^5.62.0", 20 | "@typescript-eslint/parser": "^5.62.0", 21 | "axios": "^1.4.0", 22 | "babel-eslint": "^10.1.0", 23 | "dotenv": "^8.6.0", 24 | "eslint": "^8.51.0", 25 | "eslint-config-standard-with-typescript": "^35.0.0", 26 | "eslint-import-resolver-typescript": "^3.6.1", 27 | "eslint-plugin-import": "^2.28.1", 28 | "eslint-plugin-n": "^15.7.0", 29 | "eslint-plugin-playwright": "^0.16.0", 30 | "eslint-plugin-promise": "^6.1.1", 31 | "moment": "^2.27.0", 32 | "playwright-slack-report": "^1.1.24", 33 | "random-email": "^1.0.3", 34 | "superagent": "^6.1.0", 35 | "timediff": "^1.1.1", 36 | "tyk-test-automation-wrappers": "git+https://github.com/TykTechnologies/tyk-test-automation-wrappers.git#main", 37 | "typescript": "^5.2.2", 38 | "uuid": "^9.0.0" 39 | }, 40 | "dependencies": { 41 | "aws-sdk": "^2.1470.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /playwright/slack_notify.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const webHookURL = process.env.SLACK_WEBHOOK_URL; 3 | const executionStatus = process.env.STATUS || "failed"; 4 | 5 | console.log("Sending message to Slack. Status: " + executionStatus); 6 | 7 | let message = { 8 | "username": "Automated test", // This will appear as user name who posts the message 9 | "text": "UI automate tests", 10 | "icon_emoji": ":no_entry:", // User icon, default value 11 | "blocks": [ { 12 | "type": "section", 13 | "text": { 14 | "type": "mrkdwn", 15 | "text": `:computer: *test env*: ${process.env.JOB_NAME}` 16 | } 17 | }, 18 | { 19 | "type": "section", 20 | "text": { 21 | "type": "mrkdwn", 22 | "text": `:tyk17: *triggered by*: ${process.env.EVENT_TRIGGER}` 23 | } 24 | }, 25 | { 26 | "type": "section", 27 | "text": { 28 | "type": "mrkdwn", 29 | "text": `:link: ` 30 | } 31 | }, 32 | ], 33 | "attachments": [], 34 | }; 35 | 36 | if (executionStatus === "success") { 37 | message.icon_emoji = ":white_check_mark:"; 38 | message.blocks.push({ 39 | "type": "section", 40 | "text": { 41 | "type": "mrkdwn", 42 | "text": `:rickroll: *Tests passed!*` 43 | } 44 | }) 45 | } else { 46 | message.icon_emoji = ":no_entry:"; 47 | message.blocks.push({ 48 | "type": "section", 49 | "text": { 50 | "type": "mrkdwn", 51 | "text": `:poop: *Tests failed!*` 52 | } 53 | }) 54 | } 55 | 56 | axios.post(webHookURL, message).then(() => { 57 | console.log("Message sent to Slack"); 58 | }).catch((error) => { 59 | console.log(error); 60 | }); 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /playwright/tests/specs/api_designer/create_api.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | import { Locator } from '@playwright/test'; 3 | 4 | test('Create simple API', async ({ createUserAndLogin, main_page, apis_page, page }) => { 5 | const apiDetails = { 6 | name: "test" 7 | }; 8 | let $apiTableElement: Locator; 9 | 10 | await test.step('User should be able to create new API', async () => { 11 | await main_page.openAPIs(); 12 | await apis_page.DESIGN_API_BOX.click(); 13 | await apis_page.API_NAME_INPUT.fill(apiDetails.name); 14 | await apis_page.CONFIGURE_API_BUTTON.click(); 15 | await apis_page.SAVE_BUTTON.click(); 16 | }); 17 | 18 | await test.step('New API should be visible in table', async () => { 19 | await main_page.openAPIs(); 20 | $apiTableElement = page.locator(`span:text("${apiDetails.name}")`); 21 | await assert($apiTableElement).toBeVisible(); 22 | }); 23 | 24 | await test.step('User should be able to delete API', async () => { 25 | await $apiTableElement.click(); 26 | await apis_page.OPTIONS_BUTTON.click(); 27 | await apis_page.DELETE_BUTTON.click(); 28 | await apis_page.DELETE_API_BUTTON.click(); 29 | }); 30 | 31 | await test.step('Deleted API should not be visible', async () => { 32 | await assert($apiTableElement).not.toBeVisible(); 33 | }); 34 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/api_designer/oas_api_page_search_test.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | import { config } from '@variables'; 3 | 4 | test('Test Search functionality on OAS API Page', async ({ createUserAndLogin, main_page, apis_page, page }) => { 5 | const apiName = "oas-api-search-test"; 6 | 7 | await test.step('User should be able to open search bar by clicking search icon', async () => { 8 | // await page.goto(config.URL + config.LANDING_PAGE_PATH); //TO BE REMOVED WHEN RELEASED 9 | await apis_page.DESIGN_API_BOX.click(); 10 | await apis_page.API_NAME_INPUT.fill(apiName); 11 | await apis_page.OAS_API_REST_RADIO.click(); 12 | await apis_page.OAS_NEXT_BUTTON.click(); 13 | await assert(apis_page.OAS_SEARCH_ICON).toBeVisible(); 14 | await apis_page.OAS_SEARCH_ICON.click(); 15 | await assert(apis_page.OAS_SEARCH_BAR).toBeVisible(); 16 | }); 17 | 18 | //was disabled 19 | await test.step('User should be able to close search bar by clicking X icon', async () => { 20 | await apis_page.OAS_SEARCH_BAR_CLOSE_ICON.click(); 21 | await assert(apis_page.OAS_SEARCH_BAR).not.toBeVisible(); 22 | }); 23 | 24 | await test.step('User should be able to open search bar with keyboard shortcut ctrl+f', async () => { 25 | await page.press(["\uE009", "f"]); 26 | browser.keys("\uE009"); 27 | await assert(apis_page.OAS_SEARCH_BAR).toBeVisible(); 28 | }); 29 | 30 | await test.step('User should be able to close search bar with keyboard shortcut ESC', async () => { 31 | browser.keys("\uE00C"); 32 | await assert(apis_page.OAS_SEARCH_BAR).not.toBeVisible(); 33 | }); 34 | 35 | await test.step('User should be able to open search bar with keyboard shortcut cmd+f', async () => { 36 | browser.keys(["\uE03D", "f"]); 37 | browser.keys("\uE03D"); 38 | await assert(apis_page.OAS_SEARCH_BAR).toBeVisible(); 39 | }); 40 | 41 | await test.step('User should be able to search by main section title', async () => { 42 | await apis_page.OAS_SEARCH_BAR.fill("Listen path"); 43 | await assert(apis_page.OAS_LISTEN_PATH_INPUT).toBeVisible(); 44 | await assert(apis_page.OAS_AUTHENTICATION_DROPDOWN).not.toBeVisible(); 45 | await assert(apis_page.API_NAME_INPUT).not.toBeVisible(); 46 | await assert(apis_page.OAS_TARGET_URL_INPUT).not.toBeVisible(); 47 | }); 48 | 49 | await test.step('User should be able to search by "potential match" text', async () => { 50 | await apis_page.OAS_SEARCH_BAR.fill("JWT"); 51 | await assert(apis_page.OAS_AUTHENTICATION_DROPDOWN).toBeVisible(); 52 | await assert(apis_page.OAS_HIDDEN_MATCH_MSG).toHaveText('A match for "JWT" can be found in this section, if proper settings are configured'); 53 | await assert(apis_page.OAS_LISTEN_PATH_INPUT).not.toBeVisible(); 54 | await assert(apis_page.API_NAME_INPUT).not.toBeVisible(); 55 | await assert(apis_page.OAS_TARGET_URL_INPUT).not.toBeVisible(); 56 | }); 57 | 58 | await test.step('User should be able to see multiple results when typing', async () => { 59 | await apis_page.OAS_SEARCH_BAR.fill("strip"); 60 | await assert(apis_page.OAS_LISTEN_PATH_INPUT).toBeVisible(); 61 | await assert(apis_page.OAS_AUTHENTICATION_DROPDOWN).toBeVisible(); 62 | await assert(apis_page.API_NAME_INPUT).not.toBeVisible(); 63 | await assert(apis_page.OAS_TARGET_URL_INPUT).not.toBeVisible(); 64 | }); 65 | 66 | await test.step('User should be able to clear search results', async () => { 67 | await apis_page.OAS_SEARCH_BAR_CLEAR_ICON.click(); 68 | await assert(apis_page.OAS_LISTEN_PATH_INPUT).toBeVisible(); 69 | await assert(apis_page.OAS_AUTHENTICATION_DROPDOWN).toBeVisible(); 70 | await assert(apis_page.API_NAME_INPUT).toBeVisible(); 71 | await assert(apis_page.OAS_TARGET_URL_INPUT).toBeVisible(); 72 | await assert(apis_page.OAS_SEARCH_BAR).toBeVisible(); 73 | }); 74 | 75 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/api_designer/oas_fields_validation_test.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | import { apis_page } from '../../../lib/pom/Apis_page'; 3 | import { URL, LANDING_PAGE_PATH } from './../../../config_variables'; 4 | import { expect } from 'chai'; 5 | 6 | xtest('Test mandatory fields on OAS API designer page', async ({ createUserAndLogin, main_page }) => { 7 | const apiName = "oas-api-validation-test"; 8 | 9 | 10 | await test.step('API Name is required on popup', async () => { 11 | browser.navigateTo(URL + LANDING_PAGE_PATH); //TO BE REMOVED WHEN RELEASED 12 | await apis_page.DESIGN_API_BOX.click(); 13 | await apis_page.OAS_NEXT_BUTTON.click(); 14 | const apiNameErrorMessage = await this.page.locator('//input[@name="x-tyk-api-gateway.info.name"]//following::p[1]'); 15 | await assert(apiNameErrorMessage).toHaveText('API Name is required'); 16 | }); 17 | 18 | await test.step('API Name is required on main designer page', async () => { 19 | await apis_page.API_NAME_INPUT.fill(apiName); 20 | await apis_page.OAS_NEXT_BUTTON.click(); 21 | await apis_page.API_NAME_INPUT.fill(''); 22 | await apis_page.OAS_SAVE_BUTTON.click(); 23 | const apiNameErrorMessage = await this.page.locator('//input[@name="x-tyk-api-gateway.info.name"]//following::p[1]'); 24 | await assert(apiNameErrorMessage).toHaveText('API Name is required'); 25 | }); 26 | 27 | await test.step('Listen Path is required on main designer page', async () => { 28 | const listenPathErrorMessage = await this.page.locator('//input[@name="x-tyk-api-gateway.server.listenPath.value"]//following::p[1]'); 29 | await assert(listenPathErrorMessage).toHaveText('Listen Path is required'); 30 | }); 31 | 32 | await test.step('Target URL is required on main designer page', async () => { 33 | const targetURLErrorMessage = await this.page.locator('//input[@name="x-tyk-api-gateway.upstream.url"]//following::p[1]'); 34 | await assert(targetURLErrorMessage).toHaveText('Target URL is required'); 35 | }); 36 | 37 | await test.step('Access is required on main designer page', async () => { 38 | const accessErrorMessage = await this.page.locator('//span[@title="Select access"]//following::p[contains(@class, "error-message")]'); 39 | await assert(accessErrorMessage).toHaveText('Access is required'); 40 | }); 41 | 42 | await test.step('GW Status is required on main designer page', async () => { 43 | const statusErrorMessage = await this.page.locator('//span[@title="Select status"]//following::p[contains(@class, "error-message")]'); 44 | await assert(statusErrorMessage).toHaveText('Status is required'); 45 | }); 46 | 47 | await test.step('Authentication is required on main designer page', async () => { 48 | const authErrorMessage = await this.page.locator('//span[@title="Select authentication type"]//following::p[contains(@class, "error-message")]'); 49 | await assert(authErrorMessage).toHaveText('Authentication is required'); 50 | }); 51 | 52 | await test.step('Auth Key Header is required on main designer page', async () => { 53 | await apis_page.OAS_AUTHENTICATION_DROPDOWN.selectOption('Auth Token'); 54 | const authHeaderErrorMessage = await this.page.locator('//input[@name="x-tyk-api-gateway.server.authentication.token.header.name"]//following::p[1]'); 55 | await assert(authHeaderErrorMessage).toHaveText('Auth Key Header Name is required'); 56 | }); 57 | 58 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/api_designer/oas_middleware_tests/oas_api_allow_plugin_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../../lib/pom/Login_page'; 2 | import { apis_page } from '../../../../lib/pom/Apis_page'; 3 | import { main_page } from '../../../../lib/pom/Main_page'; 4 | import { endpoints_page } from '../../../../lib/pom/Endpoints_page'; 5 | import { expect } from 'chai'; 6 | 7 | test('Test Allow List plugin on OAS Endpoints designer page', async ({ createUserAndLogin, main_page }) => { 8 | let envDetails; 9 | 10 | before(() => { 11 | envDetails = setUpEnv(); 12 | login_page.open(); 13 | login_page.login(envDetails.userEmail, envDetails.userPassword); 14 | }); 15 | 16 | await test.step('User can add Allow List plugin and save API', async () => { 17 | await main_page.openAPIs(); 18 | await apis_page.DESIGN_API_BOX.click(); 19 | await apis_page.API_TYPE_OAS_BUTTON.click(); 20 | await apis_page.API_NAME_INPUT.fill('allow-plugin-test'); 21 | await apis_page.OAS_NEXT_BUTTON.click(); 22 | await apis_page.OAS_GW_STATUS_DROPDOWN.selectOption("Active"); 23 | await apis_page.OAS_ACCESS_DROPDOWN.selectOption("External"); 24 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 25 | endpoints_page.addNewEndpoint("/ip", "GET"); 26 | endpoints_page.addMiddlewareByName("Allow List"); 27 | await apis_page.OAS_SAVE_BUTTON.click(); 28 | assert(apis_page.isApiCreatedPopUpDisplayed()).toBeTruthy(); 29 | }); 30 | 31 | await test.step('Allow List plugin is displayed after page reload', async () => { 32 | browser.refresh(); 33 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 34 | assert(endpoints_page.verifyMiddlewareExistsByName("Allow List")).toBeTruthy(); 35 | }); 36 | 37 | await test.step('User can disable Allow List plugin and save API', async () => { 38 | browser.refresh(); 39 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 40 | await apis_page.EDIT_BUTTON.click(); 41 | endpoints_page.changeMiddlewareStatusByName("Allow List"); 42 | await apis_page.OAS_SAVE_BUTTON.click(); 43 | assert(apis_page.isApiUpdatedPopUpDisplayed()).toBeTruthy(); 44 | }); 45 | 46 | await test.step('Allow List plugin is disabled after page reload', async () => { 47 | browser.refresh(); 48 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 49 | assert(endpoints_page.verifyMiddlewareDisabledByName("Allow List")).toBeTruthy(); 50 | }); 51 | 52 | await test.step('User can enable Allow List plugin and save API', async () => { 53 | browser.refresh(); 54 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 55 | await apis_page.EDIT_BUTTON.click(); 56 | endpoints_page.changeMiddlewareStatusByName("Allow List"); 57 | await apis_page.OAS_SAVE_BUTTON.click(); 58 | assert(apis_page.isApiUpdatedPopUpDisplayed()).toBeTruthy(); 59 | }); 60 | 61 | await test.step('Allow List plugin is enabled after page reload', async () => { 62 | browser.refresh(); 63 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 64 | assert(endpoints_page.verifyMiddlewareDisabledByName("Allow List")).toBeFalsy(); 65 | }); 66 | 67 | await test.step('User can remove Allow List plugin and save API', async () => { 68 | browser.refresh(); 69 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 70 | await apis_page.EDIT_BUTTON.click(); 71 | endpoints_page.removeMiddlewareByName("Allow List"); 72 | await apis_page.OAS_SAVE_BUTTON.click(); 73 | assert(apis_page.isApiUpdatedPopUpDisplayed()).toBeTruthy(); 74 | }); 75 | 76 | await test.step('Allow List plugin is removed after page reload', async () => { 77 | browser.refresh(); 78 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 79 | assert(endpoints_page.verifyMiddlewareExistsByName("Allow List")).toBeFalsy(); 80 | }); 81 | 82 | }); 83 | -------------------------------------------------------------------------------- /playwright/tests/specs/api_designer/oas_middleware_tests/oas_api_block_plugin_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../../lib/pom/Login_page'; 2 | import { apis_page } from '../../../../lib/pom/Apis_page'; 3 | import { main_page } from '../../../../lib/pom/Main_page'; 4 | import { endpoints_page } from '../../../../lib/pom/Endpoints_page'; 5 | import { expect } from 'chai'; 6 | 7 | test('Test Block List plugin on OAS Endpoints designer page', async ({ createUserAndLogin, main_page }) => { 8 | let envDetails; 9 | 10 | before(() => { 11 | envDetails = setUpEnv(); 12 | login_page.open(); 13 | login_page.login(envDetails.userEmail, envDetails.userPassword); 14 | }); 15 | 16 | await test.step('User can add Block List plugin and save API', async () => { 17 | await main_page.openAPIs(); 18 | await apis_page.DESIGN_API_BOX.click(); 19 | await apis_page.API_TYPE_OAS_BUTTON.click(); 20 | await apis_page.API_NAME_INPUT.fill('Block-plugin-test'); 21 | await apis_page.OAS_NEXT_BUTTON.click(); 22 | await apis_page.OAS_GW_STATUS_DROPDOWN.selectOption("Active"); 23 | await apis_page.OAS_ACCESS_DROPDOWN.selectOption("External"); 24 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 25 | endpoints_page.addNewEndpoint("/ip", "GET"); 26 | endpoints_page.addMiddlewareByName("Block List"); 27 | await apis_page.OAS_SAVE_BUTTON.click(); 28 | assert(apis_page.isApiCreatedPopUpDisplayed()).toBeTruthy(); 29 | }); 30 | 31 | await test.step('Block List plugin is displayed after page reload', async () => { 32 | browser.refresh(); 33 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 34 | assert(endpoints_page.verifyMiddlewareExistsByName("Block List")).toBeTruthy(); 35 | }); 36 | 37 | await test.step('User can disable Block List plugin and save API', async () => { 38 | browser.refresh(); 39 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 40 | await apis_page.EDIT_BUTTON.click(); 41 | endpoints_page.changeMiddlewareStatusByName("Block List"); 42 | await apis_page.OAS_SAVE_BUTTON.click(); 43 | assert(apis_page.isApiUpdatedPopUpDisplayed()).toBeTruthy(); 44 | }); 45 | 46 | await test.step('Block List plugin is disabled after page reload', async () => { 47 | browser.refresh(); 48 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 49 | assert(endpoints_page.verifyMiddlewareDisabledByName("Block List")).toBeTruthy(); 50 | }); 51 | 52 | await test.step('User can enable Block List plugin and save API', async () => { 53 | browser.refresh(); 54 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 55 | await apis_page.EDIT_BUTTON.click(); 56 | endpoints_page.changeMiddlewareStatusByName("Block List"); 57 | await apis_page.OAS_SAVE_BUTTON.click(); 58 | assert(apis_page.isApiUpdatedPopUpDisplayed()).toBeTruthy(); 59 | }); 60 | 61 | await test.step('Block List plugin is enabled after page reload', async () => { 62 | browser.refresh(); 63 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 64 | assert(endpoints_page.verifyMiddlewareDisabledByName("Block List")).toBeFalsy(); 65 | }); 66 | 67 | await test.step('User can remove Block List plugin and save API', async () => { 68 | browser.refresh(); 69 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 70 | await apis_page.EDIT_BUTTON.click(); 71 | endpoints_page.removeMiddlewareByName("Block List"); 72 | await apis_page.OAS_SAVE_BUTTON.click(); 73 | assert(apis_page.isApiUpdatedPopUpDisplayed()).toBeTruthy(); 74 | }); 75 | 76 | await test.step('Block List plugin is removed after page reload', async () => { 77 | browser.refresh(); 78 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 79 | assert(endpoints_page.verifyMiddlewareExistsByName("Block List")).toBeFalsy(); 80 | }); 81 | 82 | }); 83 | -------------------------------------------------------------------------------- /playwright/tests/specs/api_designer/oas_middleware_tests/oas_api_ignore_plugin_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../../lib/pom/Login_page'; 2 | import { apis_page } from '../../../../lib/pom/Apis_page'; 3 | import { main_page } from '../../../../lib/pom/Main_page'; 4 | import { endpoints_page } from '../../../../lib/pom/Endpoints_page'; 5 | import { expect } from 'chai'; 6 | 7 | test('Test Ignore plugin on OAS Endpoints designer page', async ({ createUserAndLogin, main_page }) => { 8 | let envDetails; 9 | 10 | before(() => { 11 | envDetails = setUpEnv(); 12 | login_page.open(); 13 | login_page.login(envDetails.userEmail, envDetails.userPassword); 14 | }); 15 | 16 | await test.step('User can add Ignore plugin and save API', async () => { 17 | await main_page.openAPIs(); 18 | await apis_page.DESIGN_API_BOX.click(); 19 | await apis_page.API_TYPE_OAS_BUTTON.click(); 20 | await apis_page.API_NAME_INPUT.fill('ignore-plugin-test'); 21 | await apis_page.OAS_NEXT_BUTTON.click(); 22 | await apis_page.OAS_GW_STATUS_DROPDOWN.selectOption("Active"); 23 | await apis_page.OAS_ACCESS_DROPDOWN.selectOption("External"); 24 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 25 | endpoints_page.addNewEndpoint("/ip", "GET"); 26 | endpoints_page.addMiddlewareByName("Ignore Authentication"); 27 | await apis_page.OAS_SAVE_BUTTON.click(); 28 | assert(apis_page.isApiCreatedPopUpDisplayed()).toBeTruthy(); 29 | }); 30 | 31 | await test.step('Ignore plugin is displayed after page reload', async () => { 32 | browser.refresh(); 33 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 34 | assert(endpoints_page.verifyMiddlewareExistsByName("Ignore Authentication")).toBeTruthy(); 35 | }); 36 | 37 | await test.step('User can disable Ignore plugin and save API', async () => { 38 | browser.refresh(); 39 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 40 | await apis_page.EDIT_BUTTON.click(); 41 | endpoints_page.changeMiddlewareStatusByName("Ignore Authentication"); 42 | await apis_page.OAS_SAVE_BUTTON.click(); 43 | assert(apis_page.isApiUpdatedPopUpDisplayed()).toBeTruthy(); 44 | }); 45 | 46 | await test.step('Ignore plugin is disabled after page reload', async () => { 47 | browser.refresh(); 48 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 49 | assert(endpoints_page.verifyMiddlewareDisabledByName("Ignore Authentication")).toBeTruthy(); 50 | }); 51 | 52 | await test.step('User can enable Ignore plugin and save API', async () => { 53 | browser.refresh(); 54 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 55 | await apis_page.EDIT_BUTTON.click(); 56 | endpoints_page.changeMiddlewareStatusByName("Ignore Authentication"); 57 | await apis_page.OAS_SAVE_BUTTON.click(); 58 | assert(apis_page.isApiUpdatedPopUpDisplayed()).toBeTruthy(); 59 | }); 60 | 61 | await test.step('Ignore plugin is enabled after page reload', async () => { 62 | browser.refresh(); 63 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 64 | assert(endpoints_page.verifyMiddlewareDisabledByName("Ignore Authentication")).toBeFalsy(); 65 | }); 66 | 67 | await test.step('User can remove Ignore plugin and save API', async () => { 68 | browser.refresh(); 69 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 70 | await apis_page.EDIT_BUTTON.click(); 71 | endpoints_page.removeMiddlewareByName("Ignore Authentication"); 72 | await apis_page.OAS_SAVE_BUTTON.click(); 73 | assert(apis_page.isApiUpdatedPopUpDisplayed()).toBeTruthy(); 74 | }); 75 | 76 | await test.step('Ignore plugin is removed after page reload', async () => { 77 | browser.refresh(); 78 | await endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 79 | assert(endpoints_page.verifyMiddlewareExistsByName("Ignore Authentication")).toBeFalsy(); 80 | }); 81 | 82 | }); 83 | -------------------------------------------------------------------------------- /playwright/tests/specs/graphql/crud_graphql_proxy.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | import { Locator } from '@playwright/test'; 3 | 4 | test('CRUD simple GraphQL (proxy-only) API', async ({ page, main_page, apis_page, graphql_page }) => { 5 | const apiDetails = { 6 | name: "GraphQL-test" 7 | }; 8 | let $apiTableElement: Locator; 9 | 10 | await test.step('User should be able to create new GraphQL API', async () => { 11 | await main_page.openAPIs(); 12 | await apis_page.DESIGN_API_BOX.click(); 13 | await apis_page.API_NAME_INPUT.fill(apiDetails.name); 14 | await apis_page.API_TYPE_GRAPHQL_BUTTON.click(); 15 | await apis_page.CONFIGURE_API_BUTTON.click(); 16 | await graphql_page.GRAPHQL_SCHEMA_TAB_BUTTON.click(); 17 | await assert(graphql_page.GRAPHQL_UPDATE_SCHEMA_BUTTON).toBeVisible(); 18 | await apis_page.SAVE_BUTTON.click(); 19 | }); 20 | 21 | await test.step('New GraphQL API should be visible in table', async () => { 22 | await main_page.openAPIs(); 23 | $apiTableElement = page.locator(`span:text-is('${apiDetails.name}')`); 24 | await assert($apiTableElement).toBeVisible(); 25 | }); 26 | 27 | await test.step('User should be able to update GraphQL API', async () => { 28 | await $apiTableElement.click(); 29 | await graphql_page.GRAPHQL_ENABLE_PLAYGROUND_TOGGLE.click(); 30 | assert(await graphql_page.GRAPHQL_ENABLE_PLAYGROUND_TOGGLE.isSelected()).toBeTruthy(); 31 | await apis_page.UPDATE_BUTTON.click(); 32 | await apis_page.UPDATE_API_BUTTON.click(); 33 | await assert(apis_page.API_UPDATED_MESSAGE).toBeVisible(); 34 | await main_page.openAPIs(); 35 | await $apiTableElement.click(); 36 | assert(await graphql_page.GRAPHQL_ENABLE_PLAYGROUND_TOGGLE.isSelected()).toBeTruthy(); 37 | }); 38 | 39 | await test.step('User should be able to delete GraphQL API', async () => { 40 | await apis_page.OPTIONS_BUTTON.click(); 41 | await apis_page.DELETE_BUTTON.click(); 42 | await apis_page.DELETE_API_BUTTON.click(); 43 | await assert(apis_page.API_DELETED_MESSAGE).toBeVisible(); 44 | }); 45 | 46 | await test.step('Deleted API should not be visible', async () => { 47 | await assert($apiTableElement).not.toBeVisible(); 48 | }); 49 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/graphql/crud_udg.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | import { Locator } from '@playwright/test'; 3 | 4 | test('CRUD simple UDG API', async ({ main_page, graphql_page, apis_page, page }) => { 5 | const apiDetails = { 6 | name: "UDG-test" 7 | }; 8 | let $apiTableElement: Locator; 9 | 10 | await test.step('User should be able to create new UDG API', async () => { 11 | await main_page.openAPIs(); 12 | await apis_page.DESIGN_API_BOX.click(); 13 | await apis_page.API_NAME_INPUT.fill(apiDetails.name); 14 | await apis_page.API_TYPE_UDG_BUTTON.click(); 15 | await apis_page.CONFIGURE_API_BUTTON.click(); 16 | await graphql_page.GRAPHQL_SCHEMA_TAB_BUTTON.click(); 17 | await assert(graphql_page.UDG_IMPORT_SCHEMA_FILE_FIELD).toBeVisible(); 18 | await apis_page.SAVE_BUTTON.click(); 19 | }); 20 | 21 | await test.step('New UDG API should be visible in table', async () => { 22 | await main_page.openAPIs(); 23 | $apiTableElement = page.locator(`span:text-is('${apiDetails.name}')`); 24 | await assert($apiTableElement).toBeVisible(); 25 | }); 26 | 27 | await test.step('User should be able to update UDG API', async () => { 28 | await $apiTableElement.click(); 29 | await graphql_page.GRAPHQL_ENABLE_PLAYGROUND_TOGGLE.click(); 30 | assert(await graphql_page.GRAPHQL_ENABLE_PLAYGROUND_TOGGLE.isSelected()).toBeTruthy(); 31 | await apis_page.UPDATE_BUTTON.click(); 32 | await apis_page.UPDATE_API_BUTTON.click(); 33 | await assert(apis_page.API_UPDATED_MESSAGE).toBeVisible(); 34 | await main_page.openAPIs(); 35 | await $apiTableElement.click(); 36 | assert(await graphql_page.GRAPHQL_ENABLE_PLAYGROUND_TOGGLE.isSelected()).toBeTruthy(); 37 | }); 38 | 39 | await test.step('User should be able to delete UDG API', async () => { 40 | await apis_page.OPTIONS_BUTTON.click(); 41 | await apis_page.DELETE_BUTTON.click(); 42 | await apis_page.DELETE_API_BUTTON.click(); 43 | }); 44 | 45 | await test.step('Deleted API should not be visible', async () => { 46 | await assert($apiTableElement).not.toBeVisible(); 47 | }); 48 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/graphql/udg-schema.gql: -------------------------------------------------------------------------------- 1 | type Query { 2 | restQuery: RestType 3 | gqlQuery: GqlType 4 | kafkaQuery: KafkaType 5 | } 6 | 7 | type RestType{ 8 | restTypeField1: String 9 | } 10 | 11 | type GqlType{ 12 | gqlTypeField1: String 13 | } 14 | 15 | type KafkaType{ 16 | kafkaTypeField1: String 17 | } -------------------------------------------------------------------------------- /playwright/tests/specs/keys/keys_hash_crud_test.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | import { Dashboard_connection } from '@api_connections/Dashboard_connection'; 3 | import { newAPIdefinitionWithDefaults } from '@lib/utils/API_object_designer'; 4 | 5 | const authTokenApi = { 6 | "name": "authtoken", 7 | "use_keyless": false, 8 | "use_standard_auth": true 9 | }; 10 | 11 | const apiKeysDetails = { 12 | apiName: 'keys_crud', 13 | keyExpiryTime: "1 hour", 14 | alias: 'test', 15 | }; 16 | 17 | const updatedKeyDetails = { 18 | keyExpiryTimeUpdateValue: "6 hours", 19 | aliasUpdate: 'updateAlias', 20 | metadataKey: 'test', 21 | metadataValue: '123', 22 | }; 23 | 24 | 25 | test('Create/update/delete keys without policy', async ({ createUserAndLogin, main_page, keys_page }) => { 26 | const dashboard_connection = new Dashboard_connection(); 27 | 28 | await test.step('Prerequisits: creating API definition via dashboard API', async () => { 29 | const body = newAPIdefinitionWithDefaults(authTokenApi); 30 | await dashboard_connection.createAPI(body, createUserAndLogin.userSecret); 31 | }); 32 | 33 | await test.step('User should be able to create new Key', async () => { 34 | await main_page.openKeys(); 35 | await keys_page.ADD_KEY_BUTTON.click(); 36 | await keys_page.CHOOSE_API_TOGGLE.click(); 37 | await assert(keys_page.CHOOSE_API_TABLE).toContainText(authTokenApi.name); 38 | await keys_page.CHOOSE_API_TABLE.clickCellWithText(authTokenApi.name); 39 | await keys_page.CONFIGURATIONS_TAB_BUTTON.click(); 40 | await keys_page.ALIAS_INPUT_FIELD.click(); 41 | await keys_page.ALIAS_INPUT_FIELD.fill(apiKeysDetails.alias); 42 | await keys_page.KEY_EXPIRE_DROPDOWN.click(); 43 | await keys_page.KEY_EXPIRE_DROPDOWN.selectOption(apiKeysDetails.keyExpiryTime); 44 | await keys_page.ENABLE_DETAILED_LOGGING_BUTTON.click(); 45 | await keys_page.CREATE_KEY_BUTTON.click(); 46 | console.log('>>> Key was created'); 47 | await keys_page.OK_BUTTON.click(); 48 | await keys_page.checkIfKeyCreatedPopUpDisplayed(); 49 | }); 50 | 51 | await test.step('User should be able to modify key', async () => { 52 | const keyHashValue: string = await keys_page.COPY_KEY_HASH_BUTTON.getAttribute('copy'); 53 | assert(keyHashValue).not.toBeNull(); 54 | await main_page.openKeys(); 55 | await keys_page.KEY_SEARCH_FIELD.click(); 56 | await keys_page.KEY_SEARCH_FIELD.fill(keyHashValue); 57 | await keys_page.LOOKUP_KEY_BUTTON.click(); 58 | await keys_page.CONFIGURATIONS_TAB_BUTTON.click(); 59 | const key = await keys_page.KEY_HASH_VALUE.getAttribute('copy'); 60 | assert(key).toContain(keyHashValue); 61 | await assert(keys_page.UPDATE_BUTTON).toBeVisible(); 62 | await assert(keys_page.UPDATE_WITHOUT_QUOTA_RESET_BUTTON).toBeVisible(); 63 | await assert(keys_page.DELETE_BUTTON).toBeVisible(); 64 | await assert(keys_page.ALIAS_INPUT_FIELD).toHaveValue(apiKeysDetails.alias); 65 | await keys_page.ALIAS_INPUT_FIELD.click(); 66 | await keys_page.ALIAS_INPUT_FIELD.fill(updatedKeyDetails.aliasUpdate); 67 | await keys_page.ENABLE_DETAILED_LOGGING_BUTTON.click(); 68 | await keys_page.METADATA_KEY_INPUT.fill(updatedKeyDetails.metadataKey); 69 | await keys_page.METADATA_VALUE_INPUT.fill(updatedKeyDetails.metadataValue); 70 | await keys_page.METADATA_ADD_BUTTON.click(); 71 | await keys_page.KEY_EXPIRE_DROPDOWN.selectOption(updatedKeyDetails.keyExpiryTimeUpdateValue); 72 | await keys_page.UPDATE_BUTTON.click(); 73 | await keys_page.CONFIRM_BUTTON.click(); 74 | await assert(keys_page.ALIAS_INPUT_FIELD).toHaveValue(updatedKeyDetails.aliasUpdate); 75 | }); 76 | 77 | await test.step('Confirmation popup should be displayed', async () => { 78 | assert(keys_page.checkIfKeyUpdatedPopUpDisplayed()).toBeTruthy(); 79 | }); 80 | 81 | await test.step('User should be able to delete key', async () => { 82 | const DeletedKeyHashValue = await keys_page.KEY_HASH_VALUE.getAttribute('copy'); 83 | assert(DeletedKeyHashValue).not.toBeNull(); 84 | await keys_page.DELETE_BUTTON.click(); 85 | await keys_page.DELETE_KEY_CONFIRMATION_BUTTON.click(); 86 | await keys_page.checkIfKeyDeletedPopUpDisplayed(); 87 | await keys_page.KEY_SEARCH_FIELD.click(); 88 | await keys_page.KEY_SEARCH_FIELD.fill(DeletedKeyHashValue); 89 | await keys_page.LOOKUP_KEY_BUTTON.click(); 90 | await keys_page.isCouldNotRetrieveKeyDisplayed(); 91 | }); 92 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/login_test/empty_username_test.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | 3 | test('Test Login with empty username', async ({ createUserAndLogin, main_page, login_page, page }) => { 4 | 5 | await test.step('User cannot login without providing username', async () => { 6 | await main_page.logOut(); 7 | await login_page.open(); 8 | await login_page.login("", createUserAndLogin.userPassword); 9 | const errorMessage = page.locator('div:text-is("Credentials are incorrect, please try again")'); 10 | await assert(errorMessage).toBeVisible(); 11 | }); 12 | 13 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/policies/multiple_apis_policy_test.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | import { Dashboard_connection } from '@api_connections/Dashboard_connection'; 3 | import { newAPIdefinitionWithDefaults } from '@lib/utils/API_object_designer'; 4 | 5 | const policyDetails = { 6 | policyName: 'multiple_apis', 7 | keyExpiryTime: "1 hour", 8 | }; 9 | 10 | const basicAuthApisDetails = [ 11 | { 12 | "name": "basic_auth_1", 13 | "use_basic_auth": true, 14 | "use_keyless": false 15 | }, 16 | { 17 | "name": "basic_auth_2", 18 | "use_basic_auth": true, 19 | "use_keyless": false 20 | }, 21 | { 22 | "name": "basic_auth_3", 23 | "use_basic_auth": true, 24 | "use_keyless": false 25 | }, 26 | ]; 27 | 28 | const authTokenApiDetails = [ 29 | { 30 | "name": "open_1", 31 | "use_keyless": false, 32 | 33 | } 34 | ]; 35 | 36 | test('Multiple APIs policies', async ({ createUserAndLogin, main_page, policies_page, page }) => { 37 | const dashboard_connection = new Dashboard_connection(); 38 | 39 | await test.step('Prerequisits: creating API definitions via dashboard API', async () => { 40 | const allApis = [...authTokenApiDetails, ...basicAuthApisDetails]; 41 | console.log(`>> Creating ${allApis.length} API definitions`); 42 | for (const api of allApis) { 43 | const apiDefinition = newAPIdefinitionWithDefaults(api); 44 | await dashboard_connection.createAPI(apiDefinition, createUserAndLogin.userSecret); 45 | } 46 | }); 47 | 48 | await test.step('User should be able to create new Policy with multiple APIs', async () => { 49 | await main_page.openPolicies(); 50 | await policies_page.ADD_POLICY_BUTTON.click(); 51 | await policies_page.API_TABLE.clickCellWithText(basicAuthApisDetails[0].name); 52 | await policies_page.API_TABLE.waitFor(); //waiting for table to be hidden 53 | await policies_page.API_SECTION_HEADER.click(); //opening section with API table 54 | await policies_page.API_TABLE.clickCellWithText(basicAuthApisDetails[1].name); 55 | await policies_page.CONFIGURATIONS_TAB_BUTTON.click(); 56 | await policies_page.NAME_INPUT.fill(policyDetails.policyName); 57 | await page.waitForTimeout(1000); 58 | await policies_page.KEY_EXPIRY_AFTER_DROPDOWN.selectOption(policyDetails.keyExpiryTime); 59 | await policies_page.CREATE_POLICY_BUTTON.click(); 60 | await policies_page.checkIfSuccessPopupDisplayedWithText(policies_page.policy_created_expected_mesage); 61 | }); 62 | 63 | await test.step(`User can't add policy with different Authorization type to policy`, async () => { 64 | await main_page.openPolicies(); 65 | await policies_page.POLICY_TABLE.clickCellWithText(policyDetails.policyName); 66 | await policies_page.API_SECTION_HEADER.click(); //opening section with API table 67 | const isOpenAPnotAvailable = policies_page.API_TABLE.isCellWithTextNotDisplayed(authTokenApiDetails[0].name); 68 | assert(isOpenAPnotAvailable).toBeTruthy(); 69 | }); 70 | 71 | await test.step('User should be able to add API with tha same Authorization type to policy', async () => { 72 | await policies_page.API_TABLE.clickCellWithText(basicAuthApisDetails[2].name); 73 | await policies_page.UPDATE_POLICY_BUTTON.click(); 74 | await policies_page.UPDATE_CONFIRMATION_BUTTON.click(); 75 | }); 76 | 77 | await test.step('User should be able to see all APIs assigned to policy', async () => { 78 | await main_page.openPolicies(); 79 | await policies_page.POLICY_TABLE.clickCellWithText(policyDetails.policyName); 80 | const apisObjects = page.locator('.policy-api__api-name'); 81 | await apisObjects.first().waitFor(); 82 | assert(await apisObjects.count()).toEqual(3); 83 | for (const api of basicAuthApisDetails) { 84 | await assert(page.locator(`span:text("${api.name}")`)).toBeVisible(); 85 | } 86 | }); 87 | 88 | await test.step('User should be able to delete API access from policy', async () => { 89 | await page.locator(`span:text("${basicAuthApisDetails[1].name}")`).click(); 90 | const $removeAPIButton = page.locator(`span:text("${basicAuthApisDetails[1].name}")`).locator('../..').locator(`span:text("Remove Access")`); 91 | await $removeAPIButton.click(); 92 | await policies_page.CONFIRM_BUTTON.click(); 93 | assert(await page.locator('.policy-api__api-name').count()).toEqual(2); 94 | }); 95 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/policies/policy_crud.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | import { Dashboard_connection } from '@api_connections/Dashboard_connection'; 3 | import { newAPIdefinitionWithDefaults } from '@lib/utils/API_object_designer'; 4 | 5 | const policyDetails = { 6 | apiName: 'test_policy', 7 | policyName: 'policy_auto_test_1', 8 | policyNameUpdate: 'policy_auto_test_1_update', 9 | keyEpiryTime: "1 hour", 10 | keyEpiryTimeUpdateValue: "6 hours" 11 | }; 12 | 13 | test('Create/update/delete policies', async ({ createUserAndLogin, main_page, policies_page, page }) => { 14 | const dashboard_connection = new Dashboard_connection(); 15 | 16 | await test.step('Prerequisits: creating API definition via dashboard API', async () => { 17 | const apiDefinition = newAPIdefinitionWithDefaults({ "name": policyDetails.apiName }); 18 | await dashboard_connection.createAPI(apiDefinition, createUserAndLogin.userSecret); 19 | }); 20 | 21 | await test.step('User should be able to create new Policy', async () => { 22 | await main_page.openPolicies(); 23 | await policies_page.ADD_POLICY_BUTTON.click(); 24 | await policies_page.API_TABLE.clickCellWithText(policyDetails.apiName); 25 | await policies_page.CONFIGURATIONS_TAB_BUTTON.click(); 26 | await policies_page.NAME_INPUT.fill(policyDetails.policyName); 27 | await page.waitForTimeout(1000); 28 | await policies_page.KEY_EXPIRY_AFTER_DROPDOWN.selectOption(policyDetails.keyEpiryTime); 29 | await policies_page.CREATE_POLICY_BUTTON.click(); 30 | }); 31 | 32 | await test.step('Confirmation popup should be displayed', async () => { 33 | await policies_page.checkIfPolicyCreatedPopUpDisplayed(); 34 | }); 35 | 36 | await test.step('User should be able to edit created Policy', async () => { 37 | await main_page.openPolicies(); 38 | await policies_page.POLICY_TABLE.clickCellWithText(policyDetails.policyName); 39 | await policies_page.CONFIGURATIONS_TAB_BUTTON.click(); 40 | await policies_page.KEY_EXPIRY_AFTER_DROPDOWN.selectOption(policyDetails.keyEpiryTimeUpdateValue); 41 | await policies_page.NAME_INPUT.fill(policyDetails.policyNameUpdate); 42 | await policies_page.UPDATE_POLICY_BUTTON.click(); 43 | await policies_page.UPDATE_CONFIRMATION_BUTTON.click(); 44 | }); 45 | 46 | await test.step(`Changes should be displayed after reload. Key expiry: ${policyDetails.keyEpiryTimeUpdateValue}`, async () => { 47 | await main_page.openPolicies(); 48 | await policies_page.POLICY_TABLE.clickCellWithText(policyDetails.policyNameUpdate); 49 | await policies_page.CONFIGURATIONS_TAB_BUTTON.click(); 50 | await assert(policies_page.KEY_EXPIRY_AFTER_DROPDOWN).toHaveText(policyDetails.keyEpiryTimeUpdateValue); 51 | }); 52 | 53 | await test.step('User should be able to delete policy', async () => { 54 | await main_page.openPolicies(); 55 | await policies_page.POLICY_TABLE.clickCellWithText(policyDetails.policyNameUpdate); 56 | await policies_page.DELETE_BUTTON.click(); 57 | await policies_page.DELETE_CONFIRMATION_BUTTON.click(); 58 | await main_page.openPolicies(); 59 | await assert(page.locator(`span:text-is("${policyDetails.policyNameUpdate}")`)).not.toBeVisible(); 60 | }); 61 | 62 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/policies/policy_mandatory_fields.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | 3 | import { Dashboard_connection } from '@api_connections/Dashboard_connection'; 4 | import { newAPIdefinitionWithDefaults } from '@lib/utils/API_object_designer'; 5 | 6 | const policyDetails = { 7 | apiName: 'test_api', 8 | policyName: 'policy_mandatory_fields', 9 | keyEpiryTime: "1 hour" 10 | }; 11 | 12 | test('Create/update/delete tags on policy', async ({ createUserAndLogin, main_page, policies_page }) => { 13 | const dashboard_connection = new Dashboard_connection(); 14 | 15 | await test.step('Prerequisits: creating API definition via dashboard API', async () => { 16 | const apiDefinition = newAPIdefinitionWithDefaults({ "name": policyDetails.apiName }); 17 | await dashboard_connection.createAPI(apiDefinition, createUserAndLogin.userSecret); 18 | }); 19 | 20 | await test.step('User should see error message on Access Rights tab if no API was selected', async () => { 21 | await main_page.openPolicies(); 22 | await policies_page.ADD_POLICY_BUTTON.click(); 23 | await policies_page.CREATE_POLICY_BUTTON.click(); 24 | await assert(policies_page.API_ERROR_ICON).toBeVisible(); 25 | await assert(policies_page.CONFIG_ERROR_ICON).toBeVisible(); 26 | await assert(policies_page.API_MANDATORY_TEXT).toBeVisible(); 27 | }); 28 | 29 | await test.step('User should not see errors on Access Rights tab if 1 API was selected', async () => { 30 | await policies_page.API_TABLE.clickCellWithText(policyDetails.apiName); 31 | await assert(policies_page.API_ERROR_ICON).not.toBeVisible(); 32 | await assert(policies_page.API_MANDATORY_TEXT).not.toBeVisible(); 33 | await assert(policies_page.CONFIG_ERROR_ICON).toBeVisible(); 34 | }); 35 | 36 | await test.step('User should see errors on Configurations tab - Name and Expiry missing', async () => { 37 | await policies_page.CONFIGURATIONS_TAB_BUTTON.click(); 38 | await assert(policies_page.NAME_MANDATORY_TEXT).toBeVisible(); 39 | await assert(policies_page.EXPIRY_MANDATORY_TEXT).toBeVisible(); 40 | }); 41 | 42 | await test.step('User should be able to save Policy onces all mandatory fields are entered', async () => { 43 | await policies_page.NAME_INPUT.fill(policyDetails.policyName); 44 | await policies_page.KEY_EXPIRY_AFTER_DROPDOWN.selectOption(policyDetails.keyEpiryTime); 45 | await assert(policies_page.CONFIG_ERROR_ICON).not.toBeVisible(); 46 | await assert(policies_page.NAME_MANDATORY_TEXT).not.toBeVisible(); 47 | await assert(policies_page.EXPIRY_MANDATORY_TEXT).not.toBeVisible(); 48 | await policies_page.CREATE_POLICY_BUTTON.click(); 49 | }); 50 | 51 | await test.step('Confirmation popup should be displayed', async () => { 52 | await policies_page.checkIfPolicyCreatedPopUpDisplayed(); 53 | }); 54 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/portal_settings/admin_settings.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | 3 | test('Portal Settings main Admin page', async ({ main_page, admin_settings_page, page }) => { 4 | const email = "test_notification_email@tyk.io"; 5 | 6 | await test.step('User should see proper default values', async () => { 7 | await main_page.openPortalSettings(); 8 | await assert(admin_settings_page.ACCESS_REQUEST_INPUT).toHaveValue(''); 9 | assert(await admin_settings_page.DEVELOPER_SIGN_UP_TOGGLE.isSelected()).toBeFalsy(); 10 | assert(await admin_settings_page.DEVELOPER_LOGIN_TOGGLE.isSelected()).toBeFalsy(); 11 | assert(await admin_settings_page.RESTRICTED_CATALOGUE_TOGGLE.isSelected()).toBeFalsy(); 12 | }); 13 | 14 | await test.step('User should be able to edit all fields and save changes without error', async () => { 15 | await admin_settings_page.ACCESS_REQUEST_INPUT.fill(email); 16 | await admin_settings_page.DEVELOPER_SIGN_UP_TOGGLE.click(); 17 | await admin_settings_page.DEVELOPER_LOGIN_TOGGLE.click(); 18 | await admin_settings_page.RESTRICTED_CATALOGUE_TOGGLE.click(); 19 | await admin_settings_page.SAVE_BUTTON.click(); 20 | await admin_settings_page.checkIfSettingsUpdatedPopUpDisplayed(); 21 | }); 22 | 23 | await test.step('User should see saved values after re-load values', async () => { 24 | await page.reload(); 25 | await assert(admin_settings_page.ACCESS_REQUEST_INPUT).toHaveValue(email); 26 | assert(await admin_settings_page.DEVELOPER_SIGN_UP_TOGGLE.isSelected()).toBeTruthy(); 27 | assert(await admin_settings_page.DEVELOPER_LOGIN_TOGGLE.isSelected()).toBeTruthy(); 28 | assert(await admin_settings_page.RESTRICTED_CATALOGUE_TOGGLE.isSelected()).toBeTruthy(); 29 | }); 30 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/portal_settings/api_access_settings.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | 3 | test('Portal Settings - API access manipulations', async ({ main_page, admin_settings_page, page }) => { 4 | const redirectUrl = "http://test"; 5 | const numberfAllowedRequests = "5"; 6 | 7 | await test.step('User should see proper default values', async () => { 8 | await main_page.openPortalSettings(); 9 | await admin_settings_page.API_ACCESS_TAB_BUTTON.click(); 10 | assert(await admin_settings_page.MANUAL_ACCESS_APPROVAL_TOGGLE.isSelected()).toBeFalsy(); 11 | assert(await admin_settings_page.MULTIPLE_API_SUBSCRIPTION_TOGGLE.isSelected()).toBeFalsy(); 12 | assert(await admin_settings_page.THIRD_PARTY_REDIRECT_TOGGLE.isSelected()).toBeFalsy(); 13 | await assert(admin_settings_page.NUMBER_OF_ALLOWED_REQUESTS_INPUT).toHaveValue("0"); 14 | }); 15 | 16 | await test.step('User should be able to edit all fields and save changes without error', async () => { 17 | await admin_settings_page.MANUAL_ACCESS_APPROVAL_TOGGLE.click(); 18 | await admin_settings_page.HIDE_API_SECRET_TOGGLE.click(); 19 | await admin_settings_page.MULTIPLE_API_SUBSCRIPTION_TOGGLE.click(); 20 | await admin_settings_page.THIRD_PARTY_REDIRECT_TOGGLE.click(); 21 | await admin_settings_page.REDIRECT_URL_INPUT.fill(redirectUrl); 22 | await admin_settings_page.NUMBER_OF_ALLOWED_REQUESTS_INPUT.fill(numberfAllowedRequests); 23 | await admin_settings_page.SAVE_BUTTON.click(); 24 | await admin_settings_page.checkIfSettingsUpdatedPopUpDisplayed(); 25 | }); 26 | 27 | await test.step('User should see saved values after re-load values', async () => { 28 | await page.reload(); 29 | await admin_settings_page.API_ACCESS_TAB_BUTTON.click(); 30 | await assert(admin_settings_page.REDIRECT_URL_INPUT).toHaveValue(redirectUrl); 31 | await assert(admin_settings_page.NUMBER_OF_ALLOWED_REQUESTS_INPUT).toHaveValue(numberfAllowedRequests); 32 | assert(await admin_settings_page.MANUAL_ACCESS_APPROVAL_TOGGLE.isSelected()).toBeTruthy(); 33 | assert(await admin_settings_page.HIDE_API_SECRET_TOGGLE.isSelected()).toBeTruthy(); 34 | assert(await admin_settings_page.MULTIPLE_API_SUBSCRIPTION_TOGGLE.isSelected()).toBeTruthy(); 35 | assert(await admin_settings_page.THIRD_PARTY_REDIRECT_TOGGLE.isSelected()).toBeTruthy(); 36 | }); 37 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/portal_settings/dcr_settings.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | 3 | test('Portal Settings - API access manipulations', async ({ main_page, admin_settings_page, page }) => { 4 | const inputs = { 5 | provider: "Okta", 6 | grant_types: ["Refresh Token", "Password"], 7 | token_endpoint_auth: "Client Secret - Post", 8 | response_types: ["Token", "Authorization Code"], 9 | idp_host: "http://localhost", 10 | client_registration_endpoint: "http://localhost/client", 11 | token: "testToken" 12 | }; 13 | const errorElementClass = /has-error/; 14 | 15 | await test.step('DCR should be disabled by default', async () => { 16 | await main_page.openPortalSettings(); 17 | await admin_settings_page.API_ACCESS_TAB_BUTTON.click(); 18 | assert(await admin_settings_page.DCR_TOGGLE.isSelected()).toBeFalsy(); 19 | }); 20 | 21 | await test.step('If DCR is enabled fields become mandatory', async () => { 22 | await admin_settings_page.DCR_TOGGLE.click(); 23 | await admin_settings_page.SAVE_BUTTON.click(); 24 | const dropdowns = [admin_settings_page.DCR_PROVIDERS_DROPDOWN, admin_settings_page.DCR_TOKEN_ENDPOINT_DROPDOWN, 25 | admin_settings_page.DCR_GRANT_TYPES_DROPDOWN, admin_settings_page.DCR_RESPONSE_TYPE_DROPDOWN]; 26 | for (const dropdown of dropdowns) { 27 | await assert(dropdown).toHaveAttribute("class", errorElementClass); 28 | } 29 | await assert(admin_settings_page.DCR_HOST_INPUT).toHaveAttribute("error", "Enter an IDP host"); 30 | await assert(admin_settings_page.DCR_CLIENT_REGISTRATION_ENDPOINT_INPUT).toHaveAttribute("error", "Enter an endpoint"); 31 | await assert(admin_settings_page.DCR_TOKEN_INPUT).toHaveAttribute("error", ""); //Token is not a mandatory field -> no error 32 | }); 33 | 34 | await test.step('User should be able to edit DCR details and save changes without error', async () => { 35 | await admin_settings_page.DCR_TOKEN_INPUT.scrollIntoView(); 36 | await admin_settings_page.DCR_PROVIDERS_DROPDOWN.selectOption(inputs.provider); 37 | await admin_settings_page.DCR_GRANT_TYPES_DROPDOWN.selectOptions(inputs.grant_types); 38 | await admin_settings_page.DCR_TOKEN_ENDPOINT_DROPDOWN.selectOption(inputs.token_endpoint_auth); 39 | await admin_settings_page.DCR_RESPONSE_TYPE_DROPDOWN.selectOptions(inputs.response_types); 40 | await admin_settings_page.DCR_HOST_INPUT.fill(inputs.idp_host); 41 | await admin_settings_page.DCR_CLIENT_REGISTRATION_ENDPOINT_INPUT.fill(inputs.client_registration_endpoint); 42 | await admin_settings_page.DCR_TOKEN_INPUT.fill(inputs.token); 43 | await admin_settings_page.SAVE_BUTTON.click(); 44 | await admin_settings_page.checkIfSettingsUpdatedPopUpDisplayed(); 45 | }); 46 | 47 | await test.step('User should see saved values after re-load values', async () => { 48 | await page.reload(); 49 | await admin_settings_page.API_ACCESS_TAB_BUTTON.click(); 50 | assert(await admin_settings_page.DCR_TOGGLE.isSelected()).toBeTruthy(); 51 | await assert(admin_settings_page.DCR_PROVIDERS_DROPDOWN.locator(`span:text("${inputs.provider}")`)).toBeVisible(); 52 | for (const grant_type of inputs.grant_types) { 53 | await assert(admin_settings_page.DCR_GRANT_TYPES_DROPDOWN.locator(`span:text("${grant_type}")`)).toBeVisible(); 54 | } 55 | await assert(admin_settings_page.DCR_TOKEN_ENDPOINT_DROPDOWN.locator(`span:text("${inputs.token_endpoint_auth}")`)).toBeVisible(); 56 | for (const response_type of inputs.response_types) { 57 | await assert(admin_settings_page.DCR_RESPONSE_TYPE_DROPDOWN.locator(`span:text("${response_type}")`)).toBeVisible(); 58 | } 59 | await assert(admin_settings_page.DCR_HOST_INPUT).toHaveValue(inputs.idp_host); 60 | await assert(admin_settings_page.DCR_CLIENT_REGISTRATION_ENDPOINT_INPUT).toHaveValue(inputs.client_registration_endpoint); 61 | await assert(admin_settings_page.DCR_TOKEN_INPUT).toHaveValue(inputs.token); 62 | }); 63 | 64 | await test.step('User is able to save Settings with DCR turned off (fields are no longer mandatory)', async () => { 65 | await admin_settings_page.DCR_HOST_INPUT.click(); 66 | await admin_settings_page.DCR_HOST_INPUT.clear(); 67 | await admin_settings_page.DCR_TOGGLE.click(); 68 | assert(await admin_settings_page.DCR_TOGGLE.isSelected()).toBeFalsy(); 69 | await admin_settings_page.SAVE_BUTTON.click(); 70 | await admin_settings_page.checkIfSettingsUpdatedPopUpDisplayed(); 71 | }); 72 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/test.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from 'lib/utils/fixtures'; 2 | 3 | 4 | test('Login/logout check', async ({ page }) => { 5 | 6 | await test.step('Login', async () => { 7 | await assert(page).toHaveTitle('Tyk.io API Gateway'); 8 | }); 9 | 10 | 11 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/tib/public_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsR1fF+JAA+s/O8YGXONx 3 | K5JRc+4z/NtiFAww39lC/2qWD2b/30ojrJVNbE500QzOTOO0YoJ3eWJupjIqFm3I 4 | mK+x8gSCWNz+pneWVY7RaoEbmSgZRQ9YizYpVUnS4wb5UxhkzvCwsaEhqWja6yP0 5 | inaUIuW3gzrTuKTG2VBAnMtcxYn7ttes9/BZebh0giSO0vtj7pg8Ai0n3I2moNHU 6 | umiJ1ye3pYEjys32sSb0HUGJf+T0k5ELs+dBM/Z7SuCq9toLNX/Uj196ZPQiv+Bh 7 | CmM4VQyID5wR5riIR11/0z0Er4FZjLAPNBFlE5bOMC87UXSf7kylvgZUuLHOKOFc 8 | 2wIDAQAB 9 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /playwright/tests/specs/users/users_creation.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | import { generateRandomEmail } from '@lib/utils/utils'; 3 | 4 | const userDetails = { 5 | firstName: "user_name", 6 | lastName: "user_last_name", 7 | emailAdress: generateRandomEmail(), 8 | password: "test123", 9 | isUserAnAdmin: true 10 | }; 11 | const invalidEmail = { emailAdress: "not_an_email" }; 12 | const shortPassword = { password: "test" }; 13 | 14 | test('Users creation', async ({ main_page, users_page, page }) => { 15 | 16 | const fillUserData = async (userDetailsObject: any) => { 17 | await users_page.ADD_USER_BUTTON.click(); 18 | await users_page.FIRST_NAME_INPUT.fill(userDetailsObject.firstName); 19 | await users_page.LAST_NAME_INPUT.fill(userDetailsObject.lastName); 20 | await users_page.EMAIL_ADRESS_INPUT.fill(userDetailsObject.emailAdress); 21 | await users_page.PASSWORD_INPUT.fill(userDetailsObject.password); 22 | if (userDetailsObject.isUserAnAdmin) { 23 | await users_page.ACCOUNT_IS_ADMIN_CHECKBOX.check(); 24 | } 25 | }; 26 | 27 | await test.step('Admin should NOT be able to create user with invalid email', async () => { 28 | await main_page.openUsers(); 29 | await fillUserData({ ...userDetails, ...invalidEmail }); 30 | await users_page.SAVE_BUTTON.click(); 31 | await users_page.checkIfErrorPopUpDisplayed(); 32 | await main_page.openUsers(); 33 | await users_page.USERS_TABLE.isCellWithTextNotDisplayed(invalidEmail.emailAdress); 34 | }); 35 | 36 | await test.step('Admin should be able to create inactive user', async () => { 37 | await main_page.openUsers(); 38 | await fillUserData(userDetails); 39 | await users_page.ACCOUNT_IS_ACTIVE_CHECKBOX.uncheck(); 40 | await users_page.SAVE_BUTTON.click(); 41 | await users_page.USERS_TABLE.clickCellWithText(userDetails.firstName); 42 | const isUserActive = await users_page.ACCOUNT_IS_ACTIVE_CHECKBOX.isSelected(); 43 | assert(isUserActive).toBeFalsy(); 44 | }); 45 | 46 | await test.step('Admin should NOT be able to create user with already existing email', async () => { 47 | await main_page.openUsers(); 48 | await fillUserData(userDetails); //user with email in userDetails is already created 49 | await users_page.SAVE_BUTTON.click(); 50 | assert(users_page.checkIfUserAlreadyExistsPopUpDisplayed()).toBeTruthy(); 51 | }); 52 | 53 | await test.step('Admin should NOT be able to create user with short password', async () => { 54 | await main_page.openUsers(); 55 | await fillUserData({ ...userDetails, ...shortPassword }); 56 | await users_page.SAVE_BUTTON.click(); 57 | await users_page.checkIfErrorPopUpDisplayed(); 58 | }); 59 | 60 | await test.step('Admin should be able to create user with limited permissions', async () => { 61 | await main_page.openUsers(); 62 | const userForPermissionsTest = { 63 | firstName: "user_permissions", 64 | lastName: "user_last_name", 65 | emailAdress: generateRandomEmail(), 66 | password: "test123", 67 | }; 68 | await fillUserData(userForPermissionsTest); 69 | await users_page.selectReadAccessForPermission('analytics'); 70 | await page.waitForTimeout(1000); 71 | await users_page.SAVE_BUTTON.click(); 72 | 73 | await users_page.checkIfUserCreatedPopUpDisplayed(); 74 | await main_page.openUsers(); 75 | await users_page.USERS_TABLE.clickCellWithText(userForPermissionsTest.firstName); 76 | await assert(users_page.PERMISSIONS_ANALYTICS_ROW).toHaveValue('read'); 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /playwright/tests/specs/users/users_crud.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | 3 | import { generateRandomEmail } from '../../../lib/utils/utils'; 4 | 5 | const userDetails = { 6 | firstName: "crud_user_name", 7 | firstNameUpdate: "crud_user_name_update", 8 | lastName: "crud_user_last_name", 9 | emailAdress: generateRandomEmail(), 10 | password: "test123" 11 | }; 12 | 13 | test('Create/update/delete users', async ({ main_page, users_page }) => { 14 | 15 | await test.step('Admin should be able to create new user', async () => { 16 | await main_page.openUsers(); 17 | await users_page.ADD_USER_BUTTON.click(); 18 | await users_page.FIRST_NAME_INPUT.fill(userDetails.firstName); 19 | await users_page.LAST_NAME_INPUT.fill(userDetails.lastName); 20 | await users_page.EMAIL_ADRESS_INPUT.fill(userDetails.emailAdress); 21 | await users_page.PASSWORD_INPUT.fill(userDetails.password); 22 | await users_page.ACCOUNT_IS_ADMIN_CHECKBOX.check(); 23 | await users_page.SAVE_BUTTON.click(); 24 | await users_page.checkIfUserCreatedPopUpDisplayed(); 25 | await users_page.USERS_TABLE.clickCellWithText(userDetails.firstName); 26 | await assert(users_page.EMAIL_ADRESS_INPUT).toHaveValue(userDetails.emailAdress); 27 | }); 28 | 29 | await test.step('Admin should be able to edit created user', async () => { 30 | await users_page.FIRST_NAME_INPUT.fill(userDetails.firstNameUpdate); 31 | await users_page.UPDATE_BUTTON.click(); 32 | await users_page.checkIfUserCreatedPopUpDisplayed(); 33 | await main_page.openUsers(); 34 | await users_page.USERS_TABLE.clickCellWithText(userDetails.firstNameUpdate); 35 | await assert(users_page.FIRST_NAME_INPUT).toHaveValue(userDetails.firstNameUpdate); 36 | }); 37 | 38 | await test.step('Admin should be able to delete user', async () => { 39 | await users_page.DELETE_BUTTON.click(); 40 | const userIsNotVisibleInTable = await users_page.USERS_TABLE.isCellWithTextNotDisplayed(userDetails.emailAdress); 41 | assert(userIsNotVisibleInTable).toBeTruthy(); 42 | }); 43 | 44 | }); -------------------------------------------------------------------------------- /playwright/tests/specs/webhooks/webhooks_crud.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from '@fixtures'; 2 | 3 | const NewWebhookDetails = { 4 | "name": "QA test", 5 | "RequestMethod": "GET", 6 | "Target": "http://test.com", 7 | "HeaderKey": "xyz", 8 | "HeaderValue": "123", 9 | }; 10 | 11 | const UpdatedWebhookDetails = { 12 | "name": "Webhook", 13 | "RequestMethod": "POST", 14 | "Target": "http://test456.com", 15 | }; 16 | 17 | const emptyWebhookMessage = "No data to display"; 18 | 19 | test('CRUD operation on webhook', async ({ main_page, webhooks_page }) => { 20 | 21 | await test.step('User should be able to add new webhook', async () => { 22 | await main_page.openWebhooks(); 23 | await webhooks_page.ADD_WEBHOOK.click(); 24 | await webhooks_page.NAME_INPUT.click(); 25 | await webhooks_page.NAME_INPUT.fill(NewWebhookDetails.name); 26 | await webhooks_page.REQUEST_METHOD_DROPDOWN.selectOption(NewWebhookDetails.RequestMethod); 27 | await webhooks_page.TARGET_INPUT.click(); 28 | await webhooks_page.TARGET_INPUT.fill(NewWebhookDetails.Target); 29 | await webhooks_page.HEADER_KEY.fill(NewWebhookDetails.HeaderKey); 30 | await webhooks_page.HEADER_VALUE.fill(NewWebhookDetails.HeaderValue); 31 | await webhooks_page.ADD_HEADER_BUTTON.click(); 32 | await webhooks_page.SAVE_BUTTON.click(); 33 | }); 34 | 35 | await test.step('User should be able to modify the webhook', async () => { 36 | await webhooks_page.WEBHOOK_TABLE.clickCellWithText(NewWebhookDetails.name); 37 | await assert(webhooks_page.NAME_INPUT).toHaveValue(NewWebhookDetails.name); 38 | await assert(webhooks_page.REQUEST_METHOD_DROPDOWN).toHaveValue(NewWebhookDetails.RequestMethod); 39 | await assert(webhooks_page.TARGET_INPUT).toHaveValue(NewWebhookDetails.Target); 40 | await webhooks_page.NAME_INPUT.fill(UpdatedWebhookDetails.name); 41 | await webhooks_page.REQUEST_METHOD_DROPDOWN.selectOption(UpdatedWebhookDetails.RequestMethod); 42 | await webhooks_page.TARGET_INPUT.fill(UpdatedWebhookDetails.Target); 43 | await webhooks_page.UPDATE_BUTTON.click(); 44 | await assert(webhooks_page.NAME_INPUT).toHaveValue(UpdatedWebhookDetails.name); 45 | await assert(webhooks_page.REQUEST_METHOD_DROPDOWN).toHaveValue(UpdatedWebhookDetails.RequestMethod); 46 | await assert(webhooks_page.TARGET_INPUT).toHaveValue(UpdatedWebhookDetails.Target); 47 | }); 48 | 49 | await test.step('User must be able to delete webhook', async () => { 50 | await webhooks_page.DELETE_BUTTON.click(); 51 | await webhooks_page.DELETE_KEY_CONFIRMATION_BUTTON.click(); 52 | await assert(webhooks_page.NO_DATA_TO_DISPLAY).toHaveText(emptyWebhookMessage); 53 | }); 54 | 55 | }); -------------------------------------------------------------------------------- /playwright/update_xray.sh: -------------------------------------------------------------------------------- 1 | echo "Sending update of test execution to Xray" 2 | if [ "$STATUS" == "success" ]; then 3 | RESULT="PASSED" 4 | else 5 | RESULT="FAILED" 6 | fi 7 | echo "Checking branch: $BRANCH" 8 | if [ "$BRANCH" == "refs/heads/master" ]; then 9 | EXECUTION=QA-894 10 | fi 11 | if [ "$BRANCH" == "refs/heads/release-4.3" ]; then 12 | EXECUTION=QA-902 13 | fi 14 | if [ "$BRANCH" == "refs/heads/release-4" ]; then 15 | EXECUTION=QA-903 16 | fi 17 | if [ "$BRANCH" == "refs/heads/release-4-lts" ]; then 18 | EXECUTION=QA-904 19 | fi 20 | 21 | if [[ ! -z "$EXECUTION" ]]; then 22 | echo "Requesting Token" 23 | TOKEN=$(curl -H "Content-Type: application/json" -X POST --data "{ \"client_id\": \"$CLIENT_ID\",\"client_secret\": \"$CLIENT_SECRET\" }" https://xray.cloud.getxray.app/api/v2/authenticate| tr -d '"') 24 | echo "Sending update $RESULT on $TEST and execution $EXECUTION" 25 | curl -H "Authorization: Bearer $TOKEN" -X POST https://xray.cloud.getxray.app/api/v2/import/execution \ 26 | -d '{"testExecutionKey":"'$EXECUTION'","tests":[{"testKey":"'$TEST'","status":"'$RESULT'"}]}' \ 27 | -H 'Content-Type: application/json' 28 | else 29 | echo "Branch $BRANCH is not specified for updated" 30 | fi 31 | -------------------------------------------------------------------------------- /template_test.js: -------------------------------------------------------------------------------- 1 | 2 | import { login_page } from '../../../lib/pom/Login_page'; 3 | import { main_page } from '../../../lib/pom/Main_Page'; 4 | 5 | describe('HIGH LEVEL DESCRIPTION OF FEATURE', () => { 6 | 7 | before(() => { 8 | const envDetails = setUpEnv(); 9 | login_page.open(); 10 | login_page.login(envDetails.userEmail, envDetails.userPassword); 11 | }); 12 | 13 | it('User should be able to.....', () => { 14 | 15 | }); 16 | 17 | it('User should be able to......', () => { 18 | 19 | }); 20 | }); -------------------------------------------------------------------------------- /test/specs/api_designer/create_api_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { apis_page } from '../../../lib/pom/Apis_page'; 3 | import { main_page } from '../../../lib/pom/Main_page'; 4 | 5 | describe('Create simple API', () => { 6 | const apiDetails = { 7 | name: "test" 8 | }; 9 | let $apiTableElement; 10 | 11 | before(() => { 12 | const envDetails = setUpEnv(); 13 | login_page.open(); 14 | login_page.login(envDetails.userEmail, envDetails.userPassword); 15 | }); 16 | 17 | it('User should be able to create new API', () => { 18 | main_page.openAPIs(); 19 | apis_page.DESIGN_API_BOX.click(); 20 | apis_page.API_NAME_INPUT.setValue(apiDetails.name); 21 | browser.pause(2000);//TODO replace using wait 22 | apis_page.CONFIGURE_API_BUTTON.click(); 23 | apis_page.SAVE_BUTTON.click(); 24 | }); 25 | 26 | it('New API should be visible in table', () => { 27 | main_page.openAPIs(); 28 | $apiTableElement = $(`span=${apiDetails.name}`); 29 | wdioExpect($apiTableElement).toBeClickable(); 30 | }); 31 | 32 | it('User should be able to delete API', () => { 33 | $apiTableElement.click(); 34 | apis_page.OPTIONS_BUTTON.click(); 35 | apis_page.DELETE_BUTTON.click(); 36 | apis_page.DELETE_API_BUTTON.click(); 37 | }); 38 | 39 | it('Deleted API should not be visible', () => { 40 | wdioExpect($apiTableElement).not.toBeDisplayed(); 41 | }); 42 | }); -------------------------------------------------------------------------------- /test/specs/api_designer/oas_api_page_search_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { apis_page } from '../../../lib/pom/Apis_page'; 3 | import { URL, LANDING_PAGE_PATH } from './../../../config_variables'; 4 | 5 | xdescribe('Test Search functionality on OAS API Page', () => { 6 | const apiName = "oas-api-search-test"; 7 | let envDetails; 8 | 9 | before(() => { 10 | envDetails = setUpEnv(); 11 | login_page.open(); 12 | login_page.login(envDetails.userEmail, envDetails.userPassword); 13 | }); 14 | 15 | it('User should be able to open search bar by clicking search icon', () => { 16 | browser.navigateTo(URL + LANDING_PAGE_PATH); //TO BE REMOVED WHEN RELEASED 17 | apis_page.DESIGN_API_BOX.click(); 18 | apis_page.API_NAME_INPUT.setValue(apiName); 19 | apis_page.OAS_API_REST_RADIO.click(); 20 | apis_page.OAS_NEXT_BUTTON.click(); 21 | wdioExpect(apis_page.OAS_SEARCH_ICON).toBeDisplayed(); 22 | apis_page.OAS_SEARCH_ICON.click(); 23 | wdioExpect(apis_page.OAS_SEARCH_BAR).toBeDisplayed(); 24 | }); 25 | 26 | it('User should be able to close search bar by clicking X icon', () => { 27 | apis_page.OAS_SEARCH_BAR_CLOSE_ICON.click(); 28 | wdioExpect(apis_page.OAS_SEARCH_BAR).not.toBeDisplayed(); 29 | }); 30 | 31 | it('User should be able to open search bar with keyboard shortcut ctrl+f', () => { 32 | browser.keys(["\uE009", "f"]); 33 | browser.keys("\uE009"); 34 | wdioExpect(apis_page.OAS_SEARCH_BAR).toBeDisplayed(); 35 | }); 36 | 37 | it('User should be able to close search bar with keyboard shortcut ESC', () => { 38 | browser.keys("\uE00C"); 39 | wdioExpect(apis_page.OAS_SEARCH_BAR).not.toBeDisplayed(); 40 | }); 41 | 42 | it('User should be able to open search bar with keyboard shortcut cmd+f', () => { 43 | browser.keys(["\uE03D", "f"]); 44 | browser.keys("\uE03D"); 45 | wdioExpect(apis_page.OAS_SEARCH_BAR).toBeDisplayed(); 46 | }); 47 | 48 | it('User should be able to search by main section title', () => { 49 | apis_page.OAS_SEARCH_BAR.setValue("Listen path"); 50 | wdioExpect(apis_page.OAS_LISTEN_PATH_INPUT).toBeDisplayed(); 51 | wdioExpect(apis_page.OAS_AUTHENTICATION_DROPDOWN).not.toBeDisplayed(); 52 | wdioExpect(apis_page.API_NAME_INPUT).not.toBeDisplayed(); 53 | wdioExpect(apis_page.OAS_TARGET_URL_INPUT).not.toBeDisplayed(); 54 | }); 55 | 56 | it('User should be able to search by "potential match" text', () => { 57 | apis_page.OAS_SEARCH_BAR.setValue("JWT"); 58 | wdioExpect(apis_page.OAS_AUTHENTICATION_DROPDOWN).toBeDisplayed(); 59 | wdioExpect(apis_page.OAS_HIDDEN_MATCH_MSG).toHaveText('A match for "JWT" can be found in this section, if proper settings are configured'); 60 | wdioExpect(apis_page.OAS_LISTEN_PATH_INPUT).not.toBeDisplayed(); 61 | wdioExpect(apis_page.API_NAME_INPUT).not.toBeDisplayed(); 62 | wdioExpect(apis_page.OAS_TARGET_URL_INPUT).not.toBeDisplayed(); 63 | }); 64 | 65 | it('User should be able to see multiple results when typing', () => { 66 | apis_page.OAS_SEARCH_BAR.setValue("strip"); 67 | wdioExpect(apis_page.OAS_LISTEN_PATH_INPUT).toBeDisplayed(); 68 | wdioExpect(apis_page.OAS_AUTHENTICATION_DROPDOWN).toBeDisplayed(); 69 | wdioExpect(apis_page.API_NAME_INPUT).not.toBeDisplayed(); 70 | wdioExpect(apis_page.OAS_TARGET_URL_INPUT).not.toBeDisplayed(); 71 | }); 72 | 73 | it('User should be able to clear search results', () => { 74 | apis_page.OAS_SEARCH_BAR_CLEAR_ICON.click(); 75 | browser.pause(2000); 76 | wdioExpect(apis_page.OAS_LISTEN_PATH_INPUT).toBeDisplayed(); 77 | wdioExpect(apis_page.OAS_AUTHENTICATION_DROPDOWN).toBeDisplayed(); 78 | wdioExpect(apis_page.API_NAME_INPUT).toBeDisplayed(); 79 | wdioExpect(apis_page.OAS_TARGET_URL_INPUT).toBeDisplayed(); 80 | wdioExpect(apis_page.OAS_SEARCH_BAR).toBeDisplayed(); 81 | }); 82 | 83 | }); -------------------------------------------------------------------------------- /test/specs/api_designer/oas_fields_validation_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { apis_page } from '../../../lib/pom/Apis_page'; 3 | import { URL, LANDING_PAGE_PATH } from './../../../config_variables'; 4 | import { expect } from 'chai'; 5 | 6 | xdescribe('Test mandatory fields on OAS API designer page', () => { 7 | const apiName = "oas-api-validation-test"; 8 | let envDetails; 9 | 10 | before(() => { 11 | envDetails = setUpEnv(); 12 | login_page.open(); 13 | login_page.login(envDetails.userEmail, envDetails.userPassword); 14 | }); 15 | 16 | it('API Name is required on popup', () => { 17 | browser.navigateTo(URL + LANDING_PAGE_PATH); //TO BE REMOVED WHEN RELEASED 18 | apis_page.DESIGN_API_BOX.click(); 19 | apis_page.OAS_NEXT_BUTTON.click(); 20 | let apiNameErrorMessage = $('//input[@name="x-tyk-api-gateway.info.name"]//following::p[1]') 21 | wdioExpect(apiNameErrorMessage).toHaveText('API Name is required'); 22 | }); 23 | 24 | it('API Name is required on main designer page', () => { 25 | apis_page.API_NAME_INPUT.setValue(apiName); 26 | apis_page.OAS_NEXT_BUTTON.click(); 27 | apis_page.API_NAME_INPUT.setValue(''); 28 | apis_page.OAS_SAVE_BUTTON.click(); 29 | let apiNameErrorMessage = $('//input[@name="x-tyk-api-gateway.info.name"]//following::p[1]') 30 | wdioExpect(apiNameErrorMessage).toHaveText('API Name is required'); 31 | }); 32 | 33 | it('Listen Path is required on main designer page', () => { 34 | let listenPathErrorMessage = $('//input[@name="x-tyk-api-gateway.server.listenPath.value"]//following::p[1]'); 35 | wdioExpect(listenPathErrorMessage).toHaveText('Listen Path is required'); 36 | }); 37 | 38 | it('Target URL is required on main designer page', () => { 39 | let targetURLErrorMessage = $('//input[@name="x-tyk-api-gateway.upstream.url"]//following::p[1]'); 40 | wdioExpect(targetURLErrorMessage).toHaveText('Target URL is required'); 41 | }); 42 | 43 | it('Access is required on main designer page', () => { 44 | let accessErrorMessage = $('//span[@title="Select access"]//following::p[contains(@class, "error-message")]'); 45 | wdioExpect(accessErrorMessage).toHaveText('Access is required'); 46 | }); 47 | 48 | it('GW Status is required on main designer page', () => { 49 | let statusErrorMessage = $('//span[@title="Select status"]//following::p[contains(@class, "error-message")]'); 50 | wdioExpect(statusErrorMessage).toHaveText('Status is required'); 51 | }); 52 | 53 | it('Authentication is required on main designer page', () => { 54 | let authErrorMessage = $('//span[@title="Select authentication type"]//following::p[contains(@class, "error-message")]'); 55 | wdioExpect(authErrorMessage).toHaveText('Authentication is required'); 56 | }); 57 | 58 | it('Auth Key Header is required on main designer page', () => { 59 | apis_page.OAS_AUTHENTICATION_DROPDOWN.selectOption('Auth Token'); 60 | let authHeaderErrorMessage = $('//input[@name="x-tyk-api-gateway.server.authentication.token.header.name"]//following::p[1]'); 61 | wdioExpect(authHeaderErrorMessage).toHaveText('Auth Key Header Name is required'); 62 | }); 63 | 64 | }); -------------------------------------------------------------------------------- /test/specs/api_designer/oas_middleware_tests/oas_api_allow_plugin_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../../lib/pom/Login_page'; 2 | import { apis_page } from '../../../../lib/pom/Apis_page'; 3 | import { main_page } from '../../../../lib/pom/Main_page'; 4 | import { endpoints_page } from '../../../../lib/pom/Endpoints_page'; 5 | import { expect } from 'chai'; 6 | 7 | describe('Test Allow List plugin on OAS Endpoints designer page', () => { 8 | let envDetails; 9 | 10 | before(() => { 11 | envDetails = setUpEnv(); 12 | login_page.open(); 13 | login_page.login(envDetails.userEmail, envDetails.userPassword); 14 | }); 15 | 16 | it('User can add Allow List plugin and save API', () => { 17 | main_page.openAPIs(); 18 | apis_page.DESIGN_API_BOX.click(); 19 | apis_page.API_TYPE_OAS_BUTTON.click(); 20 | apis_page.API_NAME_INPUT.setValue('allow-plugin-test'); 21 | apis_page.OAS_NEXT_BUTTON.click(); 22 | apis_page.OAS_GW_STATUS_DROPDOWN.selectOption("Active"); 23 | apis_page.OAS_ACCESS_DROPDOWN.selectOption("External"); 24 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 25 | endpoints_page.addNewEndpoint("/ip", "GET"); 26 | endpoints_page.addMiddlewareByName("Allow List"); 27 | apis_page.OAS_SAVE_BUTTON.click(); 28 | expect(apis_page.isApiCreatedPopUpDisplayed()).to.be.true; 29 | }); 30 | 31 | it('Allow List plugin is displayed after page reload', () => { 32 | browser.refresh(); 33 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 34 | expect(endpoints_page.verifyMiddlewareExistsByName("Allow List")).to.be.true; 35 | }); 36 | 37 | it('User can disable Allow List plugin and save API', () => { 38 | browser.refresh(); 39 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 40 | apis_page.EDIT_BUTTON.click(); 41 | endpoints_page.changeMiddlewareStatusByName("Allow List"); 42 | apis_page.OAS_SAVE_BUTTON.click(); 43 | expect(apis_page.isApiUpdatedPopUpDisplayed()).to.be.true; 44 | }); 45 | 46 | it('Allow List plugin is disabled after page reload', () => { 47 | browser.refresh(); 48 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 49 | expect(endpoints_page.verifyMiddlewareDisabledByName("Allow List")).to.be.true; 50 | }); 51 | 52 | it('User can enable Allow List plugin and save API', () => { 53 | browser.refresh(); 54 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 55 | apis_page.EDIT_BUTTON.click(); 56 | endpoints_page.changeMiddlewareStatusByName("Allow List"); 57 | apis_page.OAS_SAVE_BUTTON.click(); 58 | expect(apis_page.isApiUpdatedPopUpDisplayed()).to.be.true; 59 | }); 60 | 61 | it('Allow List plugin is enabled after page reload', () => { 62 | browser.refresh(); 63 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 64 | expect(endpoints_page.verifyMiddlewareDisabledByName("Allow List")).to.be.false; 65 | }); 66 | 67 | it('User can remove Allow List plugin and save API', () => { 68 | browser.refresh(); 69 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 70 | apis_page.EDIT_BUTTON.click(); 71 | endpoints_page.removeMiddlewareByName("Allow List"); 72 | apis_page.OAS_SAVE_BUTTON.click(); 73 | expect(apis_page.isApiUpdatedPopUpDisplayed()).to.be.true; 74 | }); 75 | 76 | it('Allow List plugin is removed after page reload', () => { 77 | browser.refresh(); 78 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 79 | expect(endpoints_page.verifyMiddlewareExistsByName("Allow List")).to.be.false; 80 | }); 81 | 82 | }); 83 | -------------------------------------------------------------------------------- /test/specs/api_designer/oas_middleware_tests/oas_api_block_plugin_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../../lib/pom/Login_page'; 2 | import { apis_page } from '../../../../lib/pom/Apis_page'; 3 | import { main_page } from '../../../../lib/pom/Main_page'; 4 | import { endpoints_page } from '../../../../lib/pom/Endpoints_page'; 5 | import { expect } from 'chai'; 6 | 7 | describe('Test Block List plugin on OAS Endpoints designer page', () => { 8 | let envDetails; 9 | 10 | before(() => { 11 | envDetails = setUpEnv(); 12 | login_page.open(); 13 | login_page.login(envDetails.userEmail, envDetails.userPassword); 14 | }); 15 | 16 | it('User can add Block List plugin and save API', () => { 17 | main_page.openAPIs(); 18 | apis_page.DESIGN_API_BOX.click(); 19 | apis_page.API_TYPE_OAS_BUTTON.click(); 20 | apis_page.API_NAME_INPUT.setValue('Block-plugin-test'); 21 | apis_page.OAS_NEXT_BUTTON.click(); 22 | apis_page.OAS_GW_STATUS_DROPDOWN.selectOption("Active"); 23 | apis_page.OAS_ACCESS_DROPDOWN.selectOption("External"); 24 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 25 | endpoints_page.addNewEndpoint("/ip", "GET"); 26 | endpoints_page.addMiddlewareByName("Block List"); 27 | apis_page.OAS_SAVE_BUTTON.click(); 28 | expect(apis_page.isApiCreatedPopUpDisplayed()).to.be.true; 29 | }); 30 | 31 | it('Block List plugin is displayed after page reload', () => { 32 | browser.refresh(); 33 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 34 | expect(endpoints_page.verifyMiddlewareExistsByName("Block List")).to.be.true; 35 | }); 36 | 37 | it('User can disable Block List plugin and save API', () => { 38 | browser.refresh(); 39 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 40 | apis_page.EDIT_BUTTON.click(); 41 | endpoints_page.changeMiddlewareStatusByName("Block List"); 42 | apis_page.OAS_SAVE_BUTTON.click(); 43 | expect(apis_page.isApiUpdatedPopUpDisplayed()).to.be.true; 44 | }); 45 | 46 | it('Block List plugin is disabled after page reload', () => { 47 | browser.refresh(); 48 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 49 | expect(endpoints_page.verifyMiddlewareDisabledByName("Block List")).to.be.true; 50 | }); 51 | 52 | it('User can enable Block List plugin and save API', () => { 53 | browser.refresh(); 54 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 55 | apis_page.EDIT_BUTTON.click(); 56 | endpoints_page.changeMiddlewareStatusByName("Block List"); 57 | apis_page.OAS_SAVE_BUTTON.click(); 58 | expect(apis_page.isApiUpdatedPopUpDisplayed()).to.be.true; 59 | }); 60 | 61 | it('Block List plugin is enabled after page reload', () => { 62 | browser.refresh(); 63 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 64 | expect(endpoints_page.verifyMiddlewareDisabledByName("Block List")).to.be.false; 65 | }); 66 | 67 | it('User can remove Block List plugin and save API', () => { 68 | browser.refresh(); 69 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 70 | apis_page.EDIT_BUTTON.click(); 71 | endpoints_page.removeMiddlewareByName("Block List"); 72 | apis_page.OAS_SAVE_BUTTON.click(); 73 | expect(apis_page.isApiUpdatedPopUpDisplayed()).to.be.true; 74 | }); 75 | 76 | it('Block List plugin is removed after page reload', () => { 77 | browser.refresh(); 78 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 79 | expect(endpoints_page.verifyMiddlewareExistsByName("Block List")).to.be.false; 80 | }); 81 | 82 | }); 83 | -------------------------------------------------------------------------------- /test/specs/api_designer/oas_middleware_tests/oas_api_ignore_plugin_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../../lib/pom/Login_page'; 2 | import { apis_page } from '../../../../lib/pom/Apis_page'; 3 | import { main_page } from '../../../../lib/pom/Main_page'; 4 | import { endpoints_page } from '../../../../lib/pom/Endpoints_page'; 5 | import { expect } from 'chai'; 6 | 7 | describe('Test Ignore plugin on OAS Endpoints designer page', () => { 8 | let envDetails; 9 | 10 | before(() => { 11 | envDetails = setUpEnv(); 12 | login_page.open(); 13 | login_page.login(envDetails.userEmail, envDetails.userPassword); 14 | }); 15 | 16 | it('User can add Ignore plugin and save API', () => { 17 | main_page.openAPIs(); 18 | apis_page.DESIGN_API_BOX.click(); 19 | apis_page.API_TYPE_OAS_BUTTON.click(); 20 | apis_page.API_NAME_INPUT.setValue('ignore-plugin-test'); 21 | apis_page.OAS_NEXT_BUTTON.click(); 22 | apis_page.OAS_GW_STATUS_DROPDOWN.selectOption("Active"); 23 | apis_page.OAS_ACCESS_DROPDOWN.selectOption("External"); 24 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 25 | endpoints_page.addNewEndpoint("/ip", "GET"); 26 | endpoints_page.addMiddlewareByName("Ignore Authentication"); 27 | apis_page.OAS_SAVE_BUTTON.click(); 28 | expect(apis_page.isApiCreatedPopUpDisplayed()).to.be.true; 29 | }); 30 | 31 | it('Ignore plugin is displayed after page reload', () => { 32 | browser.refresh(); 33 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 34 | expect(endpoints_page.verifyMiddlewareExistsByName("Ignore Authentication")).to.be.true; 35 | }); 36 | 37 | it('User can disable Ignore plugin and save API', () => { 38 | browser.refresh(); 39 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 40 | apis_page.EDIT_BUTTON.click(); 41 | endpoints_page.changeMiddlewareStatusByName("Ignore Authentication"); 42 | apis_page.OAS_SAVE_BUTTON.click(); 43 | expect(apis_page.isApiUpdatedPopUpDisplayed()).to.be.true; 44 | }); 45 | 46 | it('Ignore plugin is disabled after page reload', () => { 47 | browser.refresh(); 48 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 49 | expect(endpoints_page.verifyMiddlewareDisabledByName("Ignore Authentication")).to.be.true; 50 | }); 51 | 52 | it('User can enable Ignore plugin and save API', () => { 53 | browser.refresh(); 54 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 55 | apis_page.EDIT_BUTTON.click(); 56 | endpoints_page.changeMiddlewareStatusByName("Ignore Authentication"); 57 | apis_page.OAS_SAVE_BUTTON.click(); 58 | expect(apis_page.isApiUpdatedPopUpDisplayed()).to.be.true; 59 | }); 60 | 61 | it('Ignore plugin is enabled after page reload', () => { 62 | browser.refresh(); 63 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 64 | expect(endpoints_page.verifyMiddlewareDisabledByName("Ignore Authentication")).to.be.false; 65 | }); 66 | 67 | it('User can remove Ignore plugin and save API', () => { 68 | browser.refresh(); 69 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 70 | apis_page.EDIT_BUTTON.click(); 71 | endpoints_page.removeMiddlewareByName("Ignore Authentication"); 72 | apis_page.OAS_SAVE_BUTTON.click(); 73 | expect(apis_page.isApiUpdatedPopUpDisplayed()).to.be.true; 74 | }); 75 | 76 | it('Ignore plugin is removed after page reload', () => { 77 | browser.refresh(); 78 | endpoints_page.OAS_ENDPOINTS_BUTTON.click(); 79 | expect(endpoints_page.verifyMiddlewareExistsByName("Ignore Authentication")).to.be.false; 80 | }); 81 | 82 | }); 83 | -------------------------------------------------------------------------------- /test/specs/graphql/crud_graphql_proxy_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { apis_page } from '../../../lib/pom/Apis_page'; 3 | import { graphql_page } from '../../../lib/pom/Graphql_page'; 4 | import { main_page } from '../../../lib/pom/Main_page'; 5 | import { expect } from 'chai'; 6 | 7 | describe('CRUD simple GraphQL (proxy-only) API', () => { 8 | const apiDetails = { 9 | name: "GraphQL-test" 10 | }; 11 | let $apiTableElement; 12 | 13 | before(() => { 14 | const envDetails = setUpEnv(); 15 | login_page.open(); 16 | login_page.login(envDetails.userEmail, envDetails.userPassword); 17 | }); 18 | 19 | it('User should be able to create new GraphQL API', () => { 20 | main_page.openAPIs(); 21 | apis_page.DESIGN_API_BOX.click(); 22 | apis_page.API_NAME_INPUT.setValue(apiDetails.name); 23 | apis_page.API_TYPE_GRAPHQL_BUTTON.click(); 24 | apis_page.CONFIGURE_API_BUTTON.click(); 25 | graphql_page.GRAPHQL_SCHEMA_TAB_BUTTON.click(); 26 | wdioExpect(graphql_page.GRAPHQL_UPDATE_SCHEMA_BUTTON).toExist(); 27 | apis_page.SAVE_BUTTON.click(); 28 | }); 29 | 30 | it('New GraphQL API should be visible in table', () => { 31 | main_page.openAPIs(); 32 | $apiTableElement = $(`span=${apiDetails.name}`); 33 | wdioExpect($apiTableElement).toBeClickable(); 34 | }); 35 | 36 | it('User should be able to update GraphQL API', () => { 37 | $apiTableElement.click(); 38 | graphql_page.GRAPHQL_ENABLE_PLAYGROUND_TOGGLE.click(); 39 | expect(graphql_page.GRAPHQL_ENABLE_PLAYGROUND_TOGGLE.isSelected()).to.be.true; 40 | apis_page.UPDATE_BUTTON.click(); 41 | apis_page.UPDATE_API_BUTTON.click(); 42 | wdioExpect(apis_page.API_UPDATED_MESSAGE).toExist(); 43 | main_page.openAPIs(); 44 | $apiTableElement.click(); 45 | expect(graphql_page.GRAPHQL_ENABLE_PLAYGROUND_TOGGLE.isSelected()).to.be.true; 46 | }); 47 | 48 | it('User should be able to delete GraphQL API', () => { 49 | apis_page.OPTIONS_BUTTON.click(); 50 | apis_page.DELETE_BUTTON.click(); 51 | apis_page.DELETE_API_BUTTON.click(); 52 | wdioExpect(apis_page.API_DELETED_MESSAGE).toExist(); 53 | }); 54 | 55 | it('Deleted API should not be visible', () => { 56 | wdioExpect($apiTableElement).not.toBeDisplayed(); 57 | }); 58 | }); -------------------------------------------------------------------------------- /test/specs/graphql/crud_udg_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { apis_page } from '../../../lib/pom/Apis_page'; 3 | import { graphql_page } from '../../../lib/pom/Graphql_page'; 4 | import { main_page } from '../../../lib/pom/Main_page'; 5 | import { expect } from 'chai'; 6 | 7 | describe('CRUD simple UDG API', () => { 8 | const apiDetails = { 9 | name: "UDG-test" 10 | }; 11 | let $apiTableElement; 12 | 13 | before(() => { 14 | const envDetails = setUpEnv(); 15 | login_page.open(); 16 | login_page.login(envDetails.userEmail, envDetails.userPassword); 17 | }); 18 | 19 | it('User should be able to create new UDG API', () => { 20 | main_page.openAPIs(); 21 | apis_page.DESIGN_API_BOX.click(); 22 | apis_page.API_NAME_INPUT.setValue(apiDetails.name); 23 | apis_page.API_TYPE_UDG_BUTTON.click(); 24 | apis_page.CONFIGURE_API_BUTTON.click(); 25 | graphql_page.GRAPHQL_SCHEMA_TAB_BUTTON.click(); 26 | wdioExpect(graphql_page.UDG_IMPORT_SCHEMA_FILE_FIELD).toExist(); 27 | apis_page.SAVE_BUTTON.click(); 28 | }); 29 | 30 | it('New UDG API should be visible in table', () => { 31 | main_page.openAPIs(); 32 | $apiTableElement = $(`span=${apiDetails.name}`); 33 | wdioExpect($apiTableElement).toBeClickable(); 34 | }); 35 | 36 | it('User should be able to update UDG API', () => { 37 | $apiTableElement.click(); 38 | graphql_page.GRAPHQL_ENABLE_PLAYGROUND_TOGGLE.click(); 39 | expect(graphql_page.GRAPHQL_ENABLE_PLAYGROUND_TOGGLE.isSelected()).to.be.true; 40 | apis_page.UPDATE_BUTTON.click(); 41 | apis_page.UPDATE_API_BUTTON.click(); 42 | wdioExpect(apis_page.API_UPDATED_MESSAGE).toExist(); 43 | main_page.openAPIs(); 44 | $apiTableElement.click(); 45 | expect(graphql_page.GRAPHQL_ENABLE_PLAYGROUND_TOGGLE.isSelected()).to.be.true; 46 | }); 47 | 48 | it('User should be able to delete UDG API', () => { 49 | apis_page.OPTIONS_BUTTON.click(); 50 | apis_page.DELETE_BUTTON.click(); 51 | apis_page.DELETE_API_BUTTON.click(); 52 | }); 53 | 54 | it('Deleted API should not be visible', () => { 55 | wdioExpect($apiTableElement).not.toBeDisplayed(); 56 | }); 57 | }); -------------------------------------------------------------------------------- /test/specs/graphql/udg-schema.gql: -------------------------------------------------------------------------------- 1 | type Query { 2 | restQuery: RestType 3 | gqlQuery: GqlType 4 | kafkaQuery: KafkaType 5 | } 6 | 7 | type RestType{ 8 | restTypeField1: String 9 | } 10 | 11 | type GqlType{ 12 | gqlTypeField1: String 13 | } 14 | 15 | type KafkaType{ 16 | kafkaTypeField1: String 17 | } -------------------------------------------------------------------------------- /test/specs/keys/keys_hash_crud_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { main_page } from '../../../lib/pom/Main_page'; 3 | import { keys_page } from '../../../lib/pom/Keys_page.js'; 4 | import { Dashboard_connection } from '../../../lib/utils/api_connections/Dashboard_connection'; 5 | import { newAPIdefinitionWithDefaults } from '../../../lib/utils/API_object_designer'; 6 | 7 | const authTokenApi = { 8 | "name": "authtoken", 9 | "use_keyless": false, 10 | "use_standard_auth": true 11 | }; 12 | 13 | const apiKeysDetails = { 14 | apiName: 'keys_crud', 15 | keyExpiryTime: "1 hour", 16 | alias:'test', 17 | }; 18 | 19 | const updatedKeyDetails={ 20 | keyExpiryTimeUpdateValue: "6 hours", 21 | aliasUpdate:'updateAlias', 22 | metadataKey:'test', 23 | metadataValue:'123', 24 | }; 25 | 26 | 27 | describe('Create/update/delete keys without policy', () => { 28 | const dashboard_connection = new Dashboard_connection(); 29 | let envDetails; 30 | 31 | before(() => { 32 | envDetails = setUpEnv(); 33 | login_page.open(); 34 | login_page.login(envDetails.userEmail, envDetails.userPassword); 35 | }); 36 | 37 | it('Prerequisits: creating API definition via dashboard API', () => { 38 | const body = newAPIdefinitionWithDefaults(authTokenApi); 39 | dashboard_connection.createAPI(body, envDetails.userSecret); 40 | }); 41 | 42 | it('User should be able to create new Key', () => { 43 | main_page.openKeys(); 44 | keys_page.ADD_KEY_BUTTON.click(); 45 | keys_page.CHOOSE_API_TOGGLE.click(); 46 | wdioExpect(keys_page.CHOOSE_API_TABLE).toHaveTextContaining(authTokenApi.name); 47 | keys_page.CHOOSE_API_TABLE.clickCellWithText(authTokenApi.name); 48 | keys_page.CONFIGURATIONS_TAB_BUTTON.click(); 49 | keys_page.ALIAS_INPUT_FIELD.click(); 50 | keys_page.ALIAS_INPUT_FIELD.setValue(apiKeysDetails.alias); 51 | keys_page.KEY_EXPIRE_DROPDOWN.click(); 52 | keys_page.KEY_EXPIRE_DROPDOWN.selectOption(apiKeysDetails.keyExpiryTime); 53 | keys_page.ENABLE_DETAILED_LOGGING_BUTTON.click(); 54 | keys_page.CREATE_KEY_BUTTON.click(); 55 | keys_page.OK_BUTTON.click(); 56 | expect(keys_page.isKeyCreatedPopUpDisplayed()).to.be.true; 57 | }); 58 | 59 | it ('User should be able to modify key',()=>{ 60 | const keyHashValue= keys_page.COPY_KEY_HASH_BUTTON.getAttribute('copy'); 61 | main_page.openKeys(); 62 | keys_page.KEY_SEARCH_FIELD.click(); 63 | keys_page.KEY_SEARCH_FIELD.setValue(keyHashValue); 64 | keys_page.LOOKUP_KEY_BUTTON.click(); 65 | keys_page.CONFIGURATIONS_TAB_BUTTON.click(); 66 | wdioExpect(keys_page.KEY_HASH_VALUE).toHaveAttributeContaining('copy', keyHashValue); 67 | wdioExpect(keys_page.UPDATE_BUTTON).toBeClickable(); 68 | wdioExpect(keys_page.UPDATE_WITHOUT_QUOTA_RESET_BUTTON).toBeClickable(); 69 | wdioExpect(keys_page.DELETE_BUTTON).toBeClickable(); 70 | wdioExpect(keys_page.ALIAS_INPUT_FIELD).toHaveValue(apiKeysDetails.alias); 71 | keys_page.ALIAS_INPUT_FIELD.click(); 72 | keys_page.ALIAS_INPUT_FIELD.setValue(updatedKeyDetails.aliasUpdate); 73 | keys_page.ENABLE_DETAILED_LOGGING_BUTTON.click(); 74 | keys_page.METADATA_KEY_INPUT.setValue(updatedKeyDetails.metadataKey); 75 | keys_page.METADATA_VALUE_INPUT.setValue(updatedKeyDetails.metadataValue); 76 | keys_page.METADATA_ADD_BUTTON.click(); 77 | keys_page.KEY_EXPIRE_DROPDOWN.selectOption(updatedKeyDetails.keyExpiryTimeUpdateValue); 78 | keys_page.UPDATE_BUTTON.click(); 79 | keys_page.CONFIRM_BUTTON.click(); 80 | wdioExpect(keys_page.ALIAS_INPUT_FIELD).toHaveValue(updatedKeyDetails.aliasUpdate); 81 | }); 82 | 83 | xit('Confirmation popup should be displayed', () => { 84 | expect(keys_page.isKeyUpdatedPopUpDisplayed()).to.be.true; 85 | }); 86 | 87 | it('User should be able to delete key',()=>{ 88 | const DeletedKeyHashValue= keys_page.KEY_HASH_VALUE.getAttribute('copy'); 89 | keys_page.DELETE_BUTTON.click(); 90 | keys_page.DELETE_KEY_CONFIRMATION_BUTTON.click(); 91 | expect(keys_page.isKeyDeletedPopUpDisplayed()).to.be.true; 92 | browser.pause(2000); 93 | keys_page.KEY_SEARCH_FIELD.click(); 94 | keys_page.KEY_SEARCH_FIELD.setValue(DeletedKeyHashValue); 95 | keys_page.LOOKUP_KEY_BUTTON.click(); 96 | expect(keys_page.isCouldNotRetrieveKeyDisplayed()).to.be.true; 97 | }); 98 | }); -------------------------------------------------------------------------------- /test/specs/login_test/empty_username_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | 3 | describe('Test Login with empty username', () => { 4 | 5 | it('User cannot login without providing username', () => { 6 | const envDetails = setUpEnv(); 7 | login_page.open(); 8 | login_page.login(null, envDetails.userPassword); 9 | let errorMessage = $('div*=Credentials are incorrect, please try again'); 10 | wdioExpect(errorMessage).toBeDisplayed(); 11 | }); 12 | 13 | }); -------------------------------------------------------------------------------- /test/specs/policies/multiple_apis_policy_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { main_page } from '../../../lib/pom/Main_page'; 3 | import { policies_page } from '../../../lib/pom/Policies_page'; 4 | import { Dashboard_connection } from '../../../lib/utils/api_connections/Dashboard_connection'; 5 | import { newAPIdefinitionWithDefaults } from '../../../lib/utils/API_object_designer'; 6 | 7 | const policyDetails = { 8 | policyName: 'multiple_apis', 9 | keyExpiryTime: "1 hour", 10 | }; 11 | 12 | const basicAuthApisDetails = [ 13 | { 14 | "name": "basic_auth_1", 15 | "use_basic_auth": true, 16 | "use_keyless": false 17 | }, 18 | { 19 | "name": "basic_auth_2", 20 | "use_basic_auth": true, 21 | "use_keyless": false 22 | }, 23 | { 24 | "name": "basic_auth_3", 25 | "use_basic_auth": true, 26 | "use_keyless": false 27 | }, 28 | ]; 29 | 30 | const authTokenApiDetails = [ 31 | { 32 | "name": "open_1", 33 | "use_keyless": false, 34 | 35 | } 36 | ]; 37 | 38 | describe('Multiple APIs policies', () => { 39 | const dashboard_connection = new Dashboard_connection(); 40 | let envDetails; 41 | 42 | before(() => { 43 | envDetails = setUpEnv(); 44 | login_page.open(); 45 | login_page.login(envDetails.userEmail, envDetails.userPassword); 46 | }); 47 | 48 | it('Prerequisits: creating API definitions via dashboard API', () => { 49 | const allApis = [...authTokenApiDetails,...basicAuthApisDetails]; 50 | console.log(`>> Creating ${allApis.length} API definitions`); 51 | allApis.forEach (api => { 52 | let apiDefinition = newAPIdefinitionWithDefaults(api); 53 | dashboard_connection.createAPI(apiDefinition, envDetails.userSecret); 54 | }); 55 | }); 56 | 57 | it('User should be able to create new Policy with multiple APIs', () => { 58 | main_page.openPolicies(); 59 | policies_page.ADD_POLICY_BUTTON.click(); 60 | policies_page.API_TABLE.clickCellWithText(basicAuthApisDetails[0].name); 61 | policies_page.API_TABLE.waitForDisplayed({reverse: true}); //waiting for table to be hidden 62 | policies_page.API_SECTION_HEADER.click(); //opening section with API table 63 | policies_page.API_TABLE.clickCellWithText(basicAuthApisDetails[1].name); 64 | policies_page.CONFIGURATIONS_TAB_BUTTON.click(); 65 | policies_page.NAME_INPUT.setValue(policyDetails.policyName); 66 | policies_page.KEY_EXPIRY_AFTER_DROPDOWN.selectOption(policyDetails.keyExpiryTime); 67 | policies_page.CREATE_POLICY_BUTTON.click(); 68 | }); 69 | 70 | it(`User can't add policy with different Authorization type to policy`, () => { 71 | main_page.openPolicies(); 72 | policies_page.POLICY_TABLE.clickCellWithText(policyDetails.policyName); 73 | policies_page.API_SECTION_HEADER.click(); //opening section with API table 74 | const isOpenAPnotAvailable = policies_page.API_TABLE.isCellWithTextNotDisplayed(authTokenApiDetails[0].name); 75 | expect(isOpenAPnotAvailable).to.be.true; 76 | }); 77 | 78 | it('User should be able to add API with tha same Authorization type to policy', () => { 79 | policies_page.API_TABLE.clickCellWithText(basicAuthApisDetails[2].name); 80 | policies_page.UPDATE_POLICY_BUTTON.click(); 81 | policies_page.UPDATE_CONFIRMATION_BUTTON.click(); 82 | }); 83 | 84 | it('User should be able to see all APIs assigned to policy', () => { 85 | main_page.openPolicies(); 86 | policies_page.POLICY_TABLE.clickCellWithText(policyDetails.policyName); 87 | wdioExpect($$('.policy-api__api-name')).toBeElementsArrayOfSize(3); 88 | basicAuthApisDetails.forEach(api => wdioExpect($(`span=${api.name}`)).toBeDisplayed()); 89 | }); 90 | 91 | it('User should be able to delete API access from policy', () => { 92 | $(`span=${basicAuthApisDetails[1].name}`).click(); 93 | const $removeAPIButton = $(`span=${basicAuthApisDetails[1].name}`).$('../..').$(`span=Remove Access`); 94 | $removeAPIButton.click(); 95 | policies_page.CONFIRM_BUTTON.click(); 96 | wdioExpect($$('.policy-api__api-name')).toBeElementsArrayOfSize(2); 97 | }); 98 | }); -------------------------------------------------------------------------------- /test/specs/policies/policy_crud_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { main_page } from '../../../lib/pom/Main_page'; 3 | import { policies_page } from '../../../lib/pom/Policies_page'; 4 | import { Dashboard_connection } from '../../../lib/utils/api_connections/Dashboard_connection'; 5 | import { newAPIdefinitionWithDefaults } from '../../../lib/utils/API_object_designer'; 6 | 7 | const policyDetails = { 8 | apiName: 'test_policy', 9 | policyName: 'policy_auto_test_1', 10 | policyNameUpdate: 'policy_auto_test_1_update', 11 | keyEpiryTime: "1 hour", 12 | keyEpiryTimeUpdateValue: "6 hours" 13 | }; 14 | 15 | describe('Create/update/delete policies', () => { 16 | const dashboard_connection = new Dashboard_connection(); 17 | let envDetails; 18 | 19 | before(() => { 20 | envDetails = setUpEnv(); 21 | login_page.open(); 22 | login_page.login(envDetails.userEmail, envDetails.userPassword); 23 | }); 24 | 25 | it('Prerequisits: creating API definition via dashboard API', () => { 26 | const apiDefinition = newAPIdefinitionWithDefaults({"name":policyDetails.apiName}); 27 | dashboard_connection.createAPI(apiDefinition, envDetails.userSecret); 28 | }); 29 | 30 | it('User should be able to create new Policy', () => { 31 | main_page.openPolicies(); 32 | policies_page.ADD_POLICY_BUTTON.click(); 33 | policies_page.API_TABLE.clickCellWithText(policyDetails.apiName); 34 | policies_page.CONFIGURATIONS_TAB_BUTTON.click(); 35 | policies_page.NAME_INPUT.setValue(policyDetails.policyName); 36 | policies_page.KEY_EXPIRY_AFTER_DROPDOWN.selectOption(policyDetails.keyEpiryTime); 37 | policies_page.CREATE_POLICY_BUTTON.click(); 38 | }); 39 | 40 | it('Confirmation popup should be displayed', () => { 41 | expect(policies_page.isPolicyCreatedPopUpDisplayed()).to.be.true; 42 | }); 43 | 44 | it('User should be able to edit created Policy', () => { 45 | main_page.openPolicies(); 46 | policies_page.POLICY_TABLE.clickCellWithText(policyDetails.policyName); 47 | policies_page.CONFIGURATIONS_TAB_BUTTON.click(); 48 | policies_page.KEY_EXPIRY_AFTER_DROPDOWN.selectOption(policyDetails.keyEpiryTimeUpdateValue); 49 | policies_page.NAME_INPUT.setValue(policyDetails.policyNameUpdate); 50 | policies_page.UPDATE_POLICY_BUTTON.click(); 51 | policies_page.UPDATE_CONFIRMATION_BUTTON.click(); 52 | }); 53 | 54 | it(`Changes should be displayed after reload. Key expiry: ${policyDetails.keyEpiryTimeUpdateValue}`, () => { 55 | main_page.openPolicies(); 56 | policies_page.POLICY_TABLE.clickCellWithText(policyDetails.policyNameUpdate); 57 | policies_page.CONFIGURATIONS_TAB_BUTTON.click(); 58 | expect(policies_page.KEY_EXPIRY_AFTER_DROPDOWN.getText()).to.equal(policyDetails.keyEpiryTimeUpdateValue); 59 | }); 60 | 61 | it('User should be able to delete policy', () => { 62 | main_page.openPolicies(); 63 | policies_page.POLICY_TABLE.clickCellWithText(policyDetails.policyNameUpdate); 64 | policies_page.DELETE_BUTTON.click(); 65 | policies_page.DELETE_CONFIRMATION_BUTTON.click(); 66 | main_page.openPolicies(); 67 | const wasPolicyDeleted = policies_page.POLICY_TABLE.isCellWithTextNotDisplayed(policyDetails.policyNameUpdate); 68 | expect(wasPolicyDeleted).to.be.true; 69 | }); 70 | 71 | }); -------------------------------------------------------------------------------- /test/specs/policies/policy_mandatory_fields_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { main_page } from '../../../lib/pom/Main_page'; 3 | import { policies_page } from '../../../lib/pom/Policies_page'; 4 | import { Dashboard_connection } from '../../../lib/utils/api_connections/Dashboard_connection'; 5 | import { newAPIdefinitionWithDefaults } from '../../../lib/utils/API_object_designer'; 6 | 7 | const policyDetails = { 8 | apiName: 'test_api', 9 | policyName: 'policy_mandatory_fields', 10 | keyEpiryTime: "1 hour" 11 | }; 12 | 13 | describe('Create/update/delete tags on policy', () => { 14 | const dashboard_connection = new Dashboard_connection(); 15 | let envDetails; 16 | 17 | before(() => { 18 | envDetails = setUpEnv(); 19 | login_page.open(); 20 | login_page.login(envDetails.userEmail, envDetails.userPassword); 21 | }); 22 | 23 | it('Prerequisits: creating API definition via dashboard API', () => { 24 | const apiDefinition = newAPIdefinitionWithDefaults({"name":policyDetails.apiName}); 25 | dashboard_connection.createAPI(apiDefinition, envDetails.userSecret); 26 | }); 27 | 28 | it('User should see error message on Access Rights tab if no API was selected', () => { 29 | main_page.openPolicies(); 30 | policies_page.ADD_POLICY_BUTTON.click(); 31 | policies_page.CREATE_POLICY_BUTTON.click(); 32 | wdioExpect(policies_page.API_ERROR_ICON).toBeDisplayed(); 33 | wdioExpect(policies_page.CONFIG_ERROR_ICON).toBeDisplayed(); 34 | wdioExpect(policies_page.API_MANDATORY_TEXT).toBeDisplayed(); 35 | }); 36 | 37 | it('User should not see errors on Access Rights tab if 1 API was selected', () => { 38 | policies_page.API_TABLE.clickCellWithText(policyDetails.apiName); 39 | wdioExpect(policies_page.API_ERROR_ICON).not.toBeDisplayed(); 40 | wdioExpect(policies_page.API_MANDATORY_TEXT).not.toBeDisplayed(); 41 | wdioExpect(policies_page.CONFIG_ERROR_ICON).toBeDisplayed(); 42 | }); 43 | 44 | it('User should see errors on Configurations tab - Name and Expiry missing', () => { 45 | policies_page.CONFIGURATIONS_TAB_BUTTON.click(); 46 | wdioExpect(policies_page.NAME_MANDATORY_TEXT).toBeDisplayed(); 47 | wdioExpect(policies_page.EXPIRY_MANDATORY_TEXT).toBeDisplayed(); 48 | }); 49 | 50 | it('User should be able to save Policy onces all mandatory fields are entered', () => { 51 | policies_page.NAME_INPUT.setValue(policyDetails.policyName); 52 | policies_page.KEY_EXPIRY_AFTER_DROPDOWN.selectOption(policyDetails.keyEpiryTime); 53 | wdioExpect(policies_page.CONFIG_ERROR_ICON).not.toBeDisplayed(); 54 | wdioExpect(policies_page.NAME_MANDATORY_TEXT).not.toBeDisplayed(); 55 | wdioExpect(policies_page.EXPIRY_MANDATORY_TEXT).not.toBeDisplayed(); 56 | policies_page.CREATE_POLICY_BUTTON.click(); 57 | }); 58 | 59 | it('Confirmation popup should be displayed', () => { 60 | expect(policies_page.isPolicyCreatedPopUpDisplayed()).to.be.true; 61 | }); 62 | 63 | }); -------------------------------------------------------------------------------- /test/specs/portal_settings/admin_settings_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { main_page } from '../../../lib/pom/Main_page'; 3 | import { admin_settings_page } from '../../../lib/pom/portal/Admin_settings_page'; 4 | 5 | describe('Portal Settings main Admin page', () => { 6 | const email = "test_notification_email@tyk.io"; 7 | 8 | before(() => { 9 | const envDetails = setUpEnv(); 10 | login_page.open(); 11 | login_page.login(envDetails.userEmail, envDetails.userPassword); 12 | }); 13 | 14 | it('User should see proper default values', () => { 15 | main_page.openPortalSettings(); 16 | wdioExpect(admin_settings_page.ACCESS_REQUEST_INPUT).toHaveValue(''); 17 | expect(admin_settings_page.DEVELOPER_SIGN_UP_TOGGLE.isSelected()).to.be.false; 18 | expect(admin_settings_page.DEVELOPER_LOGIN_TOGGLE.isSelected()).to.be.false; 19 | expect(admin_settings_page.RESTRICTED_CATALOGUE_TOGGLE.isSelected()).to.be.false; 20 | }); 21 | 22 | it('User should be able to edit all fields and save changes without error', () => { 23 | admin_settings_page.ACCESS_REQUEST_INPUT.setValue(email); 24 | admin_settings_page.DEVELOPER_SIGN_UP_TOGGLE.click(); 25 | admin_settings_page.DEVELOPER_LOGIN_TOGGLE.click(); 26 | admin_settings_page.RESTRICTED_CATALOGUE_TOGGLE.click(); 27 | admin_settings_page.SAVE_BUTTON.click(); 28 | expect(admin_settings_page.isSettingsUpdatedPopUpDisplayed()).to.be.true; 29 | }); 30 | 31 | it('User should see saved values after re-load values', () => { 32 | browser.refresh(); 33 | wdioExpect(admin_settings_page.ACCESS_REQUEST_INPUT).toHaveValue(email); 34 | expect(admin_settings_page.DEVELOPER_SIGN_UP_TOGGLE.isSelected()).to.be.true; 35 | expect(admin_settings_page.DEVELOPER_LOGIN_TOGGLE.isSelected()).to.be.true; 36 | expect(admin_settings_page.RESTRICTED_CATALOGUE_TOGGLE.isSelected()).to.be.true; 37 | }); 38 | }); -------------------------------------------------------------------------------- /test/specs/portal_settings/api_access_settings_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { main_page } from '../../../lib/pom/Main_page'; 3 | import { admin_settings_page } from '../../../lib/pom/portal/Admin_settings_page'; 4 | 5 | describe('Portal Settings - API access manipulations', () => { 6 | const redirectUrl = "http://test"; 7 | const numberfAllowedRequests = "5"; 8 | 9 | before(() => { 10 | const envDetails = setUpEnv(); 11 | login_page.open(); 12 | login_page.login(envDetails.userEmail, envDetails.userPassword); 13 | }); 14 | 15 | it('User should see proper default values', () => { 16 | main_page.openPortalSettings(); 17 | admin_settings_page.API_ACCESS_TAB_BUTTON.click(); 18 | expect(admin_settings_page.MANUAL_ACCESS_APPROVAL_TOGGLE.isSelected()).to.be.false; 19 | expect(admin_settings_page.MULTIPLE_API_SUBSCRIPTION_TOGGLE.isSelected()).to.be.false; 20 | expect(admin_settings_page.THIRD_PARTY_REDIRECT_TOGGLE.isSelected()).to.be.false; 21 | wdioExpect(admin_settings_page.NUMBER_OF_ALLOWED_REQUESTS_INPUT).toHaveValue("0"); 22 | }); 23 | 24 | it('User should be able to edit all fields and save changes without error', () => { 25 | admin_settings_page.MANUAL_ACCESS_APPROVAL_TOGGLE.click(); 26 | admin_settings_page.HIDE_API_SECRET_TOGGLE.click(); 27 | admin_settings_page.MULTIPLE_API_SUBSCRIPTION_TOGGLE.click(); 28 | admin_settings_page.THIRD_PARTY_REDIRECT_TOGGLE.click(); 29 | admin_settings_page.REDIRECT_URL_INPUT.setValue(redirectUrl); 30 | admin_settings_page.NUMBER_OF_ALLOWED_REQUESTS_INPUT.setValue(numberfAllowedRequests); 31 | admin_settings_page.SAVE_BUTTON.click(); 32 | expect(admin_settings_page.isSettingsUpdatedPopUpDisplayed()).to.be.true; 33 | }); 34 | 35 | it('User should see saved values after re-load values', () => { 36 | browser.refresh(); 37 | admin_settings_page.API_ACCESS_TAB_BUTTON.click(); 38 | wdioExpect(admin_settings_page.REDIRECT_URL_INPUT).toHaveValue(redirectUrl); 39 | wdioExpect(admin_settings_page.NUMBER_OF_ALLOWED_REQUESTS_INPUT).toHaveValue(numberfAllowedRequests); 40 | expect(admin_settings_page.MANUAL_ACCESS_APPROVAL_TOGGLE.isSelected()).to.be.true; 41 | expect(admin_settings_page.HIDE_API_SECRET_TOGGLE.isSelected()).to.be.true; 42 | expect(admin_settings_page.MULTIPLE_API_SUBSCRIPTION_TOGGLE.isSelected()).to.be.true; 43 | expect(admin_settings_page.THIRD_PARTY_REDIRECT_TOGGLE.isSelected()).to.be.true; 44 | }); 45 | }); -------------------------------------------------------------------------------- /test/specs/portal_settings/dcr_settings_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { main_page } from '../../../lib/pom/Main_page'; 3 | import { admin_settings_page } from '../../../lib/pom/portal/Admin_settings_page'; 4 | 5 | describe('Portal Settings - API access manipulations', () => { 6 | const inputs = { 7 | provider: "Okta", 8 | grant_types: ["Refresh Token", "Password"], 9 | token_endpoint_auth: "Client Secret - Post", 10 | response_types: ["Token", "Authorization Code"], 11 | idp_host: "http://localhost", 12 | client_registration_endpoint: "http://localhost/client", 13 | token: "testToken" 14 | }; 15 | const errorElementClass = "has-error"; 16 | 17 | before(() => { 18 | const envDetails = setUpEnv(); 19 | login_page.open(); 20 | login_page.login(envDetails.userEmail, envDetails.userPassword); 21 | }); 22 | 23 | it('DCR should be disabled by default', () => { 24 | main_page.openPortalSettings(); 25 | admin_settings_page.API_ACCESS_TAB_BUTTON.click(); 26 | expect(admin_settings_page.DCR_TOGGLE.isSelected()).to.be.false; 27 | }); 28 | 29 | it('If DCR is enabled fields become mandatory', () => { 30 | admin_settings_page.DCR_TOGGLE.click(); 31 | admin_settings_page.SAVE_BUTTON.click(); 32 | [admin_settings_page.DCR_PROVIDERS_DROPDOWN, admin_settings_page.DCR_TOKEN_ENDPOINT_DROPDOWN, 33 | admin_settings_page.DCR_GRANT_TYPES_DROPDOWN, admin_settings_page.DCR_RESPONSE_TYPE_DROPDOWN].forEach(element => 34 | wdioExpect(element).toHaveAttrContaining("class", errorElementClass) 35 | ); 36 | wdioExpect(admin_settings_page.DCR_HOST_INPUT).toHaveAttrContaining("error", "Enter an IDP host"); 37 | wdioExpect(admin_settings_page.DCR_CLIENT_REGISTRATION_ENDPOINT_INPUT).toHaveAttrContaining("error", "Enter an endpoint"); 38 | wdioExpect(admin_settings_page.DCR_TOKEN_INPUT).toHaveAttrContaining("error", ""); //Token is not a mandatory field -> no error 39 | }); 40 | 41 | it('User should be able to edit DCR details and save changes without error', () => { 42 | admin_settings_page.DCR_TOKEN_INPUT.scrollIntoView(); 43 | admin_settings_page.DCR_PROVIDERS_DROPDOWN.selectOption(inputs.provider); 44 | admin_settings_page.DCR_GRANT_TYPES_DROPDOWN.selectOptions(inputs.grant_types); 45 | admin_settings_page.DCR_TOKEN_ENDPOINT_DROPDOWN.selectOption(inputs.token_endpoint_auth); 46 | admin_settings_page.DCR_RESPONSE_TYPE_DROPDOWN.selectOptions(inputs.response_types); 47 | admin_settings_page.DCR_HOST_INPUT.setValue(inputs.idp_host); 48 | admin_settings_page.DCR_CLIENT_REGISTRATION_ENDPOINT_INPUT.setValue(inputs.client_registration_endpoint); 49 | admin_settings_page.DCR_TOKEN_INPUT.setValue(inputs.token); 50 | admin_settings_page.SAVE_BUTTON.click(); 51 | expect(admin_settings_page.isSettingsUpdatedPopUpDisplayed()).to.be.true; 52 | }); 53 | 54 | it('User should see saved values after re-load values', () => { 55 | browser.refresh(); 56 | admin_settings_page.API_ACCESS_TAB_BUTTON.click(); 57 | expect(admin_settings_page.DCR_TOGGLE.isSelected()).to.be.true; 58 | wdioExpect(admin_settings_page.DCR_PROVIDERS_DROPDOWN.$(`span=${inputs.provider}`)).toBeDisplayed(); 59 | inputs.grant_types.forEach(grant_type => wdioExpect(admin_settings_page.DCR_GRANT_TYPES_DROPDOWN.$(`span=${grant_type}`)).toBeDisplayed()); 60 | wdioExpect(admin_settings_page.DCR_TOKEN_ENDPOINT_DROPDOWN.$(`span=${inputs.token_endpoint_auth}`)).toBeDisplayed(); 61 | inputs.response_types.forEach(response_type => wdioExpect(admin_settings_page.DCR_RESPONSE_TYPE_DROPDOWN.$(`span=${response_type}`)).toBeDisplayed()); 62 | wdioExpect(admin_settings_page.DCR_HOST_INPUT).toHaveValue(inputs.idp_host); 63 | wdioExpect(admin_settings_page.DCR_CLIENT_REGISTRATION_ENDPOINT_INPUT).toHaveValue(inputs.client_registration_endpoint); 64 | wdioExpect(admin_settings_page.DCR_TOKEN_INPUT).toHaveValue(inputs.token); 65 | }); 66 | 67 | it('User is able to save Settings with DCR turned off (fields are no longer mandatory)', () => { 68 | admin_settings_page.DCR_HOST_INPUT.click(); 69 | admin_settings_page.DCR_HOST_INPUT.clear(); 70 | admin_settings_page.DCR_TOGGLE.click(); 71 | expect(admin_settings_page.DCR_TOGGLE.isSelected()).to.be.false; 72 | admin_settings_page.SAVE_BUTTON.click(); 73 | expect(admin_settings_page.isSettingsUpdatedPopUpDisplayed()).to.be.true; 74 | }); 75 | }); -------------------------------------------------------------------------------- /test/specs/tib/public_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsR1fF+JAA+s/O8YGXONx 3 | K5JRc+4z/NtiFAww39lC/2qWD2b/30ojrJVNbE500QzOTOO0YoJ3eWJupjIqFm3I 4 | mK+x8gSCWNz+pneWVY7RaoEbmSgZRQ9YizYpVUnS4wb5UxhkzvCwsaEhqWja6yP0 5 | inaUIuW3gzrTuKTG2VBAnMtcxYn7ttes9/BZebh0giSO0vtj7pg8Ai0n3I2moNHU 6 | umiJ1ye3pYEjys32sSb0HUGJf+T0k5ELs+dBM/Z7SuCq9toLNX/Uj196ZPQiv+Bh 7 | CmM4VQyID5wR5riIR11/0z0Er4FZjLAPNBFlE5bOMC87UXSf7kylvgZUuLHOKOFc 8 | 2wIDAQAB 9 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /test/specs/users/users_creation_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { main_page } from '../../../lib/pom/Main_page'; 3 | import { users_page } from '../../../lib/pom/Users_page'; 4 | import { generateRandomEmail } from '../../../lib/utils/utils'; 5 | 6 | let envDetails; 7 | const userDetails = { 8 | firstName: "user_name", 9 | lastName: "user_last_name", 10 | emailAdress: generateRandomEmail(), 11 | password: "test123", 12 | isUserAnAdmin: true 13 | }; 14 | const invalidEmail = {emailAdress: "not_an_email"}; 15 | const shortPassword = {password: "test"}; 16 | 17 | describe('Users creation', () => { 18 | 19 | before(() => { 20 | envDetails = setUpEnv(); 21 | login_page.open(); 22 | login_page.login(envDetails.userEmail, envDetails.userPassword); 23 | }); 24 | 25 | beforeEach(() => { 26 | main_page.openUsers(); 27 | users_page.ADD_USER_BUTTON.click(); 28 | }); 29 | 30 | it('Admin should NOT be able to create user with invalid email', () => { 31 | fillUserData({...userDetails, ...invalidEmail}); 32 | users_page.SAVE_BUTTON.click(); 33 | 34 | expect(users_page.isErrorPopUpDisplayed()).to.be.true; 35 | main_page.openUsers(); 36 | const userIsNotVisibleInTable = users_page.USERS_TABLE.isCellWithTextNotDisplayed(invalidEmail.emailAdress); 37 | expect(userIsNotVisibleInTable).to.be.true; 38 | }); 39 | 40 | it('Admin should be able to create inactive user', () => { 41 | fillUserData(userDetails); 42 | users_page.ACCOUNT_IS_ACTIVE_CHECKBOX.click(); 43 | users_page.SAVE_BUTTON.click(); 44 | users_page.USERS_TABLE.clickCellWithText(userDetails.firstName); 45 | const isUserActive = users_page.ACCOUNT_IS_ACTIVE_CHECKBOX.isSelected(); 46 | expect(isUserActive).to.be.false; 47 | }); 48 | 49 | it('Admin should NOT be able to create user with already existing email', () => { 50 | fillUserData(userDetails); //user with email in userDetails is already created 51 | users_page.SAVE_BUTTON.click(); 52 | expect(users_page.isUserAlreadyExistsPopUpDisplayed()).to.be.true; 53 | }); 54 | 55 | it('Admin should NOT be able to create user with short password', () => { 56 | fillUserData({...userDetails, ...shortPassword}); 57 | users_page.SAVE_BUTTON.click(); 58 | expect(users_page.isErrorPopUpDisplayed()).to.be.true; 59 | }); 60 | 61 | it('Admin should be able to create user with limited permissions', () => { 62 | let userForPermissionsTest = { 63 | firstName: "user_permissions", 64 | lastName: "user_last_name", 65 | emailAdress: generateRandomEmail(), 66 | password: "test123", 67 | }; 68 | fillUserData(userForPermissionsTest); 69 | users_page.selectReadAccessForPermission('analytics'); 70 | users_page.SAVE_BUTTON.click(); 71 | 72 | expect(users_page.isUserCreatedPopUpDisplayed()).to.be.true; 73 | main_page.openUsers(); 74 | users_page.USERS_TABLE.clickCellWithText(userForPermissionsTest.firstName); 75 | wdioExpect(users_page.PERMISSIONS_ANALYTICS_ROW).toHaveValue('read'); 76 | }); 77 | }); 78 | 79 | const fillUserData = (userDetailsObject) => { 80 | users_page.FIRST_NAME_INPUT.setValue(userDetailsObject.firstName); 81 | users_page.LAST_NAME_INPUT.setValue(userDetailsObject.lastName); 82 | users_page.EMAIL_ADRESS_INPUT.setValue(userDetailsObject.emailAdress); 83 | users_page.PASSWORD_INPUT.setValue(userDetailsObject.password); 84 | if (userDetailsObject.isUserAnAdmin) {users_page.ACCOUNT_IS_ADMIN_CHECKBOX.check();} 85 | }; 86 | -------------------------------------------------------------------------------- /test/specs/users/users_crud_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { main_page } from '../../../lib/pom/Main_page'; 3 | import { users_page } from '../../../lib/pom/Users_page'; 4 | import { generateRandomEmail } from '../../../lib/utils/utils'; 5 | 6 | const userDetails = { 7 | firstName: "crud_user_name", 8 | firstNameUpdate: "crud_user_name_update", 9 | lastName: "crud_user_last_name", 10 | emailAdress: generateRandomEmail(), 11 | password: "test123" 12 | }; 13 | 14 | describe('Create/update/delete users', () => { 15 | 16 | before(() => { 17 | const envDetails = setUpEnv(); 18 | login_page.open(); 19 | login_page.login(envDetails.userEmail, envDetails.userPassword); 20 | }); 21 | 22 | it('Admin should be able to create new user', () => { 23 | main_page.openUsers(); 24 | users_page.ADD_USER_BUTTON.click(); 25 | users_page.FIRST_NAME_INPUT.setValue(userDetails.firstName); 26 | users_page.LAST_NAME_INPUT.setValue(userDetails.lastName); 27 | users_page.EMAIL_ADRESS_INPUT.setValue(userDetails.emailAdress); 28 | users_page.PASSWORD_INPUT.setValue(userDetails.password); 29 | users_page.ACCOUNT_IS_ADMIN_CHECKBOX.click(); 30 | users_page.SAVE_BUTTON.click(); 31 | expect(users_page.isUserCreatedPopUpDisplayed()).to.be.true; 32 | users_page.USERS_TABLE.clickCellWithText(userDetails.firstName); 33 | wdioExpect(users_page.EMAIL_ADRESS_INPUT).toHaveValue(userDetails.emailAdress); 34 | }); 35 | 36 | it('Admin should be able to edit created user', () => { 37 | users_page.FIRST_NAME_INPUT.setValue(userDetails.firstNameUpdate); 38 | users_page.UPDATE_BUTTON.click(); 39 | expect(users_page.isUserUpdatedPopUpDisplayed()).to.be.true; 40 | main_page.openUsers(); 41 | users_page.USERS_TABLE.clickCellWithText(userDetails.firstNameUpdate); 42 | wdioExpect(users_page.FIRST_NAME_INPUT).toHaveValue(userDetails.firstNameUpdate); 43 | }); 44 | 45 | it('Admin should be able to delete user', () => { 46 | users_page.DELETE_BUTTON.click(); 47 | const userIsNotVisibleInTable = users_page.USERS_TABLE.isCellWithTextNotDisplayed(userDetails.emailAdress); 48 | expect(userIsNotVisibleInTable).to.be.true; 49 | }); 50 | 51 | }); -------------------------------------------------------------------------------- /test/specs/webhooks/webhooks_crud_test.js: -------------------------------------------------------------------------------- 1 | import { login_page } from '../../../lib/pom/Login_page'; 2 | import { main_page } from '../../../lib/pom/Main_page'; 3 | import { Dashboard_connection } from '../../../lib/utils/api_connections/Dashboard_connection';; 4 | import {webhook_page} from '../../../lib/pom/Webhooks_page'; 5 | 6 | const NewWebhookDetails = { 7 | "name": "QA test", 8 | "RequestMethod":"GET", 9 | "Target": "http://test.com", 10 | "HeaderKey":"xyz", 11 | "HeaderValue":"123", 12 | }; 13 | 14 | const UpdatedWebhookDetails = { 15 | "name": "Webhook", 16 | "RequestMethod": "POST", 17 | "Target": "http://test456.com", 18 | }; 19 | 20 | const emptyWebhookMessage = "No data to display"; 21 | 22 | 23 | describe('Create/update/delete keys by ID without policy', () => { 24 | const dashboard_connection = new Dashboard_connection(); 25 | let envDetails; 26 | before(() => { 27 | envDetails = setUpEnv(); 28 | login_page.open(); 29 | login_page.login(envDetails.userEmail, envDetails.userPassword); 30 | }); 31 | 32 | it('User should be able to add new webhook', ()=>{ 33 | main_page.openWebhooks(); 34 | webhook_page.ADD_WEBHOOK.click(); 35 | webhook_page.NAME_INPUT.click(); 36 | webhook_page.NAME_INPUT.setValue(NewWebhookDetails.name); 37 | webhook_page.REQUEST_METHOD_DROPDOWN.selectOption(NewWebhookDetails.RequestMethod); 38 | webhook_page.TARGET_INPUT.click(); 39 | webhook_page.TARGET_INPUT.setValue(NewWebhookDetails.Target); 40 | webhook_page.HEADER_KEY.setValue(NewWebhookDetails.HeaderKey); 41 | webhook_page.HEADER_VALUE.setValue(NewWebhookDetails.HeaderValue); 42 | webhook_page.ADD_HEADER_BUTTON.click(); 43 | webhook_page.SAVE_BUTTON.click(); 44 | }); 45 | 46 | it('User should be able to modify the webhook',()=>{ 47 | webhook_page.WEBHOOK_TABLE.clickCellWithText(NewWebhookDetails.name); 48 | wdioExpect(webhook_page.NAME_INPUT).toHaveValue(NewWebhookDetails.name); 49 | wdioExpect(webhook_page.REQUEST_METHOD_DROPDOWN).toHaveValue(NewWebhookDetails.RequestMethod); 50 | wdioExpect(webhook_page.TARGET_INPUT).toHaveValue(NewWebhookDetails.Target); 51 | webhook_page.NAME_INPUT.setValue(UpdatedWebhookDetails.name); 52 | webhook_page.REQUEST_METHOD_DROPDOWN.selectOption(UpdatedWebhookDetails.RequestMethod); 53 | webhook_page.TARGET_INPUT.setValue(UpdatedWebhookDetails.Target); 54 | webhook_page.UPDATE_BUTTON.click(); 55 | wdioExpect(webhook_page.NAME_INPUT).toHaveValue(UpdatedWebhookDetails.name); 56 | wdioExpect(webhook_page.REQUEST_METHOD_DROPDOWN).toHaveValue(UpdatedWebhookDetails.RequestMethod); 57 | wdioExpect(webhook_page.TARGET_INPUT).toHaveValue(UpdatedWebhookDetails.Target); 58 | }); 59 | 60 | it('User must be able to delete webhook',()=>{ 61 | webhook_page.DELETE_BUTTON.click(); 62 | webhook_page.DELETE_KEY_CONFIRMATION_BUTTON.click(); 63 | wdioExpect(webhook_page.NO_DATA_TO_DISPLAY).toHaveText(emptyWebhookMessage); 64 | }); 65 | 66 | }); -------------------------------------------------------------------------------- /update_xray.sh: -------------------------------------------------------------------------------- 1 | echo "Sending update of test execution to Xray" 2 | if [ "$STATUS" == "success" ]; then 3 | RESULT="PASSED" 4 | else 5 | RESULT="FAILED" 6 | fi 7 | echo "Checking branch: $BRANCH" 8 | if [ "$BRANCH" == "refs/heads/master" ]; then 9 | EXECUTION=QA-894 10 | fi 11 | if [ "$BRANCH" == "refs/heads/release-4.3" ]; then 12 | EXECUTION=QA-902 13 | fi 14 | if [ "$BRANCH" == "refs/heads/release-4" ]; then 15 | EXECUTION=QA-903 16 | fi 17 | if [ "$BRANCH" == "refs/heads/release-4-lts" ]; then 18 | EXECUTION=QA-904 19 | fi 20 | 21 | if [[ ! -z "$EXECUTION" ]]; then 22 | echo "Requesting Token" 23 | TOKEN=$(curl -H "Content-Type: application/json" -X POST --data "{ \"client_id\": \"$CLIENT_ID\",\"client_secret\": \"$CLIENT_SECRET\" }" https://xray.cloud.getxray.app/api/v2/authenticate| tr -d '"') 24 | echo "Sending update $RESULT on $TEST and execution $EXECUTION" 25 | curl -H "Authorization: Bearer $TOKEN" -X POST https://xray.cloud.getxray.app/api/v2/import/execution \ 26 | -d '{"testExecutionKey":"'$EXECUTION'","tests":[{"testKey":"'$TEST'","status":"'$RESULT'"}]}' \ 27 | -H 'Content-Type: application/json' 28 | else 29 | echo "Branch $BRANCH is not specified for updated" 30 | fi 31 | --------------------------------------------------------------------------------