Skip to content

E2E test

E2E test #22790

Workflow file for this run

name: E2E test
on:
workflow_dispatch:
inputs:
cases:
description: 'specific cases to be excuted. Sample: ["./aad/a.tests.ts", "./bot/b.tests.ts"]. Set empty to run all cases'
required: false
target-testplan-id:
description: "target testplan id: 24569079. If not set, will not archive ado testplan"
required: false
type: string
target-version:
description: "target TTK version. Sample: 5.0.2-alpha.2fdf2b99b.0, 5.0.2-rc.0"
required: false
type: string
schedule:
- cron: "0 22 * * *"
pull_request_target:
jobs:
setup:
if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == 'teamsfx-bot/TeamsFx') }}
runs-on: ubuntu-latest
outputs:
cases: ${{ steps.schedule-cases.outputs.cases || steps.dispatch-cases.outputs.cases || steps.pr-cases.outputs.cases }}
env:
AZURE_ACCOUNT_NAME: ${{ secrets.TEST_USER_NAME }}
AZURE_ACCOUNT_OBJECT_ID: ${{ secrets.TEST_USER_OBJECT_ID }}
AZURE_ACCOUNT_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
AZURE_SUBSCRIPTION_ID: ${{ secrets.TEST_SUBSCRIPTION_ID }}
AZURE_TENANT_ID: ${{ secrets.TEST_TENANT_ID }}
M365_ACCOUNT_NAME: ${{ secrets.TEST_USER_NAME }}
M365_ACCOUNT_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
M365_TENANT_ID: ${{ secrets.TEST_TENANT_ID_2 }}
CI_ENABLED: "true"
M365_ACCOUNT_COLLABORATOR: ${{ secrets.TEST_COLLABORATOR_USER_NAME }}
AZURE_DEVOPS_EXT_PAT: ${{ secrets.ADO_PAT }}
AUTO_TEST_PLAN_ID: ${{ github.event.inputs.target-testplan-id }}
ADO_TOKEN: ${{ secrets.ADO_PAT }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 16
- name: Setup legacy-peer-deps
run: |
npm config set legacy-peer-deps true
- name: manage pkgs to setup
run: bash .github/scripts/lerna.sh tests
- name: Setup project
uses: nick-fields/retry@v2
with:
timeout_minutes: 10
max_attempts: 5
command: |
npm run setup
- name: List cases for schedule
id: schedule-cases
if: ${{ github.event_name == 'schedule' }}
working-directory: packages/tests/src/e2e
run: |
cases=`find . -wholename "*.tests.ts" | jq -Rsc '[split("\n") | .[]| select(.!="")]'`
echo "cases=$cases" >> $GITHUB_OUTPUT
- name: List cases for dispatch
id: dispatch-cases
if: ${{ github.event_name == 'workflow_dispatch' }}
working-directory: packages/tests/src/e2e
run: |
inputCases='${{ github.event.inputs.cases }}'
if [ -z "$inputCases" ]; then
allCases=`find . -wholename "*.tests.ts" | jq -Rsc '[split("\n") | .[]| select(.!="")]'`
echo "cases=$allCases" >> $GITHUB_OUTPUT
else
echo "cases=$inputCases" >> $GITHUB_OUTPUT
fi
- name: List cases for pull request
id: pr-cases
if: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == 'teamsfx-bot/TeamsFx' }}
working-directory: packages/tests/src/e2e
run: |
cases=`find ./bot ./frontend -path "*.tests.ts" -and \
-not '(' -path '*/*.dotnet.tests.ts' -or -path '*/Blazor*' ')' \
| jq -Rsc '[split("\n") | .[]| select(.!="")]'`
echo "cases=$cases" >> $GITHUB_OUTPUT
- name: E2E Test clean
working-directory: packages/tests
run: |
npm run test:e2e:clean
- name: Archive Test Plan
if: ${{ github.event.inputs.target-testplan-id != '' }}
working-directory: ./packages/tests
run: |
npm install
testplanid=`npx ts-node src/scripts/testPlan.ts obtain vscode ${{ github.event.inputs.target-version }}`
npx ts-node src/scripts/testPlan.ts archive $testplanid
- name: Upload testplan to artifact
if: ${{ github.event.inputs.target-testplan-id != '' }}
uses: actions/upload-artifact@v3
with:
name: testplan
path: |
./packages/tests/testplan.json
execute-case:
if: ${{ needs.setup.outputs.cases }}
env:
AZURE_ACCOUNT_NAME: ${{ secrets.TEST_USER_NAME }}
AZURE_ACCOUNT_OBJECT_ID: ${{ secrets.TEST_USER_OBJECT_ID }}
AZURE_ACCOUNT_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
AZURE_SUBSCRIPTION_ID: ${{ secrets.TEST_SUBSCRIPTION_ID }}
AZURE_TENANT_ID: ${{ secrets.TEST_TENANT_ID }}
M365_ACCOUNT_NAME: ${{ secrets.TEST_USER_NAME }}
M365_ACCOUNT_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
M365_TENANT_ID: ${{ secrets.TEST_TENANT_ID_2 }}
CI_ENABLED: "true"
M365_ACCOUNT_COLLABORATOR: ${{ secrets.TEST_COLLABORATOR_USER_NAME }}
AZURE_DEVOPS_EXT_PAT: ${{ secrets.ADO_PAT }}
TEAMSFX_DEBUG_TEMPLATE: "true"
NODE_ENV: "development"
TEAMSFX_AAD_DEPLOY_ONLY: "true"
SIDELOADING_SERVICE_ENDPOINT: ${{ secrets.SIDELOADING_SERVICE_ENDPOINT }}
SIDELOADING_SERVICE_SCOPE: ${{ secrets.SIDELOADING_SERVICE_SCOPE }}
ADO_TOKEN: ${{ secrets.ADO_PAT }}
needs: setup
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
cases: ${{ fromJson(needs.setup.outputs.cases) }}
name: ${{ matrix.cases }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 16
- name: Setup Azure Functions Core Tools For Linux
run: |
curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg
sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-$(lsb_release -cs)-prod $(lsb_release -cs) main" > /etc/apt/sources.list.d/dotnetdev.list'
sudo apt-get update
sudo apt-get install azure-functions-core-tools-4
which func
func --version
- name: manage pkgs to setup
run: bash .github/scripts/lerna.sh tests
- name: Setup legacy-peer-deps
run: |
npm config set legacy-peer-deps true
- name: Setup .net
uses: actions/setup-dotnet@v2
with:
dotnet-version: 6.0.x
- name: Setup project
uses: nick-fields/retry@v2
with:
timeout_minutes: 10
max_attempts: 5
command: |
npm run setup
- name: Link CLI
if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
run: |
npm link --force
- name: Update CLI and legacy-peer-deps for PR cases
if: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == 'teamsfx-bot/TeamsFx' }}
run: |
npm install -g @microsoft/teamsfx-cli@latest
npm config set legacy-peer-deps false
- name: print system info
run: |
lscpu
- name: Download samples(daily)
if: github.event_name == 'schedule' && startsWith(matrix.cases, './samples/') && contains(matrix.cases, 'ProactiveMessage') == false
uses: actions/checkout@v3
with:
repository: OfficeDev/TeamsFx-Samples
ref: dev
path: packages/tests/src/e2e/resource
- name: Download samples(rc)
if: github.event_name == 'workflow_dispatch' && startsWith(matrix.cases, './samples/') && contains(matrix.cases, 'ProactiveMessage') == false && contains(matrix.cases, 'SignatureOutlook') == false
uses: actions/checkout@v3
with:
repository: OfficeDev/TeamsFx-Samples
ref: v3
path: packages/tests/src/e2e/resource
- name: Download samples from another repo
if: startsWith(matrix.cases, './samples/') && contains(matrix.cases, 'ProactiveMessage')
uses: actions/checkout@v3
with:
repository: OfficeDev/Microsoft-Teams-Samples
ref: main
path: packages/tests/src/e2e/resource
- name: Download samples from office repo
if: startsWith(matrix.cases, './samples/') && contains(matrix.cases, 'SignatureOutlook')
uses: actions/checkout@v3
with:
repository: OfficeDev/Office-Add-in-samples
ref: main
path: packages/tests/src/e2e/resource
- name: run test
working-directory: packages/tests/src/e2e
run: |
file=`find . -wholename "${{ matrix.cases }}"`
if [ -z "$file" ]; then
echo "can't find target case in $file"
exit 1
else
npx mocha --reporter mochawesome --timeout 1200000 $file
fi
- name: get report name
id: get-report-name
if: ${{ always() }}
run: |
name="${{ matrix.cases }}"
name="${name//'.tests.ts'/}"
name="${name//.\//}"
name="${name//\//_}"
echo "name=$name" >> $GITHUB_OUTPUT
- name: Upload test report
uses: actions/upload-artifact@v3
if: ${{ github.event_name != 'schedule' || success() || (failure() && github.run_attempt >= 5) }}
with:
name: test-result-${{ steps.get-report-name.outputs.name }}
path: |
./packages/tests/src/e2e/mochawesome-report/mochawesome.json
- name: Download TestPlan
if: ${{ always() && github.event.inputs.target-testplan-id != '' }}
uses: actions/download-artifact@v3
with:
name: testplan
path: ./packages/tests
- name: Sync to Azure DevOps Test Plan
if: ${{ always() && github.event.inputs.target-testplan-id != '' }}
working-directory: packages/tests
run: |
npx ts-node src/scripts/testPlan.ts report ./testplan.json src/e2e/mochawesome-report/mochawesome.json
tear-down:
if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == 'teamsfx-bot/TeamsFx') }}
needs: execute-case
runs-on: ubuntu-latest
env:
AZURE_ACCOUNT_NAME: ${{ secrets.TEST_USER_NAME }}
AZURE_ACCOUNT_OBJECT_ID: ${{ secrets.TEST_USER_OBJECT_ID }}
AZURE_ACCOUNT_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
AZURE_SUBSCRIPTION_ID: ${{ secrets.TEST_SUBSCRIPTION_ID }}
AZURE_TENANT_ID: ${{ secrets.TEST_TENANT_ID }}
M365_ACCOUNT_NAME: ${{ secrets.TEST_USER_NAME }}
M365_ACCOUNT_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
M365_TENANT_ID: ${{ secrets.TEST_TENANT_ID_2 }}
CI_ENABLED: "true"
M365_ACCOUNT_COLLABORATOR: ${{ secrets.TEST_COLLABORATOR_USER_NAME }}
AZURE_DEVOPS_EXT_PAT: ${{ secrets.ADO_PAT }}
steps:
- name: Checkout (dev)
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 16
- name: manage pkgs to setup
run: bash .github/scripts/lerna.sh tests
- name: Setup legacy-peer-deps
run: |
npm config set legacy-peer-deps true
- name: Setup project
uses: nick-fields/retry@v2
with:
timeout_minutes: 10
max_attempts: 5
command: |
npm run setup
- name: E2E Test clean
working-directory: packages/tests
run: |
npm run test:e2e:clean
rerun:
needs: tear-down
if: ${{ (github.event_name == 'schedule' || (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == 'teamsfx-bot/TeamsFx')) && failure() && github.run_attempt < 5 }}
runs-on: ubuntu-latest
steps:
- name: rerun
run: |
curl \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"\
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/${{ github.repository }}/actions/workflows/rerun.yml/dispatches \
-d '{"ref":"${{ github.ref_name }}","inputs":{"run_id":"${{ github.run_id }}", "max_attempts":"5"}}'
report:
needs: execute-case
if: ${{ github.event_name == 'schedule' && (success() || (failure() && github.run_attempt >= 5)) }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Dateutils
run: |
sudo apt install dateutils
- uses: actions/download-artifact@v3
with:
path: ~/artifacts
- name: List jobs
id: list-jobs
working-directory: packages/tests
run: |
page=1
jobs="[]"
while :
do
url=https://api.github.com/repos/OfficeDev/TeamsFx/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}/jobs\?per_page\=100\&page\=$page
resp=`curl -H "Accept: application/vnd.github.v3+json" -u:${{ secrets.GITHUB_TOKEN }} $url`
new_jobs=`echo $resp | jq -cr '.jobs'`
jobs=`jq -cr --slurp 'add' <(echo "$jobs") <(echo "$new_jobs")`
has_next=`curl -I -H "Accept: application/vnd.github.v3+json" -u:${{ secrets.GITHUB_TOKEN }} $url | grep -Fi "link:" | grep "rel=\"last\"" || true`
if [ -z "$has_next" ]; then
break
fi
page=$((page+1))
done
cases=`echo $jobs| jq -r '.[] | select(.name | contains("tests.ts")) | .name'`
passed=0
failed=0
skipped=0
passed_lists=""
failed_lists=""
skipped_lists=""
emails="[email protected];"
while IFS= read -r case;
do
if [ -z "$case" ]; then
continue
fi
file="src/e2e/$case"
elegant_path="${file//.\//}"
started_at=`echo $jobs | jq --arg case $case -r '.[] | select(.name == $case ) | .steps[] | select(.name == "run test") | .started_at'`
completed_at=`echo $jobs | jq --arg case $case -r '.[] | select(.name == $case ) | .steps[] | select(.name == "run test") | .completed_at'`
duration=`dateutils.ddiff $started_at $completed_at -f "%Mm %Ss"`
email=""
if grep -q "@author" $file; then
email=`grep '@author' $file | grep -i -o '[A-Z0-9._%+-]\+@[A-Z0-9.-]\+\.[A-Z]\{2,4\}'`
fi
author=""
if [ -z "$email" ]; then
author="N/A"
else
author="<a href=\\\"mailto:$email\\\"><span>$email</span></a>"
fi
url=`echo $jobs | jq --arg case $case -r '.[] | select(.name == $case ) | .html_url'`
url="<a href=\\\"$url\\\">$elegant_path</a>"
target_type="TS/JS"
if [[ $case == *".dotnet."* ]]; then
target_type=".NET"
fi
name="${case//'.tests.ts'/}"
name="${name//.\//}"
name="${name//\//_}"
job_id=`echo $jobs | jq --arg case $case -r '.[] | select(.name == $case ) | .id'`
report_file=`find ~/artifacts -wholename "*${name}*/mochawesome.json"`
if [ ! -z "$report_file" ]; then
echo "Found the $report_file with $job_id and $name"
tests=`cat $report_file | jq -cr '[ .. | objects | with_entries(select(.key=="tests")) | select(. != {}) | select(.tests | type=="array") ] | map(.tests | .[]) | .[]'`
lable=""
while IFS= read -r test;
do
name=`echo $test | jq -cr .fullTitle`
duration=`echo $test | jq -cr .duration`
if [[ ! -z `echo $test | jq 'select(.pass==true)'` ]]; then
passed=$((passed+1))
label="<span style=\\\"background-color:#2aa198;color:white;font-weight:bold;\\\">PASSED</span>"
elif [[ ! -z `echo $test | jq 'select(.fail==true)'` ]]; then
failed=$((failed+1))
label="<span style=\\\"background-color: #dc322f;color:white;font-weight:bold;\\\">FAILED</span>"
if [[ ! -z "$email" && ! "$emails" == *"$email"* ]]; then
emails="$emails;$email"
fi
elif [[ ! -z `echo $test | jq 'select(.skipped==true)'` || ! -z `echo $test | jq 'select(.pending==true)'` ]]; then
skipped=$((skipped+1))
label="<span style=\\\"background-color: #b58900;color:white;font-weight:bold;\\\">SKIPPED</span>"
fi
row="<tr> <td style=\\\"text-align: left;\\\">$url</td> <td style=\\\"text-align: left;\\\">$name</td> <td style=\\\"text-align: center;\\\">$target_type</td> <td style=\\\"text-align: center;\\\">$label</td> <td style=\\\"text-align: center;\\\">$author</td> <td>$((duration/1000)) sec</td> </tr>"
if [[ ! -z `echo $test | jq 'select(.pass==true)'` ]]; then
passed_lists="$passed_lists $row"
elif [[ ! -z `echo $test | jq 'select(.fail==true)'` ]]; then
failed_lists="$failed_lists $row"
elif [[ ! -z `echo $test | jq 'select(.skipped==true)'` || ! -z `echo $test | jq 'select(.pending==true)'` ]]; then
skipped_lists="$skipped_lists $row"
fi
done <<< $tests
else
echo "Failed to find the $report_file with $job_id and $name"
fi
done <<< $cases
body="<table class=\\\"w3-table w3-striped w3-bordered\\\"> <tr> <th>PATH</th> <th>CASE</th> <th>TARGET TYPE</th> <th>STATUS</th> <th>AUTHOR</th> <th>DURATION</th> </tr> $failed_lists $skipped_lists $passed_lists </table> <br />"
total=$((passed+failed+skipped))
subject="TeamsFx E2E V3 Test Report ($passed/$total Passed, $failed/$total Failed, $skipped/$total Skipped)"
if [ $failed -gt 0 ]; then
subject="[FAILED] $subject"
else
subject="[PASSED] $subject"
fi
echo "body=$body" >> $GITHUB_OUTPUT
echo "to=$emails" >> $GITHUB_OUTPUT
echo "subject=$subject" >> $GITHUB_OUTPUT