From 90d7f160d5795cec46588ef065ccf52732fd0148 Mon Sep 17 00:00:00 2001 From: Rodel Calasagsag Date: Wed, 11 Oct 2023 20:36:18 +0800 Subject: [PATCH 1/8] Implement 5min timeout --- .../woocommerce/tests/api-core-tests/ci-release.global-setup.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js b/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js index ac45a4ea05b..696dcf0933a 100644 --- a/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js +++ b/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js @@ -7,6 +7,8 @@ const zipPath = path.resolve( 'tmp', 'woocommerce.zip' ); const downloadURL = `https://github.com/woocommerce/woocommerce/releases/download/${ UPDATE_WC }/woocommerce.zip`; test( `Setup remote test site`, async ( { page, request } ) => { + test.setTimeout( 5 * 60 * 1000 ); + await test.step( `Download WooCommerce build zip`, async () => { const response = await request.get( downloadURL ); expect( response.ok() ).toBeTruthy(); From c3a65eefaa5a8ae1131819015d4c186081337916 Mon Sep 17 00:00:00 2001 From: Rodel Calasagsag Date: Wed, 11 Oct 2023 20:37:36 +0800 Subject: [PATCH 2/8] Start waiting for response before click --- .../tests/api-core-tests/ci-release.global-setup.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js b/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js index 696dcf0933a..39d24191fc3 100644 --- a/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js +++ b/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js @@ -63,10 +63,11 @@ test( `Setup remote test site`, async ( { page, request } ) => { await page.goto( '/wp-admin/plugin-install.php' ); await page.getByRole( 'button', { name: Upload_Plugin } ).click(); await page.getByLabel( Plugin_zip_file ).setInputFiles( zipPath ); + const uploadPromise = page.waitForResponse( + '/wp-admin/update.php?action=upload-plugin' + ); await page.getByRole( 'button', { name: Install_Now } ).click(); - const uploadResponse = await page.waitForResponse( - '**/wp-admin/update.php?action=upload-plugin' - );; + const uploadResponse = await uploadPromise; expect( uploadResponse.ok() ).toBeTruthy(); await expect( page.getByRole( 'link', { name: Activate_Plugin } ) From 5587d752c9646f98153d608b2d5fcabe1b9969c9 Mon Sep 17 00:00:00 2001 From: Rodel Calasagsag Date: Wed, 11 Oct 2023 20:37:48 +0800 Subject: [PATCH 3/8] Minor spacing fix --- .../woocommerce/tests/api-core-tests/ci-release.global-setup.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js b/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js index 39d24191fc3..2766e939639 100644 --- a/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js +++ b/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js @@ -99,7 +99,7 @@ test( `Setup remote test site`, async ( { page, request } ) => { const response = await request.get( '/wp-json/wc/v3/system_status' ); const { database } = await response.json(); const { wc_database_version } = database; - const [major, minor] = UPDATE_WC.split( '.' ); + const [ major, minor ] = UPDATE_WC.split( '.' ); const pattern = new RegExp( `^${ major }\.${ minor }` ); expect( wc_database_version ).toMatch( pattern ); } ); From 0db95f37508e24cc20694e7d914c364b2d0c8913 Mon Sep 17 00:00:00 2001 From: Rodel Calasagsag Date: Wed, 11 Oct 2023 20:41:08 +0800 Subject: [PATCH 4/8] Add changelog --- .../woocommerce/changelog/dev-fix-release-test-global-setup | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 plugins/woocommerce/changelog/dev-fix-release-test-global-setup diff --git a/plugins/woocommerce/changelog/dev-fix-release-test-global-setup b/plugins/woocommerce/changelog/dev-fix-release-test-global-setup new file mode 100644 index 00000000000..05349fe2554 --- /dev/null +++ b/plugins/woocommerce/changelog/dev-fix-release-test-global-setup @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix global setup for release tests. From b5421de444b495201e0e0017c68da08c3f70773b Mon Sep 17 00:00:00 2001 From: Rodel Calasagsag Date: Sat, 14 Oct 2023 16:19:31 +0800 Subject: [PATCH 5/8] Use chrome user agent --- .../tests/api-core-tests/ci-release.playwright.config.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/woocommerce/tests/api-core-tests/ci-release.playwright.config.js b/plugins/woocommerce/tests/api-core-tests/ci-release.playwright.config.js index b2b0d4889e8..e44208c2fc2 100644 --- a/plugins/woocommerce/tests/api-core-tests/ci-release.playwright.config.js +++ b/plugins/woocommerce/tests/api-core-tests/ci-release.playwright.config.js @@ -1,4 +1,5 @@ const defaultConfig = require( './playwright.config' ); +const { devices } = require( '@playwright/test' ); // Global setup will be done through the 'Setup' project, not through the `globalSetup` property delete defaultConfig[ 'globalSetup' ]; @@ -13,6 +14,7 @@ const config = { name: 'Setup', testDir: './', testMatch: 'ci-release.global-setup.js', + use: { ...devices[ 'Desktop Chrome' ] }, }, { name: 'API tests', From f63b8353ee4bf5fa18832c66633197badd0bdf82 Mon Sep 17 00:00:00 2001 From: Rodel Calasagsag Date: Sat, 14 Oct 2023 16:20:33 +0800 Subject: [PATCH 6/8] Add support for draft releases --- .../workflows/scripts/download-release-zip.js | 19 +++ .../scripts/validate-release-version.js | 51 ++++++ .github/workflows/smoke-test-release.yml | 161 +++++++++--------- .../api-core-tests/ci-release.global-setup.js | 108 ++++++------ .../api-core-tests/utils/plugin-utils.js | 108 +++++++++++- .../smoke-tests/update-woocommerce.spec.js | 146 +++++++--------- 6 files changed, 385 insertions(+), 208 deletions(-) create mode 100644 .github/workflows/scripts/download-release-zip.js create mode 100644 .github/workflows/scripts/validate-release-version.js diff --git a/.github/workflows/scripts/download-release-zip.js b/.github/workflows/scripts/download-release-zip.js new file mode 100644 index 00000000000..f49be259890 --- /dev/null +++ b/.github/workflows/scripts/download-release-zip.js @@ -0,0 +1,19 @@ +module.exports = async ( { github, context, core } ) => { + const { ASSET_ID: asset_id } = process.env; + const { owner, repo } = context.repo; + const fs = require( 'fs' ); + const path = require( 'path' ); + + const response = await github.rest.repos.getReleaseAsset( { + owner, + repo, + asset_id, + headers: { accept: 'application/octet-stream' }, + } ); + + const zipPath = path.resolve( 'tmp', 'woocommerce.zip' ); + fs.mkdirSync( 'tmp' ); + fs.writeFileSync( zipPath, Buffer.from( response.data ) ); + + core.setOutput( 'zip-path', zipPath ); +}; diff --git a/.github/workflows/scripts/validate-release-version.js b/.github/workflows/scripts/validate-release-version.js new file mode 100644 index 00000000000..16a4bd47ff6 --- /dev/null +++ b/.github/workflows/scripts/validate-release-version.js @@ -0,0 +1,51 @@ +module.exports = async ( { github, context, core } ) => { + const { RELEASE_VERSION, GITHUB_EVENT_NAME } = process.env; + + async function findRelease() { + const { owner, repo } = context.repo; + const list = await github.rest.repos.listReleases( { + owner, + repo, + per_page: 100, + } ); + const match = list.data.find( ( { tag_name, name } ) => + [ tag_name, name ].includes( RELEASE_VERSION ) + ); + + return match; + } + + async function handleWorkflowDispatch() { + const match = await findRelease(); + + if ( match ) { + return match; + } + + throw new Error( + `"${ RELEASE_VERSION }" is not a valid release version!` + ); + } + + function findWooCommerceZipAsset() { + const match = release.assets.find( + ( { name } ) => name === 'woocommerce.zip' + ); + if ( ! match ) { + throw new Error( + `Release ${ RELEASE_VERSION } does not contain a woocommerce.zip asset!` + ); + } + + return match; + } + + const release = + GITHUB_EVENT_NAME === 'release' + ? await findRelease() + : await handleWorkflowDispatch(); + const asset = findWooCommerceZipAsset(); + core.setOutput( 'version', RELEASE_VERSION ); + core.setOutput( 'created', release.created_at ); + core.setOutput( 'asset-id', asset.id ); +}; diff --git a/.github/workflows/smoke-test-release.yml b/.github/workflows/smoke-test-release.yml index 554f92da5d2..cf6703abfd3 100644 --- a/.github/workflows/smoke-test-release.yml +++ b/.github/workflows/smoke-test-release.yml @@ -5,7 +5,7 @@ on: workflow_dispatch: inputs: tag: - description: 'WooCommerce Release Tag' + description: 'WooCommerce release version' required: true concurrency: group: ${{ github.workflow }}-${{ github.event.release.tag_name || inputs.tag }} @@ -16,55 +16,33 @@ env: E2E_UPDATE_WC_ARTIFACT: WooCommerce version update test on release smoke test site (run ${{ github.run_number }}) SLACK_BLOCKS_ARTIFACT: slack-blocks jobs: - get-tag: - name: Get WooCommerce release tag + validate-version: + name: Validate release version permissions: contents: read runs-on: ubuntu-20.04 outputs: - tag: ${{ steps.get-tag.outputs.tag }} - created: ${{ steps.created-at.outputs.created }} + version: ${{ steps.validate-version.outputs.version }} + created: ${{ steps.validate-version.outputs.created }} + asset-id: ${{ steps.validate-version.outputs.asset-id }} steps: - - name: Validate tag - if: ${{ github.event_name == 'workflow_dispatch' }} - env: - GH_TOKEN: ${{ secrets.E2E_GH_TOKEN }} - run: gh release view "${{ inputs.tag }}" --repo=woocommerce/woocommerce + - uses: actions/checkout@v3 - - name: Get tag from triggered event - id: get-tag + - name: Validate release version + id: validate-version + uses: actions/github-script@v6 env: - RELEASE_TAG: ${{ github.event.release.tag_name || inputs.tag }} - run: | - echo "Triggered event: ${{ github.event_name }}" - echo "Tag from event: $RELEASE_TAG" - echo "tag=$RELEASE_TAG" >> $GITHUB_OUTPUT - - - name: Verify woocommerce.zip asset - env: - GH_TOKEN: ${{ secrets.E2E_GH_TOKEN }} - RELEASE_TAG: ${{ steps.get-tag.outputs.tag }} - run: | - ASSET_NAMES=$(gh release view $RELEASE_TAG --repo woocommerce/woocommerce --json assets --jq ".assets[].name") - if [[ $ASSET_NAMES == *"woocommerce.zip"* ]] - then - echo "$RELEASE_TAG has a valid woocommerce.zip asset." - exit 0 - fi - - echo "$RELEASE_TAG does not have a valid woocommerce.zip asset." - exit 1 - - - name: Get 'created-at' of WooCommerce zip - id: created-at - env: - GH_TOKEN: ${{ secrets.E2E_GH_TOKEN }} - run: echo "created=$(gh release view ${{ steps.get-tag.outputs.tag }} --json assets --jq .assets[0].createdAt --repo woocommerce/woocommerce)" >> $GITHUB_OUTPUT + RELEASE_VERSION: ${{ inputs.tag }} + with: + github-token: ${{ secrets.E2E_GH_TOKEN }} + script: | + const script = require('./.github/workflows/scripts/validate-release-version.js'); + await script({ github, context, core }); e2e-update-wc: name: Test WooCommerce update runs-on: ubuntu-20.04 - needs: [get-tag] + needs: [validate-version] permissions: contents: read env: @@ -94,7 +72,7 @@ jobs: CUSTOMER_USER: ${{ secrets.RELEASE_TEST_CUSTOMER_USER }} DEFAULT_TIMEOUT_OVERRIDE: 120000 GITHUB_TOKEN: ${{ secrets.E2E_GH_TOKEN }} - UPDATE_WC: ${{ needs.get-tag.outputs.tag }} + UPDATE_WC: ${{ needs.validate-version.outputs.version }} - name: Upload Allure artifacts to bucket if: success() || ( failure() && steps.run-e2e-composite-action.conclusion == 'failure' ) @@ -113,10 +91,10 @@ jobs: ENV_DESCRIPTION: wp-latest run: | gh workflow run publish-test-reports-release.yml \ - -f created_at="${{ needs.get-tag.outputs.created }}" \ + -f created_at="${{ needs.validate-version.outputs.created }}" \ -f run_id=${{ github.run_id }} \ -f run_number=${{ github.run_number }} \ - -f release_tag=${{ needs.get-tag.outputs.tag }} \ + -f release_tag=${{ needs.validate-version.outputs.version }} \ -f artifact="${{ env.E2E_WP_LATEST_ARTIFACT }}" \ -f env_description="${{ env.ENV_DESCRIPTION }}" \ -f test_type="e2e" \ @@ -132,12 +110,12 @@ jobs: test-name: WC Update test e2e-result: ${{ steps.run-e2e-composite-action.outputs.result }} env-slug: wp-latest - release-version: ${{ needs.get-tag.outputs.tag }} + release-version: ${{ needs.validate-version.outputs.version }} api-wp-latest: name: API on WP Latest runs-on: ubuntu-20.04 - needs: [get-tag, e2e-update-wc] + needs: [validate-version, e2e-update-wc] permissions: contents: read outputs: @@ -170,7 +148,8 @@ jobs: API_BASE_URL: ${{ secrets.RELEASE_TEST_URL }} USER_KEY: ${{ secrets.RELEASE_TEST_ADMIN_USER }} USER_SECRET: ${{ secrets.RELEASE_TEST_ADMIN_PASSWORD }} - UPDATE_WC: ${{ needs.get-tag.outputs.tag }} + UPDATE_WC: ${{ needs.validate-version.outputs.version }} + GITHUB_TOKEN: ${{ secrets.E2E_GH_TOKEN }} - name: Upload Allure artifacts to bucket if: success() || ( failure() && steps.run-api-composite-action.conclusion == 'failure' ) @@ -189,10 +168,10 @@ jobs: ENV_DESCRIPTION: wp-latest run: | gh workflow run publish-test-reports-release.yml \ - -f created_at="${{ needs.get-tag.outputs.created }}" \ + -f created_at="${{ needs.validate-version.outputs.created }}" \ -f run_id=${{ github.run_id }} \ -f run_number=${{ github.run_number }} \ - -f release_tag=${{ needs.get-tag.outputs.tag }} \ + -f release_tag=${{ needs.validate-version.outputs.version }} \ -f artifact="${{ env.API_WP_LATEST_ARTIFACT }}" \ -f env_description="${{ env.ENV_DESCRIPTION }}" \ -f test_type="api" \ @@ -208,12 +187,12 @@ jobs: test-name: WP Latest api-result: ${{ steps.run-api-composite-action.outputs.result }} env-slug: wp-latest - release-version: ${{ needs.get-tag.outputs.tag }} + release-version: ${{ needs.validate-version.outputs.version }} e2e-wp-latest: name: E2E on WP Latest runs-on: ubuntu-20.04 - needs: [get-tag, api-wp-latest] + needs: [validate-version, api-wp-latest] permissions: contents: read env: @@ -291,10 +270,10 @@ jobs: ENV_DESCRIPTION: wp-latest run: | gh workflow run publish-test-reports-release.yml \ - -f created_at="${{ needs.get-tag.outputs.created }}" \ + -f created_at="${{ needs.validate-version.outputs.created }}" \ -f run_id=${{ github.run_id }} \ -f run_number=${{ github.run_number }} \ - -f release_tag=${{ needs.get-tag.outputs.tag }} \ + -f release_tag=${{ needs.validate-version.outputs.version }} \ -f artifact="${{ env.E2E_WP_LATEST_ARTIFACT }}" \ -f env_description="${{ env.ENV_DESCRIPTION }}" \ -f test_type="e2e" \ @@ -311,12 +290,12 @@ jobs: api-result: ${{ needs.api-wp-latest.outputs.result }} e2e-result: ${{ steps.run-e2e-composite-action.outputs.result }} env-slug: wp-latest - release-version: ${{ needs.get-tag.outputs.tag }} + release-version: ${{ needs.validate-version.outputs.version }} test-wp-latest-1: name: Test against WP Latest-1 runs-on: ubuntu-20.04 - needs: [ get-tag ] + needs: [validate-version] env: API_ALLURE_REPORT_DIR: ${{ github.workspace }}/plugins/woocommerce/tests/e2e-pw/test-results/api/allure-report API_ALLURE_RESULTS_DIR: ${{ github.workspace }}/plugins/woocommerce/tests/e2e-pw/test-results/api/allure-results @@ -350,12 +329,20 @@ jobs: WP_ENV_CORE: WordPress/WordPress#${{ steps.get-wp-latest-1.outputs.version }} - name: Download release zip + id: download-zip + uses: actions/github-script@v6 env: - GH_TOKEN: ${{ secrets.E2E_GH_TOKEN }} - run: gh release download ${{ steps.get-wp-latest-1.outputs.version }} --dir tmp + ASSET_ID: ${{ needs.validate-version.outputs.asset-id }} + with: + github-token: ${{ secrets.E2E_GH_TOKEN }} + script: | + const script = require('./.github/workflows/scripts/download-release-zip.js'); + await script({ github, context, core }); - name: Replace `plugins/woocommerce` with unzipped woocommerce release build - run: unzip -d plugins -o tmp/woocommerce.zip + run: unzip -d plugins -o ${{ env.ZIP_PATH }} + env: + ZIP_PATH: ${{ steps.download-zip.outputs.zip-path }} - name: Run API tests id: run-api-composite-action @@ -387,10 +374,10 @@ jobs: ENV_DESCRIPTION: wp-latest-1 run: | gh workflow run publish-test-reports-release.yml \ - -f created_at="${{ needs.get-tag.outputs.created }}" \ + -f created_at="${{ needs.validate-version.outputs.created }}" \ -f run_id=${{ github.run_id }} \ -f run_number=${{ github.run_number }} \ - -f release_tag=${{ needs.get-tag.outputs.tag }} \ + -f release_tag=${{ needs.validate-version.outputs.version }} \ -f artifact="${{ env.API_WP_LATEST_X_ARTIFACT }}" \ -f env_description="${{ env.ENV_DESCRIPTION }}" \ -f test_type="api" \ @@ -428,10 +415,10 @@ jobs: ENV_DESCRIPTION: wp-latest-1 run: | gh workflow run publish-test-reports-release.yml \ - -f created_at="${{ needs.get-tag.outputs.created }}" \ + -f created_at="${{ needs.validate-version.outputs.created }}" \ -f run_id=${{ github.run_id }} \ -f run_number=${{ github.run_number }} \ - -f release_tag=${{ needs.get-tag.outputs.tag }} \ + -f release_tag=${{ needs.validate-version.outputs.version }} \ -f artifact="${{ env.E2E_WP_LATEST_X_ARTIFACT }}" \ -f env_description="${{ env.ENV_DESCRIPTION }}" \ -f test_type="e2e" \ @@ -451,12 +438,12 @@ jobs: api-result: ${{ steps.run-api-composite-action.outputs.result }} e2e-result: ${{ steps.run-e2e-composite-action.outputs.result }} env-slug: wp-latest-1 - release-version: ${{ needs.get-tag.outputs.tag }} + release-version: ${{ needs.validate-version.outputs.version }} test-php-versions: name: Test against PHP ${{ matrix.php_version }} runs-on: ubuntu-20.04 - needs: [get-tag] + needs: [validate-version] strategy: fail-fast: false matrix: @@ -490,12 +477,20 @@ jobs: run: bash verify-php-version.sh - name: Download release zip + id: download-zip + uses: actions/github-script@v6 env: - GH_TOKEN: ${{ secrets.E2E_GH_TOKEN }} - run: gh release download ${{ needs.get-tag.outputs.tag }} --dir tmp + ASSET_ID: ${{ needs.validate-version.outputs.asset-id }} + with: + github-token: ${{ secrets.E2E_GH_TOKEN }} + script: | + const script = require('./.github/workflows/scripts/download-release-zip.js'); + await script({ github, context, core }); - name: Replace `plugins/woocommerce` with unzipped woocommerce release build - run: unzip -d plugins -o tmp/woocommerce.zip + run: unzip -d plugins -o ${{ env.ZIP_PATH }} + env: + ZIP_PATH: ${{ steps.download-zip.outputs.zip-path }} - name: Run API tests id: run-api-composite-action @@ -527,10 +522,10 @@ jobs: ENV_DESCRIPTION: php-${{ matrix.php_version }} run: | gh workflow run publish-test-reports-release.yml \ - -f created_at="${{ needs.get-tag.outputs.created }}" \ + -f created_at="${{ needs.validate-version.outputs.created }}" \ -f run_id=${{ github.run_id }} \ -f run_number=${{ github.run_number }} \ - -f release_tag=${{ needs.get-tag.outputs.tag }} \ + -f release_tag=${{ needs.validate-version.outputs.version }} \ -f artifact="${{ env.API_ARTIFACT }}" \ -f env_description="${{ env.ENV_DESCRIPTION }}" \ -f test_type="api" \ @@ -568,10 +563,10 @@ jobs: ENV_DESCRIPTION: php-${{ matrix.php_version }} run: | gh workflow run publish-test-reports-release.yml \ - -f created_at="${{ needs.get-tag.outputs.created }}" \ + -f created_at="${{ needs.validate-version.outputs.created }}" \ -f run_id=${{ github.run_id }} \ -f run_number=${{ github.run_number }} \ - -f release_tag=${{ needs.get-tag.outputs.tag }} \ + -f release_tag=${{ needs.validate-version.outputs.version }} \ -f artifact="${{ env.E2E_ARTIFACT }}" \ -f env_description="${{ env.ENV_DESCRIPTION }}" \ -f test_type="e2e" \ @@ -591,12 +586,12 @@ jobs: api-result: ${{ steps.run-api-composite-action.outputs.result }} e2e-result: ${{ steps.run-e2e-composite-action.outputs.result }} env-slug: php-${{ matrix.php_version }} - release-version: ${{ needs.get-tag.outputs.tag }} + release-version: ${{ needs.validate-version.outputs.version }} test-plugins: name: With ${{ matrix.plugin }} runs-on: ubuntu-20.04 - needs: [get-tag] + needs: [validate-version] env: ALLURE_RESULTS_DIR: ${{ github.workspace }}/plugins/woocommerce/tests/e2e-pw/allure-results ALLURE_REPORT_DIR: ${{ github.workspace }}/plugins/woocommerce/tests/e2e-pw/allure-report @@ -638,12 +633,20 @@ jobs: run: pnpm run env:test - name: Download release zip + id: download-zip + uses: actions/github-script@v6 env: - GH_TOKEN: ${{ secrets.E2E_GH_TOKEN }} - run: gh release download ${{ needs.get-tag.outputs.tag }} --dir tmp + ASSET_ID: ${{ needs.validate-version.outputs.asset-id }} + with: + github-token: ${{ secrets.E2E_GH_TOKEN }} + script: | + const script = require('./.github/workflows/scripts/download-release-zip.js'); + await script({ github, context, core }); - name: Replace `plugins/woocommerce` with unzipped woocommerce release build - run: unzip -d plugins -o tmp/woocommerce.zip + run: unzip -d plugins -o ${{ env.ZIP_PATH }} + env: + ZIP_PATH: ${{ steps.download-zip.outputs.zip-path }} - name: Run 'Upload plugin' test id: run-upload-test @@ -686,10 +689,10 @@ jobs: GITHUB_TOKEN: ${{ secrets.REPORTS_TOKEN }} run: | gh workflow run publish-test-reports-release.yml \ - -f created_at="${{ needs.get-tag.outputs.created }}" \ + -f created_at="${{ needs.validate-version.outputs.created }}" \ -f run_id=${{ github.run_id }} \ -f run_number=${{ github.run_number }} \ - -f release_tag=${{ needs.get-tag.outputs.tag }} \ + -f release_tag=${{ needs.validate-version.outputs.version }} \ -f artifact="${{ env.ARTIFACT_NAME }}" \ -f env_description="${{ matrix.env_description }}" \ -f test_type="e2e" \ @@ -704,7 +707,7 @@ jobs: test-name: With ${{ matrix.plugin }} e2e-result: ${{ steps.run-e2e-composite-action.outputs.result }} env-slug: ${{ matrix.env_description }} - release-version: ${{ needs.get-tag.outputs.tag }} + release-version: ${{ needs.validate-version.outputs.version }} post-slack-summary: name: Post Slack summary @@ -717,7 +720,7 @@ jobs: ) needs: - e2e-wp-latest - - get-tag + - validate-version - test-php-versions - test-plugins - test-wp-latest-1 @@ -735,7 +738,7 @@ jobs: id: run-payload-action uses: ./.github/actions/tests/slack-summary-on-release/slack-payload with: - release-version: ${{ needs.get-tag.outputs.tag }} + release-version: ${{ needs.validate-version.outputs.version }} blocks-dir: ${{ steps.download-slack-blocks.outputs.download-path }} - name: Send Slack message diff --git a/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js b/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js index 2766e939639..80689772d13 100644 --- a/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js +++ b/plugins/woocommerce/tests/api-core-tests/ci-release.global-setup.js @@ -1,23 +1,19 @@ const { UPDATE_WC, USER_KEY, USER_SECRET } = process.env; -const { test, expect } = require( '@playwright/test' ); -const path = require( 'path' ); +const { test: setup, expect } = require( '@playwright/test' ); const fs = require( 'fs' ); +const { downloadWooCommerceRelease } = require( './utils/plugin-utils' ); +const pluginEndpoint = '/wp-json/wp/v2/plugins/woocommerce/woocommerce'; -const zipPath = path.resolve( 'tmp', 'woocommerce.zip' ); -const downloadURL = `https://github.com/woocommerce/woocommerce/releases/download/${ UPDATE_WC }/woocommerce.zip`; +let zipPath; -test( `Setup remote test site`, async ( { page, request } ) => { - test.setTimeout( 5 * 60 * 1000 ); +setup( `Setup remote test site`, async ( { page, request } ) => { + setup.setTimeout( 5 * 60 * 1000 ); - await test.step( `Download WooCommerce build zip`, async () => { - const response = await request.get( downloadURL ); - expect( response.ok() ).toBeTruthy(); - const body = await response.body(); - fs.mkdirSync( 'tmp', { recursive: true } ); - fs.writeFileSync( zipPath, body ); + await setup.step( `Download WooCommerce build zip`, async () => { + zipPath = await downloadWooCommerceRelease( { request } ); } ); - await test.step( 'Login to wp-admin', async () => { + await setup.step( 'Login to wp-admin', async () => { const Username = 'Username or Email Address'; const Password = 'Password'; const Log_In = 'Log In'; @@ -35,67 +31,83 @@ test( `Setup remote test site`, async ( { page, request } ) => { ).toBeVisible(); } ); - await test.step( `Deactivate currently installed WooCommerce version`, async () => { - const response = await request.put( - '/wp-json/wp/v2/plugins/woocommerce/woocommerce', - { + const installed = await setup.step( + `See if there's a WooCommerce plugin installed`, + async () => { + const response = await request.get( pluginEndpoint ); + const isOK = response.ok(); + const status = response.status(); + + // Fast-fail if response was neither OK nor 404. + expect( isOK || status === 404 ).toEqual( true ); + + return isOK; + } + ); + + await setup.step( + `Deactivate currently installed WooCommerce version`, + async () => { + if ( ! installed ) { + return; + } + + const options = { data: { status: 'inactive', }, + }; + const response = await request.put( pluginEndpoint, options ); + expect( response.ok() ).toBeTruthy(); + } + ); + + await setup.step( + `Delete currently installed WooCommerce version`, + async () => { + if ( ! installed ) { + return; } - ); - expect( response.ok() ).toBeTruthy(); - } ); - await test.step( `Delete currently installed WooCommerce version`, async () => { - const response = await request.delete( - '/wp-json/wp/v2/plugins/woocommerce/woocommerce' - ); - expect( response.ok() ).toBeTruthy(); - } ); + const response = await request.delete( pluginEndpoint ); + expect( response.ok() ).toBeTruthy(); + } + ); - await test.step( `Install WooCommerce ${ UPDATE_WC }`, async () => { + await setup.step( `Install WooCommerce ${ UPDATE_WC }`, async () => { const Upload_Plugin = 'Upload Plugin'; const Plugin_zip_file = 'Plugin zip file'; const Install_Now = 'Install Now'; const Activate_Plugin = 'Activate Plugin'; + const timeout = 3 * 60 * 1000; await page.goto( '/wp-admin/plugin-install.php' ); await page.getByRole( 'button', { name: Upload_Plugin } ).click(); await page.getByLabel( Plugin_zip_file ).setInputFiles( zipPath ); - const uploadPromise = page.waitForResponse( - '/wp-admin/update.php?action=upload-plugin' - ); await page.getByRole( 'button', { name: Install_Now } ).click(); - const uploadResponse = await uploadPromise; - expect( uploadResponse.ok() ).toBeTruthy(); await expect( page.getByRole( 'link', { name: Activate_Plugin } ) - ).toBeVisible(); + ).toBeVisible( { timeout } ); } ); - await test.step( `Activate WooCommerce`, async () => { - const response = await request.put( - '/wp-json/wp/v2/plugins/woocommerce/woocommerce', - { - data: { - status: 'active', - }, - } - ); + await setup.step( `Activate WooCommerce`, async () => { + const options = { + data: { + status: 'active', + }, + }; + const response = await request.put( pluginEndpoint, options ); expect( response.ok() ).toBeTruthy(); } ); - await test.step( `Verify WooCommerce version was installed`, async () => { - const response = await request.get( - '/wp-json/wp/v2/plugins/woocommerce/woocommerce' - ); + await setup.step( `Verify WooCommerce version was installed`, async () => { + const response = await request.get( pluginEndpoint ); const { status, version } = await response.json(); expect( status ).toEqual( 'active' ); expect( version ).toEqual( UPDATE_WC ); } ); - await test.step( `Verify WooCommerce database version`, async () => { + await setup.step( `Verify WooCommerce database version`, async () => { const response = await request.get( '/wp-json/wc/v3/system_status' ); const { database } = await response.json(); const { wc_database_version } = database; @@ -104,7 +116,7 @@ test( `Setup remote test site`, async ( { page, request } ) => { expect( wc_database_version ).toMatch( pattern ); } ); - await test.step( `Delete zip`, async () => { + await setup.step( `Delete zip`, async () => { fs.unlinkSync( zipPath ); } ); } ); diff --git a/plugins/woocommerce/tests/api-core-tests/utils/plugin-utils.js b/plugins/woocommerce/tests/api-core-tests/utils/plugin-utils.js index a3be326a9a5..c147e2565b0 100644 --- a/plugins/woocommerce/tests/api-core-tests/utils/plugin-utils.js +++ b/plugins/woocommerce/tests/api-core-tests/utils/plugin-utils.js @@ -1,10 +1,25 @@ -const { APIRequest } = require( '@playwright/test' ); +const { APIRequest, expect } = require( '@playwright/test' ); const axios = require( 'axios' ).default; const fs = require( 'fs' ); const path = require( 'path' ); const { promisify } = require( 'util' ); const execAsync = promisify( require( 'child_process' ).exec ); +/** + * GitHub [release asset](https://docs.github.com/en/rest/releases/assets?apiVersion=2022-11-28) object. + * @typedef {Object} ReleaseAsset + * @property {string} name + * @property {string} url + */ + +/** + * GitHub [release](https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28) object. + * @typedef {Object} Release + * @property {ReleaseAsset[]} assets + * @property {string} tag_name + * @property {string} name + */ + /** * Encode basic auth username and password to be used in HTTP Authorization header. * @@ -258,3 +273,94 @@ export const installPluginThruWpCli = async ( pluginPath ) => { await runWpCliCommand( `wp plugin list` ); }; + +/** + * Download the WooCommerce release zip. Can download draft releases when `token` is specified. + * + * @param {Object} params + * @param {import("@playwright/test").APIRequestContext} params.request + * @param {string} params.version The version indicated in the release `tag_name` or `name` field. + * @param {string} params.token + * @param {string} params.downloadDir + * + * @throws When `version` was not found. + * + * @returns {Promise} Absolute path to the downloaded WooCommerce zip. + */ +export const downloadWooCommerceRelease = async ( { + request, + version = process.env.UPDATE_WC, + token = process.env.GITHUB_TOKEN, + downloadDir = 'tmp', +} ) => { + /** + * + * @returns {Promise} + */ + const getRelease = async () => { + const url = + 'https://api.github.com/repos/woocommerce/woocommerce/releases'; + const options = { + params: { + per_page: 100, + }, + headers: { + Authorization: token ? `Bearer ${ token }` : undefined, + }, + }; + const response = await request.get( url, options ); + + /** + * @type {Release[]} + */ + const releases = await response.json(); + + const match = releases.find( ( { tag_name, name } ) => + [ tag_name, name ].includes( version ) + ); + + if ( ! match ) { + throw new Error( `Release ${ version } not found!` ); + } + + return match; + }; + + /** + * + * @param {Release} release + * @throws When `release` does not contain a woocommerce zip. + * @returns {ReleaseAsset} + */ + const getWooCommerceZipAsset = ( release ) => { + const zipName = + version.toLowerCase() === 'nightly' + ? 'woocommerce-trunk-nightly.zip' + : 'woocommerce.zip'; + const asset = release.assets.find( ( { name } ) => name === zipName ); + + if ( ! asset ) { + throw new Error( + `Release ${ version } does not contain a WooCommerce ZIP asset` + ); + } + + return asset; + }; + + const release = await getRelease(); + const asset = getWooCommerceZipAsset( release ); + const downloadResponse = await request.get( asset.url, { + headers: { + Authorization: token ? `Bearer ${ token }` : undefined, + Accept: 'application/octet-stream', + }, + } ); + expect( downloadResponse.ok() ).toBeTruthy(); + const body = await downloadResponse.body(); + const zipPath = path.resolve( downloadDir, asset.name ); + fs.mkdirSync( path.resolve( downloadDir ), { recursive: true } ); + fs.writeFileSync( zipPath, body ); + + return zipPath; +}; diff --git a/plugins/woocommerce/tests/e2e-pw/tests/smoke-tests/update-woocommerce.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/smoke-tests/update-woocommerce.spec.js index 689d8f9db6f..2b968b55fb2 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/smoke-tests/update-woocommerce.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/smoke-tests/update-woocommerce.spec.js @@ -63,17 +63,17 @@ const getWCDownloadURL = async () => { throw new Error( error.message ); } ); - const releaseWithTagName = response.data.find( - ( { tag_name } ) => tag_name === UPDATE_WC + const release = response.data.find( ( { tag_name, name } ) => + [ tag_name, name ].includes( UPDATE_WC ) ); - if ( ! releaseWithTagName ) { + if ( ! release ) { throw new Error( - `No release with tag_name="${ UPDATE_WC }" found. If "${ UPDATE_WC }" is a draft release, make sure to specify a GITHUB_TOKEN environment variable.` + `Release "${ UPDATE_WC }" not found. If "${ UPDATE_WC }" is a draft release, make sure to specify a GITHUB_TOKEN environment variable.` ); } - const wcZipAsset = releaseWithTagName.assets.find( ( { name } ) => + const wcZipAsset = release.assets.find( ( { name } ) => name.match( /^woocommerce(-trunk-nightly)?\.zip$/ ) ); @@ -82,7 +82,7 @@ const getWCDownloadURL = async () => { } throw new Error( - `WooCommerce release with tag "${ UPDATE_WC }" found, but does not have a WooCommerce ZIP asset.` + `Release "${ UPDATE_WC }" found, but does not have a WooCommerce ZIP asset.` ); }; @@ -91,6 +91,8 @@ skipTestIfUndefined(); test.describe.serial( 'WooCommerce update', () => { test.use( { storageState: ADMINSTATE } ); + test.setTimeout( 5 * 60 * 1000 ); + test.beforeAll( async () => { await test.step( 'Download WooCommerce zip from GitHub', async () => { const url = await getWCDownloadURL(); @@ -135,18 +137,15 @@ test.describe.serial( 'WooCommerce update', () => { await page.waitForLoadState( 'networkidle' ); } ); - await test.step( - 'Choose the option "Replace current with uploaded"', - async () => { - await page - .locator( '.button-primary.update-from-upload-overwrite' ) - .click(); - await page.waitForLoadState( 'networkidle' ); - await expect( - page.getByText( 'Plugin updated successfully.' ) - ).toBeVisible(); - } - ); + await test.step( 'Choose the option "Replace current with uploaded"', async () => { + await page + .locator( '.button-primary.update-from-upload-overwrite' ) + .click(); + await page.waitForLoadState( 'networkidle' ); + await expect( + page.getByText( 'Plugin updated successfully.' ) + ).toBeVisible(); + } ); await test.step( 'Go to "Installed plugins" page', async () => { await page.goto( 'wp-admin/plugins.php', { @@ -154,45 +153,38 @@ test.describe.serial( 'WooCommerce update', () => { } ); } ); - await test.step( - 'Assert that "WooCommerce" is listed and active', - async () => { - await expect( - page.locator( '.plugin-title strong', { - hasText: /^WooCommerce$/, - } ) - ).toBeVisible(); - await expect( - page.locator( '#deactivate-woocommerce' ) - ).toBeVisible(); - } - ); + await test.step( 'Assert that "WooCommerce" is listed and active', async () => { + await expect( + page.locator( '.plugin-title strong', { + hasText: /^WooCommerce$/, + } ) + ).toBeVisible(); + await expect( + page.locator( '#deactivate-woocommerce' ) + ).toBeVisible(); + } ); if ( UPDATE_WC !== 'nightly' ) { - await test.step( - 'Verify that WooCommerce was updated to the expected version', - async () => { - const api = new wcApi( { - url: baseURL, - consumerKey: process.env.CONSUMER_KEY, - consumerSecret: process.env.CONSUMER_SECRET, - version: 'wc/v3', + await test.step( 'Verify that WooCommerce was updated to the expected version', async () => { + const api = new wcApi( { + url: baseURL, + consumerKey: process.env.CONSUMER_KEY, + consumerSecret: process.env.CONSUMER_SECRET, + version: 'wc/v3', + } ); + + const response = await api + .get( 'system_status' ) + .catch( ( error ) => { + throw new Error( error.message ); } ); - const response = await api - .get( 'system_status' ) - .catch( ( error ) => { - throw new Error( error.message ); - } ); + const wcPluginData = response.data.active_plugins.find( + ( { plugin } ) => plugin === 'woocommerce/woocommerce.php' + ); - const wcPluginData = response.data.active_plugins.find( - ( { plugin } ) => - plugin === 'woocommerce/woocommerce.php' - ); - - expect( wcPluginData.version ).toEqual( UPDATE_WC ); - } - ); + expect( wcPluginData.version ).toEqual( UPDATE_WC ); + } ); } } ); @@ -208,40 +200,34 @@ test.describe.serial( 'WooCommerce update', () => { } ); } ); - await test.step( - 'Skip this test if the "Update WooCommerce Database" button did not appear', - async () => { - test.skip( - ! ( await updateButton.isVisible() ), - 'The "Update WooCommerce Database" button did not appear after updating WooCommerce. Verify with the team if the WooCommerce version being tested does not really trigger a database update.' - ); - } - ); + await test.step( 'Skip this test if the "Update WooCommerce Database" button did not appear', async () => { + test.skip( + ! ( await updateButton.isVisible() ), + 'The "Update WooCommerce Database" button did not appear after updating WooCommerce. Verify with the team if the WooCommerce version being tested does not really trigger a database update.' + ); + } ); await test.step( 'Notice appeared. Start DB update', async () => { await updateButton.click(); await page.waitForLoadState( 'networkidle' ); } ); - await test.step( - 'Assert that the notice "WooCommerce database update complete." appears', - async () => { - await expect - .poll( - async () => { - await page.goto( 'wp-admin/plugins.php', { - waitUntil: 'networkidle', - } ); + await test.step( 'Assert that the notice "WooCommerce database update complete." appears', async () => { + await expect + .poll( + async () => { + await page.goto( 'wp-admin/plugins.php', { + waitUntil: 'networkidle', + } ); - return await updateCompleteMessage.isVisible(); - }, - { - intervals: [ 10_000 ], - timeout: 120_000, - } - ) - .toEqual( true ); - } - ); + return await updateCompleteMessage.isVisible(); + }, + { + intervals: [ 10_000 ], + timeout: 120_000, + } + ) + .toEqual( true ); + } ); } ); } ); From de22698dc76a034d13713fab357d75e029ed79ee Mon Sep 17 00:00:00 2001 From: Rodel Calasagsag Date: Sat, 14 Oct 2023 16:20:47 +0800 Subject: [PATCH 7/8] Add changelog --- plugins/woocommerce/changelog/dev-release-test-wooaf-drafts | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 plugins/woocommerce/changelog/dev-release-test-wooaf-drafts diff --git a/plugins/woocommerce/changelog/dev-release-test-wooaf-drafts b/plugins/woocommerce/changelog/dev-release-test-wooaf-drafts new file mode 100644 index 00000000000..c9a77118b85 --- /dev/null +++ b/plugins/woocommerce/changelog/dev-release-test-wooaf-drafts @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Update release test workflow to support release drafts. From a1e6d8828a5d0179d1bf4a9566479b285178dda4 Mon Sep 17 00:00:00 2001 From: Rodel Calasagsag Date: Tue, 17 Oct 2023 11:21:32 +0800 Subject: [PATCH 8/8] Delete extra changelog --- .../woocommerce/changelog/dev-fix-release-test-global-setup | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 plugins/woocommerce/changelog/dev-fix-release-test-global-setup diff --git a/plugins/woocommerce/changelog/dev-fix-release-test-global-setup b/plugins/woocommerce/changelog/dev-fix-release-test-global-setup deleted file mode 100644 index 05349fe2554..00000000000 --- a/plugins/woocommerce/changelog/dev-fix-release-test-global-setup +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: dev - -Fix global setup for release tests.