Skip to content

@Desktop • UI e2e • Test App triggered by ypolishchuk-ledger on ref test/parallelization #199

@Desktop • UI e2e • Test App triggered by ypolishchuk-ledger on ref test/parallelization

@Desktop • UI e2e • Test App triggered by ypolishchuk-ledger on ref test/parallelization #199

name: "@Desktop • UI e2e • Test App"
run-name: "@Desktop • UI e2e • Test App triggered by ${{ inputs.login || github.actor }} ${{ format('on ref {0}', github.ref_name) }}"
on:
schedule:
- cron: "0 5 * * 1-5"
workflow_dispatch:
inputs:
ref:
description: the branch which triggered this workflow
required: false
login:
description: The GitHub username that triggered the workflow
required: false
base_ref:
description: The base branch to merge the head into when checking out the code
required: false
test_filter:
description: Filter test pattern to execute only tests suites named according to pattern(s) separated by '|' (e.g. to execute accounts and settings describe blocks "Accounts @smoke" or "Accounts @smoke|Settings")
required: false
invert_filter:
description: Ignore test having name pattern (entered in the previous field)
type: boolean
default: false
speculos_tests:
description: Run the speculos tests (if false, mocked tests will be run instead)
type: boolean
default: true
enable_broadcast:
description: Enable transaction broadcast
type: boolean
default: false
report_path:
description: Path where you want to store this execution's results
required: false
default: "allure-results-linux"
slack_notif:
description: "Send notification to Slack?"
required: false
type: boolean
default: false
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name != 'develop' && github.ref || github.run_id }}
cancel-in-progress: true
permissions:
id-token: write
contents: read
jobs:
e2e-tests-linux:
name: "Desktop Tests E2E (Ubuntu)"
outputs:
status: ${{ steps.tests.outcome }}
env:
NODE_OPTIONS: "--max-old-space-size=7168"
INSTRUMENT_BUILD: true
FORCE_COLOR: 3
CI_OS: "ubuntu-latest"
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
# DEBUG: "pw:browser*"
# DEBUG_LOGS: 1
runs-on: [ledger-live-4xlarge]
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3]
shardTotal: [3]
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.sha }}
- name: Setup caches
id: caches
uses: LedgerHQ/ledger-live/tools/actions/composites/setup-caches@develop
with:
skip-turbo-cache: "false"
accountId: ${{ secrets.AWS_ACCOUNT_ID_PROD }}
roleName: ${{ secrets.AWS_CACHE_ROLE_NAME }}
region: ${{ secrets.AWS_CACHE_REGION }}
turbo-server-token: ${{ secrets.TURBOREPO_SERVER_TOKEN }}
- uses: LedgerHQ/ledger-live/tools/actions/composites/setup-test-desktop@develop
id: setup-test-desktop
with:
skip_ruby: true
install_playwright: true
turborepo-server-port: ${{ steps.caches.outputs.port }}
- name: generate token
id: generate-token
uses: tibdex/github-app-token@v1
with:
app_id: ${{ secrets.GH_BOT_APP_ID }}
private_key: ${{ secrets.GH_BOT_PRIVATE_KEY }}
- name: Retrieving coin apps
uses: actions/checkout@v4
with:
ref: generated/ledger-live-bot
repository: LedgerHQ/coin-apps
token: ${{ steps.generate-token.outputs.token }}
path: coin-apps
- name: pull docker image
run: docker pull ghcr.io/ledgerhq/speculos:sha-e262a0c
shell: bash
- name: Run playwright tests [Linux => xvfb-run]
id: tests
run: |
export COINAPPS=$PWD/coin-apps
if [ "$ENABLE_BROADCAST" = true ]; then export ENABLE_TRANSACTION_BROADCAST=1; fi
if [ "$SPECULOS_TESTS" = true ]; then export MOCK=0 && speculos_tests=":speculos"; fi
if [ "${{ inputs.invert_filter }}" = true ]; then invert_filter="-invert"; fi
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- pnpm desktop test:playwright$speculos_tests ${INPUTS_TEST_FILTER:+--grep$invert_filter} "${{ inputs.test_filter }}" --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
env:
INPUTS_TEST_FILTER: ${{ inputs.test_filter }}
SEED: ${{ secrets.SEED_QAA_B2C }}
ENABLE_BROADCAST: ${{ contains(inputs.enable_broadcast, 'true') }}
SPECULOS_TESTS: ${{ !contains(inputs.speculos_tests, 'false') }}
- name: Upload Allure Results
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4.3.0
with:
name: allure-results-${{ matrix.shardIndex }}
path: "apps/ledger-live-desktop/allure-results"
report-and-notify:
name: "Report and Notify"
runs-on: [ledger-live-4xlarge]
needs: e2e-tests-linux
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.sha }}
- name: Download Allure Results
uses: actions/download-artifact@v4.1.1
with:
path: "apps/ledger-live-desktop/allure-results"
pattern: allure-results-*
merge-multiple: true
- name: Publish report on Allure Server
id: allure-server
if: ${{ !cancelled() }}
uses: LedgerHQ/send-to-allure-server-action@2.1.2
with:
allure-server-url: "https://ledger-live.allure.green.ledgerlabs.net"
build-name: ${{ github.workflow }}
build-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
username: ${{ vars.ALLURE_USERNAME }}
password: ${{ secrets.ALLURE_LEDGER_LIVE_PASSWORD }}
path: ${{ github.ref_name }}/linux
allure-results: "apps/ledger-live-desktop/allure-results"
- name: Write Allure report in summary
if: ${{ !cancelled() }}
shell: bash
run: echo "::notice title=Allure report URL::${{ steps.allure-server.outputs.report-url }}"
- name: Get summary
if: ${{ !cancelled() }}
shell: bash
run: |
cd apps/ledger-live-desktop
allure generate
cd allure-report/widgets
passedTests=$(jq '.statistic.passed' summary.json)
failedTests=$(jq '.statistic.failed' summary.json)
brokenTests=$(jq '.statistic.broken' summary.json)
skippedTests=$(jq '.statistic.skipped' summary.json)
totalTests=$(jq '.statistic.total' summary.json)
echo "TEST_RESULT=$passedTests passed, $failedTests failed, $brokenTests broken, $skippedTests skipped, $totalTests total" >> $GITHUB_ENV
- name: Get status color
if: ${{ !cancelled() }}
shell: bash
run: >
if ${{ needs.e2e-tests-linux.outputs.outcome == 'success' }};
then echo "STATUS_COLOR=#33FF39" >> $GITHUB_ENV;
elif ${{ needs.e2e-tests-linux.outputs.outcome == 'failure' }};
then echo "STATUS_COLOR=#FF333C" >> $GITHUB_ENV;
else echo "STATUS_COLOR=#F3FF33" >> $GITHUB_ENV;
fi
- uses: actions/github-script@v6
if: ${{ !cancelled() }}
name: prepare status
id: status
with:
script: |
const fs = require("fs");
const path = require("path");
const [ owner, repo ] = "${{ github.repository }}".split("/");
const jobs = await github.paginate(github.rest.actions.listJobsForWorkflowRunAttempt, {
owner,
repo,
run_id: "${{ github.run_id }}",
attempt_number: "${{ github.run_attempt }}",
});
const findJobUrl = os =>
jobs.find(job => job.name == `Live Desktop Tests (${os})`)?.html_url;
const keys = {
linux: {
symbol: "🐧",
name: "Linux",
jobUrl: findJobUrl("Linux")
},
};
const report = {
linux: {
pass: ${{ needs.e2e-tests-linux.outputs.outcome == 'success' }},
status: "${{ needs.e2e-tests-linux.outputs.outcome }}",
}
};
let summary = `### Playwright Tests
`
summary += `|`
const reportKeys = Object.keys(report);
const playwrightSuccess = Object.entries(report).every(([os, values]) => !!values.pass);
reportKeys.forEach((k) => {
summary += ` [${keys[k].symbol} ${keys[k].name}](${keys[k].jobUrl}) |`;
});
summary += `
|`;
for (let i = 0; i < reportKeys.length; i++) {
summary += ` :--: |`;
}
summary += `
|`;
Object.entries(report).forEach(([os, values]) => {
summary += ` ${values.pass ? "✅" : "❌"} (${values.status}) |`;
});
summary += `
${{ steps.comment.outputs.body }}
`
const output = {
summary,
actions: [{
// 20 chars max
label: "Regen. Screenshots",
// 20 chars max
identifier: "regen_screenshots",
// 40 chars max
description: "Will regenerate playwright screenshots",
}, {
// 20 chars max
label: "Run full LLD suite",
// 20 chars max
identifier: "lld_full_suite",
// 40 chars max
description: "Run the full e2e test suite for LLD",
}],
};
if (${{ !inputs.slack_notif && github.event_name == 'workflow_dispatch' }}) return;
const slackPayload = {
"text": "Ledger Live Desktop tests results on ${{github.ref_name}}",
"attachments": [
{
"color": "${{ env.STATUS_COLOR }}",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":ledger-logo: Ledger Live Desktop tests results on ${{ github.ref_name }}",
"emoji": true
}
},
{
"type": "divider"
},
{
"type": "header",
"text": {
"type": "plain_text",
"text": "E2E Tests"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": `- 🐧 linux: ${report.linux.pass ? "✅" : "❌"} ${process.env.TEST_RESULT || 'No test results'}`
}
},
{
"type": "divider"
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Allure Report*\n<${{ steps.allure-server.outputs.report-url }}|allure-results-linux>"
},
{
"type": "mrkdwn",
"text": "*Workflow*\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Workflow Run>"
}
]
}
]
}
]
};
fs.writeFileSync("payload-slack-content.json", JSON.stringify(slackPayload), "utf-8");
- name: Print Slack Payload Content
if: ${{ !cancelled() && (inputs.slack_notif || github.event_name == 'schedule' )}}
run: cat ${{ github.workspace }}/payload-slack-content.json
- name: post to a Slack channel
id: slack
uses: slackapi/slack-github-action@v1.23.0
if: ${{ !cancelled() && (inputs.slack_notif || github.event_name == 'schedule' )}}
with:
channel-id: "C05FKJ7DFAP"
payload-file-path: ${{ github.workspace }}/payload-slack-content.json
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_LIVE_CI_BOT_TOKEN }}