From a927d30fad44eef8d04c6ca8c0849c71b708477b Mon Sep 17 00:00:00 2001 From: Andrey Belym Date: Thu, 17 Nov 2022 15:38:44 +0400 Subject: [PATCH] test: use github actions to test safari (closes #7322) --- .github/workflows/deploy-to-artifacts.yml | 2 + .../test-functional-local-safari.yml | 103 ++++++++++++++++++ Gulpfile.js | 6 + test/functional/config.js | 21 +++- .../fixtures/regression/gh-845/test.js | 2 +- test/functional/fixtures/reporter/test.js | 5 +- test/functional/fixtures/ui/test.js | 2 +- test/functional/safari-connector.js | 29 +++++ test/functional/setup.js | 2 + 9 files changed, 164 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/test-functional-local-safari.yml create mode 100644 test/functional/safari-connector.js diff --git a/.github/workflows/deploy-to-artifacts.yml b/.github/workflows/deploy-to-artifacts.yml index 567d7e4cbe..b4ed586df5 100644 --- a/.github/workflows/deploy-to-artifacts.yml +++ b/.github/workflows/deploy-to-artifacts.yml @@ -173,6 +173,8 @@ jobs: tasks.push('test-functional-local-proxyless.yml'); tasks.push('test-functional-local-legacy.yml'); + + tasks.push('test-functional-local-safari.yml'); tasks.push('test-functional-remote-macos.yml'); tasks.push('test-functional-remote-mobile.yml'); diff --git a/.github/workflows/test-functional-local-safari.yml b/.github/workflows/test-functional-local-safari.yml new file mode 100644 index 0000000000..f0e201d119 --- /dev/null +++ b/.github/workflows/test-functional-local-safari.yml @@ -0,0 +1,103 @@ +name: Test Functional (Local Safari) + +on: + workflow_dispatch: + inputs: + sha: + description: 'The test commit SHA or ref' + required: true + default: 'master' + merged_sha: + description: 'The merge commit SHA' + deploy_run_id: + description: 'The ID of a deployment workspace run with artifacts' +jobs: + test: + runs-on: macos-12 + environment: test-functional + env: + RETRY_FAILED_TESTS: true + steps: + - run: sudo safaridriver --enable + - uses: actions/github-script@v3 + with: + script: | + await github.repos.createCommitStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + sha: context.payload.inputs.sha, + context: context.workflow, + state: 'pending', + target_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` + }); + - uses: actions/checkout@v2 + with: + ref: ${{github.event.inputs.merged_sha || github.event.inputs.sha}} + + - uses: actions/setup-node@v2 + with: + node-version: 14 + + - uses: actions/github-script@v3 + with: + script: | + const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); + + let artifacts = {}; + + for(let i = 0;i<36&&!artifacts.total_count;i++,await delay(5000)) { + try { + ({ data: artifacts } = await github.actions.listWorkflowRunArtifacts({ + repo: context.repo.repo, + owner: context.repo.owner, + run_id: context.payload.inputs.deploy_run_id + })); + } + catch (e) { + console.log(e); + } + } + + const { data: artifact } = await github.request(artifacts.artifacts.find(artifact=> artifact.name === 'npm').archive_download_url); + require('fs').writeFileSync(require('path').join(process.env.GITHUB_WORKSPACE, 'package.zip'), Buffer.from(artifact)) + + - run: | + unzip package.zip + tar --strip-components=1 -xzf testcafe-*.tgz + + - name: Get npm cache directory + id: npm-cache-dir + run: | + echo "::set-output name=dir::$(npm config get cache)" + - uses: actions/cache@v2 + with: + path: ${{ steps.npm-cache-dir.outputs.dir }} + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + - run: npm ci + - run: npx gulp test-functional-local-safari-run --steps-as-tasks + timeout-minutes: 60 + - uses: actions/github-script@v3 + with: + script: | + await github.repos.createCommitStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + sha: context.payload.inputs.sha, + context: context.workflow, + state: 'success', + target_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` + }); + - uses: actions/github-script@v3 + if: failure() || cancelled() + with: + script: | + await github.repos.createCommitStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + sha: context.payload.inputs.sha, + context: context.workflow, + state: 'failure', + target_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` + }); diff --git a/Gulpfile.js b/Gulpfile.js index 1bfe09be70..e2d943849c 100644 --- a/Gulpfile.js +++ b/Gulpfile.js @@ -388,6 +388,12 @@ gulp.step('test-functional-local-headless-firefox-run', () => { gulp.task('test-functional-local-headless-firefox', gulp.series('prepare-tests', 'test-functional-local-headless-firefox-run')); +gulp.step('test-functional-local-safari-run', () => { + return testFunctional(TESTS_GLOB, functionalTestConfig.testingEnvironmentNames.localSafari); +}); + +gulp.task('test-functional-local-safari', gulp.series('prepare-tests', 'test-functional-local-safari-run')); + gulp.step('test-functional-remote-run', () => { if (QR_CODE) process.env.QR_CODE = 'true'; diff --git a/test/functional/config.js b/test/functional/config.js index 1d3fea69ab..8c7a468208 100644 --- a/test/functional/config.js +++ b/test/functional/config.js @@ -4,6 +4,7 @@ const browserProviderNames = { sauceLabs: 'sauceLabs', browserstack: 'browserstack', remote: 'remote', + safari: 'safari', }; const testingEnvironmentNames = { @@ -13,6 +14,7 @@ const testingEnvironmentNames = { localBrowsersChromeFirefox: 'local-browsers-chrome-firefox', localBrowsers: 'local-browsers', localChrome: 'local-chrome', + localSafari: 'local-safari', localHeadlessChrome: 'local-headless-chrome', localHeadlessFirefox: 'local-headless-firefox', remote: 'remote', @@ -31,10 +33,6 @@ testingEnvironments[testingEnvironmentNames.osXDesktopAndMSEdgeBrowsers] = { }, browsers: [ - { - browserName: 'browserstack:safari', - alias: 'safari', - }, { browserName: 'browserstack:edge:OS X Monterey', alias: 'edge', @@ -144,6 +142,21 @@ testingEnvironments[testingEnvironmentNames.localHeadlessChrome] = { ], }; +testingEnvironments[testingEnvironmentNames.localSafari] = { + remote: true, + provider: browserProviderNames.safari, + + safari: {}, + + browsers: [ + { + browserName: 'safari', + userAgent: 'safari', + alias: 'safari', + }, + ], +}; + testingEnvironments[testingEnvironmentNames.localHeadlessFirefox] = { isLocalBrowsers: true, isHeadlessBrowsers: true, diff --git a/test/functional/fixtures/regression/gh-845/test.js b/test/functional/fixtures/regression/gh-845/test.js index 7a758443bb..603447c41d 100644 --- a/test/functional/fixtures/regression/gh-845/test.js +++ b/test/functional/fixtures/regression/gh-845/test.js @@ -1,7 +1,7 @@ // NOTE: we skip 'iphone,ipad' because no way to download file by link on these devices describe('[Regression](GH-845) Should execute click on a download link', function () { it('gh-845', function () { - return runTests('testcafe-fixtures/index-test.js', 'Click on a download link', { skip: ['iphone', 'ipad', 'android'] }); + return runTests('testcafe-fixtures/index-test.js', 'Click on a download link', { skip: ['iphone', 'ipad', 'android', 'safari'] }); }); it('gh-845 in iframe', function () { diff --git a/test/functional/fixtures/reporter/test.js b/test/functional/fixtures/reporter/test.js index 0d678553c8..bb5a240c51 100644 --- a/test/functional/fixtures/reporter/test.js +++ b/test/functional/fixtures/reporter/test.js @@ -18,7 +18,7 @@ const del = require('del'); const experimentalDebug = !!process.env.EXPERIMENTAL_DEBUG; -describe('Reporter', () => { +(config.hasBrowser('chrome') ? describe : describe.skip)('Reporter', () => { const stdoutWrite = process.stdout.write; const stderrWrite = process.stderr.write; @@ -1198,7 +1198,8 @@ describe('Reporter', () => { } }); - it('Should work with option from configuration file', () => { + it('Should work with option from configuration file', function () { + return runTestsWithConfig('Simple test', './test/functional/fixtures/reporter/configs/xunit-config.js') .then(() => { const pathReport = path.resolve(__dirname, 'report.xml'); diff --git a/test/functional/fixtures/ui/test.js b/test/functional/fixtures/ui/test.js index c928f31f4d..a109bf59b5 100644 --- a/test/functional/fixtures/ui/test.js +++ b/test/functional/fixtures/ui/test.js @@ -4,6 +4,6 @@ describe('TestCafe UI', () => { }); it('Hide elements when resizing the window', () => { - return runTests('./testcafe-fixtures/status-bar-test.js', 'Hide elements when resizing the window', { skip: ['android', 'ipad', 'iphone', 'edge'] }); + return runTests('./testcafe-fixtures/status-bar-test.js', 'Hide elements when resizing the window', { skip: ['android', 'ipad', 'iphone', 'edge', 'safari'] }); }); }); diff --git a/test/functional/safari-connector.js b/test/functional/safari-connector.js new file mode 100644 index 0000000000..5e9d1a1a86 --- /dev/null +++ b/test/functional/safari-connector.js @@ -0,0 +1,29 @@ +const { exec } = require('child_process'); +const debug = require('debug'); + + +const DEBUG = debug('testcafe:test:functional:safari-connector'); + +module.exports = class SafariConnector { + connect () { + return Promise.resolve(); + } + + waitForFreeMachines () { + return Promise.resolve(); + } + + startBrowser (settings, url) { + exec(`open -a /Applications/Safari.app ${url}`, (...args) => DEBUG(args)); + + return Promise.resolve(); + } + + stopBrowser () { + return Promise.resolve(); + } + + disconnect () { + return Promise.resolve(); + } +}; diff --git a/test/functional/setup.js b/test/functional/setup.js index 13b823e361..d91035bc45 100644 --- a/test/functional/setup.js +++ b/test/functional/setup.js @@ -9,6 +9,7 @@ const BrowserConnection = require('../../lib/browser/connection'); const config = require('./config.js'); const site = require('./site'); const RemoteConnector = require('./remote-connector'); +const SafariConnector = require('./safari-connector'); const getTestError = require('./get-test-error.js'); const { createSimpleTestStream } = require('./utils/stream'); const BrowserConnectionStatus = require('../../lib/browser/connection/status'); @@ -40,6 +41,7 @@ const REMOTE_CONNECTORS_MAP = { [config.browserProviderNames.browserstack]: BsConnector, [config.browserProviderNames.sauceLabs]: SlConnector, [config.browserProviderNames.remote]: RemoteConnector, + [config.browserProviderNames.safari]: SafariConnector, }; const USE_PROVIDER_POOL = config.useLocalBrowsers || isBrowserStack;