From 5069b3072540bdc5982b7838204147e16453a8b1 Mon Sep 17 00:00:00 2001 From: Will Tsai <28876888+willtsai@users.noreply.github.com> Date: Thu, 29 Jun 2023 14:14:49 -0700 Subject: [PATCH] edge to v0.22 upmerge to pick up changes Signed-off-by: Will Tsai <28876888+willtsai@users.noreply.github.com> --- .devcontainer/on-create.sh | 25 +++- .github/workflows/purge-test-resources.yaml | 47 +++++++ .github/workflows/test.yaml | 126 +++++++++++++++--- quickstarts/dapr/dapr-azure.bicep | 32 +++-- quickstarts/dapr/dapr.bicep | 20 +-- quickstarts/environment-variables/app.bicep | 11 +- reference-apps/aws/awss3.bicep | 1 - .../container-app-store/iac/app.bicep | 31 +---- .../container-app-store/iac/infra-azure.bicep | 14 +- .../iac/infra-selfhosted.bicep | 2 +- .../eshop-dapr/infra/dapr-pub-sub.bicep | 24 +++- .../eshop-dapr/infra/dapr-secret-store.bicep | 2 +- .../eshop-dapr/infra/dapr-state-store.bicep | 2 +- .../eshop-dapr/infra/sql-server.bicep | 33 ++++- reference-apps/eshop-dapr/main.bicep | 17 --- .../eshop-dapr/services/basket-api.bicep | 14 +- .../eshop-dapr/services/catalog-api.bicep | 15 +-- .../eshop-dapr/services/identity-api.bicep | 15 +-- .../eshop-dapr/services/ordering-api.bicep | 15 +-- .../eshop-dapr/services/payment-api.bicep | 15 +-- .../eshop-dapr/services/webshopping-agg.bicep | 46 +------ .../eshop-dapr/services/webshopping-gw.bicep | 16 --- .../eshop-dapr/services/webstatus.bicep | 60 --------- reference-apps/eshop/iac/eshop.bicep | 8 -- reference-apps/eshop/iac/infra/aws.bicep | 34 ++++- reference-apps/eshop/iac/infra/azure.bicep | 68 ++++++++-- .../eshop/iac/infra/containers.bicep | 36 ++++- .../eshop/iac/services/catalog.bicep | 9 +- .../eshop/iac/services/identity.bicep | 9 +- .../eshop/iac/services/ordering.bicep | 11 +- .../eshop/iac/services/webhooks.bicep | 9 +- ui-tests/.gitignore | 4 + ui-tests/package-lock.json | 78 +++++++++++ ui-tests/package.json | 16 +++ ui-tests/playwright.config.ts | 50 +++++++ ui-tests/tests/demo.app.spec.ts | 111 +++++++++++++++ ui-tests/tests/eshop/container.app.spec.ts | 98 ++++++++++++++ 37 files changed, 749 insertions(+), 375 deletions(-) create mode 100644 .github/workflows/purge-test-resources.yaml create mode 100644 ui-tests/.gitignore create mode 100644 ui-tests/package-lock.json create mode 100644 ui-tests/package.json create mode 100644 ui-tests/playwright.config.ts create mode 100644 ui-tests/tests/demo.app.spec.ts create mode 100644 ui-tests/tests/eshop/container.app.spec.ts diff --git a/.devcontainer/on-create.sh b/.devcontainer/on-create.sh index 5237a023..306552e0 100644 --- a/.devcontainer/on-create.sh +++ b/.devcontainer/on-create.sh @@ -16,5 +16,26 @@ wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O dapr uninstall # clean if needed dapr init -k -## Install stable rad CLI (edge conditionally downloaded in post-create script) -wget -q "https://get.radapp.dev/tools/rad/install.sh" -O - | /bin/bash +## Install rad CLI +CURRENT_BRANCH=$(git branch --show-current) + +if [ "$CURRENT_BRANCH" = "edge" ]; then + RADIUS_VERSION=edge +else + ## If CURRENT_BRANCH matches a regex of the form "v0.20", set RADIUS_VERSION to the matching string minus the "v" + if [[ "$CURRENT_BRANCH" =~ ^v[0-9]+\.[0-9]+$ ]]; then + RADIUS_VERSION=${CURRENT_BRANCH:1} + else + ## Otherwise, set RADIUS_VERSION to "edge" + RADIUS_VERSION=edge + fi +fi + +if [ "$RADIUS_VERSION" = "edge" ]; then + wget -q "https://get.radapp.dev/tools/rad/install.sh" -O - | /bin/bash -s edge +else + wget -q "https://get.radapp.dev/tools/rad/install.sh" -O - | /bin/bash +fi + +## Download Bicep extension +curl https://get.radapp.dev/tools/vscode-extensibility/$RADIUS_VERSION/rad-vscode-bicep.vsix --output /tmp/rad-vscode-bicep.vsix \ No newline at end of file diff --git a/.github/workflows/purge-test-resources.yaml b/.github/workflows/purge-test-resources.yaml new file mode 100644 index 00000000..db47b568 --- /dev/null +++ b/.github/workflows/purge-test-resources.yaml @@ -0,0 +1,47 @@ +name: Purge test resources +on: + schedule: + - cron: "30 0,12 * * *" +env: + AZURE_RG_DELETE_LIST_FILE: "az_rg_list.txt" + VALID_RESOURCE_WINDOW: 6*60*60 +jobs: + purge_azure_resources: + name: Azure resources clean-ups + runs-on: [self-hosted, 1ES.Pool=1ES-Radius] + steps: + - name: Login to Azure + run: | + az login --service-principal \ + --username ${{ secrets.AZURE_SP_TESTS_APPID }} \ + --password ${{ secrets.AZURE_SP_TESTS_PASSWORD }} \ + --tenant ${{ secrets.AZURE_SP_TESTS_TENANTID }} + + az account set --subscription ${{ secrets.AZURE_SUBSCRIPTIONID_TESTS }} + + - name: List Test Resource Groups + run: | + echo "## Test resource group list" >> $GITHUB_STEP_SUMMARY + az group list --query "[?starts_with(name, 'samplestest-')].{Name:name, creationTime:tags.creationTime}" -o json > resource_groups.json + + current_time=$(date +%s) + hours_ago=$((current_time - ${{ env.VALID_RESOURCE_WINDOW }})) + + jq -r '.[] | select(.creationTime == null || .creationTime < '$hours_ago') | .Name' resource_groups.json > ${{ env.AZURE_RG_DELETE_LIST_FILE}} + jq -r '.[] | {name: .Name, creationTime: .creationTime // "None"}' resource_groups.json > $GITHUB_STEP_SUMMARY + + - name: Delete Azure Resource Groups + run: | + echo "## Deleting resource group list" >> $GITHUB_STEP_SUMMARY + cat ${{ env.AZURE_RG_DELETE_LIST_FILE}} | while read -r line + do + echo " * $line" >> $GITHUB_STEP_SUMMARY + az group delete --resource-group $line --yes --verbose + done + + - name: Create GitHub issue on failure + if: ${{ failure() }} + run: | + gh issue create --title "Samples purge test resources failed \ + --body "Test failed on ${{ github.repository }}. See [workflow logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for more details." \ + s--repo ${{ github.repository }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index cc32b916..e406ac33 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -7,22 +7,22 @@ on: - v*.* - edge paths: - - 'quickstarts/**' - - 'reference-apps/**' - - '.github/workflows/**' + - "quickstarts/**" + - "reference-apps/**" + - ".github/workflows/**" pull_request: types: [opened, synchronize, reopened] branches: - v*.* - edge schedule: # 7:45 AM Pacific Time - - cron: '45 15 * * *' + - cron: "45 15 * * *" jobs: test: name: Deploy quickstarts to local environment if: github.event.action != 'closed' - runs-on: ubuntu-latest + runs-on: [self-hosted, 1ES.Pool=1ES-Radius] strategy: fail-fast: false matrix: @@ -31,6 +31,9 @@ jobs: app: demo path: ./demo/app.bicep args: --application demo + uiTestFile: tests/demo.app.spec.ts + port: 3000 + container: demo - name: dapr app: dapr-quickstart path: ./quickstarts/dapr/dapr.bicep @@ -44,48 +47,131 @@ jobs: - name: eshop app: eshop path: ./reference-apps/eshop/iac/eshop.bicep + args: --application eshop + uiTestFile: tests/eshop/container.app.spec.ts + - name: eshop-azure + app: eshop + path: ./reference-apps/eshop/iac/eshop.bicep + args: --application eshop -p platform=azure + uiTestFile: tests/eshop/container.app.spec.ts + credential: azure env: BRANCH: ${{ github.base_ref || github.ref_name }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # The Azure Location to store test resources + AZURE_LOCATION: westus3 steps: + # TODO: Do we need to set any specific environment variables for pull_request, push, + # schedule, and workflow_dispatch steps? + - name: Generate output variables + id: gen-id + run: | + BASE_STR="SAMPLES|${GITHUB_SHA}|${GITHUB_SERVER_URL}|${GITHUB_REPOSITORY}|${GITHUB_RUN_ID}|${GITHUB_RUN_ATTEMPT}" + UNIQUE_ID=$(echo $BASE_STR | sha1sum | head -c 10) + + # Set output variables to be used in the other jobs + echo "UNIQUE_ID=${UNIQUE_ID}" >> $GITHUB_OUTPUT + echo "TEST_RESOURCE_GROUP_PREFIX=samplestest-${UNIQUE_ID}" >> $GITHUB_OUTPUT - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 16 - name: az CLI login run: | az login --service-principal \ --username ${{ secrets.AZURE_SP_TESTS_APPID }} \ --password ${{ secrets.AZURE_SP_TESTS_PASSWORD }} \ --tenant ${{ secrets.AZURE_SP_TESTS_TENANTID }} + - name: Create Azure resource group + if: ${{ matrix.credential == 'azure' }} + env: + RESOURCE_GROUP: ${{ steps.gen-id.outputs.TEST_RESOURCE_GROUP_PREFIX }}-${{ matrix.name }} + SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTIONID_TESTS }} + run: | + current_time=$(date +%s) + az group create \ + --location ${{ env.AZURE_LOCATION }} \ + --name $RESOURCE_GROUP \ + --subscription $SUBSCRIPTION_ID \ + --tags creationTime=$current_time + while [ $(az group exists --name $RESOURCE_GROUP --subscription $SUBSCRIPTION_ID) = false ]; do + echo "Waiting for resource group $RESOURCE_GROUP to be created..." + sleep 5 + done - name: Download k3d - run: wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash + run: wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash - name: Download rad CLI run: | - echo "Downloading rad CLI from branch $BRANCH" - if [ "$BRANCH" = "edge" ]; then - wget -q "https://get.radapp.dev/tools/rad/install.sh" -O - | /bin/bash -s edge - else - wget -q "https://get.radapp.dev/tools/rad/install.sh" -O - | /bin/bash - fi + echo "Downloading rad CLI from branch $BRANCH" + if [ "$BRANCH" = "edge" ]; then + wget -q "https://get.radapp.dev/tools/rad/install.sh" -O - | /bin/bash -s edge + else + wget -q "https://get.radapp.dev/tools/rad/install.sh" -O - | /bin/bash + fi - name: Create k3d cluster - run: k3d cluster create -p "8081:80@loadbalancer" --k3s-arg "--disable=traefik@server:0" + run: k3d cluster create -p "80:80@loadbalancer" --k3s-arg "--disable=traefik@server:0" - name: Install Dapr if: ${{ matrix.enableDapr }} run: | helm repo add dapr https://dapr.github.io/helm-charts/ helm install dapr dapr/dapr --version=1.6 --namespace dapr-system --create-namespace --wait - - name: Init environment + - name: Init local environment + env: + RESOURCE_GROUP: ${{ steps.gen-id.outputs.TEST_RESOURCE_GROUP_PREFIX }}-${{ matrix.name }} + SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTIONID_TESTS }} run: | - rad install kubernetes --set global.rp.publicEndpointOverride=localhost:8081 + rad install kubernetes --set rp.publicEndpointOverride=localhost rad group create default rad workspace create kubernetes default --group default rad group switch default rad env create default rad env switch default - rad recipe register default --template-kind bicep --template-path radius.azurecr.io/recipes/dev/rediscaches:0.21 --link-type Applications.Link/redisCaches + rad recipe register default -e default -w default --template-kind bicep --template-path radius.azurecr.io/recipes/dev/rediscaches:latest --link-type Applications.Link/redisCaches + rad recipe register default -e default -w default --template-kind bicep --template-path radius.azurecr.io/recipes/dev/mongodatabases:latest --link-type Applications.Link/mongoDatabases + if [[ "${{ matrix.credential }}" == "azure" ]]; then + rad env update default --azure-subscription-id $SUBSCRIPTION_ID --azure-resource-group $RESOURCE_GROUP + rad credential register azure --client-id ${{ secrets.AZURE_SP_TESTS_APPID }} --client-secret ${{ secrets.AZURE_SP_TESTS_PASSWORD }} --tenant-id ${{ secrets.AZURE_SP_TESTS_TENANTID }} + fi - name: Deploy app - run: rad deploy ${{ matrix.path }} ${{ matrix.args }} + run: rad deploy ${{ matrix.path }} ${{ matrix.args }} + - name: Wait for all pods to be ready + run: | + namespace="default-${{ matrix.app }}" + label="radius.dev/application=${{ matrix.app }}" + kubectl wait --for=condition=Ready pod -l $label -n $namespace --timeout=5m + - name: Run Playwright Test + if: ${{ matrix.uiTestFile != '' }} + run: | + if [[ "${{ matrix.container }}" != "" ]]; then + rad resource expose containers ${{ matrix.container }} ${{ matrix.args }} --port ${{ matrix.port }} & + fi + cd ui-tests/ + npm ci + npx playwright install --with-deps + npx playwright test ${{ matrix.uiTestFile }} + - name: Upload Playwright Results + uses: actions/upload-artifact@v3 + if: always() && matrix.uiTestFile != '' + with: + name: playwright-report-${{ matrix.name }} + path: ui-tests/playwright-report/ + retention-days: 30 + if-no-files-found: error - name: Delete app - run: rad app delete ${{ matrix.app }} -y + run: rad app delete ${{ matrix.app }} -y + - name: Delete Azure resource group + if: always() && matrix.credential == 'azure' + env: + RESOURCE_GROUP: ${{ steps.gen-id.outputs.TEST_RESOURCE_GROUP_PREFIX }}-${{ matrix.name }} + SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTIONID_TESTS }} + run: | + # if deletion fails, purge workflow will purge the resource group and its resources later. + az group delete \ + --subscription $SUBSCRIPTION_ID \ + --name $RESOURCE_GROUP \ + --yes - name: Create GitHub issue on failure - if: ${{ failure() }} + if: failure() && github.event_name != 'pull_request' run: gh issue create --title "Samples deployment failed for ${{ matrix.app }}" --body "Test failed on ${{ github.repository }}. See [workflow logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for more details." --repo ${{ github.repository }} diff --git a/quickstarts/dapr/dapr-azure.bicep b/quickstarts/dapr/dapr-azure.bicep index 5b65cab3..a993ee5a 100644 --- a/quickstarts/dapr/dapr-azure.bicep +++ b/quickstarts/dapr/dapr-azure.bicep @@ -30,7 +30,6 @@ resource backend 'Applications.Core/containers@2022-03-15-privatepreview' = { extensions: [ { kind: 'daprSidecar' - provides: backendRoute.id appId: 'backend' appPort: 3000 } @@ -38,21 +37,15 @@ resource backend 'Applications.Core/containers@2022-03-15-privatepreview' = { } } -resource backendRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' = { - name: 'backend-route' - properties: { - environment: environment - application: app.id - appId: 'backend' - } -} - resource frontend 'Applications.Core/containers@2022-03-15-privatepreview' = { name: 'frontend' properties: { application: app.id container: { image: 'radius.azurecr.io/quickstarts/dapr-frontend:edge' + env: { + CONNECTION_BACKEND_APPID: backend.name + } ports: { ui: { containerPort: 80 @@ -60,11 +53,6 @@ resource frontend 'Applications.Core/containers@2022-03-15-privatepreview' = { } } } - connections: { - backend: { - source: backendRoute.id - } - } extensions: [ { kind: 'daprSidecar' @@ -119,7 +107,17 @@ resource stateStore 'Applications.Link/daprStateStores@2022-03-15-privatepreview properties: { environment: environment application: app.id - mode: 'resource' - resource: account::tableServices::table.id + resourceProvisioning: 'manual' + resources: [ + { id: account.id } + { id: account::tableServices::table.id } + ] + metadata: { + accountName: account.name + accountKey: account.listKeys().keys[0].value + tableName: account::tableServices::table.name + } + type: 'state.azure.tablestorage' + version: 'v1' } } diff --git a/quickstarts/dapr/dapr.bicep b/quickstarts/dapr/dapr.bicep index 3ba7f584..019861b7 100644 --- a/quickstarts/dapr/dapr.bicep +++ b/quickstarts/dapr/dapr.bicep @@ -33,7 +33,6 @@ resource backend 'Applications.Core/containers@2022-03-15-privatepreview' = { extensions: [ { kind: 'daprSidecar' - provides: backendRoute.id appId: 'backend' appPort: 3000 } @@ -41,21 +40,15 @@ resource backend 'Applications.Core/containers@2022-03-15-privatepreview' = { } } -resource backendRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' = { - name: 'backend-route' - properties: { - environment: environment - application: app.id - appId: 'backend' - } -} - resource frontend 'Applications.Core/containers@2022-03-15-privatepreview' = { name: 'frontend' properties: { application: app.id container: { image: 'radius.azurecr.io/quickstarts/dapr-frontend:edge' + env: { + CONNECTION_BACKEND_APPID: backend.name + } ports: { ui: { containerPort: 80 @@ -63,11 +56,6 @@ resource frontend 'Applications.Core/containers@2022-03-15-privatepreview' = { } } } - connections: { - backend: { - source: backendRoute.id - } - } extensions: [ { kind: 'daprSidecar' @@ -102,7 +90,7 @@ resource stateStore 'Applications.Link/daprStateStores@2022-03-15-privatepreview properties: { environment: environment application: app.id - mode: 'values' + resourceProvisioning: 'manual' type: 'state.redis' version: 'v1' metadata: { diff --git a/quickstarts/environment-variables/app.bicep b/quickstarts/environment-variables/app.bicep index 5c7d3b7e..befc496f 100644 --- a/quickstarts/environment-variables/app.bicep +++ b/quickstarts/environment-variables/app.bicep @@ -28,20 +28,11 @@ resource container 'Applications.Core/containers@2022-03-15-privatepreview' = { } } -module mongoContainerModule 'br:radius.azurecr.io/modules/mongo-container:edge' = { - name: 'mongo-container-module' -} - resource mongoLink 'Applications.Link/mongoDatabases@2022-03-15-privatepreview' = { name: 'mongo-link' properties: { environment: environment application: app.id - mode: 'values' - host: mongoContainerModule.outputs.host - port: mongoContainerModule.outputs.port - secrets: { - connectionString: mongoContainerModule.outputs.connectionString - } + // The default Recipe will run to provision the backing infrastructure } } diff --git a/reference-apps/aws/awss3.bicep b/reference-apps/aws/awss3.bicep index dafd152e..39bb8ad0 100644 --- a/reference-apps/aws/awss3.bicep +++ b/reference-apps/aws/awss3.bicep @@ -17,7 +17,6 @@ resource s3 'AWS.S3/Bucket@default' = { alias: bucket properties: { BucketName: bucket - AccessControl: 'Private' } } diff --git a/reference-apps/container-app-store/iac/app.bicep b/reference-apps/container-app-store/iac/app.bicep index 2a976c78..2c6839de 100644 --- a/reference-apps/container-app-store/iac/app.bicep +++ b/reference-apps/container-app-store/iac/app.bicep @@ -26,21 +26,11 @@ resource go_app 'Applications.Core/containers@2022-03-15-privatepreview' = { kind: 'daprSidecar' appId: 'go-app' appPort: 8050 - provides: go_app_route.id } ] } } -resource go_app_route 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' = { - name: 'go-app-route' - properties: { - application: app.id - environment: environment - appId: 'go-app' - } -} - resource node_app_route 'Applications.Core/httpRoutes@2022-03-15-privatepreview' = { name: 'node-app-route' properties: { @@ -67,8 +57,8 @@ resource node_app 'Applications.Core/containers@2022-03-15-privatepreview' = { container: { image: 'radius.azurecr.io/reference-apps/container-app-node-service:edge' env: { - ORDER_SERVICE_NAME: python_app_route.properties.appId - INVENTORY_SERVICE_NAME: go_app_route.properties.appId + ORDER_SERVICE_NAME: 'python-app' + INVENTORY_SERVICE_NAME: 'go-app' } ports: { web: { @@ -77,14 +67,6 @@ resource node_app 'Applications.Core/containers@2022-03-15-privatepreview' = { } } } - connections: { - inventory: { - source: go_app_route.id - } - orders: { - source: python_app_route.id - } - } extensions: [ { kind: 'daprSidecar' @@ -116,20 +98,11 @@ resource python_app 'Applications.Core/containers@2022-03-15-privatepreview' = { kind: 'daprSidecar' appId: 'python-app' appPort: 5000 - provides: python_app_route.id } ] } } -resource python_app_route 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' = { - name: 'python-app' - properties: { - application: app.id - environment: environment - appId: 'python-app' - } -} module infraFile 'infra-selfhosted.bicep' = { name: 'infrastructure' diff --git a/reference-apps/container-app-store/iac/infra-azure.bicep b/reference-apps/container-app-store/iac/infra-azure.bicep index c934aa9d..ac469ca3 100644 --- a/reference-apps/container-app-store/iac/infra-azure.bicep +++ b/reference-apps/container-app-store/iac/infra-azure.bicep @@ -28,8 +28,18 @@ resource statestore 'Applications.Link/daprStateStores@2022-03-15-privatepreview properties: { application: applicationId environment: environment - mode: 'resource' - resource: account::tableServices::table.id + resourceProvisioning: 'manual' + resources: [ + { id: account.id } + { id: account::tableServices::table.id } + ] + metadata: { + accountName: account.name + accountKey: account.listKeys().keys[0].value + tableName: account::tableServices::table.name + } + type: 'state.azure.tablestorage' + version: 'v1' } } diff --git a/reference-apps/container-app-store/iac/infra-selfhosted.bicep b/reference-apps/container-app-store/iac/infra-selfhosted.bicep index 115d25ae..e580bdd2 100644 --- a/reference-apps/container-app-store/iac/infra-selfhosted.bicep +++ b/reference-apps/container-app-store/iac/infra-selfhosted.bicep @@ -31,7 +31,7 @@ resource redisRoute 'Applications.Core/httpRoutes@2022-03-15-privatepreview' = { resource statestore 'Applications.Link/daprStateStores@2022-03-15-privatepreview' = { name: 'orders' properties: { - mode: 'values' + resourceProvisioning: 'manual' type: 'state.redis' application: applicationId environment: environment diff --git a/reference-apps/eshop-dapr/infra/dapr-pub-sub.bicep b/reference-apps/eshop-dapr/infra/dapr-pub-sub.bicep index 784c3c62..c9b314ea 100644 --- a/reference-apps/eshop-dapr/infra/dapr-pub-sub.bicep +++ b/reference-apps/eshop-dapr/infra/dapr-pub-sub.bicep @@ -23,6 +23,17 @@ resource serviceBus 'Microsoft.ServiceBus/namespaces@2021-06-01-preview' = { name: 'Standard' tier: 'Standard' } + + resource authorizationRule 'AuthorizationRules' = { + name: 'eshopondaprpubsub' + properties: { + rights: [ + 'Listen' + 'Send' + 'Manage' + ] + } + } } //----------------------------------------------------------------------------- @@ -35,8 +46,17 @@ resource daprPubSubBroker 'Applications.Link/daprPubSubBrokers@2022-03-15-privat properties: { application: appId environment: environment - mode: 'resource' - resource: serviceBus.id + resourceProvisioning: 'manual' + resources: [ + { + id: serviceBus.id + } + ] + type: 'pubsub.azure.servicebus.topics' + version: 'v1' + metadata: { + connectionString: serviceBus::authorizationRule.listKeys().primaryConnectionString + } } } diff --git a/reference-apps/eshop-dapr/infra/dapr-secret-store.bicep b/reference-apps/eshop-dapr/infra/dapr-secret-store.bicep index 143a8b9a..d7d24c9a 100644 --- a/reference-apps/eshop-dapr/infra/dapr-secret-store.bicep +++ b/reference-apps/eshop-dapr/infra/dapr-secret-store.bicep @@ -52,7 +52,7 @@ resource daprSecretStore 'Applications.Link/daprSecretStores@2022-03-15-privatep properties: { application: appId environment: environment - mode: 'values' + resourceProvisioning: 'manual' type: 'secretstores.azure.keyvault' version: 'v1' metadata: { diff --git a/reference-apps/eshop-dapr/infra/dapr-state-store.bicep b/reference-apps/eshop-dapr/infra/dapr-state-store.bicep index a5aff59f..ca96b912 100644 --- a/reference-apps/eshop-dapr/infra/dapr-state-store.bicep +++ b/reference-apps/eshop-dapr/infra/dapr-state-store.bicep @@ -86,7 +86,7 @@ resource daprStateStore 'Applications.Link/daprStateStores@2022-03-15-privatepre properties: { application: appId environment: environment - mode: 'values' + resourceProvisioning: 'manual' type: 'state.azure.cosmosdb' version: 'v1' metadata: { diff --git a/reference-apps/eshop-dapr/infra/sql-server.bicep b/reference-apps/eshop-dapr/infra/sql-server.bicep index 330d00ad..f02b1b9a 100644 --- a/reference-apps/eshop-dapr/infra/sql-server.bicep +++ b/reference-apps/eshop-dapr/infra/sql-server.bicep @@ -117,8 +117,15 @@ resource catalogDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview' = properties: { application: appId environment: environment - mode: 'resource' - resource: sqlServer::catalogDb.id + resourceProvisioning: 'manual' + resources: [ + { + id: sqlServer::catalogDb.id + } + ] + database: sqlServer::catalogDb.name + server: sqlServer.properties.fullyQualifiedDomainName + port: 1433 } } @@ -127,8 +134,15 @@ resource identityDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview' = properties: { application: appId environment: environment - mode: 'resource' - resource: sqlServer::identityDb.id + resourceProvisioning: 'manual' + resources: [ + { + id: sqlServer::identityDb.id + } + ] + database: sqlServer::identityDb.name + server: sqlServer.properties.fullyQualifiedDomainName + port: 1433 } } @@ -137,8 +151,15 @@ resource orderingDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview' = properties: { application: appId environment: environment - mode: 'resource' - resource: sqlServer::orderingDb.id + resourceProvisioning: 'manual' + resources: [ + { + id: sqlServer::orderingDb.id + } + ] + database: sqlServer::orderingDb.name + server: sqlServer.properties.fullyQualifiedDomainName + port: 1433 } } diff --git a/reference-apps/eshop-dapr/main.bicep b/reference-apps/eshop-dapr/main.bicep index d28b2e7a..8290e49e 100644 --- a/reference-apps/eshop-dapr/main.bicep +++ b/reference-apps/eshop-dapr/main.bicep @@ -147,7 +147,6 @@ module basketApi 'services/basket-api.bicep' = { name: '${deployment().name}-basket-api' params: { appId: eShopOnDapr.id - environment: environment.id basketApiRouteName: httpRoutes.outputs.basketApiRouteName daprPubSubBrokerName: daprPubSub.outputs.daprPubSubBrokerName daprStateStoreName: stateStore.outputs.daprStateStoreName @@ -161,7 +160,6 @@ module catalogApi 'services/catalog-api.bicep' = { name: '${deployment().name}-catalog-api' params: { appId: eShopOnDapr.id - environment: environment.id catalogApiRouteName: httpRoutes.outputs.catalogApiRouteName catalogDbName: sqlServer.outputs.catalogDbName daprPubSubBrokerName: daprPubSub.outputs.daprPubSubBrokerName @@ -175,7 +173,6 @@ module identityApi 'services/identity-api.bicep' = { name: '${deployment().name}-identity-api' params: { appId: eShopOnDapr.id - environment: environment.id daprSecretStoreName: secretStore.outputs.daprSecretStoreName identityApiRouteName: httpRoutes.outputs.identityApiRouteName identityDbName: sqlServer.outputs.identityDbName @@ -189,7 +186,6 @@ module orderingApi 'services/ordering-api.bicep' = { name: '${deployment().name}-ordering-api' params: { appId: eShopOnDapr.id - environment: environment.id daprPubSubBrokerName: daprPubSub.outputs.daprPubSubBrokerName daprSecretStoreName: secretStore.outputs.daprSecretStoreName identityApiRouteName: httpRoutes.outputs.identityApiRouteName @@ -205,7 +201,6 @@ module paymentApi 'services/payment-api.bicep' = { name: '${deployment().name}-payment-api' params: { appId: eShopOnDapr.id - environment: environment.id daprPubSubBrokerName: daprPubSub.outputs.daprPubSubBrokerName paymentApiRouteName: httpRoutes.outputs.paymentApiRouteName seqRouteName: httpRoutes.outputs.seqRouteName @@ -216,11 +211,7 @@ module webshoppingAgg 'services/webshopping-agg.bicep' = { name: '${deployment().name}-ws-agg' params: { appId: eShopOnDapr.id - environment: environment.id - basketApiDaprRouteName: basketApi.outputs.daprRouteName - catalogApiDaprRouteName: catalogApi.outputs.daprRouteName identityApiRouteName: httpRoutes.outputs.identityApiRouteName - identityApiDaprRouteName: identityApi.outputs.daprRouteName gatewayName: gateway.outputs.gatewayName seqRouteName: httpRoutes.outputs.seqRouteName webshoppingAggRouteName: httpRoutes.outputs.webshoppingAggRouteName @@ -232,9 +223,7 @@ module webshoppingGw 'services/webshopping-gw.bicep' = { params: { appId: eShopOnDapr.id catalogApiRouteName: httpRoutes.outputs.catalogApiRouteName - catalogApiDaprRouteName: catalogApi.outputs.daprRouteName orderingApiRouteName: httpRoutes.outputs.orderingApiRouteName - orderingApiDaprRouteName: orderingApi.outputs.daprRouteName webshoppingGwRouteName: httpRoutes.outputs.webshoppingGwRouteName } } @@ -243,13 +232,7 @@ module webstatus 'services/webstatus.bicep' = { name: '${deployment().name}-webstatus' params: { appId: eShopOnDapr.id - basketApiDaprRouteName: basketApi.outputs.daprRouteName blazorClientApiRouteName: httpRoutes.outputs.blazorClientRouteName - catalogApiDaprRouteName: catalogApi.outputs.daprRouteName - identityApiDaprRouteName: identityApi.outputs.daprRouteName - orderingApiDaprRouteName: orderingApi.outputs.daprRouteName - paymentApiDaprRouteName: paymentApi.outputs.daprRouteName - webshoppingAggDaprRouteName: webshoppingAgg.outputs.daprRouteName webstatusRouteName: httpRoutes.outputs.webstatusRouteName } } diff --git a/reference-apps/eshop-dapr/services/basket-api.bicep b/reference-apps/eshop-dapr/services/basket-api.bicep index e35ce6f5..c73089b5 100644 --- a/reference-apps/eshop-dapr/services/basket-api.bicep +++ b/reference-apps/eshop-dapr/services/basket-api.bicep @@ -3,9 +3,6 @@ import radius as radius @description('The Radius application ID.') param appId string -@description('The Radius environment name.') -param environment string - @description('The name of the basket API HTTP route.') param basketApiRouteName string @@ -84,7 +81,6 @@ resource basketApi 'Applications.Core/containers@2022-03-15-privatepreview' = { kind: 'daprSidecar' appId: daprAppId appPort: 80 - provides: daprRoute.id } ] connections: { @@ -104,17 +100,9 @@ resource basketApi 'Applications.Core/containers@2022-03-15-privatepreview' = { } } -resource daprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' = { - name: 'basket-api-dapr-route' - properties: { - application: appId - environment: environment - appId: daprAppId - } -} //----------------------------------------------------------------------------- // Output //----------------------------------------------------------------------------- -output daprRouteName string = daprRoute.name +output appId string = daprAppId diff --git a/reference-apps/eshop-dapr/services/catalog-api.bicep b/reference-apps/eshop-dapr/services/catalog-api.bicep index 29b10e35..f271946c 100644 --- a/reference-apps/eshop-dapr/services/catalog-api.bicep +++ b/reference-apps/eshop-dapr/services/catalog-api.bicep @@ -3,9 +3,6 @@ import radius as radius @description('The Radius application ID.') param appId string -@description('The Radius environment name.') -param environment string - @description('The name of the Catalog API HTTP route.') param catalogApiRouteName string @@ -84,7 +81,6 @@ resource catalogApi 'Applications.Core/containers@2022-03-15-privatepreview' = { kind: 'daprSidecar' appId: daprAppId appPort: 80 - provides: daprRoute.id } ] connections: { @@ -114,17 +110,8 @@ resource catalogApi 'Applications.Core/containers@2022-03-15-privatepreview' = { } } -resource daprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' = { - name: 'catalog-api-dapr-route' - properties: { - application: appId - environment: environment - appId: daprAppId - } -} - //----------------------------------------------------------------------------- // Output //----------------------------------------------------------------------------- -output daprRouteName string = daprRoute.name +output appId string = daprAppId diff --git a/reference-apps/eshop-dapr/services/identity-api.bicep b/reference-apps/eshop-dapr/services/identity-api.bicep index 2fc2747f..ad687cdb 100644 --- a/reference-apps/eshop-dapr/services/identity-api.bicep +++ b/reference-apps/eshop-dapr/services/identity-api.bicep @@ -3,9 +3,6 @@ import radius as radius @description('The Radius application ID.') param appId string -@description('The Radius environment name.') -param environment string - @secure() // Decorated with @secure() to circumvent the false positive warning to use secure parameters @description('The name of the Dapr secret store component.') param daprSecretStoreName string @@ -86,7 +83,6 @@ resource identityApi 'Applications.Core/containers@2022-03-15-privatepreview' = kind: 'daprSidecar' appId: daprAppId appPort: 80 - provides: daprRoute.id } ] connections: { @@ -113,17 +109,8 @@ resource identityApi 'Applications.Core/containers@2022-03-15-privatepreview' = } } -resource daprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' = { - name: 'identity-api-dapr-route' - properties: { - application: appId - environment: environment - appId: daprAppId - } -} - //----------------------------------------------------------------------------- // Output //----------------------------------------------------------------------------- -output daprRouteName string = daprRoute.name +output appId string = daprAppId diff --git a/reference-apps/eshop-dapr/services/ordering-api.bicep b/reference-apps/eshop-dapr/services/ordering-api.bicep index a67f66d9..9d5e9ef4 100644 --- a/reference-apps/eshop-dapr/services/ordering-api.bicep +++ b/reference-apps/eshop-dapr/services/ordering-api.bicep @@ -3,9 +3,6 @@ import radius as radius @description('The Radius application ID.') param appId string -@description('The Radius environment name.') -param environment string - @description('The name of the Dapr pub/sub component.') param daprPubSubBrokerName string @@ -101,7 +98,6 @@ resource orderingApi 'Applications.Core/containers@2022-03-15-privatepreview' = kind: 'daprSidecar' appId: daprAppId appPort: 80 - provides: daprRoute.id } ] connections: { @@ -134,18 +130,9 @@ resource orderingApi 'Applications.Core/containers@2022-03-15-privatepreview' = } } -resource daprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' = { - name: 'ordering-api-dapr-route' - properties: { - application: appId - environment: environment - appId: daprAppId - } -} - //----------------------------------------------------------------------------- // Output //----------------------------------------------------------------------------- -output daprRouteName string = daprRoute.name +output appId string = daprAppId diff --git a/reference-apps/eshop-dapr/services/payment-api.bicep b/reference-apps/eshop-dapr/services/payment-api.bicep index 6b26acad..00e90f79 100644 --- a/reference-apps/eshop-dapr/services/payment-api.bicep +++ b/reference-apps/eshop-dapr/services/payment-api.bicep @@ -3,9 +3,6 @@ import radius as radius @description('The Radius application ID.') param appId string -@description('The Radius environment name.') -param environment string - @description('The name of the Payment API HTTP route.') param paymentApiRouteName string @@ -61,7 +58,6 @@ resource paymentApi 'Applications.Core/containers@2022-03-15-privatepreview' = { kind: 'daprSidecar' appId: daprAppId appPort: 80 - provides: daprRoute.id } ] connections: { @@ -75,18 +71,9 @@ resource paymentApi 'Applications.Core/containers@2022-03-15-privatepreview' = { } } -resource daprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' = { - name: 'payment-api-dapr-route' - properties: { - application: appId - environment: environment - appId: daprAppId - } -} - //----------------------------------------------------------------------------- // Output //----------------------------------------------------------------------------- -output daprRouteName string = daprRoute.name +output appId string = appId output workloadIdentityId string = paymentApi.properties.identity.resource diff --git a/reference-apps/eshop-dapr/services/webshopping-agg.bicep b/reference-apps/eshop-dapr/services/webshopping-agg.bicep index 0ddcdb46..fdbd2e1e 100644 --- a/reference-apps/eshop-dapr/services/webshopping-agg.bicep +++ b/reference-apps/eshop-dapr/services/webshopping-agg.bicep @@ -3,24 +3,12 @@ import radius as radius @description('The Radius application ID.') param appId string -@description('The Radius environment name.') -param environment string - -@description('The name of the basket API Dapr route.') -param basketApiDaprRouteName string - -@description('The name of the Catalog API Dapr route.') -param catalogApiDaprRouteName string - @description('The name of the Radius gateway.') param gatewayName string @description('The name of the Identity API HTTP route.') param identityApiRouteName string -@description('The name of the Identity API Dapr route.') -param identityApiDaprRouteName string - @description('The name of the Seq HTTP route.') param seqRouteName string @@ -34,14 +22,6 @@ var daprAppId = 'webshoppingagg' // Get references to existing resources //----------------------------------------------------------------------------- -resource basketApiDaprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' existing = { - name: basketApiDaprRouteName -} - -resource catalogApiDaprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' existing = { - name: catalogApiDaprRouteName -} - resource gateway 'Applications.Core/gateways@2022-03-15-privatepreview' existing = { name: gatewayName } @@ -49,11 +29,6 @@ resource gateway 'Applications.Core/gateways@2022-03-15-privatepreview' existing resource identityApiRoute 'Applications.Core/httpRoutes@2022-03-15-privatepreview' existing = { name: identityApiRouteName } - -resource identityApiDaprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' existing = { - name: identityApiDaprRouteName -} - resource seqRoute 'Applications.Core/httpRoutes@2022-03-15-privatepreview' existing = { name: seqRouteName } @@ -94,22 +69,12 @@ resource webshoppingAgg 'Applications.Core/containers@2022-03-15-privatepreview' kind: 'daprSidecar' appId: daprAppId appPort: 80 - provides: daprRoute.id } ] connections: { - basketApiDaprRoute: { - source: basketApiDaprRoute.id - } - catalogApiDaprRoute: { - source: catalogApiDaprRoute.id - } identityApi: { source: identityApiRoute.id } - identityApiDaprRoute: { - source: identityApiDaprRoute.id - } seq: { source: seqRoute.id } @@ -117,17 +82,8 @@ resource webshoppingAgg 'Applications.Core/containers@2022-03-15-privatepreview' } } -resource daprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' = { - name: 'webshopping-agg-dapr-route' - properties: { - application: appId - environment: environment - appId: daprAppId - } -} - //----------------------------------------------------------------------------- // Output //----------------------------------------------------------------------------- -output daprRouteName string = daprRoute.name +output appId string = daprAppId diff --git a/reference-apps/eshop-dapr/services/webshopping-gw.bicep b/reference-apps/eshop-dapr/services/webshopping-gw.bicep index fd2c18e5..fdc4e99d 100644 --- a/reference-apps/eshop-dapr/services/webshopping-gw.bicep +++ b/reference-apps/eshop-dapr/services/webshopping-gw.bicep @@ -3,9 +3,7 @@ import radius as radius param appId string param catalogApiRouteName string -param catalogApiDaprRouteName string param orderingApiRouteName string -param orderingApiDaprRouteName string param webshoppingGwRouteName string var daprAppId = 'webshoppingapigw' @@ -14,18 +12,10 @@ resource catalogApiRoute 'Applications.Core/httpRoutes@2022-03-15-privatepreview name: catalogApiRouteName } -resource catalogApiDaprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' existing = { - name: catalogApiDaprRouteName -} - resource orderingApiRoute 'Applications.Core/httpRoutes@2022-03-15-privatepreview' existing = { name: orderingApiRouteName } -resource orderingApiDaprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' existing = { - name: orderingApiDaprRouteName -} - resource webshoppingGwRoute 'Applications.Core/httproutes@2022-03-15-privatepreview' existing = { name: webshoppingGwRouteName } @@ -60,15 +50,9 @@ resource webshoppingGw 'Applications.Core/containers@2022-03-15-privatepreview' catalogApi: { source: catalogApiRoute.id } - catalogApiDapr: { - source: catalogApiDaprRoute.id - } orderingApi: { source: orderingApiRoute.id } - orderingApiDapr: { - source: orderingApiDaprRoute.id - } } } } diff --git a/reference-apps/eshop-dapr/services/webstatus.bicep b/reference-apps/eshop-dapr/services/webstatus.bicep index 50c72bc4..af56868a 100644 --- a/reference-apps/eshop-dapr/services/webstatus.bicep +++ b/reference-apps/eshop-dapr/services/webstatus.bicep @@ -3,27 +3,9 @@ import radius as radius @description('The Radius application ID.') param appId string -@description('The name of the basket API Dapr route.') -param basketApiDaprRouteName string - @description('The name of the Blazor Client API HTTP route.') param blazorClientApiRouteName string -@description('The name of the Catalog API Dapr route.') -param catalogApiDaprRouteName string - -@description('The name of the Identity API Dapr route.') -param identityApiDaprRouteName string - -@description('The name of the Catalog API Dapr route.') -param orderingApiDaprRouteName string - -@description('The name of the Ordering API Dapr route.') -param paymentApiDaprRouteName string - -@description('The name of the Web Shopping Aggregator API Dapr route.') -param webshoppingAggDaprRouteName string - @description('The name of the webstatus API HTTP route.') param webstatusRouteName string @@ -34,34 +16,10 @@ var daprAppId = 'webstatus' // Get references to existing resources //----------------------------------------------------------------------------- -resource basketApiDaprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' existing = { - name: basketApiDaprRouteName -} - resource blazorClientApiRoute 'Applications.Core/httpRoutes@2022-03-15-privatepreview' existing = { name: blazorClientApiRouteName } -resource catalogApiDaprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' existing = { - name: catalogApiDaprRouteName -} - -resource identityApiDaprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' existing = { - name: identityApiDaprRouteName -} - -resource orderingApiDaprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' existing = { - name: orderingApiDaprRouteName -} - -resource paymentApiDaprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' existing = { - name: paymentApiDaprRouteName -} - -resource webshoppingAggDaprRoute 'Applications.Link/daprInvokeHttpRoutes@2022-03-15-privatepreview' existing = { - name: webshoppingAggDaprRouteName -} - resource webstatusRoute 'Applications.Core/httproutes@2022-03-15-privatepreview' existing = { name: webstatusRouteName } @@ -113,24 +71,6 @@ resource webstatus 'Applications.Core/containers@2022-03-15-privatepreview' = { blazorClient: { source: blazorClientApiRoute.id } - basketApiDaprRoute: { - source: basketApiDaprRoute.id - } - catalogApiDaprRoute: { - source: catalogApiDaprRoute.id - } - identityApiDaprRoute: { - source: identityApiDaprRoute.id - } - orderingApiDaprRoute: { - source: orderingApiDaprRoute.id - } - paymentApiDaprRoute: { - source: paymentApiDaprRoute.id - } - webshoppingAggDaprRoute: { - source: webshoppingAggDaprRoute.id - } } } } diff --git a/reference-apps/eshop/iac/eshop.bicep b/reference-apps/eshop/iac/eshop.bicep index 3f7ba76b..aec6fb5b 100644 --- a/reference-apps/eshop/iac/eshop.bicep +++ b/reference-apps/eshop/iac/eshop.bicep @@ -141,8 +141,6 @@ module basket 'services/basket.bicep' = { module catalog 'services/catalog.bicep' = { name: 'catalog' params: { - adminLogin: adminLogin - adminPassword: adminPassword application: eshop.id APPLICATION_INSIGHTS_KEY: APPLICATION_INSIGHTS_KEY AZURESERVICEBUSENABLED: AZURESERVICEBUSENABLED @@ -161,8 +159,6 @@ module catalog 'services/catalog.bicep' = { module identity 'services/identity.bicep' = { name: 'identity' params: { - adminLogin: adminLogin - adminPassword: adminPassword application: eshop.id APPLICATION_INSIGHTS_KEY: APPLICATION_INSIGHTS_KEY basketHttpName: networking.outputs.basketHttp @@ -183,8 +179,6 @@ module identity 'services/identity.bicep' = { module ordering 'services/ordering.bicep' = { name: 'ordering' params: { - adminLogin: adminLogin - adminPassword: adminPassword application: eshop.id APPLICATION_INSIGHTS_KEY: APPLICATION_INSIGHTS_KEY AZURESERVICEBUSENABLED: AZURESERVICEBUSENABLED @@ -248,8 +242,6 @@ module web 'services/web.bicep' = { module webhooks 'services/webhooks.bicep' = { name: 'webhooks' params: { - adminLogin: adminLogin - adminPassword: adminPassword application: eshop.id AZURESERVICEBUSENABLED: AZURESERVICEBUSENABLED gatewayName: networking.outputs.gateway diff --git a/reference-apps/eshop/iac/infra/aws.bicep b/reference-apps/eshop/iac/infra/aws.bicep index 4800174d..0c208a99 100644 --- a/reference-apps/eshop/iac/infra/aws.bicep +++ b/reference-apps/eshop/iac/infra/aws.bicep @@ -197,9 +197,15 @@ resource sqlIdentityDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview properties: { application: application environment: environment - mode: 'values' + resourceProvisioning: 'manual' database: 'IdentityDb' server: identityDb.properties.Endpoint.Address + port: int(identityDb.properties.Endpoint.Port) + username: adminLogin + secrets: { + password: adminPassword + connectionString: 'Server=tcp:${identityDb.properties.Endpoint.Address},${identityDb.properties.Endpoint.Port};Initial Catalog=IdentityDb;User Id=${adminLogin};Password=${adminPassword};Encrypt=false' + } } } @@ -208,9 +214,15 @@ resource sqlCatalogDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview' properties: { application: application environment: environment - mode: 'values' + resourceProvisioning: 'manual' database: 'CatalogDb' server: catalogDb.properties.Endpoint.Address + port: int(catalogDb.properties.Endpoint.Port) + username: adminLogin + secrets: { + password: adminPassword + connectionString: 'Server=tcp:${catalogDb.properties.Endpoint.Address},${catalogDb.properties.Endpoint.Port};Initial Catalog=CatalogDb;User Id=${adminLogin};Password=${adminPassword};Encrypt=false' + } } } @@ -219,9 +231,15 @@ resource sqlOrderingDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview properties: { application: application environment: environment - mode: 'values' + resourceProvisioning: 'manual' database: 'OrderingDb' server: orderingDb.properties.Endpoint.Address + port: int(orderingDb.properties.Endpoint.Port) + username: adminLogin + secrets: { + password: adminPassword + connectionString: 'Server=tcp:${orderingDb.properties.Endpoint.Address},${orderingDb.properties.Endpoint.Port};Initial Catalog=OrderingDb;User Id=${adminLogin};Password=${adminPassword};Encrypt=false' + } } } @@ -230,9 +248,15 @@ resource sqlWebhooksDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview properties: { application: application environment: environment - mode: 'values' + resourceProvisioning: 'manual' database: 'WebhooksDb' server: webhooksDb.properties.Endpoint.Address + port: int(webhooksDb.properties.Endpoint.Port) + username: adminLogin + secrets: { + password: adminPassword + connectionString: 'Server=tcp:${webhooksDb.properties.Endpoint.Address},${webhooksDb.properties.Endpoint.Port};Initial Catalog=WebhooksDb;User Id=${adminLogin};Password=${adminPassword};Encrypt=false' + } } } @@ -269,7 +293,7 @@ resource rabbitmq 'Applications.Link/rabbitmqMessageQueues@2022-03-15-privatepre properties: { application: application environment: environment - mode: 'values' + resourceProvisioning: 'manual' queue: 'eshop-event-bus' secrets: { connectionString: rabbitmqRoute.properties.hostname diff --git a/reference-apps/eshop/iac/infra/azure.bicep b/reference-apps/eshop/iac/infra/azure.bicep index 8307b098..fc1fe5e2 100644 --- a/reference-apps/eshop/iac/infra/azure.bicep +++ b/reference-apps/eshop/iac/infra/azure.bicep @@ -17,6 +17,8 @@ param adminLogin string @secure() param adminPassword string +var sqlPort = 1433 + // Infrastructure ------------------------------------------------------------ // TODO: Move the infrastructure into Recipes @@ -242,7 +244,7 @@ resource rabbitmq 'Applications.Link/rabbitmqMessageQueues@2022-03-15-privatepre properties: { application: application environment: environment - mode: 'values' + resourceProvisioning: 'manual' queue: 'eshop-event-bus' secrets: { connectionString: 'test' @@ -255,8 +257,20 @@ resource sqlIdentityDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview properties: { application: application environment: environment - mode: 'resource' - resource: sql::identityDb.id + resourceProvisioning: 'manual' + database: sql::identityDb.name + server: sql.properties.fullyQualifiedDomainName + port: sqlPort + username: adminLogin + secrets: { + password: adminPassword + connectionString: 'Server=tcp:${sql.properties.fullyQualifiedDomainName},${sqlPort};Initial Catalog=${sql::identityDb.name};User Id=${adminLogin};Password=${adminPassword};Encrypt=false' + } + resources: [ + { + id: sql::identityDb.id + } + ] } } @@ -265,8 +279,20 @@ resource sqlCatalogDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview' properties: { application: application environment: environment - mode: 'resource' - resource: sql::catalogDb.id + resourceProvisioning: 'manual' + database: sql::catalogDb.name + server: sql.properties.fullyQualifiedDomainName + port: sqlPort + username: adminLogin + secrets: { + password: adminPassword + connectionString: 'Server=tcp:${sql.properties.fullyQualifiedDomainName},${sqlPort};Initial Catalog=${sql::catalogDb.name};User Id=${adminLogin};Password=${adminPassword};Encrypt=false' + } + resources: [ + { + id: sql::catalogDb.id + } + ] } } @@ -275,8 +301,20 @@ resource sqlOrderingDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview properties: { application: application environment: environment - mode: 'resource' - resource: sql::orderingDb.id + resourceProvisioning: 'manual' + database: sql::orderingDb.name + server: sql.properties.fullyQualifiedDomainName + port: sqlPort + username: adminLogin + secrets: { + password: adminPassword + connectionString: 'Server=tcp:${sql.properties.fullyQualifiedDomainName},${sqlPort};Initial Catalog=${sql::orderingDb.name};User Id=${adminLogin};Password=${adminPassword};Encrypt=false' + } + resources: [ + { + id: sql::orderingDb.id + } + ] } } @@ -285,8 +323,20 @@ resource sqlWebhooksDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview properties: { application: application environment: environment - mode: 'resource' - resource: sql::webhooksDb.id + resourceProvisioning: 'manual' + database: sql::webhooksDb.name + server: sql.properties.fullyQualifiedDomainName + port: sqlPort + username: adminLogin + secrets: { + password: adminPassword + connectionString: 'Server=tcp:${sql.properties.fullyQualifiedDomainName},${sqlPort};Initial Catalog=${sql::webhooksDb.name};User Id=${adminLogin};Password=${adminPassword};Encrypt=false' + } + resources: [ + { + id: sql::webhooksDb.id + } + ] } } diff --git a/reference-apps/eshop/iac/infra/containers.bicep b/reference-apps/eshop/iac/infra/containers.bicep index f9578577..52c493f5 100644 --- a/reference-apps/eshop/iac/infra/containers.bicep +++ b/reference-apps/eshop/iac/infra/containers.bicep @@ -10,6 +10,8 @@ param application string @secure() param adminPassword string +var adminUsername = 'sa' + // Infrastructure ------------------------------------------------- resource rabbitmqContainer 'Applications.Core/containers@2022-03-15-privatepreview' = { @@ -210,7 +212,7 @@ resource rabbitmq 'Applications.Link/rabbitmqMessageQueues@2022-03-15-privatepre properties: { application: application environment: environment - mode: 'values' + resourceProvisioning: 'manual' queue: 'eshop-event-bus' secrets: { connectionString: rabbitmqRoute.properties.hostname @@ -223,9 +225,15 @@ resource sqlIdentityDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview properties: { application: application environment: environment - mode: 'values' + resourceProvisioning: 'manual' server: sqlIdentityRoute.properties.hostname database: 'IdentityDb' + port: sqlIdentityRoute.properties.port + username: adminUsername + secrets: { + password: adminPassword + connectionString: 'Server=tcp:${sqlIdentityRoute.properties.hostname},${sqlIdentityRoute.properties.port};Initial Catalog=IdentityDb;User Id=${adminUsername};Password=${adminPassword};Encrypt=false' + } } } @@ -234,9 +242,15 @@ resource sqlCatalogDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview' properties: { application: application environment: environment - mode: 'values' + resourceProvisioning: 'manual' server: sqlCatalogRoute.properties.hostname database: 'CatalogDb' + port: sqlCatalogRoute.properties.port + username: adminUsername + secrets: { + password: adminPassword + connectionString: 'Server=tcp:${sqlCatalogRoute.properties.hostname},${sqlCatalogRoute.properties.port};Initial Catalog=CatalogDb;User Id=${adminUsername};Password=${adminPassword};Encrypt=false' + } } } @@ -245,9 +259,15 @@ resource sqlOrderingDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview properties: { application: application environment: environment - mode: 'values' + resourceProvisioning: 'manual' server: sqlOrderingRoute.properties.hostname database: 'OrderingDb' + port: sqlOrderingRoute.properties.port + username: adminUsername + secrets: { + password: adminPassword + connectionString: 'Server=tcp:${sqlOrderingRoute.properties.hostname},${sqlOrderingRoute.properties.port};Initial Catalog=OrderingDb;User Id=${adminUsername};Password=${adminPassword};Encrypt=false' + } } } @@ -256,9 +276,15 @@ resource sqlWebhooksDb 'Applications.Link/sqlDatabases@2022-03-15-privatepreview properties: { application: application environment: environment - mode: 'values' + resourceProvisioning: 'manual' server: sqlWebhooksRoute.properties.hostname database: 'WebhooksDb' + port: sqlWebhooksRoute.properties.port + username: adminUsername + secrets: { + password: adminPassword + connectionString: 'Server=tcp:${sqlWebhooksRoute.properties.hostname},${sqlWebhooksRoute.properties.port};Initial Catalog=WebhooksDb;User Id=${adminUsername};Password=${adminPassword};Encrypt=false' + } } } diff --git a/reference-apps/eshop/iac/services/catalog.bicep b/reference-apps/eshop/iac/services/catalog.bicep index c0d98d12..930f8866 100644 --- a/reference-apps/eshop/iac/services/catalog.bicep +++ b/reference-apps/eshop/iac/services/catalog.bicep @@ -31,13 +31,6 @@ param AZURESERVICEBUSENABLED string @description('Cotnainer image tag to use for eshop images') param TAG string -@description('SQL administrator username') -param adminLogin string - -@description('SQL administrator password') -@secure() -param adminPassword string - @description('Name of the Gateway') param gatewayName string @@ -80,7 +73,7 @@ resource catalog 'Applications.Core/containers@2022-03-15-privatepreview' = { AzureStorageEnabled: AZURESTORAGEENABLED ApplicationInsights__InstrumentationKey: APPLICATION_INSIGHTS_KEY AzureServiceBusEnabled: AZURESERVICEBUSENABLED - ConnectionString: 'Server=tcp:${sqlCatalogDb.properties.server},1433;Initial Catalog=${sqlCatalogDb.properties.database};User Id=${adminLogin};Password=${adminPassword};Encrypt=false' + ConnectionString: sqlCatalogDb.connectionString() EventBusConnection: (AZURESERVICEBUSENABLED == 'True') ? serviceBusConnectionString : rabbitmq.connectionString() } ports: { diff --git a/reference-apps/eshop/iac/services/identity.bicep b/reference-apps/eshop/iac/services/identity.bicep index f87ff7e3..a4cd2c4a 100644 --- a/reference-apps/eshop/iac/services/identity.bicep +++ b/reference-apps/eshop/iac/services/identity.bicep @@ -18,13 +18,6 @@ param ENABLEDEVSPACES string @description('Cotnainer image tag to use for eshop images. Defaults to linux-dotnet7') param TAG string -@description('SQL administrator username') -param adminLogin string - -@description('SQL administrator password') -@secure() -param adminPassword string - @description('Name of the Gateway') param gatewayName string @@ -74,7 +67,7 @@ resource identity 'Applications.Core/containers@2022-03-15-privatepreview' = { ApplicationInsights__InstrumentationKey: APPLICATION_INSIGHTS_KEY XamarinCallback: '' EnableDevspaces: ENABLEDEVSPACES - ConnectionString: 'Server=tcp:${sqlIdentityDb.properties.server},1433;Initial Catalog=${sqlIdentityDb.properties.database};User Id=${adminLogin};Password=${adminPassword};Encrypt=false' + ConnectionString: sqlIdentityDb.connectionString() MvcClient: '${gateway.properties.url}/${webmvcHttp.properties.hostname}' SpaClient: gateway.properties.url BasketApiClient: '${gateway.properties.url}/${basketHttp.properties.hostname}' diff --git a/reference-apps/eshop/iac/services/ordering.bicep b/reference-apps/eshop/iac/services/ordering.bicep index 0aae92e2..dbeef5ea 100644 --- a/reference-apps/eshop/iac/services/ordering.bicep +++ b/reference-apps/eshop/iac/services/ordering.bicep @@ -24,13 +24,6 @@ param AZURESERVICEBUSENABLED string @description('Cotnainer image tag to use for eshop images') param TAG string -@description('SQL administrator username') -param adminLogin string - -@description('SQL administrator password') -@secure() -param adminPassword string - @description('Name of the Gateway') param gatewayName string @@ -91,7 +84,7 @@ resource ordering 'Applications.Core/containers@2022-03-15-privatepreview' = { PATH_BASE: '/ordering-api' GRPC_PORT: '81' PORT: '80' - ConnectionString: 'Server=tcp:${sqlOrderingDb.properties.server},1433;Initial Catalog=${sqlOrderingDb.properties.database};User Id=${adminLogin};Password=${adminPassword};Encrypt=false' + ConnectionString: sqlOrderingDb.connectionString() EventBusConnection: (AZURESERVICEBUSENABLED == 'True') ? serviceBusConnectionString : rabbitmq.connectionString() identityUrl: identityHttp.properties.url IdentityUrlExternal: '${gateway.properties.url}/${identityHttp.properties.hostname}' @@ -138,7 +131,7 @@ resource orderbgtasks 'Applications.Core/containers@2022-03-15-privatepreview' = 'Serilog__MinimumLevel__Override__Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ': 'Verbose' OrchestratorType: ORCHESTRATOR_TYPE AzureServiceBusEnabled: AZURESERVICEBUSENABLED - ConnectionString: 'Server=tcp:${sqlOrderingDb.properties.server},1433;Initial Catalog=${sqlOrderingDb.properties.database};User Id=${adminLogin};Password=${adminPassword};Encrypt=false' + ConnectionString: sqlOrderingDb.connectionString() EventBusConnection: (AZURESERVICEBUSENABLED == 'True') ? serviceBusConnectionString : rabbitmq.connectionString() } ports: { diff --git a/reference-apps/eshop/iac/services/webhooks.bicep b/reference-apps/eshop/iac/services/webhooks.bicep index c824ff1b..4cd71ad0 100644 --- a/reference-apps/eshop/iac/services/webhooks.bicep +++ b/reference-apps/eshop/iac/services/webhooks.bicep @@ -21,13 +21,6 @@ param AZURESERVICEBUSENABLED string @description('Cotnainer image tag to use for eshop images. Defaults to linux-dotnet7') param TAG string -@description('SQL administrator username') -param adminLogin string - -@description('SQL administrator password') -@secure() -param adminPassword string - @description('Name of the Gateway') param gatewayName string @@ -65,7 +58,7 @@ resource webhooks 'Applications.Core/containers@2022-03-15-privatepreview' = { ASPNETCORE_URLS: 'http://0.0.0.0:80' OrchestratorType: ORCHESTRATOR_TYPE AzureServiceBusEnabled: AZURESERVICEBUSENABLED - ConnectionString: 'Server=tcp:${sqlWebhooksDb.properties.server},1433;Initial Catalog=${sqlWebhooksDb.properties.database};User Id=${adminLogin};Password=${adminPassword};Encrypt=false' + ConnectionString: sqlWebhooksDb.connectionString() EventBusConnection: (AZURESERVICEBUSENABLED == 'True') ? serviceBusConnectionString : rabbitmq.connectionString() identityUrl: identityHttp.properties.url IdentityUrlExternal: '${gateway.properties.url}/${identityHttp.properties.hostname}' diff --git a/ui-tests/.gitignore b/ui-tests/.gitignore new file mode 100644 index 00000000..75e854d8 --- /dev/null +++ b/ui-tests/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +/test-results/ +/playwright-report/ +/playwright/.cache/ diff --git a/ui-tests/package-lock.json b/ui-tests/package-lock.json new file mode 100644 index 00000000..fb5b6ee4 --- /dev/null +++ b/ui-tests/package-lock.json @@ -0,0 +1,78 @@ +{ + "name": "ui-tests", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ui-tests", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "uuid": "^9.0.0" + }, + "devDependencies": { + "@playwright/test": "^1.35.0" + } + }, + "node_modules/@playwright/test": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.35.0.tgz", + "integrity": "sha512-6qXdd5edCBynOwsz1YcNfgX8tNWeuS9fxy5o59D0rvHXxRtjXRebB4gE4vFVfEMXl/z8zTnAzfOs7aQDEs8G4Q==", + "dev": true, + "dependencies": { + "@types/node": "*", + "playwright-core": "1.35.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/@types/node": { + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.0.tgz", + "integrity": "sha512-cumHmIAf6On83X7yP+LrsEyUOf/YlociZelmpRYaGFydoaPdxdt80MAbu6vWerQT2COCp2nPvHdsbD7tHn/YlQ==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright-core": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.35.0.tgz", + "integrity": "sha512-muMXyPmIx/2DPrCHOD1H1ePT01o7OdKxKj2ebmCAYvqhUy+Y1bpal7B0rdoxros7YrXI294JT/DWw2LqyiqTPA==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + } + } +} diff --git a/ui-tests/package.json b/ui-tests/package.json new file mode 100644 index 00000000..178df5ea --- /dev/null +++ b/ui-tests/package.json @@ -0,0 +1,16 @@ +{ + "name": "ui-tests", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": {}, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@playwright/test": "^1.35.0" + }, + "dependencies": { + "uuid": "^9.0.0" + } +} diff --git a/ui-tests/playwright.config.ts b/ui-tests/playwright.config.ts new file mode 100644 index 00000000..e2b6772b --- /dev/null +++ b/ui-tests/playwright.config.ts @@ -0,0 +1,50 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './tests', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + // baseURL: 'http://127.0.0.1:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + ], +}); diff --git a/ui-tests/tests/demo.app.spec.ts b/ui-tests/tests/demo.app.spec.ts new file mode 100644 index 00000000..9e786ff7 --- /dev/null +++ b/ui-tests/tests/demo.app.spec.ts @@ -0,0 +1,111 @@ +import { test, expect } from "@playwright/test"; +import { v4 as uuidv4 } from "uuid"; + +test("To-Do App Basic UI Checks", async ({ page }) => { + // Listen for all console events and handle errors + page.on('console', msg => { + if (msg.type() === 'error') { + console.log(`Error text: "${msg.text()}"`); + } + }); + + // Go to http://localhost:3000/ + await page.goto("http://localhost:3000/"); + + // Expect page to have proper URL + expect(page).toHaveURL("http://localhost:3000/"); + + // Expect page to have proper title + expect(page).toHaveTitle("Radius Demo"); + + // Make sure the tabs are visible + await expect(page.getByRole("link", { name: "Radius Demo" })) + .toBeVisible(); + await expect(page.getByRole("link", { name: "Container Info" })) + .toBeVisible(); + await expect(page.getByRole("link", { name: "Todo List" })) + .toBeVisible(); + + // Make sure the tabs are clickable + await page.getByRole("link", { name: "Radius Demo" }) + .click(); + await page.getByRole("link", { name: "Container Info" }) + .click(); + await page.getByRole("link", { name: "Todo List" }) + .click(); + + // Go back to Main Page + await page.getByRole("link", { name: "Radius Demo" }) + .click(); + + // Make sure important environment variables are visible + await expect(page.getByText("CONNECTION_REDIS_CONNECTIONSTRING")) + .toBeVisible(); + await expect(page.getByText("CONNECTION_REDIS_HOST")) + .toBeVisible(); + await expect(page.getByText("CONNECTION_REDIS_PORT")) + .toBeVisible(); +}); + +test("Add an item and check basic functionality", async ({ page }) => { + await page.goto("http://localhost:3000/"); + // Go to Todo List Page + await page.getByRole("link", { name: "Todo List" }).click(); + + // Make sure the input is visible + await expect(page.getByPlaceholder("What do you need to do?")) + .toBeVisible(); + + // Add a todo item + const todoItem = `Test Item ${uuidv4()}`; + await page.getByPlaceholder("What do you need to do?") + .fill(todoItem); + await page.getByRole("button", { name: "Add send" }) + .click(); + + // Make sure the todo item is visible now + await expect(page.getByRole("cell", { name: todoItem })) + .toBeVisible(); + + // Complete a todo item + + // At first we expect a lightbulb icon in the status column for the given todo item + await expect(page.getByRole("row", { name: `${todoItem} lightbulb` })) + .toBeVisible(); + + // Then we expect to have a Complete button for the given todo item + await expect(page + .getByRole("row", { + name: `${todoItem} lightbulb Complete done Delete delete`, + }) + .getByRole("button", { name: "Complete done" })) + .toBeVisible(); + + // We click the Complete button + await page + .getByRole("row", { + name: `${todoItem} lightbulb Complete done Delete delete`, + }) + .getByRole("button", { name: "Complete done" }) + .click(); + + // Now we expect a checkmark icon represented as `done` in the status column for the given todo item + await expect(page + .getByRole("row", { + name: `${todoItem} done Complete done Delete delete`, + }) + .getByRole("button", { name: "Complete done" })) + .toBeVisible(); + + // Delete a todo item + await page + .getByRole("row", { + name: `${todoItem} done Complete done Delete delete`, + }) + .getByRole("button", { name: "Delete delete" }) + .click(); + + // Make sure the todo item is not visible now + await expect(page.getByRole("cell", { name: todoItem })) + .not.toBeVisible(); +}); diff --git a/ui-tests/tests/eshop/container.app.spec.ts b/ui-tests/tests/eshop/container.app.spec.ts new file mode 100644 index 00000000..0da587ed --- /dev/null +++ b/ui-tests/tests/eshop/container.app.spec.ts @@ -0,0 +1,98 @@ +import { test, expect } from "@playwright/test"; + +test("eShop on Containers App Basic UI and Functionality Checks", async ({ page }) => { + // Listen for all console events and handle errors + page.on('console', msg => { + if (msg.type() === 'error') { + console.log(`Error text: "${msg.text()}"`); + } + }); + + // Go to http://localhost + await page.goto("http://localhost"); + + // Expect page to have proper URL + expect(page).toHaveURL("http://localhost/catalog"); + + // Expect page to have proper title + expect(page).toHaveTitle("eShopOnContainers - SPA"); + + // Check for the LOGIN button + await expect(page.getByText("LOGIN")) + .toBeVisible(); + + // Click on the LOGIN button + await page.getByText("LOGIN").click(); + + // Expect page to have proper title + expect(page).toHaveTitle("eShopOnContainers - Identity"); + + // Fill in the username and password + expect(page.getByPlaceholder('Username')) + .toBeVisible(); + await page.getByPlaceholder('Username') + .click(); + await page.getByPlaceholder('Username') + .fill('alice'); + + expect(page.getByPlaceholder('Password')) + .toBeVisible(); + await page.getByPlaceholder('Password') + .click(); + await page.getByPlaceholder('Password') + .fill('Pass123$'); + + // Click on the LOGIN button + await page.getByRole('button', { name: 'Login' }) + .click(); + + // After login, expect to be redirected to the catalog page + // Expect page to have proper URL + expect(page).toHaveURL("http://localhost/catalog"); + + // Expect page to have proper title + expect(page).toHaveTitle("eShopOnContainers - SPA"); + + // Logged user details should be visible + expect(page.getByText('AliceSmith@email.com')) + .toBeVisible(); + + // Click on the user details + await page.getByText('AliceSmith@email.com').click(); + + // Check dropdown menu + expect(page.getByText('My orders')) + .toBeVisible(); + expect(page.getByText('Log Out')) + .toBeVisible(); + + let numberOfItemsAdded = 0; + // Add an item to the cart + await page.locator('div:nth-child(2) > .esh-catalog-item > .esh-catalog-thumbnail-wrapper > .esh-catalog-thumbnail-icon > .esh-catalog-thumbnail-icon-svg') + .click(); + numberOfItemsAdded++; + + // Go to the cart + await page.getByRole('link', { name: `${numberOfItemsAdded}` }) + .click(); + + // Expect page to have proper URL + expect(page).toHaveURL("http://localhost/basket"); + + // Checkout + await page.getByRole('button', { name: 'Checkout' }) + .click(); + + // Place the order + await page.getByRole('button', { name: 'Place Order' }) + .click(); + + // Continue Shopping + await page.getByRole('link', { name: 'Continue Shopping' }) + .click(); + + // Logout + await page.locator('div').filter({ hasText: 'Log Out' }) + .nth(0) + .click(); +});