From d19647495ff7b56df9ce7e54c63294255d1ac254 Mon Sep 17 00:00:00 2001 From: Shveta Sachdeva Date: Thu, 10 Oct 2024 20:27:30 -0700 Subject: [PATCH 1/9] Initial framework commit for playwright tests Signed-off-by: Shveta Sachdeva --- package.json | 9 ++ pages/launch_vscode.page.js | 45 ++++++ playwright.config.ts | 79 ++++++++++ scripts/populate-konveyor.sh | 290 +++++++++++++++++++++++++++++++++++ tests/vscode.test.ts | 35 +++++ 5 files changed, 458 insertions(+) create mode 100755 package.json create mode 100644 pages/launch_vscode.page.js create mode 100755 playwright.config.ts create mode 100755 scripts/populate-konveyor.sh create mode 100644 tests/vscode.test.ts diff --git a/package.json b/package.json new file mode 100755 index 00000000..6b863511 --- /dev/null +++ b/package.json @@ -0,0 +1,9 @@ +{ + "devDependencies": { + "@playwright/test": "^1.48.0", + "@types/node": "^22.7.5", + "electron": "^32.2.0", + "playwright-electron": "^0.5.0" + }, + "scripts": {} +} diff --git a/pages/launch_vscode.page.js b/pages/launch_vscode.page.js new file mode 100644 index 00000000..c2654dea --- /dev/null +++ b/pages/launch_vscode.page.js @@ -0,0 +1,45 @@ +// launch_vscode.page.js +const { _electron: electron } = require('playwright'); +const path = require('path'); +const fs = require('fs'); + +class LaunchVSCodePage { + constructor() { + this.vscodeApp = null; + this.window = null; + } + + async launchVSCode(executablePath) { + this.vscodeApp = await electron.launch({ + executablePath: executablePath, // Path to VSCode executable + }); + + } + + async installExtensionFromVSIX(vsixFilePath) { + if (!fs.existsSync(vsixFilePath)) { + throw new Error(`VSIX file not found at path: ${vsixFilePath}`); + } + + await this.window.click('.activity-bar a[title="Extensions"]'); + await this.window.waitForSelector('.extensions-viewlet'); + + // Click on the "More Actions" (three dots menu) in the Extensions view + await this.window.click('.extensions-viewlet .action-item .codicon-ellipsis'); + + // Click on "Install from VSIX..." + await this.window.click('.context-view .menu-item span:has-text("Install from VSIX...")'); + + const inputSelector = 'input[type="file"]'; + await this.window.setInputFiles(inputSelector, vsixFilePath); + + await this.window.waitForSelector('.extension-list-item .uninstall', { timeout: 60000 }); + } + + async closeVSCode() { + // Close the VSCode application + await this.vscodeApp.close(); + } +} + +module.exports = { LaunchVSCodePage }; \ No newline at end of file diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100755 index 00000000..a05d8b5a --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,79 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// import dotenv from 'dotenv'; +// import path from 'path'; +// dotenv.config({ path: path.resolve(__dirname, '.env') }); + +/** + * 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'] }, + }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // url: 'http://127.0.0.1:3000', + // reuseExistingServer: !process.env.CI, + // }, +}); diff --git a/scripts/populate-konveyor.sh b/scripts/populate-konveyor.sh new file mode 100755 index 00000000..1326d4ca --- /dev/null +++ b/scripts/populate-konveyor.sh @@ -0,0 +1,290 @@ +#!/bin/bash + +baseName="Test" +count=10 + +declare -A app1=( + [name]="Tackle-testapp public" + [url]="https://github.com/abrugaro/tackle-testapp-public" + [oldBranch]="main" + [newBranch]="hardcode-ip-fix" + [target]="cloud-readiness" +) + +declare -A app2=( + [name]="Day Trader" + [url]="https://github.com/abrugaro/sample.daytrader7.git" + [oldBranch]="master" + [newBranch]="fixes" + [target]="cloud-readiness" +) + +declare -A app3=( + [name]="Ticket Monster" + [url]="https://github.com/jmle/monolith.git" + [oldBranch]="master" + [newBranch]="quarkus" + [target]="quarkus" +) + +declare -A app4=( + [name]="Hello world" + [url]="https://github.com/savitharaghunathan/helloworld-mdb.git" + [oldBranch]="main" + [newBranch]="quarkus" + [target]="quarkus" +) + +apps=("app1" "app2" "app3" "app4") +declare -A createdApps + +pid=$$ +self=$(basename $0) +tmp=/tmp/${self}-${pid} + +usage() { + echo "Usage: ${self} " + echo "Auth has to be disabled in order to execute this script" + echo "-h help" + echo "Required:" + echo " -u /hub" + echo "Options:" + echo " -b base name (Test)" + echo " -n count (10)" + echo " -o output" +} + +while getopts "u:b:n:o:h" arg; do + case $arg in + u) + host=$OPTARG + ;; + b) + baseName=$OPTARG + ;; + n) + count=$OPTARG + ;; + o) + output=$OPTARG + ;; + h) + usage + exit 1 + ;; + *) + usage + exit 1 + ;; + esac +done + +if [ -z "${host}" ]; then + echo "-u required." + usage + exit 0 +fi + +print() { + if [ -n "$output" ]; then + echo -e "$@" >>"$output" + else + echo -e "$@" + fi +} + +echo +echo "Host: ${host}" +echo "Name: ${baseName}" +echo "Count: ${count}" +echo +answer="y" +read -rp "Continue[Y,n]: " answer +if [ "$answer" != "y" ]; then + exit 0 +fi + +createAnalysis() { + appId=$1 + appName=$2 + appTarget=$3 + d=" +{ + \"name\": \"taskgroup.analyzer\", + \"kind\": \"analyzer\", + \"state\": \"Created\", + \"priority\": 10, + \"data\": { + \"tagger\": { + \"enabled\": true + }, + \"mode\": { + \"binary\": false, + \"withDeps\": true + }, + \"rules\": { + \"labels\": { + \"included\": [ + \"konveyor.io/target=${appTarget}\" + ] + } + } + }, + \"tasks\": [ + { + \"name\": \"${appName}.${appId}.windup\", + \"application\": { + \"id\": ${appId}, + \"name\": \"${appName}\" + } + } + ] +}" + + # Create TaskGroup + code=$(curl -kSs -o "$tmp" -w "%{http_code}" -X POST "${host}/taskgroups" -H 'Content-Type:application/json' -H 'Accept: application/json' -d "$d") + ret=$? + if [ ! $ret -eq 0 ]; then + exit $ret + fi + case ${code} in + 201) + taskGroupId=$(jq .id "$tmp") + print "TaskGroup $taskGroupId CREATED Taskgroup for application: $appName id=${appId}" + ;; + *) + print "Create task for: appId=${appId} - FAILED: $code." + cat "$tmp" + exit 1 + ;; + esac + + # Start analysis + code=$(curl -kSs -o "$tmp" -w "%{http_code}" -X PUT "${host}/taskgroups/${taskGroupId}/submit" -H 'Content-Type:application/json' -d "$d") + ret=$? + if [ ! $ret -eq 0 ]; then + exit $ret + fi + case ${code} in + 204) + id=$(jq .id "$tmp") + print "Analysis $id STARTED for application: $appName id=${appId}" + ;; + *) + print "Start analysis for: appId=${appId} - FAILED: $code." + cat "$tmp" + exit 1 + ;; + esac +} + +updateBranch() { + appId=$1 + appName=$2 + repositoryUrl=$3 + newBranch=$4 + d=" +--- +name: $appName +description: $appName Test application. +repository: + kind: git + branch: $newBranch + url: $repositoryUrl +tags: +" + code=$(curl -kSs -o "$tmp" -w "%{http_code}" -X PUT "${host}/applications/${appId}" -H 'Content-Type:application/x-yaml' -d "$d") + ret=$? + if [ ! $ret -eq 0 ]; then + exit $ret + fi + case $code in + 204) + print "Application $appName id=${appId} - UPDATED" + ;; + *) + print "Update application $appName - FAILED: $code." + cat "$tmp" + exit 1 + ;; + esac +} + +waitForAnalyses() { + while true; do + code=$(curl -kSs -o "$tmp" -w "%{http_code}" "${host}/tasks/report/queue") + total=$(jq .total "$tmp") + + if [ "$total" -eq 0 ]; then + echo "All analyses are finished" + break + fi + + echo "Some analyses are still running, waiting 30 secs..." + sleep 30 + done +} + +createApplications() { + for i in $(seq 1 "$count"); do + + randomApp=${apps[$RANDOM % ${#apps[@]}]} + + appName="$(eval echo \${"${randomApp}"[name]})-$i" + appUrl=$(eval echo \${"${randomApp}"[url]}) + appBranch=$(eval echo \${"${randomApp}"[oldBranch]}) + appTarget=$(eval echo \${"${randomApp}"[target]}) + + d=" +--- +name: $appName +description: $appName Test application. +repository: + kind: git + branch: $appBranch + url: $appUrl +tags: +- id: 16 +" + code=$(curl -kSs -o "$tmp" -w "%{http_code}" -X POST "${host}"/applications -H 'Content-Type:application/x-yaml' -d "$d") + ret=$? + if [ ! $ret -eq 0 ]; then + exit $ret + fi + case $code in + 201) + id=$(jq .id "$tmp") + print "Application $appName id=${id} - CREATED" + + createdApps["${id}"]="${randomApp}" + + createAnalysis "$id" "$appName" "$appTarget" + ;; + *) + print "Create application $appName - FAILED: $code." + cat "$tmp" + exit 1 + ;; + esac + done + + waitForAnalyses + + for appId in "${!createdApps[@]}"; do + appKey="${createdApps[$appId]}" + + appName=$(eval echo \${"${appKey}"[name]}) + appUrl=$(eval echo \${"${appKey}"[url]}) + appTarget=$(eval echo \${"${appKey}"[target]}) + appNewBranch=$(eval echo \${"${appKey}"[newBranch]}) + + updateBranch "$appId" "${appName}-${appId}" "$appUrl" "$appNewBranch" + + createAnalysis "$appId" "${appName}-${appId}" "$appTarget" + done + + waitForAnalyses + +} + +createApplications diff --git a/tests/vscode.test.ts b/tests/vscode.test.ts new file mode 100644 index 00000000..48256670 --- /dev/null +++ b/tests/vscode.test.ts @@ -0,0 +1,35 @@ +// vscode.spec.js +const { test, expect } = require('@playwright/test'); +const { LaunchVSCodePage } = require('../pages/launch_vscode.page'); +const path = require('path'); + +test.describe('VSCode Extension Installation from VSIX', () => { + test('should install extension from a VSIX file in VSCode', async ({page}) => { + + // Path to the VSCode executable + const vscodeExecutablePath = '/usr/bin/code'; // Change this to the actual path + + // Path to the VSIX file + const vsixFilePath = path.resolve(__dirname, '/home/sshveta/Downloads/kai-vscode-plugin-0.0.3.vsix'); // Provide the path to your VSIX file + + // Create a new instance of the LaunchVSCodePage + const launchVSCodePage = new LaunchVSCodePage(); + await new Promise(resolve => setTimeout(resolve, 20000)); // 20,000 milliseconds = 20 seconds + // await page.pause(); + + // Launch VSCode + await launchVSCodePage.launchVSCode(vscodeExecutablePath); + + // Install the extension from the VSIX file + await launchVSCodePage.installExtensionFromVSIX(vsixFilePath); + await page.pause(); + // Optionally verify if the extension was installed successfully + const uninstallButton = await launchVSCodePage.window.$('.extension-list-item .uninstall'); + expect(uninstallButton).not.toBeNull(); + + // Close VSCode after installation + await launchVSCodePage.closeVSCode(); + }); +}); + + \ No newline at end of file From 5fd5ecd6e6996820b2d702984574064cbe17f1d6 Mon Sep 17 00:00:00 2001 From: Shveta Sachdeva Date: Thu, 10 Oct 2024 21:25:08 -0700 Subject: [PATCH 2/9] README Signed-off-by: Shveta Sachdeva --- e2e/pages/launch_vscode.page.js | 45 +++++++++++++++++++++++++++++++++ e2e/tests/vscode.test.ts | 35 +++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 e2e/pages/launch_vscode.page.js create mode 100644 e2e/tests/vscode.test.ts diff --git a/e2e/pages/launch_vscode.page.js b/e2e/pages/launch_vscode.page.js new file mode 100644 index 00000000..c2654dea --- /dev/null +++ b/e2e/pages/launch_vscode.page.js @@ -0,0 +1,45 @@ +// launch_vscode.page.js +const { _electron: electron } = require('playwright'); +const path = require('path'); +const fs = require('fs'); + +class LaunchVSCodePage { + constructor() { + this.vscodeApp = null; + this.window = null; + } + + async launchVSCode(executablePath) { + this.vscodeApp = await electron.launch({ + executablePath: executablePath, // Path to VSCode executable + }); + + } + + async installExtensionFromVSIX(vsixFilePath) { + if (!fs.existsSync(vsixFilePath)) { + throw new Error(`VSIX file not found at path: ${vsixFilePath}`); + } + + await this.window.click('.activity-bar a[title="Extensions"]'); + await this.window.waitForSelector('.extensions-viewlet'); + + // Click on the "More Actions" (three dots menu) in the Extensions view + await this.window.click('.extensions-viewlet .action-item .codicon-ellipsis'); + + // Click on "Install from VSIX..." + await this.window.click('.context-view .menu-item span:has-text("Install from VSIX...")'); + + const inputSelector = 'input[type="file"]'; + await this.window.setInputFiles(inputSelector, vsixFilePath); + + await this.window.waitForSelector('.extension-list-item .uninstall', { timeout: 60000 }); + } + + async closeVSCode() { + // Close the VSCode application + await this.vscodeApp.close(); + } +} + +module.exports = { LaunchVSCodePage }; \ No newline at end of file diff --git a/e2e/tests/vscode.test.ts b/e2e/tests/vscode.test.ts new file mode 100644 index 00000000..48256670 --- /dev/null +++ b/e2e/tests/vscode.test.ts @@ -0,0 +1,35 @@ +// vscode.spec.js +const { test, expect } = require('@playwright/test'); +const { LaunchVSCodePage } = require('../pages/launch_vscode.page'); +const path = require('path'); + +test.describe('VSCode Extension Installation from VSIX', () => { + test('should install extension from a VSIX file in VSCode', async ({page}) => { + + // Path to the VSCode executable + const vscodeExecutablePath = '/usr/bin/code'; // Change this to the actual path + + // Path to the VSIX file + const vsixFilePath = path.resolve(__dirname, '/home/sshveta/Downloads/kai-vscode-plugin-0.0.3.vsix'); // Provide the path to your VSIX file + + // Create a new instance of the LaunchVSCodePage + const launchVSCodePage = new LaunchVSCodePage(); + await new Promise(resolve => setTimeout(resolve, 20000)); // 20,000 milliseconds = 20 seconds + // await page.pause(); + + // Launch VSCode + await launchVSCodePage.launchVSCode(vscodeExecutablePath); + + // Install the extension from the VSIX file + await launchVSCodePage.installExtensionFromVSIX(vsixFilePath); + await page.pause(); + // Optionally verify if the extension was installed successfully + const uninstallButton = await launchVSCodePage.window.$('.extension-list-item .uninstall'); + expect(uninstallButton).not.toBeNull(); + + // Close VSCode after installation + await launchVSCodePage.closeVSCode(); + }); +}); + + \ No newline at end of file From f47de851299d345902d9c9bdd3f013968fc4e53c Mon Sep 17 00:00:00 2001 From: Shveta Sachdeva Date: Thu, 10 Oct 2024 21:26:26 -0700 Subject: [PATCH 3/9] README Signed-off-by: Shveta Sachdeva --- README.md | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 59a9732d..692da5f2 100644 --- a/README.md +++ b/README.md @@ -1 +1,63 @@ -# kai-ci \ No newline at end of file +# kai-ci +# VSCode Automation with Playwright + +This repository contains automated tests using Playwright to launch Visual Studio Code (VSCode) and install a specified extension from a VSIX file. + +## Table of Contents + +- [Features](#features) +- [Prerequisites](#prerequisites) +- [Installation](#installation) +- [Usage](#usage) +- [Test Structure](#test-structure) +- [Running Tests](#running-tests) +- [Contributing](#contributing) +- [License](#license) + +## Features + +- Launch Visual Studio Code as an Electron application. +- Install extensions from VSIX files. +- Basic test structure using Playwright's page object model. + +## Prerequisites + +Before you begin, ensure you have met the following requirements: + +- Node.js installed (version 14 or later). +- Playwright installed. You can install it using npm. +- Visual Studio Code installed on your system. + +## Installation + +1. **Clone the Repository** + + git clone https://github.com/konveyor/kai-ci + cd kai-ci + +2. **Install Dependencies** + + Install the required packages using npm: + + # npm install + +3. **Install Playwright Browsers** + To ensure Playwright is set up correctly, run: + # npx playwright install + +## Usage +Configuration + + Modify the vscode.spec.js file to specify the correct path to your VSIX file and VSCode executable. + + # const vscodeExecutablePath = '/path/to/your/VSCode/executable'; + # const vsixFilePath = '/path/to/your/extension.vsix'; + +## Running Tests + To run the automated tests, use the following command: + + # npx playwright test + + This command will execute all tests defined in your repository. You can also run a specific test file: + + # npx playwright test vscode.spec.js From 6946aa9ef0f412c569d0326ccbf7820a1df71d1f Mon Sep 17 00:00:00 2001 From: Shveta Sachdeva Date: Thu, 10 Oct 2024 21:27:19 -0700 Subject: [PATCH 4/9] README Signed-off-by: Shveta Sachdeva --- pages/launch_vscode.page.js | 45 ------------------------------------- tests/vscode.test.ts | 35 ----------------------------- 2 files changed, 80 deletions(-) delete mode 100644 pages/launch_vscode.page.js delete mode 100644 tests/vscode.test.ts diff --git a/pages/launch_vscode.page.js b/pages/launch_vscode.page.js deleted file mode 100644 index c2654dea..00000000 --- a/pages/launch_vscode.page.js +++ /dev/null @@ -1,45 +0,0 @@ -// launch_vscode.page.js -const { _electron: electron } = require('playwright'); -const path = require('path'); -const fs = require('fs'); - -class LaunchVSCodePage { - constructor() { - this.vscodeApp = null; - this.window = null; - } - - async launchVSCode(executablePath) { - this.vscodeApp = await electron.launch({ - executablePath: executablePath, // Path to VSCode executable - }); - - } - - async installExtensionFromVSIX(vsixFilePath) { - if (!fs.existsSync(vsixFilePath)) { - throw new Error(`VSIX file not found at path: ${vsixFilePath}`); - } - - await this.window.click('.activity-bar a[title="Extensions"]'); - await this.window.waitForSelector('.extensions-viewlet'); - - // Click on the "More Actions" (three dots menu) in the Extensions view - await this.window.click('.extensions-viewlet .action-item .codicon-ellipsis'); - - // Click on "Install from VSIX..." - await this.window.click('.context-view .menu-item span:has-text("Install from VSIX...")'); - - const inputSelector = 'input[type="file"]'; - await this.window.setInputFiles(inputSelector, vsixFilePath); - - await this.window.waitForSelector('.extension-list-item .uninstall', { timeout: 60000 }); - } - - async closeVSCode() { - // Close the VSCode application - await this.vscodeApp.close(); - } -} - -module.exports = { LaunchVSCodePage }; \ No newline at end of file diff --git a/tests/vscode.test.ts b/tests/vscode.test.ts deleted file mode 100644 index 48256670..00000000 --- a/tests/vscode.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -// vscode.spec.js -const { test, expect } = require('@playwright/test'); -const { LaunchVSCodePage } = require('../pages/launch_vscode.page'); -const path = require('path'); - -test.describe('VSCode Extension Installation from VSIX', () => { - test('should install extension from a VSIX file in VSCode', async ({page}) => { - - // Path to the VSCode executable - const vscodeExecutablePath = '/usr/bin/code'; // Change this to the actual path - - // Path to the VSIX file - const vsixFilePath = path.resolve(__dirname, '/home/sshveta/Downloads/kai-vscode-plugin-0.0.3.vsix'); // Provide the path to your VSIX file - - // Create a new instance of the LaunchVSCodePage - const launchVSCodePage = new LaunchVSCodePage(); - await new Promise(resolve => setTimeout(resolve, 20000)); // 20,000 milliseconds = 20 seconds - // await page.pause(); - - // Launch VSCode - await launchVSCodePage.launchVSCode(vscodeExecutablePath); - - // Install the extension from the VSIX file - await launchVSCodePage.installExtensionFromVSIX(vsixFilePath); - await page.pause(); - // Optionally verify if the extension was installed successfully - const uninstallButton = await launchVSCodePage.window.$('.extension-list-item .uninstall'); - expect(uninstallButton).not.toBeNull(); - - // Close VSCode after installation - await launchVSCodePage.closeVSCode(); - }); -}); - - \ No newline at end of file From 567e7328ac2203c0a8cc04218e4222c6e6569745 Mon Sep 17 00:00:00 2001 From: Shveta Sachdeva Date: Thu, 10 Oct 2024 21:28:04 -0700 Subject: [PATCH 5/9] README Signed-off-by: Shveta Sachdeva --- populate-konveyor.sh | 292 ------------------------------------------- 1 file changed, 292 deletions(-) delete mode 100644 populate-konveyor.sh diff --git a/populate-konveyor.sh b/populate-konveyor.sh deleted file mode 100644 index e1ec4878..00000000 --- a/populate-konveyor.sh +++ /dev/null @@ -1,292 +0,0 @@ -#!/bin/bash - -baseName="Test" -count=10 - -declare -A app1=( - [name]="Tackle-testapp public" - [url]="https://github.com/abrugaro/tackle-testapp-public" - [oldBranch]="main" - [newBranch]="hardcode-ip-fix" - [target]="cloud-readiness" -) - -declare -A app2=( - [name]="Day Trader" - [url]="https://github.com/abrugaro/sample.daytrader7.git" - [oldBranch]="master" - [newBranch]="fixes" - [target]="cloud-readiness" -) - -declare -A app3=( - [name]="Ticket Monster" - [url]="https://github.com/jmle/monolith.git" - [oldBranch]="master" - [newBranch]="quarkus" - [target]="quarkus" -) - -declare -A app4=( - [name]="Hello world" - [url]="https://github.com/savitharaghunathan/helloworld-mdb.git" - [oldBranch]="main" - [newBranch]="quarkus" - [target]="quarkus" -) - -apps=("app1" "app2" "app3" "app4") -declare -A createdApps - -pid=$$ -self=$(basename $0) -tmp=/tmp/${self}-${pid} - -usage() { - echo "Usage: ${self} " - echo "-h help" - echo "Auth has to be disabled in order to execute this script" - echo "Required:" - echo " -u URL of the hub" - echo "Example:" - echo " ${self} -u htps://my-konveyor-instance/hub -n 5" - echo "Options:" - echo " -b base name (Test)" - echo " -n count (10)" - echo " -o output" -} - -while getopts "u:b:n:o:h" arg; do - case $arg in - u) - host=$OPTARG - ;; - b) - baseName=$OPTARG - ;; - n) - count=$OPTARG - ;; - o) - output=$OPTARG - ;; - h) - usage - exit 1 - ;; - *) - usage - exit 1 - ;; - esac -done - -if [ -z "${host}" ]; then - echo "-u required." - usage - exit 0 -fi - -print() { - if [ -n "$output" ]; then - echo -e "$@" >>"$output" - else - echo -e "$@" - fi -} - -echo -echo "Host: ${host}" -echo "Name: ${baseName}" -echo "Count: ${count}" -echo -answer="y" -read -rp "Continue[Y,n]: " answer -if [ "$answer" != "y" ]; then - exit 0 -fi - -createAnalysis() { - appId=$1 - appName=$2 - appTarget=$3 - d=" -{ - \"name\": \"taskgroup.analyzer\", - \"kind\": \"analyzer\", - \"state\": \"Created\", - \"priority\": 10, - \"data\": { - \"tagger\": { - \"enabled\": true - }, - \"mode\": { - \"binary\": false, - \"withDeps\": true - }, - \"rules\": { - \"labels\": { - \"included\": [ - \"konveyor.io/target=${appTarget}\" - ] - } - } - }, - \"tasks\": [ - { - \"name\": \"${appName}.${appId}.windup\", - \"application\": { - \"id\": ${appId}, - \"name\": \"${appName}\" - } - } - ] -}" - - # Create TaskGroup - code=$(curl -kSs -o "$tmp" -w "%{http_code}" -X POST "${host}/taskgroups" -H 'Content-Type:application/json' -H 'Accept: application/json' -d "$d") - ret=$? - if [ ! $ret -eq 0 ]; then - exit $ret - fi - case ${code} in - 201) - taskGroupId=$(jq .id "$tmp") - print "TaskGroup $taskGroupId CREATED Taskgroup for application: $appName id=${appId}" - ;; - *) - print "Create task for: appId=${appId} - FAILED: $code." - cat "$tmp" - exit 1 - ;; - esac - - # Start analysis - code=$(curl -kSs -o "$tmp" -w "%{http_code}" -X PUT "${host}/taskgroups/${taskGroupId}/submit" -H 'Content-Type:application/json' -d "$d") - ret=$? - if [ ! $ret -eq 0 ]; then - exit $ret - fi - case ${code} in - 204) - id=$(jq .id "$tmp") - print "Analysis $id STARTED for application: $appName id=${appId}" - ;; - *) - print "Start analysis for: appId=${appId} - FAILED: $code." - cat "$tmp" - exit 1 - ;; - esac -} - -updateBranch() { - appId=$1 - appName=$2 - repositoryUrl=$3 - newBranch=$4 - d=" ---- -name: $appName -description: $appName Test application. -repository: - kind: git - branch: $newBranch - url: $repositoryUrl -tags: -" - code=$(curl -kSs -o "$tmp" -w "%{http_code}" -X PUT "${host}/applications/${appId}" -H 'Content-Type:application/x-yaml' -d "$d") - ret=$? - if [ ! $ret -eq 0 ]; then - exit $ret - fi - case $code in - 204) - print "Application $appName id=${appId} - UPDATED" - ;; - *) - print "Update application $appName - FAILED: $code." - cat "$tmp" - exit 1 - ;; - esac -} - -waitForAnalyses() { - while true; do - code=$(curl -kSs -o "$tmp" -w "%{http_code}" "${host}/tasks/report/queue") - total=$(jq .total "$tmp") - - if [ "$total" -eq 0 ]; then - echo "All analyses are finished" - break - fi - - echo "Some analyses are still running, waiting 1 min..." - sleep 60 - done -} - -createApplications() { - for i in $(seq 1 "$count"); do - - randomApp=${apps[$RANDOM % ${#apps[@]}]} - - appName="$(eval echo \${"${randomApp}"[name]})-$i" - appUrl=$(eval echo \${"${randomApp}"[url]}) - appBranch=$(eval echo \${"${randomApp}"[oldBranch]}) - appTarget=$(eval echo \${"${randomApp}"[target]}) - - d=" ---- -name: $appName -description: $appName Test application. -repository: - kind: git - branch: $appBranch - url: $appUrl -tags: -- id: 16 -" - code=$(curl -kSs -o "$tmp" -w "%{http_code}" -X POST "${host}"/applications -H 'Content-Type:application/x-yaml' -d "$d") - ret=$? - if [ ! $ret -eq 0 ]; then - exit $ret - fi - case $code in - 201) - id=$(jq .id "$tmp") - print "Application $appName id=${id} - CREATED" - - createdApps["${id}"]="${randomApp}" - - createAnalysis "$id" "$appName" "$appTarget" - ;; - *) - print "Create application $appName - FAILED: $code." - cat "$tmp" - exit 1 - ;; - esac - done - - waitForAnalyses - - for appId in "${!createdApps[@]}"; do - appKey="${createdApps[$appId]}" - - appName=$(eval echo \${"${appKey}"[name]}) - appUrl=$(eval echo \${"${appKey}"[url]}) - appTarget=$(eval echo \${"${appKey}"[target]}) - appNewBranch=$(eval echo \${"${appKey}"[newBranch]}) - - updateBranch "$appId" "${appName}-${appId}" "$appUrl" "$appNewBranch" - - createAnalysis "$appId" "${appName}-${appId}" "$appTarget" - done - - waitForAnalyses - -} - -createApplications From 8b8570f70979adde21143b5cb7137c70700ebd9a Mon Sep 17 00:00:00 2001 From: Shveta Sachdeva Date: Mon, 14 Oct 2024 17:13:23 -0700 Subject: [PATCH 6/9] Improved code Signed-off-by: Shveta Sachdeva --- README.md | 9 ++- e2e/pages/launch_vscode.page.js | 45 -------------- e2e/pages/vscode.pages.ts | 68 ++++++++++++++++++++ e2e/tests/vscode.test.ts | 44 +++++-------- package.json | 106 +++++++++++++++++++++++++++++++- playwright.config.ts | 59 +++--------------- 6 files changed, 203 insertions(+), 128 deletions(-) delete mode 100644 e2e/pages/launch_vscode.page.js create mode 100644 e2e/pages/vscode.pages.ts diff --git a/README.md b/README.md index 692da5f2..d9d184a3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # kai-ci + # VSCode Automation with Playwright -This repository contains automated tests using Playwright to launch Visual Studio Code (VSCode) and install a specified extension from a VSIX file. +This repository contains automated tests using Playwright to launch Visual Studio Code (VSCode) and install a specified extension from a VSIX file. ## Table of Contents @@ -46,6 +47,7 @@ Before you begin, ensure you have met the following requirements: # npx playwright install ## Usage + Configuration Modify the vscode.spec.js file to specify the correct path to your VSIX file and VSCode executable. @@ -54,6 +56,7 @@ Configuration # const vsixFilePath = '/path/to/your/extension.vsix'; ## Running Tests + To run the automated tests, use the following command: # npx playwright test @@ -61,3 +64,7 @@ Configuration This command will execute all tests defined in your repository. You can also run a specific test file: # npx playwright test vscode.spec.js + + To format tests , use + + # npm run format diff --git a/e2e/pages/launch_vscode.page.js b/e2e/pages/launch_vscode.page.js deleted file mode 100644 index c2654dea..00000000 --- a/e2e/pages/launch_vscode.page.js +++ /dev/null @@ -1,45 +0,0 @@ -// launch_vscode.page.js -const { _electron: electron } = require('playwright'); -const path = require('path'); -const fs = require('fs'); - -class LaunchVSCodePage { - constructor() { - this.vscodeApp = null; - this.window = null; - } - - async launchVSCode(executablePath) { - this.vscodeApp = await electron.launch({ - executablePath: executablePath, // Path to VSCode executable - }); - - } - - async installExtensionFromVSIX(vsixFilePath) { - if (!fs.existsSync(vsixFilePath)) { - throw new Error(`VSIX file not found at path: ${vsixFilePath}`); - } - - await this.window.click('.activity-bar a[title="Extensions"]'); - await this.window.waitForSelector('.extensions-viewlet'); - - // Click on the "More Actions" (three dots menu) in the Extensions view - await this.window.click('.extensions-viewlet .action-item .codicon-ellipsis'); - - // Click on "Install from VSIX..." - await this.window.click('.context-view .menu-item span:has-text("Install from VSIX...")'); - - const inputSelector = 'input[type="file"]'; - await this.window.setInputFiles(inputSelector, vsixFilePath); - - await this.window.waitForSelector('.extension-list-item .uninstall', { timeout: 60000 }); - } - - async closeVSCode() { - // Close the VSCode application - await this.vscodeApp.close(); - } -} - -module.exports = { LaunchVSCodePage }; \ No newline at end of file diff --git a/e2e/pages/vscode.pages.ts b/e2e/pages/vscode.pages.ts new file mode 100644 index 00000000..3e51086c --- /dev/null +++ b/e2e/pages/vscode.pages.ts @@ -0,0 +1,68 @@ +// launch_vscode.page.ts +import { _electron as electron, ElectronApplication, Page } from "playwright"; +import { expect } from "@playwright/test"; +import * as fs from "fs"; + +class LaunchVSCodePage { + private vscodeApp: ElectronApplication | null = null; + private window: Page | null = null; + + public async launchVSCode(executablePath): Promise { + this.vscodeApp = await electron.launch({ + executablePath: executablePath, // Path to VSCode executable + }); + this.window = await this.vscodeApp.firstWindow(); + + const title = await this.window.title(); + console.log(`VSCode window title: ${title}`); + + expect(title).toContain("Visual Studio Code"); + } + + public async installExtensionFromVSIX(vsixFilePath): Promise { + if (!fs.existsSync(vsixFilePath)) { + throw new Error(`VSIX file not found at path: ${vsixFilePath}`); + } + + if (!this.window) { + throw new Error("VSCode window is not initialized."); + } + + const extensionsTab = await this.window.getByRole("tab", { + name: "Extensions (Ctrl+Shift+X)", + }); + await extensionsTab.locator("a").waitFor({ state: "visible" }); + await extensionsTab.locator("a").click({ force: true }); + + const extensionsActionsButton = + await this.window.getByLabel("Extensions actions"); + await extensionsActionsButton.click(); + + // Find the "Views and More Actions..." inside the Extensions actions and click it + const moreActionsButton = await extensionsActionsButton.getByLabel( + "Views and More Actions...", + ); + await moreActionsButton.click(); + + await this.window.click( + '.context-view .menu-item span:has-text("Install from VSIX...")', + ); + // Set the file input for the VSIX file + const inputSelector = 'input[type="file"]'; + await this.window.setInputFiles(inputSelector, vsixFilePath); + + // Wait for the uninstall button to appear indicating the extension is installed + await this.window.waitForSelector(".extension-list-item .uninstall", { + timeout: 60000, + }); + } + + // Method to close VSCode + public async closeVSCode(): Promise { + if (this.vscodeApp) { + await this.vscodeApp.close(); + } + } +} + +export { LaunchVSCodePage }; diff --git a/e2e/tests/vscode.test.ts b/e2e/tests/vscode.test.ts index 48256670..01161103 100644 --- a/e2e/tests/vscode.test.ts +++ b/e2e/tests/vscode.test.ts @@ -1,35 +1,19 @@ -// vscode.spec.js -const { test, expect } = require('@playwright/test'); -const { LaunchVSCodePage } = require('../pages/launch_vscode.page'); -const path = require('path'); +import { test } from "@playwright/test"; +import { LaunchVSCodePage } from "../pages/vscode.pages"; -test.describe('VSCode Extension Installation from VSIX', () => { - test('should install extension from a VSIX file in VSCode', async ({page}) => { - - // Path to the VSCode executable - const vscodeExecutablePath = '/usr/bin/code'; // Change this to the actual path +test.describe("VSCode Extension Installation from VSIX", () => { + const vscodePage = new LaunchVSCodePage(); - // Path to the VSIX file - const vsixFilePath = path.resolve(__dirname, '/home/sshveta/Downloads/kai-vscode-plugin-0.0.3.vsix'); // Provide the path to your VSIX file - - // Create a new instance of the LaunchVSCodePage - const launchVSCodePage = new LaunchVSCodePage(); - await new Promise(resolve => setTimeout(resolve, 20000)); // 20,000 milliseconds = 20 seconds - // await page.pause(); - - // Launch VSCode - await launchVSCodePage.launchVSCode(vscodeExecutablePath); - - // Install the extension from the VSIX file - await launchVSCodePage.installExtensionFromVSIX(vsixFilePath); - await page.pause(); - // Optionally verify if the extension was installed successfully - const uninstallButton = await launchVSCodePage.window.$('.extension-list-item .uninstall'); - expect(uninstallButton).not.toBeNull(); + test("VSCode launches and has correct window title", async () => { + const executablePath = process.env.VSCODE_EXECUTABLE_PATH; + await vscodePage.launchVSCode(executablePath); + }); - // Close VSCode after installation - await launchVSCodePage.closeVSCode(); + test("should install extension from a VSIX file in VSCode", async ({ + page, + }) => { + const vsixFilePath = process.env.VSIX_FILE_PATH; + await vscodePage.installExtensionFromVSIX(vsixFilePath); + await page.pause(); }); }); - - \ No newline at end of file diff --git a/package.json b/package.json index 6b863511..386cdd2b 100755 --- a/package.json +++ b/package.json @@ -3,7 +3,109 @@ "@playwright/test": "^1.48.0", "@types/node": "^22.7.5", "electron": "^32.2.0", - "playwright-electron": "^0.5.0" + "playwright-electron": "^0.5.0", + "prettier": "^3.3.3" }, - "scripts": {} + "scripts": { + "check": "prettier --check './**/*.{ts,js,json}'", + "format": "prettier --write './**/*.{ts,js,json}'" + }, + "name": "kai-ci", + "version": "1.0.0", + "description": "This repository contains automated tests using Playwright to launch Visual Studio Code (VSCode) and install a specified extension from a VSIX file.", + "main": "index.js", + "directories": { + "test": "tests" + }, + "dependencies": { + "agent-base": "^6.0.2", + "balanced-match": "^1.0.2", + "boolean": "^3.2.0", + "brace-expansion": "^1.1.11", + "buffer-crc32": "^0.2.13", + "cacheable-lookup": "^5.0.4", + "cacheable-request": "^7.0.4", + "clone-response": "^1.0.3", + "concat-map": "^0.0.1", + "debug": "^4.3.7", + "decompress-response": "^6.0.0", + "defer-to-connect": "^2.0.1", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "detect-node": "^2.1.0", + "dotenv": "^16.4.5", + "end-of-stream": "^1.4.4", + "env-paths": "^2.2.1", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es6-error": "^4.1.1", + "escape-string-regexp": "^4.0.0", + "extract-zip": "^2.0.1", + "fd-slicer": "^1.1.0", + "fs-extra": "^8.1.0", + "fs.realpath": "^1.0.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "get-stream": "^5.2.0", + "glob": "^7.2.3", + "global-agent": "^3.0.0", + "globalthis": "^1.0.4", + "gopd": "^1.0.1", + "got": "^11.8.6", + "graceful-fs": "^4.2.11", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "http-cache-semantics": "^4.1.1", + "http2-wrapper": "^1.0.3", + "https-proxy-agent": "^5.0.1", + "inflight": "^1.0.6", + "inherits": "^2.0.4", + "jpeg-js": "^0.4.4", + "json-buffer": "^3.0.1", + "json-stringify-safe": "^5.0.1", + "jsonfile": "^4.0.0", + "keyv": "^4.5.4", + "lowercase-keys": "^2.0.0", + "matcher": "^3.0.0", + "mime": "^2.6.0", + "mimic-response": "^1.0.1", + "minimatch": "^3.1.2", + "ms": "^2.1.3", + "normalize-url": "^6.1.0", + "object-keys": "^1.1.1", + "once": "^1.4.0", + "p-cancelable": "^2.1.1", + "path-is-absolute": "^1.0.1", + "pend": "^1.2.0", + "playwright": "^1.48.0", + "playwright-core": "^1.48.0", + "pngjs": "^5.0.0", + "progress": "^2.0.3", + "proper-lockfile": "^4.1.2", + "proxy-from-env": "^1.1.0", + "pump": "^3.0.2", + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.1", + "responselike": "^2.0.1", + "retry": "^0.12.0", + "rimraf": "^3.0.2", + "roarr": "^2.15.4", + "semver": "^6.3.1", + "semver-compare": "^1.0.0", + "serialize-error": "^7.0.1", + "signal-exit": "^3.0.7", + "sprintf-js": "^1.1.3", + "sumchecker": "^3.0.1", + "type-fest": "^0.13.1", + "undici-types": "^6.19.8", + "universalify": "^0.1.2", + "wrappy": "^1.0.2", + "ws": "^7.5.10", + "yauzl": "^2.10.0" + }, + "keywords": [], + "author": "", + "license": "ISC" } diff --git a/playwright.config.ts b/playwright.config.ts index a05d8b5a..e3e879c3 100755 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,75 +1,34 @@ -import { defineConfig, devices } from '@playwright/test'; +import { defineConfig, devices } from "@playwright/test"; +import dotenv from "dotenv"; /** * Read environment variables from file. * https://github.com/motdotla/dotenv */ -// import dotenv from 'dotenv'; -// import path from 'path'; -// dotenv.config({ path: path.resolve(__dirname, '.env') }); + +import path from "path"; +dotenv.config({ path: path.resolve(__dirname, ".env") }); /** * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ - testDir: './tests', - /* Run tests in files in parallel */ + testDir: "./e2e/tests", + 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', + 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', + 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'] }, - }, - - /* Test against mobile viewports. */ - // { - // name: 'Mobile Chrome', - // use: { ...devices['Pixel 5'] }, - // }, - // { - // name: 'Mobile Safari', - // use: { ...devices['iPhone 12'] }, - // }, - - /* Test against branded browsers. */ - // { - // name: 'Microsoft Edge', - // use: { ...devices['Desktop Edge'], channel: 'msedge' }, - // }, - // { - // name: 'Google Chrome', - // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, - // }, - ], - /* Run your local dev server before starting the tests */ // webServer: { // command: 'npm run start', From b21f7bafa58466070699eab28a4522f6adccb7c3 Mon Sep 17 00:00:00 2001 From: Shveta Sachdeva Date: Tue, 15 Oct 2024 14:12:38 -0700 Subject: [PATCH 7/9] Improved code Signed-off-by: Shveta Sachdeva --- .env.example | 11 +++++ .prettierrc | 6 +++ README.md | 53 ++++++++++----------- e2e/pages/vscode.pages.ts | 92 +++++++++++++++++++++++------------- e2e/tests/vscode.test.ts | 41 +++++++++++----- scripts/populate-konveyor.sh | 10 ++-- 6 files changed, 135 insertions(+), 78 deletions(-) create mode 100644 .env.example create mode 100644 .prettierrc diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..65189ab9 --- /dev/null +++ b/.env.example @@ -0,0 +1,11 @@ +#################### +### EXAMPLE FILE ### +#################### + +# Do NOT edit this file unless adding new env variables +# Instead, copy it, remove the .example extension and provide your custom values +# For git password please use your generated git token, not a clear text password + + +VSCODE_EXECUTABLE_PATH='/usr/share/code/code' +VSIX_FILE_PATH='kai-vscode-plugin-0.0.3.vsix' diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..3481057b --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "semi": true, + "trailingComma": "es5", + "tabWidth": 2 +} diff --git a/README.md b/README.md index d9d184a3..70146b81 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -# kai-ci - # VSCode Automation with Playwright This repository contains automated tests using Playwright to launch Visual Studio Code (VSCode) and install a specified extension from a VSIX file. @@ -17,54 +15,55 @@ This repository contains automated tests using Playwright to launch Visual Studi ## Features -- Launch Visual Studio Code as an Electron application. -- Install extensions from VSIX files. -- Basic test structure using Playwright's page object model. + Launch Visual Studio Code as an Electron application. + Install extensions from VSIX files. + Basic test structure using Playwright's Page Object Model. ## Prerequisites -Before you begin, ensure you have met the following requirements: +Before you begin, ensure you have the following: -- Node.js installed (version 14 or later). -- Playwright installed. You can install it using npm. -- Visual Studio Code installed on your system. + Node.js (version 14 or later) installed. + Playwright installed. You can install it using npm. + Visual Studio Code installed on your system. ## Installation 1. **Clone the Repository** - git clone https://github.com/konveyor/kai-ci - cd kai-ci +`git clone https://github.com/konveyor/kai-ci` +`cd kai-ci` 2. **Install Dependencies** - Install the required packages using npm: +Install the required packages using npm: - # npm install +`npm install` -3. **Install Playwright Browsers** - To ensure Playwright is set up correctly, run: - # npx playwright install ## Usage -Configuration - - Modify the vscode.spec.js file to specify the correct path to your VSIX file and VSCode executable. + Create .env file and copy the content of .env.example into it and provide appropriate values: - # const vscodeExecutablePath = '/path/to/your/VSCode/executable'; - # const vsixFilePath = '/path/to/your/extension.vsix'; + VSCODE_EXECUTABLE_PATH='/usr/share/code/code' + VSIX_FILE_PATH='/home/sshveta/Downloads/kai-vscode-plugin-0.0.3.vsix' ## Running Tests - To run the automated tests, use the following command: +To run the automated tests, use the following command: + +`npx playwright test` + +This command will execute all tests in your repository. To run a specific test file: + +`npx playwright test vscode.test.ts` - # npx playwright test +#### Code formatting using Prettier tool - This command will execute all tests defined in your repository. You can also run a specific test file: +1. Format code - # npx playwright test vscode.spec.js + `npm run format` - To format tests , use +2. Check formatting - # npm run format + `npm run check` diff --git a/e2e/pages/vscode.pages.ts b/e2e/pages/vscode.pages.ts index 3e51086c..872b0a3d 100644 --- a/e2e/pages/vscode.pages.ts +++ b/e2e/pages/vscode.pages.ts @@ -1,13 +1,24 @@ // launch_vscode.page.ts -import { _electron as electron, ElectronApplication, Page } from "playwright"; -import { expect } from "@playwright/test"; -import * as fs from "fs"; +import { _electron as electron, ElectronApplication, Page } from 'playwright'; +import { execSync } from 'child_process'; +import { expect } from '@playwright/test'; +import * as fs from 'fs'; class LaunchVSCodePage { private vscodeApp: ElectronApplication | null = null; private window: Page | null = null; public async launchVSCode(executablePath): Promise { + // Get the VSIX file path from environment variable + const vsixFilePath = process.env.VSIX_FILE_PATH; + + if (vsixFilePath) { + // Pass the environment variable to the method + this.installExtensionFromVSIX(vsixFilePath); + } else { + console.error('Error: VSIX_FILE_PATH is not set in the environment.'); + } + // this.installExtensionFromVSIX(process.env.VSIX_FILE_PATH) this.vscodeApp = await electron.launch({ executablePath: executablePath, // Path to VSCode executable }); @@ -16,45 +27,58 @@ class LaunchVSCodePage { const title = await this.window.title(); console.log(`VSCode window title: ${title}`); - expect(title).toContain("Visual Studio Code"); + expect(title).toContain('Visual Studio Code'); } - public async installExtensionFromVSIX(vsixFilePath): Promise { - if (!fs.existsSync(vsixFilePath)) { - throw new Error(`VSIX file not found at path: ${vsixFilePath}`); - } + // public async installExtensionFromVSIX(vsixFilePath): Promise { + // if (!fs.existsSync(vsixFilePath)) { + // throw new Error(`VSIX file not found at path: ${vsixFilePath}`); + // } - if (!this.window) { - throw new Error("VSCode window is not initialized."); - } + // if (!this.window) { + // throw new Error("VSCode window is not initialized."); + // } - const extensionsTab = await this.window.getByRole("tab", { - name: "Extensions (Ctrl+Shift+X)", - }); - await extensionsTab.locator("a").waitFor({ state: "visible" }); - await extensionsTab.locator("a").click({ force: true }); + // const extensionsTab = await this.window.getByRole("tab", { + // name: "Extensions (Ctrl+Shift+X)", + // }); + // await extensionsTab.locator("a").waitFor({ state: "visible" }); + // await extensionsTab.locator("a").click({ force: true }); - const extensionsActionsButton = - await this.window.getByLabel("Extensions actions"); - await extensionsActionsButton.click(); + // const extensionsActionsButton = + // await this.window.getByLabel("Extensions actions"); + // await extensionsActionsButton.click(); - // Find the "Views and More Actions..." inside the Extensions actions and click it - const moreActionsButton = await extensionsActionsButton.getByLabel( - "Views and More Actions...", - ); - await moreActionsButton.click(); + // // Find the "Views and More Actions..." inside the Extensions actions and click it + // const moreActionsButton = await extensionsActionsButton.getByLabel( + // "Views and More Actions...", + // ); + // await moreActionsButton.click(); - await this.window.click( - '.context-view .menu-item span:has-text("Install from VSIX...")', - ); - // Set the file input for the VSIX file - const inputSelector = 'input[type="file"]'; - await this.window.setInputFiles(inputSelector, vsixFilePath); + // await this.window.click( + // '.context-view .menu-item span:has-text("Install from VSIX...")', + // ); + // // Set the file input for the VSIX file + // const inputSelector = 'input[type="file"]'; + // await this.window.setInputFiles(inputSelector, vsixFilePath); - // Wait for the uninstall button to appear indicating the extension is installed - await this.window.waitForSelector(".extension-list-item .uninstall", { - timeout: 60000, - }); + // // Wait for the uninstall button to appear indicating the extension is installed + // await this.window.waitForSelector(".extension-list-item .uninstall", { + // timeout: 60000, + // }); + // } + + public installExtensionFromVSIX(vsixFilePath: string): void { + // Install VSCode extension using terminal command + try { + console.log(`Installing extension from ${vsixFilePath}...`); + execSync(`code --install-extension ${vsixFilePath}`, { + stdio: 'inherit', + }); + console.log('Extension installed successfully'); + } catch (error) { + console.error('Error installing the VSIX extension:', error); + } } // Method to close VSCode diff --git a/e2e/tests/vscode.test.ts b/e2e/tests/vscode.test.ts index 01161103..4445e58f 100644 --- a/e2e/tests/vscode.test.ts +++ b/e2e/tests/vscode.test.ts @@ -1,19 +1,34 @@ -import { test } from "@playwright/test"; -import { LaunchVSCodePage } from "../pages/vscode.pages"; +import { test, expect } from '@playwright/test'; +import { LaunchVSCodePage } from '../pages/vscode2.pages'; -test.describe("VSCode Extension Installation from VSIX", () => { - const vscodePage = new LaunchVSCodePage(); +test.describe('VSCode Tests', () => { + let vscodeApp: LaunchVSCodePage; - test("VSCode launches and has correct window title", async () => { - const executablePath = process.env.VSCODE_EXECUTABLE_PATH; - await vscodePage.launchVSCode(executablePath); + test.beforeAll(async () => { + const executablePath = + process.env.VSCODE_EXECUTABLE_PATH || '/usr/share/code/code'; + vscodeApp = await LaunchVSCodePage.launchVSCode(executablePath); }); - test("should install extension from a VSIX file in VSCode", async ({ - page, - }) => { - const vsixFilePath = process.env.VSIX_FILE_PATH; - await vscodePage.installExtensionFromVSIX(vsixFilePath); - await page.pause(); + test.afterAll(async () => { + await vscodeApp.closeVSCode(); + }); + + test('should launch VSCode and check window title', async () => { + const window = vscodeApp.getWindow(); + const title = await window.title(); + expect(title).toContain('Visual Studio Code'); + }); + + test('should open Extensions tab and verify installed extension', async () => { + const window = vscodeApp.getWindow(); + const kaiTab = await window.getByRole('tab', { name: 'KAI', exact: true }); + await kaiTab.click(); + // Assert if KAI explorer is opened. + const title = await window.getByRole('heading', { + name: 'KAI', + exact: true, + }); + expect(title).toBeTruthy(); }); }); diff --git a/scripts/populate-konveyor.sh b/scripts/populate-konveyor.sh index 1326d4ca..e1ec4878 100755 --- a/scripts/populate-konveyor.sh +++ b/scripts/populate-konveyor.sh @@ -44,10 +44,12 @@ tmp=/tmp/${self}-${pid} usage() { echo "Usage: ${self} " - echo "Auth has to be disabled in order to execute this script" echo "-h help" + echo "Auth has to be disabled in order to execute this script" echo "Required:" - echo " -u /hub" + echo " -u URL of the hub" + echo "Example:" + echo " ${self} -u htps://my-konveyor-instance/hub -n 5" echo "Options:" echo " -b base name (Test)" echo " -n count (10)" @@ -220,8 +222,8 @@ waitForAnalyses() { break fi - echo "Some analyses are still running, waiting 30 secs..." - sleep 30 + echo "Some analyses are still running, waiting 1 min..." + sleep 60 done } From 810b1f6db3c3f1420f4cd2faa89b224389ea6943 Mon Sep 17 00:00:00 2001 From: Shveta Sachdeva Date: Tue, 15 Oct 2024 14:16:29 -0700 Subject: [PATCH 8/9] Improved code Signed-off-by: Shveta Sachdeva --- e2e/pages/vscode.pages.ts | 127 +++++++++++++++++++------------------- e2e/tests/vscode.test.ts | 2 +- playwright.config.ts | 35 +++-------- 3 files changed, 73 insertions(+), 91 deletions(-) diff --git a/e2e/pages/vscode.pages.ts b/e2e/pages/vscode.pages.ts index 872b0a3d..7153f32a 100644 --- a/e2e/pages/vscode.pages.ts +++ b/e2e/pages/vscode.pages.ts @@ -1,91 +1,92 @@ -// launch_vscode.page.ts import { _electron as electron, ElectronApplication, Page } from 'playwright'; import { execSync } from 'child_process'; -import { expect } from '@playwright/test'; import * as fs from 'fs'; class LaunchVSCodePage { - private vscodeApp: ElectronApplication | null = null; - private window: Page | null = null; + private vscodeApp?: ElectronApplication; + private window?: Page; - public async launchVSCode(executablePath): Promise { - // Get the VSIX file path from environment variable - const vsixFilePath = process.env.VSIX_FILE_PATH; - - if (vsixFilePath) { - // Pass the environment variable to the method - this.installExtensionFromVSIX(vsixFilePath); - } else { - console.error('Error: VSIX_FILE_PATH is not set in the environment.'); - } - // this.installExtensionFromVSIX(process.env.VSIX_FILE_PATH) - this.vscodeApp = await electron.launch({ - executablePath: executablePath, // Path to VSCode executable - }); - this.window = await this.vscodeApp.firstWindow(); - - const title = await this.window.title(); - console.log(`VSCode window title: ${title}`); - - expect(title).toContain('Visual Studio Code'); + private constructor(vscodeApp: ElectronApplication, window: Page) { + this.vscodeApp = vscodeApp; + this.window = window; } - // public async installExtensionFromVSIX(vsixFilePath): Promise { - // if (!fs.existsSync(vsixFilePath)) { - // throw new Error(`VSIX file not found at path: ${vsixFilePath}`); - // } - - // if (!this.window) { - // throw new Error("VSCode window is not initialized."); - // } - - // const extensionsTab = await this.window.getByRole("tab", { - // name: "Extensions (Ctrl+Shift+X)", - // }); - // await extensionsTab.locator("a").waitFor({ state: "visible" }); - // await extensionsTab.locator("a").click({ force: true }); + public static async launchVSCode( + executablePath: string + ): Promise { + try { + const vsixFilePath = process.env.VSIX_FILE_PATH; + if (vsixFilePath) { + console.log(`Installing extension from VSIX file: ${vsixFilePath}`); + await LaunchVSCodePage.installExtensionFromVSIX(vsixFilePath); + } else { + console.warn( + 'VSIX_FILE_PATH environment variable is not set. Skipping extension installation.' + ); + } - // const extensionsActionsButton = - // await this.window.getByLabel("Extensions actions"); - // await extensionsActionsButton.click(); + // Launch VSCode as an Electron app + const vscodeApp = await electron.launch({ + executablePath: executablePath, + }); - // // Find the "Views and More Actions..." inside the Extensions actions and click it - // const moreActionsButton = await extensionsActionsButton.getByLabel( - // "Views and More Actions...", - // ); - // await moreActionsButton.click(); + // Get the main window + const window = await vscodeApp.firstWindow(); - // await this.window.click( - // '.context-view .menu-item span:has-text("Install from VSIX...")', - // ); - // // Set the file input for the VSIX file - // const inputSelector = 'input[type="file"]'; - // await this.window.setInputFiles(inputSelector, vsixFilePath); + // Return an instance of LaunchVSCodePage + return new LaunchVSCodePage(vscodeApp, window); + } catch (error) { + console.error('Error launching VSCode:', error); + throw error; + } + } - // // Wait for the uninstall button to appear indicating the extension is installed - // await this.window.waitForSelector(".extension-list-item .uninstall", { - // timeout: 60000, - // }); - // } + /** + * Installs an extension from a VSIX file using the VSCode CLI. + * This method is static because it is independent of the instance. + */ + private static async installExtensionFromVSIX( + vsixFilePath: string + ): Promise { + if (!fs.existsSync(vsixFilePath)) { + throw new Error(`VSIX file not found at path: ${vsixFilePath}`); + } - public installExtensionFromVSIX(vsixFilePath: string): void { - // Install VSCode extension using terminal command try { + // Execute command to install VSIX file using VSCode CLI console.log(`Installing extension from ${vsixFilePath}...`); execSync(`code --install-extension ${vsixFilePath}`, { stdio: 'inherit', }); - console.log('Extension installed successfully'); + console.log('Extension installed successfully.'); } catch (error) { console.error('Error installing the VSIX extension:', error); + throw error; } } - // Method to close VSCode + /** + * Closes the VSCode instance. + */ public async closeVSCode(): Promise { - if (this.vscodeApp) { - await this.vscodeApp.close(); + try { + if (this.vscodeApp) { + await this.vscodeApp.close(); + console.log('VSCode closed successfully.'); + } + } catch (error) { + console.error('Error closing VSCode:', error); + } + } + + /** + * Returns the main window for further interactions. + */ + public getWindow(): Page { + if (!this.window) { + throw new Error('VSCode window is not initialized.'); } + return this.window; } } diff --git a/e2e/tests/vscode.test.ts b/e2e/tests/vscode.test.ts index 4445e58f..777d753f 100644 --- a/e2e/tests/vscode.test.ts +++ b/e2e/tests/vscode.test.ts @@ -1,5 +1,5 @@ import { test, expect } from '@playwright/test'; -import { LaunchVSCodePage } from '../pages/vscode2.pages'; +import { LaunchVSCodePage } from '../pages/vscode.pages'; test.describe('VSCode Tests', () => { let vscodeApp: LaunchVSCodePage; diff --git a/playwright.config.ts b/playwright.config.ts index e3e879c3..05b82baf 100755 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,38 +1,19 @@ -import { defineConfig, devices } from "@playwright/test"; -import dotenv from "dotenv"; +import { defineConfig } from '@playwright/test'; +import dotenv from 'dotenv'; -/** - * Read environment variables from file. - * https://github.com/motdotla/dotenv - */ +import path from 'path'; +dotenv.config({ path: path.resolve(__dirname, '.env') }); -import path from "path"; -dotenv.config({ path: path.resolve(__dirname, ".env") }); - -/** - * See https://playwright.dev/docs/test-configuration. - */ export default defineConfig({ - testDir: "./e2e/tests", + testDir: './e2e/tests', fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, - 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', + reporter: 'html', - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: "on-first-retry", + use: { + trace: 'on-first-retry', }, - - /* Run your local dev server before starting the tests */ - // webServer: { - // command: 'npm run start', - // url: 'http://127.0.0.1:3000', - // reuseExistingServer: !process.env.CI, - // }, }); From 607abd7b3f088b602431a9f066de93135149bf68 Mon Sep 17 00:00:00 2001 From: Shveta Sachdeva Date: Tue, 15 Oct 2024 14:48:56 -0700 Subject: [PATCH 9/9] added formatting check on PR Signed-off-by: Shveta Sachdeva --- .github/workflows/prettier.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/prettier.yaml diff --git a/.github/workflows/prettier.yaml b/.github/workflows/prettier.yaml new file mode 100644 index 00000000..75de6da3 --- /dev/null +++ b/.github/workflows/prettier.yaml @@ -0,0 +1,11 @@ +name: Code formatting +on: pull_request + +jobs: + build: + name: Prettier + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: npm install . + - run: npm run check