From 1a50c0aabab7a441497634c16aa5998579c6a2c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20Escalante=20=C3=81lvarez?= Date: Wed, 22 Jan 2025 11:30:04 +0100 Subject: [PATCH 01/11] Setup playwright Co-authored-by: mikel.martin@gmail.com --- .gitattributes | 4 ++ .gitignore | 9 +++- bin/playwright | 41 +++++++++++++++ composer.json | 6 ++- package-lock.json | 91 +++++++++++++++++++++++++++++++++ package.json | 14 +++++ playwright.config.js | 45 ++++++++++++++++ tests-e2e/specs/example.spec.js | 19 +++++++ 8 files changed, 227 insertions(+), 2 deletions(-) create mode 100755 bin/playwright create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 playwright.config.js create mode 100644 tests-e2e/specs/example.spec.js diff --git a/.gitattributes b/.gitattributes index 708212f..83834ea 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,6 +5,9 @@ docker-compose.yml export-ignore docker-compose.override.sample.yml export-ignore README.md export-ignore +package.json export-ignore +package-lock.json export-ignore +playwright.config.js export-ignore # Exclude specific directories .github export-ignore @@ -14,6 +17,7 @@ bin export-ignore docker-entrypoint-init.d export-ignore .docker export-ignore .github export-ignore +tests-e2e export-ignore # Exclude scripts *.sh export-ignore \ No newline at end of file diff --git a/.gitignore b/.gitignore index b32220e..29e8b14 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,11 @@ docker-compose.override.yml .env default.vcl id_rsa -.magento-src \ No newline at end of file +.magento-src + +# Playwright +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/bin/playwright b/bin/playwright new file mode 100755 index 0000000..7a80cb8 --- /dev/null +++ b/bin/playwright @@ -0,0 +1,41 @@ +#!/bin/bash +BASEDIR="$(dirname $(realpath $0))/.." + +cd "${BASEDIR}" || exit +set -o allexport +source .env +set +o allexport + +if [ -z "$PUBLIC_URL" ]; then + PUBLIC_URL="$M2_URL" +fi + +wait_for() { + local retry=60 + local timeout=1 + local start=$(date +%s) + + while [ $(($(date +%s) - $start)) -lt $retry ]; do + if "$@" > /dev/null 2>&1; then + return 0 + fi + sleep $timeout + done + return 1 +} +echo "🚀 Waiting for ngrok tunnel to be ready..." +result=$(wait_for curl -H "ngrok-skip-browser-warning: 1" -s -o /dev/null --head --fail "${PUBLIC_URL}") +if [ "$result" == "1" ]; then + echo "❌ Magento is not available at: ${PUBLIC_URL}" + exit 1 +fi +echo "✅ Magento is available at: ${PUBLIC_URL}" + +# Check if --headed is passed +if [[ "$@" == *"--headed"* || "$@" == *"--ui"* ]]; then + npx playwright test $@ +else + docker run \ + --env-file "${BASEDIR}"/.env \ + -it --rm -v "${BASEDIR}":/app -w /app mcr.microsoft.com/playwright:v1.49.1-jammy bash -c "npx playwright test $@" +fi diff --git a/composer.json b/composer.json index 7841c3f..ec8580b 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,11 @@ "docker-compose.yml", "README.md", "setup.sh", - "teardown.sh" + "teardown.sh", + "tests-e2e", + "package.json", + "package-lock.json", + "playwright.config.js" ] }, "require-dev": { diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..4809af9 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,91 @@ +{ + "name": "magento2-core", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "magento2-core", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@playwright/test": "^1.49.1", + "@types/node": "^22.10.7" + } + }, + "node_modules/@playwright/test": { + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.1.tgz", + "integrity": "sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==", + "dev": true, + "dependencies": { + "playwright": "1.49.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "22.10.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz", + "integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==", + "dev": true, + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", + "integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", + "dev": true, + "dependencies": { + "playwright-core": "1.49.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", + "integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..29ca24e --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "magento2-core", + "version": "1.0.0", + "description": "1. [About seQura](#about-sequra) 2. [Installation guide](https://sequra.atlassian.net/wiki/spaces/DOC/pages/1377304583/MAGENTO+2) 3. [Sign-up](#sign-up) 4. [For developers](#for-developers)", + "main": "index.js", + "scripts": {}, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@playwright/test": "^1.49.1", + "@types/node": "^22.10.7" + } +} diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 0000000..f707167 --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,45 @@ +// @ts-check +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-e2e/specs', + timeout: 5 * 60 * 1000, // 5 minutes + /* Run tests in files in parallel */ + fullyParallel: false, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: 0, + /* Opt out of parallel tests on CI. */ + workers: 1, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: process.env.CI ? 'dot' : 'list', + /* 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: process.env.PUBLIC_URL, + /* 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: 'example', + use: { ...devices['Desktop Chrome'] }, + testMatch: 'example.spec.js', + }, + ], +}); + diff --git a/tests-e2e/specs/example.spec.js b/tests-e2e/specs/example.spec.js new file mode 100644 index 0000000..26ed206 --- /dev/null +++ b/tests-e2e/specs/example.spec.js @@ -0,0 +1,19 @@ +// @ts-check +import { test, expect } from '@playwright/test'; + +test('has title', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Expect a title "to contain" a substring. + await expect(page).toHaveTitle(/Playwright/); +}); + +test('get started link', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Click the get started link. + await page.getByRole('link', { name: 'Get started' }).click(); + + // Expects page to have a heading with the name of Installation. + await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible(); +}); From 0937efe638f9aa548d0efea0a4b5f52cff8ffac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20Escalante=20=C3=81lvarez?= Date: Fri, 31 Jan 2025 12:54:45 +0100 Subject: [PATCH 02/11] Implement webhook functionality with task execution for Sequra helper module --- .../Sequra/Helper/Api/WebhooksInterface.php | 11 ++ .../Sequra/Helper/Model/Api/Webhooks.php | 46 ++++++ .../Model/Task/ClearConfigurationTask.php | 24 +++ .../Helper/Model/Task/ConfigureDummyTask.php | 146 ++++++++++++++++++ .../Sequra/Helper/Model/Task/Task.php | 79 ++++++++++ .../HelperModule/Sequra/Helper/etc/di.xml | 1 + .../HelperModule/Sequra/Helper/etc/webapi.xml | 9 ++ 7 files changed, 316 insertions(+) create mode 100644 .docker/magento/HelperModule/Sequra/Helper/Api/WebhooksInterface.php create mode 100644 .docker/magento/HelperModule/Sequra/Helper/Model/Api/Webhooks.php create mode 100644 .docker/magento/HelperModule/Sequra/Helper/Model/Task/ClearConfigurationTask.php create mode 100644 .docker/magento/HelperModule/Sequra/Helper/Model/Task/ConfigureDummyTask.php create mode 100644 .docker/magento/HelperModule/Sequra/Helper/Model/Task/Task.php create mode 100644 .docker/magento/HelperModule/Sequra/Helper/etc/webapi.xml diff --git a/.docker/magento/HelperModule/Sequra/Helper/Api/WebhooksInterface.php b/.docker/magento/HelperModule/Sequra/Helper/Api/WebhooksInterface.php new file mode 100644 index 0000000..c25a0de --- /dev/null +++ b/.docker/magento/HelperModule/Sequra/Helper/Api/WebhooksInterface.php @@ -0,0 +1,11 @@ +conn = $resourceConnection; + } + + public function execute() + { + return $this->getTaskForWebhook((string)($_GET['sq-webhook'] ?? null))->execute(); + } + + + /** + * Get task for webhook + */ + private function getTaskForWebhook( $webhook ): Task { + $map = array( + // 'dummy_services_config' => ConfigureDummy_Service_Task::class, + 'dummy_config' => ConfigureDummyTask::class, + 'clear_config' => ClearConfigurationTask::class, + // 'remove_db_tables' => RemoveDbTablesTask::class + + ); + return ! isset( $map[ $webhook ] ) ? new Task($this->conn) : new $map[ $webhook ]($this->conn); + } + +} \ No newline at end of file diff --git a/.docker/magento/HelperModule/Sequra/Helper/Model/Task/ClearConfigurationTask.php b/.docker/magento/HelperModule/Sequra/Helper/Model/Task/ClearConfigurationTask.php new file mode 100644 index 0000000..9a8a256 --- /dev/null +++ b/.docker/magento/HelperModule/Sequra/Helper/Model/Task/ClearConfigurationTask.php @@ -0,0 +1,24 @@ +removeStoreDataFromEntityTable(); + return $this->httpSuccessResponse(); + } +} diff --git a/.docker/magento/HelperModule/Sequra/Helper/Model/Task/ConfigureDummyTask.php b/.docker/magento/HelperModule/Sequra/Helper/Model/Task/ConfigureDummyTask.php new file mode 100644 index 0000000..ea3a9aa --- /dev/null +++ b/.docker/magento/HelperModule/Sequra/Helper/Model/Task/ConfigureDummyTask.php @@ -0,0 +1,146 @@ +conn->getConnection()->fetchAll( $query ); + return is_array( $result ) && count( $result ) === $expected_rows; + } + + /** + * Set configuration for dummy merchant + */ + private function setDummyConfig( bool $widgets ): void { + $table_name = DatabaseHandler::SEQURA_ENTITY_TABLE; + $conn = $this->conn->getConnection(); + $time = time(); + $id = $time; + $conn->insert( + $table_name, + array( + 'id' => ++$id, + 'type' => 'ConnectionData', + 'index_1' => '1', + 'data' => '{"class_name":"SeQura\\\\Core\\\\BusinessLogic\\\\DataAccess\\\\ConnectionData\\\\Entities\\\\ConnectionData","id":'. $id .',"storeId":"1","connectionData":{"environment":"sandbox","merchantId":null,"authorizationCredentials":{"username":"dummy_automated_tests","password":"0:3:KMpTv7VGdtxQKYfaoOFZXs5u2TSNQjCV3MNcl6rwyHe\/PwP7aa\/P+EdSnQ1yIX5GwFgZyoDuTduIHw=="}}}', + ) + ); + $conn->insert( + $table_name, + array( + 'id' => ++$id, + 'type' => 'StatisticalData', + 'index_1' => '1', + 'data' => '{"class_name":"SeQura\\\\Core\\\\BusinessLogic\\\\DataAccess\\\\StatisticalData\\\\Entities\\\\StatisticalData","id":'. $id .',"storeId":"1","statisticalData":{"sendStatisticalData":true}}', + ) + ); + $conn->insert( + $table_name, + array( + 'id' => ++$id, + 'type' => 'SendReport', + 'index_1' => '1', + 'index_2' => $this->timeToString( $time ), + 'data' => '{"class_name":"SeQura\\\\Core\\\\BusinessLogic\\\\DataAccess\\\\SendReport\\\\Entities\\\\SendReport","id":'. $id .',"context":"1","sendReportTime":'.$time.',"sendData":{"sendReportTime":'.$time.'}', + ) + ); + $conn->insert( + $table_name, + array( + 'id' => ++$id, + 'type' => 'CountryConfiguration', + 'index_1' => '1', + 'data' => '{"class_name":"SeQura\\\\Core\\\\BusinessLogic\\\\DataAccess\\\\CountryConfiguration\\\\Entities\\\\CountryConfiguration","id":'. $id .',"storeId":"1","countryConfigurations":[{"countryCode":"ES","merchantId":"dummy_automated_tests"},{"countryCode":"FR","merchantId":"dummy_automated_tests_fr"},{"countryCode":"IT","merchantId":"dummy_automated_tests_it"},{"countryCode":"PT","merchantId":"dummy_automated_tests_pt"}]}', + ) + ); + $conn->insert( + $table_name, + array( + 'id' => ++$id, + 'type' => 'PaymentMethods', + 'index_1' => '1', + 'index_2' => 'dummy_automated_tests', + /* + {"class_name":"Sequra\\Core\\DataAccess\\Entities\\PaymentMethods","id":1738322366, "storeId":"1","merchantId":"dummy_automated_tests","paymentMethods":[{"product":"i1","title":"Paga Despu\u00e9s","longTitle":"Recibe tu compra antes de pagar","startsAt":"2024-08-29 13:25:00","endsAt":"3333-09-01 14:25:00","campaign":"","claim":"Sin coste adicional","description":"Compra ahora, recibe primero y paga despu\u00e9s. Cuando tu pedido salga de la tienda tendr\u00e1s 7 d\u00edas para realizar el pago desde el enlace que recibir\u00e1s en tu email o mediante transferencia bancaria.","icon":"\r\n\r\n \r\n