diff --git a/.env.example b/.env.example index 4b151929a..ac2a60e6a 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ REACT_APP_ORCID_REDIRECT= GENERATE_SOURCEMAP=false -SCHEMA_URL=http://localhost:4100/graphql +SCHEMA_URL=http://localhost:4000/graphql diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index d4ff8d765..2303a3964 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -24,25 +24,35 @@ jobs: local branch=$1 local found=0 shift - for endpoint in $@; do - local json=$(curl -s $endpoint) - local branch_found=$(echo $json | jq -c ".[] | select(.name==\"$branch\") | .name") - # to track what we found - >&2 echo "$endpoint -> $branch_found" - if [[ $branch_found != "" ]]; then - found=$((found += 1)) - fi - done + + local dockerhub_endpoint=$1 + local dockerhub_json=$(curl -s $dockerhub_endpoint) + local dockerhub_branch_found=$(echo $dockerhub_json | jq -c ".results[] | select(.name==\"$branch\") | .name") + # to track what we found + >&2 echo "$dockerhub_endpoint -> $dockerhub_branch_found" + if [[ $dockerhub_branch_found != "" ]]; then + found=$((found += 1)) + fi + + local github_endpoint=$2 + local github_json=$(curl -s $github_endpoint) + local github_branch_found=$(echo $github_json | jq -c ".[] | select(.name==\"$branch\") | .name") + # to track what we found + >&2 echo "$github_endpoint -> $github_branch_found" + if [[ $github_branch_found != "" ]]; then + found=$((found += 1)) + fi + echo $found } BE_TAGS=$(check_feature ${{ github.head_ref }} \ - https://registry.hub.docker.com/v1/repositories/dmsc/duo-backend/tags \ - https://api.github.com/repos/UserOfficeProject/user-office-backend/branches + https://registry.hub.docker.com/v2/repositories/dmsc/duo-backend/tags \ + https://api.github.com/repos/UserOfficeProject/user-office-backend/branches?per_page=100 ) FACTORY_TAGS=$(check_feature ${{ github.head_ref }} \ - https://registry.hub.docker.com/v1/repositories/dmsc/duo-factory/tags \ - https://api.github.com/repos/UserOfficeProject/user-office-factory/branches + https://registry.hub.docker.com/v2/repositories/dmsc/duo-factory/tags \ + https://api.github.com/repos/UserOfficeProject/user-office-factory/branches?per_page=100 ) BE_TAG=develop @@ -263,7 +273,7 @@ jobs: run: | DOCKERFILE_VERSION=${{ hashFiles('Dockerfile.e2e', 'cypress/*.json') }} TAG="docker.pkg.github.com/userofficeproject/user-office-frontend/e2e-cypress-core:$DOCKERFILE_VERSION" - docker pull $TAG + docker pull $TAG docker tag $TAG e2e-cypress:latest - name: Load app cache @@ -330,6 +340,37 @@ jobs: -f docker-compose.all.yml \ up --exit-code-from cypress + - name: Run docker-compose stfc + env: + SVC_ACC_TOKEN: ${{ secrets.SVC_ACC_TOKEN }} + run: | + cd "$GITHUB_WORKSPACE/.." + + REPO_DIR_NAME=$(basename $GITHUB_WORKSPACE) + + export USER_OFFICE_BACKEND_TAG=${{ needs.resolve_dep.outputs.BE_TAG }} + export USER_OFFICE_BACKEND_DIR=user-office-backend + export USER_OFFICE_BACKEND=http://backend:4000/graphql + export USER_OFFICE_ENDPOINT=$USER_OFFICE_BACKEND + + export USER_OFFICE_FACTORY_TAG=${{ needs.resolve_dep.outputs.FACTORY_TAG }} + export USER_OFFICE_FACTORY_ENDPOINT=http://factory:4500/generate + + export USER_OFFICE_FRONTEND_DIR=$REPO_DIR_NAME + export BUILD_TAG=${{ github.sha }} + + export CYPRES_SPEC_PATTERN=${{ matrix.pattern }} + + docker-compose --project-directory $PWD \ + -f "$REPO_DIR_NAME/docker-compose-stfc.e2e.yml" \ + up -d mockServer + + sleep 10 + + docker-compose --project-directory $PWD \ + -f "$REPO_DIR_NAME/docker-compose-stfc.e2e.yml" \ + up --exit-code-from cypress + - name: Upload cypres screenshots if: ${{ failure() }} uses: actions/upload-artifact@v2 diff --git a/.prettierignore b/.prettierignore index 4da405e90..1d75ad308 100644 --- a/.prettierignore +++ b/.prettierignore @@ -6,3 +6,4 @@ src/generated/ README.md .vscode/ cypress/fixtures/ +docker-compose-stfc.e2e.yml diff --git a/cypress/fixtures/shipments_template.json b/cypress/fixtures/shipments_template.json new file mode 100644 index 000000000..a0dbd0273 --- /dev/null +++ b/cypress/fixtures/shipments_template.json @@ -0,0 +1 @@ +{"metadata":{"version":"1.2.0","exportDate":"2022-06-21T11:27:55.062Z"},"data":{"template":{"templateId":20,"groupId":"SHIPMENT","name":"Shipment template","description":"Default shipment template","isArchived":false},"templateSteps":[{"topic":{"id":82,"title":"New shipment","templateId":20,"sortOrder":0,"isEnabled":true},"fields":[{"question":{"categoryId":3,"id":"shipment_basis","naturalKey":"shipment_basis","dataType":"SHIPMENT_BASIS","question":"Name of the contents","config":{"tooltip":"","required":false,"small_label":""}},"topicId":82,"sortOrder":0,"config":{"tooltip":"","required":false,"small_label":""},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"text_input_1625558124022","naturalKey":"detailed_description_of_content","dataType":"TEXT_INPUT","question":"Detailed description of content","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":true,"placeholder":"","isCounterHidden":true}},"topicId":82,"sortOrder":1,"config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":true,"placeholder":"","isCounterHidden":true},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"number_input_1625560985685","naturalKey":"parcel_length","dataType":"NUMBER_INPUT","question":"Length","config":{"small_label":"","required":false,"tooltip":"","units":[{"id":"centimeter","unit":"centimeter","symbol":"cm","quantity":"length","siConversionFormula":"x / 100"},{"id":"length","unit":"meter","symbol":"m","quantity":"length","siConversionFormula":"x"}],"numberValueConstraint":"ONLY_POSITIVE"}},"topicId":82,"sortOrder":2,"config":{"small_label":"","required":false,"tooltip":"","units":[{"id":"centimeter","unit":"centimeter","symbol":"cm","quantity":"length","siConversionFormula":"x / 100"},{"id":"length","unit":"meter","symbol":"m","quantity":"length","siConversionFormula":"x"}],"numberValueConstraint":"ONLY_POSITIVE"},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"number_input_1618486507976","naturalKey":"parcel_width","dataType":"NUMBER_INPUT","question":"Width","config":{"small_label":"","required":false,"tooltip":"","units":[{"id":"centimeter","unit":"centimeter","symbol":"cm","quantity":"length","siConversionFormula":"x / 100"},{"id":"length","unit":"meter","symbol":"m","quantity":"length","siConversionFormula":"x"}],"numberValueConstraint":null}},"topicId":82,"sortOrder":3,"config":{"small_label":"","required":true,"tooltip":"","units":[{"id":"centimeter","unit":"centimeter","symbol":"cm","quantity":"length","siConversionFormula":"x / 100"},{"id":"length","unit":"meter","symbol":"m","quantity":"length","siConversionFormula":"x"}],"numberValueConstraint":"ONLY_POSITIVE"},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"number_input_1618486519108","naturalKey":"parcel_height","dataType":"NUMBER_INPUT","question":"Height","config":{"small_label":"","required":false,"tooltip":"","units":[{"id":"centimeter","unit":"centimeter","symbol":"cm","quantity":"length","siConversionFormula":"x / 100"},{"id":"length","unit":"meter","symbol":"m","quantity":"length","siConversionFormula":"x"}],"numberValueConstraint":null}},"topicId":82,"sortOrder":4,"config":{"small_label":"","required":true,"tooltip":"","units":[{"id":"centimeter","unit":"centimeter","symbol":"cm","quantity":"length","siConversionFormula":"x / 100"},{"id":"length","unit":"meter","symbol":"m","quantity":"length","siConversionFormula":"x"}],"numberValueConstraint":"NONE"},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"number_input_1625558279983","naturalKey":"parcel_weight","dataType":"NUMBER_INPUT","question":"Weight","config":{"small_label":"","required":false,"tooltip":"","units":[{"id":"gram","unit":"gram","symbol":"g","quantity":"mass","siConversionFormula":"x / 1000"},{"id":"mass","unit":"kilogram","symbol":"kg","quantity":"mass","siConversionFormula":"x"}],"numberValueConstraint":"ONLY_POSITIVE"}},"topicId":82,"sortOrder":5,"config":{"small_label":"","required":true,"tooltip":"","units":[{"id":"gram","unit":"gram","symbol":"g","quantity":"mass","siConversionFormula":"x / 1000"},{"id":"mass","unit":"kilogram","symbol":"kg","quantity":"mass","siConversionFormula":"x"}],"numberValueConstraint":"ONLY_POSITIVE"},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"selection_from_options_1643620237783","naturalKey":"storage_temperature","dataType":"SELECTION_FROM_OPTIONS","question":"Storage temperature","config":{"small_label":"","required":true,"tooltip":"","variant":"dropdown","options":["Ambient","< 0 C","< -20 C"],"isMultipleSelect":false}},"topicId":82,"sortOrder":6,"config":{"small_label":"","required":true,"tooltip":"","variant":"dropdown","options":["Ambient","< 0 C","< -20 C"],"isMultipleSelect":false},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"boolean_1625558385021","naturalKey":"is_dangerous_goods","dataType":"BOOLEAN","question":"Dangerous goods","config":{"small_label":"","required":false,"tooltip":""}},"topicId":82,"sortOrder":7,"config":{"small_label":"","required":false,"tooltip":""},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"text_input_1625558434184","naturalKey":"dangerous_goods_un_number","dataType":"TEXT_INPUT","question":"Dangerous goods UN number","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":"4","max":"4","multiline":false,"placeholder":"A four-digit number that identifies hazardous materials (United Nations number)","isCounterHidden":true}},"topicId":82,"sortOrder":8,"config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":4,"max":4,"multiline":false,"placeholder":"A four-digit number that identifies hazardous materials (United Nations number)","isCounterHidden":true},"dependencies":[{"questionId":"text_input_1625558434184","dependencyId":"boolean_1625558385021","dependencyNaturalKey":"is_dangerous_goods","condition":{"params":true,"condition":"eq"}}],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"text_input_1625558611322","naturalKey":"dangerous_goods_details","dataType":"TEXT_INPUT","question":"Specify all dangerous goods in detail","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":true,"placeholder":"","isCounterHidden":true}},"topicId":82,"sortOrder":9,"config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":true,"placeholder":"","isCounterHidden":true},"dependencies":[{"questionId":"text_input_1625558611322","dependencyId":"boolean_1625558385021","dependencyNaturalKey":"is_dangerous_goods","condition":{"params":true,"condition":"eq"}}],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"text_input_1610625438357","naturalKey":"shipment_sample_risks","dataType":"TEXT_INPUT","question":"Specify risks for shipment associated with samples, if any","config":{"required":false,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":true,"placeholder":"","isCounterHidden":false}},"topicId":82,"sortOrder":10,"config":{"required":false,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":true,"placeholder":"","isCounterHidden":false},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"number_input_1610625456101","naturalKey":"parcel_value","dataType":"NUMBER_INPUT","question":"Value(EUR)","config":{"small_label":"","required":false,"tooltip":"","units":[],"numberValueConstraint":null}},"topicId":82,"sortOrder":11,"config":{"small_label":"","required":false,"tooltip":"","units":[]},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"text_input_1625558974500","naturalKey":"shipment_sender_name","dataType":"TEXT_INPUT","question":"Sender name","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true}},"topicId":82,"sortOrder":12,"config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"text_input_1625558691786","naturalKey":"shipment_sender_company","dataType":"TEXT_INPUT","question":"Sender Company","config":{"required":false,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"Optional","isCounterHidden":true}},"topicId":82,"sortOrder":13,"config":{"required":false,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"Optional","isCounterHidden":true},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"text_input_1625558989021","naturalKey":"shipment_sender_email","dataType":"TEXT_INPUT","question":"Sender email","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true}},"topicId":82,"sortOrder":14,"config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"text_input_1625559010980","naturalKey":"shipment_sender_phone","dataType":"TEXT_INPUT","question":"Sender phone number","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true}},"topicId":82,"sortOrder":15,"config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"text_input_1625558820540","naturalKey":"shipment_sender_street_address","dataType":"TEXT_INPUT","question":"Sender street address","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true}},"topicId":82,"sortOrder":16,"config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"text_input_1625558884080","naturalKey":"shipment_sender_zip_code","dataType":"TEXT_INPUT","question":"Sender Zip code","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true}},"topicId":82,"sortOrder":17,"config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"text_input_1625558913433","naturalKey":"shipment_sender_city_country","dataType":"TEXT_INPUT","question":"Sender City / Country","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true}},"topicId":82,"sortOrder":18,"config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"file_upload_1625559467285","naturalKey":"shipment_file_attachment","dataType":"FILE_UPLOAD","question":"Attachment","config":{"small_label":"","required":false,"tooltip":"","file_type":[],"max_files":0}},"topicId":82,"sortOrder":19,"config":{"small_label":"","required":false,"tooltip":"","file_type":[],"max_files":"10"},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"file_upload_1625559541684","naturalKey":"shipment_customs_invoice","dataType":"FILE_UPLOAD","question":"Customs invoice","config":{"small_label":"","required":false,"tooltip":"","file_type":[".pdf",".doc",".docx","image/*"],"max_files":1}},"topicId":82,"sortOrder":20,"config":{"small_label":"","required":false,"tooltip":"","file_type":[".pdf",".doc",".docx","image/*"],"max_files":"1"},"dependencies":[],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"file_upload_1625559734367","naturalKey":"shipment_msds","dataType":"FILE_UPLOAD","question":"MSDS","config":{"small_label":"Please, attach technical product data sheet and related safety data sheet","required":false,"tooltip":"","file_type":[],"max_files":0}},"topicId":82,"sortOrder":21,"config":{"small_label":"If there are any dangerous goods, please, attach technical product data sheet and related safety data sheet.","required":false,"tooltip":"","file_type":[],"max_files":0},"dependencies":[{"questionId":"file_upload_1625559734367","dependencyId":"boolean_1625558385021","dependencyNaturalKey":"is_dangerous_goods","condition":{"params":true,"condition":"eq"}}],"dependenciesOperator":"AND"},{"question":{"categoryId":3,"id":"text_input_1610363200423","naturalKey":"shipment_additional_information","dataType":"TEXT_INPUT","question":"Additional information","config":{"required":false,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":true,"placeholder":"","isCounterHidden":true}},"topicId":82,"sortOrder":22,"config":{"required":false,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":true,"placeholder":"","isCounterHidden":true},"dependencies":[],"dependenciesOperator":"AND"}]}],"questions":[{"categoryId":3,"id":"shipment_basis","naturalKey":"shipment_basis","dataType":"SHIPMENT_BASIS","question":"Shipment basic information","config":{"tooltip":"","required":false,"small_label":""}},{"categoryId":3,"id":"text_input_1625558124022","naturalKey":"detailed_description_of_content","dataType":"TEXT_INPUT","question":"Detailed description of content","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":true,"placeholder":"","isCounterHidden":true}},{"categoryId":3,"id":"number_input_1625560985685","naturalKey":"parcel_length","dataType":"NUMBER_INPUT","question":"Length","config":{"small_label":"","required":false,"tooltip":"","units":[{"id":"centimeter","unit":"centimeter","symbol":"cm","quantity":"length","siConversionFormula":"x / 100"},{"id":"length","unit":"meter","symbol":"m","quantity":"length","siConversionFormula":"x"}],"numberValueConstraint":"ONLY_POSITIVE"}},{"categoryId":3,"id":"number_input_1618486507976","naturalKey":"parcel_width","dataType":"NUMBER_INPUT","question":"Width","config":{"small_label":"","required":false,"tooltip":"","units":[{"id":"centimeter","unit":"centimeter","symbol":"cm","quantity":"length","siConversionFormula":"x / 100"},{"id":"length","unit":"meter","symbol":"m","quantity":"length","siConversionFormula":"x"}],"numberValueConstraint":null}},{"categoryId":3,"id":"number_input_1618486519108","naturalKey":"parcel_height","dataType":"NUMBER_INPUT","question":"Height","config":{"small_label":"","required":false,"tooltip":"","units":[{"id":"centimeter","unit":"centimeter","symbol":"cm","quantity":"length","siConversionFormula":"x / 100"},{"id":"length","unit":"meter","symbol":"m","quantity":"length","siConversionFormula":"x"}],"numberValueConstraint":null}},{"categoryId":3,"id":"number_input_1625558279983","naturalKey":"parcel_weight","dataType":"NUMBER_INPUT","question":"Weight","config":{"small_label":"","required":false,"tooltip":"","units":[{"id":"gram","unit":"gram","symbol":"g","quantity":"mass","siConversionFormula":"x / 1000"},{"id":"mass","unit":"kilogram","symbol":"kg","quantity":"mass","siConversionFormula":"x"}],"numberValueConstraint":"ONLY_POSITIVE"}},{"categoryId":3,"id":"selection_from_options_1643620237783","naturalKey":"storage_temperature","dataType":"SELECTION_FROM_OPTIONS","question":"Storage temperature","config":{"small_label":"","required":true,"tooltip":"","variant":"dropdown","options":["Ambient","< 0 C","< -20 C"],"isMultipleSelect":false}},{"categoryId":3,"id":"boolean_1625558385021","naturalKey":"is_dangerous_goods","dataType":"BOOLEAN","question":"Dangerous goods","config":{"small_label":"","required":false,"tooltip":""}},{"categoryId":3,"id":"text_input_1625558434184","naturalKey":"dangerous_goods_un_number","dataType":"TEXT_INPUT","question":"Dangerous goods UN number","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":"4","max":"4","multiline":false,"placeholder":"A four-digit number that identifies hazardous materials (United Nations number)","isCounterHidden":true}},{"categoryId":3,"id":"text_input_1625558611322","naturalKey":"dangerous_goods_details","dataType":"TEXT_INPUT","question":"Specify all dangerous goods in detail","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":true,"placeholder":"","isCounterHidden":true}},{"categoryId":3,"id":"text_input_1610625438357","naturalKey":"shipment_sample_risks","dataType":"TEXT_INPUT","question":"Specify risks for shipment associated with samples, if any","config":{"required":false,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":true,"placeholder":"","isCounterHidden":false}},{"categoryId":3,"id":"number_input_1610625456101","naturalKey":"parcel_value","dataType":"NUMBER_INPUT","question":"Value(EUR)","config":{"small_label":"","required":false,"tooltip":"","units":[],"numberValueConstraint":null}},{"categoryId":3,"id":"text_input_1625558974500","naturalKey":"shipment_sender_name","dataType":"TEXT_INPUT","question":"Sender name","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true}},{"categoryId":3,"id":"text_input_1625558691786","naturalKey":"shipment_sender_company","dataType":"TEXT_INPUT","question":"Sender Company","config":{"required":false,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"Optional","isCounterHidden":true}},{"categoryId":3,"id":"text_input_1625558989021","naturalKey":"shipment_sender_email","dataType":"TEXT_INPUT","question":"Sender email","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true}},{"categoryId":3,"id":"text_input_1625559010980","naturalKey":"shipment_sender_phone","dataType":"TEXT_INPUT","question":"Sender phone number","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true}},{"categoryId":3,"id":"text_input_1625558820540","naturalKey":"shipment_sender_street_address","dataType":"TEXT_INPUT","question":"Sender street address","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true}},{"categoryId":3,"id":"text_input_1625558884080","naturalKey":"shipment_sender_zip_code","dataType":"TEXT_INPUT","question":"Sender Zip code","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true}},{"categoryId":3,"id":"text_input_1625558913433","naturalKey":"shipment_sender_city_country","dataType":"TEXT_INPUT","question":"Sender City / Country","config":{"required":true,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":false,"placeholder":"","isCounterHidden":true}},{"categoryId":3,"id":"file_upload_1625559467285","naturalKey":"shipment_file_attachment","dataType":"FILE_UPLOAD","question":"Attachment","config":{"small_label":"","required":false,"tooltip":"","file_type":[],"max_files":0}},{"categoryId":3,"id":"file_upload_1625559541684","naturalKey":"shipment_customs_invoice","dataType":"FILE_UPLOAD","question":"Customs invoice","config":{"small_label":"","required":false,"tooltip":"","file_type":[".pdf",".doc",".docx","image/*"],"max_files":1}},{"categoryId":3,"id":"file_upload_1625559734367","naturalKey":"shipment_msds","dataType":"FILE_UPLOAD","question":"MSDS","config":{"small_label":"Please, attach technical product data sheet and related safety data sheet","required":false,"tooltip":"","file_type":[],"max_files":0}},{"categoryId":3,"id":"text_input_1610363200423","naturalKey":"shipment_additional_information","dataType":"TEXT_INPUT","question":"Additional information","config":{"required":false,"small_label":"","tooltip":"","htmlQuestion":"","isHtmlQuestion":false,"min":null,"max":null,"multiline":true,"placeholder":"","isCounterHidden":true}}],"subTemplates":[]}} diff --git a/cypress/integration/SEP.ts b/cypress/integration/SEP.ts index 82f615040..b2b27a684 100644 --- a/cypress/integration/SEP.ts +++ b/cypress/integration/SEP.ts @@ -1,4 +1,4 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { ProposalEndStatus, @@ -7,8 +7,12 @@ import { UserRole, UpdateUserMutationVariables, User, + TemplateGroupId, + FeatureId, } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; +import { updatedCall } from '../support/utils'; const sepMembers = { chair: initialDBData.users.user2, @@ -107,8 +111,35 @@ const instrument = { let createdSepId: number; let createdProposalPk: number; let createdProposalId: string; +let createdWorkflowId: number; +let createdEsiTemplateId: number; + +function createWorkflowAndEsiTemplate() { + const workflowName = faker.lorem.words(2); + const workflowDescription = faker.lorem.words(5); + + cy.createProposalWorkflow({ + name: workflowName, + description: workflowDescription, + }).then((result) => { + const workflow = result.createProposalWorkflow.proposalWorkflow; + if (workflow) { + createdWorkflowId = workflow.id; + + cy.createTemplate({ + name: 'default esi template', + groupId: TemplateGroupId.PROPOSAL_ESI, + }).then((result) => { + if (result.createTemplate.template) { + createdEsiTemplateId = result.createTemplate.template.templateId; + } + }); + } + }); +} function initializationBeforeTests() { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); cy.createSep({ code: sep1.code, @@ -154,15 +185,26 @@ function initializationBeforeTests() { id: sepMembers.reviewer.id, roles: [initialDBData.roles.sepReviewer], }); + createWorkflowAndEsiTemplate(); } context('SEP reviews tests', () => { beforeEach(() => { initializationBeforeTests(); + cy.getAndStoreFeaturesEnabled(); + }); + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.SEP_REVIEW)) { + this.skip(); + } }); describe('User officer role', () => { - it('Officer should be able to assign proposal to existing SEP', () => { + it('Officer should be able to assign proposal to existing SEP', function () { + cy.getAndStoreFeaturesEnabled(); + if (featureFlags.getEnabledFeatures().get(FeatureId.EXTERNAL_AUTH)) { + this.skip(); + } cy.login('officer'); cy.visit(`/SEPPage/${createdSepId}?tab=2`); @@ -183,6 +225,32 @@ context('SEP reviews tests', () => { ); cy.get('[data-cy="sep-selection"]').click(); + // NOTE: Check first for empty list because call has no SEPs assigned. + cy.get('[role="presentation"] .MuiAutocomplete-noOptions').contains( + 'No SEPs' + ); + + // NOTE: Assign SEP to a call. + cy.updateCall({ + id: initialDBData.call.id, + ...updatedCall, + proposalWorkflowId: createdWorkflowId, + esiTemplateId: createdEsiTemplateId, + seps: [createdSepId], + }); + + cy.reload(); + + cy.contains(proposal1.title).parent().find('[type="checkbox"]').check(); + + cy.get("[aria-label='Assign proposals to SEP']").first().click(); + + cy.get('[data-cy="sep-selection"] input').should( + 'not.have.class', + 'Mui-disabled' + ); + cy.get('[data-cy="sep-selection"]').click(); + cy.get('[data-cy="sep-selection-options"]').contains(sep1.code).click(); cy.get('[data-cy="submit"]').click(); @@ -857,6 +925,12 @@ context('SEP meeting components tests', () => { beforeEach(() => { initializationBeforeTests(); + }); + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.SEP_REVIEW)) { + this.skip(); + } + createWorkflowAndEsiTemplate(); cy.assignProposalsToSep({ sepId: createdSepId, proposals: [ @@ -909,6 +983,14 @@ context('SEP meeting components tests', () => { }); } }); + // NOTE: Assign SEP to a call. + cy.updateCall({ + id: initialDBData.call.id, + ...updatedCall, + proposalWorkflowId: createdWorkflowId, + esiTemplateId: createdEsiTemplateId, + seps: [createdSepId], + }); }); describe('User Officer role', () => { @@ -1554,7 +1636,9 @@ context('SEP meeting components tests', () => { cy.get('[data-cy="download-sep-xlsx"]').click(); cy.get('[data-cy="preparing-download-dialog"]').should('exist'); - cy.get('[data-cy="preparing-download-dialog-item"]').contains('call 1'); + cy.get('[data-cy="preparing-download-dialog-item"]').contains( + updatedCall.shortCode + ); }); it('Officer should be able to remove assigned SEP member from proposal in existing SEP', () => { diff --git a/cypress/integration/appSettings.ts b/cypress/integration/appSettings.ts index e5be325c7..ec50230ab 100644 --- a/cypress/integration/appSettings.ts +++ b/cypress/integration/appSettings.ts @@ -1,7 +1,12 @@ +import { FeatureId, ReviewerFilter } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; context('App settings tests', () => { beforeEach(() => { + cy.viewport(1920, 2000); + cy.getAndStoreAppSettings(); + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); }); @@ -25,11 +30,15 @@ context('App settings tests', () => { initialDBData.getFormats().dateTimeFormat ); - cy.get('body').type('{esc}'); + cy.get('[data-cy="close-modal-btn"]').click(); cy.get('[data-cy="officer-menu-items"]').contains('Settings').click(); cy.get('[data-cy="officer-menu-items"]').contains('App settings').click(); + cy.get('[data-cy="settings-table"]') + .find('button[aria-label="Next Page"]') + .click(); + cy.get('[data-cy="settings-table"]') .contains(initialDBData.settings.dateTimeFormat.id) .parent() @@ -73,5 +82,46 @@ context('App settings tests', () => { newDateTimeFormat ); }); + + it('Instrument Scientist filter should differ based on setting value', function () { + if (featureFlags.getEnabledFeatures().get(FeatureId.EXTERNAL_AUTH)) { + //temporarily skipping, until instr sci login is enabled + this.skip(); + } + const scientist2 = initialDBData.users.user2; + + cy.updateUserRoles({ + id: scientist2.id, + + roles: [initialDBData.roles.instrumentScientist], + }); + + cy.login(scientist2); + + cy.visit('/'); + + cy.log( + 'hello' + JSON.stringify(initialDBData.getFormats().reviewerFilter) + ); + + cy.contains('Proposals'); + + if (initialDBData.getFormats().reviewerFilter === 'ALL') { + cy.get('[data-cy="reviewer-filter"] input').should( + 'have.value', + ReviewerFilter.ALL + ); + } else { + cy.get('[data-cy="reviewer-filter"] input').should( + 'have.value', + ReviewerFilter.ME + ); + } + if (initialDBData.getFormats().statusFilter === 'ALL') { + cy.get('[data-cy="status-filter"] input').should('have.value', 0); + } else { + cy.get('[data-cy="status-filter"] input').should('have.value', 2); + } + }); }); }); diff --git a/cypress/integration/calls.ts b/cypress/integration/calls.ts index 56d0a5a12..3fc93be45 100644 --- a/cypress/integration/calls.ts +++ b/cypress/integration/calls.ts @@ -1,11 +1,13 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { DateTime } from 'luxon'; import { AllocationTimeUnits, CreateInstrumentMutationVariables, + FeatureId, TemplateGroupId, } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; context('Calls tests', () => { @@ -74,6 +76,7 @@ context('Calls tests', () => { }; beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); cy.createTemplate({ groupId: TemplateGroupId.PROPOSAL_ESI, @@ -110,6 +113,7 @@ context('Calls tests', () => { describe('Call basic tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.login('officer'); cy.visit('/'); }); @@ -180,8 +184,10 @@ context('Calls tests', () => { .contains(initialDBData.template.name) .click(); - cy.get('[data-cy="call-esi-template"]').click(); - cy.get('[role="presentation"]').contains(esiTemplateName).click(); + if (featureFlags.getEnabledFeatures().get(FeatureId.RISK_ASSESSMENT)) { + cy.get('[data-cy="call-esi-template"]').click(); + cy.get('[role="presentation"]').contains(esiTemplateName).click(); + } cy.get('[data-cy="call-workflow"]').click(); cy.get('[role="presentation"]').contains(proposalWorkflow.name).click(); @@ -291,8 +297,10 @@ context('Calls tests', () => { cy.get('[data-cy="call-template"]').click(); cy.get('[role="presentation"]').contains(templateName).click(); - cy.get('[data-cy="call-esi-template"]').click(); - cy.get('[role="presentation"]').contains(esiTemplateName).click(); + if (featureFlags.getEnabledFeatures().get(FeatureId.RISK_ASSESSMENT)) { + cy.get('[data-cy="call-esi-template"]').click(); + cy.get('[role="presentation"]').contains(esiTemplateName).click(); + } cy.get('#proposalWorkflowId-input').click(); @@ -321,6 +329,43 @@ context('Calls tests', () => { .should('include.text', '0'); }); + it('A user-officer should be able to add SEPs to a call', () => { + cy.createCall({ + ...newCall, + esiTemplateId: esiTemplateId, + proposalWorkflowId: workflowId, + }); + + cy.contains('Calls').click(); + + cy.contains(newCall.shortCode) + .parent() + .find('[aria-label="Edit"]') + .click(); + + cy.finishedLoading(); + cy.get('[data-cy="call-template"] input').should( + 'have.value', + initialDBData.template.name + ); + cy.get('[data-cy="next-step"]').click(); + + cy.get('[data-cy="call-seps"]').click(); + + cy.get('[data-cy="call-seps-options"]').click(); + + cy.contains(initialDBData.sep.code).click(); + + cy.get('[data-cy="next-step"]').click(); + cy.get('[data-cy="submit"]').click(); + + cy.finishedLoading(); + + cy.notification({ variant: 'success', text: 'successfully' }); + + cy.contains(newCall.shortCode).parent().find('td').last().contains('1'); + }); + it('A user-officer should be able to edit a call', () => { const { shortCode, startDate, endDate } = updatedCall; const updatedCallStartDate = startDate.toFormat( @@ -391,6 +436,7 @@ context('Calls tests', () => { let createdInstrumentId: number; beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.login('officer'); cy.createCall({ ...newCall, diff --git a/cypress/integration/eventLogs.ts b/cypress/integration/eventLogs.ts index 256ca3182..a52eba31e 100644 --- a/cypress/integration/eventLogs.ts +++ b/cypress/integration/eventLogs.ts @@ -1,11 +1,17 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { DateTime } from 'luxon'; -import { UpdateUserMutationVariables, User } from '../../src/generated/sdk'; +import { + FeatureId, + UpdateUserMutationVariables, + User, +} from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; context('Event log tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); }); @@ -44,7 +50,10 @@ context('Event log tests', () => { }); describe('User event logs', () => { - beforeEach(() => { + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.USER_MANAGEMENT)) { + this.skip(); + } cy.login('user'); }); diff --git a/cypress/integration/experiments.ts b/cypress/integration/experiments.ts index be1d6940a..658c37f1b 100644 --- a/cypress/integration/experiments.ts +++ b/cypress/integration/experiments.ts @@ -1,13 +1,18 @@ +import { FeatureId } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; context('Experiments tests', () => { - before(() => { + beforeEach(() => { cy.resetDB(true); + cy.getAndStoreFeaturesEnabled(); }); - beforeEach(() => { + beforeEach(function () { cy.viewport(1920, 1080); - cy.resetDB(true); + if (!featureFlags.getEnabledFeatures().get(FeatureId.SCHEDULER)) { + this.skip(); + } cy.updateProposalManagementDecision({ proposalPk: initialDBData.proposal.id, statusId: 1, diff --git a/cypress/integration/features.ts b/cypress/integration/features.ts index 382abc4ba..27e109fcc 100644 --- a/cypress/integration/features.ts +++ b/cypress/integration/features.ts @@ -2,6 +2,7 @@ import initialDBData from '../support/initialDBData'; context('Features tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); }); diff --git a/cypress/integration/generalSeps.ts b/cypress/integration/generalSeps.ts index e257c204d..907099202 100644 --- a/cypress/integration/generalSeps.ts +++ b/cypress/integration/generalSeps.ts @@ -1,6 +1,7 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; -import { UserRole } from '../../src/generated/sdk'; +import { FeatureId, UserRole } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; function searchMuiTableAsync(search: string) { @@ -28,6 +29,7 @@ const sep2 = { context('General scientific evaluation panel tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); }); @@ -43,7 +45,10 @@ context('General scientific evaluation panel tests', () => { }); describe('SEP basic tests as user officer role', () => { - beforeEach(() => { + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.SEP_REVIEW)) { + this.skip(); + } cy.login('officer'); cy.visit('/'); }); @@ -156,7 +161,10 @@ context('General scientific evaluation panel tests', () => { describe('SEP members manipulation tests as user officer role', () => { let createdSepId: number; - beforeEach(() => { + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.SEP_REVIEW)) { + this.skip(); + } cy.login('officer'); cy.visit('/'); cy.createSep({ @@ -390,7 +398,10 @@ context('General scientific evaluation panel tests', () => { describe('SEP tests as SEP Chair role', () => { let createdSepId: number; - beforeEach(() => { + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.SEP_REVIEW)) { + this.skip(); + } cy.updateUserRoles({ id: sepMembers.chair.id, roles: [initialDBData.roles.user, initialDBData.roles.sepReviewer], @@ -502,7 +513,10 @@ context('General scientific evaluation panel tests', () => { }); describe('SEP tests as SEP Secretary', () => { - beforeEach(() => { + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.SEP_REVIEW)) { + this.skip(); + } cy.updateUserRoles({ id: sepMembers.secretary.id, roles: [initialDBData.roles.user, initialDBData.roles.sepReviewer], diff --git a/cypress/integration/generic_templates.ts b/cypress/integration/generic_templates.ts index 7e6d96b9d..17506496e 100644 --- a/cypress/integration/generic_templates.ts +++ b/cypress/integration/generic_templates.ts @@ -1,13 +1,12 @@ -import faker from 'faker'; -import { DateTime } from 'luxon'; +import { faker } from '@faker-js/faker'; import { - AllocationTimeUnits, DataType, TemplateCategoryId, TemplateGroupId, } from '../../src/generated/sdk'; import initialDBData from '../support/initialDBData'; +import { updatedCall } from '../support/utils'; function twoFakes(numberWords: number) { return [faker.lorem.words(numberWords), faker.lorem.words(numberWords)]; @@ -28,33 +27,13 @@ context('GenericTemplates tests', () => { description: faker.random.words(5), }; - const currentDayStart = DateTime.now().startOf('day'); - - const updatedCall = { - id: initialDBData.call.id, - shortCode: faker.random.alphaNumeric(15), - startCall: DateTime.fromJSDate(faker.date.past()), - endCall: DateTime.fromJSDate(faker.date.future()), - startReview: currentDayStart, - endReview: currentDayStart, - startSEPReview: currentDayStart, - endSEPReview: currentDayStart, - startNotify: currentDayStart, - endNotify: currentDayStart, - startCycle: currentDayStart, - endCycle: currentDayStart, - templateName: initialDBData.template.name, - allocationTimeUnit: AllocationTimeUnits.DAY, - cycleComment: faker.lorem.word(10), - surveyComment: faker.lorem.word(10), - }; - let createdTemplateId: number; let createdGenericTemplateId: number; let workflowId: number; let createdQuestion1Id: string; beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); }); @@ -307,6 +286,7 @@ context('GenericTemplates tests', () => { it('Should have different Question lables for different tables', () => { cy.updateCall({ + id: initialDBData.call.id, ...updatedCall, templateId: createdTemplateId, proposalWorkflowId: workflowId, @@ -336,6 +316,7 @@ context('GenericTemplates tests', () => { it('Should be able to create proposal with genericTemplate', () => { cy.updateCall({ + id: initialDBData.call.id, ...updatedCall, templateId: createdTemplateId, proposalWorkflowId: workflowId, @@ -407,11 +388,12 @@ context('GenericTemplates tests', () => { it('Should be able to clone proposal with GenericTemplates', () => { cy.updateCall({ + id: initialDBData.call.id, ...updatedCall, templateId: createdTemplateId, proposalWorkflowId: workflowId, }); - cy.createProposal({ callId: updatedCall.id }).then((result) => { + cy.createProposal({ callId: initialDBData.call.id }).then((result) => { if (result.createProposal.proposal) { cy.updateProposal({ proposalPk: result.createProposal.proposal.primaryKey, @@ -471,11 +453,12 @@ context('GenericTemplates tests', () => { it('User should not be able to submit proposal with unfinished genericTemplate', () => { cy.updateCall({ + id: initialDBData.call.id, ...updatedCall, templateId: createdTemplateId, proposalWorkflowId: workflowId, }); - cy.createProposal({ callId: updatedCall.id }); + cy.createProposal({ callId: initialDBData.call.id }); cy.login('user'); cy.visit('/'); @@ -532,11 +515,12 @@ context('GenericTemplates tests', () => { it('Officer should able to delete proposal with genericTemplate', () => { cy.updateCall({ + id: initialDBData.call.id, ...updatedCall, templateId: createdTemplateId, proposalWorkflowId: workflowId, }); - cy.createProposal({ callId: updatedCall.id }).then((result) => { + cy.createProposal({ callId: initialDBData.call.id }).then((result) => { if (result.createProposal.proposal) { cy.updateProposal({ proposalPk: result.createProposal.proposal.primaryKey, diff --git a/cypress/integration/institutions.ts b/cypress/integration/institutions.ts index 76ebe738a..08fdcea52 100644 --- a/cypress/integration/institutions.ts +++ b/cypress/integration/institutions.ts @@ -1,9 +1,18 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; + +import { FeatureId } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; context('Institution tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); }); + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.USER_MANAGEMENT)) { + this.skip(); + } + }); it('User should not be able to see Institutions page', () => { cy.login('user'); diff --git a/cypress/integration/instruments.ts b/cypress/integration/instruments.ts index 66de60d16..54034a534 100644 --- a/cypress/integration/instruments.ts +++ b/cypress/integration/instruments.ts @@ -1,6 +1,11 @@ -import faker from 'faker'; - -import { ReviewerFilter, TechnicalReviewStatus } from '../../src/generated/sdk'; +import { faker } from '@faker-js/faker'; + +import { + FeatureId, + ReviewerFilter, + TechnicalReviewStatus, +} from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; const selectAllProposalsFilterStatus = () => { @@ -37,6 +42,7 @@ context('Instrument tests', () => { }; beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); }); @@ -61,7 +67,10 @@ context('Instrument tests', () => { }); }); - it('User officer should be able to create instrument', () => { + it('User officer should be able to create instrument', function () { + if (featureFlags.getEnabledFeatures().get(FeatureId.EXTERNAL_AUTH)) { + this.skip(); + } cy.contains('Instruments').click(); cy.contains('Create').click(); cy.get('#name').type(instrument1.name); @@ -275,7 +284,10 @@ context('Instrument tests', () => { }); }); - it('User Officer should be able to see who submitted the technical review', () => { + it('User Officer should be able to see who submitted the technical review', function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.TECHNICAL_REVIEW)) { + this.skip(); + } cy.assignScientistsToInstrument({ instrumentId: createdInstrumentId, scientistIds: [scientist2.id], @@ -320,7 +332,10 @@ context('Instrument tests', () => { ); }); - it('User Officer should be able to re-open submitted technical review', () => { + it('User Officer should be able to re-open submitted technical review', function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.TECHNICAL_REVIEW)) { + this.skip(); + } cy.assignScientistsToInstrument({ instrumentId: createdInstrumentId, scientistIds: [scientist2.id], @@ -405,7 +420,10 @@ context('Instrument tests', () => { ); }); - it('User Officer should be able to see proposal instrument scientist and re-assign technical reviewer', () => { + it('User Officer should be able to see proposal instrument scientist and re-assign technical reviewer', function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.TECHNICAL_REVIEW)) { + this.skip(); + } const numberOfScientistsAndManagerAssignedToCreatedInstrument = 2; cy.assignScientistsToInstrument({ instrumentId: createdInstrumentId, @@ -518,7 +536,10 @@ context('Instrument tests', () => { let createdProposalPk: number; let createdProposalId: string; - beforeEach(() => { + beforeEach(function () { + if (featureFlags.getEnabledFeatures().get(FeatureId.EXTERNAL_AUTH)) { + this.skip(); + } cy.updateUserRoles({ id: scientist2.id, roles: [initialDBData.roles.instrumentScientist], @@ -822,6 +843,39 @@ context('Instrument tests', () => { cy.contains('20'); }); + it('Instrument scientists should be able to see but not modify the management decision', () => { + cy.contains('Proposals'); + + selectAllProposalsFilterStatus(); + + cy.contains(proposal1.title) + .parent() + .find('[data-cy="edit-technical-review"]') + .click(); + cy.get('[role="dialog"]').as('dialog'); + cy.finishedLoading(); + cy.get('@dialog').contains('Admin').click(); + + cy.get('@dialog') + .find('[data-cy="proposal-final-status"] input') + .should('be.disabled'); + cy.get('@dialog') + .find('[data-cy="managementTimeAllocation"] input') + .should('be.disabled'); + cy.get('@dialog') + .find('[data-cy="commentForUser"] textarea') + .should('be.disabled'); + cy.get('@dialog') + .find('[data-cy="commentForManagement"] textarea') + .should('be.disabled'); + cy.get('@dialog') + .find('[data-cy="is-management-decision-submitted"] input') + .should('be.disabled'); + cy.get('@dialog') + .find('[data-cy="save-admin-decision"]') + .should('be.disabled'); + }); + it('Technical review assignee should see edit icon if assigned to review a proposal and review is not submitted', () => { selectAllProposalsFilterStatus(); diff --git a/cypress/integration/mobileViews.ts b/cypress/integration/mobileViews.ts index 422632d32..50f5eeb71 100644 --- a/cypress/integration/mobileViews.ts +++ b/cypress/integration/mobileViews.ts @@ -1,5 +1,6 @@ context('Mobile views tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); cy.viewport('iphone-x'); }); diff --git a/cypress/integration/pages.ts b/cypress/integration/pages.ts index ec2e57306..15aead0af 100644 --- a/cypress/integration/pages.ts +++ b/cypress/integration/pages.ts @@ -1,7 +1,8 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; context('Page tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); }); diff --git a/cypress/integration/pdf_templates.ts b/cypress/integration/pdf_templates.ts new file mode 100644 index 000000000..e5d013101 --- /dev/null +++ b/cypress/integration/pdf_templates.ts @@ -0,0 +1,143 @@ +import { faker } from '@faker-js/faker'; + +import { TemplateGroupId } from '../../src/generated/sdk'; + +context('PDF template tests', () => { + const templateName = faker.lorem.words(3); + const templateDesc = faker.lorem.words(3); + const pdfTemplateData = faker.lorem.paragraphs(10); + + let createdTemplateName: string; + + beforeEach(() => { + cy.resetDB(); + cy.viewport(1920, 1080); + cy.getAndStoreFeaturesEnabled(); + }); + + describe('PDF template basic tests', () => { + it('User officer can create a PDF template', () => { + cy.login('officer'); + cy.visit('/'); + + cy.navigateToTemplatesSubmenu('PDF'); + + cy.get('[data-cy=create-new-button]').click(); + + cy.get('[data-cy="name"] input') + .first() + .type(templateName) + .should('have.value', templateName); + + cy.get('[data-cy="description"] textarea') + .first() + .type(templateDesc) + .should('have.value', templateDesc); + + cy.get('[data-cy=submit]').click(); + + cy.contains(templateName); + + cy.get('[data-cy="template-data"] textarea') + .first() + .type(pdfTemplateData) + .should('have.value', pdfTemplateData); + + cy.get('[data-cy=submit]').click(); + + cy.notification({ variant: 'success', text: 'successfully' }); + + cy.navigateToTemplatesSubmenu('PDF'); + + cy.contains(templateName); + }); + }); + + describe('PDF template advanced tests', () => { + beforeEach(() => { + cy.createTemplate({ + name: templateName, + groupId: TemplateGroupId.PDF_TEMPLATE, + }).then((result) => { + if (result.createTemplate.template) { + createdTemplateName = result.createTemplate.template.name; + } + }); + }); + + it('User officer can modify PDF template', () => { + cy.login('officer'); + cy.visit('/'); + + cy.navigateToTemplatesSubmenu('PDF'); + + cy.contains(createdTemplateName) + .parent() + .find("[aria-label='Edit']") + .click(); + + cy.contains(createdTemplateName).should('exist'); + + cy.get('[data-cy="template-data"] textarea') + .first() + .type(pdfTemplateData) + .should('have.value', pdfTemplateData); + + cy.get('[data-cy=submit]').click(); + + cy.notification({ variant: 'success', text: 'successfully' }); + + cy.navigateToTemplatesSubmenu('PDF'); + + cy.contains(createdTemplateName) + .parent() + .find("[aria-label='Edit']") + .click(); + + cy.contains(createdTemplateName); + + cy.contains(pdfTemplateData.replace(/\n|\r/g, ' ')).should('exist'); + }); + + it('User officer can clone PDF template', () => { + cy.login('officer'); + cy.visit('/'); + + cy.navigateToTemplatesSubmenu('PDF'); + + cy.contains(createdTemplateName) + .parent() + .find("[aria-label='Edit']") + .click(); + + cy.contains(createdTemplateName).should('exist'); + + cy.get('[data-cy="template-data"] textarea') + .first() + .type(pdfTemplateData) + .should('have.value', pdfTemplateData); + + cy.get('[data-cy=submit]').click(); + + cy.notification({ variant: 'success', text: 'successfully' }); + + cy.navigateToTemplatesSubmenu('PDF'); + + cy.contains(createdTemplateName) + .parent() + .find("[aria-label='Clone']") + .click(); + + cy.contains('Yes').click(); + + cy.contains(`Copy of ${createdTemplateName}`) + .parent() + .find("[aria-label='Edit']") + .click(); + + cy.contains(`Copy of ${createdTemplateName}`).should('exist'); + + cy.contains(pdfTemplateData.replace(/\n|\r/g, ' ')).should('exist'); + }); + }); +}); diff --git a/cypress/integration/peopleTable.ts b/cypress/integration/peopleTable.ts index 1776b7d23..625bca7c9 100644 --- a/cypress/integration/peopleTable.ts +++ b/cypress/integration/peopleTable.ts @@ -1,5 +1,7 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; +import { FeatureId } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; context('PageTable component tests', () => { @@ -8,8 +10,14 @@ context('PageTable component tests', () => { const abstract = faker.random.words(8); beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); }); + beforeEach(function () { + if (featureFlags.getEnabledFeatures().get(FeatureId.EXTERNAL_AUTH)) { + this.skip(); + } + }); describe('ProposalPeopleTable component Preserve selected users', () => { it('Should add a new collaborator and that collaborator should stay as suggestion in the collaborators list', () => { diff --git a/cypress/integration/personal_information.ts b/cypress/integration/personal_information.ts index fa121f719..0ee96acf8 100644 --- a/cypress/integration/personal_information.ts +++ b/cypress/integration/personal_information.ts @@ -1,9 +1,12 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; +import { FeatureId } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; context('Personal information tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); }); @@ -16,179 +19,187 @@ context('Personal information tests', () => { const newPosition = faker.random.word().split(' ')[0]; const newTelephone = faker.phone.phoneNumber('0##########'); - it('Should be able update personal information', () => { - cy.login('user'); + it('Should be able to see user officer role in use', () => { + cy.updateUserRoles({ + id: initialDBData.users.userOfficer.id, + roles: [initialDBData.roles.userOfficer, initialDBData.roles.sepChair], + }); + cy.login('officer'); cy.visit('/'); - cy.get('[data-cy="active-user-profile"]').click(); + cy.get("[data-cy='profile-page-btn']").click(); - cy.get("[name='firstname']").clear().type(newFirstName); + cy.contains('Roles').click(); - cy.get("[name='middlename']").clear().type(newMiddleName); + cy.finishedLoading(); - cy.get("[name='lastname']").clear().type(newLastName); + cy.contains('User roles'); - cy.get("[name='preferredname']").clear().type(newPreferredName); + cy.get("[data-cy='role-selection-table'] table tbody tr").should( + (element) => { + expect(element.text()).to.contain('User Officer'); - cy.get("[name='position']").clear().type(newPosition); + expect(element.text()).to.contain('In Use'); + } + ); + }); - cy.get("[name='department']").clear().type(newDepartment); + describe('Personal information advanced tests', () => { + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.USER_MANAGEMENT)) { + this.skip(); + } + }); - cy.get("[name='telephone']").clear().type(newTelephone); + it('Should be able update personal information', () => { + cy.login('user'); + cy.visit('/'); - cy.get("[name='otherOrganisation']").clear().type(otherOrg); + cy.get('[data-cy="active-user-profile"]').click(); - cy.get('[data-cy="organizationCountry"] input').click(); - cy.get('[data-cy="organizationCountry-options"]').first().click(); + cy.get("[name='firstname']").clear().type(newFirstName); - cy.contains('Update Profile').click(); + cy.get("[name='middlename']").clear().type(newMiddleName); - cy.notification({ variant: 'success', text: 'Updated Information' }); + cy.get("[name='lastname']").clear().type(newLastName); - cy.reload(); + cy.get("[name='preferredname']").clear().type(newPreferredName); - cy.get("[name='firstname']").invoke('val').should('eq', newFirstName); + cy.get("[name='position']").clear().type(newPosition); - cy.get("[name='middlename']").invoke('val').should('eq', newMiddleName); + cy.get("[name='department']").clear().type(newDepartment); - cy.get("[name='lastname']").invoke('val').should('eq', newLastName); + cy.get("[name='telephone']").clear().type(newTelephone); - cy.get("[name='preferredname']") - .invoke('val') - .should('eq', newPreferredName); + cy.get("[name='otherOrganisation']").clear().type(otherOrg); - cy.get("[name='position']").invoke('val').should('eq', newPosition); + cy.get('[data-cy="organizationCountry"] input').click(); + cy.get('[data-cy="organizationCountry-options"]').first().click(); - cy.get("[name='department']").invoke('val').should('eq', newDepartment); + cy.contains('Update Profile').click(); - cy.get("[name='telephone']").invoke('val').should('eq', newTelephone); - }); + cy.notification({ variant: 'success', text: 'Updated Information' }); - it('User Officer should be able to see all and change roles if there are multiple', () => { - cy.login('officer'); - cy.visit('/'); + cy.reload(); - cy.contains('People').click(); + cy.get("[name='firstname']").invoke('val').should('eq', newFirstName); - cy.finishedLoading(); + cy.get("[name='middlename']").invoke('val').should('eq', newMiddleName); - cy.contains('Andersson') - .parent() - .find('button[aria-label="Edit user"]') - .click(); + cy.get("[name='lastname']").invoke('val').should('eq', newLastName); - cy.get('main').as('mainContentElement'); - cy.get('@mainContentElement').contains('Settings').click(); + cy.get("[name='preferredname']") + .invoke('val') + .should('eq', newPreferredName); - cy.finishedLoading(); + cy.get("[name='position']").invoke('val').should('eq', newPosition); - cy.get('[data-cy="add-role-button"]').click(); + cy.get("[name='department']").invoke('val').should('eq', newDepartment); - cy.finishedLoading(); + cy.get("[name='telephone']").invoke('val').should('eq', newTelephone); + }); - cy.get('[data-cy="role-modal"]') - .contains('SEP Chair') - .parent() - .find('input[type="checkbox"]') - .click(); + it('User Officer should be able to see all and change roles if there are multiple', () => { + cy.login('officer'); + cy.visit('/'); - cy.contains('Update').click(); + cy.contains('People').click(); - cy.notification({ variant: 'warning', text: 'successfully' }); + cy.finishedLoading(); - // wait before trying to get profile button otherwise page - // might re-render and you could be trying to access element - // that is not attached to the DOM - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(2000); + cy.contains('Andersson') + .parent() + .find('button[aria-label="Edit user"]') + .click(); - cy.finishedLoading(); + cy.get('main').as('mainContentElement'); + cy.get('@mainContentElement').contains('Settings').click(); - cy.get("[data-cy='profile-page-btn']").click(); + cy.finishedLoading(); - cy.get('[role="menu"]').contains('Roles').click(); + cy.get('[data-cy="add-role-button"]').click(); - cy.finishedLoading(); + cy.finishedLoading(); - cy.get('[data-cy="role-selection-table"]').contains('User roles'); + cy.get('[data-cy="role-modal"]') + .contains('SEP Chair') + .parent() + .find('input[type="checkbox"]') + .click(); - cy.get('[data-cy="role-selection-table"]') - .contains('SEP Chair', { matchCase: false }) - .parent() - .find('button') - .click(); + cy.contains('Update').click(); - cy.finishedLoading(); + cy.notification({ variant: 'warning', text: 'successfully' }); - cy.contains('Proposals to grade'); + // wait before trying to get profile button otherwise page + // might re-render and you could be trying to access element + // that is not attached to the DOM + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(2000); - cy.get('[data-cy="SEPRoles-menu-items"]') - .find('.MuiListItem-root') - .should('have.length', 2); - }); + cy.finishedLoading(); - it('Should be able to see user officer role in use', () => { - cy.updateUserRoles({ - id: initialDBData.users.userOfficer.id, - roles: [initialDBData.roles.userOfficer, initialDBData.roles.sepChair], - }); - cy.login('officer'); - cy.visit('/'); + cy.get("[data-cy='profile-page-btn']").click(); - cy.get("[data-cy='profile-page-btn']").click(); + cy.get('[role="menu"]').contains('Roles').click(); - cy.contains('Roles').click(); + cy.finishedLoading(); - cy.finishedLoading(); + cy.get('[data-cy="role-selection-table"]').contains('User roles'); - cy.contains('User roles'); + cy.get('[data-cy="role-selection-table"]') + .contains('SEP Chair', { matchCase: false }) + .parent() + .find('button') + .click(); - cy.get("[data-cy='role-selection-table'] table tbody tr") - .first() - .should((element) => { - expect(element.text()).to.contain('User Officer'); + cy.finishedLoading(); - expect(element.text()).to.contain('In Use'); - }); - }); + cy.contains('Proposals to grade'); - it('Should be able to change role even in the view where next role is not allowed to be', () => { - cy.updateUserRoles({ - id: initialDBData.users.userOfficer.id, - roles: [initialDBData.roles.userOfficer, initialDBData.roles.sepChair], + cy.get('[data-cy="SEPRoles-menu-items"]') + .find('.MuiListItem-root') + .should('have.length', 2); }); - const workflowName = faker.lorem.words(2); - const workflowDescription = faker.lorem.words(5); - cy.login('officer'); - cy.visit('/'); - cy.contains('Settings').click(); - cy.contains('Proposal workflows').click(); + it('Should be able to change role even in the view where next role is not allowed to be', () => { + cy.updateUserRoles({ + id: initialDBData.users.userOfficer.id, + roles: [initialDBData.roles.userOfficer, initialDBData.roles.sepChair], + }); + const workflowName = faker.lorem.words(2); + const workflowDescription = faker.lorem.words(5); + cy.login('officer'); + cy.visit('/'); - cy.contains('Create').click(); - cy.get('#name').type(workflowName); - cy.get('#description').type(workflowDescription); - cy.get('[data-cy="submit"]').click(); + cy.contains('Settings').click(); + cy.contains('Proposal workflows').click(); - cy.notification({ variant: 'success', text: 'created successfully' }); + cy.contains('Create').click(); + cy.get('#name').type(workflowName); + cy.get('#description').type(workflowDescription); + cy.get('[data-cy="submit"]').click(); - cy.get('[data-cy^="connection_DRAFT_1"]').should('contain.text', 'DRAFT'); + cy.notification({ variant: 'success', text: 'created successfully' }); - cy.get("[data-cy='profile-page-btn']").click(); + cy.get('[data-cy^="connection_DRAFT_1"]').should('contain.text', 'DRAFT'); - cy.contains('Roles').click(); + cy.get("[data-cy='profile-page-btn']").click(); - cy.finishedLoading(); + cy.contains('Roles').click(); - cy.contains('User roles'); + cy.finishedLoading(); - cy.contains('SEP Chair', { matchCase: false }) - .parent() - .find('button') - .click(); + cy.contains('User roles'); - cy.finishedLoading(); + cy.contains('SEP Chair', { matchCase: false }) + .parent() + .find('button') + .click(); + + cy.finishedLoading(); - cy.get('[data-cy="SEPRoles-menu-items"]').should('exist'); + cy.get('[data-cy="SEPRoles-menu-items"]').should('exist'); + }); }); }); diff --git a/cypress/integration/proposal_administration.ts b/cypress/integration/proposal_administration.ts index ec79b2722..2495249f5 100644 --- a/cypress/integration/proposal_administration.ts +++ b/cypress/integration/proposal_administration.ts @@ -1,6 +1,8 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { DateTime } from 'luxon'; +import { FeatureId } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; context('Proposal administration tests', () => { @@ -16,6 +18,7 @@ context('Proposal administration tests', () => { const existingQuestionaryId = 1; beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); }); @@ -44,7 +47,10 @@ context('Proposal administration tests', () => { cy.visit('/'); }); - it('Should be able to set comment for user/manager and final status', () => { + it('Should be able to set comment for user/manager and final status', function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.TECHNICAL_REVIEW)) { + this.skip(); + } cy.contains('Proposals').click(); cy.get('[data-cy=view-proposal]').click(); @@ -197,7 +203,9 @@ context('Proposal administration tests', () => { cy.contains(proposalName1).parent().contains('No'); - cy.logout(); + if (!featureFlags.getEnabledFeatures().get(FeatureId.EXTERNAL_AUTH)) { + cy.logout(); + } cy.login('user'); cy.visit('/'); @@ -213,7 +221,10 @@ context('Proposal administration tests', () => { cy.contains('Submit').parent().should('not.be.disabled'); }); - it('If you select a tab in tabular view and reload the page it should stay on specific selected tab', () => { + it('If you select a tab in tabular view and reload the page it should stay on specific selected tab', function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.TECHNICAL_REVIEW)) { + this.skip(); + } cy.contains('Proposals').click(); cy.get('[data-cy=view-proposal]').click(); @@ -268,7 +279,11 @@ context('Proposal administration tests', () => { ); }); - it('Should be able to download proposal pdf', () => { + it('Should be able to download proposal pdf', function () { + if (featureFlags.getEnabledFeatures().get(FeatureId.EXTERNAL_AUTH)) { + //temporarily skipping, until issue is fixed on github actions + this.skip(); + } cy.contains('Proposals').click(); cy.request({ @@ -402,7 +417,10 @@ context('Proposal administration tests', () => { cy.get('table tbody tr').eq(0).contains(proposalFixedName); }); - it('User officer should see Reviews tab before doing the Admin(management decision)', () => { + it('User officer should see Reviews tab before doing the Admin(management decision)', function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.TECHNICAL_REVIEW)) { + this.skip(); + } cy.contains('Proposals').click(); cy.finishedLoading(); diff --git a/cypress/integration/proposal_esi.ts b/cypress/integration/proposal_esi.ts index 9062730c0..37d37d7b7 100644 --- a/cypress/integration/proposal_esi.ts +++ b/cypress/integration/proposal_esi.ts @@ -1,5 +1,7 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; +import { FeatureId } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; const coProposer = initialDBData.users.user2; @@ -17,6 +19,7 @@ const clonedSampleTitle = faker.lorem.words(2); context('visits tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(true); cy.updateProposal({ proposalPk: existingProposalId, @@ -36,6 +39,12 @@ context('visits tests', () => { }); }); + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.RISK_ASSESSMENT)) { + this.skip(); + } + }); + it('PI should see ESI assessment button ', () => { cy.login(PI); cy.visit('/'); diff --git a/cypress/integration/proposals.ts b/cypress/integration/proposals.ts index 0edd3b666..fe6ffa9dd 100644 --- a/cypress/integration/proposals.ts +++ b/cypress/integration/proposals.ts @@ -1,12 +1,14 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { DateTime } from 'luxon'; import { AllocationTimeUnits, DataType, + FeatureId, TemplateCategoryId, TemplateGroupId, } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; context('Proposal tests', () => { @@ -83,6 +85,7 @@ context('Proposal tests', () => { describe('Proposal basic tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); cy.createTemplate({ name: 'default esi template', @@ -211,7 +214,10 @@ context('Proposal tests', () => { cy.contains(proposalTitleUpdated); }); - it('User officer should be able to save proposal column selection', () => { + it('User officer should be able to save proposal column selection', function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.SEP_REVIEW)) { + this.skip(); + } cy.login('officer'); cy.visit('/'); @@ -233,7 +239,10 @@ context('Proposal tests', () => { cy.contains('SEP'); }); - it('Should be able to see proposal allocation time unit on the proposal', () => { + it('Should be able to see proposal allocation time unit on the proposal', function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.TECHNICAL_REVIEW)) { + this.skip(); + } cy.login('officer'); cy.visit('/'); @@ -549,6 +558,7 @@ context('Proposal tests', () => { describe('Proposal advanced tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(true); }); diff --git a/cypress/integration/questions.ts b/cypress/integration/questions.ts index eb6a55e07..5099c023c 100644 --- a/cypress/integration/questions.ts +++ b/cypress/integration/questions.ts @@ -1,4 +1,4 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { DataType, TemplateCategoryId } from '../../src/generated/sdk'; import initialDBData from '../support/initialDBData'; @@ -8,6 +8,7 @@ context('Questions tests', () => { const samplesQuestion = initialDBData.questions.addSamples.text; beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(true); cy.createQuestion({ diff --git a/cypress/integration/samples.ts b/cypress/integration/samples.ts index 4e879ab66..bd9dfcebb 100644 --- a/cypress/integration/samples.ts +++ b/cypress/integration/samples.ts @@ -1,16 +1,18 @@ -import faker from 'faker'; -import { DateTime } from 'luxon'; +import { faker } from '@faker-js/faker'; import { - AllocationTimeUnits, DataType, + FeatureId, TemplateCategoryId, TemplateGroupId, } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; +import { updatedCall } from '../support/utils'; context('Samples tests', () => { const existingUser = initialDBData.users.user1; + const booleanQuestion = faker.lorem.words(3); const proposalTemplateName = faker.lorem.words(2); const sampleTemplateName = faker.lorem.words(2); const sampleTemplateDescription = faker.lorem.words(4); @@ -24,25 +26,6 @@ context('Samples tests', () => { description: faker.random.words(5), }; - const currentDayStart = DateTime.now().startOf('day'); - - const updatedCall = { - id: initialDBData.call.id, - shortCode: faker.random.alphaNumeric(15), - startCall: faker.date.past().toISOString().slice(0, 10), - endCall: faker.date.future().toISOString().slice(0, 10), - startReview: currentDayStart, - endReview: currentDayStart, - startSEPReview: currentDayStart, - endSEPReview: currentDayStart, - startNotify: currentDayStart, - endNotify: currentDayStart, - startCycle: currentDayStart, - endCycle: currentDayStart, - allocationTimeUnit: AllocationTimeUnits.DAY, - cycleComment: faker.lorem.word(10), - surveyComment: faker.lorem.word(10), - }; let createdWorkflowId: number; let createdSampleTemplateId: number; let createdSampleQuestionId: string; @@ -119,10 +102,32 @@ context('Samples tests', () => { }); } }); + + cy.createQuestion({ + categoryId: TemplateCategoryId.PROPOSAL_QUESTIONARY, + dataType: DataType.BOOLEAN, + }).then((questionResult) => { + const createdQuestion = + questionResult.createQuestion.question; + if (createdQuestion) { + cy.updateQuestion({ + id: createdQuestion.id, + question: booleanQuestion, + }); + + cy.createQuestionTemplateRelation({ + questionId: createdQuestion.id, + templateId: templateId, + sortOrder: 0, + topicId: topicId, + }); + } + }); } }); cy.updateCall({ + id: initialDBData.call.id, ...updatedCall, proposalWorkflowId: createdWorkflowId, templateId: templateId, @@ -134,6 +139,7 @@ context('Samples tests', () => { }; beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(true); cy.createProposalWorkflow(proposalWorkflow).then((result) => { if (result.createProposalWorkflow.proposalWorkflow) { @@ -290,6 +296,101 @@ context('Samples tests', () => { cy.contains('OK').click(); }); + + it('Should be able to modify sample declaration question and all other questions without loosing information', () => { + createProposalTemplateWithSampleQuestionAndUseTemplateInCall(); + cy.login('user'); + cy.visit('/'); + + cy.contains('new proposal', { matchCase: false }).click(); + cy.get('[data-cy=title] input').type(proposalTitle); + + cy.get('[data-cy=abstract] textarea').first().type(proposalTitle); + + cy.contains('Save and continue').click(); + + cy.finishedLoading(); + + cy.get('[data-cy=add-button]').click(); + + cy.get('[data-cy=title-input] input').clear(); + + cy.get( + '[data-cy=sample-declaration-modal] [data-cy=save-and-continue-button]' + ).click(); + + cy.contains('This is a required field'); + + cy.get('[data-cy=title-input] input') + .clear() + .type(sampleTitle) + .should('have.value', sampleTitle); + + cy.get( + '[data-cy=sample-declaration-modal] [data-cy=save-and-continue-button]' + ).click(); + + cy.finishedLoading(); + + cy.get( + '[data-cy=sample-declaration-modal] [data-cy=save-and-continue-button]' + ).click(); + + cy.finishedLoading(); + + cy.get('[data-cy="questionnaires-list-item"]').should('have.length', 1); + + cy.contains(booleanQuestion) + .parent() + .find('input') + .should('have.value', 'false') + .click(); + + cy.get('[data-cy="questionnaires-list-item"]').should('have.length', 1); + + cy.get('[data-cy="clone"]').click(); + + cy.contains('OK').click(); + + cy.get('[data-cy="questionnaires-list-item"]').should('have.length', 2); + + cy.get('[data-cy="questionnaires-list-item-completed:true"]').should( + 'have.length', + 2 + ); + + cy.contains(booleanQuestion) + .parent() + .find('input') + .should('have.value', 'true') + .click(); + + cy.get('[data-cy="questionnaires-list-item"]').should('have.length', 2); + + cy.get('[data-cy=add-button]').should('be.disabled'); // Add button should be disabled because of max entry limit + + cy.get('[data-cy="delete"]').eq(1).click(); + + cy.contains('OK').click(); + + cy.get('[data-cy="questionnaires-list-item"]').should('have.length', 1); + + cy.contains(booleanQuestion) + .parent() + .find('input') + .should('have.value', 'false') + .click(); + + cy.get('[data-cy="questionnaires-list-item"]').should('have.length', 1); + + cy.get('[data-cy=add-button]').should('not.be.disabled'); + + cy.contains('Save and continue').click(); + + cy.contains('Submit').click(); + + cy.contains('OK').click(); + }); }); describe('Samples advanced tests', () => { @@ -438,7 +539,10 @@ context('Samples tests', () => { cy.contains('OK').click(); }); - it('Officer should be able to evaluate sample', () => { + it('Officer should be able to evaluate sample', function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.SAMPLE_SAFETY)) { + this.skip(); + } cy.createSample({ proposalPk: createdProposalPk, templateId: createdSampleTemplateId, @@ -501,7 +605,10 @@ context('Samples tests', () => { cy.contains('HIGH_RISK'); // test if status has changed }); - it('Download samples is working with dialog window showing up', () => { + it('Download samples is working with dialog window showing up', function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.SAMPLE_SAFETY)) { + this.skip(); + } cy.createSample({ proposalPk: createdProposalPk, templateId: createdSampleTemplateId, @@ -526,7 +633,10 @@ context('Samples tests', () => { ); }); - it('Should be able to download sample pdf', () => { + it('Should be able to download sample pdf', function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.SAMPLE_SAFETY)) { + this.skip(); + } cy.createSample({ proposalPk: createdProposalPk, templateId: createdSampleTemplateId, diff --git a/cypress/integration/scheduler.ts b/cypress/integration/scheduler.ts index 63f72658b..52e6cbe19 100644 --- a/cypress/integration/scheduler.ts +++ b/cypress/integration/scheduler.ts @@ -1,3 +1,5 @@ +import { FeatureId } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; context('Scheduler tests', () => { @@ -9,7 +11,15 @@ context('Scheduler tests', () => { const scientist = initialDBData.users.user1; beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(true); + }); + + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.SCHEDULER)) { + this.skip(); + } + cy.updateUserRoles({ id: scientist.id, roles: [ diff --git a/cypress/integration/settings.ts b/cypress/integration/settings.ts index 28cff1ae2..4f19781be 100644 --- a/cypress/integration/settings.ts +++ b/cypress/integration/settings.ts @@ -1,15 +1,17 @@ -import faker from 'faker'; -import { DateTime } from 'luxon'; +import { faker } from '@faker-js/faker'; import { - AllocationTimeUnits, + FeatureId, TechnicalReviewStatus, TemplateGroupId, } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; +import { updatedCall } from '../support/utils'; context('Settings tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); }); @@ -133,26 +135,6 @@ context('Settings tests', () => { let prevProposalStatusId: number; let createdEsiTemplateId: number; - const currentDayStart = DateTime.now().startOf('day'); - - const updatedCall = { - shortCode: faker.random.alphaNumeric(15), - startCall: faker.date.past().toISOString().slice(0, 10), - endCall: faker.date.future().toISOString().slice(0, 10), - startReview: currentDayStart, - endReview: currentDayStart, - startSEPReview: currentDayStart, - endSEPReview: currentDayStart, - startNotify: currentDayStart, - endNotify: currentDayStart, - startCycle: currentDayStart, - endCycle: currentDayStart, - allocationTimeUnit: AllocationTimeUnits.DAY, - cycleComment: faker.lorem.word(10), - surveyComment: faker.lorem.word(10), - templateId: initialDBData.template.id, - }; - const addMultipleStatusesToProposalWorkflowWithChangingEvents = () => { cy.addProposalWorkflowStatus({ droppableGroupId: workflowDroppableGroupId, @@ -299,6 +281,7 @@ context('Settings tests', () => { ...updatedCall, proposalWorkflowId: workflow.id, esiTemplateId: createdEsiTemplateId, + seps: [initialDBData.sep.id], }); } }); @@ -503,7 +486,10 @@ context('Settings tests', () => { cy.contains('PROPOSAL_SUBMITTED & PROPOSAL_FEASIBLE'); }); - it('Proposal should follow the selected workflow', () => { + it('Proposal should follow the selected workflow', function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.TECHNICAL_REVIEW)) { + this.skip(); + } const internalComment = faker.random.words(2); const publicComment = faker.random.words(2); addMultipleStatusesToProposalWorkflowWithChangingEvents(); @@ -645,7 +631,10 @@ context('Settings tests', () => { cy.contains('SEP_REVIEW'); }); - it('Proposal status should update immediately after all SEP reviews submitted', () => { + it('Proposal status should update immediately after all SEP reviews submitted', function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.SEP_REVIEW)) { + this.skip(); + } addMultipleStatusesToProposalWorkflowWithChangingEvents(); cy.createProposal({ callId: initialDBData.call.id }).then((result) => { const proposal = result.createProposal.proposal; @@ -887,7 +876,10 @@ context('Settings tests', () => { ).should('have.length', 2); }); - it('Proposal should follow multi-column workflow', () => { + it('Proposal should follow multi-column workflow', function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.TECHNICAL_REVIEW)) { + this.skip(); + } const firstProposalTitle = faker.random.words(2); const firstProposalAbstract = faker.random.words(5); const secondProposalTitle = faker.random.words(2); diff --git a/cypress/integration/shipments.ts b/cypress/integration/shipments.ts index 009b19fab..27b045b00 100644 --- a/cypress/integration/shipments.ts +++ b/cypress/integration/shipments.ts @@ -1,5 +1,7 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; +import { FeatureId } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; faker.seed(1); @@ -20,7 +22,14 @@ const shipmentTemplateDescription = faker.lorem.words(3); context('Shipments tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(true); + }); + + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.SHIPPING)) { + this.skip(); + } cy.updateProposalManagementDecision({ proposalPk: existingProposal.id, @@ -53,48 +62,44 @@ context('Shipments tests', () => { const WEIGHT_KEY = 'parcel_weight'; const STORAGE_TEMPERATURE_KEY = 'storage_temperature'; - const IS_FRAGILE_KEY = 'is_fragile'; - const LOCAL_CONTACT_KEY = 'shipment_local_contact'; - const IS_DANGEROUS_KEY = 'is_dangerous'; - - const localContactName = faker.name.firstName(); - const storageOption = faker.lorem.words(3); + const DESCRIPTION_KEY = 'detailed_description_of_content'; + const SENDER_NAME_KEY = 'shipment_sender_name'; + const SENDER_EMAIL_KEY = 'shipment_sender_email'; + const SENDER_PHONE_KEY = 'shipment_sender_phone'; + const SENDER_STREET_ADDRESS_KEY = 'shipment_sender_street_address'; + const SENDER_ZIP_CODE_KEY = 'shipment_sender_zip_code'; + const SENDER_CITY_COUNTRY_KEY = 'shipment_sender_city_country'; + + const shipmentsTemplateFile = 'shipments_template.json'; + + const temp = 'Ambient'; + const description = faker.lorem.words(2); + const name = faker.name.firstName(); + const email = faker.internet.email(); + const phone = faker.phone.phoneNumber(); + const street = faker.address.streetAddress(); + const zip = faker.address.zipCode(); + const city = faker.address.city(); cy.login('officer'); cy.visit('/'); cy.navigateToTemplatesSubmenu('Shipment declaration templates'); - cy.get('[data-cy=create-new-button]').click(); + cy.get('[data-cy=import-template-button]').click(); - cy.get('[data-cy=name] input') - .type(shipmentTemplateName) - .should('have.value', shipmentTemplateName); - - cy.get('[data-cy=description]').type(shipmentTemplateDescription); - - cy.get('[data-cy=submit]').click(); + cy.get('input[type="file"]').attachFixture({ + filePath: shipmentsTemplateFile, + fileName: shipmentsTemplateFile, + mimeType: 'application/json', + }); - cy.createNumberInputQuestion('width', { key: WIDTH_KEY }); - cy.createNumberInputQuestion('height', { key: HEIGHT_KEY }); - cy.createNumberInputQuestion('length', { key: LENGTH_KEY }); - cy.createNumberInputQuestion('weight', { key: WEIGHT_KEY }); + cy.get('[data-cy="import-template-button"]').click(); - cy.createMultipleChoiceQuestion('storage temperature', { - key: STORAGE_TEMPERATURE_KEY, - option1: storageOption, - option2: faker.lorem.words(3), + cy.notification({ + variant: 'success', + text: 'Template imported successfully', }); - cy.createBooleanQuestion('is fragile', { key: IS_FRAGILE_KEY }); - cy.createMultipleChoiceQuestion('local contact', { - key: LOCAL_CONTACT_KEY, - option1: localContactName, - option2: faker.name.firstName(), - option3: faker.name.firstName(), - }); - cy.createBooleanQuestion('is dangerous', { key: IS_DANGEROUS_KEY }); - - cy.contains('New shipment'); cy.logout(); cy.login('user'); @@ -125,19 +130,21 @@ context('Shipments tests', () => { cy.get('body').type('{esc}'); + cy.get(`[data-natural-key=${DESCRIPTION_KEY}]`).type(description); + cy.get(`[data-natural-key=${WIDTH_KEY}]`).clear().type('1').click(); cy.get(`[data-natural-key=${HEIGHT_KEY}]`).clear().type('1').click(); cy.get(`[data-natural-key=${LENGTH_KEY}]`).clear().type('1').click(); cy.get(`[data-natural-key=${WEIGHT_KEY}]`).clear().type('1').click(); cy.get(`[data-natural-key=${STORAGE_TEMPERATURE_KEY}]`).click(); - cy.get('[role=presentation]').contains(storageOption).click(); - - cy.get(`[data-natural-key=${LOCAL_CONTACT_KEY}]`).click(); - cy.get('[role=presentation]').contains(localContactName).click(); - - cy.get(`[data-natural-key=${IS_DANGEROUS_KEY}]`).click(); - cy.get(`[data-natural-key=${IS_FRAGILE_KEY}]`).click(); + cy.get('[role=presentation]').contains(temp).click(); + cy.get(`[data-natural-key=${SENDER_NAME_KEY}]`).type(name); + cy.get(`[data-natural-key=${SENDER_EMAIL_KEY}]`).type(email); + cy.get(`[data-natural-key=${SENDER_PHONE_KEY}]`).type(phone); + cy.get(`[data-natural-key=${SENDER_STREET_ADDRESS_KEY}]`).type(street); + cy.get(`[data-natural-key=${SENDER_ZIP_CODE_KEY}]`).type(zip); + cy.get(`[data-natural-key=${SENDER_CITY_COUNTRY_KEY}]`).type(city); cy.get('[data-cy=save-and-continue-button]').click(); @@ -149,6 +156,15 @@ context('Shipments tests', () => { cy.contains('SUBMITTED', { matchCase: false }); + cy.contains(temp).should('exist'); + cy.contains(description).should('exist'); + cy.contains(name).should('exist'); + cy.contains(email).should('exist'); + cy.contains(phone).should('exist'); + cy.contains(street).should('exist'); + cy.contains(zip).should('exist'); + cy.contains(city).should('exist'); + cy.get('[data-cy=download-shipment-label]').click(); cy.get('[data-cy="preparing-download-dialog"]').should('exist'); diff --git a/cypress/integration/templates.ts b/cypress/integration/templates.ts index 9c904d0f4..3e1e75ff7 100644 --- a/cypress/integration/templates.ts +++ b/cypress/integration/templates.ts @@ -1,14 +1,16 @@ import path from 'path'; -import faker, { lorem } from 'faker'; +import { faker } from '@faker-js/faker'; import { DateTime } from 'luxon'; import { DataType, DependenciesLogicOperator, EvaluatorOperator, + FeatureId, TemplateCategoryId, } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; context('Template tests', () => { @@ -47,8 +49,13 @@ context('Template tests', () => { answer: faker.lorem.words(3), }; const multipleChoiceQuestion = { - title: lorem.words(2), - answers: [faker.lorem.words(3), faker.lorem.words(3), faker.lorem.words(3)], + title: faker.lorem.words(2), + answers: [ + faker.lorem.words(3), + faker.lorem.words(3), + faker.lorem.words(3), + faker.lorem.words(3), + ], }; const numberQuestion2 = { title: faker.lorem.words(3) }; @@ -341,933 +348,1013 @@ context('Template tests', () => { }; beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(true); cy.viewport(1920, 1680); }); describe('Proposal templates basic tests', () => { - // it('User officer can delete active template', () => { - // const newName = faker.lorem.words(3); - // const newDescription = faker.lorem.words(5); + it('User officer can delete active template', function () { + if (featureFlags.getEnabledFeatures().get(FeatureId.EXTERNAL_AUTH)) { + this.skip(); + } + const newName = faker.lorem.words(3); + const newDescription = faker.lorem.words(5); - // cy.login('officer'); - // cy.visit('/'); + cy.login('officer'); + cy.visit('/'); - // cy.navigateToTemplatesSubmenu('Shipment declaration templates'); + cy.navigateToTemplatesSubmenu('Shipment declaration templates'); - // cy.get('[data-cy=create-new-button]').click(); + cy.get('[data-cy=create-new-button]').click(); - // cy.get('[data-cy=name] input').type(newName); - // cy.get('[data-cy=description]').type(newDescription); + cy.get('[data-cy=name] input').type(newName); + cy.get('[data-cy=description]').type(newDescription); - // cy.get('[data-cy=submit]').click(); + cy.get('[data-cy=submit]').click(); - // cy.visit('/'); - // cy.navigateToTemplatesSubmenu('Shipment declaration templates'); + cy.visit('/'); + cy.navigateToTemplatesSubmenu('Shipment declaration templates'); - // cy.get('[data-cy=mark-as-active]').click(); + cy.get('[data-cy=mark-as-active]').click(); - // cy.get('[data-cy=delete-template]').click(); + cy.get('[data-cy=delete-template]').click(); - // cy.get('[data-cy=confirm-ok]').click(); + cy.get('[data-cy=confirm-ok]').click(); - // cy.finishedLoading(); + cy.finishedLoading(); - // cy.contains(newName).should('not.exist'); - // }); + cy.contains(newName).should('not.exist'); + }); - // it('User officer can modify proposal template', () => { - // cy.login('officer'); - // cy.visit('/'); + it('User officer can modify and preview proposal template', () => { + cy.login('officer'); + cy.visit('/'); - // cy.navigateToTemplatesSubmenu('Proposal'); + cy.navigateToTemplatesSubmenu('Proposal'); - // cy.contains(initialDBData.template.name) - // .parent() - // .find("[aria-label='Edit']") - // .first() - // .click(); + cy.contains(initialDBData.template.name) + .parent() + .find("[aria-label='Edit']") + .first() + .click(); - // /* Boolean */ + /* Boolean */ - // cy.createBooleanQuestion(booleanQuestion); + cy.createBooleanQuestion(booleanQuestion); - // cy.contains(booleanQuestion) - // .closest('[data-cy=question-container]') - // .find("[data-cy='proposal-question-id']") - // .invoke('html') - // .then((fieldId) => { - // boolId = fieldId; - // }); + cy.contains(booleanQuestion) + .closest('[data-cy=question-container]') + .find("[data-cy='proposal-question-id']") + .invoke('html') + .then((fieldId) => { + boolId = fieldId; + }); - // /* --- */ + /* --- */ - // /* Interval */ - // cy.createIntervalQuestion(intervalQuestion, { - // units: ['celsius', 'kelvin'], - // }); + /* Interval */ + cy.createIntervalQuestion(intervalQuestion, { + units: ['celsius', 'kelvin'], + }); - // cy.contains(intervalQuestion) - // .closest('[data-cy=question-container]') - // .find("[data-cy='proposal-question-id']") - // .invoke('html') - // .then((fieldId) => { - // intervalId = fieldId; - // }); + cy.contains(intervalQuestion) + .closest('[data-cy=question-container]') + .find("[data-cy='proposal-question-id']") + .invoke('html') + .then((fieldId) => { + intervalId = fieldId; + }); - // /* --- */ + /* --- */ - // /* Number */ + /* Number */ - // cy.createNumberInputQuestion(numberQuestion, { - // units: ['celsius', 'kelvin'], - // }); + cy.createNumberInputQuestion(numberQuestion, { + units: ['celsius', 'kelvin'], + }); - // cy.contains(numberQuestion) - // .closest('[data-cy=question-container]') - // .find("[data-cy='proposal-question-id']") - // .invoke('html') - // .then((fieldId) => { - // numberId = fieldId; - // }); + cy.contains(numberQuestion) + .closest('[data-cy=question-container]') + .find("[data-cy='proposal-question-id']") + .invoke('html') + .then((fieldId) => { + numberId = fieldId; + }); - // /* --- */ + /* --- */ + + /* Text input */ + cy.createTextQuestion(textQuestion.title, { + isRequired: true, + isMultipleLines: true, + maxCharacters: textQuestion.maxChars, + }); + + cy.contains(textQuestion.title) + .closest('[data-cy=question-container]') + .find("[data-cy='proposal-question-id']") + .invoke('html') + .then((fieldId) => { + textId = fieldId; + }); - // /* Text input */ - // cy.createTextQuestion(textQuestion.title, { - // isRequired: true, - // isMultipleLines: true, - // maxCharacters: textQuestion.maxChars, - // }); + /* Update question */ - // cy.contains(textQuestion.title) - // .closest('[data-cy=question-container]') - // .find("[data-cy='proposal-question-id']") - // .invoke('html') - // .then((fieldId) => { - // textId = fieldId; - // }); + cy.contains(textQuestion.title).click(); - // /* Update question */ + cy.get('[data-cy="natural-key"]').click(); - // cy.contains(textQuestion.title).click(); + cy.get("[data-cy='natural_key']").clear().type(textQuestion.newId); - // cy.get('[data-cy="natural-key"]').click(); + cy.contains('Save').click(); - // cy.get("[data-cy='natural_key']").clear().type(textQuestion.newId); + cy.contains(textQuestion.newId); + /* --- */ - // cy.contains('Save').click(); + /* Check if template preview works */ + cy.get('[data-cy="preview-questionary-template"]').click(); + cy.get('[aria-labelledby="preview-questionary-template-modal"]').should( + 'exist' + ); - // cy.contains(textQuestion.newId); - // /* --- */ + cy.get('[data-cy="questionary-stepper"] button').last().click(); - // cy.contains(textQuestion.title).click(); + cy.get( + '[aria-labelledby="preview-questionary-template-modal"] form' + ).contains(booleanQuestion); + cy.get( + '[aria-labelledby="preview-questionary-template-modal"] form' + ).contains(intervalQuestion); + cy.get( + '[aria-labelledby="preview-questionary-template-modal"] form' + ).contains(numberQuestion); + cy.get( + '[aria-labelledby="preview-questionary-template-modal"] form' + ).contains(textQuestion.title); - // // Updating dependencies - // cy.get('[data-cy="add-dependency-button"]').click(); - // cy.get('#dependency-id').click(); - // cy.get('[data-cy=question-relation-dialogue]') - // .get('#menu- > .MuiPaper-root > .MuiList-root > [tabindex="0"]') - // .click(); // get boolean question - - // cy.get('#dependencyValue').click(); - // cy.get('[data-cy=question-relation-dialogue]') - // .get("#menu- > .MuiPaper-root > .MuiList-root > [tabindex='0']") - // .click(); // get true from dropdown - - // cy.contains('Update').click(); - - // // Check reordering - // cy.contains(textQuestion.title) - // .parent() - // .dragElement([{ direction: 'up', length: 1 }]); // Move item to top, in case it isn't + cy.closeModal(); + /* --- */ - // cy.contains(initialDBData.template.topic.title) - // .closest('[data-rbd-draggable-context-id]') // new topic column - // .find('[data-rbd-drag-handle-draggable-id]') // all questions - // .first() // first question - // .contains(textQuestion.title); + cy.contains(textQuestion.title).click(); - // cy.contains(textQuestion.title) - // .parent() - // .dragElement([{ direction: 'down', length: 1 }]); - - // cy.contains(initialDBData.template.topic.title) - // .closest('[data-rbd-draggable-context-id]') // new topic column - // .find('[data-rbd-drag-handle-draggable-id]') // all questions - // .first() // first question - // .should('not.contain', textQuestion); + // Updating dependencies + cy.get('[data-cy="add-dependency-button"]').click(); + cy.get('#dependency-id').click(); + cy.get('[data-cy=question-relation-dialogue]') + .get('#menu- > .MuiPaper-root > .MuiList-root > [tabindex="0"]') + .click(); // get boolean question - // /* Selection from options */ - // cy.createMultipleChoiceQuestion(multipleChoiceQuestion.title, { - // option1: multipleChoiceQuestion.answers[0], - // option2: multipleChoiceQuestion.answers[1], - // option3: multipleChoiceQuestion.answers[2], - // isMultipleSelect: true, - // }); + cy.get('#dependencyValue').click(); + cy.get('[data-cy=question-relation-dialogue]') + .get("#menu- > .MuiPaper-root > .MuiList-root > [tabindex='0']") + .click(); // get true from dropdown - // cy.contains(multipleChoiceQuestion.title) - // .closest('[data-cy=question-container]') - // .find("[data-cy='proposal-question-id']") - // .invoke('html') - // .then((fieldId) => { - // multipleChoiceId = fieldId; - // }); + cy.contains('Update').click(); - // cy.finishedLoading(); + // Check reordering + cy.contains(textQuestion.title) + .parent() + .dragElement([{ direction: 'up', length: 1 }]); // Move item to top, in case it isn't - // cy.contains(multipleChoiceQuestion.title).click(); - - // cy.get('[data-cy=natural-key]').click(); - - // cy.get('[index=0]').should( - // 'not.contain', - // multipleChoiceQuestion.answers[1] - // ); + cy.contains(initialDBData.template.topic.title) + .closest('[data-rbd-draggable-context-id]') // new topic column + .find('[data-rbd-drag-handle-draggable-id]') // all questions + .first() // first question + .contains(textQuestion.title); - // cy.contains(multipleChoiceQuestion.answers[1]) - // .parent() - // .find('[aria-label=Up]') - // .click(); + cy.contains(textQuestion.title) + .parent() + .dragElement([{ direction: 'down', length: 1 }]); + + cy.contains(initialDBData.template.topic.title) + .closest('[data-rbd-draggable-context-id]') // new topic column + .find('[data-rbd-drag-handle-draggable-id]') // all questions + .first() // first question + .should('not.contain', textQuestion); + + /* Selection from options */ + cy.createMultipleChoiceQuestion(multipleChoiceQuestion.title, { + option1: multipleChoiceQuestion.answers[0], + option2: multipleChoiceQuestion.answers[1], + option3: multipleChoiceQuestion.answers[2], + isMultipleSelect: true, + }); + + cy.contains(multipleChoiceQuestion.title) + .closest('[data-cy=question-container]') + .find("[data-cy='proposal-question-id']") + .invoke('html') + .then((fieldId) => { + multipleChoiceId = fieldId; + }); - // cy.get('[index=0]').contains(multipleChoiceQuestion.answers[1]); + cy.finishedLoading(); - // cy.contains(multipleChoiceQuestion.answers[1]) - // .parent() - // .find('[aria-label=Down]') - // .click(); + cy.contains(multipleChoiceQuestion.title).click(); - // cy.contains('Save').click(); + cy.get('[data-cy=natural-key]').click(); - // /* --- */ + cy.get('[index=0]').should( + 'not.contain', + multipleChoiceQuestion.answers[1] + ); - // /* Date */ - // cy.createDateQuestion(dateQuestion.title, { - // includeTime: false, - // isRequired: true, - // }); + cy.contains(multipleChoiceQuestion.answers[1]) + .parent() + .find('[aria-label=Up]') + .click(); - // cy.contains(dateQuestion.title) - // .closest('[data-cy=question-container]') - // .find("[data-cy='proposal-question-id']") - // .invoke('html') - // .then((fieldId) => { - // dateId = fieldId; - // }); + cy.get('[index=0]').contains(multipleChoiceQuestion.answers[1]); + cy.get('[index=1]').contains(multipleChoiceQuestion.answers[0]); - // cy.createDateQuestion(timeQuestion, { - // includeTime: true, - // isRequired: false, - // }); + cy.contains(multipleChoiceQuestion.answers[1]) + .parent() + .find('[aria-label=Down]') + .click(); - // cy.contains(timeQuestion) - // .closest('[data-cy=question-container]') - // .find("[data-cy='proposal-question-id']") - // .invoke('html') - // .then((fieldId) => { - // timeId = fieldId; - // }); + cy.contains(multipleChoiceQuestion.answers[0]) + .parent() + .find('[aria-label=Up]') + .find('[type=button]') + .should('be.disabled'); - // /* --- */ + cy.contains(multipleChoiceQuestion.answers[0]) + .parent() + .find('[aria-label=Down]') + .click(); - // /* File */ + cy.contains(multipleChoiceQuestion.answers[0]) + .parent() + .find('[aria-label=Up]') + .click(); - // cy.createFileUploadQuestion(fileQuestion, ['.pdf', 'image/*']); + cy.contains(multipleChoiceQuestion.answers[2]) + .parent() + .find('[aria-label=Down]') + .find('[type=button]') + .should('be.disabled'); - // /* --- */ + cy.contains(multipleChoiceQuestion.answers[2]) + .parent() + .find('[aria-label=Up]') + .click(); - // /* Rich Text Input */ + cy.contains(multipleChoiceQuestion.answers[2]) + .parent() + .find('[aria-label=Down]') + .click(); - // cy.createRichTextInput(richTextInputQuestion.title, { - // maxChars: richTextInputQuestion.maxChars, - // }); + cy.contains(multipleChoiceQuestion.answers[0]) + .parent() + .find('[aria-label=Edit]') + .click() + .get('[aria-label=Answer]') + .type(multipleChoiceQuestion.answers[3]) + .get('[aria-label=Save]') + .click() + .get('[index=0]') + .should('contain', multipleChoiceQuestion.answers[3]); + + cy.contains(multipleChoiceQuestion.answers[1]) + .parent() + .find('[aria-label=Delete]') + .click() + .get('[aria-label=Save]') + .click() + .should('not.exist'); + + cy.contains('Save').click(); + + /* --- */ + + /* Date */ + cy.createDateQuestion(dateQuestion.title, { + includeTime: false, + isRequired: true, + }); + + cy.contains(dateQuestion.title) + .closest('[data-cy=question-container]') + .find("[data-cy='proposal-question-id']") + .invoke('html') + .then((fieldId) => { + dateId = fieldId; + }); - // cy.contains(richTextInputQuestion.title); + cy.createDateQuestion(timeQuestion, { + includeTime: true, + isRequired: false, + }); + + cy.contains(timeQuestion) + .closest('[data-cy=question-container]') + .find("[data-cy='proposal-question-id']") + .invoke('html') + .then((fieldId) => { + timeId = fieldId; + }); - // cy.contains(richTextInputQuestion.title) - // .closest('[data-cy=question-container]') - // .find("[data-cy='proposal-question-id']") - // .invoke('html') - // .then((fieldId) => { - // richTextInputId = fieldId; - // }); + /* --- */ - // /* --- */ + /* File */ - // /* --- Update templateQuestionRelation */ - // cy.contains(dateQuestion.title).click(); - // cy.get("[data-cy='tooltip'] input").clear().type(dateQuestion.tooltip); + cy.createFileUploadQuestion(fileQuestion, ['.pdf', 'image/*']); - // cy.contains('Update').click(); + /* --- */ - // cy.reload(); + /* Rich Text Input */ - // cy.contains(dateQuestion.title).click(); - // cy.get("[data-cy='tooltip'] input").should( - // 'have.value', - // dateQuestion.tooltip - // ); - // cy.get('body').type('{esc}'); - // /* --- */ + cy.createRichTextInput(richTextInputQuestion.title, { + maxChars: richTextInputQuestion.maxChars, + }); - // cy.contains(booleanQuestion); - // cy.contains(textQuestion.title); - // cy.contains(dateQuestion.title); - // cy.contains(timeQuestion); - // }); + cy.contains(richTextInputQuestion.title); - // it('User officer can change template title and description', () => { - // const newName = faker.lorem.words(3); - // const newDescription = faker.lorem.words(5); + cy.contains(richTextInputQuestion.title) + .closest('[data-cy=question-container]') + .find("[data-cy='proposal-question-id']") + .invoke('html') + .then((fieldId) => { + richTextInputId = fieldId; + }); - // cy.login('officer'); - // cy.visit('/'); + /* --- */ - // cy.navigateToTemplatesSubmenu('Proposal'); + /* --- Update templateQuestionRelation */ + cy.contains(dateQuestion.title).click(); + cy.get("[data-cy='tooltip'] input").clear().type(dateQuestion.tooltip); - // cy.contains(initialDBData.template.name) - // .parent() - // .find("[aria-label='Edit']") - // .first() - // .click(); + cy.contains('Update').click(); - // cy.get('[data-cy=edit-metadata]').click(); - // cy.get('[data-cy=template-name] input').clear().type(newName); - // cy.get('[data-cy=template-description] input') - // .clear() - // .type(newDescription); + cy.reload(); - // cy.get('[data-cy="save-metadata-btn"]').click(); + cy.contains(dateQuestion.title).click(); + cy.get("[data-cy='tooltip'] input").should( + 'have.value', + dateQuestion.tooltip + ); + cy.get('body').type('{esc}'); + /* --- */ - // cy.finishedLoading(); - - // cy.contains(newName); - // cy.contains(newDescription); - // }); + cy.contains(booleanQuestion); + cy.contains(textQuestion.title); + cy.contains(dateQuestion.title); + cy.contains(timeQuestion); + }); - // it('User officer can clone template', () => { - // cy.login('officer'); - // cy.visit('/'); - - // cy.navigateToTemplatesSubmenu('Proposal'); + it('User officer can change template title and description', () => { + const newName = faker.lorem.words(3); + const newDescription = faker.lorem.words(5); - // cy.contains(initialDBData.template.name) - // .parent() - // .find("[aria-label='Clone']") - // .first() - // .click(); + cy.login('officer'); + cy.visit('/'); - // cy.contains('Yes').click(); + cy.navigateToTemplatesSubmenu('Proposal'); - // cy.contains(`Copy of ${initialDBData.template.name}`); - // }); + cy.contains(initialDBData.template.name) + .parent() + .find("[aria-label='Edit']") + .first() + .click(); - // it('User officer can delete template', () => { - // cy.cloneTemplate({ templateId: initialDBData.template.id }); - // cy.login('officer'); - // cy.visit('/'); + cy.get('[data-cy=edit-metadata]').click(); + cy.get('[data-cy=template-name] input').clear().type(newName); + cy.get('[data-cy=template-description] input') + .clear() + .type(newDescription); - // cy.navigateToTemplatesSubmenu('Proposal'); + cy.get('[data-cy="save-metadata-btn"]').click(); - // cy.contains(`Copy of ${initialDBData.template.name}`) - // .parent() - // .find("[aria-label='Delete']") - // .first() - // .click(); + cy.finishedLoading(); - // cy.contains('Yes').click(); + cy.contains(newName); + cy.contains(newDescription); + }); - // cy.contains(`Copy of ${initialDBData.template.name}`).should('not.exist'); - // }); + it('User officer can clone template', () => { + cy.login('officer'); + cy.visit('/'); - // it('User officer archive and unarchive template', () => { - // cy.login('officer'); - // cy.visit('/'); + cy.navigateToTemplatesSubmenu('Proposal'); - // cy.navigateToTemplatesSubmenu('Proposal'); + cy.contains(initialDBData.template.name) + .parent() + .find("[aria-label='Clone']") + .first() + .click(); - // cy.contains(initialDBData.template.name) - // .parent() - // .find("[aria-label='Archive']") - // .first() - // .click(); + cy.contains('Yes').click(); - // cy.contains('Yes').click(); + cy.contains(`Copy of ${initialDBData.template.name}`); + }); - // cy.notification({ variant: 'success', text: 'successfully' }); + it('User officer can delete template', () => { + cy.cloneTemplate({ templateId: initialDBData.template.id }); + cy.login('officer'); + cy.visit('/'); - // cy.contains(initialDBData.template.name).should('not.exist'); + cy.navigateToTemplatesSubmenu('Proposal'); - // cy.contains('Archived').click(); + cy.contains(`Copy of ${initialDBData.template.name}`) + .parent() + .find("[aria-label='Delete']") + .first() + .click(); - // cy.contains(initialDBData.template.name); + cy.contains('Yes').click(); - // cy.contains(initialDBData.template.name) - // .parent() - // .find("[aria-label='Unarchive']") - // .first() - // .click(); + cy.contains(`Copy of ${initialDBData.template.name}`).should('not.exist'); + }); - // cy.contains('Yes').click(); - // }); + it('User officer archive and unarchive template', () => { + cy.login('officer'); + cy.visit('/'); - // it('should render the Date field with default value and min max values when set', () => { - // let dateFieldId: string; - // const minDate = DateTime.fromJSDate(faker.date.past()).toFormat( - // initialDBData.getFormats().dateFormat - // ); - // const earlierThanMinDate = DateTime.fromFormat( - // minDate, - // initialDBData.getFormats().dateFormat - // ) - // .minus({ day: 1 }) - // .toFormat(initialDBData.getFormats().dateFormat); - // const maxDate = DateTime.fromJSDate(faker.date.future()).toFormat( - // initialDBData.getFormats().dateFormat - // ); - // const laterThanMaxDate = DateTime.fromFormat( - // maxDate, - // initialDBData.getFormats().dateFormat - // ) - // .plus({ day: 1 }) - // .toFormat(initialDBData.getFormats().dateFormat); - // const defaultDate = DateTime.now().toFormat( - // initialDBData.getFormats().dateFormat - // ); + cy.navigateToTemplatesSubmenu('Proposal'); - // const tomorrowDate = DateTime.now() - // .plus({ day: 1 }) - // .toFormat(initialDBData.getFormats().dateFormat); + cy.contains(initialDBData.template.name) + .parent() + .find("[aria-label='Archive']") + .first() + .click(); - // cy.login('officer'); - // cy.visit('/'); + cy.contains('Yes').click(); - // cy.navigateToTemplatesSubmenu('Proposal'); + cy.notification({ variant: 'success', text: 'successfully' }); - // cy.contains(initialDBData.template.name) - // .parent() - // .find("[aria-label='Edit']") - // .first() - // .click(); + cy.contains(initialDBData.template.name).should('not.exist'); - // cy.get('[data-cy=show-more-button]').first().click(); + cy.contains('Archived').click(); - // cy.get('[data-cy=add-question-menu-item]').first().click(); + cy.contains(initialDBData.template.name); - // cy.get('[data-cy=questionPicker] [data-cy=show-more-button]') - // .first() - // .click(); + cy.contains(initialDBData.template.name) + .parent() + .find("[aria-label='Unarchive']") + .first() + .click(); - // cy.contains('Add Date').click(); + cy.contains('Yes').click(); + }); - // cy.get('[data-cy=question]').clear().type(dateQuestion.title); + it('should render the Date field with default value and min max values when set', () => { + let dateFieldId: string; + const minDate = DateTime.fromJSDate(faker.date.past()).toFormat( + initialDBData.getFormats().dateFormat + ); + const earlierThanMinDate = DateTime.fromFormat( + minDate, + initialDBData.getFormats().dateFormat + ) + .minus({ day: 1 }) + .toFormat(initialDBData.getFormats().dateFormat); + const maxDate = DateTime.fromJSDate(faker.date.future()).toFormat( + initialDBData.getFormats().dateFormat + ); + const laterThanMaxDate = DateTime.fromFormat( + maxDate, + initialDBData.getFormats().dateFormat + ) + .plus({ day: 1 }) + .toFormat(initialDBData.getFormats().dateFormat); + const defaultDate = DateTime.now().toFormat( + initialDBData.getFormats().dateFormat + ); + + const tomorrowDate = DateTime.now() + .plus({ day: 1 }) + .toFormat(initialDBData.getFormats().dateFormat); - // cy.get('[data-cy="minDate"] input').type(minDate); - // cy.get('[data-cy="maxDate"] input').type(maxDate); - // cy.get('[data-cy="defaultDate"] input').type(defaultDate); + cy.login('officer'); + cy.visit('/'); - // cy.contains('Save').click(); + cy.navigateToTemplatesSubmenu('Proposal'); - // cy.contains(dateQuestion.title) - // .closest('[data-cy=question-container]') - // .find("[data-cy='proposal-question-id']") - // .invoke('html') - // .then((fieldId) => { - // dateFieldId = fieldId; - // }); + cy.contains(initialDBData.template.name) + .parent() + .find("[aria-label='Edit']") + .first() + .click(); - // cy.contains(dateQuestion.title) - // .parent() - // .dragElement([{ direction: 'left', length: 1 }]); + cy.get('[data-cy=show-more-button]').first().click(); - // cy.finishedLoading(); + cy.get('[data-cy=add-question-menu-item]').first().click(); - // cy.contains(dateQuestion.title).click(); + cy.get('[data-cy=questionPicker] [data-cy=show-more-button]') + .first() + .click(); - // cy.get('[data-cy="minDate"] input').should('have.value', minDate); - // cy.get('[data-cy="maxDate"] input').should('have.value', maxDate); - // cy.get('[data-cy="defaultDate"] input').should('have.value', defaultDate); + cy.contains('Add Date').click(); - // cy.get('[data-cy="minDate"] input').clear().type(minDate); - // cy.get('[data-cy="maxDate"] input').clear().type(maxDate); - // cy.get('[data-cy="defaultDate"] input').clear().type(defaultDate); + cy.get('[data-cy=question]').clear().type(dateQuestion.title); - // cy.contains('Update').click(); + cy.get('[data-cy="minDate"] input').type(minDate); + cy.get('[data-cy="maxDate"] input').type(maxDate); + cy.get('[data-cy="defaultDate"] input').type(defaultDate); - // cy.logout(); + cy.contains('Save').click(); - // cy.login('user'); - // cy.visit('/'); + cy.contains(dateQuestion.title) + .closest('[data-cy=question-container]') + .find("[data-cy='proposal-question-id']") + .invoke('html') + .then((fieldId) => { + dateFieldId = fieldId; + }); - // cy.contains('New Proposal').click(); + cy.contains(dateQuestion.title) + .parent() + .dragElement([{ direction: 'left', length: 1 }]); - // cy.contains(dateQuestion.title); - // cy.get('body').then(() => { - // cy.get(`[data-cy="${dateFieldId}.value"] input`).as('dateField'); + cy.finishedLoading(); - // cy.get('@dateField').should('have.value', defaultDate); + cy.contains(dateQuestion.title).click(); - // cy.get('@dateField').clear().type(earlierThanMinDate); - // cy.contains('Save and continue').click(); - // cy.contains('Date must be no earlier than'); + cy.get('[data-cy="minDate"] input').should('have.value', minDate); + cy.get('[data-cy="maxDate"] input').should('have.value', maxDate); + cy.get('[data-cy="defaultDate"] input').should('have.value', defaultDate); - // cy.get('@dateField').clear().type(laterThanMaxDate); - // cy.contains('Save and continue').click(); - // cy.contains('Date must be no latter than'); + cy.get('[data-cy="minDate"] input').clear().type(minDate); + cy.get('[data-cy="maxDate"] input').clear().type(maxDate); + cy.get('[data-cy="defaultDate"] input').clear().type(defaultDate); - // cy.get('@dateField').clear().type(tomorrowDate); - // cy.contains('Save and continue').click(); - // cy.contains('Date must be no').should('not.exist'); - // }); - // }); + cy.contains('Update').click(); - // it('should render the Number field accepting only positive, negative numbers if set', () => { - // let numberField1Id: string; - // let numberField2Id: string; + cy.logout(); - // cy.login('officer'); - // cy.visit('/'); + cy.login('user'); + cy.visit('/'); - // cy.navigateToTemplatesSubmenu('Proposal'); + cy.contains('New Proposal').click(); - // cy.contains(initialDBData.template.name) - // .parent() - // .find("[aria-label='Edit']") - // .first() - // .click(); + cy.contains(dateQuestion.title); + cy.get('body').then(() => { + cy.get(`[data-cy="${dateFieldId}.value"] input`).as('dateField'); - // cy.get('[data-cy=show-more-button]').first().click(); + cy.get('@dateField').should('have.value', defaultDate); - // cy.get('[data-cy=add-question-menu-item]').first().click(); + cy.get('@dateField').clear().type(earlierThanMinDate); + cy.contains('Save and continue').click(); + cy.contains('Date must be no earlier than'); - // cy.get('[data-cy=questionPicker] [data-cy=show-more-button]') - // .first() - // .click(); + cy.get('@dateField').clear().type(laterThanMaxDate); + cy.contains('Save and continue').click(); + cy.contains('Date must be no latter than'); - // cy.contains('Add Number').click(); + cy.get('@dateField').clear().type(tomorrowDate); + cy.contains('Save and continue').click(); + cy.contains('Date must be no').should('not.exist'); + }); + }); - // cy.get('[data-cy=question]').clear().type(numberQuestion2.title); + it('should render the Number field accepting only positive, negative numbers if set', () => { + let numberField1Id: string; + let numberField2Id: string; - // cy.get('[data-cy=units]').find('[aria-label=Open]').click(); + cy.login('officer'); + cy.visit('/'); - // cy.contains('celsius').click(); + cy.navigateToTemplatesSubmenu('Proposal'); - // cy.get('[data-cy=units]').find('[aria-label=Open]').click(); + cy.contains(initialDBData.template.name) + .parent() + .find("[aria-label='Edit']") + .first() + .click(); - // cy.contains('kelvin').click(); + cy.get('[data-cy=show-more-button]').first().click(); - // cy.get('[data-cy="numberValueConstraint"]').click(); + cy.get('[data-cy=add-question-menu-item]').first().click(); - // cy.contains('Only positive numbers').click(); + cy.get('[data-cy=questionPicker] [data-cy=show-more-button]') + .first() + .click(); + + cy.contains('Add Number').click(); + + cy.get('[data-cy=question]').clear().type(numberQuestion2.title); + + cy.get('[data-cy=units]').find('[aria-label=Open]').click(); + + cy.contains('celsius').click(); + + cy.get('[data-cy=units]').find('[aria-label=Open]').click(); + + cy.contains('kelvin').click(); + + cy.get('[data-cy="numberValueConstraint"]').click(); + + cy.contains('Only positive numbers').click(); + + cy.contains('Save').click(); - // cy.contains('Save').click(); + cy.contains(numberQuestion2.title) + .closest('[data-cy=question-container]') + .find("[data-cy='proposal-question-id']") + .invoke('html') + .then((fieldId) => { + numberField1Id = fieldId; + }); + + cy.contains(numberQuestion2.title) + .parent() + .dragElement([{ direction: 'left', length: 1 }]); + + cy.get('[data-cy=questionPicker] [data-cy=show-more-button]') + .first() + .click(); - // cy.contains(numberQuestion2.title) - // .closest('[data-cy=question-container]') - // .find("[data-cy='proposal-question-id']") - // .invoke('html') - // .then((fieldId) => { - // numberField1Id = fieldId; - // }); + cy.contains('Add Number').click(); - // cy.contains(numberQuestion2.title) - // .parent() - // .dragElement([{ direction: 'left', length: 1 }]); + cy.get('[data-cy=question]').clear().type(numberQuestion3.title); - // cy.get('[data-cy=questionPicker] [data-cy=show-more-button]') - // .first() - // .click(); + cy.get('[data-cy=units]').find('[aria-label=Open]').click(); - // cy.contains('Add Number').click(); + cy.contains('celsius').click(); - // cy.get('[data-cy=question]').clear().type(numberQuestion3.title); + cy.get('[data-cy=units]').find('[aria-label=Open]').click(); - // cy.get('[data-cy=units]').find('[aria-label=Open]').click(); + cy.contains('kelvin').click(); - // cy.contains('celsius').click(); + cy.get('[data-cy="numberValueConstraint"]').click(); - // cy.get('[data-cy=units]').find('[aria-label=Open]').click(); + cy.contains('Only positive numbers').click(); - // cy.contains('kelvin').click(); + cy.contains('Save').click(); - // cy.get('[data-cy="numberValueConstraint"]').click(); + cy.contains(numberQuestion3.title) + .closest('[data-cy=question-container]') + .find("[data-cy='proposal-question-id']") + .invoke('html') + .then((fieldId) => { + numberField2Id = fieldId; + }); - // cy.contains('Only positive numbers').click(); + cy.contains(numberQuestion3.title) + .parent() + .dragElement([{ direction: 'left', length: 1 }]); - // cy.contains('Save').click(); + cy.finishedLoading(); - // cy.contains(numberQuestion3.title) - // .closest('[data-cy=question-container]') - // .find("[data-cy='proposal-question-id']") - // .invoke('html') - // .then((fieldId) => { - // numberField2Id = fieldId; - // }); + cy.contains(numberQuestion3.title).click(); - // cy.contains(numberQuestion3.title) - // .parent() - // .dragElement([{ direction: 'left', length: 1 }]); + cy.get('[data-cy=units]').contains('celsius'); + cy.get('[data-cy=units]').contains('kelvin'); - // cy.finishedLoading(); + cy.get('[data-cy="numberValueConstraint"] input').should( + 'have.value', + 'Only positive numbers' + ); - // cy.contains(numberQuestion3.title).click(); + cy.get('[data-cy="numberValueConstraint"]').click(); - // cy.get('[data-cy=units]').contains('celsius'); - // cy.get('[data-cy=units]').contains('kelvin'); + cy.contains('Only negative numbers').click(); + + cy.contains('Update').click(); - // cy.get('[data-cy="numberValueConstraint"] input').should( - // 'have.value', - // 'Only positive numbers' - // ); + cy.logout(); - // cy.get('[data-cy="numberValueConstraint"]').click(); + cy.login('user'); + cy.visit('/'); - // cy.contains('Only negative numbers').click(); + cy.contains('New Proposal').click(); - // cy.contains('Update').click(); + cy.contains(numberQuestion2.title); + cy.contains(numberQuestion3.title); + cy.get('body').then(() => { + cy.get(`[data-cy="${numberField1Id}.value"] input`).as('numberField1'); + cy.get(`[data-cy="${numberField2Id}.value"] input`).as('numberField2'); - // cy.logout(); + cy.get('@numberField1').type('1{leftarrow}-'); + cy.get('@numberField2').type('1'); - // cy.login('user'); - // cy.visit('/'); + cy.contains('Save and continue').click(); + cy.contains('Value must be a negative number'); + cy.contains('Value must be a positive number'); - // cy.contains('New Proposal').click(); + cy.get('@numberField1').clear().type('1'); + cy.get('@numberField2').clear().type('1{leftarrow}-'); - // cy.contains(numberQuestion2.title); - // cy.contains(numberQuestion3.title); - // cy.get('body').then(() => { - // cy.get(`[data-cy="${numberField1Id}.value"] input`).as('numberField1'); - // cy.get(`[data-cy="${numberField2Id}.value"] input`).as('numberField2'); + cy.contains('Value must be a negative number').should('not.exist'); + cy.contains('Value must be a positive number').should('not.exist'); + }); + }); - // cy.get('@numberField1').type('1{leftarrow}-'); - // cy.get('@numberField2').type('1'); + it('User officer can add multiple choice question as a dependency', () => { + cy.createProposal({ callId: initialDBData.call.id }).then((result) => { + const createdProposal = result.createProposal.proposal; + if (createdProposal) { + cy.updateProposal({ + proposalPk: createdProposal.primaryKey, + title: proposal.title, + abstract: proposal.abstract, + proposerId: initialDBData.users.user1.id, + }); + } + }); - // cy.contains('Save and continue').click(); - // cy.contains('Value must be a negative number'); - // cy.contains('Value must be a positive number'); + cy.login('officer'); + cy.visit('/'); - // cy.get('@numberField1').clear().type('1'); - // cy.get('@numberField2').clear().type('1{leftarrow}-'); + cy.navigateToTemplatesSubmenu('Proposal'); - // cy.contains('Value must be a negative number').should('not.exist'); - // cy.contains('Value must be a positive number').should('not.exist'); - // }); - // }); + cy.contains(initialDBData.template.name) + .parent() + .find("[aria-label='Edit']") + .first() + .click(); - // it('User officer can add multiple choice question as a dependency', () => { - // cy.createProposal({ callId: initialDBData.call.id }).then((result) => { - // const createdProposal = result.createProposal.proposal; - // if (createdProposal) { - // cy.updateProposal({ - // proposalPk: createdProposal.primaryKey, - // title: proposal.title, - // abstract: proposal.abstract, - // proposerId: initialDBData.users.user1.id, - // }); - // } - // }); + cy.createMultipleChoiceQuestion( + templateDependencies.questions.selectQuestion.title, + { + option1: templateDependencies.questions.selectQuestion.answer1, + option2: templateDependencies.questions.selectQuestion.answer2, + } + ); - // cy.login('officer'); - // cy.visit('/'); + cy.createBooleanQuestion( + templateDependencies.questions.booleanQuestion.title + ); - // cy.navigateToTemplatesSubmenu('Proposal'); + cy.contains(templateDependencies.questions.booleanQuestion.title).click(); - // cy.contains(initialDBData.template.name) - // .parent() - // .find("[aria-label='Edit']") - // .first() - // .click(); + cy.get('[data-cy="add-dependency-button"]').click(); - // cy.createMultipleChoiceQuestion( - // templateDependencies.questions.selectQuestion.title, - // { - // option1: templateDependencies.questions.selectQuestion.answer1, - // option2: templateDependencies.questions.selectQuestion.answer2, - // } - // ); + cy.get('[id="dependency-id"]').click(); - // cy.createBooleanQuestion( - // templateDependencies.questions.booleanQuestion.title - // ); + cy.get('[role="presentation"]') + .contains(templateDependencies.questions.selectQuestion.title) + .click(); - // cy.contains(templateDependencies.questions.booleanQuestion.title).click(); - - // cy.get('[data-cy="add-dependency-button"]').click(); - - // cy.get('[id="dependency-id"]').click(); - - // cy.get('[role="presentation"]') - // .contains(templateDependencies.questions.selectQuestion.title) - // .click(); - - // cy.get('[id="dependencyValue"]').click(); + cy.get('[id="dependencyValue"]').click(); - // cy.contains( - // templateDependencies.questions.selectQuestion.answer1 - // ).click(); - - // cy.get('[data-cy="submit"]').click(); + cy.contains( + templateDependencies.questions.selectQuestion.answer1 + ).click(); - // cy.logout(); - - // cy.login('user'); - // cy.visit('/'); - - // cy.contains(proposal.title) - // .parent() - // .find('[aria-label="Edit proposal"]') - // .click(); + cy.get('[data-cy="submit"]').click(); - // cy.contains('save and continue', { matchCase: false }).click(); - // cy.finishedLoading(); + cy.logout(); - // // Dependee is NOT visible - // cy.get('main form').should( - // 'not.contain.text', - // templateDependencies.questions.booleanQuestion.title - // ); + cy.login('user'); + cy.visit('/'); - // cy.contains(templateDependencies.questions.selectQuestion.title) - // .parent() - // .click(); - // cy.contains( - // templateDependencies.questions.selectQuestion.answer1 - // ).click(); - - // // Dependee is visible - // cy.get('main form').should( - // 'contain.text', - // templateDependencies.questions.booleanQuestion.title - // ); + cy.contains(proposal.title) + .parent() + .find('[aria-label="Edit proposal"]') + .click(); - // cy.contains(templateDependencies.questions.selectQuestion.title) - // .parent() - // .click(); - // cy.contains( - // templateDependencies.questions.selectQuestion.answer2 - // ).click(); - - // // Dependee is NOT visible again - // cy.get('main form').should( - // 'not.contain.text', - // templateDependencies.questions.booleanQuestion.title - // ); - // }); + cy.contains('save and continue', { matchCase: false }).click(); + cy.finishedLoading(); - // it('Should not let you create circular dependency chain', () => { - // const field1 = 'boolean_1_' + Date.now(); - // const field2 = 'boolean_2_' + Date.now(); - // const field3 = 'boolean_3_' + Date.now(); - // cy.login('officer'); - // cy.visit('/'); - - // cy.navigateToTemplatesSubmenu('Proposal'); + // Dependee is NOT visible + cy.get('main form').should( + 'not.contain.text', + templateDependencies.questions.booleanQuestion.title + ); - // cy.contains(initialDBData.template.name) - // .parent() - // .find("[aria-label='Edit']") - // .first() - // .click(); - - // cy.createBooleanQuestion(field1); - // cy.createBooleanQuestion(field2); - // cy.createBooleanQuestion(field3); - - // function addDependency( - // fieldName: string, - // contains: string[], - // select?: string - // ) { - // cy.contains(fieldName).click(); - // cy.get('[data-cy="add-dependency-button"]').click(); - // cy.get('[id="dependency-id"]').click(); - - // contains.forEach((field) => { - // cy.get('[role="listbox"]').contains(field); - // }); - - // if (contains.length === 0) { - // cy.get('[role="listbox"]').children().should('have.length', 2); - // } - - // if (select) { - // cy.get('[role="listbox"]').contains(select).click(); - - // cy.get('[id="dependencyValue"]').click(); - // cy.get('[role="listbox"]').contains('true').click(); - - // cy.contains('Update').click(); - - // cy.finishedLoading(); - // } - // } - - // addDependency(field1, [field2, field3], field2); - // addDependency(field2, [field3], field3); - // addDependency(field3, []); - // }); - - // it('User officer should be able to search questions', function () { - // createTopicWithQuestionsAndRelations(); - // cy.login('officer'); - // cy.visit('/'); - - // cy.navigateToTemplatesSubmenu('Proposal'); - - // // Create an empty template so we can search all question from the question picker - - // cy.get('[data-cy=create-new-button]').click(); - - // cy.get('[data-cy="name"]').type(templateSearch.title); - - // cy.get('[data-cy="description"]').type(templateSearch.description); - - // cy.get('[data-cy="submit"]').click(); - - // cy.get('[data-cy=show-more-button]').click(); - - // // Search questions - // cy.contains('Add question').click(); - - // cy.get('[data-cy=search-button]').click(); - - // // after entering textQuestion, dateQuestion should not be visible - // cy.contains(dateQuestion.title); - // cy.get('[data-cy=search-text] input').clear().type(textQuestion.title); - // cy.contains(textQuestion.title).should('exist'); - // cy.contains(dateQuestion.title).should('not.exist'); - - // cy.get('[data-cy=search-text] input').clear(); - - // // after entering dateQuestion, textQuestion should not be visible - // cy.contains(textQuestion.title); - // cy.get('[data-cy=search-text] input').clear().type(dateQuestion.title); - // cy.contains(dateQuestion.title).should('exist'); - // cy.contains(textQuestion.title).should('not.exist'); - - // cy.get('[data-cy=search-text] input').clear(); - // cy.get('[data-cy=question-list]') - // .contains(booleanQuestion) - // .should('exist'); // this command is here to wait for the list to be clean of the previous search - - // // searching by categories + cy.contains(templateDependencies.questions.selectQuestion.title) + .parent() + .click(); + cy.contains( + templateDependencies.questions.selectQuestion.answer1 + ).click(); - // // Boolean - // cy.get('[data-cy=data-type]').click(); - // cy.get('[role=listbox]').contains('Boolean').click(); - // cy.get('[data-cy=question-list]') - // .contains(booleanQuestion) - // .should('exist'); - // cy.get('[data-cy=question-list]') - // .contains(textQuestion.title) - // .should('not.exist'); + // Dependee is visible + cy.get('main form').should( + 'contain.text', + templateDependencies.questions.booleanQuestion.title + ); - // // Date - // cy.get('[data-cy=data-type]').click(); - // cy.get('[role=listbox]').contains('Date').click(); - // cy.get('[data-cy=question-list]') - // .contains(dateQuestion.title) - // .should('exist'); - // cy.get('[data-cy=question-list]') - // .contains(textQuestion.title) - // .should('not.exist'); + cy.contains(templateDependencies.questions.selectQuestion.title) + .parent() + .click(); + cy.contains( + templateDependencies.questions.selectQuestion.answer2 + ).click(); + + // Dependee is NOT visible again + cy.get('main form').should( + 'not.contain.text', + templateDependencies.questions.booleanQuestion.title + ); + }); - // // All question types - // cy.get('[data-cy=data-type]').click(); - // cy.get('[role=listbox]').contains('All').click(); - // cy.get('[data-cy=question-list]') - // .contains(dateQuestion.title) - // .should('exist'); - // cy.get('[data-cy=question-list]') - // .contains(textQuestion.title) - // .should('exist'); + it('Should not let you create circular dependency chain', () => { + const field1 = 'boolean_1_' + Date.now(); + const field2 = 'boolean_2_' + Date.now(); + const field3 = 'boolean_3_' + Date.now(); + cy.login('officer'); + cy.visit('/'); - // // filter with no results - // cy.get('[data-cy=search-text] input') - // .clear() - // .type('string match no results'); - // cy.get('[data-cy=question-list] div').should('have.length', 0); + cy.navigateToTemplatesSubmenu('Proposal'); - // // closing resets the filter - // cy.get('[data-cy=search-button]').click(); - // cy.get('[data-cy=question-list] div').should('have.length.above', 0); - // }); + cy.contains(initialDBData.template.name) + .parent() + .find("[aria-label='Edit']") + .first() + .click(); - // it('User officer import template', () => { - // const fileName = 'template_import.json'; - // const resolvedQuestionTitle = 'General information'; + cy.createBooleanQuestion(field1); + cy.createBooleanQuestion(field2); + cy.createBooleanQuestion(field3); + + function addDependency( + fieldName: string, + contains: string[], + select?: string + ) { + cy.contains(fieldName).click(); + cy.get('[data-cy="add-dependency-button"]').click(); + cy.get('[id="dependency-id"]').click(); + + contains.forEach((field) => { + cy.get('[role="listbox"]').contains(field); + }); - // cy.login('officer'); - // cy.visit('/'); + if (contains.length === 0) { + cy.get('[role="listbox"]').children().should('have.length', 2); + } - // cy.navigateToTemplatesSubmenu('Proposal'); + if (select) { + cy.get('[role="listbox"]').contains(select).click(); - // cy.get('[data-cy=import-template-button]').click(); + cy.get('[id="dependencyValue"]').click(); + cy.get('[role="listbox"]').contains('true').click(); - // cy.get('input[type="file"]').attachFixture({ - // filePath: fileName, - // fileName: fileName, - // mimeType: 'image/png', - // }); + cy.contains('Update').click(); - // cy.get("[data-cy='proposal_basis-accordion']") - // .find('[data-cy=conflict-icon]') - // .should('exist'); + cy.finishedLoading(); + } + } - // cy.get("[data-cy='proposal_basis-accordion']").click(); + addDependency(field1, [field2, field3], field2); + addDependency(field2, [field3], field3); + addDependency(field3, []); + }); - // cy.get("[data-cy='proposal_basis-accordion']") - // .find("[data-cy='new-item-checkbox']") - // .click(); + it('User officer should be able to search questions', function () { + createTopicWithQuestionsAndRelations(); + cy.login('officer'); + cy.visit('/'); - // cy.get("[data-cy='proposal_basis-accordion']") - // .find('[data-cy=conflict-icon]') - // .should('not.exist'); - - // cy.get("[data-cy='proposal_basis-accordion']") - // .find('[data-cy=resolved-icon]') - // .should('exist'); - - // cy.get('[data-cy=import-template-button]').click(); - - // cy.contains(resolvedQuestionTitle).should('exist'); - - // cy.notification({ - // variant: 'success', - // text: 'Template imported successfully', - // }); - // }); - - // it('should export template in compatible format', () => { - // cy.login('officer'); - // cy.visit('/'); - - // cy.navigateToTemplatesSubmenu('Proposal'); - - // cy.contains(initialDBData.template.name) - // .closest('TR') - // .find('[aria-label="Export"]') - // .click(); - - // cy.fixture('template_export.json').then((expectedExport) => { - // const downloadsFolder = Cypress.config('downloadsFolder'); - - // cy.readFile( - // path.join(downloadsFolder, `${initialDBData.template.name}.json`) - // ).then((actualExport) => { - // // remove date from the export, because it is not deterministic - // delete expectedExport.metadata.exportDate; - // delete actualExport.metadata.exportDate; - - // const exportSubtemplates = expectedExport.data.subTemplates[0]; - // const importSubtemplates = actualExport.data.subTemplates[0]; - - // expect(expectedExport).to.deep.equal(actualExport); - - // expect(exportSubtemplates).to.deep.equal(importSubtemplates); - // }); - // }); - // }); + cy.navigateToTemplatesSubmenu('Proposal'); + + // Create an empty template so we can search all question from the question picker + + cy.get('[data-cy=create-new-button]').click(); + + cy.get('[data-cy="name"]').type(templateSearch.title); + + cy.get('[data-cy="description"]').type(templateSearch.description); + + cy.get('[data-cy="submit"]').click(); + + cy.get('[data-cy=show-more-button]').click(); + + // Search questions + cy.contains('Add question').click(); + + cy.get('[data-cy=search-button]').click(); + + // after entering textQuestion, dateQuestion should not be visible + cy.contains(dateQuestion.title); + cy.get('[data-cy=search-text] input').clear().type(textQuestion.title); + cy.contains(textQuestion.title).should('exist'); + cy.contains(dateQuestion.title).should('not.exist'); + + cy.get('[data-cy=search-text] input').clear(); + + // after entering dateQuestion, textQuestion should not be visible + cy.contains(textQuestion.title); + cy.get('[data-cy=search-text] input').clear().type(dateQuestion.title); + cy.contains(dateQuestion.title).should('exist'); + cy.contains(textQuestion.title).should('not.exist'); + + cy.get('[data-cy=search-text] input').clear(); + cy.get('[data-cy=question-list]') + .contains(booleanQuestion) + .should('exist'); // this command is here to wait for the list to be clean of the previous search + + // searching by categories + + // Boolean + cy.get('[data-cy=data-type]').click(); + cy.get('[role=listbox]').contains('Boolean').click(); + cy.get('[data-cy=question-list]') + .contains(booleanQuestion) + .should('exist'); + cy.get('[data-cy=question-list]') + .contains(textQuestion.title) + .should('not.exist'); + + // Date + cy.get('[data-cy=data-type]').click(); + cy.get('[role=listbox]').contains('Date').click(); + cy.get('[data-cy=question-list]') + .contains(dateQuestion.title) + .should('exist'); + cy.get('[data-cy=question-list]') + .contains(textQuestion.title) + .should('not.exist'); + + // All question types + cy.get('[data-cy=data-type]').click(); + cy.get('[role=listbox]').contains('All').click(); + cy.get('[data-cy=question-list]') + .contains(dateQuestion.title) + .should('exist'); + cy.get('[data-cy=question-list]') + .contains(textQuestion.title) + .should('exist'); + + // filter with no results + cy.get('[data-cy=search-text] input') + .clear() + .type('string match no results'); + cy.get('[data-cy=question-list] div').should('have.length', 0); + + // closing resets the filter + cy.get('[data-cy=search-button]').click(); + cy.get('[data-cy=question-list] div').should('have.length.above', 0); + }); + + it('User officer import template', () => { + const fileName = 'template_import.json'; + const resolvedQuestionTitle = 'General information'; + + cy.login('officer'); + cy.visit('/'); + + cy.navigateToTemplatesSubmenu('Proposal'); + + cy.get('[data-cy=import-template-button]').click(); + + cy.get('input[type="file"]').attachFixture({ + filePath: fileName, + fileName: fileName, + mimeType: 'image/png', + }); + + cy.get("[data-cy='proposal_basis-accordion']") + .find('[data-cy=conflict-icon]') + .should('exist'); + + cy.get("[data-cy='proposal_basis-accordion']").click(); + + cy.get("[data-cy='proposal_basis-accordion']") + .find("[data-cy='new-item-checkbox']") + .click(); + + cy.get("[data-cy='proposal_basis-accordion']") + .find('[data-cy=conflict-icon]') + .should('not.exist'); + + cy.get("[data-cy='proposal_basis-accordion']") + .find('[data-cy=resolved-icon]') + .should('exist'); + + cy.get('[data-cy=import-template-button]').click(); + + cy.contains(resolvedQuestionTitle).should('exist'); + + cy.notification({ + variant: 'success', + text: 'Template imported successfully', + }); + }); + + it('should export template in compatible format', () => { + cy.login('officer'); + cy.visit('/'); + + cy.navigateToTemplatesSubmenu('Proposal'); + + cy.contains(initialDBData.template.name) + .closest('TR') + .find('[aria-label="Export"]') + .click(); + + cy.fixture('template_export.json').then((expectedExport) => { + const downloadsFolder = Cypress.config('downloadsFolder'); + + cy.readFile( + path.join(downloadsFolder, `${initialDBData.template.name}.json`) + ).then((actualExport) => { + // remove date from the export, because it is not deterministic + delete expectedExport.metadata.exportDate; + delete actualExport.metadata.exportDate; + + const exportSubtemplates = expectedExport.data.subTemplates[0]; + const importSubtemplates = actualExport.data.subTemplates[0]; + + expect(expectedExport).to.deep.equal(actualExport); + + expect(exportSubtemplates).to.deep.equal(importSubtemplates); + }); + }); + }); it('should validate question template relation input', () => { createTopicWithQuestionsAndRelations(); @@ -1296,161 +1383,161 @@ context('Template tests', () => { createTopicWithQuestionsAndRelations(true); }); - // it('User can create proposal with template', () => { - // const dateTimeFieldValue = DateTime.fromJSDate( - // faker.date.past() - // ).toFormat(initialDBData.getFormats().dateTimeFormat); - // cy.createProposal({ callId: initialDBData.call.id }).then((result) => { - // const createdProposal = result.createProposal.proposal; - // if (createdProposal) { - // cy.updateProposal({ - // proposalPk: createdProposal.primaryKey, - // title: proposal.title, - // abstract: proposal.abstract, - // proposerId: initialDBData.users.user1.id, - // }); - // } - // }); - // cy.login('user'); - // cy.visit('/'); - - // cy.contains(proposal.title) - // .parent() - // .find('[aria-label="Edit proposal"]') - // .click(); - - // cy.contains('save and continue', { matchCase: false }).click(); - // cy.finishedLoading(); - - // cy.get(`[data-cy="${intervalId}.min"]`).click().type('1'); - // cy.get(`[data-cy="${intervalId}.max"]`).click().type('2'); - // cy.get(`[data-cy="${numberId}.value"]`).click().type('1'); - // cy.get(`#${boolId}`).click(); - // cy.get(`#${textId}`).clear().type('this_word_{enter}should_be_multiline'); - // cy.contains('this_word_should_be_multiline').should('not.exist'); - // cy.get(`#${textId}`).clear().type(textQuestion.answer); - // cy.contains(`${textQuestion.answer.length}/${textQuestion.maxChars}`); - // cy.get(`[data-cy='${dateId}.value'] button`).click(); - // cy.contains('15').click(); - // cy.get(`[data-cy='${timeId}.value'] input`) - // .clear() - // .type(dateTimeFieldValue); - - // cy.get(`#${multipleChoiceId}`).click(); - // cy.contains(multipleChoiceQuestion.answers[0]).click(); - // cy.contains(multipleChoiceQuestion.answers[2]).click(); - // cy.get('body').type('{esc}'); - - // cy.window().then((win) => { - // return new Cypress.Promise((resolve) => { - // win.tinyMCE.editors[richTextInputId].setContent( - // richTextInputQuestion.answer - // ); - // win.tinyMCE.editors[richTextInputId].fire('blur'); - - // resolve(); - // }); - // }); - - // cy.get(`#${richTextInputId}_ifr`) - // .its('0.contentDocument.body') - // .should('not.be.empty') - // .contains(richTextInputQuestion.answer); - - // cy.get('[data-cy="rich-text-char-count"]').then((element) => { - // expect(element.text()).to.be.equal( - // `Characters: ${richTextInputQuestion.answer.length} / ${richTextInputQuestion.maxChars}` - // ); - // }); - - // cy.contains('Save and continue').click(); - - // cy.contains('Submit').click(); - - // cy.contains('OK').click(); - - // cy.contains(proposal.title); - // cy.contains(proposal.abstract); - // cy.contains(textQuestion.answer); - // cy.contains(multipleChoiceQuestion.answers[0]); - // cy.contains(multipleChoiceQuestion.answers[1]).should('not.exist'); - // cy.contains(multipleChoiceQuestion.answers[2]); - // cy.contains(dateTimeFieldValue); - - // cy.contains(richTextInputQuestion.title); - // cy.get(`[data-cy="${richTextInputId}_open"]`).click(); - // cy.get('[role="dialog"]').contains(richTextInputQuestion.title); - // cy.get('[role="dialog"]').contains(richTextInputQuestion.answer); - // cy.get('[role="dialog"]').contains('Close').click(); - - // cy.contains('Dashboard').click(); - // cy.contains(proposal.title); - // cy.contains('submitted'); - // }); - - // it('File Upload field could be set as required', () => { - // const fileName = 'file_upload_test.png'; - - // cy.login('officer'); - // cy.visit('/'); - - // cy.navigateToTemplatesSubmenu('Proposal'); - - // cy.contains(initialDBData.template.name) - // .parent() - // .find("[aria-label='Edit']") - // .first() - // .click(); - - // cy.contains(fileQuestion).click(); - - // cy.get('[role="presentation"]').contains('image/*').click(); - - // cy.get('body').type('{esc}'); - - // cy.contains('Is required').click(); + it('User can create proposal with template', () => { + const dateTimeFieldValue = DateTime.fromJSDate( + faker.date.past() + ).toFormat(initialDBData.getFormats().dateTimeFormat); + cy.createProposal({ callId: initialDBData.call.id }).then((result) => { + const createdProposal = result.createProposal.proposal; + if (createdProposal) { + cy.updateProposal({ + proposalPk: createdProposal.primaryKey, + title: proposal.title, + abstract: proposal.abstract, + proposerId: initialDBData.users.user1.id, + }); + } + }); + cy.login('user'); + cy.visit('/'); + + cy.contains(proposal.title) + .parent() + .find('[aria-label="Edit proposal"]') + .click(); + + cy.contains('save and continue', { matchCase: false }).click(); + cy.finishedLoading(); + + cy.get(`[data-cy="${intervalId}.min"]`).click().type('1'); + cy.get(`[data-cy="${intervalId}.max"]`).click().type('2'); + cy.get(`[data-cy="${numberId}.value"]`).click().type('1'); + cy.get(`#${boolId}`).click(); + cy.get(`#${textId}`).clear().type('this_word_{enter}should_be_multiline'); + cy.contains('this_word_should_be_multiline').should('not.exist'); + cy.get(`#${textId}`).clear().type(textQuestion.answer); + cy.contains(`${textQuestion.answer.length}/${textQuestion.maxChars}`); + cy.get(`[data-cy='${dateId}.value'] button`).click(); + cy.contains('15').click(); + cy.get(`[data-cy='${timeId}.value'] input`) + .clear() + .type(dateTimeFieldValue); + + cy.get(`#${multipleChoiceId}`).click(); + cy.contains(multipleChoiceQuestion.answers[0]).click(); + cy.contains(multipleChoiceQuestion.answers[2]).click(); + cy.get('body').type('{esc}'); + + cy.window().then((win) => { + return new Cypress.Promise((resolve) => { + win.tinyMCE.editors[richTextInputId].setContent( + richTextInputQuestion.answer + ); + win.tinyMCE.editors[richTextInputId].fire('blur'); + + resolve(); + }); + }); + + cy.get(`#${richTextInputId}_ifr`) + .its('0.contentDocument.body') + .should('not.be.empty') + .contains(richTextInputQuestion.answer); + + cy.get('[data-cy="rich-text-char-count"]').then((element) => { + expect(element.text()).to.be.equal( + `Characters: ${richTextInputQuestion.answer.length} / ${richTextInputQuestion.maxChars}` + ); + }); + + cy.contains('Save and continue').click(); + + cy.contains('Submit').click(); + + cy.contains('OK').click(); + + cy.contains(proposal.title); + cy.contains(proposal.abstract); + cy.contains(textQuestion.answer); + cy.contains(multipleChoiceQuestion.answers[0]); + cy.contains(multipleChoiceQuestion.answers[1]).should('not.exist'); + cy.contains(multipleChoiceQuestion.answers[2]); + cy.contains(dateTimeFieldValue); + + cy.contains(richTextInputQuestion.title); + cy.get(`[data-cy="${richTextInputId}_open"]`).click(); + cy.get('[role="dialog"]').contains(richTextInputQuestion.title); + cy.get('[role="dialog"]').contains(richTextInputQuestion.answer); + cy.get('[role="dialog"]').contains('Close').click(); + + cy.contains('Dashboard').click(); + cy.contains(proposal.title); + cy.contains('submitted'); + }); + + it('File Upload field could be set as required', () => { + const fileName = 'file_upload_test.png'; - // cy.contains('Update').click(); + cy.login('officer'); + cy.visit('/'); - // cy.logout(); + cy.navigateToTemplatesSubmenu('Proposal'); - // cy.login('user'); - // cy.visit('/'); + cy.contains(initialDBData.template.name) + .parent() + .find("[aria-label='Edit']") + .first() + .click(); - // cy.contains('New Proposal').click(); + cy.contains(fileQuestion).click(); - // cy.get('[data-cy=title] input').type(faker.lorem.words(2)); - // cy.get('[data-cy=abstract] textarea').first().type(faker.lorem.words(2)); - // cy.contains('Save and continue').click(); + cy.get('[role="presentation"]').contains('image/*').click(); - // cy.contains(fileQuestion); - // cy.contains('Save and continue').click(); - // cy.contains(fileQuestion) - // .parent() - // .contains('field must have at least 1 items'); + cy.get('body').type('{esc}'); - // cy.intercept({ - // method: 'POST', - // url: '/files/upload', - // }).as('upload'); + cy.contains('Is required').click(); - // cy.get('input[type="file"]').attachFixture({ - // filePath: fileName, - // fileName: fileName, - // mimeType: 'image/png', - // }); + cy.contains('Update').click(); - // // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error - // cy.wait('@upload', { requestTimeout: 30000 }); + cy.logout(); - // cy.contains(fileName); + cy.login('user'); + cy.visit('/'); - // cy.contains(fileQuestion) - // .parent() - // .should('not.contain.text', 'field must have at least 1 items'); + cy.contains('New Proposal').click(); - // cy.logout(); - // }); + cy.get('[data-cy=title] input').type(faker.lorem.words(2)); + cy.get('[data-cy=abstract] textarea').first().type(faker.lorem.words(2)); + cy.contains('Save and continue').click(); + + cy.contains(fileQuestion); + cy.contains('Save and continue').click(); + cy.contains(fileQuestion) + .parent() + .contains('field must have at least 1 items'); + + cy.intercept({ + method: 'POST', + url: '/files/upload', + }).as('upload'); + + cy.get('input[type="file"]').attachFixture({ + filePath: fileName, + fileName: fileName, + mimeType: 'image/png', + }); + + // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error + cy.wait('@upload', { requestTimeout: 30000 }); + + cy.contains(fileName); + + cy.contains(fileQuestion) + .parent() + .should('not.contain.text', 'field must have at least 1 items'); + + cy.logout(); + }); it('File Upload max files should be required', () => { cy.login('officer'); @@ -1488,504 +1575,504 @@ context('Template tests', () => { cy.logout(); }); - // it('Officer can delete proposal questions', () => { - // cy.login('officer'); - // cy.visit('/'); + it('Officer can delete proposal questions', () => { + cy.login('officer'); + cy.visit('/'); + + cy.navigateToTemplatesSubmenu('Proposal'); + + cy.contains(initialDBData.template.name) + .parent() + .find("[aria-label='Edit']") + .first() + .click(); + + cy.contains(textQuestion.title).click(); + cy.get("[data-cy='remove-from-template']").click(); + + cy.contains(booleanQuestion).click(); + cy.get("[data-cy='remove-from-template']").click(); + + cy.contains(dateQuestion.title).click(); + cy.get("[data-cy='remove-from-template']").click(); + + cy.contains(fileQuestion).click(); + cy.get("[data-cy='remove-from-template']").click(); + }); + + it('User officer can add multiple dependencies on a question', () => { + cy.createProposal({ callId: initialDBData.call.id }).then((result) => { + const createdProposal = result.createProposal.proposal; + if (createdProposal) { + cy.updateProposal({ + proposalPk: createdProposal.primaryKey, + title: proposal.title, + abstract: proposal.abstract, + proposerId: initialDBData.users.user1.id, + }); + } + }); + cy.login('officer'); + cy.visit('/'); - // cy.navigateToTemplatesSubmenu('Proposal'); + cy.navigateToTemplatesSubmenu('Proposal'); - // cy.contains(initialDBData.template.name) - // .parent() - // .find("[aria-label='Edit']") - // .first() - // .click(); + cy.contains(initialDBData.template.name) + .parent() + .find("[aria-label='Edit']") + .first() + .click(); - // cy.contains(textQuestion.title).click(); - // cy.get("[data-cy='remove-from-template']").click(); + cy.createTextQuestion(templateDependencies.questions.textQuestion.title); - // cy.contains(booleanQuestion).click(); - // cy.get("[data-cy='remove-from-template']").click(); + cy.contains(templateDependencies.questions.textQuestion.title).click(); - // cy.contains(dateQuestion.title).click(); - // cy.get("[data-cy='remove-from-template']").click(); + cy.get('[data-cy="add-dependency-button"]').click(); - // cy.contains(fileQuestion).click(); - // cy.get("[data-cy='remove-from-template']").click(); - // }); + cy.get('[id="dependency-id"]').click(); - // it('User officer can add multiple dependencies on a question', () => { - // cy.createProposal({ callId: initialDBData.call.id }).then((result) => { - // const createdProposal = result.createProposal.proposal; - // if (createdProposal) { - // cy.updateProposal({ - // proposalPk: createdProposal.primaryKey, - // title: proposal.title, - // abstract: proposal.abstract, - // proposerId: initialDBData.users.user1.id, - // }); - // } - // }); - // cy.login('officer'); - // cy.visit('/'); + cy.get('[role="presentation"]') + .contains(multipleChoiceQuestion.title) + .click(); - // cy.navigateToTemplatesSubmenu('Proposal'); + cy.get('[id="dependencyValue"]').click(); - // cy.contains(initialDBData.template.name) - // .parent() - // .find("[aria-label='Edit']") - // .first() - // .click(); + cy.contains(multipleChoiceQuestion.answers[1]).click(); - // cy.createTextQuestion(templateDependencies.questions.textQuestion.title); + cy.get('[data-cy="add-dependency-button"]').click(); - // cy.contains(templateDependencies.questions.textQuestion.title).click(); + cy.get('[id="dependency-id"]').last().click(); - // cy.get('[data-cy="add-dependency-button"]').click(); + cy.get('[role="presentation"]').contains(booleanQuestion).click(); - // cy.get('[id="dependency-id"]').click(); + cy.get('[id="dependencyValue"]').last().click(); - // cy.get('[role="presentation"]') - // .contains(multipleChoiceQuestion.title) - // .click(); + cy.contains('true').click(); - // cy.get('[id="dependencyValue"]').click(); + cy.get('[data-cy="submit"]').click(); - // cy.contains(multipleChoiceQuestion.answers[1]).click(); + cy.logout(); - // cy.get('[data-cy="add-dependency-button"]').click(); + cy.login('user'); + cy.visit('/'); - // cy.get('[id="dependency-id"]').last().click(); + cy.contains(proposal.title) + .parent() + .find('[aria-label="Edit proposal"]') + .click(); + + cy.contains('save and continue', { matchCase: false }).click(); + cy.finishedLoading(); + + cy.get('main form').should( + 'not.contain.text', + templateDependencies.questions.textQuestion.title + ); + + cy.contains(multipleChoiceQuestion.title).parent().click(); + cy.contains(multipleChoiceQuestion.answers[1]).click(); + cy.get('body').type('{esc}'); + cy.get('main form').should( + 'not.contain.text', + templateDependencies.questions.textQuestion.title + ); - // cy.get('[role="presentation"]').contains(booleanQuestion).click(); + cy.contains(booleanQuestion).click(); - // cy.get('[id="dependencyValue"]').last().click(); + cy.get('main form').should( + 'contain.text', + templateDependencies.questions.textQuestion.title + ); - // cy.contains('true').click(); + cy.contains(multipleChoiceQuestion.title).parent().click(); + cy.get('[role="presentation"]') + .contains(multipleChoiceQuestion.answers[1]) + .click(); + cy.contains(multipleChoiceQuestion.answers[2]).click(); + cy.get('body').type('{esc}'); - // cy.get('[data-cy="submit"]').click(); + cy.get('main form').should( + 'not.contain.text', + templateDependencies.questions.textQuestion.title + ); + }); - // cy.logout(); + it('User officer can change dependency logic operator', () => { + cy.createProposal({ callId: initialDBData.call.id }).then((result) => { + const createdProposal = result.createProposal.proposal; + if (createdProposal) { + cy.updateProposal({ + proposalPk: createdProposal.primaryKey, + title: proposal.title, + abstract: proposal.abstract, + proposerId: initialDBData.users.user1.id, + }); + } + }); + cy.login('officer'); + cy.visit('/'); - // cy.login('user'); - // cy.visit('/'); + cy.navigateToTemplatesSubmenu('Proposal'); - // cy.contains(proposal.title) - // .parent() - // .find('[aria-label="Edit proposal"]') - // .click(); + cy.get('[aria-label="Edit"]').last().click(); - // cy.contains('save and continue', { matchCase: false }).click(); - // cy.finishedLoading(); + cy.contains(textQuestion.title).click(); - // cy.get('main form').should( - // 'not.contain.text', - // templateDependencies.questions.textQuestion.title - // ); + cy.get('[data-cy="add-dependency-button"]').click(); - // cy.contains(multipleChoiceQuestion.title).parent().click(); - // cy.contains(multipleChoiceQuestion.answers[1]).click(); - // cy.get('body').type('{esc}'); - // cy.get('main form').should( - // 'not.contain.text', - // templateDependencies.questions.textQuestion.title - // ); + cy.get('[id="dependency-id"]').last().click(); - // cy.contains(booleanQuestion).click(); + cy.get('[role="presentation"]') + .contains(multipleChoiceQuestion.title) + .click(); - // cy.get('main form').should( - // 'contain.text', - // templateDependencies.questions.textQuestion.title - // ); + cy.get('[id="dependencyValue"]').last().click(); - // cy.contains(multipleChoiceQuestion.title).parent().click(); - // cy.get('[role="presentation"]') - // .contains(multipleChoiceQuestion.answers[1]) - // .click(); - // cy.contains(multipleChoiceQuestion.answers[2]).click(); - // cy.get('body').type('{esc}'); + cy.contains(multipleChoiceQuestion.answers[1]).click(); - // cy.get('main form').should( - // 'not.contain.text', - // templateDependencies.questions.textQuestion.title - // ); - // }); + cy.get('[data-cy="dependencies-operator"]').click(); - // it('User officer can change dependency logic operator', () => { - // cy.createProposal({ callId: initialDBData.call.id }).then((result) => { - // const createdProposal = result.createProposal.proposal; - // if (createdProposal) { - // cy.updateProposal({ - // proposalPk: createdProposal.primaryKey, - // title: proposal.title, - // abstract: proposal.abstract, - // proposerId: initialDBData.users.user1.id, - // }); - // } - // }); - // cy.login('officer'); - // cy.visit('/'); + cy.get('[data-value="OR"]').click(); - // cy.navigateToTemplatesSubmenu('Proposal'); + cy.get('[data-cy="submit"]').click(); - // cy.get('[aria-label="Edit"]').last().click(); + cy.logout(); - // cy.contains(textQuestion.title).click(); + cy.login('user'); + cy.visit('/'); - // cy.get('[data-cy="add-dependency-button"]').click(); + cy.contains(proposal.title) + .parent() + .find('[aria-label="Edit proposal"]') + .click(); - // cy.get('[id="dependency-id"]').last().click(); + cy.contains('save and continue', { matchCase: false }).click(); + cy.finishedLoading(); - // cy.get('[role="presentation"]') - // .contains(multipleChoiceQuestion.title) - // .click(); + cy.get('main form').should('not.contain.text', textQuestion.title); - // cy.get('[id="dependencyValue"]').last().click(); + cy.contains(multipleChoiceQuestion.title).parent().click(); + cy.contains(multipleChoiceQuestion.answers[1]).click(); + cy.get('body').type('{esc}'); + cy.contains(textQuestion.title); - // cy.contains(multipleChoiceQuestion.answers[1]).click(); + cy.contains(multipleChoiceQuestion.title).parent().click(); + cy.get('[role="presentation"]') + .contains(multipleChoiceQuestion.answers[1]) + .click(); + cy.contains(multipleChoiceQuestion.answers[2]).click(); + cy.get('body').type('{esc}'); - // cy.get('[data-cy="dependencies-operator"]').click(); + cy.get('main form').should('not.contain.text', textQuestion.title); - // cy.get('[data-value="OR"]').click(); + cy.contains(booleanQuestion).click(); + cy.contains(textQuestion.title); + }); - // cy.get('[data-cy="submit"]').click(); + it('Can delete dependee, which will remove the dependency on depender', () => { + cy.login('officer'); + cy.visit('/'); - // cy.logout(); + cy.navigateToTemplatesSubmenu('Proposal'); - // cy.login('user'); - // cy.visit('/'); + cy.contains(initialDBData.template.name) + .parent() + .find("[aria-label='Edit']") + .first() + .click(); - // cy.contains(proposal.title) - // .parent() - // .find('[aria-label="Edit proposal"]') - // .click(); + cy.contains(textQuestion.title) + .closest('[data-cy=question-container]') + .find('[data-cy=dependency-list]') + .should('exist'); + cy.contains(booleanQuestion).click(); + cy.get('[data-cy=remove-from-template]').click(); + cy.contains(textQuestion.title) + .closest('[data-cy=question-container]') + .find('[data-cy=dependency-list]') + .should('not.exist'); + }); - // cy.contains('save and continue', { matchCase: false }).click(); - // cy.finishedLoading(); + it('User can add captions after uploading image/* file', () => { + const fileName = 'file_upload_test2.png'; // need to use another file due to bug in cypress, which do not allow the same fixture to be reused + cy.createProposal({ callId: initialDBData.call.id }).then((result) => { + const createdProposal = result.createProposal.proposal; + if (createdProposal) { + cy.updateProposal({ + proposalPk: createdProposal.primaryKey, + title: proposal.title, + abstract: proposal.abstract, + proposerId: initialDBData.users.user1.id, + }); + } + }); - // cy.get('main form').should('not.contain.text', textQuestion.title); + cy.login('user'); + cy.visit('/'); - // cy.contains(multipleChoiceQuestion.title).parent().click(); - // cy.contains(multipleChoiceQuestion.answers[1]).click(); - // cy.get('body').type('{esc}'); - // cy.contains(textQuestion.title); + cy.contains(proposal.title) + .parent() + .find('[aria-label="Edit proposal"]') + .click(); + cy.finishedLoading(); - // cy.contains(multipleChoiceQuestion.title).parent().click(); - // cy.get('[role="presentation"]') - // .contains(multipleChoiceQuestion.answers[1]) - // .click(); - // cy.contains(multipleChoiceQuestion.answers[2]).click(); - // cy.get('body').type('{esc}'); + cy.contains('Save and continue').click(); - // cy.get('main form').should('not.contain.text', textQuestion.title); + cy.contains(fileQuestion); - // cy.contains(booleanQuestion).click(); - // cy.contains(textQuestion.title); - // }); + cy.intercept({ + method: 'POST', + url: '/files/upload', + }).as('upload'); - // it('Can delete dependee, which will remove the dependency on depender', () => { - // cy.login('officer'); - // cy.visit('/'); + cy.get('input[type="file"]').attachFixture({ + filePath: fileName, + fileName: fileName, + mimeType: 'image/png', + }); - // cy.navigateToTemplatesSubmenu('Proposal'); + // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error + cy.wait('@upload', { requestTimeout: 30000 }); - // cy.contains(initialDBData.template.name) - // .parent() - // .find("[aria-label='Edit']") - // .first() - // .click(); + cy.contains(fileName); - // cy.contains(textQuestion.title) - // .closest('[data-cy=question-container]') - // .find('[data-cy=dependency-list]') - // .should('exist'); - // cy.contains(booleanQuestion).click(); - // cy.get('[data-cy=remove-from-template]').click(); - // cy.contains(textQuestion.title) - // .closest('[data-cy=question-container]') - // .find('[data-cy=dependency-list]') - // .should('not.exist'); - // }); + cy.get('[aria-label="Add image caption"]').click(); - // it('User can add captions after uploading image/* file', () => { - // const fileName = 'file_upload_test2.png'; // need to use another file due to bug in cypress, which do not allow the same fixture to be reused - // cy.createProposal({ callId: initialDBData.call.id }).then((result) => { - // const createdProposal = result.createProposal.proposal; - // if (createdProposal) { - // cy.updateProposal({ - // proposalPk: createdProposal.primaryKey, - // title: proposal.title, - // abstract: proposal.abstract, - // proposerId: initialDBData.users.user1.id, - // }); - // } - // }); + cy.get('[data-cy="image-figure"] input').type('Fig_test'); + cy.get('[data-cy="image-caption"] input').type('Test caption'); - // cy.login('user'); - // cy.visit('/'); + cy.get('[data-cy="save-button"]').click(); - // cy.contains(proposal.title) - // .parent() - // .find('[aria-label="Edit proposal"]') - // .click(); - // cy.finishedLoading(); + cy.notification({ variant: 'success', text: 'Saved' }); - // cy.contains('Save and continue').click(); + cy.finishedLoading(); - // cy.contains(fileQuestion); + cy.get('.MuiStep-root').contains('Review').click(); - // cy.intercept({ - // method: 'POST', - // url: '/files/upload', - // }).as('upload'); + cy.contains(proposal.abstract); - // cy.get('input[type="file"]').attachFixture({ - // filePath: fileName, - // fileName: fileName, - // mimeType: 'image/png', - // }); + cy.contains(fileName); - // // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error - // cy.wait('@upload', { requestTimeout: 30000 }); + cy.get('[data-cy="questionary-stepper"]') + .contains(initialDBData.template.topic.title) + .click(); - // cy.contains(fileName); + cy.finishedLoading(); + cy.contains('Save and continue'); - // cy.get('[aria-label="Add image caption"]').click(); - - // cy.get('[data-cy="image-figure"] input').type('Fig_test'); - // cy.get('[data-cy="image-caption"] input').type('Test caption'); - - // cy.get('[data-cy="save-button"]').click(); - - // cy.notification({ variant: 'success', text: 'Saved' }); - - // cy.finishedLoading(); - - // cy.get('.MuiStep-root').contains('Review').click(); - - // cy.contains(proposal.abstract); - - // cy.contains(fileName); - - // cy.get('[data-cy="questionary-stepper"]') - // .contains(initialDBData.template.topic.title) - // .click(); - - // cy.finishedLoading(); - // cy.contains('Save and continue'); - - // cy.contains(fileQuestion) - // .parent() - // .should('contain.text', fileName) - // .find('[data-cy="image-caption"] input') - // .should('have.value', 'Test caption'); - // cy.contains(fileQuestion) - // .parent() - // .find('[data-cy="image-figure"] input') - // .should('have.value', 'Fig_test'); - // }); + cy.contains(fileQuestion) + .parent() + .should('contain.text', fileName) + .find('[data-cy="image-caption"] input') + .should('have.value', 'Test caption'); + cy.contains(fileQuestion) + .parent() + .find('[data-cy="image-figure"] input') + .should('have.value', 'Fig_test'); + }); }); - // describe('File upload tests', () => { - // beforeEach(() => { - // cy.login('officer'); - // cy.visit('/'); + describe('File upload tests', () => { + beforeEach(() => { + cy.login('officer'); + cy.visit('/'); - // cy.navigateToTemplatesSubmenu('Proposal'); + cy.navigateToTemplatesSubmenu('Proposal'); - // cy.contains(initialDBData.template.name) - // .parent() - // .find("[aria-label='Edit']") - // .first() - // .click(); + cy.contains(initialDBData.template.name) + .parent() + .find("[aria-label='Edit']") + .first() + .click(); - // cy.createFileUploadQuestion(fileQuestion, ['.pdf', '.docx', 'image/*']); + cy.createFileUploadQuestion(fileQuestion, ['.pdf', '.docx', 'image/*']); - // cy.login('user'); - // cy.visit('/'); + cy.login('user'); + cy.visit('/'); - // cy.contains('New Proposal').click(); + cy.contains('New Proposal').click(); - // cy.get('[data-cy=title] input').type('title'); + cy.get('[data-cy=title] input').type('title'); - // cy.get('[data-cy=abstract] textarea').first().type('abstract'); + cy.get('[data-cy=abstract] textarea').first().type('abstract'); - // cy.contains(fileQuestion); - // }); + cy.contains(fileQuestion); + }); - // it('File limitation info is displayed', () => { - // cy.contains('Accepted formats: .pdf, .docx, any image'); - // cy.contains('Maximum 3 PDF page(s) per file'); - // cy.contains('Maximum 3 file(s)'); - // }); + it('File limitation info is displayed', () => { + cy.contains('Accepted formats: .pdf, .docx, any image'); + cy.contains('Maximum 3 PDF page(s) per file'); + cy.contains('Maximum 3 file(s)'); + }); - // it('File without extension cannot be uploaded', () => { - // const fileName = 'file_without_ext'; + it('File without extension cannot be uploaded', () => { + const fileName = 'file_without_ext'; - // cy.get('input[type="file"]').attachFixture({ - // filePath: fileName, - // fileName: fileName, - // mimeType: 'application/pdf', - // }); + cy.get('input[type="file"]').attachFixture({ + filePath: fileName, + fileName: fileName, + mimeType: 'application/pdf', + }); - // cy.contains('Incorrect file type'); - // }); + cy.contains('Incorrect file type'); + }); - // it('File with incorrect content header cannot be uploaded', () => { - // const fileName = 'file_upload_test.png'; + it('File with incorrect content header cannot be uploaded', () => { + const fileName = 'file_upload_test.png'; - // cy.get('input[type="file"]').attachFixture({ - // filePath: fileName, - // fileName: fileName, - // mimeType: 'application/octet-stream', - // }); + cy.get('input[type="file"]').attachFixture({ + filePath: fileName, + fileName: fileName, + mimeType: 'application/octet-stream', + }); - // cy.contains('Incorrect file type'); - // }); + cy.contains('Incorrect file type'); + }); - // it('Unidentifiable disguised file is uploaded but not accepted', () => { - // const fileName = 'unidentifiable_file.pdf'; + it('Unidentifiable disguised file is uploaded but not accepted', () => { + const fileName = 'unidentifiable_file.pdf'; - // cy.intercept({ - // method: 'POST', - // url: '/files/upload', - // }).as('upload'); + cy.intercept({ + method: 'POST', + url: '/files/upload', + }).as('upload'); - // cy.get('input[type="file"]').attachFixture({ - // filePath: fileName, - // fileName: fileName, - // mimeType: 'application/pdf', - // }); + cy.get('input[type="file"]').attachFixture({ + filePath: fileName, + fileName: fileName, + mimeType: 'application/pdf', + }); - // // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error - // cy.wait('@upload', { requestTimeout: 30000 }); + // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error + cy.wait('@upload', { requestTimeout: 30000 }); - // cy.contains(fileName); + cy.contains(fileName); - // cy.contains('Save and continue').click(); + cy.contains('Save and continue').click(); - // cy.notification({ variant: 'error', text: 'not satisfying constraint' }); - // }); + cy.notification({ variant: 'error', text: 'not satisfying constraint' }); + }); - // it('Identifiable disguised file is uploaded but not accepted', () => { - // const fileName = 'mp3_file.pdf'; + it('Identifiable disguised file is uploaded but not accepted', () => { + const fileName = 'mp3_file.pdf'; - // cy.intercept({ - // method: 'POST', - // url: '/files/upload', - // }).as('upload'); + cy.intercept({ + method: 'POST', + url: '/files/upload', + }).as('upload'); - // cy.get('input[type="file"]').attachFixture({ - // filePath: fileName, - // fileName: fileName, - // mimeType: 'application/pdf', - // }); + cy.get('input[type="file"]').attachFixture({ + filePath: fileName, + fileName: fileName, + mimeType: 'application/pdf', + }); - // // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error - // cy.wait('@upload', { requestTimeout: 30000 }); + // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error + cy.wait('@upload', { requestTimeout: 30000 }); - // cy.contains(fileName); + cy.contains(fileName); - // cy.contains('Save and continue').click(); + cy.contains('Save and continue').click(); - // cy.notification({ variant: 'error', text: 'not satisfying constraint' }); - // }); + cy.notification({ variant: 'error', text: 'not satisfying constraint' }); + }); - // it('Question is not accepted when one of many files is invalid', () => { - // const validFile = 'file_upload_test.png'; - // const invalidFile = 'mp3_file.pdf'; + it('Question is not accepted when one of many files is invalid', () => { + const validFile = 'file_upload_test.png'; + const invalidFile = 'mp3_file.pdf'; - // cy.intercept({ - // method: 'POST', - // url: '/files/upload', - // }).as('upload'); + cy.intercept({ + method: 'POST', + url: '/files/upload', + }).as('upload'); - // cy.get('input[type="file"]').attachFixture({ - // filePath: validFile, - // fileName: validFile, - // mimeType: 'image/png', - // }); + cy.get('input[type="file"]').attachFixture({ + filePath: validFile, + fileName: validFile, + mimeType: 'image/png', + }); - // // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error - // cy.wait('@upload', { requestTimeout: 30000 }); + // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error + cy.wait('@upload', { requestTimeout: 30000 }); - // cy.contains(validFile); + cy.contains(validFile); - // cy.contains('Save and continue').click(); + cy.contains('Save and continue').click(); - // cy.notification({ variant: 'success', text: 'Saved' }); + cy.notification({ variant: 'success', text: 'Saved' }); - // cy.contains('Back').click(); + cy.contains('Back').click(); - // cy.contains(fileQuestion); - // cy.contains(validFile); + cy.contains(fileQuestion); + cy.contains(validFile); - // cy.intercept({ - // method: 'POST', - // url: '/files/upload', - // }).as('upload'); + cy.intercept({ + method: 'POST', + url: '/files/upload', + }).as('upload'); - // cy.get('input[type="file"]').attachFixture({ - // filePath: invalidFile, - // fileName: invalidFile, - // mimeType: 'application/pdf', - // }); + cy.get('input[type="file"]').attachFixture({ + filePath: invalidFile, + fileName: invalidFile, + mimeType: 'application/pdf', + }); - // // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error - // cy.wait('@upload', { requestTimeout: 30000 }); + // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error + cy.wait('@upload', { requestTimeout: 30000 }); - // cy.contains(invalidFile); + cy.contains(invalidFile); - // cy.contains('Save and continue').click(); + cy.contains('Save and continue').click(); - // cy.notification({ variant: 'error', text: 'not satisfying constraint' }); - // }); + cy.notification({ variant: 'error', text: 'not satisfying constraint' }); + }); - // it('Question is not accepted when PDF file page count is outside limit', () => { - // const fileName = 'pdf_5_pages.pdf'; + it('Question is not accepted when PDF file page count is outside limit', () => { + const fileName = 'pdf_5_pages.pdf'; - // cy.intercept({ - // method: 'POST', - // url: '/files/upload', - // }).as('upload'); + cy.intercept({ + method: 'POST', + url: '/files/upload', + }).as('upload'); - // cy.get('input[type="file"]').attachFixture({ - // filePath: fileName, - // fileName: fileName, - // mimeType: 'application/pdf', - // }); + cy.get('input[type="file"]').attachFixture({ + filePath: fileName, + fileName: fileName, + mimeType: 'application/pdf', + }); - // // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error - // cy.wait('@upload', { requestTimeout: 30000 }); + // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error + cy.wait('@upload', { requestTimeout: 30000 }); - // cy.contains(fileName); + cy.contains(fileName); - // cy.contains('Save and continue').click(); + cy.contains('Save and continue').click(); - // cy.notification({ variant: 'error', text: 'not satisfying constraint' }); - // }); + cy.notification({ variant: 'error', text: 'not satisfying constraint' }); + }); - // it('Question accepted when PDF file page count is within limit', () => { - // const fileName = 'pdf_3_pages.pdf'; + it('Question accepted when PDF file page count is within limit', () => { + const fileName = 'pdf_3_pages.pdf'; - // cy.intercept({ - // method: 'POST', - // url: '/files/upload', - // }).as('upload'); + cy.intercept({ + method: 'POST', + url: '/files/upload', + }).as('upload'); - // cy.get('input[type="file"]').attachFixture({ - // filePath: fileName, - // fileName: fileName, - // mimeType: 'application/pdf', - // }); + cy.get('input[type="file"]').attachFixture({ + filePath: fileName, + fileName: fileName, + mimeType: 'application/pdf', + }); - // // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error - // cy.wait('@upload', { requestTimeout: 30000 }); + // wait for the '/files/upload' request, and leave a 30 seconds delay before throwing an error + cy.wait('@upload', { requestTimeout: 30000 }); - // cy.contains(fileName); + cy.contains(fileName); - // cy.contains('Save and continue').click(); + cy.contains('Save and continue').click(); - // cy.notification({ variant: 'success', text: 'Saved' }); - // }); - // }); + cy.notification({ variant: 'success', text: 'Saved' }); + }); + }); }); diff --git a/cypress/integration/units.ts b/cypress/integration/units.ts index 60d433d96..71f0f4c13 100644 --- a/cypress/integration/units.ts +++ b/cypress/integration/units.ts @@ -1,6 +1,6 @@ import path from 'path'; -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { DateTime } from 'luxon'; import initialDBData from '../support/initialDBData'; @@ -8,6 +8,7 @@ import initialDBData from '../support/initialDBData'; context('Units tests', () => { describe('Template basic unit tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); }); @@ -146,6 +147,7 @@ context('Units tests', () => { describe('Template advanced unit tests', () => { beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(true); }); diff --git a/cypress/integration/user_administration.ts b/cypress/integration/user_administration.ts index e67de04c6..d5a3e1bd0 100644 --- a/cypress/integration/user_administration.ts +++ b/cypress/integration/user_administration.ts @@ -1,5 +1,7 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; +import { FeatureId } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; context('User administration tests', () => { @@ -15,7 +17,14 @@ context('User administration tests', () => { const placeholderUser = initialDBData.users.placeholder; beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); + }); + + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.USER_MANAGEMENT)) { + this.skip(); + } cy.login('officer'); cy.visit('/'); diff --git a/cypress/integration/user_spec.ts b/cypress/integration/user_spec.ts index 0cc67e3b1..5240bdfc8 100644 --- a/cypress/integration/user_spec.ts +++ b/cypress/integration/user_spec.ts @@ -1,6 +1,8 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { DateTime } from 'luxon'; +import { FeatureId } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; context('User tests', () => { @@ -22,7 +24,14 @@ context('User tests', () => { const telephone = faker.phone.phoneNumber('0##########'); beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(); + }); + + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.USER_MANAGEMENT)) { + this.skip(); + } cy.visit('/SignUp?code=WRMVXa'); }); diff --git a/cypress/integration/visits.ts b/cypress/integration/visits.ts index 1645e8aae..cde1ab2e8 100644 --- a/cypress/integration/visits.ts +++ b/cypress/integration/visits.ts @@ -1,7 +1,8 @@ -import faker from 'faker'; +import { faker } from '@faker-js/faker'; import { DateTime } from 'luxon'; -import { TemplateGroupId } from '../../src/generated/sdk'; +import { FeatureId, TemplateGroupId } from '../../src/generated/sdk'; +import featureFlags from '../support/featureFlags'; import initialDBData from '../support/initialDBData'; faker.seed(1); @@ -15,7 +16,14 @@ context('visits tests', () => { const existingScheduledEventId = initialDBData.scheduledEvents.upcoming.id; beforeEach(() => { + cy.getAndStoreFeaturesEnabled(); cy.resetDB(true); + }); + + beforeEach(function () { + if (!featureFlags.getEnabledFeatures().get(FeatureId.VISIT_MANAGEMENT)) { + this.skip(); + } cy.updateProposal({ proposalPk: existingProposalId, proposerId: PI.id, diff --git a/cypress/package-lock.json b/cypress/package-lock.json index d3c323af0..772f7979c 100644 --- a/cypress/package-lock.json +++ b/cypress/package-lock.json @@ -8,21 +8,33 @@ "name": "duo-frontend", "version": "0.1.0", "dependencies": { - "@types/luxon": "^2.3.2", + "@types/luxon": "^2.4.0", "cypress-file-upload": "^6.0.0-beta.0", - "faker": "5.5.3", "graphql": "^15.8.0", "graphql-request": "^3.7.0", "graphql-tag": "2.12.6", "jwt-decode": "^3.1.2", - "luxon": "^2.4.0", - "typescript": "^4.7.2" + "luxon": "^2.5.0", + "typescript": "^4.7.4" + }, + "devDependencies": { + "@faker-js/faker": "^7.3.0" + } + }, + "node_modules/@faker-js/faker": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-7.3.0.tgz", + "integrity": "sha512-1W0PZezq2rxlAssoWemi9gFRD8IQxvf0FPL5Km3TOmGHFG7ib0TbFBJ0yC7D/1NsxunjNTK6WjUXV8ao/mKZ5w==", + "dev": true, + "engines": { + "node": ">=14.0.0", + "npm": ">=6.0.0" } }, "node_modules/@types/luxon": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-2.3.2.tgz", - "integrity": "sha512-WOehptuhKIXukSUUkRgGbj2c997Uv/iUgYgII8U7XLJqq9W2oF0kQ6frEznRQbdurioz+L/cdaIm4GutTQfgmA==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-2.4.0.tgz", + "integrity": "sha512-oCavjEjRXuR6URJEtQm0eBdfsBiEcGBZbq21of8iGkeKxU1+1xgKuFPClaBZl2KB8ZZBSWlgk61tH6Mf+nvZVw==" }, "node_modules/asynckit": { "version": "0.4.0", @@ -72,10 +84,6 @@ "url": "https://github.com/sponsors/jaydenseric" } }, - "node_modules/faker": { - "version": "5.5.3", - "license": "MIT" - }, "node_modules/form-data": { "version": "3.0.1", "license": "MIT", @@ -128,9 +136,9 @@ "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" }, "node_modules/luxon": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.4.0.tgz", - "integrity": "sha512-w+NAwWOUL5hO0SgwOHsMBAmZ15SoknmQXhSO0hIbJCAmPKSsGeK8MlmhYh2w6Iib38IxN2M+/ooXWLbeis7GuA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.5.0.tgz", + "integrity": "sha512-IDkEPB80Rb6gCAU+FEib0t4FeJ4uVOuX1CQ9GsvU3O+JAGIgu0J7sf1OarXKaKDygTZIoJyU6YdZzTFRu+YR0A==", "engines": { "node": ">=12" } @@ -164,9 +172,9 @@ "license": "0BSD" }, "node_modules/typescript": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz", - "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -177,10 +185,16 @@ } }, "dependencies": { + "@faker-js/faker": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-7.3.0.tgz", + "integrity": "sha512-1W0PZezq2rxlAssoWemi9gFRD8IQxvf0FPL5Km3TOmGHFG7ib0TbFBJ0yC7D/1NsxunjNTK6WjUXV8ao/mKZ5w==", + "dev": true + }, "@types/luxon": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-2.3.2.tgz", - "integrity": "sha512-WOehptuhKIXukSUUkRgGbj2c997Uv/iUgYgII8U7XLJqq9W2oF0kQ6frEznRQbdurioz+L/cdaIm4GutTQfgmA==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-2.4.0.tgz", + "integrity": "sha512-oCavjEjRXuR6URJEtQm0eBdfsBiEcGBZbq21of8iGkeKxU1+1xgKuFPClaBZl2KB8ZZBSWlgk61tH6Mf+nvZVw==" }, "asynckit": { "version": "0.4.0" @@ -207,9 +221,6 @@ "extract-files": { "version": "9.0.0" }, - "faker": { - "version": "5.5.3" - }, "form-data": { "version": "3.0.1", "requires": { @@ -245,9 +256,9 @@ "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" }, "luxon": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.4.0.tgz", - "integrity": "sha512-w+NAwWOUL5hO0SgwOHsMBAmZ15SoknmQXhSO0hIbJCAmPKSsGeK8MlmhYh2w6Iib38IxN2M+/ooXWLbeis7GuA==" + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.5.0.tgz", + "integrity": "sha512-IDkEPB80Rb6gCAU+FEib0t4FeJ4uVOuX1CQ9GsvU3O+JAGIgu0J7sf1OarXKaKDygTZIoJyU6YdZzTFRu+YR0A==" }, "mime-db": { "version": "1.51.0" @@ -265,9 +276,9 @@ "version": "2.3.1" }, "typescript": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz", - "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==" + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==" } } } diff --git a/cypress/package.json b/cypress/package.json index 5b653e968..fc25b6320 100644 --- a/cypress/package.json +++ b/cypress/package.json @@ -4,18 +4,20 @@ "private": true, "proxy": "http://localhost:4000", "dependencies": { - "@types/luxon": "^2.3.2", + "@types/luxon": "^2.4.0", "cypress-file-upload": "^6.0.0-beta.0", - "faker": "5.5.3", "graphql": "^15.8.0", "graphql-request": "^3.7.0", "graphql-tag": "2.12.6", "jwt-decode": "^3.1.2", - "luxon": "^2.4.0", - "typescript": "^4.7.2" + "luxon": "^2.5.0", + "typescript": "^4.7.4" }, "scripts": { "cypress:open": "cypress open", "cy:run": "cypress run --browser chrome --config defaultCommandTimeout=15000" + }, + "devDependencies": { + "@faker-js/faker": "^7.3.0" } } diff --git a/cypress/support/beforeRunHook.ts b/cypress/support/beforeRunHook.ts index 8cf8dbf83..a3ca035e1 100644 --- a/cypress/support/beforeRunHook.ts +++ b/cypress/support/beforeRunHook.ts @@ -1,4 +1,5 @@ // NOTE: Get and store the settings into localStorage before running the tests. For now this is needed because of the "getFormats()" function used in initialDBData. Cypress.on('before:run', () => { cy.getAndStoreAppSettings(); + cy.getAndStoreFeaturesEnabled(); }); diff --git a/cypress/support/featureFlags.ts b/cypress/support/featureFlags.ts new file mode 100644 index 000000000..6a9ac5ed6 --- /dev/null +++ b/cypress/support/featureFlags.ts @@ -0,0 +1,20 @@ +import { Feature, FeatureId } from '../../src/generated/sdk'; + +export default { + getEnabledFeatures: () => { + const features = window.localStorage.getItem('enabledFeatures'); + + let featuresMap = new Map(); + + if (features) { + featuresMap = new Map( + JSON.parse(features).map((feature: Feature) => [ + feature.id, + feature.isEnabled, + ]) + ); + } + + return featuresMap; + }, +}; diff --git a/cypress/support/initialDBData.ts b/cypress/support/initialDBData.ts index ee000b8a9..dd97bf4d3 100644 --- a/cypress/support/initialDBData.ts +++ b/cypress/support/initialDBData.ts @@ -26,8 +26,14 @@ export default { const dateFormat = settingsMap.get(SettingsId.DATE_FORMAT) || 'dd-MM-yyyy'; const dateTimeFormat = settingsMap.get(SettingsId.DATE_TIME_FORMAT) || 'dd-MM-yyyy HH:mm'; + const statusFilter = settingsMap.get( + SettingsId.DEFAULT_INST_SCI_STATUS_FILTER + ); + const reviewerFilter = settingsMap.get( + SettingsId.DEFAULT_INST_SCI_REVIEWER_FILTER + ); - return { dateFormat, dateTimeFormat }; + return { dateFormat, dateTimeFormat, statusFilter, reviewerFilter }; }, call: { id: 1, diff --git a/cypress/support/user.ts b/cypress/support/user.ts index 14c3bdbaa..e29c45cbd 100644 --- a/cypress/support/user.ts +++ b/cypress/support/user.ts @@ -4,6 +4,8 @@ import { CreateUserMutation, CreateUserMutationVariables, ExternalTokenLoginMutation, + FeatureId, + GetFeaturesQuery, LoginMutation, Role, SetUserEmailVerifiedMutation, @@ -13,6 +15,7 @@ import { UpdateUserRolesMutationVariables, User, } from '../../src/generated/sdk'; +import featureFlags from './featureFlags'; import { getE2EApi } from './utils'; type DecodedTokenData = { @@ -55,6 +58,21 @@ const testCredentialStore = { }, }; +const getAndStoreFeaturesEnabled = (): Cypress.Chainable => { + const api = getE2EApi(); + const request = api.getFeatures().then((resp) => { + const enabledFeatures = resp.features.filter((feat) => feat.isEnabled); + window.localStorage.setItem( + 'enabledFeatures', + JSON.stringify(enabledFeatures) + ); + + return resp; + }); + + return cy.wrap(request); +}; + function changeActiveRole(selectedRoleId: number) { const token = window.localStorage.getItem('token'); @@ -126,7 +144,7 @@ const login = ( ? testCredentialStore[roleOrCredentials] : roleOrCredentials; - if (Cypress.env('STFC') === true) { + if (featureFlags.getEnabledFeatures().get(FeatureId.EXTERNAL_AUTH)) { if (typeof roleOrCredentials !== 'string') { throw new Error('Role not authorised to login'); } @@ -213,3 +231,4 @@ Cypress.Commands.add('updateUserDetails', updateUserDetails); Cypress.Commands.add('setUserEmailVerified', setUserEmailVerified); Cypress.Commands.add('changeActiveRole', changeActiveRole); +Cypress.Commands.add('getAndStoreFeaturesEnabled', getAndStoreFeaturesEnabled); diff --git a/cypress/support/utils.ts b/cypress/support/utils.ts index 2c3a9f9a5..505b8eda7 100644 --- a/cypress/support/utils.ts +++ b/cypress/support/utils.ts @@ -1,7 +1,10 @@ import 'cypress-file-upload'; +import { faker } from '@faker-js/faker'; import { GraphQLClient } from 'graphql-request'; +import { DateTime } from 'luxon'; import { + AllocationTimeUnits, CreateApiAccessTokenMutation, CreateApiAccessTokenMutationVariables, getSdk, @@ -16,6 +19,26 @@ const KEY_CODES = { down: 40, }; +const currentDayStart = DateTime.now().startOf('day'); + +export const updatedCall = { + shortCode: faker.random.alphaNumeric(15), + startCall: faker.date.past().toISOString().slice(0, 10), + endCall: faker.date.future().toISOString().slice(0, 10), + startReview: currentDayStart, + endReview: currentDayStart, + startSEPReview: currentDayStart, + endSEPReview: currentDayStart, + startNotify: currentDayStart, + endNotify: currentDayStart, + startCycle: currentDayStart, + endCycle: currentDayStart, + allocationTimeUnit: AllocationTimeUnits.DAY, + cycleComment: faker.lorem.word(10), + surveyComment: faker.lorem.word(10), + templateId: initialDBData.template.id, +}; + export const getE2EApi = (token?: string | null) => { // NOTE: Token is used when we want to do some action as a specific logged in user. const authHeader = `Bearer ${token ? token : Cypress.env('SVC_ACC_TOKEN')}`; diff --git a/cypress/types/user.d.ts b/cypress/types/user.d.ts index 9670f4f7f..97e252510 100644 --- a/cypress/types/user.d.ts +++ b/cypress/types/user.d.ts @@ -108,6 +108,16 @@ declare global { * cy.changeActiveRole(selectedRoleId: number) */ changeActiveRole: (selectedRoleId: number) => void; + + /** + * Gets app features and stores in the localStorage to be used inside tests. + * + * @returns {typeof getAndStoreFeaturesEnabled} + * @memberof Chainable + * @example + * cy.getAndStoreFeaturesEnabled() + */ + getAndStoreFeaturesEnabled: () => Cypress.Chainable; } } } diff --git a/docker-compose-stfc.e2e.yml b/docker-compose-stfc.e2e.yml new file mode 100644 index 000000000..0614e7729 --- /dev/null +++ b/docker-compose-stfc.e2e.yml @@ -0,0 +1,123 @@ +version: "3.1" +services: + duo-reverse-proxy: + image: traefik:2.4 # The official Traefik docker image + command: --api.insecure=true --providers.docker # Enables the web UI and tells Traefik to listen to docker + ports: + - "8081:80" # The HTTP port + - "8082:8080" # The Web UI (enabled by --api) + volumes: + - type: bind + source: /var/run/docker.sock + target: /var/run/docker.sock + read_only: true + + backend: + image: "dmsc/duo-backend:${USER_OFFICE_BACKEND_TAG}" + depends_on: + - db + - duo-reverse-proxy + - factory + volumes: + - "./${USER_OFFICE_BACKEND_DIR}/db_patches:/home/node/app/db_patches" + environment: + DATABASE_URL: postgres://duouser:duopassword@db:5432/duo + secret: qMyLZALzs229ybdQXNyzYRdju7X784TH + EXTERNAL_AUTH_TOKEN: abc + NODE_ENV: development + tokenLife: 7d + baseURL: localhost:3000 + SINK_EMAIL: BISAPPSSINK@stfc.ac.uk + EMAIL_SENDER: '"STFC User Office" ' + USER_OFFICE_FACTORY_ENDPOINT: http://user-office-factory:4500/generate + EMAIL_AUTH_HOST: exchsmtp.stfc.ac.uk + EMAIL_TEMPLATE_PATH: /config/emails/ + EMAIL_FOOTER_IMAGE_PATH: /config/logos/STFC-Logo-small.png + DEPENDENCY_CONFIG: stfc + EXTERNAL_AUTH_LOGIN_URL: http://localhost:9003/auth/Login.aspx + EXTERNAL_AUTH_SERVICE_URL: http://mockServer:1080/ws/UserOfficeWebService?wsdl + ANTIVIRUS_HOST: clam-antivirus + ANTIVIRUS_PORT: 3310 + TZ: Europe/London + ISIS_UO_EMAIL: isisuo@stfc.ac.uk + FBS_EMAIL: FacilitiesBusinessSystem@stfc.ac.uk + PROFILE_PAGE_LINK: http://localhost:9003/auth/ManageDetails.aspx + labels: + - "traefik.http.routers.backend.rule=PathPrefix(`/api`, `/graphql`, `/gateway`, `/download`, `/downloads`, `/files`, `/proposal`, `/uploads`)" + - "traefik.http.services.backend.loadbalancer.server.port=4000" + + clam-antivirus: + image: clamav/clamav:0.104 + ports: + - "3310:3310" + + cypress: + image: e2e-cypress:latest + depends_on: + - frontend + - mockserver-client + - mockServer + ipc: host # see https://github.com/cypress-io/cypress/issues/350 + environment: + CYPRESS_SVC_ACC_TOKEN: $SVC_ACC_TOKEN + entrypoint: + [ + "/wait-for-frontend.sh", + "duo-reverse-proxy:80", + "cypress run --spec ${CYPRES_SPEC_PATTERN} --browser chrome --config baseUrl=http://duo-reverse-proxy:80 defaultCommandTimeout=15000" + ] + volumes: + - "./${USER_OFFICE_FRONTEND_DIR}/cypress/screenshots:/tmp/screenshots" + - "./${USER_OFFICE_FRONTEND_DIR}/cypress/fixtures:/e2e/cypress/fixtures" + - "./${USER_OFFICE_FRONTEND_DIR}/cypress/integration:/e2e/cypress/integration" + - "./${USER_OFFICE_FRONTEND_DIR}/cypress/plugins:/e2e/cypress/plugins" + - "./${USER_OFFICE_FRONTEND_DIR}/cypress/support:/e2e/cypress/support" + - "./${USER_OFFICE_FRONTEND_DIR}/cypress/types:/e2e/cypress/types" + + frontend: + image: "duo-frontend:${BUILD_TAG}" + depends_on: + - duo-reverse-proxy + - backend + labels: + - "traefik.http.routers.frontend.rule=PathPrefix(`/`)" + - "traefik.http.services.frontend.loadbalancer.server.port=80" + + factory: + image: dmsc/duo-factory:${USER_OFFICE_FACTORY_TAG} + depends_on: + - duo-reverse-proxy + - db + environment: + secret: qMyLZALzs229ybdQXNyzYRdju7X784TH + EXTERNAL_AUTH_TOKEN: abc + NODE_ENV: development + DATABASE_CONNECTION_STRING: postgres://duouser:duopassword@db:5432/duo + UO_FEATURE_ALLOW_NO_SANDBOX: 1 + HEADER_LOGO_PATH: /config/logos/STFC-Logo.png + ports: + - "4500:4500" + labels: + - "traefik.http.routers.factory.rule=PathPrefix(`/generate`, `/test-template`, `/version`, `/health-check`)" + - "traefik.port=4500" + + db: + image: postgres:11-alpine + restart: always + environment: + POSTGRES_PASSWORD: duopassword + POSTGRES_USER: duouser + POSTGRES_DB: duo + ports: + - 5432:5432 + volumes: + - "./${USER_OFFICE_BACKEND_DIR}/db_patches/:/docker-entrypoint-initdb.d/" + mockServer: + image: mockserver/mockserver:5.13.0 + command: -logLevel ERROR -serverPort 1080 + ports: + - 1080:1080 + mockserver-client: + image: "dmsc/stfc-mockserver-client:master" + depends_on: + - mockServer diff --git a/package-lock.json b/package-lock.json index 033921e24..63d58b8f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "@date-io/luxon": "^2.13.2", "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", - "@graphql-codegen/cli": "^2.6.2", + "@graphql-codegen/cli": "^2.6.3", "@graphql-codegen/typescript": "^2.4.9", "@graphql-codegen/typescript-graphql-request": "^4.4.6", "@graphql-codegen/typescript-operations": "^2.3.6", @@ -58,8 +58,8 @@ "yup": "^0.32.11" }, "devDependencies": { + "@faker-js/faker": "^7.3.0", "@types/eslint": "^8.2.1", - "@types/faker": "^5.5.9", "@types/luxon": "^2.3.0", "@types/node": "^16.0.0", "@types/react-test-renderer": "^17.0.1", @@ -75,7 +75,6 @@ "eslint-plugin-react": "^7.29.4", "eslint-plugin-react-hooks": "^4.4.0", "eslint-plugin-unused-imports": "^2.0.0", - "faker": "5.5.3", "husky": "^4.3.8", "lint-staged": "^10.5.4", "prettier": "^2.6.1", @@ -2291,10 +2290,20 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@faker-js/faker": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-7.3.0.tgz", + "integrity": "sha512-1W0PZezq2rxlAssoWemi9gFRD8IQxvf0FPL5Km3TOmGHFG7ib0TbFBJ0yC7D/1NsxunjNTK6WjUXV8ao/mKZ5w==", + "dev": true, + "engines": { + "node": ">=14.0.0", + "npm": ">=6.0.0" + } + }, "node_modules/@graphql-codegen/cli": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.6.2.tgz", - "integrity": "sha512-UO75msoVgvLEvfjCezM09cQQqp32+mR8Ma1ACsBpr7nroFvHbgcu2ulx1cMovg4sxDBCsvd9Eq/xOOMpARUxtw==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.6.3.tgz", + "integrity": "sha512-gxtKbe6LlBhGqDISZldCMcGaV1rSTS4D836clSR52kBY7UBhZZcDOcNZM0zDJDFGpjHtwuL9p0Kb4w9HRXYfew==", "dependencies": { "@graphql-codegen/core": "2.5.1", "@graphql-codegen/plugin-helpers": "^2.4.1", @@ -2315,24 +2324,18 @@ "common-tags": "^1.8.0", "cosmiconfig": "^7.0.0", "debounce": "^1.2.0", - "dependency-graph": "^0.11.0", "detect-indent": "^6.0.0", - "glob": "^7.1.6", - "globby": "^11.0.4", "graphql-config": "^4.1.0", "inquirer": "^8.0.0", "is-glob": "^4.0.1", "json-to-pretty-yaml": "^1.2.2", - "latest-version": "5.1.0", + "latest-version": "^6.0.0", "listr": "^0.14.3", "listr-update-renderer": "^0.5.0", "log-symbols": "^4.0.0", - "minimatch": "^4.0.0", "mkdirp": "^1.0.4", "string-env-interpolation": "^1.0.1", "ts-log": "^2.2.3", - "tslib": "~2.3.0", - "valid-url": "^1.0.9", "wrap-ansi": "^7.0.0", "yaml": "^1.10.0", "yargs": "^17.0.0" @@ -2936,17 +2939,6 @@ } } }, - "node_modules/@graphql-codegen/cli/node_modules/minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@graphql-codegen/cli/node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -4355,11 +4347,14 @@ } }, "node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" } }, "node_modules/@sinonjs/commons": { @@ -4605,14 +4600,14 @@ } }, "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", "dependencies": { - "defer-to-connect": "^1.0.1" + "defer-to-connect": "^2.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" } }, "node_modules/@tinymce/tinymce-react": { @@ -4698,6 +4693,17 @@ "@types/node": "*" } }, + "node_modules/@types/cacheable-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", + "integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, "node_modules/@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -4764,12 +4770,6 @@ "@types/range-parser": "*" } }, - "node_modules/@types/faker": { - "version": "5.5.9", - "resolved": "https://registry.npmjs.org/@types/faker/-/faker-5.5.9.tgz", - "integrity": "sha512-uCx6mP3UY5SIO14XlspxsGjgaemrxpssJI0Ol+GfhxtcKpv9pgRZYsS4eeKeHVLje6Qtc8lGszuBI461+gVZBA==", - "dev": true - }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -4797,6 +4797,11 @@ "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" + }, "node_modules/@types/http-proxy": { "version": "1.17.8", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", @@ -4839,6 +4844,11 @@ "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==" }, + "node_modules/@types/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ==" + }, "node_modules/@types/json-schema": { "version": "7.0.9", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", @@ -4862,6 +4872,14 @@ "@types/node": "*" } }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/lodash": { "version": "4.14.178", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", @@ -5002,6 +5020,14 @@ "@types/node": "*" } }, + "node_modules/@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/retry": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", @@ -6828,31 +6854,31 @@ "node": ">= 0.8" } }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "engines": { + "node": ">=10.6.0" + } + }, "node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", "dependencies": { "clone-response": "^1.0.2", "get-stream": "^5.1.0", "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", + "keyv": "^4.0.0", "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "engines": { - "node": ">=8" - } - }, "node_modules/cachedir": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", @@ -7199,7 +7225,7 @@ "node_modules/clone-response": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", "dependencies": { "mimic-response": "^1.0.0" } @@ -7391,6 +7417,18 @@ "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", "dev": true }, + "node_modules/compress-brotli": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.8.tgz", + "integrity": "sha512-lVcQsjhxhIXsuupfy9fmZUFtAIdBmXA7EGY6GBdgZ++qkM9zG4YFT8iU7FoBxzryNDMOpD1HIFHUSX4D87oqhQ==", + "dependencies": { + "@types/json-buffer": "~3.0.0", + "json-buffer": "~3.0.1" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -8236,14 +8274,28 @@ } }, "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dependencies": { - "mimic-response": "^1.0.0" + "mimic-response": "^3.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/dedent": { @@ -8349,9 +8401,12 @@ } }, "node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "engines": { + "node": ">=10" + } }, "node_modules/define-lazy-prop": { "version": "2.0.0", @@ -8707,11 +8762,6 @@ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" }, - "node_modules/duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -9829,12 +9879,6 @@ "node >=0.6.0" ] }, - "node_modules/faker": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", - "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", - "dev": true - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -10689,35 +10733,27 @@ } }, "node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" + "version": "11.8.5", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", + "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" }, "engines": { - "node": ">=8.6" - } - }, - "node_modules/got/node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dependencies": { - "pump": "^3.0.0" + "node": ">=10.19.0" }, - "engines": { - "node": ">=6" + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" } }, "node_modules/graceful-fs": { @@ -11162,6 +11198,18 @@ "node": ">=0.10" } }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, "node_modules/https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -13098,9 +13146,9 @@ } }, "node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" }, "node_modules/json-parse-better-errors": { "version": "1.0.2", @@ -13357,11 +13405,12 @@ "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" }, "node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.3.2.tgz", + "integrity": "sha512-kn8WmodVBe12lmHpA6W8OY7SNh6wVR+Z+wZESF4iF5FCazaVXGWOtnbnvX0tMQ1bO+/TmOD9LziuYMvrIIs0xw==", "dependencies": { - "json-buffer": "3.0.0" + "compress-brotli": "^1.3.8", + "json-buffer": "3.0.1" } }, "node_modules/kind-of": { @@ -13402,14 +13451,17 @@ } }, "node_modules/latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-6.0.0.tgz", + "integrity": "sha512-zfTuGx4PwpoSJ1mABs58AkM6qMzu49LZ7LT5JHprKvpGpQ+cYtfSibi3tLLrH4z7UylYU42rfBdwN8YgqbTljA==", "dependencies": { - "package-json": "^6.3.0" + "package-json": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lazy-ass": { @@ -14181,11 +14233,11 @@ } }, "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/lru-cache": { @@ -14635,11 +14687,14 @@ } }, "node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/notistack": { @@ -14971,11 +15026,11 @@ "dev": true }, "node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/p-limit": { @@ -15029,25 +15084,20 @@ } }, "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-7.0.0.tgz", + "integrity": "sha512-CHJqc94AA8YfSLHGQT3DbvSIuE12NLFekpM4n7LRrAd3dOJtA911+4xe9q6nC3/jcKraq7nNS9VxgtT0KC+diA==", "dependencies": { - "got": "^9.6.0", + "got": "^11.8.2", "registry-auth-token": "^4.0.0", "registry-url": "^5.0.0", - "semver": "^6.2.0" + "semver": "^7.3.5" }, "engines": { - "node": ">=8" - } - }, - "node_modules/package-json/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/param-case": { @@ -16151,17 +16201,6 @@ "postcss": "^8.2.15" } }, - "node_modules/postcss-normalize-url/node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/postcss-normalize-whitespace": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.3.tgz", @@ -16439,14 +16478,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "engines": { - "node": ">=4" - } - }, "node_modules/prettier": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.1.tgz", @@ -16749,7 +16780,7 @@ "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "engines": { "node": ">=0.10.0" } @@ -17286,11 +17317,11 @@ } }, "node_modules/registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", "dependencies": { - "rc": "^1.2.8" + "rc": "1.2.8" }, "engines": { "node": ">=6.0.0" @@ -17627,6 +17658,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, "node_modules/resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", @@ -17724,11 +17760,11 @@ } }, "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", + "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", "dependencies": { - "lowercase-keys": "^1.0.0" + "lowercase-keys": "^2.0.0" } }, "node_modules/restore-cursor": { @@ -19398,14 +19434,6 @@ "node": ">=4" } }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "engines": { - "node": ">=6" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -19811,17 +19839,6 @@ "punycode": "^2.1.0" } }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/use-memo-one": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.2.tgz", @@ -22426,10 +22443,16 @@ "strip-json-comments": "^3.1.1" } }, + "@faker-js/faker": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-7.3.0.tgz", + "integrity": "sha512-1W0PZezq2rxlAssoWemi9gFRD8IQxvf0FPL5Km3TOmGHFG7ib0TbFBJ0yC7D/1NsxunjNTK6WjUXV8ao/mKZ5w==", + "dev": true + }, "@graphql-codegen/cli": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.6.2.tgz", - "integrity": "sha512-UO75msoVgvLEvfjCezM09cQQqp32+mR8Ma1ACsBpr7nroFvHbgcu2ulx1cMovg4sxDBCsvd9Eq/xOOMpARUxtw==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.6.3.tgz", + "integrity": "sha512-gxtKbe6LlBhGqDISZldCMcGaV1rSTS4D836clSR52kBY7UBhZZcDOcNZM0zDJDFGpjHtwuL9p0Kb4w9HRXYfew==", "requires": { "@graphql-codegen/core": "2.5.1", "@graphql-codegen/plugin-helpers": "^2.4.1", @@ -22450,24 +22473,18 @@ "common-tags": "^1.8.0", "cosmiconfig": "^7.0.0", "debounce": "^1.2.0", - "dependency-graph": "^0.11.0", "detect-indent": "^6.0.0", - "glob": "^7.1.6", - "globby": "^11.0.4", "graphql-config": "^4.1.0", "inquirer": "^8.0.0", "is-glob": "^4.0.1", "json-to-pretty-yaml": "^1.2.2", - "latest-version": "5.1.0", + "latest-version": "^6.0.0", "listr": "^0.14.3", "listr-update-renderer": "^0.5.0", "log-symbols": "^4.0.0", - "minimatch": "^4.0.0", "mkdirp": "^1.0.4", "string-env-interpolation": "^1.0.1", "ts-log": "^2.2.3", - "tslib": "~2.3.0", - "valid-url": "^1.0.9", "wrap-ansi": "^7.0.0", "yaml": "^1.10.0", "yargs": "^17.0.0" @@ -22935,14 +22952,6 @@ "integrity": "sha512-E9ZXfK9iQfG9s73ars9qvvvbSIkJZF5yOo9j4tcwM5tN8mUKfj/EKN5PzOr3ZH0y5wL7dLAHw3RVEfpQV9Q7VQ==", "requires": {} }, - "minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -23856,9 +23865,9 @@ } }, "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==" }, "@sinonjs/commons": { "version": "1.8.3", @@ -24004,11 +24013,11 @@ } }, "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", "requires": { - "defer-to-connect": "^1.0.1" + "defer-to-connect": "^2.0.0" } }, "@tinymce/tinymce-react": { @@ -24084,6 +24093,17 @@ "@types/node": "*" } }, + "@types/cacheable-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", + "integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==", + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, "@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -24150,12 +24170,6 @@ "@types/range-parser": "*" } }, - "@types/faker": { - "version": "5.5.9", - "resolved": "https://registry.npmjs.org/@types/faker/-/faker-5.5.9.tgz", - "integrity": "sha512-uCx6mP3UY5SIO14XlspxsGjgaemrxpssJI0Ol+GfhxtcKpv9pgRZYsS4eeKeHVLje6Qtc8lGszuBI461+gVZBA==", - "dev": true - }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -24183,6 +24197,11 @@ "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" }, + "@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" + }, "@types/http-proxy": { "version": "1.17.8", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", @@ -24225,6 +24244,11 @@ "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==" }, + "@types/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ==" + }, "@types/json-schema": { "version": "7.0.9", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", @@ -24248,6 +24272,14 @@ "@types/node": "*" } }, + "@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "requires": { + "@types/node": "*" + } + }, "@types/lodash": { "version": "4.14.178", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", @@ -24388,6 +24420,14 @@ "@types/node": "*" } }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "requires": { + "@types/node": "*" + } + }, "@types/retry": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", @@ -25706,25 +25746,23 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, + "cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==" + }, "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", "requires": { "clone-response": "^1.0.2", "get-stream": "^5.1.0", "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", + "keyv": "^4.0.0", "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" - } + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" } }, "cachedir": { @@ -25986,7 +26024,7 @@ "clone-response": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", "requires": { "mimic-response": "^1.0.0" } @@ -26137,6 +26175,15 @@ "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", "dev": true }, + "compress-brotli": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.8.tgz", + "integrity": "sha512-lVcQsjhxhIXsuupfy9fmZUFtAIdBmXA7EGY6GBdgZ++qkM9zG4YFT8iU7FoBxzryNDMOpD1HIFHUSX4D87oqhQ==", + "requires": { + "@types/json-buffer": "~3.0.0", + "json-buffer": "~3.0.1" + } + }, "compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -26768,11 +26815,18 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "requires": { - "mimic-response": "^1.0.0" + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + } } }, "dedent": { @@ -26853,9 +26907,9 @@ } }, "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" }, "define-lazy-prop": { "version": "2.0.0", @@ -27128,11 +27182,6 @@ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -27956,12 +28005,6 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, - "faker": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", - "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", - "dev": true - }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -28586,31 +28629,21 @@ } }, "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "dependencies": { - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - } - } + "version": "11.8.5", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", + "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" } }, "graceful-fs": { @@ -28961,6 +28994,15 @@ "sshpk": "^1.14.1" } }, + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, "https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -30363,9 +30405,9 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" }, "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" }, "json-parse-better-errors": { "version": "1.0.2", @@ -30590,11 +30632,12 @@ "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" }, "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.3.2.tgz", + "integrity": "sha512-kn8WmodVBe12lmHpA6W8OY7SNh6wVR+Z+wZESF4iF5FCazaVXGWOtnbnvX0tMQ1bO+/TmOD9LziuYMvrIIs0xw==", "requires": { - "json-buffer": "3.0.0" + "compress-brotli": "^1.3.8", + "json-buffer": "3.0.1" } }, "kind-of": { @@ -30626,11 +30669,11 @@ } }, "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-6.0.0.tgz", + "integrity": "sha512-zfTuGx4PwpoSJ1mABs58AkM6qMzu49LZ7LT5JHprKvpGpQ+cYtfSibi3tLLrH4z7UylYU42rfBdwN8YgqbTljA==", "requires": { - "package-json": "^6.3.0" + "package-json": "^7.0.0" } }, "lazy-ass": { @@ -31225,9 +31268,9 @@ } }, "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" }, "lru-cache": { "version": "6.0.0", @@ -31544,9 +31587,9 @@ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=" }, "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" }, "notistack": { "version": "2.0.4", @@ -31768,9 +31811,9 @@ "dev": true }, "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==" }, "p-limit": { "version": "1.3.0", @@ -31808,21 +31851,14 @@ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" }, "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-7.0.0.tgz", + "integrity": "sha512-CHJqc94AA8YfSLHGQT3DbvSIuE12NLFekpM4n7LRrAd3dOJtA911+4xe9q6nC3/jcKraq7nNS9VxgtT0KC+diA==", "requires": { - "got": "^9.6.0", + "got": "^11.8.2", "registry-auth-token": "^4.0.0", "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } + "semver": "^7.3.5" } }, "param-case": { @@ -32529,13 +32565,6 @@ "requires": { "normalize-url": "^6.0.1", "postcss-value-parser": "^4.2.0" - }, - "dependencies": { - "normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" - } } }, "postcss-normalize-whitespace": { @@ -32730,11 +32759,6 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" - }, "prettier": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.1.tgz", @@ -32961,7 +32985,7 @@ "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" } } }, @@ -33372,11 +33396,11 @@ } }, "registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", "requires": { - "rc": "^1.2.8" + "rc": "1.2.8" } }, "registry-url": { @@ -33637,6 +33661,11 @@ "supports-preserve-symlinks-flag": "^1.0.0" } }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, "resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", @@ -33701,11 +33730,11 @@ "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==" }, "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", + "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", "requires": { - "lowercase-keys": "^1.0.0" + "lowercase-keys": "^2.0.0" } }, "restore-cursor": { @@ -34963,11 +34992,6 @@ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -35267,14 +35291,6 @@ "punycode": "^2.1.0" } }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "requires": { - "prepend-http": "^2.0.0" - } - }, "use-memo-one": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.2.tgz", diff --git a/package.json b/package.json index 7852333e9..b4ceafa4c 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "@date-io/luxon": "^2.13.2", "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", - "@graphql-codegen/cli": "^2.6.2", + "@graphql-codegen/cli": "^2.6.3", "@graphql-codegen/typescript": "^2.4.9", "@graphql-codegen/typescript-graphql-request": "^4.4.6", "@graphql-codegen/typescript-operations": "^2.3.6", @@ -100,8 +100,8 @@ ] }, "devDependencies": { + "@faker-js/faker": "^7.3.0", "@types/eslint": "^8.2.1", - "@types/faker": "^5.5.9", "@types/luxon": "^2.3.0", "@types/node": "^16.0.0", "@types/react-test-renderer": "^17.0.1", @@ -117,7 +117,6 @@ "eslint-plugin-react": "^7.29.4", "eslint-plugin-react-hooks": "^4.4.0", "eslint-plugin-unused-imports": "^2.0.0", - "faker": "5.5.3", "husky": "^4.3.8", "lint-staged": "^10.5.4", "prettier": "^2.6.1", diff --git a/src/components/DashBoard.tsx b/src/components/DashBoard.tsx index 5900a931b..2a0cc3664 100644 --- a/src/components/DashBoard.tsx +++ b/src/components/DashBoard.tsx @@ -57,6 +57,8 @@ import ProposalEsiPage from './template/EsiPage'; import FeedbackTemplatesPage from './template/FeedbackTemplatesPage'; import GenericTemplatesPage from './template/GenericTemplatesPage'; import ImportTemplatePage from './template/import/ImportTemplatePage'; +import PdfTemplateEditor from './template/PdfTemplateEditor'; +import PdfTemplatesPage from './template/PdfTemplatesPage'; import ProposalTemplatesPage from './template/ProposalTemplatesPage'; import QuestionsPage from './template/QuestionsPage'; import SampleEsiPage from './template/SampleEsiPage'; @@ -370,6 +372,18 @@ const Dashboard: React.FC = () => { path="/QuestionaryEditor/:templateId" component={TemplateEditor} /> + + = ({ }) => { const classes = useStyles(); const downloadSEPXLSX = useDownloadXLSXSEP(); - const { loadingCalls, calls } = useCallsData(); + const { loadingCalls, calls } = useCallsData({ sepIds: [sepId] }); const [query, setQuery] = useQueryParams({ call: withDefault(NumberParam, null), }); diff --git a/src/components/SEP/Proposals/AssignProposalsToSEP.tsx b/src/components/SEP/Proposals/AssignProposalsToSEP.tsx index 74e17b1b6..2b360bbb3 100644 --- a/src/components/SEP/Proposals/AssignProposalsToSEP.tsx +++ b/src/components/SEP/Proposals/AssignProposalsToSEP.tsx @@ -30,16 +30,23 @@ type AssignProposalToSEPProps = { close: () => void; assignProposalsToSEP: (sep: Sep | null) => Promise; sepIds: (number | null)[]; + callIds?: number[]; }; const AssignProposalsToSEP: React.FC = ({ close, assignProposalsToSEP, sepIds, + callIds, }) => { const classes = useStyles(); const { currentRole } = useContext(UserContext); - const { SEPs, loadingSEPs } = useSEPsData('', true, currentRole as UserRole); + const { SEPs, loadingSEPs } = useSEPsData({ + filter: '', + active: true, + role: currentRole as UserRole, + callIds: callIds, + }); const allSelectedProposalsHaveSameSep = sepIds.every( (item) => item === sepIds[0] ); diff --git a/src/components/SEP/Proposals/SEPProposalsAndAssignmentsView.tsx b/src/components/SEP/Proposals/SEPProposalsAndAssignmentsView.tsx index abb7a7d05..7643816a6 100644 --- a/src/components/SEP/Proposals/SEPProposalsAndAssignmentsView.tsx +++ b/src/components/SEP/Proposals/SEPProposalsAndAssignmentsView.tsx @@ -18,7 +18,7 @@ const SEPProposalsAndAssignments: React.FC = ({ data: sepData, onSEPUpdate, }) => { - const { loadingCalls, calls } = useCallsData(); + const { loadingCalls, calls } = useCallsData({ sepIds: [sepData.id] }); // NOTE: Default null means load all calls if nothing is selected const [query] = useQueryParams({ call: withDefault(NumberParam, null), diff --git a/src/components/SEP/SEPsTable.tsx b/src/components/SEP/SEPsTable.tsx index b7d71454a..d07ba6c74 100644 --- a/src/components/SEP/SEPsTable.tsx +++ b/src/components/SEP/SEPsTable.tsx @@ -40,13 +40,19 @@ const columns = [ const SEPsTable: React.FC = () => { const { currentRole } = useContext(UserContext); const { api } = useDataApiWithFeedback(); - const [sepFilter, setSEPFilter] = useState(true); + const [isActiveFilter, setIsActiveFilter] = useState( + true + ); const history = useHistory(); const { loadingSEPs, SEPs, setSEPsWithLoading: setSEPs, - } = useSEPsData('', sepFilter, currentRole as UserRole); + } = useSEPsData({ + filter: '', + active: isActiveFilter, + role: currentRole as UserRole, + }); const [editSEPID, setEditSEPID] = useState(0); const [urlQueryParams, setUrlQueryParams] = useQueryParams< @@ -60,9 +66,9 @@ const SEPsTable: React.FC = () => { const handleStatusFilterChange = (sepStatus: SEPStatus) => { setUrlQueryParams((queries) => ({ ...queries, sepStatus })); if (sepStatus === SEPStatus.ALL) { - setSEPFilter(undefined); + setIsActiveFilter(undefined); } else { - setSEPFilter(sepStatus === SEPStatus.ACTIVE ? true : false); + setIsActiveFilter(sepStatus === SEPStatus.ACTIVE ? true : false); } }; diff --git a/src/components/call/CallGeneralInfo.tsx b/src/components/call/CallGeneralInfo.tsx index cce7ef58b..d03587a0f 100644 --- a/src/components/call/CallGeneralInfo.tsx +++ b/src/components/call/CallGeneralInfo.tsx @@ -41,6 +41,7 @@ import { useFormattedDateTime } from 'hooks/admin/useFormattedDateTime'; const CallGeneralInfo: React.FC<{ templates: GetTemplatesQuery['templates']; esiTemplates: GetTemplatesQuery['templates']; + pdfTemplates: GetTemplatesQuery['templates']; loadingTemplates: boolean; proposalWorkflows: ProposalWorkflow[]; loadingProposalWorkflows: boolean; @@ -49,6 +50,7 @@ const CallGeneralInfo: React.FC<{ proposalWorkflows, templates, esiTemplates, + pdfTemplates, loadingTemplates, }) => { const { featuresMap } = useContext(FeatureContext); @@ -68,6 +70,12 @@ const CallGeneralInfo: React.FC<{ value: template.templateId, })) || []; + const pdfTemplateOptions = + pdfTemplates?.map((template) => ({ + text: template.name, + value: template.templateId, + })) || []; + const proposalWorkflowOptions = proposalWorkflows.map((proposalWorkflow) => ({ text: proposalWorkflow.name, @@ -148,7 +156,7 @@ const CallGeneralInfo: React.FC<{ <> )} + { const theme = useTheme(); + const { currentRole } = useContext(UserContext); + const { SEPs: allActiveSeps, loadingSEPs } = useSEPsData({ + filter: '', + active: true, + role: currentRole as UserRole, + }); const { settingsMap } = useContext(SettingsContext); const dateFormat = settingsMap.get(SettingsId.DATE_FORMAT)?.settingsValue; const mask = dateFormat?.replace(/[a-zA-Z]/g, '_'); @@ -23,6 +33,12 @@ const CallReviewAndNotification: React.FC = () => { >(); const { startReview, startSEPReview } = formik.values; + const sepOptions = + allActiveSeps?.map((sep) => ({ + text: sep.code, + value: sep.id, + })) || []; + return ( <> @@ -94,6 +110,15 @@ const CallReviewAndNotification: React.FC = () => { desktopModeMediaQuery={theme.breakpoints.up('sm')} /> + { title: '#proposals', field: 'proposalCount', }, + { + title: '#seps', + field: 'seps.length', + emptyValue: '-', + }, ]; const assignInstrumentsToCall = ( diff --git a/src/components/call/CreateUpdateCall.tsx b/src/components/call/CreateUpdateCall.tsx index 08f07e08b..4d8e3ed42 100644 --- a/src/components/call/CreateUpdateCall.tsx +++ b/src/components/call/CreateUpdateCall.tsx @@ -41,6 +41,12 @@ const CreateUpdateCall: React.FC = ({ call, close }) => { TemplateGroupId.PROPOSAL_ESI, call?.esiTemplateId ); + + const { templates: pdfTemplates } = useActiveTemplates( + TemplateGroupId.PDF_TEMPLATE, + call?.pdfTemplateId + ); + const { proposalWorkflows, loadingProposalWorkflows } = useProposalWorkflowsData(); @@ -67,6 +73,7 @@ const CreateUpdateCall: React.FC = ({ call, close }) => { description: call.description || '', templateId: call.templateId, esiTemplateId: call.esiTemplateId, + pdfTemplateId: call.pdfTemplateId, proposalWorkflowId: call.proposalWorkflowId, referenceNumberFormat: call.referenceNumberFormat || '', startCall: getDateTimeFromISO(call.startCall), @@ -80,6 +87,7 @@ const CreateUpdateCall: React.FC = ({ call, close }) => { startCycle: getDateTimeFromISO(call.startCycle), endCycle: getDateTimeFromISO(call.endCycle), submissionMessage: call.submissionMessage || '', + seps: call.seps?.map((sep) => sep.id), } : { shortCode: '', @@ -99,10 +107,12 @@ const CreateUpdateCall: React.FC = ({ call, close }) => { proposalWorkflowId: null, templateId: null, esiTemplateId: null, + pdfTemplateId: null, allocationTimeUnit: AllocationTimeUnits.DAY, title: '', description: '', submissionMessage: '', + seps: [], }; const closeModal = (error: string | null | undefined, callToReturn: Call) => { @@ -151,6 +161,7 @@ const CreateUpdateCall: React.FC = ({ call, close }) => { void; }) { const fileIds = props.value.map((fileItem) => fileItem.id); - const { files, setFiles } = useFileMetadata(fileIds); + const { files, setFiles } = useFilesMetadata({ fileIds }); const classes = useStyles(); diff --git a/src/components/common/FormikUIAutocomplete.tsx b/src/components/common/FormikUIAutocomplete.tsx index 997772fdd..bed4657f1 100644 --- a/src/components/common/FormikUIAutocomplete.tsx +++ b/src/components/common/FormikUIAutocomplete.tsx @@ -18,6 +18,7 @@ type FormikUIAutocompleteProps = { disabled?: boolean; TextFieldProps?: MUITextFieldProps; InputProps?: Partial & { 'data-cy': string }; + multiple?: boolean; 'data-cy'?: string; }; @@ -31,6 +32,7 @@ const FormikUIAutocomplete: React.FC = ({ disabled, InputProps, TextFieldProps, + multiple = false, ...props }) => { const options = items.map((item) => item.value); @@ -41,6 +43,7 @@ const FormikUIAutocomplete: React.FC = ({ name={name} component={Autocomplete} loading={loading} + multiple={multiple} options={options} noOptionsText={noOptionsText} getOptionLabel={(option: number | string) => { diff --git a/src/components/common/FormikUICustomTable.tsx b/src/components/common/FormikUICustomTable.tsx index 69c0f36bf..b81a90662 100644 --- a/src/components/common/FormikUICustomTable.tsx +++ b/src/components/common/FormikUICustomTable.tsx @@ -11,30 +11,84 @@ import makeStyles from '@mui/styles/makeStyles'; import { FormikHelpers, FormikValues } from 'formik'; import React, { useRef } from 'react'; -import { clamp } from 'utils/Math'; +import { deepEqual } from 'utils/json'; import { FunctionType } from 'utils/utilTypes'; import { ActionButtonContainer } from './ActionButtonContainer'; +enum Direction { + UP = -1, + DOWN = 1, +} + +function getElementIndex( + elements: Record[], + element: Record +): number { + if (!(elements && element)) { + return -1; + } + type Flatten = Type extends Array ? Item : Type; + const newElement = {} as Flatten; + Object.entries(element as typeof newElement).forEach(([key, value]) => { + if (Object.getOwnPropertyNames(elements[0]).includes(key)) { + newElement[key as keyof typeof newElement] = value; + } + }); + + return elements.findIndex((value) => deepEqual(value, newElement)); +} + function move( - array: Record[], - element: Record, - direction: 'UP' | 'DOWN' + elements: Record[], + elementIndex: number, + direction: Direction ) { - const currentIndex = array.indexOf(element); - const delta = direction === 'DOWN' ? 1 : -1; - const newIndex = clamp(currentIndex + delta, 0, array.length - 1); - if (currentIndex !== newIndex) { - const newArray = [...array]; - newArray.splice(currentIndex, 1); - newArray.splice(newIndex, 0, element); + if (elements !== null && elementIndex > -1) { + const elementRows = [...elements]; + const rowIndex = elementIndex; + const elementRowsCount = elements.length - 1; + const swapLock = + (rowIndex === elementRowsCount && direction === Direction.DOWN) || + (rowIndex === 0 && direction === Direction.UP); + if (!swapLock) { + [elementRows[elementIndex], elementRows[elementIndex + direction]] = [ + elementRows[elementIndex + direction], + elementRows[elementIndex], + ]; - return newArray; + return [...elementRows]; + } } - return array; + return elements; } +function updateElement( + elements: Record[], + oldelement: Record, + newelement: Record +) { + const newElements = [...elements]; + const elementIndex = getElementIndex(elements, oldelement); + + return elements && + elementIndex > -1 && + newElements.splice(elementIndex, 1, newelement) + ? newElements + : elements; +} +function removeElement( + elements: Record[], + removeelement: Record +) { + const newElements = [...elements]; + const elementIndex = getElementIndex(elements, removeelement); + + return elements && elementIndex > -1 && newElements.splice(elementIndex, 1) + ? newElements + : elements; +} const useStyles = makeStyles((theme) => ({ StyledButtonContainer: { marginTop: theme.spacing(1), @@ -107,20 +161,28 @@ export const FormikUICustomTable = ({ actions={[ (rowData) => ({ icon: ArrowUpwardIcon, - disabled: state.indexOf(rowData) === 0, + disabled: getElementIndex(state, rowData) === 0, tooltip: 'Up', onClick: (event, rowData): void => handleChange( - move(state, rowData as Record, 'UP') + move( + state, + getElementIndex(state, rowData as Record), + Direction.UP + ) ), }), (rowData) => ({ icon: ArrowDownwardIcon, - disabled: state.indexOf(rowData) === state.length - 1, + disabled: getElementIndex(state, rowData) === state.length - 1, tooltip: 'Down', onClick: (event, rowData): void => handleChange( - move(state, rowData as Record, 'DOWN') + move( + state, + getElementIndex(state, rowData as Record), + Direction.DOWN + ) ), }), ]} @@ -132,17 +194,18 @@ export const FormikUICustomTable = ({ }), onRowUpdate: (newData, oldData) => new Promise((resolve) => { - const newState = [...state]; - newState[state.indexOf(oldData as Record)] = - newData; - handleChange(newState); + handleChange( + updateElement( + state, + oldData as Record, + newData as Record + ) + ); resolve(); }), onRowDelete: (oldData) => new Promise((resolve) => { - const newState = [...state]; - newState.splice(state.indexOf(oldData), 1); - handleChange(newState); + handleChange(removeElement(state, oldData)); resolve(); }), }} diff --git a/src/components/common/SelectImportFile.tsx b/src/components/common/SelectImportFile.tsx index 69dcaa3e3..d2efd1961 100644 --- a/src/components/common/SelectImportFile.tsx +++ b/src/components/common/SelectImportFile.tsx @@ -31,7 +31,7 @@ export function SelectImportFile(props: { onChange={onFileSelected} /> - diff --git a/src/components/common/SuperMaterialTable.tsx b/src/components/common/SuperMaterialTable.tsx index 8974e31b2..5ab01ba32 100644 --- a/src/components/common/SuperMaterialTable.tsx +++ b/src/components/common/SuperMaterialTable.tsx @@ -1,6 +1,9 @@ import MaterialTable, { MaterialTableProps } from '@material-table/core'; +import CloseIcon from '@mui/icons-material/Close'; import Edit from '@mui/icons-material/Edit'; +import { IconButton } from '@mui/material'; import Button from '@mui/material/Button'; +import makeStyles from '@mui/styles/makeStyles'; import React, { SetStateAction, useState } from 'react'; import { DecodedValueMap, @@ -18,6 +21,14 @@ import { setSortDirectionOnSortColumn } from 'utils/helperFunctions'; import { tableIcons } from 'utils/materialIcons'; import { FunctionType } from 'utils/utilTypes'; +const useStyles = makeStyles((theme) => ({ + closeButton: { + position: 'absolute', + right: theme.spacing(1), + top: theme.spacing(1), + }, +})); + export type UrlQueryParamsType = { search: QueryParamConfig; selection: QueryParamConfig<(string | null | never)[]>; @@ -73,6 +84,7 @@ export function SuperMaterialTable({ }: MaterialTableProps & SuperProps) { const [show, setShow] = useState(false); const [editObject, setEditObject] = useState(null); + const classes = useStyles(); let { data, columns } = props; const { @@ -181,11 +193,19 @@ export function SuperMaterialTable({ open={show} maxWidth={props.createModalSize} fullWidth={!!props.createModalSize} - onClose={() => { + onClose={(_, reason) => { + if (reason && reason == 'backdropClick') return; setShow(false); setEditObject(null); }} > + setShow(false)} + > + + {createModal?.(onUpdated, onCreated, editObject)} = ({ return null; } - /** - * NOTE: We might use https://material-ui.com/components/autocomplete/. - * If we have lot of dropdown options to be able to search. - */ + const sortedCalls = [...calls]; + sortedCalls.sort((a, b) => a.shortCode.localeCompare(b.shortCode)); + + type CallOption = { + id: number; + shortCode: string; + }; + + const allOption: CallOption = { + id: 0, + shortCode: 'All', + }; + const options: CallOption[] = [ + ...(shouldShowAll ? [allOption] : []), // Add all call option if should show all. + ...sortedCalls, + ]; + return ( <> @@ -60,28 +73,32 @@ const CallFilter: React.FC = ({ {isLoading ? (
Loading...
) : ( - + renderInput={(params) => } + /> )}
diff --git a/src/components/institution/CreateUpdateInstitution.tsx b/src/components/institution/CreateUpdateInstitution.tsx index d92447884..f43518c58 100644 --- a/src/components/institution/CreateUpdateInstitution.tsx +++ b/src/components/institution/CreateUpdateInstitution.tsx @@ -6,7 +6,7 @@ import Typography from '@mui/material/Typography'; import { Field, Form, Formik } from 'formik'; import { Checkbox, TextField } from 'formik-mui'; import PropTypes from 'prop-types'; -import React, { useState } from 'react'; +import React from 'react'; import { useHistory } from 'react-router'; import * as Yup from 'yup'; @@ -14,9 +14,8 @@ import { ActionButtonContainer } from 'components/common/ActionButtonContainer'; import FormikUIAutocomplete from 'components/common/FormikUIAutocomplete'; import UOLoader from 'components/common/UOLoader'; import { Institution } from 'generated/sdk'; -import { useGetFields } from 'hooks/user/useGetFields'; +import { useCountries } from 'hooks/user/useCountries'; import useDataApiWithFeedback from 'utils/useDataApiWithFeedback'; -import { Option } from 'utils/utilTypes'; type CreateUpdateInstitutionProps = { close: (institution: Institution | null) => void; @@ -29,8 +28,7 @@ const CreateUpdateInstitution: React.FC = ({ }) => { const { api, isExecutingCall } = useDataApiWithFeedback(); const history = useHistory(); - const fieldsContent = useGetFields(); - const [countriesList, setCountriesList] = useState([]); + const countries = useCountries(); const initialValues = institution ? { name: institution.name, @@ -43,18 +41,10 @@ const CreateUpdateInstitution: React.FC = ({ verified: false, }; - if (!fieldsContent) { + if (!countries) { return ; } - if (!countriesList.length) { - setCountriesList( - fieldsContent.countries.map((country) => { - return { text: country.value, value: country.id }; - }) - ); - } - const createInstitution = async ( verified: boolean, name: string, @@ -140,7 +130,9 @@ const CreateUpdateInstitution: React.FC = ({ { + return { text: country.value, value: country.id }; + })} data-cy="country" required /> diff --git a/src/components/menu/TemplateMenuListItem.tsx b/src/components/menu/TemplateMenuListItem.tsx index 7d93a0c90..d5b8b97d9 100644 --- a/src/components/menu/TemplateMenuListItem.tsx +++ b/src/components/menu/TemplateMenuListItem.tsx @@ -7,6 +7,7 @@ import FlightTakeoffIcon from '@mui/icons-material/FlightTakeoff'; import InboxIcon from '@mui/icons-material/Inbox'; import LibraryBooksIcon from '@mui/icons-material/LibraryBooks'; import LocalShippingIcon from '@mui/icons-material/LocalShipping'; +import PictureAsPdfIcon from '@mui/icons-material/PictureAsPdf'; import Collapse from '@mui/material/Collapse'; import ListItem from '@mui/material/ListItem'; import ListItemIcon from '@mui/material/ListItemIcon'; @@ -102,6 +103,15 @@ export function TemplateMenuListItem() { + + + + + + + + + diff --git a/src/components/proposal/ParticipantModal.tsx b/src/components/proposal/ParticipantModal.tsx index 9f1a877bf..31be6a50d 100644 --- a/src/components/proposal/ParticipantModal.tsx +++ b/src/components/proposal/ParticipantModal.tsx @@ -1,6 +1,9 @@ import AddBox from '@mui/icons-material/AddBox'; +import CloseIcon from '@mui/icons-material/Close'; +import { IconButton } from '@mui/material'; import Dialog from '@mui/material/Dialog'; import DialogContent from '@mui/material/DialogContent'; +import makeStyles from '@mui/styles/makeStyles'; import React from 'react'; import { useCheckAccess } from 'components/common/Can'; @@ -8,6 +11,14 @@ import PeopleTable from 'components/user/PeopleTable'; import ProposalPeopleTable from 'components/user/ProposalsPeopleTable'; import { UserRole, BasicUserDetails } from 'generated/sdk'; +const useStyles = makeStyles((theme) => ({ + closeButton: { + position: 'absolute', + right: theme.spacing(1), + top: theme.spacing(1), + }, +})); + function ParticipantModal(props: { title: string; addParticipants: (data: BasicUserDetails[]) => void; @@ -24,6 +35,7 @@ function ParticipantModal(props: { props.addParticipants([addedUserDetails]); }; + const classes = useStyles(); const userTableProps = { title: props.title, @@ -51,11 +63,21 @@ function ParticipantModal(props: { aria-labelledby="simple-modal-title" aria-describedby="simple-modal-description" open={props.show} - onClose={() => props.close()} + onClose={(_, reason) => { + if (reason && reason == 'backdropClick') return; + props.close(); + }} maxWidth="sm" fullWidth > + props.close()} + > + + {props.participant && !isUserOfficer ? proposalPeopleTable : peopleTable} diff --git a/src/components/proposal/ProposalAdmin.tsx b/src/components/proposal/ProposalAdmin.tsx index bae857e18..57206edc2 100644 --- a/src/components/proposal/ProposalAdmin.tsx +++ b/src/components/proposal/ProposalAdmin.tsx @@ -10,7 +10,8 @@ import { CheckboxWithLabel, Select, TextField } from 'formik-mui'; import React from 'react'; import { Prompt } from 'react-router'; -import { ProposalEndStatus } from 'generated/sdk'; +import { useCheckAccess } from 'components/common/Can'; +import { ProposalEndStatus, UserRole } from 'generated/sdk'; import { ProposalData } from 'hooks/proposal/useProposalData'; import { StyledButtonContainer } from 'styles/StyledComponents'; import useDataApiWithFeedback from 'utils/useDataApiWithFeedback'; @@ -35,6 +36,7 @@ const ProposalAdmin: React.FC = ({ setAdministration, }) => { const { api } = useDataApiWithFeedback(); + const isUserOfficer = useCheckAccess([UserRole.USER_OFFICER]); const initialValues = { proposalPk: data.primaryKey, @@ -114,7 +116,7 @@ const ProposalAdmin: React.FC = ({ name="finalStatus" component={Select} data-cy="proposal-final-status" - disabled={isSubmitting} + disabled={!isUserOfficer || isSubmitting} MenuProps={{ 'data-cy': 'proposal-final-status-options' }} required > @@ -136,7 +138,7 @@ const ProposalAdmin: React.FC = ({ fullWidth autoComplete="off" data-cy="managementTimeAllocation" - disabled={isSubmitting} + disabled={!isUserOfficer || isSubmitting} /> @@ -151,7 +153,7 @@ const ProposalAdmin: React.FC = ({ data-cy="commentForUser" multiline rows="4" - disabled={isSubmitting} + disabled={!isUserOfficer || isSubmitting} /> @@ -166,7 +168,7 @@ const ProposalAdmin: React.FC = ({ data-cy="commentForManagement" multiline rows="4" - disabled={isSubmitting} + disabled={!isUserOfficer || isSubmitting} /> @@ -180,11 +182,13 @@ const ProposalAdmin: React.FC = ({ label: 'Submitted', }} data-cy="is-management-decision-submitted" + disabled={!isUserOfficer || isSubmitting} /> + diff --git a/src/components/proposal/ProposalContainer.tsx b/src/components/proposal/ProposalContainer.tsx index 493c0a5fb..a3c0f4da3 100644 --- a/src/components/proposal/ProposalContainer.tsx +++ b/src/components/proposal/ProposalContainer.tsx @@ -27,11 +27,14 @@ interface ProposalContainerProps { proposal: ProposalWithQuestionary; proposalUpdated?: (proposal: ProposalWithQuestionary) => void; elevation?: PaperProps['elevation']; + previewMode?: boolean; } export default function ProposalContainer(props: ProposalContainerProps) { - const { proposal, proposalUpdated, elevation } = props; + const { proposal, proposalUpdated, elevation, previewMode } = props; - const [initialState] = useState(new ProposalSubmissionState(proposal)); + const [initialState] = useState( + new ProposalSubmissionState(proposal, previewMode) + ); const eventHandlers = useEventHandlers(TemplateGroupId.PROPOSAL); @@ -48,10 +51,30 @@ export default function ProposalContainer(props: ProposalContainerProps) { } ); - const { state, dispatch } = QuestionarySubmissionModel(initialState, [ - eventHandlers, - customEventHandlers, - ]); + const customReducers = ( + state: ProposalSubmissionState, + draftState: ProposalSubmissionState, + action: Event + ) => { + switch (action.type) { + case 'SAMPLE_DECLARATION_ITEMS_MODIFIED': + draftState.proposal.samples = action.newItems; + draftState.isDirty = true; + break; + case 'GENERIC_TEMPLATE_ITEMS_MODIFIED': + draftState.proposal.genericTemplates = action.newItems; + draftState.isDirty = true; + break; + } + + return draftState; + }; + + const { state, dispatch } = QuestionarySubmissionModel( + initialState, + [eventHandlers, customEventHandlers], + customReducers + ); const hasReferenceNumberFormat = !!state.proposal.call?.referenceNumberFormat; @@ -88,6 +111,7 @@ export default function ProposalContainer(props: ProposalContainerProps) { diff --git a/src/components/proposal/ProposalCreate.tsx b/src/components/proposal/ProposalCreate.tsx index 9532820b5..dbfae4a15 100644 --- a/src/components/proposal/ProposalCreate.tsx +++ b/src/components/proposal/ProposalCreate.tsx @@ -11,18 +11,18 @@ import { ProposalWithQuestionary } from 'models/questionary/proposal/ProposalWit import ProposalContainer from './ProposalContainer'; -function createProposalStub( - callId: number, +export function createProposalStub( templateId: number, questionarySteps: QuestionaryStep[], proposer: BasicUserDetails, - call: Call | null + callId?: number, + call?: Call | null ): ProposalWithQuestionary { return { primaryKey: 0, title: '', abstract: '', - callId: callId, + callId: callId || 0, proposer: proposer, questionary: { questionaryId: 0, @@ -68,11 +68,11 @@ export default function ProposalCreate() { return ( ); diff --git a/src/components/proposal/ProposalSummary.tsx b/src/components/proposal/ProposalSummary.tsx index 75a57051b..c6e4a5cab 100644 --- a/src/components/proposal/ProposalSummary.tsx +++ b/src/components/proposal/ProposalSummary.tsx @@ -63,11 +63,11 @@ function ProposalReview({ confirm }: ProposalSummaryProps) { return; } - const { call } = await api().getCall({ id: proposal.callId }); + const { call } = await api().getCall({ callId: proposal.callId }); const workflowId = call?.proposalWorkflowId; if (workflowId) { const connections = ( - await api().getProposalWorkflow({ id: workflowId }) + await api().getProposalWorkflow({ proposalWorkflowId: workflowId }) ).proposalWorkflow?.proposalWorkflowConnectionGroups; if (connections) { diff --git a/src/components/proposal/ProposalTableInstrumentScientist.tsx b/src/components/proposal/ProposalTableInstrumentScientist.tsx index da53195c0..276942af5 100644 --- a/src/components/proposal/ProposalTableInstrumentScientist.tsx +++ b/src/components/proposal/ProposalTableInstrumentScientist.tsx @@ -20,9 +20,10 @@ import ProposalReviewContent, { } from 'components/review/ProposalReviewContent'; import ProposalReviewModal from 'components/review/ProposalReviewModal'; import ReviewerFilterComponent, { - defaultReviewerQueryFilter, + reviewFilter, } from 'components/review/ReviewerFilter'; import { FeatureContext } from 'context/FeatureContextProvider'; +import { SettingsContext } from 'context/SettingsContextProvider'; import { UserContext } from 'context/UserContextProvider'; import { FeatureId, @@ -30,6 +31,7 @@ import { ProposalsFilter, ReviewerFilter, SubmitTechnicalReviewInput, + SettingsId, } from 'generated/sdk'; import { useInstrumentScientistCallsData } from 'hooks/call/useInstrumentScientistCallsData'; import { useLocalStorage } from 'hooks/common/useLocalStorage'; @@ -111,24 +113,44 @@ const SEPReviewColumns = [ { title: 'SEP', field: 'sepCode', emptyValue: '-', hidden: true }, ]; +const proposalStatusFilter: Record = { + ALL: 0, + FEASIBILITY_REVIEW: 2, +}; + const ProposalTableInstrumentScientist: React.FC<{ confirm: WithConfirmType; }> = ({ confirm }) => { const { user } = useContext(UserContext); const featureContext = useContext(FeatureContext); const { api } = useDataApiWithFeedback(); + const { settingsMap } = useContext(SettingsContext); + const statusFilterValue = + settingsMap.get(SettingsId.DEFAULT_INST_SCI_STATUS_FILTER)?.settingsValue || + 2; + let statusFilter = proposalStatusFilter[statusFilterValue]; + if (statusFilter === undefined || statusFilter === null) { + statusFilter = 2; + } + const reviewFilterValue = + settingsMap.get(SettingsId.DEFAULT_INST_SCI_REVIEWER_FILTER) + ?.settingsValue || 'ME'; + let reviewerFilter = reviewFilter[reviewFilterValue]; + if (!reviewerFilter) { + reviewerFilter = ReviewerFilter.ME; + } const [urlQueryParams, setUrlQueryParams] = useQueryParams({ ...DefaultQueryParams, call: NumberParam, instrument: NumberParam, - proposalStatus: withDefault(NumberParam, 2), + proposalStatus: withDefault(NumberParam, statusFilter), questionId: StringParam, compareOperator: StringParam, value: StringParam, dataType: StringParam, reviewModal: NumberParam, modalTab: NumberParam, - reviewer: defaultReviewerQueryFilter, + reviewer: withDefault(StringParam, reviewerFilter), }); // NOTE: proposalStatusId has default value 2 because for Instrument Scientist default view should be all proposals in FEASIBILITY_REVIEW status const [proposalFilter, setProposalFilter] = useState({ @@ -199,6 +221,7 @@ const ProposalTableInstrumentScientist: React.FC<{ ...(isTechnicalReviewEnabled ? [PROPOSAL_MODAL_TAB_NAMES.TECHNICAL_REVIEW] : []), + ...(isSEPEnabled ? [PROPOSAL_MODAL_TAB_NAMES.ADMIN] : []), ]; /** diff --git a/src/components/proposal/ProposalTableOfficer.tsx b/src/components/proposal/ProposalTableOfficer.tsx index cdf63f726..18485a0a2 100644 --- a/src/components/proposal/ProposalTableOfficer.tsx +++ b/src/components/proposal/ProposalTableOfficer.tsx @@ -623,6 +623,9 @@ const ProposalTableOfficer: React.FC = ({ sepIds={selectedProposals.map( (selectedProposal) => selectedProposal.sepId )} + callIds={selectedProposals.map( + (selectedProposal) => selectedProposal.callId + )} /> diff --git a/src/components/questionary/Questionary.tsx b/src/components/questionary/Questionary.tsx index dd3302986..b3fcfbb11 100644 --- a/src/components/questionary/Questionary.tsx +++ b/src/components/questionary/Questionary.tsx @@ -16,9 +16,10 @@ import { QuestionaryStepButton } from './QuestionaryStepButton'; interface QuestionaryProps { title: string; info?: JSX.Element | string; + previewMode?: boolean; } -function Questionary({ title, info }: QuestionaryProps) { +function Questionary({ title, info, previewMode = false }: QuestionaryProps) { const isMobile = useMediaQuery('(max-width: 500px)'); const useStyles = makeStyles((theme) => ({ @@ -119,7 +120,7 @@ function Questionary({ title, info }: QuestionaryProps) { return displayElementFactory.getDisplayElement( currentStep, - stepMetadata.isReadonly && !isUserOfficer + (stepMetadata.isReadonly && !isUserOfficer) || previewMode ); }; diff --git a/src/components/questionary/questionaries/sample/SampleQuestionaryDefinition.ts b/src/components/questionary/questionaries/sample/SampleQuestionaryDefinition.ts index 7f1bdbce1..8da89138c 100644 --- a/src/components/questionary/questionaries/sample/SampleQuestionaryDefinition.ts +++ b/src/components/questionary/questionaries/sample/SampleQuestionaryDefinition.ts @@ -3,12 +3,12 @@ import { ItemWithQuestionary } from 'models/questionary/QuestionarySubmissionSta import { QuestionaryDefinition } from '../../QuestionaryRegistry'; import { SampleStepDisplayElementFactory } from './SampleStepDisplayElementFactory'; -import { SampleWizardStepFactory } from './SampleWizardStepFactory'; +import { StepsWizardWithoutReviewStepFactory } from './StepsWizardWithoutReviewStepFactory'; export const sampleQuestionaryDefinition: QuestionaryDefinition = { groupId: TemplateGroupId.SAMPLE, displayElementFactory: new SampleStepDisplayElementFactory(), - wizardStepFactory: new SampleWizardStepFactory(), + wizardStepFactory: new StepsWizardWithoutReviewStepFactory(), getItemWithQuestionary( api: Sdk, sampleId: number diff --git a/src/components/questionary/questionaries/sample/SampleWizardStepFactory.ts b/src/components/questionary/questionaries/sample/StepsWizardWithoutReviewStepFactory.ts similarity index 90% rename from src/components/questionary/questionaries/sample/SampleWizardStepFactory.ts rename to src/components/questionary/questionaries/sample/StepsWizardWithoutReviewStepFactory.ts index 08c4345ac..e19e0d5bd 100644 --- a/src/components/questionary/questionaries/sample/SampleWizardStepFactory.ts +++ b/src/components/questionary/questionaries/sample/StepsWizardWithoutReviewStepFactory.ts @@ -3,7 +3,7 @@ import { WizardStep } from 'models/questionary/QuestionarySubmissionState'; import { SampleQuestionaryWizardStep } from './SampleQuestionaryWizardStep'; -export class SampleWizardStepFactory { +export class StepsWizardWithoutReviewStepFactory { getWizardSteps(questionarySteps: QuestionaryStep[]): WizardStep[] { const wizardSteps: WizardStep[] = []; diff --git a/src/components/questionary/questionaryComponents/FileUpload/FilesAnswerRenderer.tsx b/src/components/questionary/questionaryComponents/FileUpload/FilesAnswerRenderer.tsx index df0721752..8903be6ec 100644 --- a/src/components/questionary/questionaryComponents/FileUpload/FilesAnswerRenderer.tsx +++ b/src/components/questionary/questionaryComponents/FileUpload/FilesAnswerRenderer.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { FileIdWithCaptionAndFigure } from 'components/common/FileUploadComponent'; import { AnswerRenderer } from 'components/questionary/QuestionaryComponentRegistry'; -import { useFileMetadata } from 'hooks/file/useFileMetadata'; +import { useFilesMetadata } from 'hooks/file/useFilesMetadata'; import { FileMetaData } from 'models/questionary/FileUpload'; const useStyles = makeStyles((theme) => ({ @@ -22,7 +22,7 @@ function DownloadableFileList(props: { fileIds: string[] }) { const { fileIds } = props; const classes = useStyles(); - const { files } = useFileMetadata(fileIds); + const { files } = useFilesMetadata({ fileIds }); const downloadLink = (file: FileMetaData) => ( diff --git a/src/components/questionary/questionaryComponents/GenericTemplate/QuestionaryComponentGenericTemplate.tsx b/src/components/questionary/questionaryComponents/GenericTemplate/QuestionaryComponentGenericTemplate.tsx index bcc8ef462..2d5f6941a 100755 --- a/src/components/questionary/questionaryComponents/GenericTemplate/QuestionaryComponentGenericTemplate.tsx +++ b/src/components/questionary/questionaryComponents/GenericTemplate/QuestionaryComponentGenericTemplate.tsx @@ -1,16 +1,17 @@ import makeStyles from '@mui/styles/makeStyles'; -import { Field, FieldProps, FormikProps } from 'formik'; +import { Field, FieldProps } from 'formik'; import React, { useContext, useState } from 'react'; import ErrorMessage from 'components/common/ErrorMessage'; import StyledModal from 'components/common/StyledModal'; import UOLoader from 'components/common/UOLoader'; +import { BasicComponentProps } from 'components/proposal/IBasicComponentProps'; import { ProposalContextType } from 'components/proposal/ProposalContainer'; import { createMissingContextErrorMessage, QuestionaryContext, } from 'components/questionary/QuestionaryContext'; -import { Answer, QuestionaryStep, SubTemplateConfig } from 'generated/sdk'; +import { QuestionaryStep, SubTemplateConfig } from 'generated/sdk'; import { GenericTemplateCore } from 'models/questionary/genericTemplate/GenericTemplateCore'; import { GenericTemplateWithQuestionary } from 'models/questionary/genericTemplate/GenericTemplateWithQuestionary'; import useDataApiWithFeedback from 'utils/useDataApiWithFeedback'; @@ -64,20 +65,18 @@ function createGenericTemplateStub( }; } -type QuestionaryComponentGenericTemplateProps = { - answer: Answer; - formikProps: FormikProps>; - confirm: WithConfirmType; - prompt: WithPromptType; -}; - function QuestionaryComponentGenericTemplate( - props: QuestionaryComponentGenericTemplateProps + props: BasicComponentProps & { + confirm: WithConfirmType; + prompt: WithPromptType; + } ) { const { answer, confirm, prompt } = props; const answerId = answer.question.id; const config = answer.config as SubTemplateConfig; - const { state } = useContext(QuestionaryContext) as ProposalContextType; + const { state, dispatch } = useContext( + QuestionaryContext + ) as ProposalContextType; const { api } = useDataApiWithFeedback(); const classes = useStyles(); @@ -92,6 +91,17 @@ function QuestionaryComponentGenericTemplate( return ( {({ field, form }: FieldProps) => { + const updateFieldValueAndState = ( + updatedItems: GenericTemplateCore[] | null + ) => { + form.setFieldValue(answerId, updatedItems); + dispatch({ + type: 'GENERIC_TEMPLATE_ITEMS_MODIFIED', + id: answerId, + newItems: updatedItems, + }); + }; + const copyGenericTemplate = (id: number, title: string) => api() .cloneGenericTemplate({ genericTemplateId: id, title: title }) @@ -99,10 +109,9 @@ function QuestionaryComponentGenericTemplate( const clonedGenericTemplate = response.cloneGenericTemplate.genericTemplate; if (clonedGenericTemplate) { - form.setFieldValue(answerId, [ - ...field.value, - clonedGenericTemplate, - ]); + const newStateItems = [...field.value, clonedGenericTemplate]; + + updateFieldValueAndState(newStateItems); } }); @@ -111,10 +120,11 @@ function QuestionaryComponentGenericTemplate( .deleteGenericTemplate({ genericTemplateId: id }) .then((response) => { if (!response.deleteGenericTemplate.rejection) { - const newStateValue = field.value.filter( + const newStateItems = field.value.filter( (genericTemplate) => genericTemplate.id !== id ); - form.setFieldValue(answerId, newStateValue); + + updateFieldValueAndState(newStateItems); } }); @@ -199,19 +209,18 @@ function QuestionaryComponentGenericTemplate( { - const newValue = field.value.map((genericTemplate) => + const newStateItems = field.value.map((genericTemplate) => genericTemplate.id === updatedGenericTemplate.id ? updatedGenericTemplate : genericTemplate ); - form.setFieldValue(answerId, newValue); + updateFieldValueAndState(newStateItems); }} genericTemplateCreated={(newGenericTemplate) => { - form.setFieldValue(answerId, [ - ...field.value, - newGenericTemplate, - ]); + const newStateItems = [...field.value, newGenericTemplate]; + + updateFieldValueAndState(newStateItems); }} genericTemplateEditDone={() => { // refresh all genericTemplates @@ -223,7 +232,7 @@ function QuestionaryComponentGenericTemplate( }, }) .then((result) => { - form.setFieldValue(answerId, result.genericTemplates); + updateFieldValueAndState(result.genericTemplates); }); setSelectedGenericTemplate(null); diff --git a/src/components/questionary/questionaryComponents/SampleDeclaration/QuestionaryComponentSampleDeclaration.tsx b/src/components/questionary/questionaryComponents/SampleDeclaration/QuestionaryComponentSampleDeclaration.tsx index 09927f58e..28e0216a2 100755 --- a/src/components/questionary/questionaryComponents/SampleDeclaration/QuestionaryComponentSampleDeclaration.tsx +++ b/src/components/questionary/questionaryComponents/SampleDeclaration/QuestionaryComponentSampleDeclaration.tsx @@ -1,18 +1,18 @@ import { Paper } from '@mui/material'; import makeStyles from '@mui/styles/makeStyles'; -import { Field, FieldProps, FormikProps } from 'formik'; +import { Field, FieldProps } from 'formik'; import React, { useContext, useState } from 'react'; import ErrorMessage from 'components/common/ErrorMessage'; import StyledModal from 'components/common/StyledModal'; import UOLoader from 'components/common/UOLoader'; +import { BasicComponentProps } from 'components/proposal/IBasicComponentProps'; import { ProposalContextType } from 'components/proposal/ProposalContainer'; import { createMissingContextErrorMessage, QuestionaryContext, } from 'components/questionary/QuestionaryContext'; import { - Answer, QuestionaryStep, SampleStatus, SubTemplateConfig, @@ -75,20 +75,18 @@ function createSampleStub( }; } -type QuestionaryComponentSampleDeclarationProps = { - answer: Answer; - formikProps: FormikProps>; - confirm: WithConfirmType; - prompt: WithPromptType; -}; - function QuestionaryComponentSampleDeclaration( - props: QuestionaryComponentSampleDeclarationProps + props: BasicComponentProps & { + confirm: WithConfirmType; + prompt: WithPromptType; + } ) { const { answer, confirm, prompt } = props; const answerId = answer.question.id; const config = answer.config as SubTemplateConfig; - const { state } = useContext(QuestionaryContext) as ProposalContextType; + const { state, dispatch } = useContext( + QuestionaryContext + ) as ProposalContextType; const { api } = useDataApiWithFeedback(); const classes = useStyles(); @@ -103,13 +101,26 @@ function QuestionaryComponentSampleDeclaration( return ( {({ field, form }: FieldProps) => { + const updateFieldValueAndState = ( + updatedItems: SampleCore[] | null + ) => { + form.setFieldValue(answerId, updatedItems); + dispatch({ + type: 'SAMPLE_DECLARATION_ITEMS_MODIFIED', + id: answerId, + newItems: updatedItems, + }); + }; + const copySample = (id: number, title: string) => api() .cloneSample({ sampleId: id, title: title }) .then((response) => { const clonedSample = response.cloneSample.sample; if (clonedSample) { - form.setFieldValue(answerId, [...field.value, clonedSample]); + const newStateItems = [...field.value, clonedSample]; + + updateFieldValueAndState(newStateItems); } }); @@ -118,10 +129,11 @@ function QuestionaryComponentSampleDeclaration( .deleteSample({ sampleId: id }) .then((response) => { if (!response.deleteSample.rejection) { - const newStateValue = field.value.filter( + const newStateItems = field.value.filter( (sample) => sample.id !== id ); - form.setFieldValue(answerId, newStateValue); + + updateFieldValueAndState(newStateItems); } }); @@ -207,14 +219,16 @@ function QuestionaryComponentSampleDeclaration( { - const newValue = field.value.map((sample) => + const newStateItems = field.value.map((sample) => sample.id === updatedSample.id ? updatedSample : sample ); - form.setFieldValue(answerId, newValue); + updateFieldValueAndState(newStateItems); }} sampleCreated={(newSample) => { - form.setFieldValue(answerId, [...field.value, newSample]); + const newStateItems = [...field.value, newSample]; + + updateFieldValueAndState(newStateItems); }} sampleEditDone={() => { // refresh all samples @@ -226,7 +240,7 @@ function QuestionaryComponentSampleDeclaration( }, }) .then((result) => { - form.setFieldValue(answerId, result.samples); + updateFieldValueAndState(result.samples); }); setSelectedSample(null); diff --git a/src/components/review/ProposalQuestionaryReview.tsx b/src/components/review/ProposalQuestionaryReview.tsx index 46afb9791..ef9b3db87 100644 --- a/src/components/review/ProposalQuestionaryReview.tsx +++ b/src/components/review/ProposalQuestionaryReview.tsx @@ -6,7 +6,7 @@ import ProposalQuestionaryDetails from 'components/proposal/ProposalQuestionaryD import { TableRowData } from 'components/questionary/QuestionaryDetails'; import { BasicUserDetails } from 'generated/sdk'; import { ProposalWithQuestionary } from 'models/questionary/proposal/ProposalWithQuestionary'; -import { getFullUserName } from 'utils/user'; +import { getFullUserNameWithEmail } from 'utils/user'; export default function ProposalQuestionaryReview( props: { @@ -22,7 +22,6 @@ export default function ProposalQuestionaryReview( const users = data.users || []; const hasReferenceNumberFormat = !!data.call?.referenceNumberFormat; - const additionalDetails: TableRowData[] = [ { label: 'Proposal ID', @@ -35,12 +34,12 @@ export default function ProposalQuestionaryReview( { label: 'Abstract', value: data.abstract }, { label: 'Principal Investigator', - value: getFullUserName(data.proposer), + value: getFullUserNameWithEmail(data.proposer), }, { label: 'Co-Proposers', value: users - .map((user: BasicUserDetails) => getFullUserName(user)) + .map((user: BasicUserDetails) => getFullUserNameWithEmail(user)) .join(', '), }, ]; diff --git a/src/components/review/ProposalReviewContent.tsx b/src/components/review/ProposalReviewContent.tsx index 6ff8e1d8e..e4dc87bf9 100644 --- a/src/components/review/ProposalReviewContent.tsx +++ b/src/components/review/ProposalReviewContent.tsx @@ -55,6 +55,7 @@ const ProposalReviewContent: React.FC = ({ }) => { const { user } = useContext(UserContext); const isUserOfficer = useCheckAccess([UserRole.USER_OFFICER]); + const isInstrumentScientist = useCheckAccess([UserRole.INSTRUMENT_SCIENTIST]); const { reviewData, setReviewData } = useReviewData(reviewId, sepId); const { proposalData, setProposalData, loading } = useProposalData( proposalPk || reviewData?.proposal?.primaryKey @@ -136,7 +137,7 @@ const ProposalReviewContent: React.FC = ({ ); - const ProposalAdminTab = isUserOfficer && ( + const ProposalAdminTab = (isUserOfficer || isInstrumentScientist) && ( diff --git a/src/components/review/ReviewerFilter.tsx b/src/components/review/ReviewerFilter.tsx index e7552f314..3a6c3d829 100644 --- a/src/components/review/ReviewerFilter.tsx +++ b/src/components/review/ReviewerFilter.tsx @@ -3,10 +3,11 @@ import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; import Select from '@mui/material/Select'; import makeStyles from '@mui/styles/makeStyles'; -import React from 'react'; +import React, { useContext } from 'react'; import { StringParam, useQueryParams, withDefault } from 'use-query-params'; -import { ReviewerFilter } from 'generated/sdk'; +import { SettingsContext } from 'context/SettingsContextProvider'; +import { ReviewerFilter, SettingsId } from 'generated/sdk'; const useStyles = makeStyles((theme) => ({ formControl: { @@ -15,23 +16,31 @@ const useStyles = makeStyles((theme) => ({ }, })); -export const defaultReviewerQueryFilter = withDefault( - StringParam, - ReviewerFilter.ME -); - type ReviewerFilterComponentProps = { reviewer: string; onChange?: (reviewer: ReviewerFilter) => void; }; +export const reviewFilter: Record = { + ALL: ReviewerFilter.ALL, + ME: ReviewerFilter.ME, +}; + const ReviewerFilterComponent: React.FC = ({ reviewer, onChange, }) => { + const { settingsMap } = useContext(SettingsContext); + const reviewFilterValue = + settingsMap.get(SettingsId.DEFAULT_INST_SCI_REVIEWER_FILTER) + ?.settingsValue || 'ME'; + let reviewerFilter = reviewFilter[reviewFilterValue]; + if (!reviewerFilter) { + reviewerFilter = ReviewerFilter.ME; + } const classes = useStyles(); const [, setQuery] = useQueryParams({ - reviewer: defaultReviewerQueryFilter, + reviewer: withDefault(StringParam, reviewerFilter), }); return ( diff --git a/src/components/settings/proposalWorkflow/ProposalWorkflowEditorModel.tsx b/src/components/settings/proposalWorkflow/ProposalWorkflowEditorModel.tsx index caaa6614e..38d107b4f 100644 --- a/src/components/settings/proposalWorkflow/ProposalWorkflowEditorModel.tsx +++ b/src/components/settings/proposalWorkflow/ProposalWorkflowEditorModel.tsx @@ -263,7 +263,7 @@ const ProposalWorkflowEditorModel = ( useEffect(() => { api() - .getProposalWorkflow({ id: parseInt(workflowId) }) + .getProposalWorkflow({ proposalWorkflowId: parseInt(workflowId) }) .then((data) => { // NOTE: Push at least one group to have initial droppable if new proposal workflow if ( diff --git a/src/components/shipments/ShippingInstructions.tsx b/src/components/shipments/ShippingInstructions.tsx index 14df50453..236bb657f 100644 --- a/src/components/shipments/ShippingInstructions.tsx +++ b/src/components/shipments/ShippingInstructions.tsx @@ -30,6 +30,7 @@ const steps = [ description: (
  • Print and cut the label;
  • +
  • Place the label inside a plastic wallet for extra protection;
  • Stick the label to both sides of the parcel;
  • If using tape not tape over the barcodes.
@@ -97,18 +98,18 @@ export default function ShippingInstructions() { @@ -121,7 +122,7 @@ export default function ShippingInstructions() { You might want to inform your local contact to expect parcel! )} diff --git a/src/components/template/PdfTemplateEditor.tsx b/src/components/template/PdfTemplateEditor.tsx new file mode 100644 index 000000000..98ae770b4 --- /dev/null +++ b/src/components/template/PdfTemplateEditor.tsx @@ -0,0 +1,95 @@ +import { Typography } from '@mui/material'; +import Button from '@mui/material/Button'; +import { Field, Form, Formik } from 'formik'; +import { TextField } from 'formik-mui'; +import React, { useEffect, useState } from 'react'; +import { useParams } from 'react-router'; + +import UOLoader from 'components/common/UOLoader'; +import { PdfTemplate, Template } from 'generated/sdk'; +import { + StyledButtonContainer, + StyledContainer, + StyledPaper, +} from 'styles/StyledComponents'; +import useDataApiWithFeedback from 'utils/useDataApiWithFeedback'; + +export default function PdfTemplateEditor() { + const { api } = useDataApiWithFeedback(); + const [loading, setLoading] = useState(true); + const [template, setTemplate] = useState