mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 11:01:54 +03:00
Migrate QMS tests (#6063)
This commit is contained in:
parent
ce8683e8e0
commit
d0785ffdd1
94
.github/workflows/main.yml
vendored
94
.github/workflows/main.yml
vendored
@ -33,6 +33,7 @@ env:
|
||||
server-plugins
|
||||
templates
|
||||
tests
|
||||
qms-tests
|
||||
rush.json
|
||||
.prettierrc
|
||||
tools
|
||||
@ -282,6 +283,99 @@ jobs:
|
||||
# with:
|
||||
# name: db-snapshot
|
||||
# path: ./tests/db_dump
|
||||
uitest-qms:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
filter: tree:0
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-node-platform
|
||||
with:
|
||||
path: |
|
||||
common/temp
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
|
||||
- name: Checking for mis-matching dependencies...
|
||||
run: node common/scripts/install-run-rush.js check
|
||||
|
||||
- name: Installing...
|
||||
run: node common/scripts/install-run-rush.js install
|
||||
|
||||
- name: Docker Build
|
||||
run: node common/scripts/install-run-rush.js docker:build -p 20
|
||||
env:
|
||||
DOCKER_CLI_HINTS: false
|
||||
- name: Prepare server
|
||||
run: |
|
||||
cd ./qms-tests
|
||||
./prepare.sh
|
||||
- name: Install Playwright
|
||||
run: |
|
||||
cd ./qms-tests/sanity
|
||||
node ../../common/scripts/install-run-rushx.js ci
|
||||
- name: Run UI tests
|
||||
run: |
|
||||
cd ./qms-tests/sanity
|
||||
node ../../common/scripts/install-run-rushx.js uitest
|
||||
- name: "Store docker logs"
|
||||
if: always()
|
||||
run: |
|
||||
cd ./qms-tests/sanity
|
||||
mkdir logs
|
||||
docker logs $(docker ps | grep transactor | cut -f 1 -d ' ') > logs/transactor.log
|
||||
docker logs $(docker ps | grep account | cut -f 1 -d ' ') > logs/account.log
|
||||
docker logs $(docker ps | grep front | cut -f 1 -d ' ') > logs/front.log
|
||||
- name: Upload test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: playwright-results-qms
|
||||
path: ./qms-tests/sanity/playwright-report/
|
||||
# - name: Get Allure history
|
||||
# uses: actions/checkout@v4
|
||||
# if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') }}
|
||||
# continue-on-error: true
|
||||
# with:
|
||||
# ref: gh-pages
|
||||
# path: gh-pages
|
||||
# - name: Generates Allure Report
|
||||
# uses: simple-elf/allure-report-action@master
|
||||
# if: always()
|
||||
# id: allure-report
|
||||
# with:
|
||||
# allure_results: ./qms-tests/sanity/allure-results/
|
||||
# gh_pages: gh-pages
|
||||
# allure_report: allure-report
|
||||
# allure_history: allure-history
|
||||
# - name: Upload allure test results
|
||||
# if: always()
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: allure-report-qms
|
||||
# path: ./allure-report/
|
||||
# - name: Deploy report to Github Pages
|
||||
# if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') }}
|
||||
# uses: peaceiris/actions-gh-pages@v4
|
||||
# with:
|
||||
# PERSONAL_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# PUBLISH_BRANCH: gh-pages
|
||||
# PUBLISH_DIR: allure-history
|
||||
- name: Upload Logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: docker-logs-qms
|
||||
path: ./qms-tests/sanity/logs
|
||||
uitest-uweb:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
|
@ -539,6 +539,9 @@ dependencies:
|
||||
'@rush-temp/products-resources':
|
||||
specifier: file:./projects/products-resources.tgz
|
||||
version: file:projects/products-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(postcss-load-config@4.0.2)(postcss@8.4.35)(ts-node@10.9.2)
|
||||
'@rush-temp/qms-tests-sanity':
|
||||
specifier: file:./projects/qms-tests-sanity.tgz
|
||||
version: file:projects/qms-tests-sanity.tgz
|
||||
'@rush-temp/query':
|
||||
specifier: file:./projects/query.tgz
|
||||
version: file:projects/query.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2)
|
||||
@ -23274,6 +23277,30 @@ packages:
|
||||
- ts-node
|
||||
dev: false
|
||||
|
||||
file:projects/qms-tests-sanity.tgz:
|
||||
resolution: {integrity: sha512-ntTsOcgNEYuQVnuTv8IDdeGHDmCqEJpcQijo2H/OJJlOfHBj52ijRQCFB8Jnhv6L2RLEV9euSHAk+VGxvWsqyw==, tarball: file:projects/qms-tests-sanity.tgz}
|
||||
name: '@rush-temp/qms-tests-sanity'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@playwright/test': 1.41.2
|
||||
'@types/jest': 29.5.12
|
||||
'@types/node': 20.11.19
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
||||
allure-playwright: 2.12.2
|
||||
cross-env: 7.0.3
|
||||
dotenv: 16.0.3
|
||||
eslint: 8.56.0
|
||||
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.3.3)
|
||||
eslint-plugin-import: 2.29.1(eslint@8.56.0)
|
||||
eslint-plugin-n: 15.7.0(eslint@8.56.0)
|
||||
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
|
||||
prettier: 3.2.5
|
||||
typescript: 5.3.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
file:projects/query.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2):
|
||||
resolution: {integrity: sha512-XIZxHSUO5njnO8+G1dIkH+RFiZ3F3xsCoSCSySE1Gy6QEGebjZUu5uT0YTFZxYe9bo3jceL7gMHPaFs3fWgMxA==, tarball: file:projects/query.tgz}
|
||||
id: file:projects/query.tgz
|
||||
|
@ -206,6 +206,7 @@
|
||||
placeholder={documents.string.DocumentCodePlaceholder}
|
||||
disabled={loadingCodes}
|
||||
bind:value={docObject.code}
|
||||
id="doc-code"
|
||||
kind="large-style"
|
||||
/>
|
||||
{#if codeNotUnique}
|
||||
|
1
qms-tests/.env
Normal file
1
qms-tests/.env
Normal file
@ -0,0 +1 @@
|
||||
STORAGE_CONFIG="minio|minio?accessKey=minioadmin&secretKey=minioadmin"
|
88
qms-tests/branding-test.json
Normal file
88
qms-tests/branding-test.json
Normal file
@ -0,0 +1,88 @@
|
||||
{
|
||||
"localhost:8083": {
|
||||
"key": "tracex",
|
||||
"title": "TraceX",
|
||||
"protocol": "http",
|
||||
"languages": "en",
|
||||
"defaultLanguage": "en",
|
||||
"defaultApplication": "documents",
|
||||
"defaultSpace": "documents:space:QualityDocuments",
|
||||
"defaultSpecial": "",
|
||||
"lastNameFirst": "true",
|
||||
"initWorkspace": "init-ws-qms",
|
||||
"links": [
|
||||
{
|
||||
"rel": "shortcut icon",
|
||||
"type": "image/x-icon",
|
||||
"href": "/tracex/favicon.ico"
|
||||
},
|
||||
{
|
||||
"rel": "icon",
|
||||
"type": "image/svg+xml",
|
||||
"sizes": "any",
|
||||
"href": "/tracex/favicon.svg"
|
||||
},
|
||||
{
|
||||
"rel": "icon",
|
||||
"type": "image/png",
|
||||
"sizes": "16x16",
|
||||
"href": "/tracex/favicon_16.png"
|
||||
},
|
||||
{
|
||||
"rel": "icon",
|
||||
"type": "image/png",
|
||||
"sizes": "32x32",
|
||||
"href": "/tracex/favicon_32.png"
|
||||
},
|
||||
{
|
||||
"rel": "icon",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192",
|
||||
"href": "/tracex/favicon_192.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
"localhost:8080": {
|
||||
"key": "tracex-dev",
|
||||
"title": "TraceX",
|
||||
"protocol": "http",
|
||||
"languages": "en",
|
||||
"defaultLanguage": "en",
|
||||
"defaultApplication": "documents",
|
||||
"defaultSpace": "documents:space:QualityDocuments",
|
||||
"defaultSpecial": "",
|
||||
"lastNameFirst": "true",
|
||||
"initWorkspace": "init-ws-qms",
|
||||
"links": [
|
||||
{
|
||||
"rel": "shortcut icon",
|
||||
"type": "image/x-icon",
|
||||
"href": "/tracex/favicon.ico"
|
||||
},
|
||||
{
|
||||
"rel": "icon",
|
||||
"type": "image/svg+xml",
|
||||
"sizes": "any",
|
||||
"href": "/tracex/favicon.svg"
|
||||
},
|
||||
{
|
||||
"rel": "icon",
|
||||
"type": "image/png",
|
||||
"sizes": "16x16",
|
||||
"href": "/tracex/favicon_16.png"
|
||||
},
|
||||
{
|
||||
"rel": "icon",
|
||||
"type": "image/png",
|
||||
"sizes": "32x32",
|
||||
"href": "/tracex/favicon_32.png"
|
||||
},
|
||||
{
|
||||
"rel": "icon",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192",
|
||||
"href": "/tracex/favicon_192.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
153
qms-tests/docker-compose.yaml
Normal file
153
qms-tests/docker-compose.yaml
Normal file
@ -0,0 +1,153 @@
|
||||
version: "3"
|
||||
services:
|
||||
mongodb:
|
||||
image: 'mongo:7-jammy'
|
||||
command: mongod --port 27018
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
ports:
|
||||
- 27018:27018
|
||||
restart: unless-stopped
|
||||
minio:
|
||||
image: 'minio/minio'
|
||||
command: server /data --address ":9000"
|
||||
expose:
|
||||
- 9000
|
||||
ports:
|
||||
- 9002:9000
|
||||
elastic:
|
||||
image: 'elasticsearch:7.14.2'
|
||||
command: |
|
||||
/bin/sh -c "./bin/elasticsearch-plugin list | grep -q ingest-attachment || yes | ./bin/elasticsearch-plugin install --silent ingest-attachment;
|
||||
/usr/local/bin/docker-entrypoint.sh eswrapper"
|
||||
expose:
|
||||
- 9200
|
||||
ports:
|
||||
- 9201:9200
|
||||
environment:
|
||||
- ELASTICSEARCH_PORT_NUMBER=9200
|
||||
- BITNAMI_DEBUG=true
|
||||
- discovery.type=single-node
|
||||
- ES_JAVA_OPTS=-Xms1024m -Xmx1024m
|
||||
- http.cors.enabled=true
|
||||
- http.cors.allow-origin=http://localhost:8082
|
||||
healthcheck:
|
||||
interval: 20s
|
||||
retries: 10
|
||||
test: curl -s http://localhost:9200/_cluster/health | grep -vq '"status":"red"'
|
||||
account:
|
||||
image: hardcoreeng/account
|
||||
pull_policy: never
|
||||
links:
|
||||
- mongodb
|
||||
- minio
|
||||
ports:
|
||||
- 3003:3003
|
||||
volumes:
|
||||
- ./branding-test.json:/var/cfg/branding-test.json
|
||||
environment:
|
||||
- ACCOUNT_PORT=3003
|
||||
- SERVER_SECRET=secret
|
||||
- MONGO_URL=mongodb://mongodb:27018
|
||||
- TRANSACTOR_URL=ws://transactor:3334
|
||||
- ENDPOINT_URL=ws://localhost:3334
|
||||
- STORAGE_CONFIG=${STORAGE_CONFIG}
|
||||
- MODEL_ENABLED=*
|
||||
- BRANDING_PATH=/var/cfg/branding-test.json
|
||||
front:
|
||||
image: hardcoreeng/front
|
||||
pull_policy: never
|
||||
links:
|
||||
- account
|
||||
- mongodb
|
||||
- minio
|
||||
- elastic
|
||||
- collaborator
|
||||
- transactor
|
||||
ports:
|
||||
- 8083:8083
|
||||
volumes:
|
||||
- ./branding-test.json:/app/dist/branding-test.json
|
||||
environment:
|
||||
- SERVER_PORT=8083
|
||||
- SERVER_SECRET=secret
|
||||
- ACCOUNTS_URL=http://localhost:3003
|
||||
- MONGO_URL=mongodb://mongodb:27018
|
||||
- UPLOAD_URL=/files
|
||||
- ELASTIC_URL=http://elastic:9200
|
||||
- GMAIL_URL=http://localhost:8088
|
||||
- CALENDAR_URL=http://localhost:8095
|
||||
- REKONI_URL=http://rekoni:4005
|
||||
- TELEGRAM_URL=http://localhost:8086
|
||||
- COLLABORATOR_URL=ws://localhost:3079
|
||||
- COLLABORATOR_API_URL=http://localhost:3079
|
||||
- STORAGE_CONFIG=${STORAGE_CONFIG}
|
||||
- BRANDING_URL=http://localhost:8083/branding-test.json
|
||||
transactor:
|
||||
image: hardcoreeng/transactor
|
||||
pull_policy: never
|
||||
links:
|
||||
- mongodb
|
||||
- elastic
|
||||
- minio
|
||||
- rekoni
|
||||
- account
|
||||
ports:
|
||||
- 3334:3334
|
||||
volumes:
|
||||
- ./branding-test.json:/var/cfg/branding-test.json
|
||||
environment:
|
||||
- SERVER_PROVIDER=${SERVER_PROVIDER}
|
||||
- SERVER_PORT=3334
|
||||
- SERVER_SECRET=secret
|
||||
- ELASTIC_URL=http://elastic:9200
|
||||
- MONGO_URL=mongodb://mongodb:27018
|
||||
- METRICS_CONSOLE=false
|
||||
- METRICS_FILE=metrics.txt
|
||||
- STORAGE_CONFIG=${STORAGE_CONFIG}
|
||||
- REKONI_URL=http://rekoni:4005
|
||||
- FRONT_URL=http://localhost:8083
|
||||
- UPLOAD_URL=http://localhost:8083/files
|
||||
- ACCOUNTS_URL=http://account:3003
|
||||
- LAST_NAME_FIRST=true
|
||||
- ELASTIC_INDEX_NAME=local_storage_index
|
||||
- BRANDING_PATH=/var/cfg/branding-test.json
|
||||
collaborator:
|
||||
image: hardcoreeng/collaborator
|
||||
links:
|
||||
- mongodb
|
||||
- minio
|
||||
- transactor
|
||||
ports:
|
||||
- 3079:3079
|
||||
environment:
|
||||
- COLLABORATOR_PORT=3079
|
||||
- SECRET=secret
|
||||
- ACCOUNTS_URL=http://account:3003
|
||||
- TRANSACTOR_URL=ws://transactor:3334
|
||||
- UPLOAD_URL=/files
|
||||
- MONGO_URL=mongodb://mongodb:27018
|
||||
- STORAGE_CONFIG=${STORAGE_CONFIG}
|
||||
restart: unless-stopped
|
||||
rekoni:
|
||||
image: hardcoreeng/rekoni-service
|
||||
restart: on-failure
|
||||
ports:
|
||||
- 4005:4004
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 1024M
|
||||
# qms-workers:
|
||||
# image: hardcoreeng/qms-workers
|
||||
# restart: always
|
||||
# links:
|
||||
# - transactor
|
||||
# - account
|
||||
# environment:
|
||||
# - SECRET=secret
|
||||
# - TRANSACTOR_URL=ws://transactor:3334
|
||||
# - ACCOUNTS_URL=http://account:3003
|
||||
volumes:
|
||||
files:
|
35
qms-tests/prepare.sh
Executable file
35
qms-tests/prepare.sh
Executable file
@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker compose -p sanity kill
|
||||
docker compose -p sanity down --volumes
|
||||
docker compose -p sanity up -d --force-recreate --renew-anon-volumes
|
||||
docker_exit=$?
|
||||
if [ ${docker_exit} -eq 0 ]; then
|
||||
echo "Container started successfully"
|
||||
else
|
||||
echo "Container started with errors"
|
||||
exit ${docker_exit}
|
||||
fi
|
||||
|
||||
|
||||
# Create init workspace
|
||||
./tool.sh create-workspace init-ws-qms -w InitTest
|
||||
./tool.sh configure init-ws-qms --enable=*
|
||||
./tool.sh configure init-ws-qms --list
|
||||
|
||||
# Create workspace record in accounts
|
||||
./tool.sh create-workspace sanity-ws-qms -w SanityTest
|
||||
# Create user record in accounts
|
||||
./tool.sh create-account user1 -f John -l Appleseed -p 1234
|
||||
./tool.sh create-account user2 -f Kainin -l Dirak -p 1234
|
||||
./tool.sh assign-workspace user1 sanity-ws-qms
|
||||
./tool.sh assign-workspace user2 sanity-ws-qms
|
||||
# Make user the workspace maintainer
|
||||
./tool.sh confirm-email user1
|
||||
./tool.sh confirm-email user2
|
||||
|
||||
./tool.sh create-account user_qara -f Qara -l Admin -p 1234
|
||||
./tool.sh assign-workspace user_qara sanity-ws-qms
|
||||
./tool.sh confirm-email user_qara
|
||||
|
||||
./restore-workspace.sh
|
14
qms-tests/restore-workspace.sh
Executable file
14
qms-tests/restore-workspace.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Restore workspace contents in mongo/elastic
|
||||
./tool.sh backup-restore ./sanity-ws-qms/ sanity-ws-qms
|
||||
|
||||
./tool.sh upgrade-workspace sanity-ws-qms
|
||||
|
||||
# Re-assign user to workspace.
|
||||
./tool.sh assign-workspace user1 sanity-ws-qms
|
||||
./tool.sh assign-workspace user2 sanity-ws-qms
|
||||
./tool.sh assign-workspace user_qara sanity-ws-qms
|
||||
|
||||
./tool.sh configure sanity-ws-qms --enable=*
|
||||
./tool.sh configure sanity-ws-qms --list
|
Binary file not shown.
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/activity-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/activity-1716580272084-0.snp.gz
Normal file
Binary file not shown.
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/attachment-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/attachment-1716580272084-0.snp.gz
Normal file
Binary file not shown.
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/automation-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/automation-1716580272084-0.snp.gz
Normal file
Binary file not shown.
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/blob-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/blob-1716580272084-0.snp.gz
Normal file
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/blob-data-1716580272084-1.tar.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/blob-data-1716580272084-1.tar.gz
Normal file
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/calendar-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/calendar-1716580272084-0.snp.gz
Normal file
Binary file not shown.
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/channel-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/channel-1716580272084-0.snp.gz
Normal file
Binary file not shown.
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/contact-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/contact-1716580272084-0.snp.gz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/documents-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/documents-1716580272084-0.snp.gz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/hr-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/hr-1716580272084-0.snp.gz
Normal file
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/hr-data-1716580272084-1.tar.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/hr-data-1716580272084-1.tar.gz
Normal file
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/kanban-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/kanban-1716580272084-0.snp.gz
Normal file
Binary file not shown.
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/love-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/love-1716580272084-0.snp.gz
Normal file
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/love-data-1716580272084-1.tar.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/love-data-1716580272084-1.tar.gz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/request-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/request-1716580272084-0.snp.gz
Normal file
Binary file not shown.
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/space-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/space-1716580272084-0.snp.gz
Normal file
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/space-data-1716580272084-1.tar.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/space-data-1716580272084-1.tar.gz
Normal file
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/status-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/status-1716580272084-0.snp.gz
Normal file
Binary file not shown.
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/tags-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/tags-1716580272084-0.snp.gz
Normal file
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/tags-data-1716580272084-1.tar.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/tags-data-1716580272084-1.tar.gz
Normal file
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/training-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/training-1716580272084-0.snp.gz
Normal file
Binary file not shown.
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/tx-1716580272084-0.snp.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/tx-1716580272084-0.snp.gz
Normal file
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/000001/tx-data-1716580272084-1.tar.gz
Normal file
BIN
qms-tests/sanity-ws-qms/000001/tx-data-1716580272084-1.tar.gz
Normal file
Binary file not shown.
BIN
qms-tests/sanity-ws-qms/backup.json.gz
Normal file
BIN
qms-tests/sanity-ws-qms/backup.json.gz
Normal file
Binary file not shown.
9
qms-tests/sanity/.env
Normal file
9
qms-tests/sanity/.env
Normal file
@ -0,0 +1,9 @@
|
||||
PLATFORM_URI='http://localhost:8083'
|
||||
PLATFORM_TRANSACTOR='ws://localhost:3334'
|
||||
PLATFORM_USER='user1'
|
||||
PLATFORM_USER_SECOND='user2'
|
||||
PLATFORM_TOKEN='eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjb25maXJtZWQiOnRydWUsImVtYWlsIjoidXNlcjEiLCJ3b3Jrc3BhY2UiOiJzYW5pdHktd3MtcW1zIiwicHJvZHVjdElkIjoiIn0.vQK1jI8gHkjnNJf5XZ71L4dCqyHNmKW4_iBGrhXrqW8'
|
||||
SETTING=storage.json
|
||||
SETTING_SECOND=storageSecond.json
|
||||
SETTING_QARA_MANAGER=storageQaraManager.json
|
||||
PLATFORM_PASSWORD='1234'
|
7
qms-tests/sanity/.eslintrc.js
Normal file
7
qms-tests/sanity/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
5
qms-tests/sanity/.gitignore
vendored
Normal file
5
qms-tests/sanity/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
playwright-report
|
||||
test-results/*
|
||||
allure-report
|
||||
allure-results
|
||||
screenshots/*
|
5
qms-tests/sanity/config/rig.json
Normal file
5
qms-tests/sanity/config/rig.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
"rigPackageName": "@hcengineering/platform-rig",
|
||||
"rigProfile": "default"
|
||||
}
|
53
qms-tests/sanity/package.json
Normal file
53
qms-tests/sanity/package.json
Normal file
@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "@hcengineering/qms-tests-sanity",
|
||||
"version": "0.6.0",
|
||||
"main": "lib/index.js",
|
||||
"svelte": "src/index.ts",
|
||||
"types": "types/index.d.ts",
|
||||
"author": "Hardcore Engineering Inc",
|
||||
"template": "@hcengineering/default-package",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "compile",
|
||||
"build:watch": "compile",
|
||||
"_phase:build": "compile transpile tests",
|
||||
"_phase:test": "",
|
||||
"_phase:format": "format src",
|
||||
"_phase:validate": "compile validate",
|
||||
"lint:fix": "eslint --fix tests",
|
||||
"lint": "eslint tests",
|
||||
"format": "format tests",
|
||||
"ci": "playwright install --with-deps chromium",
|
||||
"test": "",
|
||||
"uitest": "cross-env LOCAL_URL=http://localhost:3003/ DEV_URL= playwright test -c ./tests/playwright.config.ts",
|
||||
"staging-uitest": "cross-env PLATFORM_URI=https://front.hc.engineering/ playwright test -c ./tests/playwright.config.ts --grep @staging",
|
||||
"dev-uitest": "cross-env PLATFORM_URI=http://localhost:8080 PLATFORM_TRANSACTOR=ws://localhost:3333 SETTING=storage-dev.json SETTING_SECOND=storageSecond-dev.json DEV_URL=http://localhost:8080/account playwright test -c ./tests/playwright.config.ts",
|
||||
"debug": "playwright test -c ./tests/playwright.config.ts --debug --headed",
|
||||
"dev-debug": "cross-env PLATFORM_URI=http://localhost:8080 PLATFORM_TRANSACTOR=ws://localhost:3333 SETTING=storage-dev.json SETTING_SECOND=storageSecond-dev.json playwright test -c ./tests/playwright.config.ts --debug --headed",
|
||||
"codegen": "playwright codegen --load-storage storage.json http://localhost:8083/workbench/sanity-ws/",
|
||||
"dev-codegen": "cross-env playwright codegen --load-storage storage-dev.json http://localhost:8080/workbench/sanity-ws/",
|
||||
"allure:generate": "allure generate allure-results -o allure-report --clean"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hcengineering/platform-rig": "^0.6.0",
|
||||
"@types/jest": "^29.5.5",
|
||||
"@types/node": "~20.11.16",
|
||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-n": "^15.4.0",
|
||||
"eslint": "^8.54.0",
|
||||
"@typescript-eslint/parser": "^6.11.0",
|
||||
"eslint-config-standard-with-typescript": "^40.0.0",
|
||||
"prettier": "^3.1.0",
|
||||
"typescript": "^5.3.3",
|
||||
"@playwright/test": "^1.41.2",
|
||||
"allure-playwright": "^2.9.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "~16.0.0",
|
||||
"cross-env": "~7.0.3",
|
||||
"@hcengineering/core": "^0.6.32",
|
||||
"@hcengineering/client-resources": "^0.6.27"
|
||||
}
|
||||
}
|
34
qms-tests/sanity/storage-dev.json
Normal file
34
qms-tests/sanity/storage-dev.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"cookies": [],
|
||||
"origins": [
|
||||
{
|
||||
"origin": "http://localhost:8080",
|
||||
"localStorage": [
|
||||
{
|
||||
"name": "login:metadata:LoginEmail",
|
||||
"value": "user1"
|
||||
},
|
||||
{
|
||||
"name": "login:metadata:LoginTokens",
|
||||
"value": "{\"sanity-ws-qms\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjb25maXJtZWQiOnRydWUsImVtYWlsIjoidXNlcjEiLCJ3b3Jrc3BhY2UiOiJzYW5pdHktd3MtcW1zIiwicHJvZHVjdElkIjoiIn0.vQK1jI8gHkjnNJf5XZ71L4dCqyHNmKW4_iBGrhXrqW8\"}"
|
||||
},
|
||||
{
|
||||
"name": "login:metadata:LoginEndpoint",
|
||||
"value": "ws://localhost:3334"
|
||||
},
|
||||
{
|
||||
"name": "#platform.notification.logging",
|
||||
"value": "false"
|
||||
},
|
||||
{
|
||||
"name": "#platform.lazy.loading",
|
||||
"value": "false"
|
||||
},
|
||||
{
|
||||
"name": "flagOpenInDesktopApp",
|
||||
"value": "true"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
34
qms-tests/sanity/storage.json
Normal file
34
qms-tests/sanity/storage.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"cookies": [],
|
||||
"origins": [
|
||||
{
|
||||
"origin": "http://localhost:8083",
|
||||
"localStorage": [
|
||||
{
|
||||
"name": "login:metadata:LoginEmail",
|
||||
"value": "user1"
|
||||
},
|
||||
{
|
||||
"name": "login:metadata:LoginTokens",
|
||||
"value": "{\"sanity-ws-qms\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjb25maXJtZWQiOnRydWUsImVtYWlsIjoidXNlcjEiLCJ3b3Jrc3BhY2UiOiJzYW5pdHktd3MtcW1zIiwicHJvZHVjdElkIjoiIn0.vQK1jI8gHkjnNJf5XZ71L4dCqyHNmKW4_iBGrhXrqW8\"}"
|
||||
},
|
||||
{
|
||||
"name": "login:metadata:LoginEndpoint",
|
||||
"value": "ws://localhost:3334"
|
||||
},
|
||||
{
|
||||
"name": "#platform.notification.logging",
|
||||
"value": "false"
|
||||
},
|
||||
{
|
||||
"name": "#platform.lazy.loading",
|
||||
"value": "false"
|
||||
},
|
||||
{
|
||||
"name": "flagOpenInDesktopApp",
|
||||
"value": "true"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
34
qms-tests/sanity/storageQaraManager.json
Normal file
34
qms-tests/sanity/storageQaraManager.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"cookies": [],
|
||||
"origins": [
|
||||
{
|
||||
"origin": "http://localhost:8083",
|
||||
"localStorage": [
|
||||
{
|
||||
"name": "login:metadata:LoginEmail",
|
||||
"value": "user_qara"
|
||||
},
|
||||
{
|
||||
"name": "login:metadata:LoginTokens",
|
||||
"value": "{\"sanity-ws-qms\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjb25maXJtZWQiOnRydWUsImVtYWlsIjoidXNlcl9xYXJhIiwid29ya3NwYWNlIjoic2FuaXR5LXdzLXFtcyIsInByb2R1Y3RJZCI6IiJ9.6OuCr6aIkzS9TiUAWbnFbsK98NKnCNqAY92ZkmYvw6k\"}"
|
||||
},
|
||||
{
|
||||
"name": "login:metadata:LoginEndpoint",
|
||||
"value": "ws://localhost:3334"
|
||||
},
|
||||
{
|
||||
"name": "#platform.notification.logging",
|
||||
"value": "false"
|
||||
},
|
||||
{
|
||||
"name": "#platform.lazy.loading",
|
||||
"value": "false"
|
||||
},
|
||||
{
|
||||
"name": "flagOpenInDesktopApp",
|
||||
"value": "true"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
34
qms-tests/sanity/storageSecond-dev.json
Normal file
34
qms-tests/sanity/storageSecond-dev.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"cookies": [],
|
||||
"origins": [
|
||||
{
|
||||
"origin": "http://localhost:8080",
|
||||
"localStorage": [
|
||||
{
|
||||
"name": "login:metadata:LoginEmail",
|
||||
"value": "user2"
|
||||
},
|
||||
{
|
||||
"name": "login:metadata:LoginTokens",
|
||||
"value": "{\"sanity-ws-qms\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjb25maXJtZWQiOnRydWUsImVtYWlsIjoidXNlcjIiLCJ3b3Jrc3BhY2UiOiJzYW5pdHktd3MtcW1zIiwicHJvZHVjdElkIjoiIn0.-al3BXM41qvOaZ4s7c96xQZO73udvQrs8dH2bmhScww\"}"
|
||||
},
|
||||
{
|
||||
"name": "login:metadata:LoginEndpoint",
|
||||
"value": "ws://localhost:3334"
|
||||
},
|
||||
{
|
||||
"name": "#platform.notification.logging",
|
||||
"value": "false"
|
||||
},
|
||||
{
|
||||
"name": "#platform.lazy.loading",
|
||||
"value": "false"
|
||||
},
|
||||
{
|
||||
"name": "flagOpenInDesktopApp",
|
||||
"value": "true"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
34
qms-tests/sanity/storageSecond.json
Normal file
34
qms-tests/sanity/storageSecond.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"cookies": [],
|
||||
"origins": [
|
||||
{
|
||||
"origin": "http://localhost:8083",
|
||||
"localStorage": [
|
||||
{
|
||||
"name": "login:metadata:LoginEmail",
|
||||
"value": "user2"
|
||||
},
|
||||
{
|
||||
"name": "login:metadata:LoginTokens",
|
||||
"value": "{\"sanity-ws-qms\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjb25maXJtZWQiOnRydWUsImVtYWlsIjoidXNlcjIiLCJ3b3Jrc3BhY2UiOiJzYW5pdHktd3MtcW1zIiwicHJvZHVjdElkIjoiIn0.-al3BXM41qvOaZ4s7c96xQZO73udvQrs8dH2bmhScww\"}"
|
||||
},
|
||||
{
|
||||
"name": "login:metadata:LoginEndpoint",
|
||||
"value": "ws://localhost:3334"
|
||||
},
|
||||
{
|
||||
"name": "#platform.notification.logging",
|
||||
"value": "false"
|
||||
},
|
||||
{
|
||||
"name": "#platform.lazy.loading",
|
||||
"value": "false"
|
||||
},
|
||||
{
|
||||
"name": "flagOpenInDesktopApp",
|
||||
"value": "true"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
170
qms-tests/sanity/tests/documents/categories.spec.ts
Normal file
170
qms-tests/sanity/tests/documents/categories.spec.ts
Normal file
@ -0,0 +1,170 @@
|
||||
import { test } from '@playwright/test'
|
||||
import { attachScreenshot, generateId, HomepageURI, PlatformSetting, PlatformURI } from '../utils'
|
||||
import { DocumentStatus, NewCategory, NewTemplate, UpdateCategory } from '../model/types'
|
||||
import { allure } from 'allure-playwright'
|
||||
import { CategoriesPage } from '../model/documents/categories-page'
|
||||
import { CategoryDetailsPage } from '../model/documents/category-details-page'
|
||||
import { prepareCategoryStep } from './common-documents-steps'
|
||||
import { LeftSideMenuPage } from '../model/left-side-menu-page'
|
||||
import { NavigationMenuPage } from '../model/documents/navigation-menu-page'
|
||||
import { TemplatesPage } from '../model/documents/templates-page'
|
||||
import { DocumentContentPage } from '../model/documents/document-content-page'
|
||||
|
||||
test.use({
|
||||
storageState: PlatformSetting
|
||||
})
|
||||
|
||||
test.describe('QMS. Categories tests', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await (await page.goto(`${PlatformURI}/${HomepageURI}`))?.finished()
|
||||
})
|
||||
|
||||
test('TESTS-131. Create a new category', async ({ page }) => {
|
||||
await allure.description('Requirement\nUsers need to create a new category')
|
||||
await allure.tms('TESTS-131', 'https://front.hc.engineering/workbench/platform/tracker/TESTS-131')
|
||||
const newCategory: NewCategory = {
|
||||
title: `New category-${generateId()}`,
|
||||
code: `CODE-${generateId(4)}`,
|
||||
description: `New category description-${generateId()}`,
|
||||
attachFileName: 'cat.jpeg'
|
||||
}
|
||||
|
||||
await prepareCategoryStep(page, newCategory)
|
||||
|
||||
await test.step('2. Check category information', async () => {
|
||||
const categoriesPage = new CategoriesPage(page)
|
||||
await categoriesPage.openCategory(newCategory.title)
|
||||
|
||||
const categoryDetailsPage = new CategoryDetailsPage(page)
|
||||
await categoryDetailsPage.checkTitle(newCategory.title)
|
||||
})
|
||||
|
||||
await attachScreenshot('TESTS-131_create_category.png', page)
|
||||
})
|
||||
|
||||
test('TESTS-132. Edit a Category', async ({ page }) => {
|
||||
await allure.description('Requirement\nUsers need to edit a category')
|
||||
await allure.tms('TESTS-132', 'https://front.hc.engineering/workbench/platform/tracker/TESTS-132')
|
||||
const editCategory: NewCategory = {
|
||||
title: `Edit category-${generateId()}`,
|
||||
code: `EDIT-${generateId(4)}`,
|
||||
description: `Edit category description-${generateId()}`
|
||||
}
|
||||
const updatedEditCategory: UpdateCategory = {
|
||||
description: `Updated edit category description-${generateId()}`,
|
||||
attachFileName: 'cat.jpeg'
|
||||
}
|
||||
|
||||
await prepareCategoryStep(page, editCategory)
|
||||
|
||||
await test.step('2. Edit Description and add Attachments', async () => {
|
||||
const categoriesPage = new CategoriesPage(page)
|
||||
await categoriesPage.openCategory(editCategory.title)
|
||||
|
||||
const categoryDetailsPage = new CategoryDetailsPage(page)
|
||||
await categoryDetailsPage.checkCategory(editCategory)
|
||||
await categoryDetailsPage.editCategory(updatedEditCategory)
|
||||
})
|
||||
|
||||
await test.step('3. Check category information', async () => {
|
||||
const categoryDetailsPage = new CategoryDetailsPage(page)
|
||||
await categoryDetailsPage.checkCategory({
|
||||
...editCategory,
|
||||
...updatedEditCategory
|
||||
})
|
||||
})
|
||||
|
||||
await attachScreenshot('TESTS-132_edit_category.png', page)
|
||||
})
|
||||
|
||||
test('TESTS-133. Delete Category', async ({ page }) => {
|
||||
await allure.description('Requirement\nUsers need to delete category')
|
||||
await allure.tms('TESTS-133', 'https://front.hc.engineering/workbench/platform/tracker/TESTS-133')
|
||||
const editCategory: NewCategory = {
|
||||
title: `Delete category-${generateId()}`,
|
||||
code: `DELETE-${generateId(4)}`,
|
||||
description: `Delete category description-${generateId()}`
|
||||
}
|
||||
|
||||
await prepareCategoryStep(page, editCategory)
|
||||
|
||||
await test.step('2. Delete a Category', async () => {
|
||||
const categoriesPage = new CategoriesPage(page)
|
||||
await categoriesPage.openCategory(editCategory.title)
|
||||
|
||||
const categoryDetailsPage = new CategoryDetailsPage(page)
|
||||
await categoryDetailsPage.checkCategory(editCategory)
|
||||
await categoryDetailsPage.executeMoreAction('Delete')
|
||||
})
|
||||
|
||||
await test.step('3. Check category doesn’t exist', async () => {
|
||||
const categoriesPage = new CategoriesPage(page)
|
||||
await categoriesPage.checkCategoryNotExist(editCategory.title)
|
||||
})
|
||||
|
||||
await attachScreenshot('TESTS-133_delete_category.png', page)
|
||||
})
|
||||
|
||||
test('TESTS-215. Can not Delete Category if there are templates associated', async ({ page }) => {
|
||||
await allure.description('Requirement\nUsers can not delete the category if there are templates associated')
|
||||
await allure.tms('TESTS-215', 'https://front.hc.engineering/workbench/platform/tracker/TESTS-215')
|
||||
const canNotDeleteCategory: NewCategory = {
|
||||
title: `Can not Delete category-${generateId()}`,
|
||||
code: `CANT_DELETE-${generateId(4)}`,
|
||||
description: `Can not Delete category description-${generateId()}`
|
||||
}
|
||||
const canNotDeleteCategoryTemplate: NewTemplate = {
|
||||
location: {
|
||||
space: 'Quality documents',
|
||||
parent: 'Quality documents'
|
||||
},
|
||||
title: `Can not Delete Category Template-${generateId()}`,
|
||||
description: `Can not Delete Category Template description-${generateId()}`,
|
||||
code: generateId(4),
|
||||
category: canNotDeleteCategory.title,
|
||||
reason: 'Test reason',
|
||||
reviewers: ['Appleseed John'],
|
||||
approvers: ['Appleseed John']
|
||||
}
|
||||
|
||||
await prepareCategoryStep(page, canNotDeleteCategory)
|
||||
|
||||
await test.step('2. Create new templates to the category', async () => {
|
||||
const leftSideMenuPage = new LeftSideMenuPage(page)
|
||||
await leftSideMenuPage.buttonDocuments.click()
|
||||
|
||||
const navigationMenuPage = new NavigationMenuPage(page)
|
||||
await navigationMenuPage.buttonTemplates.click()
|
||||
|
||||
const templatesPage = new TemplatesPage(page)
|
||||
await templatesPage.buttonCreateTemplate.click()
|
||||
|
||||
await templatesPage.createTemplate(canNotDeleteCategoryTemplate)
|
||||
|
||||
const documentContentPage = new DocumentContentPage(page)
|
||||
await documentContentPage.checkDocumentTitle(canNotDeleteCategoryTemplate.title)
|
||||
await documentContentPage.checkDocument({
|
||||
type: 'N/A',
|
||||
category: canNotDeleteCategoryTemplate.category ?? '',
|
||||
version: 'v0.1',
|
||||
status: DocumentStatus.DRAFT,
|
||||
owner: 'Appleseed John',
|
||||
author: 'Appleseed John'
|
||||
})
|
||||
})
|
||||
|
||||
await test.step('3. Try to Delete a Category', async () => {
|
||||
const navigationMenuPage = new NavigationMenuPage(page)
|
||||
await navigationMenuPage.buttonCategories.click()
|
||||
|
||||
const categoriesPage = new CategoriesPage(page)
|
||||
await categoriesPage.openCategory(canNotDeleteCategory.title)
|
||||
|
||||
const categoryDetailsPage = new CategoryDetailsPage(page)
|
||||
await categoryDetailsPage.checkCategory(canNotDeleteCategory)
|
||||
await categoryDetailsPage.checkMoreActionNotExist('Delete')
|
||||
})
|
||||
|
||||
await attachScreenshot('TESTS-215_can_not_delete_category.png', page)
|
||||
})
|
||||
})
|
35
qms-tests/sanity/tests/documents/common-documents-steps.ts
Normal file
35
qms-tests/sanity/tests/documents/common-documents-steps.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { Page, test } from '@playwright/test'
|
||||
import { LeftSideMenuPage } from '../model/left-side-menu-page'
|
||||
import { DocumentsPage } from '../model/documents/documents-page'
|
||||
import { NewCategory, NewDocument } from '../model/types'
|
||||
import { NavigationMenuPage } from '../model/documents/navigation-menu-page'
|
||||
import { CategoriesPage } from '../model/documents/categories-page'
|
||||
import { CategoryCreatePopup } from '../model/documents/category-create-popup'
|
||||
|
||||
export async function prepareDocumentStep (page: Page, document: NewDocument, stepNumber: number = 1): Promise<void> {
|
||||
await test.step(`${stepNumber}. Create a new document`, async () => {
|
||||
const leftSideMenuPage = new LeftSideMenuPage(page)
|
||||
await leftSideMenuPage.buttonDocuments.click()
|
||||
|
||||
const documentsPage = new DocumentsPage(page)
|
||||
await documentsPage.buttonCreateDocument.click()
|
||||
|
||||
await documentsPage.createDocument(document)
|
||||
})
|
||||
}
|
||||
|
||||
export async function prepareCategoryStep (page: Page, newCategory: NewCategory): Promise<void> {
|
||||
await test.step('1. Create a new category', async () => {
|
||||
const leftSideMenuPage = new LeftSideMenuPage(page)
|
||||
await leftSideMenuPage.buttonDocuments.click()
|
||||
|
||||
const navigationMenuPage = new NavigationMenuPage(page)
|
||||
await navigationMenuPage.buttonCategories.click()
|
||||
|
||||
const categoriesPage = new CategoriesPage(page)
|
||||
await categoriesPage.buttonCreateCategory.click()
|
||||
|
||||
const categoryCreatePopup = new CategoryCreatePopup(page)
|
||||
await categoryCreatePopup.createCategory(newCategory)
|
||||
})
|
||||
}
|
1114
qms-tests/sanity/tests/documents/documents.spec.ts
Normal file
1114
qms-tests/sanity/tests/documents/documents.spec.ts
Normal file
File diff suppressed because it is too large
Load Diff
104
qms-tests/sanity/tests/documents/templates.spec.ts
Normal file
104
qms-tests/sanity/tests/documents/templates.spec.ts
Normal file
@ -0,0 +1,104 @@
|
||||
import { test } from '@playwright/test'
|
||||
import { attachScreenshot, generateId, HomepageURI, PlatformSetting, PlatformURI } from '../utils'
|
||||
import { LeftSideMenuPage } from '../model/left-side-menu-page'
|
||||
import { DocumentStatus, NewTemplate } from '../model/types'
|
||||
import { DocumentContentPage } from '../model/documents/document-content-page'
|
||||
import { NavigationMenuPage } from '../model/documents/navigation-menu-page'
|
||||
import { TemplatesPage } from '../model/documents/templates-page'
|
||||
import { allure } from 'allure-playwright'
|
||||
|
||||
test.use({
|
||||
storageState: PlatformSetting
|
||||
})
|
||||
|
||||
test.describe('QMS. Templates tests', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await (await page.goto(`${PlatformURI}/${HomepageURI}`))?.finished()
|
||||
})
|
||||
|
||||
test('TESTS-129. Create Template', async ({ page }) => {
|
||||
await allure.description('Requirement\nUsers need to create a new template')
|
||||
await allure.tms('TESTS-129', 'https://front.hc.engineering/workbench/platform/tracker/TESTS-129')
|
||||
const newTemplate: NewTemplate = {
|
||||
location: {
|
||||
space: 'Quality documents',
|
||||
parent: 'Quality documents'
|
||||
},
|
||||
title: `New Template-${generateId()}`,
|
||||
description: `New Template description-${generateId()}`,
|
||||
code: generateId(4),
|
||||
category: 'Document-Control',
|
||||
reason: 'Test reason',
|
||||
reviewers: ['Appleseed John'],
|
||||
approvers: ['Appleseed John']
|
||||
}
|
||||
|
||||
await test.step('1. Create a new template', async () => {
|
||||
const leftSideMenuPage = new LeftSideMenuPage(page)
|
||||
await leftSideMenuPage.buttonDocuments.click()
|
||||
|
||||
const navigationMenuPage = new NavigationMenuPage(page)
|
||||
await navigationMenuPage.buttonTemplates.click()
|
||||
|
||||
const templatesPage = new TemplatesPage(page)
|
||||
await templatesPage.buttonCreateTemplate.click()
|
||||
|
||||
await templatesPage.createTemplate(newTemplate)
|
||||
})
|
||||
|
||||
await test.step('2. Check document information', async () => {
|
||||
const documentContentPage = new DocumentContentPage(page)
|
||||
await documentContentPage.checkDocumentTitle(newTemplate.title)
|
||||
await documentContentPage.checkDocument({
|
||||
type: 'N/A',
|
||||
category: newTemplate.category ?? '',
|
||||
version: 'v0.1',
|
||||
status: DocumentStatus.DRAFT,
|
||||
owner: 'Appleseed John',
|
||||
author: 'Appleseed John'
|
||||
})
|
||||
})
|
||||
|
||||
await attachScreenshot('TESTS-129_create_template.png', page)
|
||||
})
|
||||
|
||||
test('TESTS-181. Delete template', async ({ page }) => {
|
||||
await allure.description('Requirement\nUsers need to delete the template')
|
||||
await allure.tms('TESTS-181', 'https://front.hc.engineering/workbench/platform/tracker/TESTS-181')
|
||||
const deleteTemplate: NewTemplate = {
|
||||
title: `Delete Template-${generateId()}`,
|
||||
description: `Delete Template description-${generateId()}`,
|
||||
code: generateId(4),
|
||||
location: {
|
||||
space: 'Quality documents',
|
||||
parent: 'Quality documents'
|
||||
}
|
||||
}
|
||||
|
||||
const documentContentPage = new DocumentContentPage(page)
|
||||
await test.step('1. Create a new template', async () => {
|
||||
const leftSideMenuPage = new LeftSideMenuPage(page)
|
||||
await leftSideMenuPage.buttonDocuments.click()
|
||||
|
||||
const navigationMenuPage = new NavigationMenuPage(page)
|
||||
await navigationMenuPage.buttonTemplates.click()
|
||||
|
||||
const templatesPage = new TemplatesPage(page)
|
||||
await templatesPage.buttonCreateTemplate.click()
|
||||
|
||||
await templatesPage.createTemplate(deleteTemplate)
|
||||
await documentContentPage.checkDocumentTitle(deleteTemplate.title)
|
||||
await documentContentPage.checkDocumentStatus(DocumentStatus.DRAFT)
|
||||
})
|
||||
|
||||
await test.step('2. Delete the template', async () => {
|
||||
await documentContentPage.executeMoreActions('Delete')
|
||||
await documentContentPage.pressYesForPopup(page)
|
||||
})
|
||||
|
||||
await test.step('3. Check that the document status is equal to the deleted', async () => {
|
||||
await documentContentPage.checkDocumentStatus(DocumentStatus.DELETED)
|
||||
})
|
||||
await attachScreenshot('TESTS-181_delete_template.png', page)
|
||||
})
|
||||
})
|
BIN
qms-tests/sanity/tests/files/cat.jpeg
Normal file
BIN
qms-tests/sanity/tests/files/cat.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
79
qms-tests/sanity/tests/login/registration.spec.ts
Normal file
79
qms-tests/sanity/tests/login/registration.spec.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import { expect, test } from '@playwright/test'
|
||||
import { attachScreenshot, generateId, PlatformURI, randomString } from '../utils'
|
||||
import { allure } from 'allure-playwright'
|
||||
import { UserSignUp } from '../model/types'
|
||||
import { LoginPage } from '../model/login-page'
|
||||
import { SignupPage } from '../model/signup-page'
|
||||
import { SelectWorkspacePage } from '../model/select-workspace-page'
|
||||
import { LeftSideMenuPage } from '../model/left-side-menu-page'
|
||||
|
||||
test.describe('Registration tests', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await (await page.goto(`${PlatformURI}`))?.finished()
|
||||
})
|
||||
|
||||
// Skipped until we fix init workspace for tracex
|
||||
test.skip('TESTS-143. User Registration', async ({ page }) => {
|
||||
await allure.description('Requirement\nUsers need to register with the system')
|
||||
await allure.tms('TESTS-143', 'https://front.hc.engineering/workbench/platform/tracker/TESTS-143')
|
||||
await allure.description('User Registration')
|
||||
const workspaceName = `workspace-${generateId(4)}`
|
||||
|
||||
const signUpUserData: UserSignUp = {
|
||||
firstName: randomString(),
|
||||
lastName: randomString(),
|
||||
email: `${randomString()}@gmail.com`,
|
||||
password: '1234'
|
||||
}
|
||||
|
||||
await test.step('1. Registration', async () => {
|
||||
const loginPage = new LoginPage(page)
|
||||
await loginPage.goto()
|
||||
await loginPage.buttonSignUp.click()
|
||||
|
||||
const signupPage = new SignupPage(page)
|
||||
await signupPage.signup(signUpUserData)
|
||||
|
||||
await attachScreenshot('TESTS-143_registration.png', page)
|
||||
|
||||
await signupPage.buttonSignUp.click()
|
||||
})
|
||||
|
||||
await test.step('2. Create workspace', async () => {
|
||||
const selectWorkspacePage = new SelectWorkspacePage(page)
|
||||
await selectWorkspacePage.createWorkspace(workspaceName)
|
||||
|
||||
await attachScreenshot('TESTS-143_create_workspace.png', page)
|
||||
|
||||
await selectWorkspacePage.buttonCreateWorkspace.click()
|
||||
|
||||
const leftSideMenuPage = new LeftSideMenuPage(page)
|
||||
await leftSideMenuPage.buttonDocuments.waitFor({ state: 'visible' })
|
||||
await expect(leftSideMenuPage.buttonDocuments).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
test('TESTS-144. Negative - Duplicate Email', async ({ page }) => {
|
||||
await allure.description('Requirement\nThe system should reject the registration with an email that already exists')
|
||||
await allure.tms('TESTS-144', 'https://front.hc.engineering/workbench/platform/tracker/TESTS-144')
|
||||
const signUpUserData: UserSignUp = {
|
||||
firstName: randomString(),
|
||||
lastName: randomString(),
|
||||
email: 'user1',
|
||||
password: '1234'
|
||||
}
|
||||
|
||||
await test.step('1. Attempt to register a user with an email that already exists', async () => {
|
||||
const loginPage = new LoginPage(page)
|
||||
await loginPage.goto()
|
||||
await loginPage.buttonSignUp.click()
|
||||
|
||||
const signupPage = new SignupPage(page)
|
||||
await signupPage.signup(signUpUserData)
|
||||
await signupPage.buttonSignUp.click()
|
||||
|
||||
await expect(signupPage.textError).toHaveText('Account already exists')
|
||||
})
|
||||
await attachScreenshot('TESTS-144_duplicate_email.png', page)
|
||||
})
|
||||
})
|
41
qms-tests/sanity/tests/model/calendar-page.ts
Normal file
41
qms-tests/sanity/tests/model/calendar-page.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { Locator, Page } from '@playwright/test'
|
||||
import { CommonPage } from './common-page'
|
||||
|
||||
export class CalendarPage extends CommonPage {
|
||||
readonly page: Page
|
||||
readonly buttonDatePopupToday: Locator
|
||||
readonly inputPopupDateDay: Locator
|
||||
readonly inputPopupDateMonth: Locator
|
||||
readonly inputPopupDateYear: Locator
|
||||
readonly inputPopupTime: Locator
|
||||
readonly inputPopupDateSave: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
super()
|
||||
this.page = page
|
||||
this.buttonDatePopupToday = page.locator('div.popup div.today:not(.wrongMonth)')
|
||||
this.inputPopupDateDay = page.locator('div[class*="date-popup"] div.datetime-input span.digit:first-child')
|
||||
this.inputPopupDateMonth = page.locator('div[class*="date-popup"] div.datetime-input span.digit:nth-child(3)')
|
||||
this.inputPopupDateYear = page.locator('div[class*="date-popup"] div.datetime-input span.digit:nth-child(5)')
|
||||
this.inputPopupTime = page.locator('div[class*="date-popup"] div.datetime-input span.digit:nth-child(7)')
|
||||
this.inputPopupDateSave = page.locator('div[class*="date-popup"] div.footer button')
|
||||
}
|
||||
|
||||
async fillSelectDatePopup (day: string, month: string, year: string, time: string): Promise<void> {
|
||||
await this.inputPopupDateDay.click()
|
||||
await this.inputPopupDateDay.pressSequentially(day)
|
||||
await this.inputPopupDateMonth.click()
|
||||
await this.inputPopupDateMonth.pressSequentially(month)
|
||||
await this.inputPopupDateYear.click()
|
||||
await this.inputPopupDateYear.pressSequentially(year)
|
||||
|
||||
await this.inputPopupTime.click()
|
||||
await this.inputPopupTime.pressSequentially(time)
|
||||
|
||||
await this.inputPopupDateSave.click()
|
||||
}
|
||||
|
||||
async fillSelectDateByShortcut (shortcut: string): Promise<void> {
|
||||
await this.page.locator('div.shift-container div.btn > span', { hasText: shortcut }).click()
|
||||
}
|
||||
}
|
45
qms-tests/sanity/tests/model/common-page.ts
Normal file
45
qms-tests/sanity/tests/model/common-page.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { expect, Page } from '@playwright/test'
|
||||
|
||||
export class CommonPage {
|
||||
async selectListItemWithSearch (page: Page, name: string, fullWordSearch: boolean = false): Promise<void> {
|
||||
if (name !== 'first') {
|
||||
const searchWord = fullWordSearch ? name : name.split(' ')[0]
|
||||
await page.locator('div.selectPopup input').fill(searchWord)
|
||||
}
|
||||
await page.locator('div.selectPopup div.list-item:first-child').click({ delay: 100 })
|
||||
}
|
||||
|
||||
async selectListItem (page: Page, name: string): Promise<void> {
|
||||
await page.locator('div.selectPopup div.list-item', { hasText: name }).click({ delay: 100 })
|
||||
}
|
||||
|
||||
async pressCreateButtonSelectPopup (page: Page): Promise<void> {
|
||||
await page.locator('div.selectPopup div.header button:last-child').click()
|
||||
}
|
||||
|
||||
async addNewTagPopup (page: Page, title: string, description: string): Promise<void> {
|
||||
await page.locator('div.popup form[id="tags:string:AddTag"] input[placeholder$="title"]').fill(title)
|
||||
await page
|
||||
.locator('div.popup form[id="tags:string:AddTag"] input[placeholder="Please type description here"]')
|
||||
.fill(description)
|
||||
await page.locator('div.popup form[id="tags:string:AddTag"] button[type="submit"]').click()
|
||||
}
|
||||
|
||||
async selectMenuItem (page: Page, point: string): Promise<void> {
|
||||
await page.locator('div.selectPopup button.menu-item', { hasText: point }).click()
|
||||
}
|
||||
|
||||
async pressYesDeletePopup (page: Page): Promise<void> {
|
||||
await page.locator('div.popup button.dangerous').click()
|
||||
await expect(page.locator('div.popup button.dangerous')).toBeHidden()
|
||||
}
|
||||
|
||||
async selectFromDropdown (page: Page, point: string): Promise<void> {
|
||||
await page.locator('div[class$="opup"] span[class*="label"]', { hasText: point }).click()
|
||||
}
|
||||
|
||||
async pressYesForPopup (page: Page): Promise<void> {
|
||||
await expect(page.locator('div.popup button[type="submit"]')).toBeVisible()
|
||||
await page.locator('div.popup button[type="submit"]').click()
|
||||
}
|
||||
}
|
23
qms-tests/sanity/tests/model/documents/categories-page.ts
Normal file
23
qms-tests/sanity/tests/model/documents/categories-page.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { type Locator, type Page, expect } from '@playwright/test'
|
||||
import { CalendarPage } from '../calendar-page'
|
||||
|
||||
export class CategoriesPage extends CalendarPage {
|
||||
readonly page: Page
|
||||
readonly buttonCreateCategory: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
super(page)
|
||||
this.page = page
|
||||
this.buttonCreateCategory = page.locator('div[slot="header-tools"] button[type="submit"]', { hasText: 'Category' })
|
||||
}
|
||||
|
||||
async openCategory (categoryTitle: string): Promise<void> {
|
||||
await this.page.locator(`//span[text()='${categoryTitle}']/../../..//div[contains(@class, "firstCell")]/a`).click()
|
||||
}
|
||||
|
||||
async checkCategoryNotExist (categoryTitle: string): Promise<void> {
|
||||
await expect(
|
||||
this.page.locator(`//span[text()='${categoryTitle}']/../../..//div[contains(@class, "firstCell")]/a`)
|
||||
).toBeVisible({ visible: false })
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
import { type Locator, type Page, expect } from '@playwright/test'
|
||||
import { CalendarPage } from '../calendar-page'
|
||||
import { NewCategory } from '../types'
|
||||
import path from 'path'
|
||||
|
||||
export class CategoryCreatePopup extends CalendarPage {
|
||||
readonly page: Page
|
||||
readonly inputNewCategoryTitle: Locator
|
||||
readonly inputNewCategoryDescription: Locator
|
||||
readonly inputNewCategoryCode: Locator
|
||||
readonly inputAttachFile: Locator
|
||||
readonly buttonNewCategoryCreate: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
super(page)
|
||||
this.page = page
|
||||
this.inputNewCategoryTitle = page.locator('input[placeholder="Title"]')
|
||||
this.inputNewCategoryCode = page.locator('input[placeholder="Code"]')
|
||||
this.inputNewCategoryDescription = page.locator('div.inputMsg div.tiptap')
|
||||
this.inputAttachFile = page.locator('form[id="documents:string:CreateDocumentCategory"] input[type="file"]#file')
|
||||
this.buttonNewCategoryCreate = page.locator(
|
||||
'form[id="documents:string:CreateDocumentCategory"] button[type="submit"]'
|
||||
)
|
||||
}
|
||||
|
||||
async createCategory (data: NewCategory): Promise<void> {
|
||||
await this.inputNewCategoryTitle.fill(data.title)
|
||||
await this.inputNewCategoryCode.fill(data.code)
|
||||
await this.inputNewCategoryDescription.fill(data.description)
|
||||
|
||||
if (data.attachFileName != null) {
|
||||
await this.inputAttachFile.setInputFiles(path.join(__dirname, `../../files/${data.attachFileName}`))
|
||||
await expect(
|
||||
this.page.locator('div[class*="attachments"] div.name', { hasText: data.attachFileName })
|
||||
).toBeVisible()
|
||||
}
|
||||
|
||||
await this.buttonNewCategoryCreate.click()
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
import { type Locator, type Page, expect } from '@playwright/test'
|
||||
import { CalendarPage } from '../calendar-page'
|
||||
import { NewCategory, UpdateCategory } from '../types'
|
||||
import path from 'path'
|
||||
|
||||
export class CategoryDetailsPage extends CalendarPage {
|
||||
readonly page: Page
|
||||
readonly inputCategoryTitle: Locator
|
||||
readonly inputCategoryCode: Locator
|
||||
readonly textDescription: Locator
|
||||
readonly inputAttachFile: Locator
|
||||
readonly textAttachFile: Locator
|
||||
readonly buttonMoreActions: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
super(page)
|
||||
this.page = page
|
||||
this.inputCategoryTitle = page.locator('input[placeholder="documents:string:DomainTitle"]')
|
||||
this.inputCategoryCode = page.locator('input[placeholder="Category"]')
|
||||
this.textDescription = page.locator('div.grid div.tiptap')
|
||||
this.inputAttachFile = page.locator('div.grid input#file')
|
||||
this.buttonMoreActions = page.locator('div[class*="title"] > div:last-child > button:first-child')
|
||||
this.textAttachFile = page.locator('div.attachment-grid-container div[class*="attachment"] div.name')
|
||||
}
|
||||
|
||||
async checkTitle (categoryTitle: string): Promise<void> {
|
||||
await expect(this.inputCategoryTitle).toHaveValue(categoryTitle)
|
||||
}
|
||||
|
||||
async editCategory (data: UpdateCategory): Promise<void> {
|
||||
await this.textDescription.fill(data.description)
|
||||
|
||||
if (data.attachFileName != null) {
|
||||
await this.inputAttachFile.setInputFiles(path.join(__dirname, `../../files/${data.attachFileName}`))
|
||||
await expect(this.textAttachFile.filter({ hasText: data.attachFileName })).toBeVisible()
|
||||
}
|
||||
}
|
||||
|
||||
async checkCategory (data: NewCategory): Promise<void> {
|
||||
await expect(this.inputCategoryTitle).toHaveValue(data.title)
|
||||
await expect(this.inputCategoryCode).toHaveValue(data.code)
|
||||
await expect(this.textDescription).toContainText(data.description)
|
||||
|
||||
if (data.attachFileName != null) {
|
||||
await expect(this.textAttachFile.filter({ hasText: data.attachFileName })).toBeVisible()
|
||||
}
|
||||
}
|
||||
|
||||
async executeMoreAction (action: string): Promise<void> {
|
||||
await this.buttonMoreActions.click()
|
||||
await this.selectFromDropdown(this.page, action)
|
||||
await this.pressYesDeletePopup(this.page)
|
||||
}
|
||||
|
||||
async checkMoreActionNotExist (action: string): Promise<void> {
|
||||
await this.buttonMoreActions.click()
|
||||
await expect(this.page.locator('div.popup button.ap-menuItem', { hasText: action })).toBeVisible({ visible: false })
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import { type Page, expect } from '@playwright/test'
|
||||
import { DocumentCommonPage } from './document-common-page'
|
||||
|
||||
export class DocumentApprovalsPage extends DocumentCommonPage {
|
||||
readonly page: Page
|
||||
|
||||
constructor (page: Page) {
|
||||
super(page)
|
||||
this.page = page
|
||||
}
|
||||
|
||||
async checkRejectApproval (approvalName: string, message: string): Promise<void> {
|
||||
await expect(
|
||||
this.page
|
||||
.locator('div.reject-message', { hasText: message })
|
||||
.locator('xpath=..')
|
||||
.locator('div.approver span.ap-label')
|
||||
).toHaveText(approvalName)
|
||||
}
|
||||
|
||||
async checkSuccessApproval (approvalName: string): Promise<void> {
|
||||
await expect(this.page.locator('svg[fill*="accepted"]').locator('xpath=..').locator('span.ap-label')).toHaveText(
|
||||
approvalName
|
||||
)
|
||||
}
|
||||
}
|
133
qms-tests/sanity/tests/model/documents/document-comments-page.ts
Normal file
133
qms-tests/sanity/tests/model/documents/document-comments-page.ts
Normal file
@ -0,0 +1,133 @@
|
||||
import { type Locator, type Page, expect } from '@playwright/test'
|
||||
import { DocumentCommonPage } from './document-common-page'
|
||||
|
||||
export class DocumentCommentsPage extends DocumentCommonPage {
|
||||
readonly page: Page
|
||||
readonly buttonDocumentTitle: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
super(page)
|
||||
this.page = page
|
||||
this.buttonDocumentTitle = page.locator('button.version-item span.name')
|
||||
}
|
||||
|
||||
async checkCommentExist (message: string, count: number = 1): Promise<void> {
|
||||
await expect(this.page.locator('div[data-float="aside"] div.root span', { hasText: message })).toHaveCount(count)
|
||||
}
|
||||
|
||||
async resolveComments (message: string, position: string = '1'): Promise<void> {
|
||||
await this.page
|
||||
.locator('div[data-float="aside"] div.root span', { hasText: message })
|
||||
.locator('xpath=..')
|
||||
.locator('span:first-child', { hasText: position })
|
||||
.hover()
|
||||
|
||||
await this.page
|
||||
.locator('div[data-float="aside"] div.root span', { hasText: message })
|
||||
.locator('xpath=..')
|
||||
.locator('span:first-child', { hasText: position })
|
||||
.locator('xpath=../..')
|
||||
.locator('div.tools button')
|
||||
.click()
|
||||
}
|
||||
|
||||
async resolveAllComments (): Promise<void> {
|
||||
const buttonsCount: number = await this.page.locator('div[data-float="aside"] div.root div.tools button').count()
|
||||
for (let i = 0; i < buttonsCount; i++) {
|
||||
await this.page.locator('div[data-float="aside"] div.root').first().click()
|
||||
await this.page.locator('div[data-float="aside"] div.root div.tools button').first().click()
|
||||
}
|
||||
}
|
||||
|
||||
async checkCommentNotExist (message: string): Promise<void> {
|
||||
await expect(this.page.locator('div[data-float="aside"] div.root span', { hasText: message })).toHaveCount(0)
|
||||
}
|
||||
|
||||
async checkCommentCanBeResolved (message: string, position: number): Promise<void> {
|
||||
await this.page
|
||||
.locator('div[data-float="aside"] div.root span', { hasText: message })
|
||||
.locator('xpath=..')
|
||||
.locator('span:first-child', { hasText: String(position) })
|
||||
.hover()
|
||||
|
||||
await expect(
|
||||
this.page
|
||||
.locator('div[data-float="aside"] div.root span', { hasText: message })
|
||||
.locator('xpath=..')
|
||||
.locator('span:first-child', { hasText: String(position) })
|
||||
.locator('xpath=../..')
|
||||
.locator('div.tools button')
|
||||
).toBeEnabled()
|
||||
}
|
||||
|
||||
async checkCommentCanNotBeResolved (message: string, position: number): Promise<void> {
|
||||
await this.page
|
||||
.locator('div[data-float="aside"] div.root span', { hasText: message })
|
||||
.locator('xpath=..')
|
||||
.locator('span:first-child', { hasText: String(position) })
|
||||
.hover()
|
||||
|
||||
await expect(
|
||||
this.page
|
||||
.locator('div[data-float="aside"] div.root span', { hasText: message })
|
||||
.locator('xpath=..')
|
||||
.locator('span:first-child', { hasText: String(position) })
|
||||
.locator('xpath=../..')
|
||||
.locator('div.tools button')
|
||||
).not.toBeVisible()
|
||||
}
|
||||
|
||||
async addReplyInPopupByCommentId (commentId: number, replyText: string): Promise<void> {
|
||||
const comment = this.page
|
||||
.locator('div.popup div.root div.header span:first-child', { hasText: String(commentId) })
|
||||
.locator('xpath=../../../..')
|
||||
await comment.locator('div.ref-input div.tiptap').fill(replyText)
|
||||
await comment.locator('div.ref-input div.buttons-panel > button').click()
|
||||
}
|
||||
|
||||
async checkCommentInPopupById (
|
||||
commentId: number,
|
||||
header: string,
|
||||
author: string,
|
||||
message: string,
|
||||
reply: string
|
||||
): Promise<void> {
|
||||
const comment = this.page
|
||||
.locator('div.popup div.root div.header > div > span:first-child', { hasText: String(commentId) })
|
||||
.locator('xpath=../../../..')
|
||||
// check header
|
||||
await expect(comment.locator('div.header > div > span:last-child')).toHaveText(header)
|
||||
// can be resolved
|
||||
await comment.locator('div.header div.tools button').hover()
|
||||
await expect(comment.locator('div.header div.tools button')).toBeEnabled()
|
||||
// check author
|
||||
await expect(comment.locator('div.root div.header > a span[class*="label"]').first()).toHaveText(author)
|
||||
// check message
|
||||
await expect(comment.locator('div.activityMessage div.flex-col div.clear-mins > p').first()).toHaveText(message)
|
||||
// check comment
|
||||
await expect(comment.locator('div.activityMessage div.flex-col div.clear-mins > p').last()).toHaveText(reply)
|
||||
}
|
||||
|
||||
async checkCommentInPanelById (
|
||||
commentId: number,
|
||||
header: string,
|
||||
author: string,
|
||||
message: string,
|
||||
reply: string
|
||||
): Promise<void> {
|
||||
const comment = this.page
|
||||
.locator('div.box div.root div.header > div > span:first-child', { hasText: String(commentId) })
|
||||
.locator('xpath=../../../..')
|
||||
// check header
|
||||
await expect(comment.locator('div.header > div > span:last-child')).toHaveText(header)
|
||||
// can be resolved
|
||||
await comment.locator('div.header > div > span:last-child').hover()
|
||||
await expect(comment.locator('div.header div.tools button')).toBeEnabled()
|
||||
// check author
|
||||
await expect(comment.locator('div.root div.header > a span[class*="label"]').first()).toHaveText(author)
|
||||
// check message
|
||||
await expect(comment.locator('div.activityMessage div.flex-col div.clear-mins > p').first()).toHaveText(message)
|
||||
// check comment
|
||||
await expect(comment.locator('div.activityMessage div.flex-col div.clear-mins > p').last()).toHaveText(reply)
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
import { type Locator, type Page } from '@playwright/test'
|
||||
import { CalendarPage } from '../calendar-page'
|
||||
|
||||
export class DocumentCommonPage extends CalendarPage {
|
||||
readonly page: Page
|
||||
readonly inputMessageText: Locator
|
||||
readonly buttonMessageSend: Locator
|
||||
readonly buttonReleaseTab: Locator
|
||||
readonly buttonContentTab: Locator
|
||||
readonly buttonReasonAndImpactTab: Locator
|
||||
readonly buttonHistoryTab: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
super(page)
|
||||
this.page = page
|
||||
this.inputMessageText = page.locator('div.popup div.tiptap')
|
||||
this.buttonMessageSend = page.locator('div.popup button.primary')
|
||||
this.buttonReleaseTab = page.locator('div.tab', { hasText: 'Release' })
|
||||
this.buttonContentTab = page.locator('div.tab', { hasText: 'Content' })
|
||||
this.buttonReasonAndImpactTab = page.locator('div.tab', { hasText: 'Reason & Impact' })
|
||||
this.buttonHistoryTab = page.locator('div.tab', { hasText: 'History' })
|
||||
}
|
||||
|
||||
async addMessage (message: string): Promise<void> {
|
||||
await this.inputMessageText.fill(message)
|
||||
await this.buttonMessageSend.click()
|
||||
}
|
||||
}
|
306
qms-tests/sanity/tests/model/documents/document-content-page.ts
Normal file
306
qms-tests/sanity/tests/model/documents/document-content-page.ts
Normal file
@ -0,0 +1,306 @@
|
||||
import { expect, type Locator, type Page } from '@playwright/test'
|
||||
import { Content, DocumentDetails, DocumentRights, DocumentStatus } from '../types'
|
||||
import { DocumentCommonPage } from './document-common-page'
|
||||
import { iterateLocator, PlatformPassword } from '../../utils'
|
||||
|
||||
export class DocumentContentPage extends DocumentCommonPage {
|
||||
readonly page: Page
|
||||
readonly buttonDocumentTitle: Locator
|
||||
readonly buttonMoreActions: Locator
|
||||
readonly textDocumentStatus: Locator
|
||||
readonly textType: Locator
|
||||
readonly textCategory: Locator
|
||||
readonly textVersion: Locator
|
||||
readonly textStatus: Locator
|
||||
readonly textOwner: Locator
|
||||
readonly textAuthor: Locator
|
||||
readonly buttonSelectNewOwner: Locator
|
||||
readonly buttonSelectNewOwnerChange: Locator
|
||||
readonly buttonSendForReview: Locator
|
||||
readonly buttonSendForApproval: Locator
|
||||
readonly buttonAddMembers: Locator
|
||||
readonly buttonSelectMemberSubmit: Locator
|
||||
readonly textSelectReviewersPopup: Locator
|
||||
readonly textSelectApproversPopup: Locator
|
||||
readonly buttonCurrentRights: Locator
|
||||
readonly buttonAddMessageToText: Locator
|
||||
readonly buttonComments: Locator
|
||||
readonly textDocumentTitle: Locator
|
||||
readonly buttonCompleteReview: Locator
|
||||
readonly inputPassword: Locator
|
||||
readonly buttonSubmit: Locator
|
||||
readonly buttonReject: Locator
|
||||
readonly inputRejectionReason: Locator
|
||||
readonly buttonApprove: Locator
|
||||
readonly buttonEditDocument: Locator
|
||||
readonly buttonDraftNewVersion: Locator
|
||||
readonly buttonDocumentInformation: Locator
|
||||
readonly buttonDocument: Locator
|
||||
readonly buttonDocumentApprovals: Locator
|
||||
readonly textPageHeader: Locator
|
||||
readonly buttonSelectNewOwnerChangeByQaraManager: Locator
|
||||
readonly textId: Locator
|
||||
readonly sectionsLocatorViewRight: Locator
|
||||
readonly sectionsLocatorEditRight: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
super(page)
|
||||
this.page = page
|
||||
this.buttonDocumentTitle = page.locator('button.version-item span.name')
|
||||
this.buttonMoreActions = page.locator('div.popupPanel-title > [class="no-print"] > button:not([id])')
|
||||
this.textDocumentStatus = page.locator('button.version-item div.root span.label')
|
||||
this.textType = page.locator('div.flex:has(div.label:text("Template name")) div.field')
|
||||
this.textCategory = page.locator('div.flex:has(div.label:text("Category")) div.field')
|
||||
this.textVersion = page.locator('div.flex:has(div.label:text("Version")) div.field')
|
||||
this.textStatus = page.locator('div.flex:has(div.label:text("Status")) div.field')
|
||||
this.textOwner = page.locator('div.flex:has(div.label:text("Owner")) div.field')
|
||||
this.textAuthor = page.locator('div.flex:has(div.label:text("Author")) div.field')
|
||||
this.buttonSelectNewOwner = page.locator('div.popup button.small')
|
||||
this.buttonSelectNewOwnerChange = page.locator('div.popup button.dangerous')
|
||||
this.buttonSendForReview = page.locator('div.popupPanel-title button[type="button"] > span', {
|
||||
hasText: 'Send for review'
|
||||
})
|
||||
this.buttonSendForApproval = page.locator('div.popupPanel-title button[type="button"] > span', {
|
||||
hasText: 'Send for approval'
|
||||
})
|
||||
this.buttonAddMembers = page.locator('div.popup div.addButton')
|
||||
this.buttonSelectMemberSubmit = page.locator('div.popup div.footer button[type="submit"]')
|
||||
this.textSelectReviewersPopup = page.locator('div.popup span.label', { hasText: 'Select reviewers' })
|
||||
this.textSelectApproversPopup = page.locator('div.popup span.label', { hasText: 'Select approvers' })
|
||||
this.buttonCurrentRights = page.locator('div.popupPanel-title button[type="button"] > span[slot="content"]')
|
||||
this.buttonAddMessageToText = page.locator('div.text-editor-toolbar > button:last-child')
|
||||
this.buttonComments = page.locator('button[id$="comment"]')
|
||||
this.textDocumentTitle = page.locator('div.panel div.title')
|
||||
this.buttonCompleteReview = page.locator('div.popupPanel-title button[type="button"] > span', {
|
||||
hasText: 'Complete review'
|
||||
})
|
||||
this.inputPassword = page.locator('input[name="documents:string:Password"]')
|
||||
this.buttonSubmit = page.locator('div.popup button[type="submit"]')
|
||||
this.buttonReject = page.locator('button[type="button"] > span', { hasText: 'Reject' })
|
||||
this.inputRejectionReason = page.locator('div.popup div[id="rejection-reason"] input')
|
||||
this.buttonApprove = page.locator('button[type="button"] > span', { hasText: 'Approve' })
|
||||
this.buttonDocument = page.locator('button[id$="info"]')
|
||||
this.buttonEditDocument = page.locator('div.popupPanel-title button[type="button"] > span', {
|
||||
hasText: 'Edit document'
|
||||
})
|
||||
this.buttonDraftNewVersion = page.locator('div.popupPanel-title button[type="button"] > span', {
|
||||
hasText: 'Draft new version'
|
||||
})
|
||||
this.buttonDocumentInformation = page.locator('button[id$="info"]')
|
||||
this.buttonDocumentApprovals = page.locator('button[id$="approvals"]')
|
||||
this.textPageHeader = page.locator('div.hulyNavPanel-header')
|
||||
this.buttonSelectNewOwnerChangeByQaraManager = page.locator('div.popup button[type="submit"]')
|
||||
this.textId = page.locator('div.flex:has(div.label:text("ID")) div.field')
|
||||
this.sectionsLocatorViewRight = page.locator('div.section span.label')
|
||||
this.sectionsLocatorEditRight = page.locator('div.section span.label input')
|
||||
}
|
||||
|
||||
async checkDocumentTitle (title: string): Promise<void> {
|
||||
await expect(this.buttonDocumentTitle).toContainText(title)
|
||||
}
|
||||
|
||||
async updateSectionTitle (sectionId: string, title: string): Promise<void> {
|
||||
await this.page
|
||||
.locator('span.hdr-alignment:not([class*="label"])', { hasText: sectionId })
|
||||
.locator('xpath=..')
|
||||
.locator('span.label input')
|
||||
.fill(title)
|
||||
}
|
||||
|
||||
async addContentToTheSection (content: Content): Promise<void> {
|
||||
const section = await this.getSectionLocator(content.sectionTitle)
|
||||
await section
|
||||
.locator('xpath=../../../../../../../..')
|
||||
.locator('div.content-container div.tiptap')
|
||||
.clear({ force: true })
|
||||
|
||||
await section
|
||||
.locator('xpath=../../../../../../../..')
|
||||
.locator('div.content-container div.tiptap')
|
||||
.fill(content.content)
|
||||
}
|
||||
|
||||
async checkContentForTheSection (content: Content): Promise<void> {
|
||||
const section = await this.getSectionLocator(content.sectionTitle)
|
||||
const parentLocator =
|
||||
(await this.buttonCurrentRights.textContent()) === DocumentRights.EDITING
|
||||
? '../../../../../../../..'
|
||||
: '../../../..'
|
||||
|
||||
await expect(section.locator(`xpath=${parentLocator}`).locator('div.content-container div.tiptap')).toHaveText(
|
||||
content.content
|
||||
)
|
||||
}
|
||||
|
||||
async executeMoreActions (action: string): Promise<void> {
|
||||
await this.buttonMoreActions.click()
|
||||
await this.selectFromDropdown(this.page, action)
|
||||
}
|
||||
|
||||
async checkDocumentStatus (status: DocumentStatus): Promise<void> {
|
||||
await expect(this.textDocumentStatus).toHaveText(status)
|
||||
}
|
||||
|
||||
async checkDocument (data: DocumentDetails): Promise<void> {
|
||||
if (data.type != null && data.type !== 'N/A') {
|
||||
await expect(this.textType).toHaveText(data.type)
|
||||
}
|
||||
if (data.category != null) {
|
||||
await expect(this.textCategory).toContainText(data.category)
|
||||
}
|
||||
if (data.version != null) {
|
||||
await expect(this.textVersion).toHaveText(data.version)
|
||||
}
|
||||
if (data.status != null) {
|
||||
await expect(this.textStatus).toHaveText(data.status)
|
||||
}
|
||||
if (data.owner != null) {
|
||||
await expect(this.textOwner).toHaveText(data.owner)
|
||||
}
|
||||
if (data.author != null) {
|
||||
await expect(this.textAuthor).toHaveText(data.author)
|
||||
}
|
||||
if (data.id != null) {
|
||||
await expect(this.textId).toHaveText(data.id)
|
||||
}
|
||||
}
|
||||
|
||||
async fillChangeDocumentOwnerPopup (newOwner: string): Promise<void> {
|
||||
await this.buttonSelectNewOwner.click()
|
||||
await this.selectListItemWithSearch(this.page, newOwner)
|
||||
await this.buttonSelectNewOwnerChange.click()
|
||||
}
|
||||
|
||||
async fillSelectReviewersForm (reviewers: Array<string>): Promise<void> {
|
||||
await this.buttonAddMembers.click()
|
||||
for (const reviewer of reviewers) {
|
||||
await this.selectListItemWithSearch(this.page, reviewer)
|
||||
}
|
||||
await this.textSelectReviewersPopup.click({ force: true })
|
||||
await this.buttonSelectMemberSubmit.click()
|
||||
}
|
||||
|
||||
async fillSelectApproversForm (approvers: Array<string>): Promise<void> {
|
||||
await this.buttonAddMembers.click()
|
||||
for (const approver of approvers) {
|
||||
await this.selectListItemWithSearch(this.page, approver)
|
||||
}
|
||||
await this.textSelectApproversPopup.click({ force: true })
|
||||
await this.buttonSelectMemberSubmit.click()
|
||||
}
|
||||
|
||||
async checkCurrentRights (right: DocumentRights): Promise<void> {
|
||||
await expect(this.buttonCurrentRights).toHaveText(right)
|
||||
}
|
||||
|
||||
async addMessageToTheText (text: string, message: string, closePopup: boolean = true): Promise<void> {
|
||||
await this.page.getByText(text).click()
|
||||
await this.page.getByText(text).dblclick()
|
||||
|
||||
await this.buttonAddMessageToText.click()
|
||||
await this.addMessage(message)
|
||||
|
||||
if (closePopup) {
|
||||
await this.closeNewMessagePopup()
|
||||
}
|
||||
}
|
||||
|
||||
async addMessageToTheSectionTitle (title: string, message: string, closePopup: boolean = true): Promise<void> {
|
||||
const locator = await this.getSectionLocator(title)
|
||||
const parentLocator =
|
||||
(await this.buttonCurrentRights.textContent()) === DocumentRights.EDITING ? '../../../../..' : '../..'
|
||||
|
||||
await locator.locator(`xpath=${parentLocator}`).hover()
|
||||
await locator.locator(`xpath=${parentLocator}`).locator('div.tools button[type="button"]').click()
|
||||
await this.addMessage(message)
|
||||
|
||||
if (closePopup) {
|
||||
await this.closeNewMessagePopup()
|
||||
}
|
||||
}
|
||||
|
||||
async closeNewMessagePopup (): Promise<void> {
|
||||
await this.textPageHeader.press('Escape', { delay: 300 })
|
||||
await this.textPageHeader.click({ force: true, delay: 300, position: { x: 1, y: 1 } })
|
||||
}
|
||||
|
||||
async completeReview (): Promise<void> {
|
||||
await this.buttonCompleteReview.click()
|
||||
await this.inputPassword.fill(PlatformPassword)
|
||||
await this.buttonSubmit.click()
|
||||
}
|
||||
|
||||
async confirmRejection (rejectionReason: string): Promise<void> {
|
||||
await this.buttonReject.click()
|
||||
await this.inputPassword.fill(PlatformPassword)
|
||||
await this.inputRejectionReason.fill(rejectionReason)
|
||||
await this.buttonSubmit.click()
|
||||
}
|
||||
|
||||
async confirmApproval (): Promise<void> {
|
||||
await this.buttonApprove.click()
|
||||
await this.inputPassword.fill(PlatformPassword)
|
||||
await this.buttonSubmit.click()
|
||||
}
|
||||
|
||||
async addNewSection (startSectionId: string, direction: 'above' | 'below'): Promise<void> {
|
||||
await this.page.locator('span.hdr-alignment:not([class*="label"])', { hasText: startSectionId }).hover()
|
||||
|
||||
await this.page
|
||||
.locator('span.hdr-alignment:not([class*="label"])', { hasText: startSectionId })
|
||||
.locator('xpath=../../..')
|
||||
.locator('div.tools[draggable="true"]')
|
||||
.click()
|
||||
|
||||
await this.selectFromDropdown(this.page, `Add new section ${direction}`)
|
||||
}
|
||||
|
||||
async changeCurrentRight (newRight: DocumentRights): Promise<void> {
|
||||
await this.buttonCurrentRights.click()
|
||||
await this.selectMenuItem(this.page, newRight)
|
||||
}
|
||||
|
||||
async checkComparingTextAdded (text: string): Promise<void> {
|
||||
await expect(this.page.locator('span.text-editor-highlighted-node-add', { hasText: text }).first()).toBeVisible()
|
||||
}
|
||||
|
||||
async checkComparingTextDeleted (text: string): Promise<void> {
|
||||
await expect(this.page.locator('span.text-editor-highlighted-node-delete', { hasText: text }).first()).toBeVisible()
|
||||
}
|
||||
|
||||
async openApprovals (): Promise<void> {
|
||||
await expect(this.buttonDocumentApprovals).toBeVisible()
|
||||
await this.buttonDocumentApprovals.click({ position: { x: 1, y: 1 }, force: true })
|
||||
}
|
||||
|
||||
async fillChangeDocumentOwnerPopupByQaraManager (newOwner: string): Promise<void> {
|
||||
await this.buttonSelectNewOwner.click()
|
||||
await this.selectListItemWithSearch(this.page, newOwner)
|
||||
await this.buttonSelectNewOwnerChangeByQaraManager.click()
|
||||
}
|
||||
|
||||
private async getSectionLocator (title: string): Promise<Locator> {
|
||||
let result: Locator | null = null
|
||||
const sectionsLocator = iterateLocator(
|
||||
(await this.buttonCurrentRights.textContent()) === DocumentRights.EDITING
|
||||
? this.sectionsLocatorEditRight
|
||||
: this.sectionsLocatorViewRight
|
||||
)
|
||||
for await (const locator of sectionsLocator) {
|
||||
const value =
|
||||
(await this.buttonCurrentRights.textContent()) === DocumentRights.EDITING
|
||||
? await locator.inputValue()
|
||||
: ((await locator.textContent()) ?? '').trim()
|
||||
if (value === title) {
|
||||
result = locator
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
throw new Error('Section not found')
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import { expect, type Page } from '@playwright/test'
|
||||
import { DocumentCommonPage } from './document-common-page'
|
||||
|
||||
export class DocumentHistoryPage extends DocumentCommonPage {
|
||||
readonly page: Page
|
||||
|
||||
constructor (page: Page) {
|
||||
super(page)
|
||||
this.page = page
|
||||
}
|
||||
|
||||
async checkHistoryEventExist (eventDescription: string): Promise<void> {
|
||||
await expect(this.page.locator('div.root div.description', { hasText: eventDescription })).toBeVisible()
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
import { expect, type Locator, type Page } from '@playwright/test'
|
||||
import { DocumentCommonPage } from './document-common-page'
|
||||
|
||||
export class DocumentReasonAndImpactPage extends DocumentCommonPage {
|
||||
readonly page: Page
|
||||
readonly buttonReasonAndImpactTabSelected: Locator
|
||||
readonly textAreaDescription: Locator
|
||||
readonly textAreaReason: Locator
|
||||
readonly textAreaImpactAnalysis: Locator
|
||||
readonly buttonImpactedDocuments: Locator
|
||||
readonly textDescription: Locator
|
||||
readonly textReason: Locator
|
||||
readonly textImpactAnalysis: Locator
|
||||
readonly textImpactedDocuments: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
super(page)
|
||||
this.page = page
|
||||
this.buttonReasonAndImpactTabSelected = page.locator('div.tab.selected', { hasText: 'Reason & Impact' })
|
||||
this.textAreaDescription = page.locator('div.box textarea.root').first()
|
||||
this.textAreaReason = page.locator('div.box textarea.root').nth(1)
|
||||
this.textAreaImpactAnalysis = page.locator('div.box textarea.root').last()
|
||||
this.buttonImpactedDocuments = page.locator('div.addButton')
|
||||
this.textDescription = page.locator('//div[contains(@class, "title") and text()="Description"]/..')
|
||||
this.textReason = page.locator('//div[contains(@class, "title") and text()="Reason"]/..')
|
||||
this.textImpactAnalysis = page.locator('//div[contains(@class, "title") and text()="Impact analysis"]/..')
|
||||
this.textImpactedDocuments = page.locator(
|
||||
'//div[contains(@class, "title") and text()="Impacted documents"]/..//a/span'
|
||||
)
|
||||
}
|
||||
|
||||
async setReasonAndImpactData (
|
||||
description: string,
|
||||
reason: string,
|
||||
analysis: string,
|
||||
documentName: string
|
||||
): Promise<void> {
|
||||
await this.textAreaDescription.clear()
|
||||
await this.textAreaDescription.fill(description)
|
||||
|
||||
await this.textAreaReason.clear()
|
||||
await this.textAreaReason.fill(reason)
|
||||
|
||||
await this.textAreaImpactAnalysis.focus()
|
||||
await this.textAreaImpactAnalysis.press('Meta+A')
|
||||
await this.textAreaImpactAnalysis.press('Backspace')
|
||||
await this.textAreaImpactAnalysis.fill(analysis)
|
||||
|
||||
await this.buttonImpactedDocuments.click()
|
||||
await this.selectListItem(this.page, documentName)
|
||||
|
||||
await this.buttonReasonAndImpactTabSelected.click({ force: true })
|
||||
}
|
||||
|
||||
async checkReasonAndImpactData (
|
||||
description: string,
|
||||
reason: string,
|
||||
analysis: string,
|
||||
documentName: string
|
||||
): Promise<void> {
|
||||
await expect(this.textDescription).toContainText(description)
|
||||
await expect(this.textReason).toContainText(reason)
|
||||
await expect(this.textImpactAnalysis).toContainText(analysis)
|
||||
await expect(this.textImpactedDocuments).toHaveText(documentName)
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
import { type Locator, type Page } from '@playwright/test'
|
||||
import { DocumentCommonPage } from './document-common-page'
|
||||
|
||||
export class DocumentReleasePage extends DocumentCommonPage {
|
||||
readonly page: Page
|
||||
readonly buttonReleaseTabSelected: Locator
|
||||
readonly buttonMakeEffectiveOn: Locator
|
||||
readonly buttonDateTimeButton: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
super(page)
|
||||
this.page = page
|
||||
this.buttonReleaseTabSelected = page.locator('div.tab.selected', { hasText: 'Release' })
|
||||
this.buttonMakeEffectiveOn = page.locator('label[for="documents:string:EffectiveOn"]')
|
||||
this.buttonDateTimeButton = page.locator('label[for="documents:string:EffectiveOn"] button.datetime-button')
|
||||
}
|
||||
|
||||
async setEffectiveDate (delayTime: string): Promise<void> {
|
||||
await this.buttonDateTimeButton.click()
|
||||
await this.fillSelectDateByShortcut(delayTime)
|
||||
}
|
||||
}
|
70
qms-tests/sanity/tests/model/documents/documents-page.ts
Normal file
70
qms-tests/sanity/tests/model/documents/documents-page.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { type Locator, type Page } from '@playwright/test'
|
||||
import { CalendarPage } from '../calendar-page'
|
||||
import { NewDocument } from '../types'
|
||||
export class DocumentsPage extends CalendarPage {
|
||||
readonly page: Page
|
||||
readonly buttonCreateDocument: Locator
|
||||
readonly buttonPopupNextStep: Locator
|
||||
readonly buttonSpaceSelector: Locator
|
||||
readonly buttonParentSelector: Locator
|
||||
readonly inputNewDocumentTitle: Locator
|
||||
readonly inputNewDocumentDescription: Locator
|
||||
readonly inputNewDocumentCreateDaft: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
super(page)
|
||||
this.page = page
|
||||
this.buttonCreateDocument = page.locator(
|
||||
'div[data-float="navigator"] button[type="submit"]:not([class*="only-icon"])'
|
||||
)
|
||||
this.buttonPopupNextStep = page.locator('div.popup button[type="submit"]')
|
||||
this.buttonSpaceSelector = page.locator('button[id="space.selector"]')
|
||||
this.buttonParentSelector = page.locator('div.parentSelector span[class*="label"]')
|
||||
this.inputNewDocumentTitle = page.locator('div[id="doc-title"] input')
|
||||
this.inputNewDocumentDescription = page.locator('div[id="doc-description"] input')
|
||||
this.inputNewDocumentCreateDaft = page.locator('div.footer div.footerButtons button[type="button"]')
|
||||
}
|
||||
|
||||
async createDocument (data: NewDocument, startSecondStep: boolean = false): Promise<void> {
|
||||
if (data.location != null) {
|
||||
await this.buttonSpaceSelector.click()
|
||||
await this.selectListItemWithSearch(this.page, data.location.space ?? '')
|
||||
|
||||
await this.page.locator('div.parentSelector span[class*="label"]', { hasText: data.location.parent }).click()
|
||||
}
|
||||
|
||||
// template
|
||||
if (!startSecondStep) {
|
||||
await this.buttonPopupNextStep.click()
|
||||
}
|
||||
await this.page.locator('div.templates div.tmpHeader', { hasText: data.template }).click()
|
||||
|
||||
// title
|
||||
await this.buttonPopupNextStep.click()
|
||||
await this.inputNewDocumentTitle.fill(data.title)
|
||||
await this.inputNewDocumentDescription.fill(data.description)
|
||||
|
||||
if (data.reason != null) {
|
||||
await this.page.locator('div.radio label', { hasText: data.reason }).click()
|
||||
}
|
||||
|
||||
// team
|
||||
await this.buttonPopupNextStep.click()
|
||||
|
||||
await this.inputNewDocumentCreateDaft.click()
|
||||
}
|
||||
|
||||
async openDocument (name: string): Promise<void> {
|
||||
await this.page.locator('button.hulyNavItem-container > span[class*="label"]', { hasText: name }).click()
|
||||
}
|
||||
|
||||
async executeMoreActionsOnDocument (documentName: string, action: string): Promise<void> {
|
||||
await this.page.locator('button.hulyNavItem-container > span[class*="label"]', { hasText: documentName }).hover()
|
||||
await this.page
|
||||
.locator('button.hulyNavItem-container > span[class*="label"]', { hasText: documentName })
|
||||
.locator('xpath=..')
|
||||
.locator('div[class*="actions"]:not([class*="arrow"])')
|
||||
.click()
|
||||
await this.selectFromDropdown(this.page, action)
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import { type Locator, type Page } from '@playwright/test'
|
||||
|
||||
export class NavigationMenuPage {
|
||||
readonly page: Page
|
||||
readonly buttonTemplates: Locator
|
||||
readonly buttonCategories: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
this.page = page
|
||||
this.buttonTemplates = page.locator('a[href$="templates"]', { hasText: 'Templates' })
|
||||
this.buttonCategories = page.locator('a[href$="categories"]', { hasText: 'Categories' })
|
||||
}
|
||||
}
|
84
qms-tests/sanity/tests/model/documents/templates-page.ts
Normal file
84
qms-tests/sanity/tests/model/documents/templates-page.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { type Locator, type Page } from '@playwright/test'
|
||||
import { CalendarPage } from '../calendar-page'
|
||||
import { NewTemplate } from '../types'
|
||||
|
||||
export class TemplatesPage extends CalendarPage {
|
||||
readonly page: Page
|
||||
readonly buttonCreateTemplate: Locator
|
||||
readonly buttonSpaceSelector: Locator
|
||||
readonly buttonPopupNextStep: Locator
|
||||
readonly inputNewTemplateTitle: Locator
|
||||
readonly inputNewTemplateDescription: Locator
|
||||
readonly inputNewTemplateCreateDaft: Locator
|
||||
readonly buttonNewTemplateCategory: Locator
|
||||
readonly buttonNewTemplateCustomReason: Locator
|
||||
readonly inputNewTemplateCustomReason: Locator
|
||||
readonly sectionHighlightedTeam: Locator
|
||||
readonly inputNewTemplateCode: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
super(page)
|
||||
this.page = page
|
||||
this.buttonCreateTemplate = page.locator('div[slot="header-tools"] button[type="submit"]')
|
||||
this.buttonSpaceSelector = page.locator('button[id="space.selector"]')
|
||||
this.buttonPopupNextStep = page.locator('div.popup button[type="submit"]')
|
||||
this.inputNewTemplateTitle = page.locator('div[id="doc-title"] input')
|
||||
this.inputNewTemplateDescription = page.locator('div[id="doc-description"] input')
|
||||
this.inputNewTemplateCreateDaft = page.locator('div.footer div.footerButtons button[type="button"]')
|
||||
this.buttonNewTemplateCategory = page.locator('div.popup div.sectionContent button')
|
||||
this.buttonNewTemplateCustomReason = page.locator('div.radio div.antiRadio:last-child')
|
||||
this.inputNewTemplateCustomReason = page.locator('div.popup div[id="doc-reason"] input')
|
||||
this.sectionHighlightedTeam = page.locator('div.popup div.highlighted', { hasText: 'Team' })
|
||||
this.inputNewTemplateCode = page.locator('input[placeholder="DOC-1"]')
|
||||
}
|
||||
|
||||
async createTemplate (data: NewTemplate): Promise<void> {
|
||||
if (data.location?.space != null) {
|
||||
await this.buttonSpaceSelector.click()
|
||||
await this.selectMenuItem(this.page, data.location.space)
|
||||
}
|
||||
|
||||
if (data.location?.parent != null) {
|
||||
await this.page.locator('div.parentSelector span[class*="label"]', { hasText: data.location.parent }).click()
|
||||
}
|
||||
|
||||
// title
|
||||
await this.buttonPopupNextStep.click()
|
||||
await this.inputNewTemplateTitle.fill(data.title)
|
||||
await this.inputNewTemplateDescription.fill(data.description)
|
||||
|
||||
if (data.code != null) {
|
||||
await this.inputNewTemplateCode.fill(data.code)
|
||||
}
|
||||
|
||||
if (data.category != null) {
|
||||
await this.buttonNewTemplateCategory.click()
|
||||
await this.selectListItemWithSearch(this.page, data.category, true)
|
||||
}
|
||||
|
||||
if (data.reason != null) {
|
||||
await this.buttonNewTemplateCustomReason.click()
|
||||
await this.inputNewTemplateCustomReason.fill(data.reason)
|
||||
}
|
||||
|
||||
// team
|
||||
await this.buttonPopupNextStep.click()
|
||||
if (data.reviewers != null) {
|
||||
await this.page.locator('div.addButton').nth(1).click()
|
||||
for (const reviewer of data.reviewers) {
|
||||
await this.selectListItemWithSearch(this.page, reviewer)
|
||||
}
|
||||
await this.sectionHighlightedTeam.click({ force: true })
|
||||
}
|
||||
|
||||
if (data.approvers != null) {
|
||||
await this.page.locator('div.addButton').last().click()
|
||||
for (const approver of data.approvers) {
|
||||
await this.selectListItemWithSearch(this.page, approver)
|
||||
}
|
||||
await this.sectionHighlightedTeam.click({ force: true })
|
||||
}
|
||||
|
||||
await this.inputNewTemplateCreateDaft.click()
|
||||
}
|
||||
}
|
15
qms-tests/sanity/tests/model/left-side-menu-page.ts
Normal file
15
qms-tests/sanity/tests/model/left-side-menu-page.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { type Locator, type Page } from '@playwright/test'
|
||||
|
||||
export class LeftSideMenuPage {
|
||||
readonly page: Page
|
||||
readonly buttonPlanning: Locator
|
||||
readonly buttonTeam: Locator
|
||||
readonly buttonDocuments: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
this.page = page
|
||||
this.buttonPlanning = page.locator('button[id$="Planning"]')
|
||||
this.buttonTeam = page.locator('button[id$="Team"]')
|
||||
this.buttonDocuments = page.locator('button[id$="documents:string:DocumentApplication"]')
|
||||
}
|
||||
}
|
29
qms-tests/sanity/tests/model/login-page.ts
Normal file
29
qms-tests/sanity/tests/model/login-page.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { expect, type Locator, type Page } from '@playwright/test'
|
||||
import { PlatformURI } from '../utils'
|
||||
|
||||
export class LoginPage {
|
||||
readonly page: Page
|
||||
readonly inputEmail: Locator
|
||||
readonly inputPassword: Locator
|
||||
readonly buttonLogin: Locator
|
||||
readonly buttonSignUp: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
this.page = page
|
||||
this.inputEmail = page.locator('input[name=email]')
|
||||
this.inputPassword = page.locator('input[name=current-password]')
|
||||
this.buttonLogin = page.locator('button', { hasText: 'Log In' })
|
||||
this.buttonSignUp = page.locator('a.title', { hasText: 'Sign Up' })
|
||||
}
|
||||
|
||||
async goto (): Promise<void> {
|
||||
await (await this.page.goto(`${PlatformURI}/login/login`))?.finished()
|
||||
}
|
||||
|
||||
async login (email: string, password: string): Promise<void> {
|
||||
await this.inputEmail.fill(email)
|
||||
await this.inputPassword.fill(password)
|
||||
expect(await this.buttonLogin.isEnabled()).toBe(true)
|
||||
await this.buttonLogin.click()
|
||||
}
|
||||
}
|
25
qms-tests/sanity/tests/model/select-workspace-page.ts
Normal file
25
qms-tests/sanity/tests/model/select-workspace-page.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { expect, type Locator, type Page } from '@playwright/test'
|
||||
|
||||
export class SelectWorkspacePage {
|
||||
readonly page: Page
|
||||
readonly buttonWorkspace: Locator
|
||||
readonly buttonCreateWorkspace: Locator
|
||||
readonly inputWorkspaceName: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
this.page = page
|
||||
this.buttonWorkspace = page.locator('div[class*="workspace"]')
|
||||
this.buttonCreateWorkspace = page.locator('button > span', { hasText: 'Create workspace' })
|
||||
this.inputWorkspaceName = page.locator('div.form input')
|
||||
}
|
||||
|
||||
async selectWorkspace (workspace: string): Promise<void> {
|
||||
await this.buttonWorkspace.filter({ hasText: workspace }).click()
|
||||
}
|
||||
|
||||
async createWorkspace (workspaceName: string): Promise<void> {
|
||||
await this.buttonCreateWorkspace.waitFor({ state: 'visible' })
|
||||
await expect(this.inputWorkspaceName).toBeVisible()
|
||||
await this.inputWorkspaceName.fill(workspaceName)
|
||||
}
|
||||
}
|
32
qms-tests/sanity/tests/model/signup-page.ts
Normal file
32
qms-tests/sanity/tests/model/signup-page.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { type Locator, type Page } from '@playwright/test'
|
||||
import { UserSignUp } from './types'
|
||||
|
||||
export class SignupPage {
|
||||
readonly page: Page
|
||||
readonly inputFirstName: Locator
|
||||
readonly inputLastName: Locator
|
||||
readonly inputEmail: Locator
|
||||
readonly inputNewPassword: Locator
|
||||
readonly inputRepeatNewPassword: Locator
|
||||
readonly buttonSignUp: Locator
|
||||
readonly textError: Locator
|
||||
|
||||
constructor (page: Page) {
|
||||
this.page = page
|
||||
this.inputFirstName = page.locator('input[name="given-name"]')
|
||||
this.inputLastName = page.locator('input[name="family-name"]')
|
||||
this.inputEmail = page.locator('input[name="email"]')
|
||||
this.inputNewPassword = page.locator('input[name="new-password"]').nth(0)
|
||||
this.inputRepeatNewPassword = page.locator('input[name="new-password"]').nth(1)
|
||||
this.buttonSignUp = page.locator('div.send button')
|
||||
this.textError = page.locator('div.ERROR > span')
|
||||
}
|
||||
|
||||
async signup (userData: UserSignUp): Promise<void> {
|
||||
await this.inputFirstName.fill(userData.firstName)
|
||||
await this.inputLastName.fill(userData.lastName)
|
||||
await this.inputEmail.fill(userData.email)
|
||||
await this.inputNewPassword.fill(userData.password)
|
||||
await this.inputRepeatNewPassword.fill(userData.password)
|
||||
}
|
||||
}
|
73
qms-tests/sanity/tests/model/types.ts
Normal file
73
qms-tests/sanity/tests/model/types.ts
Normal file
@ -0,0 +1,73 @@
|
||||
export interface NewDocument {
|
||||
location?: Location
|
||||
template: string
|
||||
title: string
|
||||
description: string
|
||||
reason?: string
|
||||
reviewers?: Array<string>
|
||||
approvers?: Array<string>
|
||||
}
|
||||
|
||||
export interface Location {
|
||||
space?: string
|
||||
parent?: string
|
||||
}
|
||||
export interface Content {
|
||||
sectionTitle: string
|
||||
content: string
|
||||
}
|
||||
|
||||
export interface UserSignUp {
|
||||
firstName: string
|
||||
lastName: string
|
||||
email: string
|
||||
password: string
|
||||
}
|
||||
|
||||
export enum DocumentStatus {
|
||||
DELETED = 'Deleted',
|
||||
DRAFT = 'Draft',
|
||||
IN_REVIEW = 'In Review',
|
||||
IN_APPROVAL = 'In Approval',
|
||||
REVIEWED = 'Reviewed',
|
||||
REJECTED = 'Rejected',
|
||||
APPROVED = 'Approved',
|
||||
EFFECTIVE = 'Effective'
|
||||
}
|
||||
|
||||
export interface DocumentDetails {
|
||||
type: string
|
||||
category: string
|
||||
version: string
|
||||
status: string
|
||||
owner: string
|
||||
author: string
|
||||
id?: string
|
||||
}
|
||||
|
||||
export enum DocumentRights {
|
||||
VIEWING = 'Viewing',
|
||||
EDITING = 'Editing',
|
||||
COMPARING = 'Comparing'
|
||||
}
|
||||
|
||||
export interface NewTemplate {
|
||||
location?: Location
|
||||
title: string
|
||||
description: string
|
||||
code?: string
|
||||
category?: string
|
||||
reason?: string
|
||||
reviewers?: Array<string>
|
||||
approvers?: Array<string>
|
||||
}
|
||||
|
||||
export interface NewCategory extends UpdateCategory {
|
||||
title: string
|
||||
code: string
|
||||
}
|
||||
|
||||
export interface UpdateCategory {
|
||||
description: string
|
||||
attachFileName?: string
|
||||
}
|
46
qms-tests/sanity/tests/playwright.config.ts
Normal file
46
qms-tests/sanity/tests/playwright.config.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { devices, PlaywrightTestConfig } from '@playwright/test'
|
||||
import { config as dotenvConfig } from 'dotenv'
|
||||
dotenvConfig()
|
||||
|
||||
let maxFailures: number | undefined
|
||||
if (process.env.TESTS_MAX_FAILURES !== undefined) {
|
||||
maxFailures = parseInt(process.env.TESTS_MAX_FAILURES)
|
||||
}
|
||||
|
||||
const config: PlaywrightTestConfig = {
|
||||
projects: [
|
||||
{
|
||||
name: 'QMS',
|
||||
use: {
|
||||
permissions: ['clipboard-read', 'clipboard-write'],
|
||||
...devices['Desktop Chrome'],
|
||||
screenshot: 'only-on-failure',
|
||||
viewport: {
|
||||
width: 1440,
|
||||
height: 900
|
||||
},
|
||||
trace: {
|
||||
mode: 'retain-on-failure',
|
||||
snapshots: true,
|
||||
screenshots: true,
|
||||
sources: true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
retries: 1,
|
||||
timeout: 60000,
|
||||
maxFailures,
|
||||
reporter: [
|
||||
['list'],
|
||||
['html'],
|
||||
[
|
||||
'allure-playwright',
|
||||
{
|
||||
detail: false,
|
||||
suiteTitle: false
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
export default config
|
75
qms-tests/sanity/tests/utils.ts
Normal file
75
qms-tests/sanity/tests/utils.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import { Browser, Locator, Page } from '@playwright/test'
|
||||
import { allure } from 'allure-playwright'
|
||||
|
||||
export const PlatformURI = process.env.PLATFORM_URI as string
|
||||
export const PlatformTransactor = process.env.PLATFORM_TRANSACTOR as string
|
||||
export const PlatformUser = process.env.PLATFORM_USER as string
|
||||
export const PlatformToken = process.env.PLATFORM_TOKEN as string
|
||||
export const PlatformSetting = process.env.SETTING as string
|
||||
export const PlatformSettingSecond = process.env.SETTING_SECOND as string
|
||||
export const PlatformSettingQaraManager = process.env.SETTING_QARA_MANAGER as string
|
||||
export const PlatformPassword = process.env.PLATFORM_PASSWORD as string
|
||||
export const DefaultWorkspace = 'sanity-ws-qms'
|
||||
export const DocumentURI = `workbench/${DefaultWorkspace}/documents`
|
||||
export const HomepageURI = `workbench/${DefaultWorkspace}`
|
||||
|
||||
function toHex (value: number, chars: number): string {
|
||||
const result = value.toString(16)
|
||||
if (result.length < chars) {
|
||||
return '0'.repeat(chars - result.length) + result
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
let counter = 0
|
||||
const random = toHex((Math.random() * (1 << 24)) | 0, 6) + toHex((Math.random() * (1 << 16)) | 0, 4)
|
||||
|
||||
function timestamp (): string {
|
||||
const time = (Date.now() / 1000) | 0
|
||||
return toHex(time, 8)
|
||||
}
|
||||
|
||||
function count (): string {
|
||||
const val = counter++ & 0xffffff
|
||||
return toHex(val, 6)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @returns
|
||||
*/
|
||||
export function generateId (len = 100): string {
|
||||
const v = timestamp() + random
|
||||
let s = v.length - len
|
||||
if (s < 0) {
|
||||
s = 0
|
||||
}
|
||||
return v.slice(s, v.length) + count()
|
||||
}
|
||||
|
||||
export async function getSecondPage (browser: Browser): Promise<Page> {
|
||||
const userSecondContext = await browser.newContext({ storageState: PlatformSettingSecond })
|
||||
return await userSecondContext.newPage()
|
||||
}
|
||||
|
||||
export function randomString (): string {
|
||||
return (Math.random() * 1000000).toString(36).replace('.', '')
|
||||
}
|
||||
|
||||
export async function attachScreenshot (name: string, page: Page): Promise<void> {
|
||||
await allure.attachment(name, await page.screenshot(), {
|
||||
contentType: 'image/png'
|
||||
})
|
||||
await page.screenshot({ path: `screenshots/${name}` })
|
||||
}
|
||||
|
||||
export async function getQaraManagerPage (browser: Browser): Promise<Page> {
|
||||
const qaraManagerContext = await browser.newContext({ storageState: PlatformSettingQaraManager })
|
||||
return await qaraManagerContext.newPage()
|
||||
}
|
||||
|
||||
export async function * iterateLocator (locator: Locator): AsyncGenerator<Locator> {
|
||||
for (let index = 0; index < (await locator.count()); index++) {
|
||||
yield locator.nth(index)
|
||||
}
|
||||
}
|
9
qms-tests/sanity/tsconfig.json
Normal file
9
qms-tests/sanity/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./tests",
|
||||
"outDir": "./lib",
|
||||
"declarationDir": "./types",
|
||||
"lib": ["esnext", "dom"]
|
||||
}
|
||||
}
|
12
qms-tests/tool.sh
Executable file
12
qms-tests/tool.sh
Executable file
@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
export MINIO_ACCESS_KEY=minioadmin
|
||||
export MINIO_SECRET_KEY=minioadmin
|
||||
export MINIO_ENDPOINT=localhost:9002
|
||||
export MONGO_URL=mongodb://localhost:27018
|
||||
export TRANSACTOR_URL=ws://localhost:3334
|
||||
export ELASTIC_URL=http://localhost:9201
|
||||
export SERVER_SECRET=secret
|
||||
export STORAGE_CONFIG="minio|localhost:9002?accessKey=minioadmin&secretKey=minioadmin"
|
||||
|
||||
node ../dev/tool/bundle/bundle.js $@
|
5
qms-tests/update-snapshot.sh
Executable file
5
qms-tests/update-snapshot.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
location="${1:-./sanity-ws-qms}"
|
||||
#backup
|
||||
./tool.sh backup ${location} sanity-ws-qms
|
Loading…
Reference in New Issue
Block a user